From 989dea7083f2ffdb8b4bcd0f87235539dff3fab1 Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Fri, 6 Mar 2020 15:55:56 -0800 Subject: [PATCH 001/262] refactor(benchpress): delete broken code (#35922) PR Close #35922 --- .../src/firefox_extension/.gitignore | 2 - .../data/installed_script.ts | 38 ------- .../src/firefox_extension/lib/main.ts | 80 -------------- .../src/firefox_extension/lib/parser_util.ts | 92 ---------------- .../src/firefox_extension/lib/test_helper.ts | 51 --------- .../src/firefox_extension/package.json | 1 - .../benchpress/test/firefox_extension/conf.ts | 21 ---- .../firefox_extension/parser_util_spec.ts | 100 ------------------ .../sample_benchmark_spec.ts | 45 -------- .../benchpress/test/firefox_extension/spec.ts | 45 -------- 10 files changed, 475 deletions(-) delete mode 100644 packages/benchpress/src/firefox_extension/.gitignore delete mode 100644 packages/benchpress/src/firefox_extension/data/installed_script.ts delete mode 100644 packages/benchpress/src/firefox_extension/lib/main.ts delete mode 100644 packages/benchpress/src/firefox_extension/lib/parser_util.ts delete mode 100644 packages/benchpress/src/firefox_extension/lib/test_helper.ts delete mode 100644 packages/benchpress/src/firefox_extension/package.json delete mode 100644 packages/benchpress/test/firefox_extension/conf.ts delete mode 100644 packages/benchpress/test/firefox_extension/parser_util_spec.ts delete mode 100644 packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts delete mode 100644 packages/benchpress/test/firefox_extension/spec.ts diff --git a/packages/benchpress/src/firefox_extension/.gitignore b/packages/benchpress/src/firefox_extension/.gitignore deleted file mode 100644 index fc1a520a40df6..0000000000000 --- a/packages/benchpress/src/firefox_extension/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.xpi -addon-sdk* diff --git a/packages/benchpress/src/firefox_extension/data/installed_script.ts b/packages/benchpress/src/firefox_extension/data/installed_script.ts deleted file mode 100644 index 1e14d5cc6b6c0..0000000000000 --- a/packages/benchpress/src/firefox_extension/data/installed_script.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -declare var exportFunction: any; -declare var unsafeWindow: any; - -exportFunction(function() { - const curTime = unsafeWindow.performance.now(); - (self).port.emit('startProfiler', curTime); -}, unsafeWindow, {defineAs: 'startProfiler'}); - -exportFunction(function() { - (self).port.emit('stopProfiler'); -}, unsafeWindow, {defineAs: 'stopProfiler'}); - -exportFunction(function(cb: Function) { - (self).port.once('perfProfile', cb); - (self).port.emit('getProfile'); -}, unsafeWindow, {defineAs: 'getProfile'}); - -exportFunction(function() { - (self).port.emit('forceGC'); -}, unsafeWindow, {defineAs: 'forceGC'}); - -exportFunction(function(name: string) { - const curTime = unsafeWindow.performance.now(); - (self).port.emit('markStart', name, curTime); -}, unsafeWindow, {defineAs: 'markStart'}); - -exportFunction(function(name: string) { - const curTime = unsafeWindow.performance.now(); - (self).port.emit('markEnd', name, curTime); -}, unsafeWindow, {defineAs: 'markEnd'}); diff --git a/packages/benchpress/src/firefox_extension/lib/main.ts b/packages/benchpress/src/firefox_extension/lib/main.ts deleted file mode 100644 index 348014637c467..0000000000000 --- a/packages/benchpress/src/firefox_extension/lib/main.ts +++ /dev/null @@ -1,80 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const {Cc, Ci, Cu} = require('chrome'); -const os = Cc['@mozilla.org/observer-service;1'].getService(Ci.nsIObserverService); -const ParserUtil = require('./parser_util'); - -class Profiler { - private _profiler: any; - // TODO(issue/24571): remove '!'. - private _markerEvents !: any[]; - // TODO(issue/24571): remove '!'. - private _profilerStartTime !: number; - - constructor() { this._profiler = Cc['@mozilla.org/tools/profiler;1'].getService(Ci.nsIProfiler); } - - start(entries: any, interval: any, features: any, timeStarted: any) { - this._profiler.StartProfiler(entries, interval, features, features.length); - this._profilerStartTime = timeStarted; - this._markerEvents = []; - } - - stop() { this._profiler.StopProfiler(); } - - getProfilePerfEvents() { - const profileData = this._profiler.getProfileData(); - let perfEvents = ParserUtil.convertPerfProfileToEvents(profileData); - perfEvents = this._mergeMarkerEvents(perfEvents); - perfEvents.sort(function(event1: any, event2: any) { - return event1.ts - event2.ts; - }); // Sort by ts - return perfEvents; - } - - /** @internal */ - private _mergeMarkerEvents(perfEvents: any[]): any[] { - this._markerEvents.forEach(function(markerEvent) { perfEvents.push(markerEvent); }); - return perfEvents; - } - - addStartEvent(name: string, timeStarted: number) { - this._markerEvents.push({ph: 'B', ts: timeStarted - this._profilerStartTime, name: name}); - } - - addEndEvent(name: string, timeEnded: number) { - this._markerEvents.push({ph: 'E', ts: timeEnded - this._profilerStartTime, name: name}); - } -} - -function forceGC() { - Cu.forceGC(); - os.notifyObservers(null, 'child-gc-request', null); -} - -const mod = require('sdk/page-mod'); -const data = require('sdk/self').data; -const profiler = new Profiler(); -mod.PageMod({ - include: ['*'], - contentScriptFile: data.url('installed_script.js'), - onAttach: (worker: any) => { - worker.port.on( - 'startProfiler', - (timeStarted: any) => profiler.start( - /* = profiler memory */ 3000000, 0.1, ['leaf', 'js', 'stackwalk', 'gc'], timeStarted)); - worker.port.on('stopProfiler', () => profiler.stop()); - worker.port.on( - 'getProfile', () => worker.port.emit('perfProfile', profiler.getProfilePerfEvents())); - worker.port.on('forceGC', forceGC); - worker.port.on( - 'markStart', (name: string, timeStarted: any) => profiler.addStartEvent(name, timeStarted)); - worker.port.on( - 'markEnd', (name: string, timeEnded: any) => profiler.addEndEvent(name, timeEnded)); - } -}); diff --git a/packages/benchpress/src/firefox_extension/lib/parser_util.ts b/packages/benchpress/src/firefox_extension/lib/parser_util.ts deleted file mode 100644 index 6bccc3c876245..0000000000000 --- a/packages/benchpress/src/firefox_extension/lib/parser_util.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * @param {Object} perfProfile The perf profile JSON object. - * @return {Object[]} An array of recognized events that are captured - * within the perf profile. - */ -export function convertPerfProfileToEvents(perfProfile: any): any[] { - const inProgressEvents = new Map(); // map from event name to start time - const finishedEvents: {[key: string]: any}[] = []; // Event[] finished events - const addFinishedEvent = function(eventName: string, startTime: number, endTime: number) { - const categorizedEventName = categorizeEvent(eventName); - let args: {[key: string]: any}|undefined = undefined; - if (categorizedEventName == 'gc') { - // TODO: We cannot measure heap size at the moment - args = {usedHeapSize: 0}; - } - if (startTime == endTime) { - // Finished instantly - finishedEvents.push({ph: 'X', ts: startTime, name: categorizedEventName, args: args}); - } else { - // Has duration - finishedEvents.push({ph: 'B', ts: startTime, name: categorizedEventName, args: args}); - finishedEvents.push({ph: 'E', ts: endTime, name: categorizedEventName, args: args}); - } - }; - - const samples = perfProfile.threads[0].samples; - // In perf profile, firefox samples all the frames in set time intervals. Here - // we go through all the samples and construct the start and end time for each - // event. - for (let i = 0; i < samples.length; ++i) { - const sample = samples[i]; - const sampleTime = sample.time; - - // Add all the frames into a set so it's easier/faster to find the set - // differences - const sampleFrames = new Set(); - sample.frames.forEach(function(frame: {[key: string]: any}) { - sampleFrames.add(frame['location']); - }); - - // If an event is in the inProgressEvents map, but not in the current sample, - // then it must have just finished. We add this event to the finishedEvents - // array and remove it from the inProgressEvents map. - const previousSampleTime = (i == 0 ? /* not used */ -1 : samples[i - 1].time); - inProgressEvents.forEach(function(startTime, eventName) { - if (!(sampleFrames.has(eventName))) { - addFinishedEvent(eventName, startTime, previousSampleTime); - inProgressEvents.delete(eventName); - } - }); - - // If an event is in the current sample, but not in the inProgressEvents map, - // then it must have just started. We add this event to the inProgressEvents - // map. - sampleFrames.forEach(function(eventName) { - if (!(inProgressEvents.has(eventName))) { - inProgressEvents.set(eventName, sampleTime); - } - }); - } - - // If anything is still in progress, we need to included it as a finished event - // since recording ended. - const lastSampleTime = samples[samples.length - 1].time; - inProgressEvents.forEach(function(startTime, eventName) { - addFinishedEvent(eventName, startTime, lastSampleTime); - }); - - // Remove all the unknown categories. - return finishedEvents.filter(function(event) { return event['name'] != 'unknown'; }); -} - -// TODO: this is most likely not exhaustive. -export function categorizeEvent(eventName: string): string { - if (eventName.indexOf('PresShell::Paint') > -1) { - return 'render'; - } else if (eventName.indexOf('FirefoxDriver.prototype.executeScript') > -1) { - return 'script'; - } else if (eventName.indexOf('forceGC') > -1) { - return 'gc'; - } else { - return 'unknown'; - } -} diff --git a/packages/benchpress/src/firefox_extension/lib/test_helper.ts b/packages/benchpress/src/firefox_extension/lib/test_helper.ts deleted file mode 100644 index 97cfd2519d289..0000000000000 --- a/packages/benchpress/src/firefox_extension/lib/test_helper.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -const q = require('q'); -const FirefoxProfile = require('firefox-profile'); -const jpm = require('jpm/lib/xpi'); -const pathUtil = require('path'); - -const PERF_ADDON_PACKAGE_JSON_DIR = '..'; - -exports.getAbsolutePath = function(path: string) { - const normalizedPath = pathUtil.normalize(path); - if (pathUtil.resolve(normalizedPath) == normalizedPath) { - // Already absolute path - return normalizedPath; - } else { - return pathUtil.join(__dirname, normalizedPath); - } -}; - -exports.getFirefoxProfile = function(extensionPath: string) { - const deferred = q.defer(); - - const firefoxProfile = new FirefoxProfile(); - firefoxProfile.addExtensions([extensionPath], () => { - firefoxProfile.encoded((err: any, encodedProfile: string) => { - const multiCapabilities = [{browserName: 'firefox', firefox_profile: encodedProfile}]; - deferred.resolve(multiCapabilities); - }); - }); - - return deferred.promise; -}; - -exports.getFirefoxProfileWithExtension = function() { - const absPackageJsonDir = pathUtil.join(__dirname, PERF_ADDON_PACKAGE_JSON_DIR); - const packageJson = require(pathUtil.join(absPackageJsonDir, 'package.json')); - - const savedCwd = process.cwd(); - process.chdir(absPackageJsonDir); - - return jpm(packageJson).then((xpiPath: string) => { - process.chdir(savedCwd); - return exports.getFirefoxProfile(xpiPath); - }); -}; diff --git a/packages/benchpress/src/firefox_extension/package.json b/packages/benchpress/src/firefox_extension/package.json deleted file mode 100644 index f3e5ca260841d..0000000000000 --- a/packages/benchpress/src/firefox_extension/package.json +++ /dev/null @@ -1 +0,0 @@ -{ "version" : "0.0.1", "main" : "lib/main.js", "name" : "ffperf-addon" } diff --git a/packages/benchpress/test/firefox_extension/conf.ts b/packages/benchpress/test/firefox_extension/conf.ts deleted file mode 100644 index 4be1898f2bea9..0000000000000 --- a/packages/benchpress/test/firefox_extension/conf.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -require('core-js'); -require('reflect-metadata'); -const testHelper = require('../../src/firefox_extension/lib/test_helper.js'); - -exports.config = { - specs: ['spec.js', 'sample_benchmark.js'], - - framework: 'jasmine2', - - jasmineNodeOpts: {showColors: true, defaultTimeoutInterval: 1200000}, - - getMultiCapabilities: function() { return testHelper.getFirefoxProfileWithExtension(); } -}; diff --git a/packages/benchpress/test/firefox_extension/parser_util_spec.ts b/packages/benchpress/test/firefox_extension/parser_util_spec.ts deleted file mode 100644 index 1669d0703651a..0000000000000 --- a/packages/benchpress/test/firefox_extension/parser_util_spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {convertPerfProfileToEvents} from '../../src/firefox_extension/lib/parser_util'; - -function assertEventsEqual(actualEvents: any[], expectedEvents: any[]) { - expect(actualEvents.length == expectedEvents.length); - for (let i = 0; i < actualEvents.length; ++i) { - const actualEvent = actualEvents[i]; - const expectedEvent = expectedEvents[i]; - for (const key in actualEvent) { - expect(actualEvent[key]).toEqual(expectedEvent[key]); - } - } -} - -{ - describe('convertPerfProfileToEvents', function() { - it('should convert single instantaneous event', function() { - const profileData = { - threads: [ - {samples: [{time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}]} - ] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]); - }); - - it('should convert single non-instantaneous event', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 100, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual( - perfEvents, [{ph: 'B', ts: 1, name: 'script'}, {ph: 'E', ts: 100, name: 'script'}]); - }); - - it('should convert multiple instantaneous events', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'PresShell::Paint'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual( - perfEvents, [{ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'}]); - }); - - it('should convert multiple mixed events', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'PresShell::Paint'}]}, - {time: 5, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 10, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [ - {ph: 'X', ts: 1, name: 'script'}, {ph: 'X', ts: 2, name: 'render'}, - {ph: 'B', ts: 5, name: 'script'}, {ph: 'E', ts: 10, name: 'script'} - ]); - }); - - it('should add args to gc events', function() { - const profileData = {threads: [{samples: [{time: 1, frames: [{location: 'forceGC'}]}]}]}; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'gc', args: {usedHeapSize: 0}}]); - }); - - it('should skip unknown events', function() { - const profileData = { - threads: [{ - samples: [ - {time: 1, frames: [{location: 'FirefoxDriver.prototype.executeScript'}]}, - {time: 2, frames: [{location: 'foo'}]} - ] - }] - }; - const perfEvents = convertPerfProfileToEvents(profileData); - assertEventsEqual(perfEvents, [{ph: 'X', ts: 1, name: 'script'}]); - }); - }); -} diff --git a/packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts b/packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts deleted file mode 100644 index 2657a2347a147..0000000000000 --- a/packages/benchpress/test/firefox_extension/sample_benchmark_spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {$, browser} from 'protractor'; - -const benchpress = require('../../index.js'); - -// TODO: this test is currnetly failing. it seems that it didn't run on the ci for a while -xdescribe('deep tree baseline', function() { - const runner = new benchpress.Runner([ - // use protractor as Webdriver client - benchpress.SeleniumWebDriverAdapter.PROTRACTOR_PROVIDERS, - // use RegressionSlopeValidator to validate samples - benchpress.Validator.bind(benchpress.RegressionSlopeValidator), - // use 10 samples to calculate slope regression - benchpress.bind(benchpress.RegressionSlopeValidator.SAMPLE_SIZE).toValue(20), - // use the script metric to calculate slope regression - benchpress.bind(benchpress.RegressionSlopeValidator.METRIC).toValue('scriptTime'), - benchpress.bind(benchpress.Options.FORCE_GC).toValue(true) - ]); - - - it('should be fast!', function(done) { - browser.ignoreSynchronization = true; - browser.get('http://localhost:8001/playground/src/benchpress/'); - - /* - * Tell benchpress to click the buttons to destroy and re-create the tree for each sample. - * Benchpress will log the collected metrics after each sample is collected, and will stop - * sampling as soon as the calculated regression slope for last 20 samples is stable. - */ - runner - .sample({ - id: 'baseline', - execute: function() { $('button').click(); }, - providers: [benchpress.bind(benchpress.Options.SAMPLE_DESCRIPTION).toValue({depth: 9})] - }) - .then(done, done.fail); - }); -}); diff --git a/packages/benchpress/test/firefox_extension/spec.ts b/packages/benchpress/test/firefox_extension/spec.ts deleted file mode 100644 index 754ea37212340..0000000000000 --- a/packages/benchpress/test/firefox_extension/spec.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/* tslint:disable:no-console */ -import {browser} from 'protractor'; - -const assertEventsContainsName = function(events: any[], eventName: string) { - let found = false; - for (let i = 0; i < events.length; ++i) { - if (events[i].name == eventName) { - found = true; - break; - } - } - expect(found).toBeTruthy(); -}; - -// TODO: this test is currnetly failing. it seems that it didn't run on the ci for a while -xdescribe('firefox extension', function() { - const TEST_URL = 'http://localhost:8001/playground/src/hello_world/index.html'; - - it('should measure performance', function() { - browser.sleep(3000); // wait for extension to load - - browser.driver.get(TEST_URL); - - browser.executeScript('window.startProfiler()').then(function() { - console.log('started measuring perf'); - }); - - browser.executeAsyncScript('setTimeout(arguments[0], 1000);'); - browser.executeScript('window.forceGC()'); - - browser.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);') - .then(function(profile: any) { - assertEventsContainsName(profile, 'gc'); - assertEventsContainsName(profile, 'script'); - }); - }); -}); From 6fc85073d2e49164a52077fda0df828f29b668c8 Mon Sep 17 00:00:00 2001 From: Joey Perrott Date: Tue, 10 Mar 2020 10:29:44 -0700 Subject: [PATCH 002/262] feat(dev-infra): create commit-message validation script/tooling (#36117) PR Close #36117 --- .dev-infra.json | 47 ++++ dev-infra/BUILD.bazel | 3 + dev-infra/cli.ts | 10 + dev-infra/commit-message/BUILD.bazel | 39 ++++ dev-infra/commit-message/config.ts | 13 ++ dev-infra/commit-message/validate.spec.ts | 248 ++++++++++++++++++++++ dev-infra/commit-message/validate.ts | 134 ++++++++++++ dev-infra/utils/BUILD.bazel | 1 + dev-infra/utils/config.ts | 14 +- 9 files changed, 503 insertions(+), 6 deletions(-) create mode 100644 .dev-infra.json create mode 100644 dev-infra/commit-message/BUILD.bazel create mode 100644 dev-infra/commit-message/config.ts create mode 100644 dev-infra/commit-message/validate.spec.ts create mode 100644 dev-infra/commit-message/validate.ts diff --git a/.dev-infra.json b/.dev-infra.json new file mode 100644 index 0000000000000..0a0997a8e9957 --- /dev/null +++ b/.dev-infra.json @@ -0,0 +1,47 @@ +{ + "commitMessage": { + "maxLength": 120, + "minBodyLength": 0, + "types": [ + "build", + "ci", + "docs", + "feat", + "fix", + "perf", + "refactor", + "release", + "style", + "test" + ], + "scopes": [ + "animations", + "bazel", + "benchpress", + "changelog", + "common", + "compiler", + "compiler-cli", + "core", + "dev-infra", + "docs-infra", + "elements", + "forms", + "http", + "language-service", + "localize", + "ngcc", + "packaging", + "platform-browser", + "platform-browser-dynamic", + "platform-server", + "platform-webworker", + "platform-webworker-dynamic", + "router", + "service-worker", + "upgrade", + "ve", + "zone.js" + ] + } +} \ No newline at end of file diff --git a/dev-infra/BUILD.bazel b/dev-infra/BUILD.bazel index 2d70417db398e..348009afd6607 100644 --- a/dev-infra/BUILD.bazel +++ b/dev-infra/BUILD.bazel @@ -8,7 +8,9 @@ ts_library( ], module_name = "@angular/dev-infra-private", deps = [ + "//dev-infra/commit-message", "//dev-infra/pullapprove", + "//dev-infra/utils:config", "@npm//@types/node", ], ) @@ -33,6 +35,7 @@ pkg_npm( deps = [ ":cli", ":package-json", + "//dev-infra/commit-message", "//dev-infra/ts-circular-dependencies", ], ) diff --git a/dev-infra/cli.ts b/dev-infra/cli.ts index b6285c768d5b4..3aa6d2e73364b 100644 --- a/dev-infra/cli.ts +++ b/dev-infra/cli.ts @@ -6,7 +6,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {readFileSync} from 'fs'; +import {join} from 'path'; import {verify} from './pullapprove/verify'; +import {validateCommitMessage} from './commit-message/validate'; +import {getRepoBaseDir} from './utils/config'; const args = process.argv.slice(2); @@ -16,6 +20,12 @@ switch (args[0]) { case 'pullapprove:verify': verify(); break; + case 'commit-message:pre-commit-validate': + const commitMessage = readFileSync(join(getRepoBaseDir(), '.git/COMMIT_EDITMSG'), 'utf8'); + if (validateCommitMessage(commitMessage)) { + console.info('√ Valid commit message'); + } + break; default: console.info('No commands were matched'); } diff --git a/dev-infra/commit-message/BUILD.bazel b/dev-infra/commit-message/BUILD.bazel new file mode 100644 index 0000000000000..e6029084c3e66 --- /dev/null +++ b/dev-infra/commit-message/BUILD.bazel @@ -0,0 +1,39 @@ +load("//tools:defaults.bzl", "jasmine_node_test") +load("@npm_bazel_typescript//:index.bzl", "ts_library") + +ts_library( + name = "commit-message", + srcs = [ + "config.ts", + "validate.ts", + ], + module_name = "@angular/dev-infra-private/commit-message", + visibility = ["//dev-infra:__subpackages__"], + deps = [ + "//dev-infra/utils:config", + "@npm//@types/node", + "@npm//tslib", + ], +) + +ts_library( + name = "validate-test", + testonly = True, + srcs = ["validate.spec.ts"], + deps = [ + ":commit-message", + "//dev-infra/utils:config", + "@npm//@types/events", + "@npm//@types/jasmine", + "@npm//@types/node", + ], +) + +jasmine_node_test( + name = "test", + bootstrap = ["//tools/testing:node_no_angular_es5"], + deps = [ + ":commit-message", + ":validate-test", + ], +) diff --git a/dev-infra/commit-message/config.ts b/dev-infra/commit-message/config.ts new file mode 100644 index 0000000000000..8b01bf3053a0f --- /dev/null +++ b/dev-infra/commit-message/config.ts @@ -0,0 +1,13 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +export interface CommitMessageConfig { + maxLineLength: number; + minBodyLength: number; + types: string[]; + scopes: string[]; +} \ No newline at end of file diff --git a/dev-infra/commit-message/validate.spec.ts b/dev-infra/commit-message/validate.spec.ts new file mode 100644 index 0000000000000..f9f3166f06778 --- /dev/null +++ b/dev-infra/commit-message/validate.spec.ts @@ -0,0 +1,248 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// Imports +import * as utilConfig from '../utils/config'; + +import {validateCommitMessage} from './validate'; + + +// Constants +const config = { + 'commitMessage': { + 'maxLineLength': 120, + 'minBodyLength': 0, + 'types': [ + 'feat', + 'fix', + 'refactor', + 'release', + 'style', + ], + 'scopes': [ + 'common', + 'compiler', + 'core', + 'packaging', + ] + } +}; +const TYPES = config.commitMessage.types.join(', '); +const SCOPES = config.commitMessage.scopes.join(', '); +const INVALID = false; +const VALID = true; + +// TODO(josephperrott): Clean up tests to test script rather than for +// specific commit messages we want to use. +describe('validate-commit-message.js', () => { + let lastError: string = ''; + + beforeEach(() => { + lastError = ''; + + spyOn(console, 'error').and.callFake((msg: string) => lastError = msg); + spyOn(utilConfig, 'getAngularDevConfig').and.returnValue(config); + }); + + describe('validateMessage()', () => { + + it('should be valid', () => { + expect(validateCommitMessage('feat(packaging): something')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('release(packaging): something')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('fixup! release(packaging): something')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('squash! release(packaging): something')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('Revert: "release(packaging): something"')).toBe(VALID); + expect(lastError).toBe(''); + + }); + + it('should validate max length', () => { + const msg = + 'fix(compiler): something super mega extra giga tera long, maybe even longer and longer and longer and longer and longer and longer...'; + + expect(validateCommitMessage(msg)).toBe(INVALID); + expect(lastError).toContain( + `The commit message header is longer than ${config.commitMessage.maxLineLength} characters`); + }); + + it('should validate "(): " format', () => { + const msg = 'not correct format'; + + expect(validateCommitMessage(msg)).toBe(INVALID); + expect(lastError).toContain(`The commit message header does not match the expected format.`); + }); + + it('should fail when type is invalid', () => { + const msg = 'weird(core): something'; + + expect(validateCommitMessage(msg)).toBe(INVALID); + expect(lastError).toContain(`'weird' is not an allowed type.\n => TYPES: ${TYPES}`); + }); + + it('should fail when scope is invalid', () => { + const errorMessageFor = (scope: string, header: string) => + `'${scope}' is not an allowed scope.\n => SCOPES: ${SCOPES}`; + + expect(validateCommitMessage('fix(Compiler): something')).toBe(INVALID); + expect(lastError).toContain(errorMessageFor('Compiler', 'fix(Compiler): something')); + + expect(validateCommitMessage('feat(bah): something')).toBe(INVALID); + expect(lastError).toContain(errorMessageFor('bah', 'feat(bah): something')); + + expect(validateCommitMessage('style(webworker): something')).toBe(INVALID); + expect(lastError).toContain(errorMessageFor('webworker', 'style(webworker): something')); + + expect(validateCommitMessage('refactor(security): something')).toBe(INVALID); + expect(lastError).toContain(errorMessageFor('security', 'refactor(security): something')); + + expect(validateCommitMessage('refactor(docs): something')).toBe(INVALID); + expect(lastError).toContain(errorMessageFor('docs', 'refactor(docs): something')); + + expect(validateCommitMessage('release(angular): something')).toBe(INVALID); + expect(lastError).toContain(errorMessageFor('angular', 'release(angular): something')); + }); + + it('should allow empty scope', () => { + expect(validateCommitMessage('fix: blablabla')).toBe(VALID); + expect(lastError).toBe(''); + }); + + // We do not want to allow WIP. It is OK to fail the PR build in this case to show that there is + // work still to be done (i.e. fixing the commit message). + it('should not allow "WIP: ..." syntax', () => { + const msg = 'WIP: fix: something'; + + expect(validateCommitMessage(msg)).toBe(INVALID); + expect(lastError).toContain(`'WIP' is not an allowed type.\n => TYPES: ${TYPES}`); + }); + + describe('(revert)', () => { + + it('should allow valid "revert: ..." syntaxes', () => { + expect(validateCommitMessage('revert: anything')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('Revert: "anything"')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('revert anything')).toBe(VALID); + expect(lastError).toBe(''); + + expect(validateCommitMessage('rEvErT anything')).toBe(VALID); + expect(lastError).toBe(''); + + }); + + it('should not allow "revert(scope): ..." syntax', () => { + const msg = 'revert(compiler): reduce generated code payload size by 65%'; + + expect(validateCommitMessage(msg)).toBe(INVALID); + expect(lastError).toContain(`'revert' is not an allowed type.\n => TYPES: ${TYPES}`); + }); + + // https://github.com/angular/angular/issues/23479 + it('should allow typical Angular messages generated by git', () => { + const msg = + 'Revert "fix(compiler): Pretty print object instead of [Object object] (#22689)" (#23442)'; + + expect(validateCommitMessage(msg)).toBe(VALID); + expect(lastError).toBe(''); + }); + }); + + describe('(squash)', () => { + + it('should strip the `squash! ` prefix and validate the rest', () => { + const errorMessage = `The commit message header does not match the expected format.`; + + // Valid messages. + expect(validateCommitMessage('squash! feat(core): add feature')).toBe(VALID); + expect(validateCommitMessage('squash! fix: a bug', false)).toBe(VALID); + + // Invalid messages. + expect(validateCommitMessage('squash! fix a typo', false)).toBe(INVALID); + expect(lastError).toContain('squash! fix a typo'); + expect(lastError).toContain(errorMessage); + + expect(validateCommitMessage('squash! squash! fix: a bug')).toBe(INVALID); + expect(lastError).toContain('squash! squash! fix: a bug'); + expect(lastError).toContain(errorMessage); + + + }); + + describe('with `disallowSquash`', () => { + + it('should fail', () => { + expect(validateCommitMessage('fix(core): something', true)).toBe(VALID); + expect(validateCommitMessage('squash! fix(core): something', true)).toBe(INVALID); + expect(lastError).toContain( + 'The commit must be manually squashed into the target commit'); + }); + }); + }); + + describe('(fixup)', () => { + + describe('without `nonFixupCommitHeaders`', () => { + + it('should strip the `fixup! ` prefix and validate the rest', () => { + const errorMessage = `The commit message header does not match the expected format.`; + + // Valid messages. + expect(validateCommitMessage('fixup! feat(core): add feature')).toBe(VALID); + expect(validateCommitMessage('fixup! fix: a bug')).toBe(VALID); + + // Invalid messages. + expect(validateCommitMessage('fixup! fix a typo')).toBe(INVALID); + expect(lastError).toContain('fixup! fix a typo'); + expect(lastError).toContain(errorMessage); + + expect(validateCommitMessage('fixup! fixup! fix: a bug')).toBe(INVALID); + expect(lastError).toContain('fixup! fixup! fix: a bug'); + expect(lastError).toContain(errorMessage); + + + }); + }); + + describe('with `nonFixupCommitHeaders`', () => { + + it('should check that the fixup commit matches a non-fixup one', () => { + const msg = 'fixup! foo'; + + expect(validateCommitMessage(msg, false, ['foo', 'bar', 'baz'])).toBe(VALID); + expect(validateCommitMessage(msg, false, ['bar', 'baz', 'foo'])).toBe(VALID); + expect(validateCommitMessage(msg, false, ['baz', 'foo', 'bar'])).toBe(VALID); + + expect(validateCommitMessage(msg, false, ['qux', 'quux', 'quuux'])).toBe(INVALID); + expect(lastError).toContain( + 'Unable to find match for fixup commit among prior commits: \n' + + ' qux\n' + + ' quux\n' + + ' quuux'); + }); + + it('should fail if `nonFixupCommitHeaders` is empty', () => { + expect(validateCommitMessage('refactor(core): make reactive', false, [])).toBe(VALID); + expect(validateCommitMessage('fixup! foo', false, [])).toBe(INVALID); + expect(lastError).toContain( + `Unable to find match for fixup commit among prior commits: -`); + }); + }); + }); + }); +}); diff --git a/dev-infra/commit-message/validate.ts b/dev-infra/commit-message/validate.ts new file mode 100644 index 0000000000000..1213cd416c43a --- /dev/null +++ b/dev-infra/commit-message/validate.ts @@ -0,0 +1,134 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {getAngularDevConfig} from '../utils/config'; +import {CommitMessageConfig} from './config'; + +const FIXUP_PREFIX_RE = /^fixup! /i; +const GITHUB_LINKING_RE = /((closed?s?)|(fix(es)?(ed)?)|(resolved?s?))\s\#(\d+)/ig; +const SQUASH_PREFIX_RE = /^squash! /i; +const REVERT_PREFIX_RE = /^revert:? /i; +const TYPE_SCOPE_RE = /^(\w+)(?:\(([^)]+)\))?\:\s(.+)$/; +const COMMIT_HEADER_RE = /^(.*)/i; +const COMMIT_BODY_RE = /^.*\n\n(.*)/i; + +/** Parse a full commit message into its composite parts. */ +export function parseCommitMessage(commitMsg: string) { + let header = ''; + let body = ''; + let bodyWithoutLinking = ''; + let type = ''; + let scope = ''; + let subject = ''; + + if (COMMIT_HEADER_RE.test(commitMsg)) { + header = COMMIT_HEADER_RE.exec(commitMsg) ![1] + .replace(FIXUP_PREFIX_RE, '') + .replace(SQUASH_PREFIX_RE, ''); + } + if (COMMIT_BODY_RE.test(commitMsg)) { + body = COMMIT_BODY_RE.exec(commitMsg) ![1]; + bodyWithoutLinking = body.replace(GITHUB_LINKING_RE, ''); + } + + if (TYPE_SCOPE_RE.test(header)) { + const parsedCommitHeader = TYPE_SCOPE_RE.exec(header) !; + type = parsedCommitHeader[1]; + scope = parsedCommitHeader[2]; + subject = parsedCommitHeader[3]; + } + return { + header, + body, + bodyWithoutLinking, + type, + scope, + subject, + isFixup: FIXUP_PREFIX_RE.test(commitMsg), + isSquash: SQUASH_PREFIX_RE.test(commitMsg), + isRevert: REVERT_PREFIX_RE.test(commitMsg), + }; +} + + +/** Validate a commit message against using the local repo's config. */ +export function validateCommitMessage( + commitMsg: string, disallowSquash: boolean = false, nonFixupCommitHeaders?: string[]) { + function error(errorMessage: string) { + console.error( + `INVALID COMMIT MSG: \n` + + `${'─'.repeat(40)}\n` + + `${commitMsg}\n` + + `${'─'.repeat(40)}\n` + + `ERROR: \n` + + ` ${errorMessage}` + + `\n\n` + + `The expected format for a commit is: \n` + + `(): \n\n`); + } + + const config = getAngularDevConfig<'commitMessage', CommitMessageConfig>().commitMessage; + const commit = parseCommitMessage(commitMsg); + + if (commit.isRevert) { + return true; + } + + if (commit.isSquash && disallowSquash) { + error('The commit must be manually squashed into the target commit'); + return false; + } + + // If it is a fixup commit and `nonFixupCommitHeaders` is not empty, we only care to check whether + // there is a corresponding non-fixup commit (i.e. a commit whose header is identical to this + // commit's header after stripping the `fixup! ` prefix). + if (commit.isFixup && nonFixupCommitHeaders) { + if (!nonFixupCommitHeaders.includes(commit.header)) { + error( + 'Unable to find match for fixup commit among prior commits: ' + + (nonFixupCommitHeaders.map(x => `\n ${x}`).join('') || '-')); + return false; + } + + return true; + } + + if (commit.header.length > config.maxLineLength) { + error(`The commit message header is longer than ${config.maxLineLength} characters`); + return false; + } + + if (!commit.type) { + error(`The commit message header does not match the expected format.`); + return false; + } + + if (!config.types.includes(commit.type)) { + error(`'${commit.type}' is not an allowed type.\n => TYPES: ${config.types.join(', ')}`); + return false; + } + + if (commit.scope && !config.scopes.includes(commit.scope)) { + error(`'${commit.scope}' is not an allowed scope.\n => SCOPES: ${config.scopes.join(', ')}`); + return false; + } + + if (commit.bodyWithoutLinking.trim().length < config.minBodyLength) { + error( + `The commit message body does not meet the minimum length of ${config.minBodyLength} characters`); + return false; + } + + const bodyByLine = commit.body.split('\n'); + if (bodyByLine.some(line => line.length > config.maxLineLength)) { + error( + `The commit messsage body contains lines greater than ${config.maxLineLength} characters`); + return false; + } + + return true; +} diff --git a/dev-infra/utils/BUILD.bazel b/dev-infra/utils/BUILD.bazel index 44785fa1b8aba..35637ade5598a 100644 --- a/dev-infra/utils/BUILD.bazel +++ b/dev-infra/utils/BUILD.bazel @@ -5,6 +5,7 @@ ts_library( srcs = [ "config.ts", ], + module_name = "@angular/dev-infra-private/utils", visibility = ["//dev-infra:__subpackages__"], deps = [ "@npm//@types/json5", diff --git a/dev-infra/utils/config.ts b/dev-infra/utils/config.ts index ad92b8946fd50..78b165d223419 100644 --- a/dev-infra/utils/config.ts +++ b/dev-infra/utils/config.ts @@ -5,16 +5,15 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {parse} from 'json5'; import {readFileSync} from 'fs'; +import {parse} from 'json5'; import {join} from 'path'; import {exec} from 'shelljs'; - /** * Gets the path of the directory for the repository base. */ -function getRepoBaseDir() { +export function getRepoBaseDir() { const baseRepoDir = exec(`git rev-parse --show-toplevel`, {silent: true}); if (baseRepoDir.code) { throw Error( @@ -28,7 +27,7 @@ function getRepoBaseDir() { /** * Retrieve the configuration from the .dev-infra.json file. */ -export function getAngularDevConfig(): DevInfraConfig { +export function getAngularDevConfig(): DevInfraConfig { const configPath = join(getRepoBaseDir(), '.dev-infra.json'); let rawConfig = ''; try { @@ -41,5 +40,8 @@ export function getAngularDevConfig(): DevInfraConfig { return parse(rawConfig); } -// Interface exressing the expected structure of the DevInfraConfig. -export interface DevInfraConfig {} \ No newline at end of file +/** + * Interface exressing the expected structure of the DevInfraConfig. + * Allows for providing a typing for a part of the config to read. + */ +export interface DevInfraConfig { [K: string]: T; } From 912692137a02f718a7b78538d7ef3691b9936034 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor Date: Wed, 18 Mar 2020 14:23:02 -0400 Subject: [PATCH 003/262] fix(docs-infra): fix image name in example (#36127) Closes #35618 PR Close #36127 --- aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts | 2 +- aio/content/examples/interpolation/src/app/app.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts b/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts index 06def93fc6a1b..475e35c255c94 100644 --- a/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts +++ b/aio/content/examples/interpolation/e2e/src/app.e2e-spec.ts @@ -30,7 +30,7 @@ describe('Interpolation e2e tests', () => { let pottedPlant = element.all(by.css('img')).get(0); let lamp = element.all(by.css('img')).get(1); - expect(pottedPlant.getAttribute('src')).toContain('pottedPlant'); + expect(pottedPlant.getAttribute('src')).toContain('potted-plant'); expect(pottedPlant.isDisplayed()).toBe(true); expect(lamp.getAttribute('src')).toContain('lamp'); diff --git a/aio/content/examples/interpolation/src/app/app.component.ts b/aio/content/examples/interpolation/src/app/app.component.ts index 06bb18afc07c5..1fffef735a27d 100644 --- a/aio/content/examples/interpolation/src/app/app.component.ts +++ b/aio/content/examples/interpolation/src/app/app.component.ts @@ -12,7 +12,7 @@ export class AppComponent { currentCustomer = 'Maria'; title = 'Featured product:'; - itemImageUrl = '../assets/pottedPlant.png'; + itemImageUrl = '../assets/potted-plant.png'; recommended = 'You might also like:'; itemImageUrl2 = '../assets/lamp.png'; From d714b95fb97d752d1efd2c039d8d488f35fc18e3 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau Date: Tue, 17 Mar 2020 14:17:53 -0700 Subject: [PATCH 004/262] feat(compiler): Propagate value span of ExpressionBinding to ParsedProperty (#36133) This commit propagates the correct value span in an ExpressionBinding of a microsyntax expression to ParsedProperty, which in turn porpagates the span to the template ASTs (both VE and Ivy). PR Close #36133 --- .../compiler/src/template_parser/binding_parser.ts | 3 ++- packages/compiler/test/render3/r3_ast_spans_spec.ts | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/compiler/src/template_parser/binding_parser.ts b/packages/compiler/src/template_parser/binding_parser.ts index 3b0fa60c6d575..deec96edced1f 100644 --- a/packages/compiler/src/template_parser/binding_parser.ts +++ b/packages/compiler/src/template_parser/binding_parser.ts @@ -145,8 +145,9 @@ export class BindingParser { binding.value ? moveParseSourceSpan(sourceSpan, binding.value.span) : undefined; targetVars.push(new ParsedVariable(key, value, bindingSpan, keySpan, valueSpan)); } else if (binding.value) { + const valueSpan = moveParseSourceSpan(sourceSpan, binding.value.ast.sourceSpan); this._parsePropertyAst( - key, binding.value, sourceSpan, undefined, targetMatchableAttrs, targetProps); + key, binding.value, sourceSpan, valueSpan, targetMatchableAttrs, targetProps); } else { targetMatchableAttrs.push([key, '']); this.parseLiteralAttr( diff --git a/packages/compiler/test/render3/r3_ast_spans_spec.ts b/packages/compiler/test/render3/r3_ast_spans_spec.ts index 2352176974c34..c4553a5a9d451 100644 --- a/packages/compiler/test/render3/r3_ast_spans_spec.ts +++ b/packages/compiler/test/render3/r3_ast_spans_spec.ts @@ -232,8 +232,8 @@ describe('R3 AST source spans', () => { expectFromHtml('
').toEqual([ ['Template', '0:32', '0:32', '32:38'], ['TextAttribute', '5:31', ''], - ['BoundAttribute', '5:31', ''], - ['Variable', '13:22', ''], // let item + ['BoundAttribute', '5:31', '25:30'], // *ngFor="let item of items" -> items + ['Variable', '13:22', ''], // let item ['Element', '0:38', '0:32', '32:38'], ]); @@ -245,8 +245,8 @@ describe('R3 AST source spans', () => { // expectFromHtml('
').toEqual([ ['Template', '0:28', '0:28', '28:34'], - ['BoundAttribute', '5:27', ''], - ['BoundAttribute', '5:27', ''], + ['BoundAttribute', '5:27', '13:18'], // ngFor="item of items" -> item + ['BoundAttribute', '5:27', '21:26'], // ngFor="item of items" -> items ['Element', '0:34', '0:28', '28:34'], ]); }); @@ -263,8 +263,8 @@ describe('R3 AST source spans', () => { it('is correct for variables via as ...', () => { expectFromHtml('
').toEqual([ ['Template', '0:27', '0:27', '27:33'], - ['BoundAttribute', '5:26', ''], - ['Variable', '6:25', '6:10'], // ngIf="expr as local -> ngIf + ['BoundAttribute', '5:26', '12:17'], // ngIf="expr as local" -> expr + ['Variable', '6:25', '6:10'], // ngIf="expr as local -> ngIf ['Element', '0:33', '0:27', '27:33'], ]); }); From ae3eaf8b1682a005b237a44c927418176c5e42dc Mon Sep 17 00:00:00 2001 From: Keen Yee Liau Date: Fri, 20 Mar 2020 11:16:36 -0700 Subject: [PATCH 005/262] test(compiler): remove whitespace in spans (#36169) https://github.com/angular/angular/pull/36133 and https://github.com/angular/angular/pull/35986 caused a conflict in test after they both got merged to master. This PR fixes the failed tests. PR Close #36169 --- packages/compiler/test/render3/r3_ast_spans_spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compiler/test/render3/r3_ast_spans_spec.ts b/packages/compiler/test/render3/r3_ast_spans_spec.ts index c4553a5a9d451..e8e6931c49ee0 100644 --- a/packages/compiler/test/render3/r3_ast_spans_spec.ts +++ b/packages/compiler/test/render3/r3_ast_spans_spec.ts @@ -245,7 +245,7 @@ describe('R3 AST source spans', () => { // expectFromHtml('
').toEqual([ ['Template', '0:28', '0:28', '28:34'], - ['BoundAttribute', '5:27', '13:18'], // ngFor="item of items" -> item + ['BoundAttribute', '5:27', '13:17'], // ngFor="item of items" -> item ['BoundAttribute', '5:27', '21:26'], // ngFor="item of items" -> items ['Element', '0:34', '0:28', '28:34'], ]); @@ -263,7 +263,7 @@ describe('R3 AST source spans', () => { it('is correct for variables via as ...', () => { expectFromHtml('
').toEqual([ ['Template', '0:27', '0:27', '27:33'], - ['BoundAttribute', '5:26', '12:17'], // ngIf="expr as local" -> expr + ['BoundAttribute', '5:26', '12:16'], // ngIf="expr as local" -> expr ['Variable', '6:25', '6:10'], // ngIf="expr as local -> ngIf ['Element', '0:33', '0:27', '27:33'], ]); From 9cc8bd5f7de5362d27df0deb8b7b9c4364b92e96 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Thu, 19 Mar 2020 16:17:32 +0200 Subject: [PATCH 006/262] refactor(docs-infra): clean up `stackblitz-builder/builder.js` script (#36071) - Remove unused dependencies. - Change `var` to `const/let`. - Change regular functions as callbacks to arrow functions. - Remove unnecessary intermediate variables. - Switch from custom `_existsSync()` implementation to built-in `fs.existsSync()`. PR Close #36071 --- aio/tools/example-zipper/exampleZipper.js | 10 +- aio/tools/stackblitz-builder/builder.js | 211 +++++++++++----------- 2 files changed, 107 insertions(+), 114 deletions(-) diff --git a/aio/tools/example-zipper/exampleZipper.js b/aio/tools/example-zipper/exampleZipper.js index 1b055d67d1c64..563b0d7d5d477 100644 --- a/aio/tools/example-zipper/exampleZipper.js +++ b/aio/tools/example-zipper/exampleZipper.js @@ -132,7 +132,7 @@ class ExampleZipper { return basePath + file; }); - if (json.files[0].substr(0, 1) === '!') { + if (json.files[0][0] === '!') { json.files = defaultIncludes.concat(json.files); } } @@ -144,16 +144,16 @@ class ExampleZipper { let gpaths = json.files.map((fileName) => { fileName = fileName.trim(); - if (fileName.substr(0, 1) === '!') { + if (fileName[0] === '!') { return '!' + path.join(exampleDirName, fileName.substr(1)); } else { return path.join(exampleDirName, fileName); } }); - Array.prototype.push.apply(gpaths, alwaysExcludes); + gpaths.push(...alwaysExcludes); - let fileNames = globby.sync(gpaths, { ignore: ['**/node_modules/**']}); + let fileNames = globby.sync(gpaths, { ignore: ['**/node_modules/**'] }); let zip = this._createZipArchive(outputFileName); fileNames.forEach((fileName) => { @@ -165,7 +165,7 @@ class ExampleZipper { // zip.append(fs.createReadStream(fileName), { name: relativePath }); let output = regionExtractor()(content, extn).contents; - zip.append(output, { name: relativePath } ) + zip.append(output, { name: relativePath } ); }); // we need the package.json from _examples root, not the _boilerplate one diff --git a/aio/tools/stackblitz-builder/builder.js b/aio/tools/stackblitz-builder/builder.js index a804fa6ba7a23..58e702371ddef 100644 --- a/aio/tools/stackblitz-builder/builder.js +++ b/aio/tools/stackblitz-builder/builder.js @@ -1,14 +1,12 @@ 'use strict'; // Canonical path provides a consistent path (i.e. always forward slashes) across different OSes -var path = require('canonical-path'); -var Q = require('q'); -var _ = require('lodash'); -var jsdom = require("jsdom"); -var fs = require("fs-extra"); -var globby = require('globby'); +const path = require('canonical-path'); +const fs = require('fs-extra'); +const globby = require('globby'); +const jsdom = require('jsdom'); -var regionExtractor = require('../transforms/examples-package/services/region-parser'); +const regionExtractor = require('../transforms/examples-package/services/region-parser'); class StackblitzBuilder { constructor(basePath, destPath) { @@ -16,26 +14,24 @@ class StackblitzBuilder { this.destPath = destPath; // Extract npm package dependencies - var packageJson = require(path.join(__dirname, '../examples/shared/boilerplate/cli/package.json')); + const packageJson = require(path.join(__dirname, '../examples/shared/boilerplate/cli/package.json')); this.examplePackageDependencies = packageJson.dependencies; // Add unit test packages from devDependency for unit test examples - var devDependencies = packageJson.devDependencies; + const devDependencies = packageJson.devDependencies; this.examplePackageDependencies['jasmine-core'] = devDependencies['jasmine-core']; this.examplePackageDependencies['jasmine-marbles'] = devDependencies['jasmine-marbles']; - this.copyrights = {}; - - this._buildCopyrightStrings(); + this.copyrights = this._buildCopyrightStrings(); } build() { this._checkForOutdatedConfig(); // When testing it sometimes helps to look a just one example directory like so: - // var stackblitzPaths = path.join(this.basePath, '**/testing/*stackblitz.json'); - var stackblitzPaths = path.join(this.basePath, '**/*stackblitz.json'); - var fileNames = globby.sync(stackblitzPaths, { ignore: ['**/node_modules/**'] }); + // const stackblitzPaths = path.join(this.basePath, '**/testing/*stackblitz.json'); + const stackblitzPaths = path.join(this.basePath, '**/*stackblitz.json'); + const fileNames = globby.sync(stackblitzPaths, { ignore: ['**/node_modules/**'] }); fileNames.forEach((configFileName) => { try { // console.log('***'+configFileName) @@ -51,12 +47,15 @@ class StackblitzBuilder { } _buildCopyrightStrings() { - var copyright = 'Copyright Google LLC. All Rights Reserved.\n' + + const copyright = 'Copyright Google LLC. All Rights Reserved.\n' + 'Use of this source code is governed by an MIT-style license that\n' + 'can be found in the LICENSE file at http://angular.io/license'; - var pad = '\n\n'; - this.copyrights.jsCss = `${pad}/*\n${copyright}\n*/`; - this.copyrights.html = `${pad}`; + const pad = '\n\n'; + + return { + jsCss: `${pad}/*\n${copyright}\n*/`, + html: `${pad}`, + }; } // Build stackblitz from JSON configuration file (e.g., stackblitz.json): @@ -68,30 +67,29 @@ class StackblitzBuilder { // file: string - name of file to display within the stackblitz (e.g. `"file": "app/app.module.ts"`) _buildStackblitzFrom(configFileName) { // replace ending 'stackblitz.json' with 'stackblitz.no-link.html' to create output file name; - var outputFileName = `stackblitz.no-link.html`; - outputFileName = configFileName.replace(/stackblitz\.json$/, outputFileName); - var altFileName; + const outputFileName = configFileName.replace(/stackblitz\.json$/, 'stackblitz.no-link.html'); + let altFileName; if (this.destPath && this.destPath.length > 0) { - var partPath = path.dirname(path.relative(this.basePath, outputFileName)); - var altFileName = path.join(this.destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.'); + const partPath = path.dirname(path.relative(this.basePath, outputFileName)); + altFileName = path.join(this.destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.'); } try { - var config = this._initConfigAndCollectFileNames(configFileName); - var postData = this._createPostData(config, configFileName); + const config = this._initConfigAndCollectFileNames(configFileName); + const postData = this._createPostData(config, configFileName); this._addDependencies(postData); - var html = this._createStackblitzHtml(config, postData); + const html = this._createStackblitzHtml(config, postData); fs.writeFileSync(outputFileName, html, 'utf-8'); if (altFileName) { - var altDirName = path.dirname(altFileName); + const altDirName = path.dirname(altFileName); fs.ensureDirSync(altDirName); fs.writeFileSync(altFileName, html, 'utf-8'); } } catch (e) { // if we fail delete the outputFile if it exists because it is an old one. - if (this._existsSync(outputFileName)) { + if (fs.existsSync(outputFileName)) { fs.unlinkSync(outputFileName); } - if (altFileName && this._existsSync(altFileName)) { + if (altFileName && fs.existsSync(altFileName)) { fs.unlinkSync(altFileName); } throw e; @@ -100,8 +98,8 @@ class StackblitzBuilder { _checkForOutdatedConfig() { // Ensure that nobody is trying to use the old config filenames (i.e. `plnkr.json`). - var plunkerPaths = path.join(this.basePath, '**/*plnkr.json'); - var fileNames = globby.sync(plunkerPaths, { ignore: ['**/node_modules/**'] }); + const plunkerPaths = path.join(this.basePath, '**/*plnkr.json'); + const fileNames = globby.sync(plunkerPaths, { ignore: ['**/node_modules/**'] }); if (fileNames.length) { const readmePath = path.join(__dirname, 'README.md'); @@ -118,85 +116,87 @@ class StackblitzBuilder { _getPrimaryFile(config) { if (config.file) { - if (!this._existsSync(path.join(config.basePath, config.file))) { + if (!fs.existsSync(path.join(config.basePath, config.file))) { throw new Error(`The specified primary file (${config.file}) does not exist in '${config.basePath}'.`); } return config.file; } else { const defaultPrimaryFiles = ['src/app/app.component.html', 'src/app/app.component.ts', 'src/app/main.ts']; - const primaryFile = defaultPrimaryFiles.find(fileName => this._existsSync(path.join(config.basePath, fileName))); - + const primaryFile = defaultPrimaryFiles.find(fileName => fs.existsSync(path.join(config.basePath, fileName))); + if (!primaryFile) { throw new Error(`None of the default primary files (${defaultPrimaryFiles.join(', ')}) exists in '${config.basePath}'.`); } - + return primaryFile; } } _createBaseStackblitzHtml(config) { - var file = `?file=${this._getPrimaryFile(config)}`; - var action = `https://run.stackblitz.com/api/angular/v1${file}`; - var html = ` -
- - `; - return html; + const file = `?file=${this._getPrimaryFile(config)}`; + const action = `https://run.stackblitz.com/api/angular/v1${file}`; + + return ` + +
+ + + `.trim(); } _createPostData(config, configFileName) { - var postData = {}; + const postData = {}; // If `config.main` is specified, ensure that it points to an existing file. - if (config.main && !this._existsSync(path.join(config.basePath, config.main))) { + if (config.main && !fs.existsSync(path.join(config.basePath, config.main))) { throw Error(`The main file ('${config.main}') specified in '${configFileName}' does not exist.`); } config.fileNames.forEach((fileName) => { - var content; - var extn = path.extname(fileName); - if (extn == '.png') { + let content; + const extn = path.extname(fileName); + if (extn === '.png') { content = this._encodeBase64(fileName); - fileName = fileName.substr(0, fileName.length - 4) + '.base64.png' + fileName = `${fileName.slice(0, -extn.length)}.base64${extn}`; } else { content = fs.readFileSync(fileName, 'utf-8'); } - if (extn == '.js' || extn == '.ts' || extn == '.css') { + if (extn === '.js' || extn === '.ts' || extn === '.css') { content = content + this.copyrights.jsCss; - } else if (extn == '.html') { + } else if (extn === '.html') { content = content + this.copyrights.html; } - // var escapedValue = escapeHtml(content); + // const escapedValue = escapeHtml(content); - var relativeFileName = path.relative(config.basePath, fileName); + let relativeFileName = path.relative(config.basePath, fileName); // Is the main a custom index-xxx.html file? Rename it - if (relativeFileName == config.main) { + if (relativeFileName === config.main) { relativeFileName = 'src/index.html'; } // A custom main.ts file? Rename it if (/src\/main[-.]\w+\.ts$/.test(relativeFileName)) { - relativeFileName = 'src/main.ts' + relativeFileName = 'src/main.ts'; } - if (relativeFileName == 'index.html') { + if (relativeFileName === 'index.html') { if (config.description == null) { // set config.description to title from index.html - var matches = /(.*)<\/title>/.exec(content); + const matches = /<title>(.*)<\/title>/.exec(content); if (matches) { config.description = matches[1]; } @@ -208,28 +208,26 @@ class StackblitzBuilder { postData[`files[${relativeFileName}]`] = content; }); - var tags = ['angular', 'example'].concat(config.tags || []); - tags.forEach(function(tag,ix) { - postData['tags[' + ix + ']'] = tag; - }); + const tags = ['angular', 'example', ...config.tags || []]; + tags.forEach((tag, ix) => postData[`tags[${ix}]`] = tag); - postData.description = "Angular Example - " + config.description; + postData.description = `Angular Example - ${config.description}`; return postData; } _createStackblitzHtml(config, postData) { - var baseHtml = this._createBaseStackblitzHtml(config); - var doc = jsdom.jsdom(baseHtml); - var form = doc.querySelector('form'); - _.forEach(postData, (value, key) => { - var ele = this._htmlToElement(doc, '<input type="hidden" name="' + key + '">'); + const baseHtml = this._createBaseStackblitzHtml(config); + const doc = jsdom.jsdom(baseHtml); + const form = doc.querySelector('form'); + + for(const [key, value] of Object.entries(postData)) { + const ele = this._htmlToElement(doc, `<input type="hidden" name="${key}">`); ele.setAttribute('value', value); - form.appendChild(ele) - }); - var html = doc.documentElement.outerHTML; + form.appendChild(ele); + } - return html; + return doc.documentElement.outerHTML; } _encodeBase64(file) { @@ -237,36 +235,20 @@ class StackblitzBuilder { return fs.readFileSync(file, { encoding: 'base64' }); } - _existsSync(filename) { - try { - fs.accessSync(filename); - return true; - } catch(ex) { - return false; - } - } - _htmlToElement(document, html) { - var div = document.createElement('div'); + const div = document.createElement('div'); div.innerHTML = html; return div.firstChild; } _initConfigAndCollectFileNames(configFileName) { - var configDir = path.dirname(configFileName); - var configSrc = fs.readFileSync(configFileName, 'utf-8'); - try { - var config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; - config.basePath = configDir; // assumes 'stackblitz.json' is at `/src` level. - } catch (e) { - throw new Error(`Stackblitz config - unable to parse json file: ${configFileName}\n${e}`); - } + const config = this._parseConfig(configFileName); - var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg']; - var boilerplateIncludes = ['src/environments/*.*', 'angular.json', 'src/polyfills.ts']; + const defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg']; + const boilerplateIncludes = ['src/environments/*.*', 'angular.json', 'src/polyfills.ts']; if (config.files) { if (config.files.length > 0) { - if (config.files[0].substr(0, 1) == '!') { + if (config.files[0][0] === '!') { config.files = defaultIncludes.concat(config.files); } } @@ -275,10 +257,10 @@ class StackblitzBuilder { } config.files = config.files.concat(boilerplateIncludes); - var includeSpec = false; - var gpaths = config.files.map(function(fileName) { + let includeSpec = false; + const gpaths = config.files.map((fileName) => { fileName = fileName.trim(); - if (fileName.substr(0,1) == '!') { + if (fileName[0] === '!') { return '!' + path.join(config.basePath, fileName.substr(1)); } else { includeSpec = includeSpec || /\.spec\.(ts|js)$/.test(fileName); @@ -286,7 +268,7 @@ class StackblitzBuilder { } }); - var defaultExcludes = [ + const defaultExcludes = [ '!**/e2e/**/*.*', '!**/tsconfig.json', '!**/package.json', @@ -308,10 +290,21 @@ class StackblitzBuilder { gpaths.push(...defaultExcludes); - config.fileNames = globby.sync(gpaths, { ignore: ["**/node_modules/**"] }); + config.fileNames = globby.sync(gpaths, { ignore: ['**/node_modules/**'] }); return config; } + + _parseConfig(configFileName) { + try { + const configSrc = fs.readFileSync(configFileName, 'utf-8'); + const config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; + config.basePath = path.dirname(configFileName); // assumes 'stackblitz.json' is at `/src` level. + return config; + } catch (e) { + throw new Error(`Stackblitz config - unable to parse json file: ${configFileName}\n${e}`); + } + } } module.exports = StackblitzBuilder; From c21c46a8e8eb2c1327bd4b1ddc17fb42daed1dc5 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Thu, 19 Mar 2020 16:17:33 +0200 Subject: [PATCH 007/262] fix(docs-infra): include correct dependencies in StackBlitz examples (#36071) Previously, all StackBlitz examples included the default dependencies for `cli`-type projects. However, different example types may have different `package.json` files with different dependencies. For example, the [boilerplate `package.json`][1] for `elements` examples includes an extra dependency on `@angular/elements`. This commit changes `StackblitzBuilder` to use the dependencies that correspond to each example type. (NOTE: Manually verified the changes.) Jira issue: [FW-2002][2] [1]: https://github.com/angular/angular/blob/05d058622/aio/tools/examples/shared/boilerplate/elements/package.json [2]: https://angular-team.atlassian.net/browse/FW-2002 PR Close #36071 --- aio/tools/stackblitz-builder/builder.js | 42 ++++++++++++++++++------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/aio/tools/stackblitz-builder/builder.js b/aio/tools/stackblitz-builder/builder.js index 58e702371ddef..c5340962b9d20 100644 --- a/aio/tools/stackblitz-builder/builder.js +++ b/aio/tools/stackblitz-builder/builder.js @@ -13,16 +13,8 @@ class StackblitzBuilder { this.basePath = basePath; this.destPath = destPath; - // Extract npm package dependencies - const packageJson = require(path.join(__dirname, '../examples/shared/boilerplate/cli/package.json')); - this.examplePackageDependencies = packageJson.dependencies; - - // Add unit test packages from devDependency for unit test examples - const devDependencies = packageJson.devDependencies; - this.examplePackageDependencies['jasmine-core'] = devDependencies['jasmine-core']; - this.examplePackageDependencies['jasmine-marbles'] = devDependencies['jasmine-marbles']; - this.copyrights = this._buildCopyrightStrings(); + this._boilerplatePackageJsons = {}; } build() { @@ -42,8 +34,34 @@ class StackblitzBuilder { }); } - _addDependencies(postData) { - postData['dependencies'] = JSON.stringify(this.examplePackageDependencies); + _addDependencies(config, postData) { + // Extract npm package dependencies + const exampleType = this._getExampleType(config.basePath); + const packageJson = this._getBoilerplatePackageJson(exampleType) || this._getBoilerplatePackageJson('cli'); + const exampleDependencies = packageJson.dependencies; + + // Add unit test packages from devDependencies for unit test examples + const devDependencies = packageJson.devDependencies; + ['jasmine-core', 'jasmine-marbles'].forEach(dep => exampleDependencies[dep] = devDependencies[dep]); + + postData.dependencies = JSON.stringify(exampleDependencies); + } + + _getExampleType(exampleDir) { + const configPath = `${exampleDir}/example-config.json`; + const configSrc = fs.existsSync(configPath) && fs.readFileSync(configPath, 'utf-8').trim(); + const config = configSrc ? JSON.parse(configSrc) : {}; + + return config.projectType || 'cli'; + } + + _getBoilerplatePackageJson(exampleType) { + if (!this._boilerplatePackageJsons.hasOwnProperty(exampleType)) { + const pkgJsonPath = `${__dirname}/../examples/shared/boilerplate/${exampleType}/package.json`; + this._boilerplatePackageJsons[exampleType] = fs.existsSync(pkgJsonPath) ? require(pkgJsonPath) : null; + } + + return this._boilerplatePackageJsons[exampleType]; } _buildCopyrightStrings() { @@ -76,7 +94,7 @@ class StackblitzBuilder { try { const config = this._initConfigAndCollectFileNames(configFileName); const postData = this._createPostData(config, configFileName); - this._addDependencies(postData); + this._addDependencies(config, postData); const html = this._createStackblitzHtml(config, postData); fs.writeFileSync(outputFileName, html, 'utf-8'); if (altFileName) { From d25012e864f41be2ccb771522412804bdd8ee61a Mon Sep 17 00:00:00 2001 From: profanis <prodromouf@gmail.com> Date: Mon, 16 Mar 2020 21:53:44 +0200 Subject: [PATCH 008/262] docs(zone.js): Typos on zone.md file and fixes on code examples. (#36138) 1. During reading the documentation I found some code examples that were refering to the class properties via methods, but without specifying the context `this`. 2. The 'onInvoke' hook was duplicated 3. A minor typo on `Zones and execution contexts` section 4. A minor typo on `Zones and async lifecycle hooks` section PR Close #36138 --- aio/content/guide/zone.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/aio/content/guide/zone.md b/aio/content/guide/zone.md index 430ea0b7c5c57..9297acd1601ca 100644 --- a/aio/content/guide/zone.md +++ b/aio/content/guide/zone.md @@ -117,12 +117,13 @@ To understand how change detection works, first consider when the application ne }) export class AppComponent implements OnInit { data = 'initial value'; + serverUrl = 'SERVER_URL'; constructor(private httpClient: HttpClient) {} ngOnInit() { - this.httpClient.get(serverUrl).subscribe(response => { + this.httpClient.get(this.serverUrl).subscribe(response => { // user does not need to trigger change detection manually - data = response.data; + this.data = response.data; }); } } @@ -141,7 +142,7 @@ export class AppComponent implements OnInit { ngOnInit() { setTimeout(() => { // user does not need to trigger change detection manually - data = 'value updated'; + this.data = 'value updated'; }); } } @@ -160,7 +161,7 @@ export class AppComponent implements OnInit { ngOnInit() { Promise.resolve(1).then(v => { // user does not need to trigger change detection manually - data = v; + this.data = v; }); } } @@ -200,7 +201,7 @@ func.apply(ctx2); The value of `this` in the callback of `setTimeout` might differ depending on when `setTimeout` is called. Thus you can lose the context in asynchronous operations. -A zone provides a new zone context other than `this`, the zone context persists across asynchronous operations. +A zone provides a new zone context other than `this`, the zone context that persists across asynchronous operations. In the following example, the new zone context is called `zoneThis`. ```javascript @@ -257,16 +258,14 @@ The Zone Task concept is very similar to the Javascript VM Task concept. - `microTask`: such as `Promise.then()`. - `eventTask`: such as `element.addEventListener()`. -The `onInvoke` hook triggers when a synchronize function is executed in a Zone. - These hooks trigger under the following circumstances: - `onScheduleTask`: triggers when a new asynchronous task is scheduled, such as when you call `setTimeout()`. - `onInvokeTask`: triggers when an asynchronous task is about to execute, such as when the callback of `setTimeout()` is about to execute. - `onHasTask`: triggers when the status of one kind of task inside a zone changes from stable to unstable or from unstable to stable. A status of stable means there are no tasks inside the Zone, while unstable means a new task is scheduled in the zone. -- `onInvoke`: triggers when a synchronize function is going to execute in the zone. +- `onInvoke`: triggers when a synchronous function is going to execute in the zone. -With these hooks, `Zone` can monitor the status of all synchronize and asynchronous operations inside a zone. +With these hooks, `Zone` can monitor the status of all synchronous and asynchronous operations inside a zone. The above example returns the following output. From 528e25a81a90c828365a2df08328f55be01e421b Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Fri, 20 Mar 2020 12:36:13 +0000 Subject: [PATCH 009/262] build(docs-infra): upgrade cli command docs sources to f5dd5b16a (#36159) Updating [angular#master](https://github.com/angular/angular/tree/master) from [cli-builds#master](https://github.com/angular/cli-builds/tree/master). ## Relevant changes in [commit range](https://github.com/angular/cli-builds/compare/6aa3c134c...f5dd5b16a): **Modified** - help/update.json PR Close #36159 --- aio/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/package.json b/aio/package.json index f02a250f256d7..bb42c5ce7998c 100644 --- a/aio/package.json +++ b/aio/package.json @@ -23,7 +23,7 @@ "build-local-with-viewengine": "yarn ~~build", "prebuild-local-with-viewengine-ci": "node scripts/switch-to-viewengine && yarn setup-local-ci", "build-local-with-viewengine-ci": "yarn ~~build --progress=false", - "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 6aa3c134c", + "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js f5dd5b16a", "lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint", "test": "yarn check-env && ng test", "pree2e": "yarn check-env && yarn update-webdriver", From 0ce8ad3493b48495a5c2782973d45f4b9853b5c1 Mon Sep 17 00:00:00 2001 From: Filipe Silva <filipematossilva@gmail.com> Date: Mon, 23 Mar 2020 13:16:36 +0000 Subject: [PATCH 010/262] fix(core): workaround Terser inlining bug (#36200) This variable name change works around https://github.com/terser/terser/issues/615, which was causing the JIT production tests to fail in the Angular CLI repository (https://github.com/angular/angular-cli/issues/17264). PR Close #36200 --- packages/core/src/render3/jit/directive.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index e77baf8d46d11..06398cb75cb02 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -69,19 +69,23 @@ export function compileComponent(type: Type<any>, metadata: Component): void { throw new Error(error.join('\n')); } - const jitOptions = getJitOptions(); + // This const was called `jitOptions` previously but had to be renamed to `options` because + // of a bug with Terser that caused optimized JIT builds to throw a `ReferenceError`. + // This bug was investigated in https://github.com/angular/angular-cli/issues/17264. + // We should not rename it back until https://github.com/terser/terser/issues/615 is fixed. + const options = getJitOptions(); let preserveWhitespaces = metadata.preserveWhitespaces; if (preserveWhitespaces === undefined) { - if (jitOptions !== null && jitOptions.preserveWhitespaces !== undefined) { - preserveWhitespaces = jitOptions.preserveWhitespaces; + if (options !== null && options.preserveWhitespaces !== undefined) { + preserveWhitespaces = options.preserveWhitespaces; } else { preserveWhitespaces = false; } } let encapsulation = metadata.encapsulation; if (encapsulation === undefined) { - if (jitOptions !== null && jitOptions.defaultEncapsulation !== undefined) { - encapsulation = jitOptions.defaultEncapsulation; + if (options !== null && options.defaultEncapsulation !== undefined) { + encapsulation = options.defaultEncapsulation; } else { encapsulation = ViewEncapsulation.Emulated; } From 85e0e366df884f69d5c3806371084b0375a5dce9 Mon Sep 17 00:00:00 2001 From: Abraham Williams <4braham@gmail.com> Date: Sat, 21 Mar 2020 09:51:32 -0500 Subject: [PATCH 011/262] docs(elements): Edge supports Web Components (#36182) PR Close #36182 --- aio/content/guide/elements.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/aio/content/guide/elements.md b/aio/content/guide/elements.md index 97e436613255d..0c409a9085977 100644 --- a/aio/content/guide/elements.md +++ b/aio/content/guide/elements.md @@ -2,7 +2,7 @@ _Angular elements_ are Angular components packaged as _custom elements_ (also called Web Components), a web standard for defining new HTML elements in a framework-agnostic way. -[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Firefox, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)). +[Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Edge (Chromium-based), Firefox, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)). A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code. The browser maintains a `CustomElementRegistry` of defined custom elements, which maps an instantiable JavaScript class to an HTML tag. @@ -82,7 +82,7 @@ For more information, see Web Component documentation for [Creating custom event ## Browser support for custom elements -The recently-developed [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) Web Platform feature is currently supported natively in a number of browsers. Support is pending or planned in other browsers. +The recently-developed [custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) Web Platform feature is currently supported natively in a number of browsers. <table> <tr> @@ -94,22 +94,20 @@ The recently-developed [custom elements](https://developer.mozilla.org/en-US/doc <td>Supported natively.</td> </tr> <tr> - <td>Opera</td> + <td>Edge (Chromium-based)</td> <td>Supported natively.</td> </tr> <tr> - <td>Safari</td> + <td>Firefox</td> <td>Supported natively.</td> </tr> <tr> - <td>Firefox</td> + <td>Opera</td> <td>Supported natively.</td> </tr> <tr> - <td>Edge</td> - <td>Working on an implementation. <br> - - </td> + <td>Safari</td> + <td>Supported natively.</td> </tr> </table> From c3a85ceabc0e9568ead559f5f84a1d5c26e86bef Mon Sep 17 00:00:00 2001 From: Aristeidis Bampakos <bampakoa@gmail.com> Date: Fri, 20 Mar 2020 23:13:33 +0200 Subject: [PATCH 012/262] docs: Change important alert of ngFor (#36176) Update the important alert of ngFor so that it has a unique format with that of ngIf PR Close #36176 --- aio/content/guide/displaying-data.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/displaying-data.md b/aio/content/guide/displaying-data.md index 8229ed3e84e54..4c2fb65e5493d 100644 --- a/aio/content/guide/displaying-data.md +++ b/aio/content/guide/displaying-data.md @@ -153,7 +153,7 @@ It marks that `<li>` element (and its children) as the "repeater template": <div class="alert is-important"> Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax. -For more information, see the [Template Syntax](guide/template-syntax#ngFor) page. +Read more about `ngFor` and `*` in the [ngFor section](guide/template-syntax#ngfor) of the [Template Syntax](guide/template-syntax) page. </div> From e81ad3a1bceed447e4d4c60ae548aa97415859b2 Mon Sep 17 00:00:00 2001 From: Aristeidis Bampakos <bampakoa@gmail.com> Date: Sat, 21 Mar 2020 18:58:42 +0200 Subject: [PATCH 013/262] docs: Add asterisk info in template syntax guide (#36176) Add helpful alert for asterisk syntax in the `ngFor` section of template syntax guide PR Close #36176 --- aio/content/guide/template-syntax.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index f24bf54e9a576..71a20f730c77e 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -1600,6 +1600,14 @@ The following example shows `NgFor` applied to a simple `<div>`. (Don't forget t <code-example path="built-in-directives/src/app/app.component.html" region="NgFor-1" header="src/app/app.component.html"></code-example> +<div class="alert is-helpful"> + +Don't forget the asterisk (`*`) in front of `ngFor`. For more information +on the asterisk, see the [asterisk (*) prefix](guide/structural-directives#the-asterisk--prefix) section of +[Structural Directives](guide/structural-directives). + +</div> + You can also apply an `NgFor` to a component element, as in the following example. <code-example path="built-in-directives/src/app/app.component.html" region="NgFor-2" header="src/app/app.component.html"></code-example> From 0e76b32aa55537056cd8541fbe297b2d41c792e8 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Fri, 20 Mar 2020 10:17:42 -0700 Subject: [PATCH 014/262] fix(dev-infra): prep ts-circular-deps to load via node_modules (#36165) to run ts-circular-deps via installed node_modules, we needed to set the hashbang of the script to be a node environment, and discover the project directory based on where the script is run rather than the scripts file location. PR Close #36165 --- dev-infra/ts-circular-dependencies/BUILD.bazel | 1 + dev-infra/ts-circular-dependencies/index.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dev-infra/ts-circular-dependencies/BUILD.bazel b/dev-infra/ts-circular-dependencies/BUILD.bazel index d7c8d6f7e6968..d438b66bd58f9 100644 --- a/dev-infra/ts-circular-dependencies/BUILD.bazel +++ b/dev-infra/ts-circular-dependencies/BUILD.bazel @@ -6,6 +6,7 @@ ts_library( module_name = "@angular/dev-infra-private/ts-circular-dependencies", visibility = ["//dev-infra:__subpackages__"], deps = [ + "//dev-infra/utils:config", "@npm//@types/glob", "@npm//@types/node", "@npm//@types/yargs", diff --git a/dev-infra/ts-circular-dependencies/index.ts b/dev-infra/ts-circular-dependencies/index.ts index d3db5016b4edb..9dc9879c378db 100644 --- a/dev-infra/ts-circular-dependencies/index.ts +++ b/dev-infra/ts-circular-dependencies/index.ts @@ -1,3 +1,4 @@ +#!/usr/bin/env node /** * @license * Copyright Google Inc. All Rights Reserved. @@ -17,7 +18,9 @@ import {Analyzer, ReferenceChain} from './analyzer'; import {compareGoldens, convertReferenceChainToGolden, Golden} from './golden'; import {convertPathToForwardSlash} from './file_system'; -const projectDir = join(__dirname, '../../'); +import {getRepoBaseDir} from '../utils/config'; + +const projectDir = getRepoBaseDir(); const packagesDir = join(projectDir, 'packages/'); // The default glob does not capture deprecated packages such as http, or the webworker platform. const defaultGlob = From 1cb7b88505f2c54557d1e18975b2b7d76cb1021b Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 23 Mar 2020 07:29:48 -0700 Subject: [PATCH 015/262] fix(dev-infra): change circular deps positional params to camelCase (#36165) Changes the positional params for the circular deps tooling to use camelCase as it requires being defined in camelCase while in strict mode. Additionally, remove the `version()` call as the boolean arguement does not exist in current versions and throws errors on execution. PR Close #36165 --- dev-infra/ts-circular-dependencies/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dev-infra/ts-circular-dependencies/index.ts b/dev-infra/ts-circular-dependencies/index.ts index 9dc9879c378db..f55d8be5c0a73 100644 --- a/dev-infra/ts-circular-dependencies/index.ts +++ b/dev-infra/ts-circular-dependencies/index.ts @@ -29,10 +29,9 @@ const defaultGlob = if (require.main === module) { const {_: command, goldenFile, glob, baseDir, warnings} = yargs.help() - .version(false) .strict() - .command('check <golden-file>', 'Checks if the circular dependencies have changed.') - .command('approve <golden-file>', 'Approves the current circular dependencies.') + .command('check <goldenFile>', 'Checks if the circular dependencies have changed.') + .command('approve <goldenFile>', 'Approves the current circular dependencies.') .demandCommand() .option( 'approve', From fced8ee40e08854c85cb46e5cfa26f995892cde9 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Wed, 18 Mar 2020 07:39:48 -0400 Subject: [PATCH 016/262] fix(localize): allow ICU expansion case to start with any character except `}` (#36123) Previously, an expansion case could only start with an alpha numeric character. This commit fixes this by allowing an expansion case to start with any character except `}`. The [ICU spec](http://userguide.icu-project.org/formatparse/messages) is pretty vague: > Use a "select" argument to select sub-messages via a fixed set of keywords. It does not specify what can be a "keyword" but from looking at the surrounding syntax it appears that it can indeed be any string that does not contain a `}` character. Closes #31586 PR Close #36123 --- packages/compiler/src/ml_parser/lexer.ts | 2 +- .../test/ml_parser/html_parser_spec.ts | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/ml_parser/lexer.ts b/packages/compiler/src/ml_parser/lexer.ts index af02426e53116..98ff8f423b5c4 100644 --- a/packages/compiler/src/ml_parser/lexer.ts +++ b/packages/compiler/src/ml_parser/lexer.ts @@ -747,7 +747,7 @@ function isNamedEntityEnd(code: number): boolean { } function isExpansionCaseStart(peek: number): boolean { - return peek === chars.$EQ || chars.isAsciiLetter(peek) || chars.isDigit(peek); + return peek !== chars.$RBRACE; } function compareCharCodeCaseInsensitive(code1: number, code2: number): boolean { diff --git a/packages/compiler/test/ml_parser/html_parser_spec.ts b/packages/compiler/test/ml_parser/html_parser_spec.ts index 3cc1b893532cd..9972bd690e890 100644 --- a/packages/compiler/test/ml_parser/html_parser_spec.ts +++ b/packages/compiler/test/ml_parser/html_parser_spec.ts @@ -313,6 +313,26 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe expect(p.errors.length).toEqual(0); }); + it(`should support ICU expressions with cases that contain any character except '}'`, + () => { + const p = parser.parse( + `{a, select, b {foo} % bar {% bar}}`, 'TestComp', {tokenizeExpansionForms: true}); + expect(p.errors.length).toEqual(0); + }); + + it('should error when expansion case is not properly closed', () => { + const p = parser.parse( + `{a, select, b {foo} % { bar {% bar}}`, 'TestComp', {tokenizeExpansionForms: true}); + expect(humanizeErrors(p.errors)).toEqual([ + [ + 6, + 'Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ \'{\' }}") to escape it.)', + '0:36' + ], + [null, 'Invalid ICU message. Missing \'}\'.', '0:22'] + ]); + }); + it('should error when expansion case is not closed', () => { const p = parser.parse( `{messages.length, plural, =0 {one`, 'TestComp', {tokenizeExpansionForms: true}); From 9d415f9c3f12cb2c29298ba414f55ce230201700 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Thu, 20 Feb 2020 22:18:23 -0500 Subject: [PATCH 017/262] fix(docs-infra): change `app-list-item` to `app-item-list` (#35601) The `app-list-item` component sounds like it is used for a single item, however it renders a list of items. There were also several changes in the documentation, where it was becoming confusing if the `app-list-item` is using a single item or multiple items. This commit fixes this issue. It renames the component and its respective properties to make sure that the intention is very clear. Closes #35598 PR Close #35601 --- .../property-binding/src/app/app.component.html | 2 +- .../property-binding/src/app/app.component.ts | 2 +- .../property-binding/src/app/app.module.ts | 4 ++-- .../item-list.component.css} | 0 .../item-list.component.html} | 0 .../item-list.component.spec.ts} | 10 +++++----- .../item-list.component.ts} | 8 ++++---- aio/content/guide/template-syntax.md | 14 +++++++------- 8 files changed, 20 insertions(+), 20 deletions(-) rename aio/content/examples/property-binding/src/app/{list-item/list-item.component.css => item-list/item-list.component.css} (100%) rename aio/content/examples/property-binding/src/app/{list-item/list-item.component.html => item-list/item-list.component.html} (100%) rename aio/content/examples/property-binding/src/app/{list-item/list-item.component.spec.ts => item-list/item-list.component.spec.ts} (61%) rename aio/content/examples/property-binding/src/app/{list-item/list-item.component.ts => item-list/item-list.component.ts} (63%) diff --git a/aio/content/examples/property-binding/src/app/app.component.html b/aio/content/examples/property-binding/src/app/app.component.html index e6ca6e5b0ae0c..4e88175854f17 100644 --- a/aio/content/examples/property-binding/src/app/app.component.html +++ b/aio/content/examples/property-binding/src/app/app.component.html @@ -46,7 +46,7 @@ <h2>Model property of a custom component:</h2> <h3>Pass objects:</h3> <!-- #docregion pass-object --> - <app-list-item [items]="currentItem"></app-list-item> + <app-item-list [items]="currentItems"></app-item-list> <!-- #enddocregion pass-object --> <hr /> diff --git a/aio/content/examples/property-binding/src/app/app.component.ts b/aio/content/examples/property-binding/src/app/app.component.ts index c8dd3b5fe4d30..cfe9abe4ddaaf 100644 --- a/aio/content/examples/property-binding/src/app/app.component.ts +++ b/aio/content/examples/property-binding/src/app/app.component.ts @@ -15,7 +15,7 @@ export class AppComponent { // #enddocregion parent-data-type // #docregion pass-object - currentItem = [{ + currentItems = [{ id: 21, name: 'phone' }]; diff --git a/aio/content/examples/property-binding/src/app/app.module.ts b/aio/content/examples/property-binding/src/app/app.module.ts index 24c86b6bcfc98..eee2b65f4b3d4 100644 --- a/aio/content/examples/property-binding/src/app/app.module.ts +++ b/aio/content/examples/property-binding/src/app/app.module.ts @@ -4,7 +4,7 @@ import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { ItemDetailComponent } from './item-detail/item-detail.component'; -import { ListItemComponent } from './list-item/list-item.component'; +import { ItemListComponent } from './item-list/item-list.component'; import { StringInitComponent } from './string-init/string-init.component'; @@ -12,7 +12,7 @@ import { StringInitComponent } from './string-init/string-init.component'; declarations: [ AppComponent, ItemDetailComponent, - ListItemComponent, + ItemListComponent, StringInitComponent ], imports: [ diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.css b/aio/content/examples/property-binding/src/app/item-list/item-list.component.css similarity index 100% rename from aio/content/examples/property-binding/src/app/list-item/list-item.component.css rename to aio/content/examples/property-binding/src/app/item-list/item-list.component.css diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.html b/aio/content/examples/property-binding/src/app/item-list/item-list.component.html similarity index 100% rename from aio/content/examples/property-binding/src/app/list-item/list-item.component.html rename to aio/content/examples/property-binding/src/app/item-list/item-list.component.html diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts b/aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts similarity index 61% rename from aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts rename to aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts index 0568b6c4c24a9..e11a57d78cd9e 100644 --- a/aio/content/examples/property-binding/src/app/list-item/list-item.component.spec.ts +++ b/aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { ListItemComponent } from './list-item.component'; +import { ItemListComponent } from './item-list.component'; describe('ItemListComponent', () => { - let component: ListItemComponent; - let fixture: ComponentFixture<ListItemComponent>; + let component: ItemListComponent; + let fixture: ComponentFixture<ItemListComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ ListItemComponent ] + declarations: [ ItemListComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(ListItemComponent); + fixture = TestBed.createComponent(ItemListComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/aio/content/examples/property-binding/src/app/list-item/list-item.component.ts b/aio/content/examples/property-binding/src/app/item-list/item-list.component.ts similarity index 63% rename from aio/content/examples/property-binding/src/app/list-item/list-item.component.ts rename to aio/content/examples/property-binding/src/app/item-list/item-list.component.ts index 48d1992cde8b2..38d29e0f64807 100644 --- a/aio/content/examples/property-binding/src/app/list-item/list-item.component.ts +++ b/aio/content/examples/property-binding/src/app/item-list/item-list.component.ts @@ -3,11 +3,11 @@ import { ITEMS } from '../mock-items'; import { Item } from '../item'; @Component({ - selector: 'app-list-item', - templateUrl: './list-item.component.html', - styleUrls: ['./list-item.component.css'] + selector: 'app-item-list', + templateUrl: './item-list.component.html', + styleUrls: ['./item-list.component.css'] }) -export class ListItemComponent { +export class ItemListComponent { listItems = ITEMS; // #docregion item-input @Input() items: Item[]; diff --git a/aio/content/guide/template-syntax.md b/aio/content/guide/template-syntax.md index 71a20f730c77e..1cbcf49ba393e 100644 --- a/aio/content/guide/template-syntax.md +++ b/aio/content/guide/template-syntax.md @@ -730,13 +730,13 @@ As you can see here, the `parentItem` in `AppComponent` is a string, which the ` The previous simple example showed passing in a string. To pass in an object, the syntax and thinking are the same. -In this scenario, `ListItemComponent` is nested within `AppComponent` and the `items` property expects an array of objects. +In this scenario, `ItemListComponent` is nested within `AppComponent` and the `items` property expects an array of objects. <code-example path="property-binding/src/app/app.component.html" region="pass-object" header="src/app/app.component.html"></code-example> -The `items` property is declared in the `ListItemComponent` with a type of `Item` and decorated with `@Input()`: +The `items` property is declared in the `ItemListComponent` with a type of `Item` and decorated with `@Input()`: -<code-example path="property-binding/src/app/list-item/list-item.component.ts" region="item-input" header="src/app/list-item.component.ts"></code-example> +<code-example path="property-binding/src/app/item-list/item-list.component.ts" region="item-input" header="src/app/item-list.component.ts"></code-example> In this sample app, an `Item` is an object that has two properties; an `id` and a `name`. @@ -747,11 +747,11 @@ specify a different item in `app.component.ts` so that the new item will render: <code-example path="property-binding/src/app/app.component.ts" region="pass-object" header="src/app.component.ts"></code-example> -You just have to make sure, in this case, that you're supplying an array of objects because that's the type of `items` and is what the nested component, `ListItemComponent`, expects. +You just have to make sure, in this case, that you're supplying an array of objects because that's the type of `Item` and is what the nested component, `ItemListComponent`, expects. In this example, `AppComponent` specifies a different `item` object -(`currentItem`) and passes it to the nested `ListItemComponent`. `ListItemComponent` was able to use `currentItem` because it matches what an `Item` object is according to `item.ts`. The `item.ts` file is where -`ListItemComponent` gets its definition of an `item`. +(`currentItems`) and passes it to the nested `ItemListComponent`. `ItemListComponent` was able to use `currentItems` because it matches what an `Item` object is according to `item.ts`. The `item.ts` file is where +`ItemListComponent` gets its definition of an `item`. ### Remember the brackets @@ -780,7 +780,7 @@ not a template expression. Angular sets it and forgets about it. <code-example path="property-binding/src/app/app.component.html" region="string-init" header="src/app/app.component.html"></code-example> -The `[item]` binding, on the other hand, remains a live binding to the component's `currentItem` property. +The `[item]` binding, on the other hand, remains a live binding to the component's `currentItems` property. ### Property binding vs. interpolation From 4419907b08948b9f7b3b835658d319a4573ea374 Mon Sep 17 00:00:00 2001 From: Misko Hevery <misko@hevery.com> Date: Mon, 23 Mar 2020 13:22:17 -0700 Subject: [PATCH 018/262] docs: release notes for the v9.1.0-rc.1 release --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e30aa0de86a..8d3522e593426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +<a name="9.1.0-rc.1"></a> +# [9.1.0-rc.1](https://github.com/angular/angular/compare/9.1.0-rc.0...9.1.0-rc.1) (2020-03-23) + + +### Bug Fixes + +* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477) +* **core:** workaround Terser inlining bug ([#36200](https://github.com/angular/angular/issues/36200)) ([f71d132](https://github.com/angular/angular/commit/f71d132)) +* **localize:** allow ICU expansion case to start with any character except `}` ([#36123](https://github.com/angular/angular/issues/36123)) ([0767d37](https://github.com/angular/angular/commit/0767d37)), closes [#31586](https://github.com/angular/angular/issues/31586) +* **compiler:** Propagate value span of ExpressionBinding to ParsedProperty ([#36133](https://github.com/angular/angular/issues/36133)) ([2ce5fa3](https://github.com/angular/angular/commit/2ce5fa3)) + + <a name="9.1.0-rc.0"></a> # [9.1.0-rc.0](https://github.com/angular/angular/compare/9.1.0-next.5...9.1.0-rc.0) (2020-03-19) From 58f4254fba04abbd0876bb3d6318d43ca1f5c3f1 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Tue, 10 Mar 2020 12:33:18 -0700 Subject: [PATCH 019/262] fix(dev-infra): use @angular/dev-infra-private package for pullapprove verification (#35996) Adds devDependency on @angular/dev-infra-private and removes the verify script from tools, relying instead on the script from ng-dev. PR Close #35996 --- .circleci/config.yml | 2 +- .pullapprove.yml | 1 - package.json | 1 + tools/pullapprove/verify.js | 206 ------------------------------------ yarn.lock | 4 + 5 files changed, 6 insertions(+), 208 deletions(-) delete mode 100644 tools/pullapprove/verify.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 3a31a29a46a38..2a73417bdc414 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -280,7 +280,7 @@ jobs: - run: yarn lint - run: yarn ts-circular-deps:check - - run: node tools/pullapprove/verify.js + - run: yarn -s ng-dev pullapprove:verify test: executor: diff --git a/.pullapprove.yml b/.pullapprove.yml index 480e472baba95..1f63de638543a 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -958,7 +958,6 @@ groups: 'tools/ngcontainer/**', 'tools/npm/**', 'tools/npm_integration_test/**', - 'tools/pullapprove/**', 'tools/rxjs/**', 'tools/saucelabs/**', 'tools/size-tracking/**', diff --git a/package.json b/package.json index 0a20382a83dfb..5a831ab9b6f1c 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,7 @@ "// 2": "devDependencies are not used under Bazel. Many can be removed after test.sh is deleted.", "devDependencies": { "@angular/cli": "9.0.3", + "@angular/dev-infra-private": "angular/dev-infra-private-builds#3724a71", "@bazel/bazelisk": "^1.3.0", "@bazel/buildifier": "^0.29.0", "@bazel/ibazel": "^0.12.3", diff --git a/tools/pullapprove/verify.js b/tools/pullapprove/verify.js deleted file mode 100644 index 35b3c54010209..0000000000000 --- a/tools/pullapprove/verify.js +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env node -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -/* tslint:disable:no-console */ -const parseYaml = require('yaml').parse; -const readFileSync = require('fs').readFileSync; -const Minimatch = require('minimatch').Minimatch; -const {exec, set, cd} = require('shelljs'); -const path = require('path'); - -// Exit early on shelljs errors -set('-e'); - -// Regex Matcher for contains_any_globs conditions -const CONTAINS_ANY_GLOBS_REGEX = /^'([^']+)',?$/; - -// Full path of the angular project directory -const ANGULAR_PROJECT_DIR = path.resolve(__dirname, '../..'); -// Change to the Angular project directory -cd(ANGULAR_PROJECT_DIR); - -// Whether to log verbosely -const VERBOSE_MODE = process.argv.includes('-v'); -// Full path to PullApprove config file -const PULL_APPROVE_YAML_PATH = path.resolve(ANGULAR_PROJECT_DIR, '.pullapprove.yml'); -// All relative path file names in the git repo, this is retrieved using git rather -// that a glob so that we only get files that are checked in, ignoring things like -// node_modules, .bazelrc.user, etc -const ALL_FILES = exec('git ls-tree --full-tree -r --name-only HEAD', {silent: true}) - .trim() - .split('\n') - .filter(_ => _); -if (!ALL_FILES.length) { - console.error( - `No files were found to be in the git tree, did you run this command from \n` + - `inside the angular repository?`); - process.exit(1); -} - -/** Gets the glob matching information from each group's condition. */ -function getGlobMatchersFromCondition(groupName, condition) { - const trimmedCondition = condition.trim(); - const globMatchers = []; - const badConditionLines = []; - - // If the condition starts with contains_any_globs, evaluate all of the globs - if (trimmedCondition.startsWith('contains_any_globs')) { - trimmedCondition.split('\n') - .slice(1, -1) - .map(glob => { - const trimmedGlob = glob.trim(); - const match = trimmedGlob.match(CONTAINS_ANY_GLOBS_REGEX); - if (!match) { - badConditionLines.push(trimmedGlob); - return; - } - return match[1]; - }) - .filter(globString => !!globString) - .forEach(globString => globMatchers.push({ - group: groupName, - glob: globString, - matcher: new Minimatch(globString, {dot: true}), - matchCount: 0, - })); - } - return [globMatchers, badConditionLines]; -} - -/** Create logs for each review group. */ -function logGroups(groups) { - Array.from(groups.entries()).sort().forEach(([groupName, globs]) => { - console.groupCollapsed(groupName); - Array.from(globs.values()) - .sort((a, b) => b.matchCount - a.matchCount) - .forEach(glob => console.log(`${glob.glob} - ${glob.matchCount}`)); - console.groupEnd(); - }); -} - -/** Logs a header within a text drawn box. */ -function logHeader(...params) { - const totalWidth = 80; - const fillWidth = totalWidth - 2; - const headerText = params.join(' ').substr(0, fillWidth); - const leftSpace = Math.ceil((fillWidth - headerText.length) / 2); - const rightSpace = fillWidth - leftSpace - headerText.length; - const fill = (count, content) => content.repeat(count); - - console.log(`┌${fill(fillWidth, '─')}┐`); - console.log(`│${fill(leftSpace, ' ')}${headerText}${fill(rightSpace, ' ')}│`); - console.log(`└${fill(fillWidth, '─')}┘`); -} - -/** Runs the pull approve verification check on provided files. */ -function runVerification(files) { - // All of the globs created for each group's conditions. - const allGlobs = []; - // The pull approve config file. - const pullApprove = readFileSync(PULL_APPROVE_YAML_PATH, {encoding: 'utf8'}); - // All of the PullApprove groups, parsed from the PullApprove yaml file. - const parsedPullApproveGroups = parseYaml(pullApprove).groups; - // All files which were found to match a condition in PullApprove. - const matchedFiles = new Set(); - // All files which were not found to match a condition in PullApprove. - const unmatchedFiles = new Set(); - // All PullApprove groups which matched at least one file. - const matchedGroups = new Map(); - // All PullApprove groups which did not match at least one file. - const unmatchedGroups = new Map(); - // All condition lines which were not able to be correctly parsed, by group. - const badConditionLinesByGroup = new Map(); - // Total number of condition lines which were not able to be correctly parsed. - let badConditionLineCount = 0; - - // Get all of the globs from the PullApprove group conditions. - Object.entries(parsedPullApproveGroups).map(([groupName, group]) => { - for (const condition of group.conditions) { - const [matchers, badConditions] = getGlobMatchersFromCondition(groupName, condition); - if (badConditions.length) { - badConditionLinesByGroup.set(groupName, badConditions); - badConditionLineCount += badConditions.length; - } - allGlobs.push(...matchers); - } - }); - - if (badConditionLineCount) { - console.log(`Discovered ${badConditionLineCount} parsing errors in PullApprove conditions`); - console.log(`Attempted parsing using: ${CONTAINS_ANY_GLOBS_REGEX}`); - console.log(); - console.log(`Unable to properly parse the following line(s) by group:`); - for (const [groupName, badConditionLines] of badConditionLinesByGroup.entries()) { - console.log(`- ${groupName}:`); - badConditionLines.forEach(line => console.log(` ${line}`)); - } - console.log(); - console.log( - `Please correct the invalid conditions, before PullApprove verification can be completed`); - process.exit(1); - } - - // Check each file for if it is matched by a PullApprove condition. - for (let file of files) { - const matched = allGlobs.filter(glob => glob.matcher.match(file)); - matched.length ? matchedFiles.add(file) : unmatchedFiles.add(file); - matched.forEach(glob => glob.matchCount++); - } - - // Add each glob for each group to a map either matched or unmatched. - allGlobs.forEach(glob => { - const groups = glob.matchCount ? matchedGroups : unmatchedGroups; - const globs = groups.get(glob.group) || new Map(); - // Set the globs map in the groups map - groups.set(glob.group, globs); - // Set the glob in the globs map - globs.set(glob.glob, glob); - }); - - // PullApprove is considered verified if no files or groups are found to be unsed. - const verificationSucceeded = !(unmatchedFiles.size || unmatchedGroups.size); - - /** - * Overall result - */ - logHeader('Result'); - if (verificationSucceeded) { - console.log('PullApprove verification succeeded!'); - } else { - console.log(`PullApprove verification failed.\n`); - console.log(`Please update '.pullapprove.yml' to ensure that all necessary`); - console.log(`files/directories have owners and all patterns that appear in`); - console.log(`the file correspond to actual files/directories in the repo.`); - } - /** - * File by file Summary - */ - logHeader('PullApprove file match results'); - console.groupCollapsed(`Matched Files (${matchedFiles.size} files)`); - VERBOSE_MODE && matchedFiles.forEach(file => console.log(file)); - console.groupEnd(); - console.groupCollapsed(`Unmatched Files (${unmatchedFiles.size} files)`); - unmatchedFiles.forEach(file => console.log(file)); - console.groupEnd(); - - /** - * Group by group Summary - */ - logHeader('PullApprove group matches'); - console.groupCollapsed(`Matched Groups (${matchedGroups.size} groups)`); - VERBOSE_MODE && logGroups(matchedGroups); - console.groupEnd(); - console.groupCollapsed(`Unmatched Groups (${unmatchedGroups.size} groups)`); - logGroups(unmatchedGroups); - console.groupEnd(); - - // Provide correct exit code based on verification success. - process.exit(verificationSucceeded ? 0 : 1); -} - -runVerification(ALL_FILES); diff --git a/yarn.lock b/yarn.lock index 832618fa93299..19c11e9b38a20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -153,6 +153,10 @@ universal-analytics "^0.4.20" uuid "^3.3.2" +"@angular/dev-infra-private@angular/dev-infra-private-builds#3724a71": + version "0.0.0" + resolved "https://codeload.github.com/angular/dev-infra-private-builds/tar.gz/3724a71047361d85f4131d990f00a5aecdbc3ddc" + "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" From a323b9b1a37bcf0034716193cc40e13638522d3f Mon Sep 17 00:00:00 2001 From: Pawel Kozlowski <pkozlowski.opensource@gmail.com> Date: Mon, 9 Mar 2020 15:34:01 +0100 Subject: [PATCH 020/262] test(core): re-enable IE 10/11 test on SauceLabs (#35962) I was not able to reproduce IE 10/11 failrue of the disabled tests on SauceLabs any more. I did some cleanup of the test in question but I doubt it was the root cause of the problem. PR Close #35962 --- packages/core/test/BUILD.bazel | 9 --------- packages/core/test/linker/ng_module_integration_spec.ts | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/core/test/BUILD.bazel b/packages/core/test/BUILD.bazel index 3e65243eeb76d..d5fc99181550b 100644 --- a/packages/core/test/BUILD.bazel +++ b/packages/core/test/BUILD.bazel @@ -87,15 +87,6 @@ jasmine_node_test( karma_web_test_suite( name = "test_web", - tags = [ - # FIXME: fix on saucelabs - # IE 11.0.0 (Windows 8.1.0.0) ivy NgModule providers should throw when the aliased provider does not exist FAILED - # Error: Expected function to throw an exception with message 'R3InjectorError(SomeModule)[car -> SportsCar]: - # NullInjectorError: No provider for Car!', but it threw an exception with message 'R3InjectorError(SomeModule)[car -> Car]: - # NullInjectorError: No provider for Car!'. - # at <Jasmine> - "fixme-saucelabs-ivy", - ], deps = [ ":test_lib", ], diff --git a/packages/core/test/linker/ng_module_integration_spec.ts b/packages/core/test/linker/ng_module_integration_spec.ts index 152f42e68c1df..08acb83c10d55 100644 --- a/packages/core/test/linker/ng_module_integration_spec.ts +++ b/packages/core/test/linker/ng_module_integration_spec.ts @@ -794,7 +794,7 @@ function declareTests(config?: {useJit: boolean}) { const injector = createInjector([{provide: 'car', useExisting: SportsCar}]); let errorMsg = `NullInjectorError: No provider for ${stringify(SportsCar)}!`; if (ivyEnabled) { - errorMsg = `R3InjectorError(SomeModule)[car -> SportsCar]: \n ` + errorMsg; + errorMsg = `R3InjectorError(SomeModule)[car -> ${stringify(SportsCar)}]: \n ` + errorMsg; } expect(() => injector.get('car')).toThrowError(errorMsg); }); From 36fc28642a1437077db77ed53f2ec43f99e3f2fc Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@umich.edu> Date: Thu, 12 Mar 2020 13:22:51 -0700 Subject: [PATCH 021/262] docs(common): Add missing entry for NgForOfContext.count (#36046) `count` is available in `NgForOfContext` but it's missing in the docs. PR Close #36046 --- packages/common/src/directives/ng_for_of.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/common/src/directives/ng_for_of.ts b/packages/common/src/directives/ng_for_of.ts index 32d5955c992e2..02d8243690c99 100644 --- a/packages/common/src/directives/ng_for_of.ts +++ b/packages/common/src/directives/ng_for_of.ts @@ -85,6 +85,7 @@ export class NgForOfContext<T, U extends NgIterable<T> = NgIterable<T>> { * more complex then a property access, for example when using the async pipe (`userStreams | * async`). * - `index: number`: The index of the current item in the iterable. + * - `count: number`: The length of the iterable. * - `first: boolean`: True when the item is the first item in the iterable. * - `last: boolean`: True when the item is the last item in the iterable. * - `even: boolean`: True when the item has an even index in the iterable. From 4f9717331d6a47c7d509b0458877ffd1382fa799 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@google.com> Date: Mon, 23 Mar 2020 17:33:39 -0700 Subject: [PATCH 022/262] test(common): Add test for NgForOfContext.count (#36046) `NgForOfContext.count` is the length of the iterable. PR Close #36046 --- packages/common/test/directives/ng_for_spec.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/common/test/directives/ng_for_spec.ts b/packages/common/test/directives/ng_for_spec.ts index 0935650f7e275..fef7e67976573 100644 --- a/packages/common/test/directives/ng_for_spec.ts +++ b/packages/common/test/directives/ng_for_spec.ts @@ -203,6 +203,17 @@ let thisArg: any; detectChangesAndExpectText('0123456789'); })); + it('should display count correctly', async(() => { + const template = '<span *ngFor="let item of items; let len=count">{{len}}</span>'; + fixture = createTestComponent(template); + + getComponent().items = [0, 1, 2]; + detectChangesAndExpectText('333'); + + getComponent().items = [4, 3, 2, 1, 0, -1]; + detectChangesAndExpectText('666666'); + })); + it('should display first item correctly', async(() => { const template = '<span *ngFor="let item of items; let isFirst=first">{{isFirst.toString()}}</span>'; From 380de1e7b464609663b36e67f303ce6933a1e3a6 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Fri, 20 Mar 2020 22:09:40 +0000 Subject: [PATCH 023/262] fix(ngcc): use path-mappings from tsconfig in dependency resolution (#36180) When computing the dependencies between packages which are not in node_modules, we may need to rely upon path-mappings to find the path to the imported entry-point. This commit allows ngcc to use the path-mappings from a tsconfig file to find dependencies. By default any tsconfig.json file in the directory above the `basePath` is loaded but it is possible to use a path to a specific file by providing the `tsConfigPath` property to mainNgcc, or to turn off loading any tsconfig file by setting `tsConfigPath` to `null`. At the command line this is controlled via the `--tsconfig` option. Fixes #36119 PR Close #36180 --- packages/compiler-cli/ngcc/BUILD.bazel | 1 + packages/compiler-cli/ngcc/main-ngcc.ts | 13 +- packages/compiler-cli/ngcc/src/main.ts | 42 ++++- .../ngcc/test/integration/ngcc_spec.ts | 174 +++++++++++++++++- 4 files changed, 215 insertions(+), 15 deletions(-) diff --git a/packages/compiler-cli/ngcc/BUILD.bazel b/packages/compiler-cli/ngcc/BUILD.bazel index db91dca21a052..3d8553c095191 100644 --- a/packages/compiler-cli/ngcc/BUILD.bazel +++ b/packages/compiler-cli/ngcc/BUILD.bazel @@ -12,6 +12,7 @@ ts_library( deps = [ "//packages:types", "//packages/compiler", + "//packages/compiler-cli", "//packages/compiler-cli/src/ngtsc/annotations", "//packages/compiler-cli/src/ngtsc/cycles", "//packages/compiler-cli/src/ngtsc/diagnostics", diff --git a/packages/compiler-cli/ngcc/main-ngcc.ts b/packages/compiler-cli/ngcc/main-ngcc.ts index 394d9cb52da93..cd88da9518eef 100644 --- a/packages/compiler-cli/ngcc/main-ngcc.ts +++ b/packages/compiler-cli/ngcc/main-ngcc.ts @@ -92,6 +92,13 @@ if (require.main === module) { type: 'boolean', default: false, }) + .option('tsconfig', { + describe: + 'A path to a tsconfig.json file that will be used to configure the Angular compiler and module resolution used by ngcc.\n' + + 'If not provided, ngcc will attempt to read a `tsconfig.json` file from the folder above that given by the `-s` option.\n' + + 'Set to false (via `--no-tsconfig`) if you do not want ngcc to use any `tsconfig.json` file.', + type: 'string', + }) .strict() .help() .parse(args); @@ -113,6 +120,10 @@ if (require.main === module) { const enableI18nLegacyMessageIdFormat = options['legacy-message-ids']; const invalidateEntryPointManifest = options['invalidate-entry-point-manifest']; const errorOnFailedEntryPoint = options['error-on-failed-entry-point']; + // yargs is not so great at mixed string+boolean types, so we have to test tsconfig against a + // string "false" to capture the `tsconfig=false` option. + // And we have to convert the option to a string to handle `no-tsconfig`, which will be `false`. + const tsConfigPath = `${options['tsconfig']}` === 'false' ? null : options['tsconfig']; (async() => { try { @@ -126,7 +137,7 @@ if (require.main === module) { createNewEntryPointFormats, logger, enableI18nLegacyMessageIdFormat, - async: options['async'], invalidateEntryPointManifest, errorOnFailedEntryPoint, + async: options['async'], invalidateEntryPointManifest, errorOnFailedEntryPoint, tsConfigPath }); if (logger) { diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index c22839a5395a0..6a202be471355 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -12,6 +12,7 @@ import {DepGraph} from 'dependency-graph'; import * as os from 'os'; import * as ts from 'typescript'; +import {readConfiguration} from '../..'; import {replaceTsWithNgInErrors} from '../../src/ngtsc/diagnostics'; import {AbsoluteFsPath, FileSystem, absoluteFrom, dirname, getFileSystem, resolve} from '../../src/ngtsc/file_system'; @@ -94,6 +95,9 @@ export interface SyncNgccOptions { /** * Paths mapping configuration (`paths` and `baseUrl`), as found in `ts.CompilerOptions`. * These are used to resolve paths to locally built Angular libraries. + * + * Note that `pathMappings` specified here take precedence over any `pathMappings` loaded from a + * TS config file. */ pathMappings?: PathMappings; @@ -143,6 +147,18 @@ export interface SyncNgccOptions { * Default: `false` (i.e. the manifest will be used if available) */ invalidateEntryPointManifest?: boolean; + + /** + * An absolute path to a TS config file (e.g. `tsconfig.json`) or a directory containing one, that + * will be used to configure module resolution with things like path mappings, if not specified + * explicitly via the `pathMappings` property to `mainNgcc`. + * + * If `undefined`, ngcc will attempt to load a `tsconfig.json` file from the directory above the + * `basePath`. + * + * If `null`, ngcc will not attempt to load any TS config file at all. + */ + tsConfigPath?: string|null; } /** @@ -165,12 +181,12 @@ export type NgccOptions = AsyncNgccOptions | SyncNgccOptions; */ export function mainNgcc(options: AsyncNgccOptions): Promise<void>; export function mainNgcc(options: SyncNgccOptions): void; -export function mainNgcc({basePath, targetEntryPointPath, - propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, - compileAllFormats = true, createNewEntryPointFormats = false, - logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false, - errorOnFailedEntryPoint = false, enableI18nLegacyMessageIdFormat = true, - invalidateEntryPointManifest = false}: NgccOptions): void|Promise<void> { +export function mainNgcc( + {basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, + compileAllFormats = true, createNewEntryPointFormats = false, + logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false, + errorOnFailedEntryPoint = false, enableI18nLegacyMessageIdFormat = true, + invalidateEntryPointManifest = false, tsConfigPath}: NgccOptions): void|Promise<void> { if (!!targetEntryPointPath) { // targetEntryPointPath forces us to error if an entry-point fails. errorOnFailedEntryPoint = true; @@ -184,7 +200,19 @@ export function mainNgcc({basePath, targetEntryPointPath, // master/worker process. const fileSystem = getFileSystem(); const absBasePath = absoluteFrom(basePath); - const config = new NgccConfiguration(fileSystem, dirname(absBasePath)); + const projectPath = dirname(absBasePath); + const config = new NgccConfiguration(fileSystem, projectPath); + const tsConfig = tsConfigPath !== null ? readConfiguration(tsConfigPath || projectPath) : null; + + // If `pathMappings` is not provided directly, then try getting it from `tsConfig`, if available. + if (tsConfig !== null && pathMappings === undefined && tsConfig.options.baseUrl !== undefined && + tsConfig.options.paths) { + pathMappings = { + baseUrl: resolve(projectPath, tsConfig.options.baseUrl), + paths: tsConfig.options.paths, + }; + } + const dependencyResolver = getDependencyResolver(fileSystem, logger, config, pathMappings); const entryPointManifest = invalidateEntryPointManifest ? new InvalidatingEntryPointManifest(fileSystem, config, logger) : diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 888c854415b25..bde8f468a03f6 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -1230,22 +1230,134 @@ runInEachFileSystem(() => { }); describe('with pathMappings', () => { - it('should find and compile packages accessible via the pathMappings', () => { + it('should infer the @app pathMapping from a local tsconfig.json path', () => { + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({compilerOptions: {paths: {'@app/*': ['dist/*']}, baseUrl: './'}})); + const logger = new MockLogger(); + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015'], logger}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + // The local-package-3 and local-package-4 will not be processed because there is no path + // mappings for `@x` and plain local imports. + expect(loadPackage('local-package-3', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-3')}.`, + 'It is missing required dependencies:\n - @x/local-package' + ]); + expect(loadPackage('local-package-4', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-4')}.`, + 'It is missing required dependencies:\n - local-package' + ]); + }); + + it('should read the @x pathMapping from a specified tsconfig.json path', () => { + fs.writeFile( + _('/tsconfig.app.json'), + JSON.stringify({compilerOptions: {paths: {'@x/*': ['dist/*']}, baseUrl: './'}})); + const logger = new MockLogger(); mainNgcc({ - basePath: '/node_modules', + basePath: '/dist', propertiesToConsider: ['es2015'], - pathMappings: {paths: {'*': ['dist/*']}, baseUrl: '/'}, + tsConfigPath: _('/tsconfig.app.json'), logger }); - expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', - fesm2015: '0.0.0-PLACEHOLDER', typings: '0.0.0-PLACEHOLDER', }); - expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + expect(loadPackage('local-package-3', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', typings: '0.0.0-PLACEHOLDER', }); + // The local-package-2 and local-package-4 will not be processed because there is no path + // mappings for `@app` and plain local imports. + expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-2')}.`, + 'It is missing required dependencies:\n - @app/local-package' + ]); + expect(loadPackage('local-package-4', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-4')}.`, + 'It is missing required dependencies:\n - local-package' + ]); }); + + it('should use the explicit `pathMappings`, ignoring the local tsconfig.json settings', + () => { + const logger = new MockLogger(); + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({compilerOptions: {paths: {'@app/*': ['dist/*']}, baseUrl: './'}})); + mainNgcc({ + basePath: '/node_modules', + propertiesToConsider: ['es2015'], + pathMappings: {paths: {'*': ['dist/*']}, baseUrl: '/'}, logger + }); + expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + fesm2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(loadPackage('local-package-4', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + // The local-package-2 and local-package-3 will not be processed because there is no path + // mappings for `@app` and `@x` local imports. + expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-2')}.`, + 'It is missing required dependencies:\n - @app/local-package' + ]); + expect(loadPackage('local-package-3', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-3')}.`, + 'It is missing required dependencies:\n - @x/local-package' + ]); + }); + + it('should not use pathMappings from a local tsconfig.json path if tsConfigPath is null', + () => { + const logger = new MockLogger(); + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({compilerOptions: {paths: {'@app/*': ['dist/*']}, baseUrl: './'}})); + mainNgcc({ + basePath: '/dist', + propertiesToConsider: ['es2015'], + tsConfigPath: null, logger, + }); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + // Since the tsconfig is not loaded, the `@app/local-package` import in `local-package-2` + // is not path-mapped correctly, and so it fails to be processed. + expect(loadPackage('local-package-2', _('/dist')).__processed_by_ivy_ngcc__) + .toBeUndefined(); + expect(logger.logs.debug).toContain([ + `Invalid entry-point ${_('/dist/local-package-2')}.`, + 'It is missing required dependencies:\n - @app/local-package' + ]); + }); }); describe('with configuration files', () => { @@ -1748,7 +1860,7 @@ runInEachFileSystem(() => { }, ]); - // An Angular package that has been built locally and stored in the `dist` directory. + // Angular packages that have been built locally and stored in the `dist` directory. loadTestFiles([ { name: _('/dist/local-package/package.json'), @@ -1764,6 +1876,54 @@ runInEachFileSystem(() => { name: _('/dist/local-package/index.d.ts'), contents: `export declare class AppComponent {};` }, + // local-package-2 depends upon local-package, via an `@app` aliased import. + { + name: _('/dist/local-package-2/package.json'), + contents: '{"name": "local-package-2", "es2015": "./index.js", "typings": "./index.d.ts"}' + }, + {name: _('/dist/local-package-2/index.metadata.json'), contents: 'DUMMY DATA'}, + { + name: _('/dist/local-package-2/index.js'), + contents: + `import {Component} from '@angular/core';\nexport {AppComponent} from '@app/local-package';` + }, + { + name: _('/dist/local-package-2/index.d.ts'), + contents: + `import {Component} from '@angular/core';\nexport {AppComponent} from '@app/local-package';` + }, + // local-package-3 depends upon local-package, via an `@x` aliased import. + { + name: _('/dist/local-package-3/package.json'), + contents: '{"name": "local-package-3", "es2015": "./index.js", "typings": "./index.d.ts"}' + }, + {name: _('/dist/local-package-3/index.metadata.json'), contents: 'DUMMY DATA'}, + { + name: _('/dist/local-package-3/index.js'), + contents: + `import {Component} from '@angular/core';\nexport {AppComponent} from '@x/local-package';` + }, + { + name: _('/dist/local-package-3/index.d.ts'), + contents: + `import {Component} from '@angular/core';\nexport {AppComponent} from '@x/local-package';` + }, + // local-package-4 depends upon local-package, via a plain import. + { + name: _('/dist/local-package-4/package.json'), + contents: '{"name": "local-package-", "es2015": "./index.js", "typings": "./index.d.ts"}' + }, + {name: _('/dist/local-package-4/index.metadata.json'), contents: 'DUMMY DATA'}, + { + name: _('/dist/local-package-4/index.js'), + contents: + `import {Component} from '@angular/core';\nexport {AppComponent} from 'local-package';` + }, + { + name: _('/dist/local-package-4/index.d.ts'), + contents: + `import {Component} from '@angular/core';\nexport {AppComponent} from 'local-package';` + }, ]); // An Angular package that has a missing dependency From ae28d7c0b2060745df034b8dcc0d872594076f4b Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Tue, 24 Mar 2020 13:02:37 +0000 Subject: [PATCH 024/262] build(docs-infra): upgrade cli command docs sources to 56c648827 (#36224) Updating [angular#master](https://github.com/angular/angular/tree/master) from [cli-builds#master](https://github.com/angular/cli-builds/tree/master). ## Relevant changes in [commit range](https://github.com/angular/cli-builds/compare/f5dd5b16a...56c648827): **Modified** - help/build.json - help/lint.json - help/test.json PR Close #36224 --- aio/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/package.json b/aio/package.json index bb42c5ce7998c..4645a2b6dc248 100644 --- a/aio/package.json +++ b/aio/package.json @@ -23,7 +23,7 @@ "build-local-with-viewengine": "yarn ~~build", "prebuild-local-with-viewengine-ci": "node scripts/switch-to-viewengine && yarn setup-local-ci", "build-local-with-viewengine-ci": "yarn ~~build --progress=false", - "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js f5dd5b16a", + "extract-cli-command-docs": "node tools/transforms/cli-docs-package/extract-cli-commands.js 56c648827", "lint": "yarn check-env && yarn docs-lint && ng lint && yarn example-lint && yarn tools-lint", "test": "yarn check-env && ng test", "pree2e": "yarn check-env && yarn update-webdriver", From 55dac05cf2fdef47ace60289093dfd294ce806c8 Mon Sep 17 00:00:00 2001 From: Faouzi Medebbeb <faouzi.medebbeb@gmail.com> Date: Tue, 24 Mar 2020 10:47:19 +0100 Subject: [PATCH 025/262] docs: fix typo in testing component with dependencies (#36219) Fixes #36210 PR Close #36219 --- aio/content/guide/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index c3dead9ba1736..4fd661ae45530 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -1288,7 +1288,7 @@ In this example, we have a new macro task (nested setTimeout), by default, when region="fake-async-test-tick-new-macro-task-async"> </code-example> -And in some case, we don't want to trigger the new maco task when ticking, we can use `tick(milliseconds, {processNewMacroTasksSynchronously: false})` to not invoke new maco task. +And in some case, we don't want to trigger the new macro task when ticking, we can use `tick(milliseconds, {processNewMacroTasksSynchronously: false})` to not invoke new maco task. #### Comparing dates inside fakeAsync() From b14ac967501c494dec04a749a0b4ac29201f3626 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Thu, 19 Mar 2020 13:50:25 +0200 Subject: [PATCH 026/262] fix(elements): correctly set `SimpleChange#firstChange` for pre-existing inputs (#36140) Previously, when an input property was set on an `NgElement` before instantiating the underlying component, the `SimpleChange` object passed to `ngOnChanges()` would have `firstChange` set to false, even if this was the first change (as far as the component instance was concerned). This commit fixes this by ensuring `SimpleChange#firstChange` is set to true on first change, regardless if the property was set before or after instantiating the component. This alignthe behavior of Angular custom elements with that of the corresponding components when used directly (not as custom elements). Jira issue: [FW-2007](https://angular-team.atlassian.net/browse/FW-2007) Fixes #36130 PR Close #36140 --- .../src/component-factory-strategy.ts | 23 ++++++++++++------- .../test/component-factory-strategy_spec.ts | 20 ++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/packages/elements/src/component-factory-strategy.ts b/packages/elements/src/component-factory-strategy.ts index 8f27a721c9fa2..6480045daedd9 100644 --- a/packages/elements/src/component-factory-strategy.ts +++ b/packages/elements/src/component-factory-strategy.ts @@ -66,8 +66,11 @@ export class ComponentNgElementStrategy implements NgElementStrategy { /** Initial input values that were set before the component was created. */ private readonly initialInputValues = new Map<string, any>(); - /** Set of inputs that were not initially set when the component was created. */ - private readonly uninitializedInputs = new Set<string>(); + /** + * Set of component inputs that have not yet changed, i.e. for which `ngOnChanges()` has not + * fired. (This is used to determine the value of `fistChange` in `SimpleChange` instances.) + */ + private readonly unchangedInputs = new Set<string>(); constructor(private componentFactory: ComponentFactory<any>, private injector: Injector) {} @@ -164,12 +167,16 @@ export class ComponentNgElementStrategy implements NgElementStrategy { /** Set any stored initial inputs on the component's properties. */ protected initializeInputs(): void { this.componentFactory.inputs.forEach(({propName}) => { + if (this.implementsOnChanges) { + // If the component implements `ngOnChanges()`, keep track of which inputs have never + // changed so far. + this.unchangedInputs.add(propName); + } + if (this.initialInputValues.has(propName)) { + // Call `setInputValue()` now that the component has been instantiated to update its + // properties and fire `ngOnChanges()`. this.setInputValue(propName, this.initialInputValues.get(propName)); - } else { - // Keep track of inputs that were not initialized in case we need to know this for - // calling ngOnChanges with SimpleChanges - this.uninitializedInputs.add(propName); } }); @@ -235,8 +242,8 @@ export class ComponentNgElementStrategy implements NgElementStrategy { return; } - const isFirstChange = this.uninitializedInputs.has(property); - this.uninitializedInputs.delete(property); + const isFirstChange = this.unchangedInputs.has(property); + this.unchangedInputs.delete(property); const previousValue = isFirstChange ? undefined : this.getInputValue(property); this.inputChanges[property] = new SimpleChange(previousValue, currentValue, isFirstChange); diff --git a/packages/elements/test/component-factory-strategy_spec.ts b/packages/elements/test/component-factory-strategy_spec.ts index 54b8bd8f8af78..4a99800a6b362 100644 --- a/packages/elements/test/component-factory-strategy_spec.ts +++ b/packages/elements/test/component-factory-strategy_spec.ts @@ -93,21 +93,21 @@ describe('ComponentFactoryNgElementStrategy', () => { it('should call ngOnChanges with the change', () => { expectSimpleChanges(componentRef.instance.simpleChanges[0], { - fooFoo: new SimpleChange(undefined, 'fooFoo-1', false), - falsyNull: new SimpleChange(undefined, null, false), - falsyEmpty: new SimpleChange(undefined, '', false), - falsyFalse: new SimpleChange(undefined, false, false), - falsyZero: new SimpleChange(undefined, 0, false), + fooFoo: new SimpleChange(undefined, 'fooFoo-1', true), + falsyNull: new SimpleChange(undefined, null, true), + falsyEmpty: new SimpleChange(undefined, '', true), + falsyFalse: new SimpleChange(undefined, false, true), + falsyZero: new SimpleChange(undefined, 0, true), }); }); it('should call ngOnChanges with proper firstChange value', fakeAsync(() => { - strategy.setInputValue('falsyUndefined', 'notanymore'); + strategy.setInputValue('fooFoo', 'fooFoo-2'); strategy.setInputValue('barBar', 'barBar-1'); tick(16); // scheduler waits 16ms if RAF is unavailable (strategy as any).detectChanges(); expectSimpleChanges(componentRef.instance.simpleChanges[1], { - falsyUndefined: new SimpleChange(undefined, 'notanymore', false), + fooFoo: new SimpleChange('fooFoo-1', 'fooFoo-2', false), barBar: new SimpleChange(undefined, 'barBar-1', true), }); })); @@ -296,9 +296,9 @@ function expectSimpleChanges(actual: SimpleChanges, expected: SimpleChanges) { Object.keys(expected).forEach(key => { expect(actual[key]).toBeTruthy(`Change should have included key ${key}`); if (actual[key]) { - expect(actual[key].previousValue).toBe(expected[key].previousValue); - expect(actual[key].currentValue).toBe(expected[key].currentValue); - expect(actual[key].firstChange).toBe(expected[key].firstChange); + expect(actual[key].previousValue).toBe(expected[key].previousValue, `${key}.previousValue`); + expect(actual[key].currentValue).toBe(expected[key].currentValue, `${key}.currentValue`); + expect(actual[key].firstChange).toBe(expected[key].firstChange, `${key}.firstChange`); } }); } From 9ba46d9f880bc561ad941f812532484f055c209c Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Thu, 19 Mar 2020 13:57:55 +0200 Subject: [PATCH 027/262] fix(elements): correctly handle setting inputs to `undefined` (#36140) Previously, when an input property was initially set to `undefined` it would not be correctly recognized as a change (and trigger `ngOnChanges()`). This commit ensures that explicitly setting an input to `undefined` is correctly handled the same as setting the property to any other value. This aligns the behavior of Angular custom elements with that of the corresponding components when used directly (not as custom elements). PR Close #36140 --- packages/elements/src/component-factory-strategy.ts | 6 +++++- packages/elements/test/component-factory-strategy_spec.ts | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/elements/src/component-factory-strategy.ts b/packages/elements/src/component-factory-strategy.ts index 6480045daedd9..fafe335b84fa9 100644 --- a/packages/elements/src/component-factory-strategy.ts +++ b/packages/elements/src/component-factory-strategy.ts @@ -133,7 +133,11 @@ export class ComponentNgElementStrategy implements NgElementStrategy { return; } - if (strictEquals(value, this.getInputValue(property))) { + // Ignore the value if it is strictly equal to the current value, except if it is `undefined` + // and this is the first change to the value (because an explicit `undefined` _is_ strictly + // equal to not having a value set at all, but we still need to record this as a change). + if (strictEquals(value, this.getInputValue(property)) && + !((value === undefined) && this.unchangedInputs.has(property))) { return; } diff --git a/packages/elements/test/component-factory-strategy_spec.ts b/packages/elements/test/component-factory-strategy_spec.ts index 4a99800a6b362..7887b55abf7f4 100644 --- a/packages/elements/test/component-factory-strategy_spec.ts +++ b/packages/elements/test/component-factory-strategy_spec.ts @@ -94,6 +94,7 @@ describe('ComponentFactoryNgElementStrategy', () => { it('should call ngOnChanges with the change', () => { expectSimpleChanges(componentRef.instance.simpleChanges[0], { fooFoo: new SimpleChange(undefined, 'fooFoo-1', true), + falsyUndefined: new SimpleChange(undefined, undefined, true), falsyNull: new SimpleChange(undefined, null, true), falsyEmpty: new SimpleChange(undefined, '', true), falsyFalse: new SimpleChange(undefined, false, true), @@ -104,11 +105,13 @@ describe('ComponentFactoryNgElementStrategy', () => { it('should call ngOnChanges with proper firstChange value', fakeAsync(() => { strategy.setInputValue('fooFoo', 'fooFoo-2'); strategy.setInputValue('barBar', 'barBar-1'); + strategy.setInputValue('falsyUndefined', 'notanymore'); tick(16); // scheduler waits 16ms if RAF is unavailable (strategy as any).detectChanges(); expectSimpleChanges(componentRef.instance.simpleChanges[1], { fooFoo: new SimpleChange('fooFoo-1', 'fooFoo-2', false), barBar: new SimpleChange(undefined, 'barBar-1', true), + falsyUndefined: new SimpleChange(undefined, 'notanymore', false), }); })); }); From ff4eb0cb635e6702b6bd2919354f0a33c84543f0 Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Mon, 16 Mar 2020 12:31:09 -0700 Subject: [PATCH 028/262] docs(elements): correct typo in custom elements image (#36090) Fixes #36050 PR Close #36090 --- .../images/guide/elements/createElement.png | Bin 73834 -> 61501 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/aio/content/images/guide/elements/createElement.png b/aio/content/images/guide/elements/createElement.png index 16328d70379c07db2bf07eea565fb8d1daff4fed..0d979575a5136bd224c7ab87110b4a4bd8242db4 100644 GIT binary patch literal 61501 zcmXt<byyJ3x5jCtkrEK;QW}vC>F!3lk?sa*>F(~9?iP^lmX_}By2JPP+&>VR-JRX3 zbIzRiGr@8)q9};?h!7AEDB@y53J?%bY7h{RQE%WtiQN~%B=8HtMoirv0s^(?^#?MZ z2K7BCgm(~^7KY!1M#ucXhK7L1|6h@?nghS1gQ>M0MDed-F;Il;0E&c+><#S9Y#hw2 ztspQFNXS4r;%m8}wT-KtnTe?bL>byJCn!bzuhh;+@AXz<2Qy0}h%Yy22;d6B>lH<7 zV+UtFJ0l1!o0r$yk^ZaP%-+C458P@8(a>2N35wsm7OU#nS(#axKy<#}4gzKH|9jri z&cF!b>c#Ki|8EntwzM>|a)7uVPUrw-aId#1nK@V(K@=TNQb9lvLx>CUE4ic{raQY} zZC&^AeO_d1dxrt#GwzNF2`MlCD~nozR$i_Ok~PInx$!cGnDufWw(Jr8Ors(Mwn{!< zOrBGmn4Bb__UQA)gF$sFj4u>ac5CL&0@Z@E$qL8k)I*P(w2KTfvy=i7^fxe2K3|F1 z4f^XWe|#l={j;k#5MAxH5d2|+Yfxvh>H%G<Iv4X1%4f|t$4GK_wWGcqT=Tua_!#9^ z=g#J^4<i~mTP^;2{cD2Wqe~KRTRq*|*E=F4&{XuY>3<zM-S+Wy>Ow@n(4)VJ5KhQ$ z#BINYG9HFdo)J!<Wkv-b(J7nXdG5_FBGfs=;5P!tt3#Jef&OOnn<3tkRT3MT@u<Ig z%_Y<N00yWR;?IVN5_U*P=N1N(Br*DQ*Z>Tf$Zp42O1^tF3rc}BW(F<z{;y@ESZ`no z{pL!&@!oS_WVi?rrE*|WN)>6ffcLF&^S=Ri*|^<$H232(L1lPgkc;0KhZ9vqB7shz z2z%{>waYX2>PJ!}-D`{GSPGm0@NP+5l1gxWwfg{8*e8gv1WUcfIM^opD{*7q+t-hI z^ehQPqLLcNTs9e<?hXi1Se!)w_j8E;_cr6A{Q-PFZK713_Ze;_PDih;(OA1>Mgbje z(|jx0ax2L`oL0>DNI`%c__szH48kahfG&aziu$B#s5pk$50Ncd=_#TTF{}1G4i&?Z zr0gBTJMYB2zg6Jf|GW1YUmY$MImW+bTD*8lFnK6cR{knAzd(-_zw%p{KfF3qpjua< zuk2g>1BG6OYLSTP7m-I&NoB{#1Zt5_=x^xl{5vtG!)W)=q;rcJ)1;GO4L9TeL9zI~ zozWGF&6A)?C?PFHj2R1BCY~Usk4q4b_77ONy2FyDUF?`Xy>qa=8W+4D+ndrGC3vdC z`z+KbM~tpH{l<raov`L@!_){-GHlt{r=0%ss5k=AWfcT+ksu60eJYmzkOkAPf`S6S zx6Tx{FQdF`!w$(P4*3*%_I0k`nzKzdX|sgy3lS%Wtzpv)(tm8#X2f6bf_L;edZ+%J zllR(x(WEd5Ss3C_e#5_pq1soI{rdFt6@!df#HER+t)8c}q(zWOoRARYNop;ke!#_X zE?L}@g)-D1n^=lK^1P>#W8;-VBYM`dP9Xnq0y)9L1LOF~UNVLrLaA<Y0|P6M&zW5& zjlr;HuaAL->&d=RiG4Qqi$P#}v)q(F73h7<TCo%rTQ-djLQY3te;BnUg$|#e#$$=7 zaCkF?r@aYM*9mux)#j2KtUvh-rd}QwAz3Y!#6wNFRO_TBH$uG0_#~%TG_BaQGtq>V znfjT#oVcoIO5CMo6b#K$M6~%KyZHHGVBvG`JchqDMirgf9OE+!y$}^~ss>bkYcxc_ z3qn1+ERx3^*|t|a5Rd7!nzOWPqHi^{&6R(rh=j9Cg9!O2Vx~6%tZYrgpHhmDxQ3d9 z3`7>}KiIf^-Qlj-bN?Y`nU}gPeW`?prF@?WF64Z7i<sNfWvyYL31#(sn5@^~`-RIM zg)^ru8M$b+QK;hud6DV92&G1Q__rf7!SkNc?AhZD0)GrSuTE18(QHM<LJg@n@lcsY zO9C2L@yg0$;p5TdSi*YC`!k0NbqBvM?{7Wg9jl-3WO*h$M+tD*WU$Dv-@v^4AfT(Y z-_L9n8EJHIjX6b}{M_~z-H=Dz$1Vg+VZ8Acp1>qr-qpBl_dprZG%*aT$e_05<Ry=z zI&MBo{F)3m#L|JDQv^)*wD|l`TEA@OxSbn;0lTfFF;NFYaz)WdW8F;NHM?vxd=k*B z3l=jxs&IbCJk^U`rsVxrRJ7!qJ*@YUmJNP08cp9vE#N})@9U}XFNnqrp<)sI$fKWc zH(Kvk+|luh#|}gju6C4fibE!fhy)X^GM(J>(XVu3L+rUqZ$0iey5MQP?F}cBxxGV# z@eM_d_H!&Ilk}*gh#k*!`E@wHTShcWEUvlQ27B^k%~M)Wlp}h8b(-Nutr0^WMv1BF zaM(ZdbnjCzk!Pj#ci9H|oAWVwww~aiz5T%G2n7>sLe`q@I12$PJp9cu1rvS5+L|tD z_itQ}r>pt0*%ZNlDR9Q0OBP2WR=xX5saeb?VOmB4Rbq+9S+sUt+76f6)0u<(=8LFf zFfsWPIO5_1a;V9vC`pxn4juZzpSiT<kyDZmFei;*ZExGHjgycQe<XqYCWpT0boh0O z#qQ$b&hhH|Z(1CDN~!|^@tFRlj!ZIGSX>mi$^DsbLOcW+DlrV<fPgqI0&)tf*eYux z;ojcqa>bzjJaQZM`FbOykdnzVJwYjceiJsBy^c{d-lCmm<&gml3Ibp>g?-W05}A$3 zQk{%rLxZ!IHPX(HB@<{#sHlQUE80^M=)Pr4wtN0E?cySO78}fl+NTiN|579K7U2?I zOW5~5V^~VS&oB555_D{ET`HUX&h7+l3Qwx}uQnVHUe=d;8aAF&h|rzkY}uFR&Evnl zj)FnV=c8Or&bKzy^uN5&OXGdXL|r`24HLYs@tC5cYpwpq<-}lU#eE3v6_Bx_mmNtP z=v(y=6jH+t5RGJZyfh`m<&2{;8QT`qBguT);lnLckyFm_I_7XPF+6>8KOs>sFMGZ- zAxvS9_Wdn@rM%Tl$m3$TEB9wOsp}XTzMp~CaO6+;<HjIOGM_86c4lNULu)6^NxP(} z9D0zQ{oZ`@mkTPHJmsMT;vtXAE_hn)`mj;U#q-`0Wy76q1-_5L9}W7>mu30Ro_8{1 zy)UWRG(ErAQ%RHZa%zkjaeceRTonx)hn=Z4Yo?M^zM2Vmr~gI?xQ!B<ZI}ddew)f$ z-7-2BX`PAf4%;W}>ad!nk$q@b&E*GXsleC^eCm+jf5P7<GwMODdR(ADFtncj{)kle z6aBsAH#Wl=Yp&vV?{KKq+^WTX4Ct<f=SwbBdU7QLqqKFi`uW)hes{i#j6K~nC9uS7 zhFh8nzx1s-oUq<CO~vU-AJN4`X@x?EI41AoiMOlqvF5M6*`vmzFT#4~OHCfnPdBv5 ze3|#f#bt|?kmLv>8^zQvI!`Vd0X)@RKT7lb-(pftmhnRuFlY$fP2{?86Q<<lSGinU z{QAHdr>)h@=rv9K`_L)MXuJK9dFmbQT7XGL_FTNGLR4bkyx9~kw;g%u%Y)AEjg6|5 zk+Rk1`0*%ooZ%!N`6*nM?^w`89#QUaDE~H`SJpd^moL57Al;k}`#rmZh%(o_3(gos zP7`gCSWz<EWjc;Y&$NJfT}#9BQI7ucu+>Kt>$p3Pm#kp(-9IQ`;%2`T0TqFx$zM-h z|72Z&B{jWvb2pZE^mw^tZ?S;^Cp6&p*2T`wu5xyBfCGV(RaS2#kdIwKNk&SEF)ajB zGG_cot1pz-Y6DtDpP-8=b*AS7onJ*q1{|FRu{Z{tI;#J_%jF27*hp8xPTeeOs-P_$ zuYsSJ4!=%TiO7SE!{5i+?xHU`AC<JXO^6+53wqoiHH0<YX#Z+ohqK`{i%NhaM006t zj^d<*p&YW)m5L!BHvWv7h@>84I-4I#FElt*oS7!2CiZ3`I-12|g@BuI@Zwyp)q~?^ z)s3c`$OWQR8^6|KfTbbzeIT02Q-QSRR0Bgu4m$SRuGYeg9K8UDwqK%XtX7ME!m13a zC@3bH^#p(I{f%FBI-Wk_5uR|@P@-FhaBCbt8A#!{INb4n4V~2g4STpHj}R=?1T9#% z^-4D^*@+ZjrQuh2U*o;i)6)bU7nksS_Xi`Z=x~@WpTA8=hGL46mp3C(+bvioos-FG ziG9WU<!P#ZL7zEFfh}SL9;u0v@-j{(#w;aJR^G*Jn)*J!&~He1w%+oxZHMp=Sl8zP zNTtCEQvxy6&g?eq=`6C6Q%Ckqou)ksQxd}J+o#cFSUB&d*uP*eS+ynL!1()?m{HY= zDr3=-khF3-ej=lk$-7zWa`-+KIB~NqS~^<}Y$<g~$k@)5eJM-$V-6{>on{k_RrC^r zL;T9Y!C~aIEODzh$6NU7v#=^I>?B=X_p3oU=!EzZ>GNu3#-HQjvm2Myq$nd2;&yY6 zHC=N{-KxnE3S?$@)MN78tLba)us{sdiHH0)fs25}YWk-rk=L!1^hb7B2}#M1Pc(YU z*vb^E>-n}Gn;$<=adW5nK*K|=ow>-Et)~184cA>wXq{>g=G3CsVvI|SU8?;!=X5f9 zaMBUkkVj7Jt0X<uEd%GLO>=-1Qxq;j7DK*%=0=mMnL3grU9ce-nj%uU95JGwomW<7 z_Yh)`Tapwef+aj*8AV>HR;fYjmQ+caSSFoF@6lk0V9si(Ke^O|jL+m-vFerTziT=j zlA`l`n!o(L*SJnWMO)jI+Yd5mO1!BXY=c}nk@8DENnpP%1^@PTiy7Ur=q@(pegD_e zQ9fETrm}5_APYj8#!hyFAxA^?*$#E2@34tO0qc1@s2Cw7cGFuFoZP!*f3H;iVHc@C z*{3^6)8=+%RpiuYd>k3j8!3>^%g-ZD9RZF`Vc(|G^})&WeMRC8?^E1AVCwT8u|ot5 z4arCFSvNyZIz;U`NvMAwrLtXI$@1y()Ytl!V7&Vvt*=Qy<oQ&0d{n(?%av~UfgJ(| z=_)qn)^U*)F(ibT`sasl4b^rd_+>aq)e~a2@^5v#F5iO1PWbfj`L3$3pU2KWZAlXu z2gx`#_}}E@4~USkkQ~KQ725kX=m<l@uVQaZ@lRe(yv3@e=1@P-r{OC;W1!xwRwRP{ zP2zf&;qvb{2RzvE6n*ueYc-5!?8hj{nJvL??h~4%Y00FG@h>T9)TB3ld06#0+lZv* zB|2cW{<Gy&V>(KJ?8Jp&Yx|fhidFz@<9qLy50OK?5j^fTjhZercHT<L`9*m!iHjf5 z=_rhh;y4JhN|FQxT{n+gnl`HXc5R-n@@6Y!tz=|6bMuRoe`St|iYZ|koU}wvOcmIw zueR5kPWorgRhWFu<du4u>u9_Wp>er8YS?pKw5+vUi1C9*i%CwG7II<lXC};yEZi9} zI1go*B>ocrrQ=y*Y&6~MZzEI8fKUa!mW$T}DKi>Tf%(I=l*{JZXO8b!PvAX6*3H2g zTFsR&osiG-9hrLuf8-eGP&{}+91TK^8N^($8scu-GO!JL^YfD;%d;Kn&%DLm*L?Pa zPqKoLgb_f$+4$%tv6xMgLsZwSU(H=vcM1mW2O!SGw%*}~Z|-cJUDR7H&3C-0e^#;4 zZ~xX5)3c_VqC(F1@-fCA<}t%Fu5$Oyzgz*?gCxmB`mIR5=PaELuUhNX=i2T0CO-K5 z+Ax)?+;yy;jDix=6cHg)>XIB{$izCcZhK71@d7O_8_wu3kzWV1D5*0N;$|O@QrLEM zB6&nWn5y-+j*OKPf8;<|QJJ&BvUING{O;6+yVhb!ZLH<o&1|}n=|jpFvWhH-)P>=s zhhu{^zGr?lQ|b@j>Zf^vu=Uu*r%abiuoD};3p;5O#*k0c3Bm`W;(iqpd*c`zv%645 z)^vB5WSHD{+!W-cswM2<z>-*JC2eC$t+iO6zqTvyL5Qa6bUb`nWq=U=6GC~bI)N_Q z2v1qrY_axZc?t_jm6ev&{tQy#Vt8(A+U>kr2H}^G)QS$?sMS1|HX&i5@p3`<<%@z6 z;F0&KsHU=&Y1*C>a@Nk=%x3Zs%2U6THjdZHJx(z|aXC(gW<FnHKAwkWjLnuNqN~4V z6V`?=No&<^4Hj9A8PtFO?hPHwsPn}<A1ll(5cJ??L&3kC6F-Ki?xA{rP15^kvf`mQ zUhVX=%c(9f_ns@BH(FLLNA*)F8_Q#}F{JK$v!r*M=6Yr+8L^o78g~Sj?`wvXwRG{3 z-7dC629Fw-?^o-)v#m`ScejL>jtBpxballeY&>g{r<PaSHBS}4uq0nj;`W6^g)Dt~ zoLN&=UhV5(9{XPIF|t)MJaOJ(ZCvy07O>m3UPPO$%d&qxV0T6C_QLDs{<M>87T+sd zKKs>|D@*5{`Y&#H@yQO|yRo)<CfrN&$Nf@9qYz$Jx7v(Ukn(`p;drO?)8^^^%3`Gz z@5jNfmWa*GO^y29;aoF(^Vu>IPR^9t+S(dtV)X)BO<WzL&2>ekFe-KU(z3EJ<x&-S zZSBzv9(Rb_=Z6y}{P0@S314HcvA%)ft;?u%PyYk1!i?4iEC-S-YB{CLxy4V2adApS z7f6ialaUAB%M3DugC%_MTEuq&@kEKG+XnXmQ&klYJEePd21lg>NPB!I2BF!{3%t)y zOIA<vGpHTxrJPQmkSIo3LvoNh;R(kxWix*TA$^f1Z$|<dpbVrxbI+5K3}=^9vWf}{ z0^;Hbe2=Hl6n!h~3{d3a`u}=@J?{4kO>VxHNPHK7VXa8Dd_c{-v<gD~puanwjZDa$ z6#kw~p9SCb>1qy-+lBF@?Pld;^6ABP+cXj@CgFEz<;!f$=^t~Y?k9vUS=G+jd}mKe zLU+P}IYo^;ylGYp^f&5djST2-WK!*~vE`;%n3<UwlcgTd`iLBM$9>AmXdxyiC+F)e z--qLWA<dJ3UjD%4gib^>7V&}0<*fIe>&>$B-gq`N#MahUQt345{eEeMP0Mm#Ufy`K zqdCNq6<ZJ*5h_88Vxf%1a&vrA60U-xB8SZy#M`%T!MIi0@5q1xvx%H)BPlbpkEJT* z0#hs+4OY_2&5n?#cOHkU9hsY(hOAagV)F8D%fB^He*E~c(pp3W?pwV@mnn<gjIyd; zm71J#e4G1COk7-#b;r}6XfjdLg=z|LCxpdfeK?Q%wVaYt&-Kyb-Da#Tgz4Nbt-7YM zHzk1s7I`KcF73;ev4P@DFpJO41NPs)e|pbmRc703>f&-MPQ=?#6sE=XxhY>c9q}X> zUCkHM#^Rs5vh3{PLZar)&)*pEH!^OCt-1Lyi?neGEk6;^^oF%mC(14T{<6vvqbu2r z!X)HSOC>Qv#t!s6KRt+xi<6L(`%9;?o`F$+4ZS!W_j|(dK11AI&FSE=+Yo1ZUgN#~ zfMG@bN%JF%xUIDlv?uAa3F^Ya0_ayp^I2L#k5m5R#tqbvkPuv64|X#%vofug1bVIJ zsKi83TU#a~k5kBtoiUT{K$Kdm<&>x>^aAPBKhwpEP1`Bv^X;Bo_S?fGw6w^%6aB5O z7r?q>EVnrKZJgP>Jlz<urkc%`;eqjNJs+f@)ohGvY-F#uS{_VdG5}roL0w(FOs&e- zY^nhCyUS*@s2o;+@kq-0m0L2OH*Y8o9qGr9!O-xil}<+*5rjMvV5rRJe!&t`P;3n& z(L!VjXxL%FBMsf&wn#5IJsEkcJ4_ogKOK#iEf${M4URa7BT|siV=d*h2CXp^X;4Wf zT<Pc8@9dMBkETgV7~Xjxa(%XI+CHbeJXneOr$F_h)f8Ym=H1gW6{OH1qhy&%jsAu` zhy?7msXu-s0iV)G=pN>HFw5j|YePy#X3Lq5jK}QH(0)sbe*LZ8g9A+GJdmR_G&F>1 z7418p{bpTdwamHVy7S?+%P?iRyEX@62Zo1xzSqTo&INM^k5Lz5vEI^PsnHgM4WNl2 zY$fC4%cRQmh{5}8Jl^K+tnGgE1!QqX(>T;<akj@Y$Lz;=M8`6CT=$C$Pu<#*MvOy3 zL#s5(hm$`C&1t)bx3+St{L%~_+c9{&J-a-Ziv;zYj&hwurKgXWWO@cpnC8{iVu{Bj zaoAHbv|VDz6n;iWJp_^cXXD{4VAPNa*rULJFj@Ys{ULf>wx+nZz@4nCibv$xg14$p zzqoe($>X%wZL(~<UEUX6)i<{AdwN-6#w1VX#dg<xRia9x9F(6$mS9b@=1egYo6bz2 zdgLWlLzaKIw;|M;qLSUY<Ty+CKV~ZUY9t%iPlCY#y{OOgnM23J+yuV{mv|EU`nr~K zXMRV}M@IU&irT8+**9_<ZsDw-@4j@<HzY16yFS_yCz1&p&4ipb^YA*EY*$@;r8h!# zu2cN@$yQFYV26ybpPu+-*R`@yfS6q{?Xyq58NNtvv=ugroq@i-n2d}_f)O_%njaj> zZwuBMFhokqMjL;^k>9f-LzoC}tfZ*5IML1Nczdq7?u@1fhlf*;kwGgf2Zx0Gs~)27 z-Z+bjixYBiV1e_4EY5*bh$Q4GQY=J;umqmGu`y|BN%I<P0*lm8ZLVfiH!kkj-7cvi zKnx1jtN|k~7&EnU74Z7r-riS>0#?gs_iKv`_hSxVRr;D84<Oo@T{^s;DwVK`YZolo zOUY$vLVWu+vL7|e|4p)xBUo8vO4ztES$kHebi<lZO}LI_L#;gTn(V*#)STc(z<P^= zl}4&8JUb<OkWuP-aXAx^D3`rquqZ^xs}QzeNX|VE_f=aDA#(KYN7IQ%pLAr$D0X*- z$xPrf#N%pWhg~;Wh3#0LbK}{>94`Aciq~TKO%xrSbM*6cD($0-qwetu+u^@vc%ALV zIxc7fBCnPJcgi-&;%;FTtGCXwZiytaw4_g&*5~tSTUd#EnPx4_=Zyz@4NXS_y~y|t zQK_OGqbcPN&=;*|t2!>{y|TD$CuGe_UlN(@`LG6{d_x26n~_Ch$lE@M_BKdojs+E% zxwL8j{{4G*p@xb^rHq)JJ!yPg&h2s+@~e;#46tNhMqMoyF+0#dtElVcnQ5%a*D3$h zF`Qx9se1aSq%0hh*V#xe?!!&~Lh$?~MTr?59o^H@lVyev#yl5H^;?hj?+<sDob^yG zIn+s`MpdH9Iyv6b2UxR5oWl=9PhV?rQ1+HecuA<D6R%VW=<KV$KhZPae8@BLGX)uD z=uEe3b6Qx~J(`KM(a?^}blQWR1Bd<K^>-I{_mV10-W|^%vE}mY`h-86l$}`C_%k|+ zF%{Y4?7}HTf?)Gq{KZwuYSUHo_2q6>1ve``@+MYX<?Y6oFx*K$5k~{F1pF}*K8uZH z*vzx>wPVfIa#)HjneDcknDyAi)3b}4w?x<y-J7^xw~h=qD7zsOy1E-D>W2fIzh{?& zb{DnA<h44;{NThVdi>$-SL1GM+&yX29ocv@C6c=XM)Y&C8q=tB9+TV<<fT3=y!!!r z^3wkqiPvP{QcoxVUN6e%`Qga;{>pS9RdF)-P2JpIN9;GFEISU^**Vlj*s!Ee0)2dN zjHctnD&-ozz^pf3|23~#xU@F7S#f6oesvwB4-tnQPuKXtlvmYur2uaEw{q3t)5REH z-}k!7JaJ49UL9Spmu_#1j>h6ohP-#1nDiZwcK`nU1CG~-cz|H78;vhdJeE>OSXeo= zVZZ6lgZFoL_iLm8MiMOAu$GhdRDM6WiE5*vuMCYPq$l&Pk5ETzU4AC#lP_OV;7UXa zDTDKzi$uFtke@HSY3>YXRIZKQrOn2*R7ae4v8AdvI#6J3+uv*z*IJ;XX>T2dlp?OT z-WO)xdM?%@QStTZvh(PX55*-UoG*u9Z*FgD;%^~g<xj?bvCYwrayZt!J?;Kme|Si? zM@qw0ku<`EW=Grt;m5z-C+)rvn~b(ADZ;HCuz2sV>GQ35qEwOWU#_6*#nhKq3mLiM zL}BJ=V7gjMA4}9q*w8nWQVtKXJ4+ew34g&6ry5pb_SnuBWKM7WJMe>g92XB3R^r9t zFF^;>f<nt8Y)_VQV@&D&zKLvCM4X!7li4G~9Uty{odv{}-mvBG1>P02SlC=@9X!ww z!ZSthiMkF&AMB-fC>=~yZsJnLkYIK`?_9>t8#0p&F;~;V11pW3B^ZPXf`iiqlgu*^ zyTM-{{H>!=ERfPW-yHBc1Carv&DvM1jwh#j%f&yPKG5PaGL&p=iN%VAaIM;uu?XTZ zjJU`?<5@3Btf}EIPbc2om*av2JZ^D4JwhT81i|FuVT3#>6S<<F9d_lA;h?K&KkNPW z2XSS|^7Dn9GPZhx>vpn95=ef&#$^_)Ad0}_up=)nE>4mv_)b`AkU3O6JYQvy%xr{+ z#(PT~L(XI|&&cU?=%TXv{_8s)?STGM;y?#;A!941gBybFP)~T<0TKONK{EwDpP%Ez zqyk53!*E}9Aa@;HIW+dkD=PidAMB|=eeC;p5rd&m(k7^-PwICiakOHO{wLZ9D>A5R zs&J~x(R^Dvy=3l3NqEU-;g9_*m5Z1R77;RdR6=skOH=J+ZuOIbwTdlArVTWN2wX_M z$E<f^ydLKiqV!5E(%oBEXQ!4tjT`qe5MaqOSxj<09@M>@ZO1u~BMA6e)=EhtAF65` zQ$C0>X)Wfdq%x5AOIQdowtPMZbD<vcBGF^)c$kd3L>pCqK0Mv^xcsDlkS=Fwy`XVe zyuk?t(&c`Im;3B@A2PuMT)M`z!8}UhM1eRng%Q2P&@%Vcxk>ZC*vqBLf6VW;=y~2r z$}6Yj|G^~G=Ym(2A!cs?KGKL0*JUq1@eK-!@DvM(B!#4;kSp4*@%8lde2xyCxSk$v zs6Lh4OC&8?ccc$7bfmR%KM7_DhvI;+gcb+sVtd43D1i=GYJ3*cui#mTs;a8iyY1AT zKYz|oyU{kT+=9cx4A1`cf&v9?Z5a&>eCHKcD$3Ymjg~~WtNkjQbpfa2B|PdW-SVPM z%Q_A9YD0u<?D(D$<Ii9xqMg+v1m2-uYx=gu`9x%j#ZaA+l@$lfm5UKJXc}S)aeYwt z{L#$vKM?L4Oymd~8t)^NULDNw8Ju*B%SZ2Ov(cwD2S>*d&~3<heO&03skfZxFBZ-2 zLDOjd^8YNrdRIBMn3$>Qyp)K5g)wOv9Dd;9&k7>`^deo~--mAO<L(J5SA;YoB|nRZ zTb^zMhx?8d6|tSXl`jk$?n<9zbVb+dFh|T;W1Vjqp$Xl7K3KPeb6K@1GYGlm^c>;C zB=IL8ARzuWWSR9iRIGcbxaQIULT;p1K*K}K=}NYD`I*uHM`*;Gf|vO6q_aPWAwy}n zhU&5%MUx-844HLnl1eE`p<O%?w`9<=`R{kWwe?VIu!?O0Pdva)AgH8<uIl)G_<@G? zY-rn)T}wM9pE63LN`r}lDW;)dWneoUUcK@Xo-nOF?xp~(*N_?gJ@#--<g$=jz>gU6 z%5Nje0zUY>!aVu<eNbHizd0UQV#tI2{rx*HfY$Y+GpWGL1B5iM8#-FG%B(*eV7nzQ zEzM)KWXdu-k2Ge=0*5hA24ba+=c@B_yPVwIy`?7m@IE9Yq+GCR>kA*M)-1R11-_W$ zNk~M*Zow$=L&HhcA_XNSVMDn0qfkZqXAi_%EU+H@1OJ+pd~d#;WKohX)ozx6QjhtX z&`GSS^kHuF_!EDP`dG`^-DPGq!ET!>S#?>1_E|&4nL8>^#^8>KL4M<D<emG*-Qp-N z^1bb2wzjwAJLMT7k=*Ag9rfi^#GQE#kM^(aaV6A`Rn80ny}kFERySwYnY(G`0x_TL zqaU#+p62?j8zzeQO8m>t+^&v>w+AoIh)z7Tigy|=FuK)xFUpHQz4smiat~I^Oju3e z3s>oa*n{za$JrEW;Ia+J*~I<39$<{~Dto%N$}bu0;QWS_6TkcmfBCij)d@0PBM%+N zVk4v;MeX{E5=+^rzwU?$52dk<m(^k{OEMMC!6HN8-%l^ims2QayAV?iKEevsuD!F# zs+?J(uX?r|##8wu{;-LxJH0x0U4HP%VA}<cMra6j3AL7s*J%VdYCr*k3_*N$uY?i9 zunXUF$IcmYMzwOnK}vqO`FwV_v(RKsgqj$t*Rb>(dT&qd@OlF_gxqJM{~e9W>ES`e zhFw#o8m*MurF^sV9#l+Eefc-nyL4w<n`K9j$E&%r<<{gs#l^z}d>KH6<i2>kFx=Ui zxEZ9udl?s;|HPdVQgVL(JD~MyJqTptmN^}hc->e~@V`K<ZH)2l^f?~vF1K-6(`pU+ zl+n6rI^o3<y837N!+5DT#V}13+Slg!-yyxLzPuR2n=V9)Tyn3V_j>f5_)ft^=4V#X z`uk7$H~xgZsa*ICk+7n6IRT*7(1BF((tGR5n@-3jULrww<h5+Blj(+dqYy;I+c_kL zO5+U?7U_-V<K??KgUIXw<`>rsX&m}*a9`7JUADRJ$gdO>WoaK_c95l~hR9nVdf~1O z3HfJqA66`??IM}Cx(*Pk)v4(n6%@9A+e?Xg-HvFfUo1kxg}J65AK}~O6@{U2F}vEV zVb^|Fx^tb+mxeZ`zYpY5zvH%ZmxV}SlUmDU@P0Mv%YO^tEYvFxMUCn11OHs<-+6kY zUSZ~%YBD6u_oKgtT4Xf|6Qt#+9}%JtM~5k<tqf)j*f8+${in9Fr%9d*VBS&f1awM> ziM^Rl=VaA%Voe6-nuBXr*w1N+VTUj_xb@J&%KcKlOogTag+Off`Ds|Q@&}MpDU~+| zmAk)hO^xvyOy`MTww+68uvm|(u6p*Z$>-jl&ZsuEn#iVEu?=-R#>AJZPSx0(SnW;) zCBCEI{F^Np92rrdxL9BNebWCUL!1ACh4JqsrY!2=6t2X%RqsqLtM=sGBI=cwT{0^? zj+hD@2FiLb&-2ib+p%h+GR>Mm^JeEl<ygwr$Lqz$C9Ca`B>wMD_m?NjsUsaPG7kxK zO*!@^oUG<5%a|t2w&Yx??@v02GIMMm=o;jbGRO9%Q`wV})wOh!r3`mAPd5)2=F3z9 zk#WCn`#^K^IMZV=o<BdFai()~x-!3Sur}FU>vBnx@jY~6Om;EfQ^?3*i`0XLLnnII z7wrqhaz#*fkCleSukyLuYFEli{$oBW8xY6~Y?&2BFLPa?c}R5|)N!X<=*&J=&0Je1 z5p+*3IA3g2nGX!ok+RJH2@A5$lAYV0sh2Fr9QoO`%wbm>Ci2l1qSi_&sL!e+reBT= zCFY6+xpbj_I-0F=GZe*;kbbi|;i~cB&ye`f*(u%v?&-u?Gsj!K4MK?_ty&35eYul* zA^+XXi^RGTSv!xs<0qUq^vt73ub%nm&!0u{8;JCbpSa~O-Z4;i6#cv+@)QyiHo613 z;O80(yxhsD(w);}skqH8roFqJy~WaZ3_LH~Vi;&kZZvaCUR>66I-^_5&3erEKp$KB z?80c!7YQGW(0jDKFsEa3eS7w3FivdKvXC0x#nADLSTgwQH7i%%ki_dm+kM<Yq!i!P z=03GC`|a)|1bc~3A7(qGHA{V?&))InS+2_0@eH2m^fFtphs~njQ!w!Ke9?O9A%v#U zc~h({+g{l^dSN(5mXG4%RL@JhIWF)6=a0G2hAfB?UEPzFw)n++4}Vzri~U-&JQlN@ zAjotXW{{QKO8F8-z)KL>-F0I=%b2IbCldL-(0aq>$J|h)`5Xo|;pnC91~Cag+It+F z{p+9a^~y0V8W`7C%wHT*Pto5;E>D#HnFD$O9^YXK-?B~ug$VMowk0iT&uGuXi|tbV z6$Yv6`SA)>+ChT(U%R0%UqmUMZNn-t-_TQnZl}0?z?Ck*#4%_qiXuO~n{RSvaJ{=j zCSZc9m<zRFv14b5)OxsyO-~e6($w7It(MaB;#KG1Xq@|%e-qA@bL)XCO*w11;5&2# z7YU!416-}}*bx1ca6mV|L^>x+iB9H_Mnhl>#yHD91x3|&kc9~H3p=!kz`{Dce|aK0 z@w|LnQa~b((Q<ua(wD(QJmliZtFS+vEjW}Qr-3L!hO$2ktNy33B#Rm_A4Mf4iwY_# z$sJpKCej;omW!rx4fH7cb91nfCHmEBYx6hS@^2!7`Q?>yTF()6UM?|3hX!Ap<mq+| zBiuzuIO-owmdx$V+k#54w&DZbRBs|1Mnb|Jl`;Bv)hkyylQ#_H2(22gH8A$4i!(}J zv**5i!f(nnzRuKsjaK%|k7Pji8W<VMt<4i+0O(}W7dEP(>gwu^kdk|*WGRc4+TaM! z`?R5{BA!n%hp`wKuMR*$IHqR6kd&D_Ew4u?&cH4JOS+qQsMc!Izuxk1mMeFb+2z4Z zs0el`%hOdq_jBG2BDwhQ4cUwe>abGfc|a7gmd4W`{eAn62#uEr!{(xHZn9YVy-mvm z3krgbDgovtM5$&zx!;TRx<3Uz3kqPplpeK|KJd{ynABC9Ul<=3?YeV-d1V-jP&gDI zE1#8Pdi><PDji$P!h5$*6Bte;dt$ZhV!N-z>2UC;(7Ls&dW_GctL5bU<mG|yna2R` zXt8c8U^Sn36Bei_)}%1AczH|fYo@kL6urG5qX#rekkb6^3k5d6qDY7~oCMU`3<21# zblMe(zP`Sl(ln&pX~d~0(#lt<jOcjyAu|@wifGCe33Pk&1>x<jFZv==ou=fJ%rSyZ zP27Nl0u)q*T`W2EC#XV9>lqcn|5Pr1*7ran(i`r0&UZH;7e{l)#)j>|P#UA3DhX2+ zF2Riq4eK#vo@h{Ia9eRJJ-%bc&u%4%Ae_mx_xSU-%KpB4M#K;D)1dd7jZ#KU*VkOP zt6RMzjq{6(U~$Q*v4uUM@@h?;5;dONp=L*m<)+vp9WU|kV;O4~RYnIYTASh+goT)* z{E$5NSGj#ZAT^ikX#7OO^$p!P!^wl)q*Iyezp)XvZlM0v^yVR|P~(62G%^di>+9)G zn!JzWAS?#M*NDxX*w|P>85z_j4h};T6Gcsh94g2Mk0L^}l)2D?5})@v0v5C?p#hxo z@-S57x~%xYCrfyKv<9rnMVRk`$cM7b`r*255i%!rly85bf1s9F3-p>$Sg*q4HGK0F zh_(}<*S$N{!bXCF#8;*z36w!hkq9AHTp;l^JCE;>G4p1)!=o9`npdnlwU|xifE3Ht zW2G?)+tsmjX1nJVRD{)yE%yB~q3jp_&8s^bcW(A2s}vwC)~RZCJ<0O)3br^!C!|S< zII#l3*Z9!$W&&i<@pt5~U{wR0k(4O_a?sPrzH)ym=qo5F9voTt?cq8;|3j<xJxGZ# zbUd-%aG$|AFT2rzS)$frOD4;G3L%pFHgU1s89`1N<KMr^q!C)}_B1CvyhpH`YQ5Pj zT(aE=*JX~*Odt6W$tROZ$YZ)xhWGOHXpgb+PfSMQUowZi4QKl0(Ns{F=L0o8UA}sE z;LfEb4p_KI>7OYpm6UsJA>C!Ml=Fd_Rb9<2F*Hccz_4?=-c2wtLcu^4ly+!=h=f?F zUhWSMkNLe00|!e;Uk=?YI9Mn!2oncG0QBOzp5DAAt5kG!^XXX-#1l<b$unx-PW|*| z@qKBfR6OH`aAY6ICVX&t>3x@cdRX&lfA4U}`o3ynLdxw{k31G(<RD+hgL~rb+xshJ zWx}=>FCg5HF=+T7P02#;+AbK?TKvVrf&~y5z~kB;1$rN_@Cl@rdxVy2l$dZZ@x<)} zpfrS0rzI5&7@zVJldjH(g#3e`8E@|oieuwoc!{z}Ncu+JVh~7y=RJpax(V?IH~R=T zvI{e}Gi!{`PPLpTj?RZ@U~3koTdt4Pp9g8el6ljq3Z?jGSlqO|IGC!c2srHg-NeN~ zJ8jr^U3;-#V`Afu`%l@K-ZB>=;f=Z8-T(va+##c+k4UX(iBMf}g?HRj00MzJyE%@d zf+F60A==n*Y9D4SRW8&R_xT%Wt44l*_*aX86~*#0w|{kztw`lLGd>vaX0#c5BxB7S zoti$9TVp)Ys>KD!M3q#O)DaOW2Nr%OF8PTGK&E11en8npNkgIf6yt((`VkT2k~iOB z$$4B-2f)H&Vd2=3^AR-+1uX9MXsHA)u6L?yM*v}gf+@POh#Dg|SNvx<1^p+))a8g? zLy!VDU`*}Op9mFES?YmClg1S9GQkvw3WXin%UjwLnqm<EhUz<tzj&KALkz7d;`>+x zWH@dkqedP=<mxaUa-qzjgBkmcR_!nm1L9Tb;$0#$W_)Nu4UoAlF-v;#q#ZFHXGt?M z0;vIjIL$_(KfM&@+~nny%xudkVfXGJ)!Lm`L|n2HxU_0p;2;I2lvIDCEkcFgk}=7D zN(tP*SiiVqRH=2$$(fC>sl@`G6oa5F2yWSG`8Xt}^mtN%TbseD6x(n4S15HX0yl`J zhM4fe@0)JjU(zGB_bVBJ<GMYUbXkYR{Zdj-_sW5P-t0Pe3l0r6_}h(k(YMmZu0;>r z?%KeZ$w|8>aI<N=MB2)|$|Qf62+@v1{MP^~X2JTNH#72Q5p|A%zMQOJnplkg+yMm} z6?{dX-_RB*8v~lMa#fO)TA0X_9;5D;<VyVTc{-eZArXx9Brz#Nawd8C9uZNpfIyXy zf|OR7=bdM6ysjqUsm?6{W_*O}9a`nEJEl7x`DckkY~MbM8olcVm0|^0%>*OQ*1-o0 zMtr6ushOVY35#DvN;*v2XFq5SkPu17<;z1F`gED~ikf-cMwRPazo2-uODujbk<qsG zsvZ#f*&*TH>r_o^P_I!M>aN_YGQrfvm$>k~{ITWQrE=cFO;1I-loo0I>_^wvpB(}5 zd|fXdSgNmtcZS`zU8Pd|bS;ZQDr>m~ibAx1scRd1noKJ%5o#eO1mJ#3Nf{^r5RusD z*QJ|Pl;{7u&0V%p|9EVi1toSu?4pQTN`wrjCV8Ib*H>oT%9If|62(&N(1oy(@50p! z4zlSvN-GYJ9f=7URgz@vp^wSv6?=7vB#LBTTtAq9@3PCO!mKkdHft>~cuKZZ=9q9z z-}ms|Ho{&}1^mtJx3mRif3RyWXEDSZFeRsE!6FZ~d1=t~R)aD1ve52Z9l0pFmu~r< zyKF#27-{<Szw;MsVfNQUESkR3YOf9m;DdkDT4?QG{|9D;B+To1ga7^*Wz30rD9$o- zQ-`Zj_veM(VTj37jd?fy6C`8n570U8dJF54M2OMTTv?=Ztpv!W5BlcnKbjzuRLa1% zq<<+@z1Vj@(PIgbq+;h2mzLQc0BSuK#7_pOzN+npr?B(~lBNKPTP$pO4*}vLtw&{D z1&mym&3f&n=~73_R0k3CPwPsR3%A#OM8%8EU!dWUi!9Ayd^dn_Mn&kI788T<o0QCa zG3_D-dI6STl!20tA|lS8x=p<ikV#+2#sBPGS6a^T8`C}_N>4T3m9W-X&aR5QDO2R1 ziXsoD49B0SR<HS6FG5@t{qxkOjVe1!Bn%EOQZ-w+n>@qoRAlf&j#B7Xxzzq@|EZ&` zkw|a-yO674%~~jN-&8lPc~VJGRgVsxHZePq{1=q+f1y9tdc<N@e)S)n{lj?~gW^BR z@tH7P`}MxXx1j3r0A*P17TZQIl=i>#92B7)+m+xuwOV;$b0<2}*_;Fc#I9DAfrq4; z^&KDj*Y|IW+vzyqD8_$-QRL{s3#%B=4|S{C>t;-+>ErLf4@fkh*9a6?(ALhA0f~-m znyk>WWTXxOXgEz>@OiI?QeOEEl=zIYeNrTP+Gq-xR~jFT@&%%GyiGQ_IPJst4>dSm zu$t@~>N#OmYdK%1YA@UzO|-QMS3Pe&K+q?KZVe?Ws;Q|Bsl2k0ccF8Ix=}`x*1Ln9 z=3MJGu1QU%utOconu`VLSOB3H*xcS$(A4yhczAUfncmOI;0G_L+g77*h9x{LjbLza zP{#bF1nb?q8X!9TkaoX0h9#z<36;+knP_pgPM}pkZ-}%n+1%O5lw;%|K>ZW(VQ9TO z2$B&${BXX?4?L3{Okwf5HU&IFd?$$Q3v~=Rc!o7@v4I3vTrd3~>EGGxpTz6Qndx=E zCvM$gG=w7(hT9cGA?X6hio4s5NZHaK`Q+k{7nv`HGbPG}ttVBq+O2?QYKf$fOsF&* zz+knQhxn?XfHB7VKs%E1#Q?~k-Vf}BgTAmxYK=B};T3H_$Hzs6gF_=k-i0zBPGTb9 z^++-rN=TRd{OZqqyAKqjP?(*U#^Zh3xb`#30%+8pNABpVg-~Z*eHV`?L2~d105?cU zNdegbGRHu>9vB(P2ka;eEG+ExLX8PpNl8phjBl?#LKqRZ3wlsDKM?ttn3x)utxyTM z`vJeuKRj#*v~w7E_*g(AP>VIW-&lcVsNLoU#BdO`x&q3jX|Es^m(>CnA~`u(EJn!H zl>>;ir87WY?_Re-$H&K?|FdPM$AVw1TA{txiin8F4mgq)rz27pmbhD&w(LTnpRcxi zf=4AJ5RGf_8WzLn4)SYj<NEu>5Rs6o7LWV`0@iKVaRDb|@F%R;=?UbcfiPKF$tXps zST_gm85kR*0wqB7_<HlHNs}H+m;_V~<arECOeS1p2m*E+2oN3V>yvhMbrrn=tAhU_ zGnE?U)8*gZ3Cn|aZh~kGsKri4e*;F0b3rflR}X_80O3tVGMBSe-E%yUSQf2X!W&lH zLQ}1p_t;Zk4Vzr>Nm5!FTDwNyurPM;iE3shhq{1nIy@i~7#;VO07(Pq=kv|FEq<lV z{o<%$wc28VSzlkD-Q$)qrQnq&dBrg{!r9b1ym%;MgF%}CjV=n3`l)Qz#vsiemzWqE zAK&|Vj9U;S+g;ZK-p$vVVS=tcTxm-MD)z;i9~#K<kNyroT4=N-1KRuiyxN~gqA_so zBMptgcosh-*THN#QfIB%l<D8vk9&K2AS+}IvdTXIqmU3!qY6H$`Uh?bka%A6nk%iY z7OU;)lamTyhJL*{Ud97s`wA}2mZ`_Z#jQED1poZ03wEZDV3rT3vPJ&<`9?rM0EFM_ z39piYQ%ib9$8!o89f-dT*0Nxrp;$}$F5?#~^`Na=&)`CG<TNw}0q-<4qpCBqJCQpu zI4B^GmBMN{2n2cDF91!4L)IOLq3{4|1DIt%MFz*)h*?<^sto!R)YN{0WEf}<fOC9a zk4tz1{`2vChygcT1Yk8{l9C$}qC~w`4K;e*aQ`+o%vM_OY){<59DYTu7TVm|MuZM1 zfXTX5jG$YuwCLqDrql2#=%SlT^M19p8h<v<PJbgYM8(AXR+QyYKB@y9p;Dnea=tYL z>f!)wr!mm7L4ei%d~c3Jr{O<hY;b$J{<y>UvK~y8K@2b<Ah%&+Vs`fgW4i8u(~ev5 zs!0H`iR8Vf2Gq(X=zBDRjZlVmU0@dgr-Kd<Bc7Y3?#X<~S9K5IJuS;#X(IsSX<T-D zVFmChSW&N753n5$CoAdT7sHyoBxq>eoc6|w`-xHK56H{CDJsUX!-X1o<@nyvchELK z#(AA-K+69a5n+6~*2Vqucp;U_8h&@Nqo}PNF=5(s<OI+)DD=u)$}}0OsY2PEf>bO0 zwN4)oV8Ns^dDFK?Qh`Yp150xO%s4QtkkD|I=5zF34@YdTpbZYK+E=imWWjC<s6`u1 zI~lLb_!U13#-yrtIn(ETx>U4kJrgk=PU4r7LkBhV5qY<!pa=^K3yF%(nP&FtlK^BJ zY|b$={9ZlACvYwi7=5U$3i`5LEthuJYX8m>BS3n;+A8pce8*pe<#%UFRXZQf0I;Ud zn(7Kzwt>-6@CGIybS(=DTC0ZCFXpqA9(Q)2+Wx`88~`!-+;J0**%D@?b2-NVGRGj2 zCoqQ^*f_9l0LCRQK7Reor6hoef2{aC5*8jF{&&Eu!uBT&?^W>j_lE)ALDIv6n>Q1! zV$OZ3%HGbdaU+5YYOKX!?>AUwz+0dIf(L+EVR?DvU~NMUtbxw}Hj)W|6ZjQ{K!m9@ z0f?ac_2D{D^9*}Kup!8)sK|zxv$L~-h5%0d)Q^{`e+H(JF?9qCVi4f>0LB#9x6!p_ zH_>EoqNEITn?PVepwS5l!Pp5YD+4jts^NX<j9VIy7rzVXl2yYSG(_M#KdzPY8;*eZ z0i|(^8v~f48D`M&V2vg)=*YxUN<;8uip7AlYQ^<-45Xw`KjPxBfQr~zGsY_k{4a5X z30U#3d{d&1S28eyfWJEZQ3!vT`UH>~c`R7*m?)!UAR$gv>Is4gA}S^(ru!==hZJB_ ze{0R8(%9cBD+81O=>w<3n>TNT<<)?)2&@XsrO*Ya5wCD+0NB7$u$b_e^o7<uK=-L0 z&7<J6=-!=gX*w@EvZu><J)Vi)Umt}|?Ez&RCbG}3d%bhx3_$%L*cFzCs)zJxVv!b9 zR@S6{mldj5IwO$_c7{OxY&!e%KAIfCuM55Z<P!r!g%fh(kg%N{Gr;V?cfE2bomV#O z1ndN;U`9b|m8sAn>D6ffsPSvv1+?j89s*zxS@ZMrfe5GMeo|9iO-)0StJfW9@=sPA zOip?{a0HeDVdZ6zh<+N^MY^RUV~v1V<?Spp@C$oWg*DD6+LKdL;<B<kV31)P_~YZ^ z9F};&xeg>%O<P#7sEEM!d<(!wdH_QM<Nw*PA3ekS*%bs1{5Cc=bxWBo$IYRDF^ta0 z7=66EkjDxj5eys$R<BdDI|$9BFXDrckWi)R1S#k>Q8zbE=M`6ztl`cqe!tt}mJ=~q z*}|ftp8%5m=fIiF<IdW!>cs_~D+F)#d8AWMc(voNOb-uFI@^j1^pCTRK1>XZ-|5aP z1Ir*02W)E7df@xY1&f~E-nSSS0>B%CmVvPbzFS;ELjUM*osap|cB(bhDQI96_{hI? z=6CBsM6Wa<2r-7!IAUda@BFg`gY4$CoX`H6SHQ;H`T6+)S^*Vsqkt)Si-YrLD^X`O zibT)_NSk<^4%EOMm1(zeMokkE5Fme5Q^R%KpGMGJ1TB}7llux<31|p}HydECVdCQt z0wWpePLxQiE&zx{8C(Hy6dI~47|4?tsC!S%%)5VO*tH0O*pq_RzM!^P07-22JU?`Q zHC~KKPTn~fuUq3YraH8pZXzVaXt1w@u~@(L>r;05XCFR<_YM<ARccUrOy2zmY7!C> z0FDrkc>|WD%Qx`XI163W8*S{4zCVV{%HN{ZG&REt%=$+1%`~!{R9swKblt%wZD<QI zthgj(Y7g1PQ9w`-T070)hADMq#;)a+HY68^bT6F^oMb^!Pmovs!k7u}^IryXK5HtS zjrQ|+KG@^3v*W5KKvzKe7|bbo4|>y%3pRK$BrjX_S+J_Q^L=--_TVKlGBN_b4p=v+ z3d^O&Xi*~1xF-9ZXFm6v4>}und|r=^*8>BD7|fy5C2hGPA7_Z=^M9)2AC%^|n3k*5 zX_V{KsYL(9sxn8?55=3t5fVrca<ZE}iDbVKCI3z#pgGo;8yU2+(_Zn=JjT&9_R#+4 zA;;_K9^y6J_y|%zAf_=p|0>UzJaV}|8*ZlK8IT)_#Lce}{w|`82OQZ?W$T_UKAjMK zX?i#>7ri@7l;dnD9{ah5YG}yQh@^_{zmqAE-Koo5WqR5sXZQasz%s9jMR=z~?!O@~ z>v$LE>|Ih18EUK$4@hKg_R8wYJQ0`aqo{YfMKk+Qi%3X+XdN3nw4>%IoKBL+nlv*Q zbZLg4`qUoh9KSt#T2~qy83n}0E4LdQcl>hKVK_`da<@KNcJg*!@!NM~$X8I`byse% z(z?Ig>z*zDR;<&(3*gvC07(JFG*8Trh9BKOF?z+tSxTjEjvtPuUg*@IUxj*oA%L_K z!`}ojacbX%r%YMGK5$)ULlzUi@jW%Ag<f@sZAa}_Yrh+R`D56o%xq9C^n>Ef*w6fL zm+~49FrdypGFWv;=}rsd-r4R)7HgV*>S&)6P$jqqldW{CgBaAZ9FR(OYqp|d_%+dl zz%Up>68-f-g$-{yb=TzpntFnNeXfg)7Z%_CtK66PjX<%TcSczU+l#e&`mZrlsf0I` z;0bNU1jBl}CW2(m2myLgdR5}sp-yCG4sJt?YGUrsl$bVbpCcA5{+KfBGp8^nhXK?F zs?-AuySvSx`o~r(+QmhyrEcIa%TT_449Hmn=G2kh9tfj#4vLP{^7cw@o!_Cd^r~5P zlca(o#>Q}aduBbW&Al@;iH%-#A*pNza>dh2G7{t;KW68Z(!A+6vg2;`$Xkk#p{G|W zQHn>z*6Ga;qtT%Gz{)xcCUSL6O~~U)J_EYphku24uF$KYEfkV4YLSAJ-N+WVJ4Dqr z)e_CD3^+A-@6F9M>MZU$)4tsR010=8UbA2F`Xga4QSySt_I{nYzGt_BNVbxGc?~HI zO=>@;XfU@|m>~Q$hOG_J*;zx+lbFl;ZdrM;S``M$qjsT88{Bl6R-`J8sxW<QY;tn& zfRclF3=*7r(4E-|YnF>2?OR=*h%jW%hld)yK2$3L9*xO5*D7i(0!}AnKkYGh5MpJv zP!{H$KE!>DlP|rfjt<3!B^-(Zk*#E$hSbRM@0wht;&D?Jatg}o?{^r#>n-)ietpPW z5s$u}*eiSGSlip%UEJKV=H6G<)O0T|x51dxzi|Zt?_7lr85b9PveciER5lLhV}f_1 znLA3Gwlczm@SV%up#^jr6ZKjU)~yRT>2+T?78WK$@MR^f8FQ32Vbz(F!#dbL3`(wl zJ%d#z?Q|npSWqff3IF7r$n}=cPonqVLJe?I-n+km>5a3u)!TeHF*rCtYHAwG^3DG_ z@us+#xEVo5jX9aX{Jr_>DS~P}x|#ynb+sN6h+2FU;H<Mi$Wv>v@PAyrcR1H?8$OOA ztD%gvsH|j#C?lgH5|NQjS&@;wXHr>3NLE6U>{M1rWtBowiOj4*M#%b}_vib3kKb|p z{&<e(dC2?y8uxu&=XIXvb=@&z9k~}B9ivlHQl7q!<CG}?CV_b$S=(uLMDv;Bj}{;n za`nv#@2rQ4Ln{|`rGvv5vsFr1ZNv>ggNJ91e>8iybD^gsgyZh}<*G%eA{zbvf<IRp zEN;cd&ZkZNxYJa*CcsGJype{P{>|~tr2@xe<5D8+bw96B36vb2{ISnzi|V0LgAg^I zi%UNv1(xkt4JGo|-B)90^PZnLzV!F^rLV<9#}nGNULC%zm4n1a&Bn&&>*qK6Id3OS zZlt#X;ER;w&+L0@T6P<bv{kXK1g}NkD;>Wb8yix4KVWQTCu2NkE}hjxRO7wpEbpw! zpXJTZvUzT1GNU`GA;i1)SZY^eW81U{U)-|Ks*Fx@@}54JQf}PXb<BTPbSBrwam`%q z^ZJGZI{8LD3;UQX=(29LyuJ4Ng`wK2xlDj?qK3M=#OKdaNVM+@&Fdb)+^M3cx#ebZ zO3H5Ia@TaUUy**1AO1^`DE^Bt_nH3sQhd92ZyoI(8ODPLcPA#YYpgh#(-nJDS4Krt zGH;T5UoFj(OH0--E-=@!E^4=$e&t<c(2F0(4<)|mOh6M}Uf7<AUxOz)zLn~G%<}D$ zzNVTpXy7V-?UVNE>Was&yeIN&vl^noQ<b+GExvsFw#93D{eZIH+thAz3fIxLP>?0< zs3*7Pr*q2eoEz)7SQ|_YR^gCk6EkrtZXT%q*_0I?v1>^--@&r6$@ia7osVJht=b<+ z)4>AUK2}{1{_pC9rIY5V)*WgZT9CNhuv5@L=5ybU$ZKFk)c&o_zEk_Dp7eHS$7A!! zUe4fy>Dron%r<$hm%A!&7gR4?&(+j(64r}Sky|-YU{a-8?j3w~-}1@|UO0CwuZ9&I z`O8(FdpZkF{#p5OF6W=YMo}@*n|uv1!_@jeE90M}4G#<Ew&&3X3oM>X;G~@wODrrZ z&GL|^;C26HHh1r^hLN_fBGozn1<LB1EIB&Q^Y3c%-Qjl*-4&<$-n1lJ?1iaEzLIe| z=z=GV8(C`OrrO$VOG(KJnrC~bsO6DD56Rl9@<Qv*O;4V<o)q2GY9^9?t8tWlN~*iZ z;gmyuP};ELz@(r?+5!3X=N11nygzx-{(a3J*%$81N9;QDe17e_;Lv07`BP4%G34cy zWlrge?fm?-+{bxh&F$^q-?U_4pXqSI{v7#~vke_owI4ndWajeHeu&IBt|;zH3$Xck zpHffA)MBC6e^=y@>!p!rZr>@8+;O|vVwTZHQF86=;LjZkId}kACvTJsl&$UG_u}i} zpvUs?9y~s<bt^3dn&;5L6$ajV)y8fAB6MfpX9<a4U)kS!WK`FfiEP=m>m4B3pFe*N zj6SA&<&q6+FwopRtTh+0zci+P(*Y-p%OcdX4;C|Ta`rOuFqd3Y@>2L*nJ3WYJ9wj+ znKJ%t<*fHpsof#L!Pk#@#T>TlJT`mlZjxl;T$kfQXU_5cOh$BB5lB|5*#rHdE)mPi z#~paNTc6n*@@S++C}kWN9mDrF*VTm_b@|ylKHglNtug(ct?or^Ot7w<4%g65Mx{Y# zc3CO$^ooG}&T~rssnsc#hN%KbZSiN9@!cL33<Y~+|D|0lc6j@SNz_luu`^fMPp-N$ z`QpA8TUD7Nb&sn~+hc%1MELLrtukjzRAzrqojyhPs(Ato#?S}3HN=(B-G-9W16NzO zM@GkA{G-XtSj@OA<G8fVjqN7IX-|n+?<Y_4*xNETbVhRsi#L>ejkCI}E`&UD8~a#z z<zhqA*4ntUj~fP^ndzxZve({5<?X!U?r!z>*H>*c?PTWi&<aPON}O)jkW1IfxhrQ) zGp<`u)1<0rF@)v(F(bs(<d&sp@qch4b$4^k{C&;`pny7!w{P3ooQ&R0<0|h9@)c)o zFO}*h--xi7c=v;HyR5f3c*lc%26V5&v(enixLt%IP``Rj)yPP|wzRyVNpibd!;q-A zfkAPq89^3Tt;bX2pV-w$75UfEIJ|y4-5J6DG*2(uJ95X3LwbriT(ONJ>>J;uNryar zs=d6tOuK25(5NllD~9obXt}q|?XhCn8pZx|s!w(A?K4(vG7}kkFLZfQS#M2ga7Tn% zYW2$P|6<mMRFi1c>{zWM%gfy!t~Osp3JlM#*Hb)@Rr2|Y&6<f~f-p@l%GJ7W-^#Dr zanlOt>zVq+t#bHM)cj&USLVFvd|QLLb!TLQ1unguVUEV%q%b8bdJBP5eC*z`y1Kfv zlb>#Al)GiPr$~`kESROGVx>g0H$Z*A^ucfxSM8{|V)ElTE2n5S?YbTvy}9#&P|1Z+ z#X<U$w}r1dh}@gjI`VWLSE%NH^*>ao8dV$E@;P45*Ke<+9<DVftJUVH+w_sHXP4!3 zJEr08PS?H}*R;OxQdvcX*oD`$6p9Ig`}PWL3VkrL_KcBczi6V2qq}*<+mSi!j<z$K zHxYn$M<C;n@QbZiwN$a?MYew}vKRaJ-RPdAqdMHbr^^k3&)Tl1p#e)=;PiWp#eMSo zHT7)4_?bcO{Z(DYU-A!?d9RCQ8_aUz6Zo3rdDYuUl$}}g<wgZQRx1~iUVa%iW_s=e zjVhN7(h}}vf+6QN+ONQ8{Jp#T657SUw($B6yO+C;2dVL({9suu6JR*8q12J_uKu%8 z5f|Ob47ZG?BhrJW<;p;7&6jzO9%8C8F>O1{bXD<dSJ&{yS!Uz>57b$zjfv-YUpS9a zMMXu4JN8s&=5o<ysV7O;-#zTYQ@?MM^I?8^$27eLp@*(=G$C}61}aOerC%%OnLXM{ z8amh*f1U`OJ961xzw83FnBJ3`_Z_8~cKc~VwYEoIRZG6EmBA#a|ADg9pz%)z(_J;C z9g+?aVPVQDdMaB~Q$VDiYw1oom>|5>ZE+uqpQ+$83WgdB(bFFa>C2K|z3m967{BsJ zJ6Sd$HFagFy})BKCO?vs`SIy&^~{G4`?Vjcspt)5@nThv%q1UlqoR<LlY9EDpPgeL zt#An%Af^rG#?Va`67b=~^xGuIy|IlqE%uIV@H+qX!mXtNkt9w2IKIJt`)#QjR`PjT zEQ{ineT{r^{9CtfEo1WA9r#!$H{L07efsR<a}^R4dP2tF1U4i-u?WaLnK`xorr18# ztJ!;BCVgPb(o$H?OM2aN{p~k{u!ID?|L!i2U*|D}li(PASy>tP>iq*$0;m)&JUGjz zqW<#C1;t&KO)vUKNA=ruuzs4in!S0`{o3r~{@8F*Q>1IhH10ikkfG!&LUY~c&(HpQ zDe)m8>nL(Ov_#m?+?kc9LskgpWZss@81b+2M7eG0j)Mntx8~pGykio-cPp$T9&3UI zq}Wj9PGl^eP-p41Exq8CY+Z9%!e!$7(R`CCgEk!|)l(|bRmEEZexp`-bAo5xK(~>F zYF6<H$K}4hK2ma_0x&W%@<iUe1g82%$FK@Fn30Qb8R2(EpRZQ#$x_=63}=(0KvQIf z^H9?=8i2X=JF<%d*8C;xznyS*mw;xFsHXJXq5Bb{*zMGdeXl}&ryF@uZR9jGu}oiQ z73fQcLHZ~tcfEY0+x`NndPk2QO+IoZ7(gK=IoYVKgX!v4YtclaVi;GrTjB$Lbyp;y zzp%B$S_2I*Y30i!BQ`z$OZMn!J-@!x?*(W<LI8g*F#S+!*ZIPEh~D}`Dz}i3`Zwh) zttyec(C3aneu7#t2Zg@~DEu;oZX3_kWc8Z!?{9~}q#u`;mk(M=eG9VoD~NHAiSJ$` zFUh9k<GUUa5wTA?;L`jB-*ut&F}H8mf)^+J)Ujj7l4X73ArX)+aBY5_^m+(k(?~#0 zi_?}U8*EGOp=G3ZbhHuNj((N*Ve6J;2qCkH>W4KnG_1kSVjw_f4MiWcg<@dd2&MhN zZUgTne{k*J9|GQV3;3Dw0t_rdH}ktOe%cQi=mk22w?Qb}wbhl|%|lS6a63`4vF+y) zgku}OJa^=%O4FRSEHjEKEj_$nIVuw}54DM8qFRGRF(~B`b8UW>4V!lH6<&=|&3e_* z5eF1&ZfAGe%8G~3;o$K1adJ{fOIKtc^S~8iV$9_J-#d5jK6B#4)l+wtwx3|oJ>WVw zrUNdu_D8_l#+u}#E@VN_(a~*|;o;^EZH(oOO-+po4`*m;Y0(m4-M+m6bodoFH>{-L zM5B;UlLG6eI|r!aWnOsx*@yWdd)e99U%YtX^!JxO*jguN=L^`yvlHEhGMDItt6)G_ zU7pbZ19{rXNo2Z0B_>Xln^1$`oq5H?VhdjWy9vTYwSMU5Pf_Q=Qx7%LgzPK4W_SqK z=C|}0GZIp<B%FI|D9LBQXC=3`ECxQ*3>dlXkhI4H3AUigDFXrmAhFyk@JG+@FeWUR zL8X}e^)(g<n!Fun7Z?4PzDHMAS6zR7xs6X}dm&M3uyTI#Bvd+C?^)72M6h^<a<pmz zDuo+RtDG06%wH}|NCOBj!n>rRrZ$Ko4f0((5Yt1o#Nb-92E7UVh>npl6BkRGYM~L1 zmO`$1x$@T#V&TF_M)cJDy!ETAbZvgK3x5WP=<w;2_Rn{T_`=-~edH)IKQvi184jpt zxA#p>YPh?*zx3&<URynlR!X$DufuyKs^Q|82Nrv9NXVrhFJ;lO$t@ysYmclqS*+@* zGL6vN%G}1|pRR#M%o=AGx7mW-*$0Wh0$ea4RqIPXAM(=CJ%0V>%?qC%X+p*e#DEtd zPBxx1_g)XD1*8^is5KLr0;ebn2weZ~or&wd8vam_3YR(_vmn(cAM@KGEG$e#MRiI= z#T-kRi<?_zX^*sf#6i9M`)B$1^zwIc1S}sy%T2b&WY3GTGL@yQhYzW!H*7Yk^t=tx zlU3M6;J3?A6U(MuM{2HZ-1)+HQ8ZVt;3s(cwnJcY_e1gd-Szx**MkQSNE`sgYK8zp z5<@tfu&8y*F33=e*j2Q2bbX+8DTrF7U0{-eef6<AAmG}j-KvQ`@z)?@D5akr%+0Me zGXvEM7P|0aeUxtjR?c-?1|+r@PJO{oWicqhYvv~*XwRSjGT^r*`0OiO8Bvn42E2NY zc~_-^LmpzdfZdHW+mGHnip;F6KeZb;AReegL<C&ld-N!~hlhvl=O=XXc-mQ=6wt&K z&CEE_;wf(Pks?m@BwB6nO4#3XO%=0lnF47)4Y1qS+Z(8xO9ZE<cAZhxtN+4nJ03H! zu_<S(r;yEc%VTp)^N<nNqRVj0m4CCBT2iEyb#*_lLzio+?CeNu$gf|QcSu}51>Gn` z%B}xn`ti0oP#n?oFtsDD@$2QkLt-Us2pz+UJh7VTiqtO``WgIJ=JayD1LBLIAKb{; zm{7{tMOpZo*Y))now^OI<2ka1pp0tg8zqu*8EQXZQ|16gWo6|f!{<U^TjWj5xD%R- zo<H9(eNFC(Y4sjcQ&SY$lt=vji6in4fe#eF{AEkkfAmg0kUqur$jB_bhh%AwD1%bl z+Za{wZ*Kh0-@k9aeobsn5H4{ZQbi3$alXWABeutz#>N{c<kQdcHMF!mgnn{FO6q}b zZjMeaE83&#-@d&Dy#<}+8fnM;7I4#~q%AeD`jGk_PbzDE6q+Gu^ldwLCT;Ln%DO$W zPaqVe3h51#K;6|{!G@RC6n8L8E5~AWdGQ6nr2DV)4nJPLM?2^O*3}gc5BLbAK^Sc3 z<>meL>(>G%R9sn!KAAWF>uVhz?IUpQ2+%|LqW=}EchQL6H!yG<i4+j+yuSV+Oe!F& z4eK1P4C|q$IH+~)1*UR8TT+_wfd0(S^I{QVlarT$Jl)vX*ay@sZ_<0`-o2(!1~!Pg zVcKkoYJbx-o?4Y8BF-?eu!JgQn4<+1Eop7AV35fK*g<5MLiPUsz4FqWq{DZ!!G_z| z8oPabmewkR7+%d_7ytyFTa$eQ{-TMDhK7c&Qr+vGpHx=fhD-&?+Y2Pz^zOCA;j|K{ zo#h^r>VN@(mGLD&@NEc;zIm)rY=1&}N=JS^a^%SUR-0SRLqy)hYl6_Cj)^32r|pM$ zCu-S5Leo9*ORo?~J<)xIbjKH`im>?#;}$-S&wcs&mF&AJ?>TxSQ(awFXoRS`HEfM{ zidiu_R?V?OH_X7Qvk~8c2!s$jh-kLH1}g=LKNTY8>FzY(0%*Ju!f5-z#0rrs{U?Y_ zdTe#!BB!I1Uy0TG^T^v|@n^Jx1FK^*^(ERVg^-XCQRR^9cWvIh`Q^W{gP0qkO5!oX zb*A^hI8`kzEj;%Ps#!7Poip)<_oO|90NOAr0wEmhwMBAO5ZD5ltABFx170IIKx<s@ z9YMo*NR>=mwg8b(Y}&L5lKZdUzq7(x5wXoLUaZ5dPgjLOs~$lADJkxu?y4>wWTuC= zVzeVS;S-gu_zu!Q$bi-rARYyw1jtH?_yaOzgkwQgAo4_@4!wS=0IHVeC;BA|quFWa zOKn*YYLKVHfQ#;TjuT~`g<tzVLfiM3emf(Tjw2Z12l823vQMJ}&|`R4jc4q0UNc18 z1&jl+K}tb*cg27qJv}|JFmG^mMD>Dwg$%zq=J)SxuC5?fXX2rYG+2Qr)6Y)5-RUUe zzw8MtxQM6r=zP&Wyg?F^Beow>RNcq6ZCgmAh4+&~v{-8h46sn*E1<b;VP~f!Qa3{D zy~B1|&o1lp>pr0!q;|o|hxl_g&!AM%u_t&+25O`igZhuoytx;IWb7>9AaDc1T?TTC zcCPNmz<2M|-dVZ4>|2*0Z2A*#0r_6c^eBNB<DCV=XyFrg_`bc$L<1k0SuL2Nt{lg& zGc`9C7p$nPtSlodi@^v~(+2Ld-m<Vf9i^nC)C!N!8v5l=;3jSa9}wn%&J&UCXLGdC z_Xm3q)gU!>ettdx$KD@@kzo^onoo71_;`!@sC9e}vfPz{w;O>(YF_#+WwK@?s=567 za)`6Q?PGm?7_RZO<@w@B!##tdVq!D0U%H!Z#2>WUoC35!1}7sdFbd<0)CAroN^YXM zzkh!+M|&$1(_TU6%i=qVii=|=;t;;@0!M>7+V-0#-uRlUCrnUeS{g^1?=&6M^V-%{ z&Bq03P}sl!IKM_g=RjXy?b2kmaECtL8&cQQ8#Ys?@y~*Y{a-N%B`7FJ*m%zoCbKxj z_?@@#F<4A@giZJ4>7K^E^!NAI&d~}*R(2U|U>eO)E$GZ>wXtb^K)q+r9_ps2xT1Rj zf)_4cEGjLvY=3yBVaVD0@2?vL1;SvA>pD7ELTUpuGWNs9RA!_O85E>85ifV{3`g8W znSy_BA)4qK@(%MwnwoA#L@=WJB6CfEGQO%x)*z1{blV@s-)H=7OQn7YJb*0;E-_v_ zJ`$es)IEKC)_ufqGJfqxHK59lBKZg!JT*hwTln`+G+@;in37CS)XeRG$RuIfnZqgb zp|Yw91?4U||74}e9kNbxC0~;ZP8;WF?@MUT;xH*Scn=t(fb34p8syVnUuW|D`_;NF zdbX-=1Ew!#Hj2(`@iC*|!i8kn$5UX1sE*PK3`B8G_E?B)pSBlEdawQHY|xIwwlcG_ zm?p%>Oy3kQ82<eEbJr*|f6LSB3RsTM{qvnej$eGHAIw<tRlqncEG&$fvB^Rd?dB>F zWi!2-hNh`%V~0|$zt(GI`>-?8Bqt{ms~q;y6NA#5NKXU9!^()$nSuFgiJ}ldR4qYs zX?mZ!{OJ)Bp0!rtQ|~$3Pqw9>1iesl%Rx)kf8n$jS=bV`BUn8`aEYgWg!+tMl1O4m zIf77g5UGxK^X7W+fPku0>(+7n)r^xOP!Mlf<<zN~+S(vwW0fv25I2m3V9V(-$B-s* z+fUc=K28_#^6(VH+Jc(;s$%+ml$qxZ4P923z4DF96t%UP;b6#w2)eMa@G;+5TF9i5 z@4aH{s4LLomEo4%u2Q?5%aWfy6$fI6h39QoR}uvF5PaAvF)LKJft6o_cSO=OR1|?$ zP&M8Ofd)C3I4FF5eVyFgvVde@&Dn_bh8<q!zaoX9O|L$GjtBLBW$e=dQoBO%LgB%W zK}4i7Ma(=4CK4$6K&15b@bJ2pmMCoAVypK%qB!KDYR%*eI=6A4qo${dd>m{anC_#p z{`@P349xriY&d=Hm*9XGr|=`d6s7ET66Z0wD6<nwqp_jkR&YLWn)r^5#EAv47qL?^ ziU2BLZ-5zw_2*EDLKMIjzdgBU8xvEIR?Z!REBAY;hT;PU{O31t#w+x0zG!C`u9T6E zfR5<;;G>@a<>#v5(oX}c<>w8;fVr@^E7w++pd(EO4Odr3EH#&`FAmL$D}2gmps!EB zzrj<RT401xj70eS`7@A-W`(=G|LWqf;)f~>pu+W`?_DiLiUpw&YlPzkj}`m^DATNg zGf4L|V(Hzi(+OG`N*hO4UOqqg)!BZYrkaA~pl&9zw19CrGfD&7PmdJvfc7lxiPI$u z1{hSJ^zV7nPp`$G2_%lT>nyzdwlmG2KeM7{10O*ANZ994LC(GO^^$Pxd551|!s<1A z?!YZ6$;QFKagC8(5pARRWU89>_Wz6##C4IP9;U{VL6*IbPdnBU_QrNOf0^p#X$BO@ zx5nmR=xVL>a>-fz0w`HiBag*}Zz6C3&Mg<L29!iWxw!{{D2}D3rY^6{|G+*4+e#{# z;SXuUFyHONB}ht2vO*yR!p_mo*-A#+!r*Z{yPYKZP<j>$unb({;>;BIcc`VV8szc7 zVT3vZ78bys2oAYaqzKlv4ScjGUt{xtP!Kb#p&-KwfaFnJ4<T@2lpFB~5lii3-Ml6w zA5yTYtE-be3iQ<mQxgTe4^2RuWc(6-1J;EK0OpP=H=qXa7;$Rt+O;d<XZ+g#^8%0? zA&8e02w(?ZA;OYjOCU$Y{QkM3T)J6NA$_Zp+C5-C3*~Hr<A=)<8E}l+$LAMp<5lnd z{aY}u@8?e?WX??1L(QxBqS@bF3B)42bLUPJEGI!dV6eeM@H-1jOY6My^yX>k<5L5D z*6qt^y>3##3#TwP??;4{W6M*=5pGZ7iM>FH57G*?^f>@P#pV|QNr?6i4i037mueip z=0i1h6xO_MI}QHA9YEGLsjdM%TAyAzhbkD3r}Y5S1Rx>^V-@A-=Iubhu0vOdwY4&8 zwM>&hp9*I|x1!}um@P&FQVSsH%9SfnR8Lj!#HKT<@{Yqh0=CFOJwqS*pk|52OJO9C za@|Nzl{88pJotgo#?!iYOkN)Jr#tU(bH13dt@6qM4PJf*P*UaGXT!E}sg#Kz4G%C1 z0lj7a<|l<MHJ*{_YC$Uk8c)EXz%5l&Gd?fDk#JBi3W|=(+7H~pJqde*-n)PU!#leu zye@JHv?ot?q7L&F^kzi@Z<K6#^}u&=S}j$k>|^ozzLTw`c6#5xe<!OOrrRUZ(iz(P zAOfmf3l{prg^6#h;nrS6P$p*P6INCaKiO)Q+UlTETc}3AAJ#_!nkO+QtEQ=mK2oU; zBck2|ZhWl{kRu!uq8ORZmZDydUqs?PfY4*aSY!ZqRkxC7&xAzc+ge&S+1c5Rt_?XK zMPZ}Wd;|2;`}f2E2`3Rh_4zaC<D2+i)^<0;r<s&Vw;L_6>`j`o^<WOU^y`*l`Yo$Q zePH=ryLZpHrHr{sVWGkyPD%pxlqSGx;$H%^8kzH!avk9;b!O9jyV8ZQM0OiOCz+T@ zmH;XZD0Y!0B`z=HE3l<kf2=J9T)lR!4Nn!1U&FycNN#muKhQeh23E)@1U-~ZnBWuo z=n)@EF{dk6_QJIV;Jp>()|~_A3X6+h0Wkeb2LI6fNHc>>5-I2;Ga?Uko<}Xd0BVGk zgE<DJ{1EeE^0NvZUg1gY#@2J_sXXA8`0}!a)oIUNOq3gUDwa7Hy6~RYuRXUZLcnd; z?nU!g>%WhGN_X5#H<9Xr<>!m>au$}Bf8Y|+d<NM+Kj!RfH7l_y%>MWWPGF>;>VwzM zm3`)po2$HQf4&!S<Nq$UEmx%Z`JSN?Q^nEm50C8+mcDgc$G5C|*DibgVl&D*nz<}^ z2oT(}zqHJW09T_dMxiT}B4p~Zcd*n7Mg9KRMkg1S{h+B)01DSS8X4^ZAcK6LbNUCF zRR^0tg6DK(hnkw&o$`H?8kg_gz8ysPtpq>-X8KTO&O|jHyx<U}3<ab((L_um!|)tE z+pL&Ii$~i0$jm4OshbMP&&9;f?TEDmZia)n?(JJ8dR9OtxWZre^qA1gW4dCde)zn* zCJz@Es<IH>+_-D9GLIr~4fqwzdkuO@&d$Z3nljr*@kd;^XkOlIUxm-8RxqGP>oHBU zPkem*H6x*VpvzE21x(iiuZM~tGEvN0bqR?)5tTv^7=%8AuZ;%P&!vx`^er_oHv5}{ zh=l)*zamq3{C-Sy06BoUX#^2UU#Yu`a4dj8SDc(I=KI8s9Fa=zWJ{Jg%dD+Rt#V+L zam}2`JLGmp^`-|;POpYhw+7E`z2f3>5lD*Lcq8chK-H{&A6z#&m&urZ)cg`ru(l(> zb8_=))x^dl6CME+>zQp@i=UcxFRg8s>I`WrbaHilrxzcpl_OASoYBfmyN@APc&cW; zv{013OZR-YtCaD}KkBUW8{XdXsG2t|G01z{-JLQu<;0_QmoQBPj(~Z~1S|jy$pD&A zJMq!BG*sO+xN`Di)sNe+dL+YP$#BB;ZTK5e$w*vO5D&5<RI~a~#`j?rTOw#8=ivo; zqWni&fKz&{p(aujGdPJ%l&x>PQ->4(b3(08XP%y#>ct-(xa|@E=)mpVGkoJbzcMja ztxv!HKa17>?|+S>sZGgs^IesFwA^QeV)s^9-`Ga}xy5ybiRi|jmZ+~KRz;5U6EXQs z49a=BVi?JFDdouqc>Pd%o;48B@pQG~<dOQ9WvHzaNJv1GnN<3v)O}ufyTs&Sa_`B6 zaJ>#|+$ZgSuA_=|_YOC<9C$f+H7iC-Wu#kYn1j{q4KG)r^^$wf6P<8p6BDNo7jj?K zZT$U_@?gru&?!;=Qz)M>*XQ0HFT*XVlHkQ<L0|dx8eGqcq%GVNRvTCqvM!Qd|Jg}T z+PIsKMn;s!%G<{0UL28bFZXgW;@7?Uy}$9bp>3kttrX+7(k-cnGFngJv6_CfRJl6* z!!%$;$Lx1wo7#UytY*VwBi#RjWtd8iI_6~g#5c=lDQ2CWdNi4AB&3|DRa?a#eTL_h z#s|B^GV4)Vg)P&oR?ctgu21a}OH^BoUpep_?~qxx^j?N?l+*N&02IxQJGVVJTj=uR z7+O(emz{8h<DH43)|-SJ9Lz-S>*j)>%l2!IKi~D``h+l^d|w%l6%+kQjhw-6kvo^m zybm93Y2lNRO;=<8<~FI0+{WSkqNGG@Wy8i-rAix}t|$x*y~z(})335*Xc&4hr;4}j zIdOwkAbrHrdd5MX;_u(T-$fHgzE;d%+?{`x&!)S)lsUq<(v@!Dch~w-`=sYz9*;a= z!4gSzc|d)d&)Z7uu3F{S2h_SbIch1Qq2GCv={%3@3$`q=o@v?X*xTE`FBq=D^?jk7 zR08Rq+ap0qJJd&cKI(XvEb+VOoZ+q`uGjMp>WLP*ST}ij2cL@Ei#1)zNuCQwEM0_> zl*g~@2}*TO>S>ENaU6XWrIWkR+wE~>W@^i&4Og`Y9>Jvd`NUK)$Q^jsDF78Lp7ux; z#B8$Sm-oItnqwG#-~AF2fAw|FZBeBro{n*c)4JJ#6qQd6tj?rGt?upiT|$3H^Yjqo zRzc|L@yW^WP-1^T0hBg+loy0Lm_>%lXK?Nlx)s#Pj6Iq=%z!D9vAO=g&;4N0G%m!* z_}VbT{NH4C>|7vg&T%HDt9d48oDziY{F&MUGlQ+Awe`Tz&`DVGL6-aT4A1`gLztHT zu!S888*UkyUCPS!zFkXm<D}gMgoihe8}rpRMU*KeS0o$8n75N>@+(n{fzemaX^OK; zH=pYT9^j2$RlXr43!q8DAAvUkYj*E~TsERBJOLj|`AZE1Q7|+NEe5bcd;<0GNc-`H zf;7%MJg{4)rof5x$<}K5PuQmzx87a__a`RrYlMvX4wh4gCIqVS90yyVo69b0K?_W@ zUtIiYW-d3aA`=s3{M6;{jm155xbs{~|5LQ)(jLVwzYT(=J>GV78#CIlnMgr_Ly_c+ z4iW3m#(cDjf8a8i`lVmau#U<puJOxDTb2+h4^~0FSEt_t)&g5yS^4J%OPJyTvT`iW zmou!aB#K<#-jbjHU`W+-^irw8fd+5Zi^b~|_>SS?Rihf$TZuWxsan{uU9EU(Ac%>r zgV0YtxSjrt#xeRc^YDc3!OQ0!pD30J=3I`Bi(?@SC`fA*-;XnM&piT9w}pj8r>z5C z+|S|9zm$AsROMzCeSaRd*IRk^J+hSYxqc%Px>9z7svB+dHW?Zo7R@SOc>It$Ph!#} z>nz`NmDR<IGimkU{os#i0I+TZ@C9mV-_}`YCPLhF`KHzCfHjA0KXHQWgoz&H$!V;G zs!5@ym)0NlV0cm;gb4=0gM0S|krfTe0?rn~IfJDKl4H)(Z3b6)7n4%~?V$aHz!A=w z&`cC9@aDWiLQzP*KxT^olc*TJZ!=8*Nn%n-aXN<!Sm}6$N9^rH{kBr3_34@VhN#%Q z);4Y4Ao+alyI*~u%ZW7E*Gyf~0v=7A(!-6c`vRCHo=Ls(2&428Jce)*YZ4w61-e^$ z&8rd*@c1=GbF_mH$cAg;eH?}sB<Q-J{%+m6C6DQ(^r68UcS?MGaFPKl5p&uEr~dx6 zg53A%iT<`g)Pz?c%W)Qrw|)4qSz1~eC7vvV$HHgN9)cD`A&sIMF>x;nFj8T6*pi9R z6B84aGcD5Ke^^mX(lBnXK@z)xbXr^6cOzeUi^+OnlR(Rhb=MBt-Gz=WZu_N>7$X!_ z#FElI9B(zxyq(@HHJet^g<@{9iy{M)vc>A<bt`ppdo{0tZ)8Q=QM%6<Pi*5zd-jLp z&1Z8v7<Y(Yms?wo1v&8t4F$*CWuYmfz=1I+keY$D7px5?$pH{TBDsZ%=L*O*P##34 zuZoF{&64W+_Du^V`el3j9L)@xo}L~Qc%aMHjmpr6Qe|m1qU{5M2Rh?0AU9HtXFuLO z>WOm&CbE#~gP%Y5NT<`FPJin8he{wZ;&mohx%=;?n%-XG%Ai#&Dq-|p!=0wR;BJoj zg5ksF5=mJB$9tUNvaufkl*Gv79X>uj6r>cz5;3*$(%092)UjBh=ke=Htp_GA0V$v5 zk3)y&x`y!wpGI9t4;&C$|F2)~V56V?(#c6H9K+^(t3oTC^PKBu`rxUpMVU@efczdr zOrpAi_6?#B{3ev;u;dD_VX(n(q4ged9;5}Fi`MQT;yFfa|3`6y68Em!gMK0lQFc<8 zBUqvC1F4K*6V}$&ppfy&8zG)9BML|RZ492;=k@15ONEIRT#)FtlKETX5vTeFmyPxG zlX#vQ8|gp}J2>P&jfUEe-aVnhFEb(Q*RMB&B@oO95~ng$GdxiukOEr*o0`E!cI4<$ zrfu7fBhG>{CNjp(oz0*I2(5-P+55q~;+9m8|Gem)K@g-sUc7?bpkL<9O+>|!L*TcN z0w{Wa{YsuJ#bEA2^nn6@L5E+v*pY<=L;dV97R9ys$Y@#MFxVL&%bEdAtEpvbWvPNq zll#1gqHtQ#orzviQ|$VQY{f(TW0MK0Sr<Ssp*QDL<EcrFb$=d#e`vK4Cp~CTCZ6%- z9w1AJ;2WrxMwOmSDEVMKotm2Bi=Ux;H6#DjOqM8K^|<*1hR+1>U&=YYMRLWU<6yLz z`t!#tljACU9*D^spXB9T`ck-8DkTc^7FfLN+1bPUJ*;I&OCbscGB}$oqJ|`Rw+2-R z{R9e`7?`2mDQC3Gbd=pZj!EOKt*!8u+(45SoR)-U0F%nCn++QHl5GHxc=&JSibqCe z&Y{rt2m1RJ;j#-Kaxp2oKz-xJjgwM^T`@G~uz;Y;ayP66kvZPG$l{Ti7`udK)C8D4 zSeLxk_j&C#C`={fBMLYSj*!ziisk$+MLNOp<>EEcVF?m&%kJG92fLS%r%prKhMKOc zsl9YND>D<c%5>PzF|S?9(R(ZrJu|bj<y?ON8XtoB%zd)wJ*cb3mle9^_<XF0tD&K? zZhq)yd<`&=wKD*<7U&zIQz26yvi-z|B^2xUL{*avAxA5ZhH(pA7k_4ENXH*!hBovd z@$!4%Ixw%!RKDlVDwduzx(?T5enOWe{2{qw@*j|IW)evdyMJQ+k>RAM17%y?WFw)# zm!Mfs(bN!4qyV6Y!8i(n;FC8w_82Q+3ceqg(YCA$Ip>h>!SxdH>ZCzFH~S@AEkL%? z673CLY6VXTlV3k?ZDqv*e{eE9l~4G66_hb(@9AJ!$s0!Hcc9q?ZK<T|b_Cp_x8EP` z69N&fHWpX|Xvcfj(B$gmM1&`;v;QEtk;&k2awIwW;N8+~-W)K-6{@MJNmM2hN1?M) zKvH>)2SRAU66+5<P)ETn$#!_rms}Z8!bZO<9QHBx5%@H4I0zzSY$s9O<!7%57(Bg> zN3v!6_EX?4$pm>Mn{)^=@V4Ob1L%=~s}$gcgDMXl+piQMpWUva@U8?dlVi9qau1pI zX!-^De;doK9o7hNxJUh$k061NQxfn}$w+c$FHZYD7=zGxbr&c3z{JldvT5uR_Bz(v zTXd|3&zg@^!zXa1?-eyTM_lNLYq_;^53d_M9FURt&OKy=dIC6YufXRoY#CVUzv3-q z^de9zXAs1|o95<lRC!>gh{gdpfGs_R*6DRlNPSp6>*Rrn{%gUl^b!Li<l*PPi6;hG z2KMFH+5IH|4PYj2#KvwT>{^yq5pEF12_zTt(jdZp1fTTD_AuN-+<bhrY-|Zsb7w%d zUzXS(yCS^*f}$c7^6o1O(Ld-=BUuQ<Kl}oW2pbTFQsL@(XH_EJj!|_Xn83an${J)< zP=iL*{wX-A0KTc$h#filB|IRr_U_vkOzcpw6<`5GKnubTZ;Q$h9~WW?)nL~uCx*2W zF$TpfvYDXUW&;CCO7x{%hl&KjkF@h&4GY@_Zv=!xoyXegc$LXAUNJD*$jHcmZcEW# zg}hGM1(6tt-Q~rVi_o4S*NH)@egmV_{rj9bNr$ltkT-`J_QB7wG(So7BLr|_u5kGN zA}B9UP&sPX-o1M%LF7UeM1&!pAQZwx{)Cy6@(YwzKxG7hjG84fP2I+Z59I<cUI3yX z6bN#H8GqbOw2kXNIS&HmKH!?T-DgG$xFBG)fqH^9M;u#FrJ>u#-3jsmzYgY9PE#@h zt}Db31ZMPCo&ZV-go!Xg$haSvlrZS>CJd%<D<QsN+Yw7JEiK>EcTb)?p^~$}s)bho zhd-Qv#Se}nVy*%wi9rK_$cq5*MlYO#$RKyo#JiG?dyrGoK{h|N?VvCDs)o~xz#1WD zfF>f`Cm22f{o)fl3RlpZ*gH0+iZ<4xNXr0UmWUc{!>*Gr9w8@SaL&u>Lk)I&p)yM& ztHHN$E=P+S&lbJ7@Hvo=`<#~~9^Wu6Ndv^g>$iatj@uS++h1XIgYFo;!oC7aW+ToQ zNW>ahx8ddFw^9ahwOD@Oek@Q$!)3SL(Q$G^yifmYy1x_M2i;^1CIX;%T|jd^R>cg& z%#YXv`>ImIj(SdU;^N_1DXX!ALcX7ehXx@9Ix1)pa*PIY5Bwm_VB<44@GJ1C3+rrm zlt@a%CPvVE3z8Fv5_BnSproxI!I;Vk)-$V?WV-(jpulKnY+Fw+FO?D#Ja>Rjr7SIT zYwIwq9C!t=1c>(lJ2V9SCSb*_U|b@z3#{I4M}v0_qIV*+J3JgH_cYiwXsG=kwMjgd zTwGi-Q&ME}ytpz@`22Z2qz<AKfunVT3ly^})X>sNL~t}eo5O{NKPW`tfZGUoPZBLS zzDvKKgIr`{XIH@kI)bNxwTO6xSkDbA^}phcABeK3q$D<mKHu<p6nbq@S%xBaAFtqs z3Q-Sq5Q&SIO4*dCc1<^T2ybQ?d@kU5@5o34yo@!-M!>giivp7cLv;Fix*5ROk`BAT zl*Y6a*>_36IMRZ(h<@=4Fe!n2B#p7?q$RKm$WrZ|I9*07Z4Jzt4D0tpm$(2kDx5uS z5ODC20zo}MST_fsO->omkXyL}&zh+HH*xY{uwTi`qCg-b6BF8o6W}2to>BMTJK$l2 zmV8N{DNi>XcR-3(3lNH;<S|$_-ATt_29hFC<RND+0+Szs4oDCqxLpEcVbjV|jU#8` zpk3f6<^hn?Euy=NttFBm;t-fVP#+zOIv+X;zh7E?1bZFmZ_4vfX|Vj1cw*DrM~M{! zCYTJ6)kI8M^Gd}w!9^=0q5{G{!4t<30LV4OX+ow{5M+Sq8Ypv$Y&-a0uC4k2v%z6v zg?$Dsgf$R6^)wtgi0xlW?by)2OF8{{9^EmZ(jn6p78NP*#9l#%7|8z2UV6_F&$sZS zIs<V*;zk|R2eE7~#yuc~79oA&hkvG~ZZ(n9XCUvqZg1a)=5DGyDXd-)7Ho#Ayr9kD zJcLo-8aJ|NFo3cJV)0N$^syMKPl%%6%2v}Xg@E<}Bu>qrZeDmwdIm_{iEb;|65SFX zL1c3rMf0=E3KP)9tRl33z^Hkudq_b+VHs%*0G7@0U>4{1$t>Gisen}(?3AA%*&ix~ z(zpGEspG)iz)Btu=u5!&n9GiZSZh{;oQOEMj?{%H)uG+OEpe9L4p5Dlk8!$*ik&+Q zxZ!Zv^-fH*z`;U%f;R9(p~!+!F}-sf0LUCO8K93dWoa#@$;IHZ2C*rLkOK}BDWDdf zL=aeqVWYDK;)2*3j0w`vjM1~*50&sOR7<Fi(98%lL5DFs5>Pc4F<BbL7?~9h6J2Zi z@eRNj1UCSG)V8#!OI35rL!!kdTDIPkg!D<yLxJ>wbEYM5765rD_<jO>u$IX?g|x`d z-iYFdxTujzhjBYV>eomXt3>qDg1m!q6qy2_Zp{x6We`J3qFZeSQD=~+fm{e%Kp6b! zXr@7xEef>}W)IA>r1oE*0-}H8LaD15JhvpbU)#*l0&5j)Tz(LeI1e9=L!J-=PDOb} z@*RL$?85@Ih1~-tp&;`OP~V+E!iOj)jBolNDQJ?TtyOg4B!~*3(oC4ra2ON0dyE>n zk2L{moyO785eAK0lRn?En>YAxT6@zbrJ1e1n+#HbKo4<Z055_#IblbDS925oHK!lP zpfmb0zmmPjv|our#`RS#ww(TRhuw%7&|mi^G?N2&0Kj@l_YewNYdAG3afAcbSP2k3 z956&zLNp7htpTS)(laU++#nQC4(O7vk&7_YhRg#2$hs9D{}%dRrc3t2hsWGi1L0i& z$$SO^13^l7GT6-!LuR}G%+0;|J@G9JA_`U~=6|%epDWk<emc8dwpD&sIjh4K6U4>H z{e#1R)8Ukx4<?rolN52b|KITw7sYp!IrUM&v4`uR@Cve2Q;QHU%0Q7oT|O$vNOL@> zkspbOD56L#1m>bTdf_s>33!={ho>K^EG`W8Ypv!H6tBcQ4r2r~bp&`YJH&+!H?olF zOEvu6BdsiYr0*eM5R9n=CHH4~x<68~#|#;EmyG8vL?!%LP$eB3D@HuPZLVl|029$$ zZA$^-b;~<3s1Gi{O`|i2qFJu*alip_DIy4APtJb~tq4tMKh0u>VhN)ROzwMq*($G} z+Cun@L^aguaH%#R^y{N)gX-IMt`wLA5Cm-#2Tk=+*W<Xzydt#up!S3Qm(%geMqIU| z4;dE5nMWPAkT1@SL>xpwxTBgit9<zqUD5IukMYluP?J%7hogE&m_XQ9<B84R4|xa7 z1q{Rxq!93lV;K)2qNJo`HUqR+=FYQlA>px6`)@%R{@Sjf>Me*9a&17C=74sgE%Z+< zoSz9)F>!DRuWWf!Uk|ml%zKU>UK6m4#8EK%1!}CXWW!STTF9kQlQU<|oP@<NG4X)g z3d~JN1ly(EpD<T~)Pu2)<NWH1K%OIi9DSD74U>X;Gm(#gr_j#dATtm%3OIl}QFNO& z@w~Xjjafl$^bv8;K(~-n&_LzE{{=!Q#2^oj=KJ_$<l42gs+p+h2j7;aO8jDfJ-oGv zGKfoF>VWJ1Gg4aXeJHihYARH|bbpg;G&fj$?(6^a0z7znke-rxeXT0f&NB}%QABIq z)vdHw#oIhe+<N4AD!9ZcLjseBXV|&VwH$SM_Rb^VH>r6r{_C{+p`*K^<lcY2!$nuo z9TgU~AzJqDc0f*$q2&QikY!)n+r#>CyK8LN=?EG}R;j6<sb}Yw-ciLtT+sJ!-lUJ( zbrj+&6=3hHJ|}n-HFLBP@=zS%*XUlxK@C`9IH&}tHT!@G`strmZsLf+SGu`w^>ZnX z4p@x(&n~m$A35wj@8V#TR&+0T2?72mhX340smsjDTHY0aIT!%#=BOFofhPa~NRDub zy?0L)xEYZ00uls}?NyY79k%T(8(d2<mgFLEBy!0|!F>5=W?nu%+gMoMfZ;{41PGh) zp9X1x@dmz_j)R?yX$%~gpY@%}4jz7o(;rc;8IOy3OJE8Z)Oz+RlV}*|02GFEvQrgd zx2svVnbZj|(veaKdlCWRc2ZI^;to!HqXue1jH<Ig?1!U6pq)O%r4fTU;7LqU(&>{Y zsd2|RB<@AE9s1Zc6cvLFjcUt&Fj*5bp2q^2Tmnj?pPV#PS(!|Zvjtam7L=7oQViE0 zQsx62;7A%Ewg<1ndxO7gQxTRJ3y+wc(bpZRngs!v4$d%CFXs!*C|Ouod>8t{CPb;c zyu1izMhC@%&T-NK!x~N<f-$>Fk$n98{Rp-|tXEO)VTmIi4j}?(;YE;Sh6;>u)aK@U zb#!zvbPFe;AP`J^d5kGyK&y%{@}QL;P7L@<NOT1qXkleF4a7uRD^NsZ76K1)ut#_X z?0?8ZcujS-rNB-7tJSbRBQ+D}7Cab~y#oUwh`$!1n)u~2nz*>QvXIf0l@&P3$P)O! zLxgA<7zW_y9UK~J1<K?<co39{yWEr2$+gw!*;!X|NkG;p{754{x^##M=h#B;ItU)_ z6)7--i8}U>@n_u*qz|sbv;ddnvgZz&yCyB2gkrSl!W)cu-goE_6Gp!3>$7tP(6O?x zkbVweDa^^4SVDE|E;ox&R*M+6)N;d7ngjD-u-6S-3|)MQ@Q{^Y@&G_9fq5MZrdlJ% z6ARvtA8ELQ>FMbP3}r+9!30I@6ugJn#uIQD!<z{MMY-#!v&!a6VRg0pqh*4XGWyU} za?HB>2pduhY6r8T^Jv$gw6Hs;pg;*L1fCi>vjoex4x`kDSh;bFpxcm%H_89cz>SmK zQ1ljh%~<jC^Ais>kR*US*+?K1Fa(R{KAsZVLB7dmW5|!Tjt(iI@qp-PX~{8Hn2<DI zsS<NSUq8{%*HD19skynEiVr*hf%8bE#3GN{2cOj+#^K)!5A#oqzQH&cfHc^k*`(cn z^}?WnHBk&F`s2rs2^<AGhKPZDQ;!vi*-n_k2X+QFPSQR>BGI}<7Z(>&0)lozI3|bh z39yD6n#Cm~lz?n7C<<}A0df*-A=YQgIf_qn8Auj4z?{q=N&sOu056jnV2~$B?SUeE z({8EP(vy|z8YY+U|0ZypOP~R3`%Dq$p#i6piDdAw5L6Edo^VT0BDTZ64xU3M8Uu5) zHPRm5zaNN`_NXvg3Cjf*e3D@hZnnTZLVQe!=5X{(Or~U~`QJm_Xh&ax!ROxyiAb8B z`YyWF{(kfG(TKTVr0PM`qdoJ(hin{6g6i*6vC_|<KY_MLmnrrO+vkI|)S6Y`3LL4N zrn%lF(<$v|+)ck@<0q$DBgv7u%iYD)6=56fyPlRkIemD?MpAu&TOoT15CbWbFb8-| z-4J{bqcBMg^Pzu}b~*4O=A@JFd)c;<ukSz${BoxQQx2+aWYbOej%8xA>3Z%+Xa@jh zGKmQV3G@Mg!G1^`P^+-JP_4J)+$@~$fCDiJWr@JHg^eu?#Vb&cC0;PWU}-qzH=7p< zd=~K)B3hHHNla7$OM%Y-Rnm?U0Hhe<f{=rNrjab={r!(25MBUNflNRKG3w@m+PV(L z4vk5`75L;WTebwk{vj$FgUW?aX&&!7K=suE6A{O}QbudaA)4ugWUw|^K@$rJ=u3n} zM-g3Tgh#~B2oOd5CdLDZA|K!?K8id|0#(uo*k=?Pr8k+-t$7dr&o*2ob`Lf`z#2p; zItB(8x$96<Vag?4U|_>bP`rabj_k1I#*skqq@YLcbi9B<Oy&$tX6K3YvqU9=%mDrn z1q?x=n4Ct&ocQ>NAs`W13CUw^wrXVScWjv&9M5?7?kTX)sOCWWlC%rmOC99hZLS+2 zM)7el7;pF=^^NMnWVRWm=a|IAMxZkQWt%+Hzr#zHU-Y=-+pR1wW7jFCpDn~JE+9Gf z!?t&%ow_Y4-!(P$V{-zRA+NylYK49RB*rbw%y1_1A~-w*NJ9H9>E`iYTk*gho*_}= z`t=$(igA!85)DpB<Hoxqen*h3{tJB@+#xIBd6HH-ymmx2Y$aMoMmz+3FgdgkOa>l3 z20S)2G~9pk<eh!Tb{rK7N}imj%!!DFFx`(A1Agx-j%tOjfB}p5wfS#EN5k<$98TZ@ z;Qk*1fy;$80GC(@s+SUoFSw8GIH(Ix4Kf5VdP0gQG{~z2Gf;YU3R0m8Ru|Z`f*C1G z1W<CCCX9o7aM><V2?#C-G^ASwTp&0IGFY^!i3H`~_f{A@)0OhQ6}5(Zlsz1tM-l1C z{S8-!;jl{;8=FT<%5T8rH-UNq)&`jxjZcPDcN1C;49BGZ5edp8F%FSv3Muzu$ycO; zVVol75Og;!O#`?BgWlNiaG)DuBA60(8kW#rKE4Lyls#s!;NvqVgBi?|)OaxT;H|Mo z_fXVMW8`^4k7IZs;cr0!qKpOreTeFW9BgXpzZeQ7IuS-Pka>7{`=HT5lofILsfMys z=pG;Ek-Gjj;UFoRO<O3cw}gg<`p&j0kIe01+_}o^y?Jx8dcDr*=`8IF`NhSTyVaA` zZ}|9RnoT`1KCZF1%>S>Yh5Y#EEj#E(M|=AyJ2OVxI}=7Z{7=QDaeUCt4r5ra*8~LS zwK$XjmzHXt@c8MIF<hY4>agoH@GcN13ueNIVhEfqfLQp(M!fh^I}eDuMjS!v+$#JR z31J#7Dp>OMps<8(YRk6+&yc1^ESI}bY|=a~G1sP*VAw2DdOZdZ4L|GY0Qh0?#cWI1 zneSlUPUlTJw<7dLoA}M?kOQL$r7REG7U~BWr32d9+EeeuJ|MvoxGyd32zLjvl81~T z%*tT-FcQ}Vq-Briz(yi&f<hrU6cP0T`avUh9KMO0%s9&j!=WW)EizD&&BQYZ%Y$?Y zn_%!au55Vq&=~)G-^~Og@Jz69{x_|`Ohkm79Op6d4#4jn4mKka6gDU`A_e%;t60W+ ze107wKnhhopMbz?8}T-rMN9_Kf{F7S&wEa+q~Jq76_}=>_Kl|5xI+Xb|I5XnJJF;0 z4zqV*wIh{c=lD^tX)e-_HTiN$2)rA9xL;)}796qVgR&5D9&C{EJF}Ma!ldHf#CSOu zQUIKmzJ4nU_RV{ISH{dsj8igcA`MPzs!(VASlN}-UE6;ndfV1s<MHIAreN+Z$!7p5 zL1sfGGHxyS`0AA+dIgmLeF2B6`0aABxKL3o05_4wK=1*iS}*;cGdw_4-1_=3_^D0* zi1Jsj{M~8lH%BZQWFhN)x<-M6*;LTiWpl3nhdwtqH+jUU^#&#<qZ=)x965AzSumhp zODm@9n~{!AXsZpEkkBTWC6HY}*T6aP$uH&21#@gff(O7{ToBoAgI$bfvq5~f%ZA?^ zXnqAUfB_jT_mmi5d;qPp=73SeE|0DJ-12M;7lt{8w2vZt1%bmP=h-5pG-5@3fdLm) zfkKv6x^6BQCdEA6b2woRS{#zaerO6vf<*`}fKT}CK6LzIP0j$_6$6<86po-L3gR}n zJ&;HWSaZP9;Fw@YIca2+>?8OV{#e8kRm23`JlUX6jLKpl(u?9%156_~k*bD>Z{VF` z&~Jz(%0Fgnyzf;ox4?Navbp=5uI^hfPp4E>AAmmqNwhos%`0GO;oOw|{tIM5U8UPb zPQiZTED@ah_PteYc~0<mGE+HC9*0?jX7LC=cwhHxOmiRBsU>VyGXF+06piTCyItS% z-&d>ya#u7kFc7>lr?>r>uV>ypbE=^G4lm4i*9XMw;#ltWYvSYyoIbt((4ivr*KzWk zFTB6sVil;U3mVwU%0Lc=2p}g35TiUImIt*fE_}s#fKDJg*6`J<1+xhw{~s^@7(^>! zaJn5cJ>P+#$NW=&g5(+p#SJgt(Yf0?{&c&n+mV8P$HQ4#L0>OFe3}Vj&(Q9WM@6?f zmX9ZDv(=|5NT;NAAIoKn9#!qeSCPDhO-&<Rr3ZJ%#1@R*Gr>L6)Yfm<;|0_Z)M*;V zn^rk8%AjXIoV6xsE}y`a%JD6{>2dD7Z2!33U@rBH*HY=)e#o0pIxC_viSQ3f%axoO zXZ?KC`(-PCy9&Nx+`B?IxfA(xZLLZE{9#NFci{B(tNmfR>T&A2k?qfYS0x&<Qv<dr z>`fQH{OLOVOvkqK{{G&Iii3Xum9`mNyo?fT;$}bF0}O!%eTCP4^~F|N2N8!;L7`m6 zX@|=(^zldZd!7JZiX*F)kM7qwD90op*}ciDc4DklvY_ST;G1sBd4n55tCw$^={>to z?me<G@&Fk*-^-zf0w07Cge2A1c&Czll9v-{f-n)77ju+_im9oC11PYV@De-egqn3= z2YU1B8y;R%AsLfi>n4AuxuavN9<O@xeWY?<)bGQ)d?w0<$r#K>Ab?5(fI3|#z9#}M znZ_NWTfe4#wT2vpU`M_gK9g3R%{F>D+6#+|W$PyG001Ik>v7lpSp6T-a=rKnRjuVd zqpM^sZ@k4t2lBSj;sR=)fTQ=jJ9^$g%O+!FWhRRxVKlE?TACd_j*yw}X+#yo5U1*< zF7aC~(T=x}xnoUJ*OC6@+{+!O8b&)?#x|<-@Zzo{k6;5r#e{s5b_>%lcqwtAj@Iad zlk7PD%NYlmjJQf+t6zg5C#5tApc;`HRPlwB?+m@JQiLVtj~g@CJcRL8Ea&Ovb$-V^ zl`ibsJ(!Sq)W1Afv?Q|l@wbPU<TN(+>@j$?%(&j$=f2iKg}j)P33ZFlHyLA=>eyD0 z&?vP5YPk*{o)doFS#(i(6UVW4#J95{W6An~R?ZiQ=?IHIG0q@2Rzi@K0YbuFV5Y*t z!kKbYYUl3fWEgi%(xX!gKX?np`ET`VYaZR8&Kj$u-I(LdV2~1DBhOJO!{|xlsnvc$ z=d5}Ec`uex<tX##-yTi=Rw$8QcRSsG{lZR*+<4>4L~5)MWprDBae1uMy;86Rk{hB# zVb||hH=QX_RKs-e0M&oXH}OQZFTdSW{r>6$gE>jPiC$y4BBo!^JGtdNKQ|xCuA}<z z{;g#5Jw3fZv#|9C|FzYP%ZI$jS|7y?du}j371%Lx|LKF9b@dEi%H+Z#?7yxbyW@IU zGwq*3Px0Y#+x##5ctdUxy198`S9G?O8eIKs!kD72m%Z;4n6wUCPy~F;H<Q#)&<efl zSmCnOz7v<IUnCtCYsFhs)HfS(Sw1j&m|HTP!qt{V;ibv?MekM#3<5f7xqPLU>&Gt{ z)oqhh4$%&Q*$SH_%->^C;_S(?9jrVmF<0%*I&IQZHakEOd9SWMeBp|t(DM`GgRK&R zQ*Cx*nTuxw92L8~+K;8v9hCfKIq|b@Hr!5r#muzu=3#m=2OV+BFh8nBD|cZ<UdV8U zzbr#TdPmrTahyY?tQ%vw>}@~gnFWX69Ii!QF7<pgJztEyNdD;Dn2FgXonH-27f-*u zQStBTn;%PU-9dV)+5={l8|@dbywUw6@0k%;ZPloyoe=rx23Mn@ar)UnEjr12C<;=j zy$^|1C{ilz|8m((6y_Kt`unYcwG=EY({B4t>ER2gKiRsau$|FCr@gq_KswX1%Ok^} zEUlO%y{5MV+>9gL6UDDPu-u7f3nw-}O=&}~J1BkE#!gAvsfUKc@dBoaK?Rz^^L|-b zyY8r-&1t#L(fLEdFokYk<LGPilJw6ut41#_iBE6OcjLAUrK;$-sg-kLbgO|Xw@s;8 zY14z#Ij<c`MJL-eE@@XEGnRJ0GyMC4jrcC);gih?VlOaaX2;=wGj@0)_h~?YV6^LH zi7x8#z)Rvg$mG~G({3*vOa=qc1G&XfY7p7&zsfNWau!}NC#OQ%tJNxxq=T}~avn_) z=)RIH@tkMNm}6yTGpbgQDHZ@~C@^tg0%HxV28)nJFLjsCac@pnv5~!ZQqppfBdl!l zvz7DX>7nx}%=A-JW)s6{GkxF7pxHCaXMKGayZKnd^$i?%<hBQ#v^c<g9}}&Dsh544 zm|rd~T+}isr7Bqr9%lPFd@=v=1BFx91uo~GWKxKuujpthWHTMKFxeybAvN-I`!*M^ zquIqJbTH7?)vddudf8q2+;B@4&N+0gT5&Jz5<X^CinSLl<}jwM)!$DWetiqoX}m#J zcq}Y1&kv-@L@?zr%$DGk_V`ZKN{x471|6s;IDIhwSk7@vl|kM^3_<?>-3VRv?YS|s z{4Z9?qtPsqKFHSC9R6kMUxIHUmkR3J>4yE$A0M9CNyeE^l#dG$tPTsck3JQ{eS4#e z4=1JG{W-^tv*RYG$1QR?EG(@{+&YDL(3O;`w7+`tOYO|s;^wcs>Qg-j3$*nTJen@3 z<i)QEs|?fMxL0rYLwuv6;z(B(gTm@+si0*(vz<!J{7%M*fJxalNe7F8SD}2evgwb< z)Z}dE*q^7=X&Nr)bXd2z(AC|mH;ym6H=vs{xN?|U-Hn5u^8nAayA7v~vV3ok-JK-a z9`KqrJ~ONJrHl2W$DnI_$A3pAgoPQNEgv5C%|EH4n4x>_Lnm9Lfnap{&%^meWk1{d zZq<+M$mVLSH@Yb2BV=nbJXZZMZu*yB{xKbXuXT&b_o~(G_DK7f7%y?FOw9kXLk3T2 z&pF2nxkTC1^9TrVsRHiPF<fLPmCqm;LIQq!p$N&~Lyp2jtsFi<K}*ohv*Vr7y}i9s z<AzRt=On34r`MR57Oi+5x<dE9^|7$u#!K+-VW$4jY6Va-93~M^3N#H2yuTj*^Xbxc z8-ujnN2$fjV|u++;QwhA5x+AGTtY=vGy2-L<j<(&kEyonObh>(DmcCkojj?1SIu)| zZb3IK{5_AHg_~3p1N|eBq}E3rd@S@>SpLV3xmNs^DDQSp@_qScUj-%ijaTQg3y<#d z^zt;Dn(lY?KgOMvb@!cBu|{%Dvkg~`%^l-#sol?R(%-xp4uY=ueEaD4{MR>e<dLil zNFinx7W1ju6WJZ*j-|y9sIs}tXQ!Pf#q@M9JnuT>=~Y(Er#3Y7<(Io}gwk6^4xzLW zS1l8xca6)wkDutO{~V4@iVb-lwqa~+TxQn$EdNor{`Cf>_q>CGrYnsHJF{xrx8;6S zYi*3(UR5cwu-G^=>e^q}l_MZr-&MaMyzxX<<JIWa>#Dibku)wUbljGf*qKyg9mhxe zC|Ma$5uCepKq*AwnY`*&_uM$u5_Vw?4UcZlqz=`SmfSSL!r~?-N62v<)ABJQI~a@2 z)_)wm_4sjvv>QDLoWL{=OiR~a(EX6Bl&6&2dG1bHbeKtWwn@O^<Viq~Mi3<;-m^BO zPz6x|uCw#Ux3$pEK~D|x-lfT<fe@?qQwz3h&N`SLo=y?ls9Lt$VKJON1UkWk`}ZjV zQ5l(N?qrG#Za9$p_?f8jSDb9b`|vUUqbKXLV&0mY+kCQJWV@{znt66=ba|1h=gNlN zlNHeoLdM(W-1w~$&THi^j&(Vzu!{t4f|8YaQF&jvt9kD>jax3$TyksE48J#Q;^LKL z!;F_lPX<jLtIsI@c$wMbCs}oE<Hh;amCD2ZGBXK6L%ppTt{kFQ6{6)@@LEK+e~G`X zkg#FT{gvL@6R>}Te2}gGbFsdrZk<Yu=ilGYz3lr>?AaxDt!B`oCs~wQM%MCnM(50N zZ>c;Q#$J3@?+~@^Vd2X8J<sKqMNV>apB3cW<FjaKk|;tcz9ZFZV53sy!ah&0BG1OH zN~lDK;^HFMC8MI&Z77zJ-JPc%rj+;dth>aA>S=oWfAhSL4JCQhlCEV)sgGYavh!S7 z7%%vK)Pgq0qx)prZjY&<SD~j=xkp@gy$9Qi<70pDrhRn($ocBqb6&pzrKvxC<0r#y z4m)w~o~%k3ndoMhapqFqyqhW{==-v-L&dy_Rlri7Z(3@q?{iz0D^=b_-gPuy>M}A5 zvq_F4GhZ&=xswp<)4x6>)%&LI%D>j1Ez<1&0@jp68`smU3o9w!zVLe6(>)@AuQ8oV z+V{wk`(*s^>5RUV=wtm~pZ8pNSG{(|%vrR~)W7VR+Zn`b78u;NquCXu9r5vYdLMzF zGE=>_LXHaAoA01FcFOF4i2m=p+*9*&|7K={Ux86?NIxD1Rv`<lx85hE`)NTJVp$qT z2XC^lnu#VAN$pxLa@ak?D*Vu+KB_nly<ka`F9&{{dpNZ`)hBRQB2rR0+RE2p2Lr3n z`i$Fx?Cdf#Ka;+9XKzmPT|RVtqB530Jal-E-yJ0;Cfw{fZ6krDaW|<|9PQ^jSGQTs zXI#)KV2bjC>_0vQO3LN&M&42P@jP;F=p_&pcZx33<(Q`JPfTR=`E#=Wo}~3Ev^9xK zTNA_nPi^lVj&&RV4@*&YWF=7%$%uxs8z_5ZlSGK@EvrE)AtaTRtjY=rSs_`W2xZSC zdz1Bhefr+t<9LqepXd4KcOS?7hx@)<uIqE2=lgt**PxwQ^V_)7Vs}14=c1-@<IvCC z?2ZX<Nnc4RyP}DQN;DVl2M@~{bClWkP#<RcRi~(9-*w@0V=TM08})HEO0{^4IZnSv z?0cx<;uxczXc`#PGE@0r!caxeH9bGw7eLRo>@pxL{@ymI#jd*F<)~%<S={NlDXPP- z134|mhibjcybEp2C8#nC8nCIGnFU_xrmA{_CTP2B*Y3X+R5m}~(@07oo{cxu4fLX2 z720WMR_C{I4q;shXxxM*8MS;v`{4+H*=BmY*qa*6Ki;E%JT&60<Z-IBr^kD<{>TMp zs#mS)ogX3x3kz*JOOO$-yUtluoISgPnsVS-wwai=`p05AnW2cyji|uww6Ym3j^al` z&tLYYhbTp{Rm;<pu7@u$a2fkVBAR}^_A1BVS?)D@FItYF#HF6W4d3;v*+-cBn091} z1JMV}gadRiu740RGdDkoG7Yn7^djT0i_(_oB{rJAWmn~;<^6qJw`U0MHJ`V0dfzn2 zupo4WK7BIMkhl>`p4M>dQ)DfFtWN#w+oa;%elk2k0T(?zsrO1g<+Crne>S<o$mq-R zvttS>3Rh~n-Ob#^@52ODMZ#^mHB@F6f7|BA`(X0&@?tS-#y9f8*Tx4c>s-fn(C#>G z`*;`0akk)28eNaS#{tP0`k}|h&0Ryc{_?=|?196QF}n&2UDQ+}>p4%cCpE;Y1=M~D z3Y7`*a}fT+4DFpmeZdM5H63N~7TMXjDPC4ouFO`_X^@lGwH4GU=0^*q`}!DERp)v) zuyMe6WWs9+YL3@>k|<=-ja9}%_O9TmWA!sk&B|dDs#&We8Mt-xt9l1;6$vfh#P{D4 zz4YO<`N1bSN7F_3EX_~UZ}#|c&fgHPuFmzSqHKdKGjJk}&z#YNFismTJ5utgZ~wWE z{V(M1kPBSOdl28;VioZmP2372?J6$!?kcar>UtJtmbtILzs>*oeqUj8CDcah`xphy zju+KHy8S4A*0YuT>pEPDhobFI;YI_>a~xl<;8z3jQ8%*QJ+2rq_3bT*4x^LaahNHU zl5)r5QmU)zfw*9{+DVz9fF{c?CYBaF^}oLC7v~`lI9pzZHue6^B|n><50RNZfA@)1 z&S@S0Uo1fE^2)NXUo$sp;>#hitXBmumvYcn@y5`G=!Bzu9W0tEP4wH`@VmZ=nJS_2 zgi*>4N7r2!ElKOorF}j}CYQ`Zn)UHP9vW0}p1*dp({2aer4N=Ig#+1)Pqg~RUdz2! zS9hNItpo?5!Qs(bB{gY<*FV2lqWM)@Ecr!;pDmFdb4-0tu`-w=jY&*?w98M_e0?e` z>U_(eK*yV9GCI-0UAIZmajt1-N_|&s#O$q_YPhV>daKI}-l%|NCV|Rx6Hd1vjdtW) zZ57?aoW>N`qJS%2*LA1I84dcvm6ds)agn8g%t(u4WT|Qw^$Zk`B{M{7)@JbWIhlB0 z>3?S8u)_0gW%+B~B?)Q6cRQ5yckga}^5*M{eZD^n!t&E~kYXk&RNlqeX%*UqYN<P< z@C~IxxNuR|Yquiy3vV>Py|lVm*wm7$aXk-D)ySc7Z|ln>tIE4Mtl0)L3yVB(!Hv0? z`q8?o-=S}6<a~8ohIzS}=tV8Pnr|`elfOH(X%8I{Bnt|_Iq}~{K3iStlk-tg#k_g^ zC-UTr2F4-Xb|Wz2>npReiuqDMh?}k|Ik~GRVJoN|({=okD}Tq5=EoH_?YdbpZ#f<u z$~!f0rO1Dn6)_8q9L82hSKhhVLx+UOlNs=E(w03uTbC;;_GGm^J3USJ(Y*FKRGkP` zh<le~b#Jr1oLoSsQ!7AuWyxyg3kuyk1Qd|&$z?sNk+|ghlk_^;p)m8IMjw!9{h?X2 z(d?l5D{5z7GTCrs;r6|%ywdVqbc<7TSFXIX{&rjR4!Ou`{gK^}NLCCW#RtF#EwKE$ zFX>OZG-@uSOs}*)$;zrb{5`&Y{^7oCbEP)hAE#G=D;OL!r`OCq2Yz^1n1G^^*~G5~ zWt62}n3TSA?@iX-+_=#CjPFG5#c|s08vXss9t+w@)<KWa0O~Z^cT|#HnFqGZlMXR5 zcQQIIwNA7dKARbi5>QgJY+0O0dT*!V;&G}MZd8j8scAW+6cM`RY=vX;AN%Ki*gNbw z5M+~?ekOo4MwMGZoVW7V7YFXglw=)j`cbN>5sJC`%ylO+b9J_tY`vy+n84QRwwWyy zVw8S3h>R|lHb!;8;N1(kmXx)pajMr$VD^26db}t0XRmL)ee_A^@gaqQ#Fy9F-tlQ^ ze|vwCSI2upY!p&sy(lR~q+-qE{Xz_q4;(*qZ?kloG>&}hDRxZ6sN>@NPufvOMqX$& zi+Xb@5B;}}K9F<K5LU%d0%ISstc7ABFsFea!BCEBf95t<?zb@v;z#zXtV{mz*%$aU zWq;K8^R)EzA!6o^2`rQmq2dO?J965<tym4rfnY7yV@_i^vN8CMW@bwy!?>=F4ftJ} z#u~S>-#&UgbafI$(I#f0AvmXh>TC)%goi;=`ol)48wJNm`1r~V3@8l*=bi{8oVl>$ zj@J^;$dJO_UU$yKKw7zp37^b9jYG?3Ej*^tCsW5@H=K8F`*Zh+y1N;Mqpl-FvrIsT z-ym3?w#Mz$wVro;Wwt-hI@t*HI6CGmXa9T~Cmx`aRdzh>e%0Bt%G3=Io%nm3?6Iy6 zL+?v6J_?F$tE+RLlN4eO3nX1`&t$Pt%W55PICWJirhK1ab|y)%fr^F##b~rBeRMc! zX({`U!iYQPL#Bte(%sa7hPWL!MPewO!nbb%>%%N4JVJCY?0BWMmUCrms*++so;Ls6 zpVQNGiS9@WW-96Y1N^^A^WA^+t6}te3XK({<xt#zJ#**l^0K<NmMjR5?`&Eh6vf|o z;Lj|0&3Po2fZ6@Nx8sYp_Hha-t`tkP72kstUUr!=!5&P^;Y>TW>4sqLO*nv|X<qhb zvSN1D2>=lcRG9}9Nxqx!6$p$FrQiR>AYRVck!-*3U8N7{NlC=42dG}YBS$O&ESNOI zR27iROHV$EI~0>x${iFOIF}{xN-yC>ooT|m;;xC(i#Kk}f+aT3DRR3?X8n^-<=vTz zU24MPmp5NtUz&WUq)=|1n>`UK!zzAlCmqcmc{pmV*tH&BWIuINK5_ps{vd^T-?}^N ztGn1ZLg4L}{_^bPxwPR*K>G9iWV#_U1FJ)==gKZNE#%zyKRspTfga<zCaLp5H5WL_ zrljRz5Z#MH<2A4a)~k!#R+is7c8VTgJ83aHmX+9i?bY#TL&`N&z=+K)rmSY<&sO+t zDvkMXGmw`{$kGkvq1iKw>h-JCiO8oG4PB)5S4GWSDP&V4?$WUBWM{2;>Nxm2CQfxT z^O9BkW7&XO*~lu*`dKXveZC@wCbKFhEyFbFrze7FI^TaQP}o(vzTsscf8Kd&ulvo) zTiyLH@NM4fXd6~BitlZr;cVO+DkUG~HI-~1%E8`L+n?H+=4ny06Ww|9_LRWw-I^CY zz5Zw|qSczFCPj8bsx~{jSjL&BhkR>(zCE4dL7k#l4f~RS`23TCyBPHHuWSvjthjfr z>*<X%XOiAqSK<CD%mCUA;-o%Hb^tYVLb<NAy!`2#H$xB4p<2Au2ejn-tAZFtLNlq= zY8At0;Hh`yzj(py8g+8g!SwizuZvG^r0eC6h3BbY{*2!92u?KtL|$9-UUCCSOl)z4 zAzLhF?Sms-{t23ol`pneGwl$F4*p@$!1^^K+Gt)g{NvS^=dBM{lGFW?^_6}c)sky? zl36W2BrE@9G*I2$5ZxJk-}$>eV~<<zGp_1Tj4Y?;7Lqlt9Ws{ZLK*QZ!EZfiw&Lt_ zxO0_AxQ35${j@0-cjC5XVE9q&%AY(u{Dng%u2aJO?tm%z!k?<^YBCM4E6#@Ol?jo5 z&HcjH=Lx1N?TZsXi!ABJjvXyXKC@L`dU@aBSXy>kO~bqc2ZbgFbeM`_ee-)&m%eLF zPIm9PQ%<78zl2_W=yxrSl2yC!92}Da(Y6NflYBJ8C6C~UUHg7-vt))GH<5(flzg%l z5E!G)nR^`@qT3HMb|ga(Oa6TP^>SzN8Btb`*<0J6%2+YLTr#6<QxzXYe|e^Qd3oiG zHk163BY#~cmG!Rue&!~~EdI`3?eE%(>~Xs<AAsF_5>Z(O+sDndvCD^IR980A-dq4; z@;n}7Tu;gUkb5_qH9Mfd{ld%rZm-u74SITY{rdpBZ2I(*p>-i@*CBgNedp!%DL;JN z9dspeO}xr|{kOK(ihDfDGklNLFaMozZf0?TEIJtZv6w2g?5`K69bySlYT){7F-m|| zq(W?-p@v2|Alw3&w~V}aWRz@o?C1;E>pN%y=3NR?nuc}abx0J+s7~&!;1YP;vo}+K zYFcr{qDu5(r1`wE73F(=YJn%*g%5Aaa~;tdzj69-<ZR3jn;f}MdE}QHtVdg^&PFja zI*dszea$$xokun1kfGmkw$H(P>*wLSSc$`U=)l?1&o)oUPP=9+_bH302FXdMXx=iO zdf!pNUwHlatd6t7zUT>MCbyCv!Lvd)%37bf|Cq4sXd4|8DV%H%NHeiesegLCG)C1^ z<!sTVIR1920s$Qk4$IGe@0rp*2=micKU4fo8PFA%_Rjx0htaB$ZNZzWB4es{N&Sqx zOVN}8<EE|+MV0$653)s#<*6SU%KmQCWD(K1)w4{;(5q*{ZKZ%a)-yxMLW=P_$avFz zci!6UUYqj6@Sa6#eT=Ddx!pg2`p=UJrO<`sX77cz<@tqUIT#ztOG*0^cB7b%8t0X6 zi@J;15x`-`Z9C?V80G-o^HkdBg9DW@FOX^sP-V@^;>3k@C+o75jp!Kg4~d|VYL@?Y zm#MaJf9o+Y=)cXQT|Cu}%i-W@&95>u%%wlP?<KqOmRvN`xP0a9O0sFT*s|RM?eT+E z^VeGE9}H&Rbmsgc6w`R@cKw1$o?fG*OS#XN-&1P6LYJNvU8CP!<o2!L%+`>hp+~yv zA0y}_Pgfe+iR}_Lp4(!4@%VQmj?b-2KdXgYf`gPiKk8a;{a|`uNPIhsb?z_8f=2i5 z%PRX_OMQgcX;(O|hm4Jz2O1rCWg(iB)-+ebY<bZ(*k!Zx;MJzmrQE5}@x^gBPl?`Q ze#UlR4LgLUGe#o%s1jC{ZcSxsQdbBbD%j~7KQQF-vd!A#tq-@%c#Xwm_<~E(i6?i@ zl)CmXeN5OTmu^%Ry(9M1L`JlZ%)POXg3bxs=i?_LxF6GQw-4QYZfw~@bn3^gD(i#C zg&%F{E~-yvVGp4y3K9CH`62weP^3~xZ++oLmU`6OoaKnoXffqd{Aq`CfTnt4Y6xM{ z&rD>cMWh{Orlzt1ZslZ!;$lOpyp)mQ5}ME7ns4$k3tdthoEGljmESqf!e3H!N?)t7 z<KcRYxbK6;urr?mx7R;O`><2jk123#o_r<v7Q6Lw<8-yPCjy=mBN+#kX#jEBYd^3n z=``GQLu$n`_=joKu}<h|o5sR@+Bvg@o?QZZ9=C6PC3#sn7P0duNvrt>T0yt%5{n~` zJP$=xbde6+4xU#FmYqu8UNop^{lHiXD;wGJ@7=pKa{Vil@1+CxN8I^AL5V;x__Z7& zJ9$_)pYkR5t%h6W7uCu{=^2@HbJiWC%j~<V-sBZc&wu}xbY)+{8DEb*lGBUL?H`H@ zzQ}r-Gx4g${+ga4P1o6Ti|v|GQ^c9q4Z^GoeGbN+r;7-8P&;dD9q%$dia<b>h@rNP zP5MsV+e!mde8(nSZtq(2kt{6HKJ~utFlC)GF^i15{ITtvn3mShL&pqB$TG?7yro=O zrH=cvxwzP(;rsi{+bmv1wY_?K&*~BO*L_C@5BCd$v_*hP@GP(I&C-|EDj*|^s_QKZ z39O``<z>rw{`Z#jce>ex<WKR{+<c4$+EEv8AMWfG)+1(FT>{7j^ADz3^m)Ou6&Vq) zsHo08{&I5-_W=1L+f%uN1d9X;928l4t>gGfKmB`%Ob%67_u}d!WD1Rpl%eQ@@5DdQ z@t>`B<~gH-?1az}VUPeC!@vJI<w_5yPpoe&pe}??2?k+6RvL}<@32#EWYSYiE}r*K z9T`3n$%SE}-^tQa%O}qmcKq1^S^+kJ-~D5x^?CcIM_Yuw3yLQ@tC%SWJi^$P4CeQC zk((1cpH=Bb12_NxL)L=uHr;!`Dw_x!ja}(tjG@;fzY~*TDGCgaQRRMO9L_YLeUe{p zN23~$x`f3oC}V!UIei~6EA<EMj)9HsMn>Rl=*Yv5)@{_KE9A7CrFSdo@%Q*YRc`&e zSkjibe4das1UYnhJhv%x0bVaPkVt~c0u$+&ec!{6&DTu6zPNsh@!z<x2}Q+s>##kp zTp)yK9G2U1t8A-C{l8Hn=B8gFsRSY@W@j^PQ~K#-KGuY(8{C-qjJ>ms<;)wQkaTsU zo`FRy_2*x8WNjDK$_4X3uC2J9im4y^x?iu5LEy>tlLQi=fF#_%Gua~dr^ACUHn;jx z`s=o}^;f>N-SgW8QuD5oN%f~ww<c;d`oezl_87GSp=d|~;+LC-;WRt90zj#^k;=dx zn@>ncKAaoiZ9)opx3u>u=U-n6dCYP<Cr$~e|E(N#G0na2>X^lAq+>cNuCF<TzcV}R z<XF~jd`D&j(iGP@WgJP59vk+v@1^C}Ij!2b(rJ(@Z#UI`dDym+{O1AJ-;cWN8t&KC z-QFu9RLYUSU7n)i6df%Z>t!=#d`RGN{=Ca6-?c7LfhWfXJ4#CyMT#z!j-d1Y>QU3m zFblv6-4JtBHxh_PoA0eP6C=|lk1jkO&cGH5@e+Zz={i&vxhrg;zyF$nF-9Oj5wZwo zDD-JVs!T!o5<wS(pjQC_oLT#WK&25Qv>r2P2#)~CpE`f^tQNPz0FG0XYj9t)qfe>J zjZo`sSKENL;nX`%8{S@}`1I-HU}z<8{Kt{_%H<i$M*U*eUyT9&+w{sf6cva5Oy^ph z38bAB3kbl~moqKQ)?Y*K2{EL~YR<}{sR}e6emiMf`A$hKue<*!E_55Vh$0*NxW!|b zsZfoRQ~x{79`eogETd<};X{KrN^An^Yi^Fj-J#gk_%6?tzxeMPfk|p|vBvQ#mj2<W z;loRq8y6(L+$Ukk>{A_brae>Gna4jMcC@;lDqTlEiHYgV+%I7-QQ7mC7vE8ByS;}_ zAso8kuUgqaIRqRAqY|8xODExF4s-($P9uWrgtITfMfWY`tf;ZmZ7|oG$?u%F5I$6j zt&!iFXki%6eI>tB46+$u7yqykWu%nLpsqu!9PC;6v!u0d{M3I!jOqxbbjY8@60WdN z57s)|DmOLg4NsCiha=zU@VscSfY#@S&LVw6P?)5&)EBZx*X?RQc;8xBoyuYQ-Ma}+ zTj3-)207CX+JPrnP1=R@{k>N+)|S2|<Xq5yugolwYf=6=7^qG4GU?*E5O%c_zQqC| zr`@)+$tH@qUseg>4CGPio5)Yl;QHwVo}bJ3jyv1yNfloE%LVl{oV@axdU`Ic`*VNg z*Y_C$PyVz<kbV1+opaN=lli;#&x$+`5%1|OE@M1Y<vk@=24p>*7jj+rV4W>&#lXn; zaj$#LfbF*f{cVgp>`2j@lP+DDrlZCT=_Zh{1hhOO(6yBikJJOJ25k#K_J|23Q2F42 zkKCb??#syUAs}Z!tO|S1UL{PbL2BeXe3;<tk^uWntc82DPTE3@FX#|YB|VR#wfq@s zUGS>a0BYUXYvKfst)qA>T4#g}FIdfhkqsbGy$U%WVEGN++th+d|5i@`!n2VmcL7P3 z*U+E`IHer0KJ5Nz+_@l}HUcOKF<=W+xOU}(4yOp_E`(eUDm@|i&p;8&0cti?JV%RN zLTJ_6jdh|50?_&jNZ^c&j4(-81kN20GBY$dfH)yMUx3*o6z>VQ0`P^n02T+15G;VF z5I%?R1XO?LV5-vswilrwjlmnpXoT^1QcB7OP1gKEEeLTWXxqzY=v+2iZH+A0p_>sd zC}P`L=hy3%WmBbJwD?6#hyVDseTFeF6V0=om%4N0UcWpmZCOowK_%cZqrOSEV_>nQ zno1+{e#)wqfcr|xZWENy>0ZjW3@!GTH+f-m#yQq9`{P7@J#)$v!Qs>E&%1o`1vpBI zuZH~|;ian0$vI|wA-p)|YbD*eYlmD$Nu|8%ockyX@;k5eoo1C{V-xjH;w~5y5_1zg zxitIB2-oVPQ{!&8&z-%tvkhM9%5H9pc^u8!!-y$BO9P8v4Hobyl<z?z=E33<d>x@n zlpi7Z6NsCux_Uc?oG>?_Viq7ASipRkeCY$$)-2W>JafALd`$=?4PuUsr;oMQ(9-e; zs16i~|12Vf-6xF*BLINT2@O)<9V@}^1r(ni?~YCuaP(i`V*w%oXsv2cK=AmT5C|<v zGdLRLr7M7H1t>M_uNCk~fN(a0_%z{^4jd%@)F*K32|VI6X!e6SkP28CfucsRbpTz% z33Moe^#@Mswa)i~xI)f^b3?BEW?7jG@>#BvC!+{ZIQSg|S{g*xPuQS{?N=dD1(Nt3 z!jl<R(Saz#301|kzigMA(Ae2|lc%5ln(K$4z+LM!MsZ~IHh1HF!^!H?vg%gr>WB3b z?MrVNmkjx+rm`m{x5gE=)u+8TJi;R{l<Tl|Y8zR(eOYZp|EOmQP4eulfK+nwbeo|Q zyRO20f%)0l#&>)QIroAd7CY?WRsFcfKIVQxj^5Dn;izF{RjS)JZ+5hwu%|sAT1Tpx z8d2@DC>9pxw0ZDg&MVxfo7cb=+E^gnK@ll41<`=Q&s-lqfV4>nw3nOg11}tq`Wf^O z3E+ImQqS1?SpvQeDhgY`Spo<N04k2=LipcPh^U|#K)fOwp4qsBv-Je@GIS6~F5uSt z3H=A)-Yg+Y0udAfbPHTMA+e3X0(b+%-o3$<{e;mesDj%djtEWzKFyieTENqOwax=W z^r8Hq*r579`se9J#*&dZFM$66EV&CFIRlIlK{)W7$ZNj_#UVn=HX$Ja=^^@Fz;J=3 zcMQ%C1fPlEAKbr>6}2lIW+rebNQAC+6^N{?tYETE=!=<{?8C)CLQr<Vx+KusBp8wH ze-IP|=>F?O-TBX^madW>vboGqY`M-c=iy1pFLf!z*}9tzliDRd#+@v@MN5=aP4_5M za~Dm&S*G#^`qwbOjFU2FF}2GafA3s4?jo+gua!~n#`+4=>#>;p-n(MXL+JD9JJ7Ik zQ&m1UIy84KeCTQVLu#?R0^)469FGOHEu&vIxoQ9URoAZT*LSnyHp4!d%XX>aX&3hG zT+4+Id!)SFSyM_G!Ap>&AV)40tG}#9WIUqLcmP-jjIz+b#fboihG0Jc5)Vzl81R2j z$0bsk|G5<tpnvTBg|t>&4WAGi0Vj5%A^@$>agi`=G0iT>C7~hT3fhVVb~)DLf0VM} zMUQumY*kQvlB>7@vv)kFCW*}FgKkhg7ERYlllb)~A&|oqq<R9qK+q3yK(<BH4%rPt zw19WtzK;_^f@zD75ptJ2MWbo*3{(J9HcVqVafF|rOGbthd_wSg2xvJt+H`cG(eImm zp>^lCmc125f^*CwhwKYj)9p*cx~=P@+Iz};OKeIE3K>9s8L%xNo%_`kxUp`YZ>&N8 z&iY_chmn6^{Q+KyJ<mlW?=(dTMRxmH4l+RNJm*KzAnnT3LuzDsukBAMgm)qU8`?)M zO>|%;6z_N$7?oA~Nu%FgE6Q(Iv&!n01`TX<UO$f5GFg1lEtQ$2p1Ek~>Q5iw3GFCt zbR-n`Y`<Q6XVXy-25=O#oRO8gYJ*}qsgn2&loK#Hkb2;@gu#R<f|Iv?VllyKA_&;` zdE-c4K<+_ubv&1lyaA6c8)Er{hZ77b30Y=n#F#)h18C+-+gd`e{n7^)WQT>TE@VF7 z(s6k7Z2|9%kpBTi6^EI_Z_N?Z+OCl{_Oc*?y6?N@ffo>Ovpn5DIhg6&SgQJ3YXFl1 zoR6oNX9E$8OYtj^dC&j?QHGF|!tD#nN(E@C#5)t1|FG7c$mjJx!Sg{D4q1aWkmMu* z^ukx;@R`>j)Cxhc^}wk_)&`#=q=H_PDMpl*pp-*|AY4BGc!I_tPrDpNuo8>j&!0}G zZ!849V8;D;c5r>kJSePNi0Z*}owPTH^<NeI`Pk(cINm7Xru_cz+I$52P8o}b<BCP= zZWojys#MQbJj>ZJJZzb+XOY_#I@aE_zEn@9-uXT<LzY*qu6+2!^`^&9;_h#i*psaJ zUZ-RwMIdh6?Ubux>F3r!qaX6jc63tQhFy!3k!IPzntl;8$QU>F{=+ABm!J21kBrX^ z+xFLhET2a$aWB|jK{of-cxP@9q*o?5`QOHQ3{XH42IL@s@6Ci+k?7<|v@~8lN~r3i zI_YXB9L2!l>98$<a0mHEa5e)uZtRFu4A4nShC7Dg8#9aTG;FfqZXIl$$peQCs#R#C z-9smk(BJ?a9Pflb0R{Tvna_I&j$L3SYyeP(e)7qL1QN+om$O>Nc4uh1fE1eg>eUVz znKFYX??62GkEKc{Iek-NPd0cd$WCBYSPLp`XoE#12v?9IA~E)!k%OKPVM+r99D)wj z+^mV%eGlda;3$JG_@O(Th^vszhEM{403WfDpo;(kIO$Cy4?|Ko=psHdKVQsujN+hz zDMTSo#j1uI<_|vktkM|GKI87}$($Z#9G-F9GEuYkr<2!G-C6Dv3(EBBEE65I<%9Bx z>@0cSg)z50nxtk60|K1hcRv+*>yTi>w>rvOxXr(TXM4P^cI|Gj%#&Yj^J^#NbQcG@ z-Rn)^!k{m(Fu@<?_sW;+rFxChn3mtu#`@pia`ZZ~&oOJ3c-8BqPdlK)SGxq^@mW^g z^hX&Ep;B(2r4B3P@J~+`4X+x$yWqw`yZ5lA80EIx(d4O>xcrj5vV4hECd>e!(R2xw z29x)7?|im5Wl;+^q==&motFV{hl)4;j^#a}f#NSLH`ij`<6J{tq1fbd*vS24SN(TT z7wWPt!087^FV;DD%&4z8TL)-7sjPi%V+)h40#S!t7DoT%BO4kqN^KbhtImD%(lN8< zfU>f()m~82(@vBk`!X0|qbA2}p~-5{0zqTf8nVwrj}^sTNAJS=;msSM#K(?qYZJ_m z$^IG>+G!tk@{yn_1w~$Hb#?uonp+c{?`zA4kN`5rHft89JmKHD_o`A`+2*C9y}FAB zY9`<3_UhsPcCIw)9=ck-W2+VI|6&2=ERj_fw~nXs&;}N}{^7PCsqB9wsK>`Q%Y%5Q z$X$EiATi})JBM=YJO=>$X1L`E^r!*dggxQc2EjnW9s>qyc^n~qoS(5>>XAuX{dgsk z-_sUwcrK4ccUrgYz#9MY>pW3n9wU3j9u;fzd&X<>=?0d?-I?cBXgs`j%+=;->>eY~ zJ?s<(w6#CwDfcaM_-vGwNYI78DPEP?kj_2$Odx`0$Le$cR{}40FpU|gGqV`!)iGRc zAvJiDVZf2G@a>I>p+<cZr9or^*_QI;2kIGl%$$x}DtHX_wVv$EX_6jUs($pX#&pLn z9*X#O*X)KbVj~g}&IdUso#Ure0Fi-qOgc-Huxb=WXd=)|3E;o~fj}SZeRYy{uR=?@ z0BQN(Y;J9v@P}0llVK;WUMR>;?d6QCcbTc`&C`07#jp!ngwy7q21On^@cxy*k^1Of z40~Cxnx@myT|DdIo8I$k#(wLrcz3zYH*KN^H2H~fABHxmKGmvgl73xbI+59SB5cf^ z2`@RMD$3Xxq6H<Z$7QLxy6Vo#`cEHt7s(X4HuO@7)uUmd`1qzLhv!gOO{_hQ+#yDB zE?$k3JWx~kO4rGALY>&axPq&NspUgUA^}*@a4e4gVfupOa?mb%D@o;J{#MT)7A?5- zcrB@HEM)o3bU8PPz|c}JO2<qnDhM5K(O1va?snUSrt|7?+RbHAfe`4Ks82Tst(y@D zFQi;w;-Fsflm@!7=b`Z}(kJ(7tOn<9)JmlCbA49syI;-m3tVa#ctr7M7940xZoPoL zgQR@YG1^}ADsA8$(5Yr2y>#qq%}y}cytM|ueeQ$kR;mwIL9`DvZ6)Wv9Amv(USMd? zCB>C!9Q@zk*hLwzV|iUU=6EDbIC5sY^NAbHzIcWlWabC1o-%d956#|dU85!(7zxJ- zqL1?4wzB}WuGQ<5uM5qna0-e1GT`jPvISA{-c#&qQpK;wzg%BBe1PGcbbQpichnpn z^G!psEs>!1I)f}H&t_XUn(wpf26H(TF#1{HjYpKp@FFIn!~<8W*{!Hb2%`_AOquK+ zH16H2WhSiKwk`}dmQP*$$UrX^OkMdRC+BuZtdqx3sNa6BTnd7(3>M+z$jGV>#m5M# z)29%#Ioai~)iTzVnFQJ|gy8|Cv~mFPWz{{T4d#9oifBRzY9!8m3!Suh#HUZ(#T;r2 zu0dlIWCHYItgj9oNo`m2t()T9*yZRrLzGcKfxSgDSue`%^ADtksJ6@?t`(MS^9Fhd zB5<9<s5&hy{e}r5k&)L#-dgYGI;U;N`w==n@9;L;j()eIv<zzX_(LZ5?|r&y^}L{) ziMrJ46kX#}1;qzJ1PgGFUBN9d`;WH`pSXbqCaU``hf12(Hu<&EH(|IHZYXf+i_8<= z%H6K*1fxydt*$>*tudwAvjoM}Jy$E<q?-p1FmNTP?<i}kekHPNWsK^`w}gwd1f#C~ zlKWnO8}7S$2DgE|M-+C@_Ls6A`V-hFJ|+N?!DslY{XpBy>Ww-{m)%LCb&8aq5U-GC zx%|18S!g&l>e3lGInNU7S_c72y#ohC;E?b-J-zRN@A|X3fwcL;<)Z}mk<e;IdJM4( z*K{QtErOH`W4yvqSg#^83V#2Zt@Z|3sXxJ`+^c)Yw=5pTBH`xeyV}`1uyA9yxGA-o zO#Y*oF3H1nV}1ps#F{)krV^3Ue6(@0IXE@$S^d4W8UM5U2}Y?<;Sd8+sKApkNH6MV zpLRpx2i*T$yE?7|L>vkXXO2lZX+!Osa|CAp$J;B!>JTixqyo*t)zZM_N;9<puS?qB zvy63lU*h>`s$nlRCs`fi*ciO5H{D@qbfYSA+1r<}MAX*3RE0}rrSA^iA?Q83zNTr! zsW`x;3*?_$#^Sd^XG=l|O6f>RQhk7imY!Y>o+m4`liH1(X$VH~{_@(lVJGLB!}AL# zLW;6GZ9OEhr*3F|zosRd6emo*HLLwjtMy<`{3W?8D!;l1?mbs0bJgbJ{rqZBY(G6_ zNsGL2@J(9gz-=m_7ueAds{4joT`%gg{X|z`1caTOTU1WQ&eyck`S=a2f@3&}rFi^C z(wWdFKq)^5g^?NHR&tOS{Cw}@HMFvEhx}MSOTMFV7FBlVgh$sTd7<x1M4}5)yQs<0 z(W<u2JG%V&ijkB4Wof+yp{df6811QzSOm8mY(kRemS)1otikXdRIg5aj%=5ajt|8l z6G6WVo`Z=wP3V8fhjKLFV-jMmw1HfQSEY6_vamp0RR}NCw&i=7&MY`8^IKe~WI$1< zbe?ixU~s0Od)cRyRmaPk@vW@vpVubB7d-WMLzkvYcz$Glj{{B7W)a4>8!Yje8z&7# z?T0$;OH)iL$tjVLxfU*H5)BW~-(E6jz9HHghIWMknDovenxA*=wY)w5P`U9>bFk2* zrs0=LnJ>IT=d7N$#`rILpelcz{;F4y)%xrfC9KKZ>iY7!FABJyVueF)(m~O@$}ite zlXxwS|LV+I%9-l4KXjzUNrHreLY0!T&FNaN@y25Q2o%$_W7(ma7)Ts#$kBv_e~ZcN z{xF!Co*rR#g1J_R1x&L8Qn`F$g`R|j3*ELIWOp#UkcV75@$9$KQ<GDW-|6>bh49T6 zu}eiQCDkin6p6Li8y?-ipH|dwLC`I&c3Nhww6Q`vlF(EgcW%n=i){Zb(MLY(WQeK4 zLT;hQmw>Z7rvsbJ<C{8Pk+#zDA^aSd<=IBMg>=CotW!_HK^$`B!No;uOm-Ynw-FfP zpA5dY`F4AZ+_={H$XcYYZm(>QzU6gprSB<cWM$b-9b?ZFweP4Ys%H_g`*K0tU3zi$ zB;jiuMR79JqH0gjkAj4o+bjpHq)NZb5HX_p#X)YK9P>Gzo=Y2t&E#pgcvCI*b|hw8 zbQ3k3J3rkMot15MZi{L_`myKu-uI5{QK<4pi!x6)=IFA@Sa5rKrnZgz(Hj2cW-;)? zyT|J~JsH^;V@{*VzxUp!eTms<=JNqNj&<i8XD72u3?zFcTup5@4(XKSJ*6QVW6Eh% z|M$v1?~@~cv_B8WZ;0v2@L*kL%+BY|X0-oMe;cwb^;p}%TB{Ts{sS}*TAtOUzz}aK zSa)}n%<Y)2zamZx=VHapk8S+=mhSCEv8PS<lF)IpOHX2W{=Ksa_o-N$4y}(5PBM$Q zeQ&C*4Q}vXeE#QgY(s$vm;S=iK}N=OuJUJ$W8p)`HE@T8krPoMg@&xS$eVt!`r(26 zxJ%5EapU9cJRy5`#YN=#?p3`cB*{hG6c<WHTzJ6AC)X)1yqBHmr|PDvnyw_yw^!Wl zYF9&|-om1(=&OLr-Dj{>W&h-DvplfpWadc8$;)OH4J$Mji0wJK&QFDf;v?+^Q(l;4 zJP#9fB0jXHeE{z}mbU{9?W_`iM_lR}LtGV7lgz4BA95ahfY)9*S8fn|^@Qoa*KR)L z!J0_8+YI(@dPH~fc56=YzH8S?9k)s8S)|hOn-=QK_hF*d|4{h$+c(oDy!+ItfdReM zDoe@r<;1R2%ht5xy-ji5MShZjPkBNLPB}SCL_Bu+JNYB+)hm;^Un<MR#=;MGm9~+v zhny0BXVo~rxh|OB<;!xZXzAnBTx^`_@H=(l!QH4f&7N-Pk>W0DULNt29xS2LZNDZF z-C7qi(OJVO_7JV)Hpj?b{bCQ1CTW?_kk}lGZFf#|e7=$&5&pdKq}S3{oFP}Egc!Sj z-)pL%+m6UG+PgirCa5>$D>+o~Q$2C;=xzMKKgs&w!2{M4i_CXJKhV3IH{|E)eH^6i zbJI0ltEq`P{_pnFoMOFut9`J1Y$oQroAhN;4)=pPX?Y=sB}AdPReec8!I31i)2F$U z-{^$&^C2M^Su>aufB3)wjelG1|LTwL^;q^DIN&63_sVzc=nfke8tv-Lh8dNX^g9o@ zpAZo>$@nPs*0k2UGJSz;zvy;hY={A_c*aB^=`9lZefKE7pW@$blK+!}d@H41@FU`A zewRRZulR4X(Gx-6XHNtT24-$te+OoN|JU-Z57|YEL-^B$xVY}H{AwH-q|;@f46uHu z;%&tK&w47W<W_&;=K;5(u>wW0*nfY&2eVq2iJm*bW73xMO@UuC3{QGX%gBg6HYY{H zGbw4PMbk1e3<l!pjr1+8uFO#Rle-1R(vXo!%1j;n5bGtq(IPp(<Er*=@9#x{VAmry zq*f4|A62Rh<*V4a#s{wY)#llH4uzW6*ZyWfZLh&y=cx7CRdKg3ZNIg-l8Sc7;W^9} zbiW(>8diG8ZfM2xNHzo_^`aP=AkO!zkY&WV>Snpi_|rs()(b@JyihXiSXA3so4o0I z&htu7J<fJ0j?UG=yEJPPRb)o44LhBjn<^$UAG#`Np8uccJm=AczNtvxhbvzUmk;lu zq%^&xnPJoO?mi1k@!8GmcOP|%(S@Gp(hYw0?<srPxgU(pab|Vs7XBsV@ho`Hp0?o% zq|h^K#Q{d14JubhevRhz?LJL>ZMJQp)#uz)g|=>|qq{6*R3_ARu(bxcx`*#1Y32vF z9fh$?%{8sNiJMH8jXJ+mrFz_moSNfvaTGJY=V!erm$R2`e^vy|UH(;v4-yd_c-}d) zk=43o-vJm%3oysrzyIkP)6*MOBsXH*MTOc01&se5JvZT&BVk_sAw7}k<?BY3mOs+i zRa0wwr<%rXb#$WXU><gpqi&o5s}4@>>k$EFD&wrcP-*Y@a{&R_La9CX)GoYum2`V% zmtFsTna%r?BXN7i!Vk1%U2d8vi&4yv^I4vcXk8n-<M-(U_iMh&eG(FZxs9U+gPCj9 z{}QyOpA)ogzAIvWtA2h1%}Ph^yNWHyQ#=a0nmEN2HTUPGoL;&P6dTyaatLu)^d^o* zU3TMR4hmQ=`m<!N{JL>!Zmw-CYkD)ziz2!~XY5fjB7ZZ<<H*MjSK_6+{5Ge|E-9A0 zgQg83AEMlngfdVhEfG^cU?Ps9G1vi>$XxNE?_CZp>cz%KL=7j*!g&gV?j0uqa^9YX zMN)cK9<~uQNV1{4g@i<fDiB@a9QfGCKV(gCXuYZ3P;yk&u_E!`l}AZ*{n4o`UhKH; zjl?*0;Rh^aECD`-_DKt(TFVWa*YPg*)n$`H^aYp)cE#MJ_*HAq$zoql&l1>b9el$! z7_Ac9r^l@r&|<6_bwLB<;z)HDvMtQu`q~WblQGtD^_8?@{g+HVYPC*&_s-wb&+Be; z^MFABcXUHz<KE8Y8|`j@u{bKai^fu5=0Q}ys3k|Tt2qckO;@*cd<iGae+U&6LS?vV zBrVshc7}{}3);7JnDIdR^q#BOO?;~hu{j+!<6Wh}3-MVze)ET@D?dv9ydtpc@BH}P zE7^cQ{7LyLpF&6uGBFWCYIrW?Vk0rT7R+qA3c@hu3WF{W+VmWuynm`6J)c=!Cq&nc zT)xT0xVGtM3vDNEgx7`^%h7&CixazD7Fx42e?4r0i!afpyIpRgHHGuwD}|){3J~^$ z*Rb_!WXEa~$Wgshp{~2>iIA*Wjn8%by2y&6sy-BD3ZVH#G;R|`XG#tm1#?Il^uLKi ziTgCgv(9}(E<zr0Q?*Zv_laSKr~orRbI^v&9)4(#T){ygd=MbZ1VIt&k}TwQgpDLn zZs%YHlBkz_T$G6X)ev5qUhziGZ?M_)qkme%*jQf9Q!FyI;Qh1j#+ddXS>!rWJWYz> za9Znd1!&iVGdr|;V4wT7{g|S1%O~qR2Dq<`X}(m%p&nvocXS;8Q5s3sBy&zv^QeX3 zR9CK^AR{x!P+w^lA(NeA^~dSTL(Cj6VyNe{)LjjnjJM{lURaygU{<AsaUIZ)_j%r( zf7Uti3!MZ@z?!p#4*tu!L-sfJo6LQtdCV#Oames9!*u(`q*PGr?JCn&!L@~(mHj3d z1j8?2M_F%E;R(HcH-O0?M1L-?4X~gv869Ia$EhQvg6Lq@i_e>seN1IXfU>x2T?&St z*+S=E3ZS(CM{)W};om*$%a?m0K}?((;>lq_R4?DMWX)=aFvFGf`g?~PJ}}aY(N+ro zX|?TTkb;!hK^d8NbOcchcbJu0Krn{*>o|6NMy=VOJ!-XyxYu|AFEqyr5iLkUsiidz z8=I(wui(rX6zE&a{d<`nS}8nuKVoue*DbzJGNHtJNHK#o>HYET#M@lMmm|ciiEaQ< z`#{iZp)mYn3cUb5z1ScG;~(I%%7K#*D!@#KgQ?0~#9i-yghe%4RIttb0#^d@O8T%v zL?eTq{{B&vwf{eU<V5jn&{5=m1U-QyG{VuY7W(k}rFD}Z)G|;+wLm8sW!4r{?o@;V z<khR{z_I#mu3pA}bv(tM?Ll?me{Le{QMguLMc;8A0?(KT=0IAEP&Pxb@ccWPiU>gi zb{l3I1mp}3k#a<j2EIS&=MjTjqA$}Vz50+)5dS-I?*b!nAAS$-ow5W&4fe5Q@lDmx z`>u!T5n+XnfH4f`jp|VsLP2U82I;e?nh9Z2)KZvRmQT15>cL2}OxJZ}x$B6Bob&{D zg<bw05~wh`wqL4-ej_3AT`-<g4-F6!;`A?jOT*k&8NMEbE;oj*Jm|w4!!4eg+-yZu zHi?!<n`ITC=n1hN#1=T6w$u!wp$A25MMXu(;U{4n3zM>^(CP!8Obo3X>NMuC4=->B zI8h2bnJNwT1^9t*U5To%0$|}lC<_yl<8<E{*pDG)!BFYWT%$xN03g(rz;S(g=|cbd z-19qV94HxQMPVcWL@VJ3uLr9dzqLV5NT*q1_o4c|i$a)C=^)gE01?5^ol8(K7!<KR zBp5p4*+1;XXOAYLr(mql;!phYrU`<VM~N{3o`6u|_K#V9>(`0l6&8({YN1Um0iCgf z@G5)rJ`^p{FlhG#&B`Uw{#%`9h!0jmtt_B-s@g7Jx5&r?%>faZa^5Z{TwF<vJo*EO ze_IzFJ8ko0+n&n}%@cuDjEp(xAj1pa8jIX3xuc!wHP0?YbjiW;;-xZiR<K;eJ@UUl zzQjatI;w0f07s|#!((egmmB&A)@y&ELPbbu0UEF~a?neXgV4suN8S^;uCPwzzzhd* z$lpY)Pa=`Hy#7ZQ4gBx58;OF9lrvL)o6)##+G;oGKn=+9UEl|V#aFWv-}C`AS;{_V zE!`*~=B3!l@*JIzX5k1O@$dXkrZSOZ6N5HSDER~NlIi*F1Tx5HqPA>+N6hd|5qjqa z`uh}#FQKX-%sK>M*a&(enGx$=CB{%I)Z|^wq(XO<n8kvMm#VsG|C|RIVfolX+;=xX zVlY&1TVB8`VC)G`5Ux-J=z9cH6r!qTc0^+X?vfudln8yZGLheFfxeT*l$S-G0p`kv zT5N5Z*bQj^N?RwoSsv|{5x~~NW-J^Gkq}miz~pG>KY=w&IMFvm0|)RS_I=XQal|ts zScDisHbV^os=^*nnI&v|M`D~CMV86{D?lSs3CKs#2=}2y1zpY-=&<6=|DACJzFVhn z@?A{%inF)oOQ1$DM(j;3E@ls{u538j`vrC^Asv2)7zZG|YYIpYHXq?dfTLJ|Z4dY$ z5oXtZoh;j8QuTm|*wsKJ>|L7s@xhg!P*y{?2@<}~(5@!EiL7-F2?TNVKnxIog{#09 zAgx4)qzrmh706WahQGqjbCg@><>0~uMOhS&6D}6aXf6w-SRI8{9wjAZ0kq0sdTox! z2-VL=03E2~wtNjPAfcB5U=|6~gEHIFY;bW(&VM}z3f|s%7z9BSDi_heX6BL*3$CG4 zNVGz22+iLAn!rGwi$l;ZYy{dI7k!tCdcT$V`C-PVKH*H5)<fPTO!}IPTL_$eZ^0;l zQ|f%_+N=_xI{<l>Q&6o0gs0C^W_33jrHD*DH^u}BABm=sM3BY_!{q3OfAAOd?r`rT z966Sgu{Z!PMF_fJpH*NoMr=zwQi;j-52Yg1i3Y5h8QW5KRSFBM%spOA#39jCLRY*C z;Gy}+Zi$?Enva+jtzdWW2FH|0764N)C)6Xor4itW<~MllQv@LKXQ4AM_9cl46b1>I zmYW<>HyrQ*h?zBH90|S}K%krmJTPP0I*rwLK=$ceFPQ%p85uIca&#{}knjEb_s{E8 zA{Y}JZnURl)v=dAIawjnLo|%o1^~XzVOAl6Nd%No&Oi%K*4UVXz^~whlAAzNv>0k! zB$&qv1EPt)Pe6x=k4nrD^dO<nZ4wC#RD0P*<mHXosID7h8N_3U;-&-Q@f?AT$}v~k zm=2U7My*G$w+X<hxCxC{X8qI|h&omSri$EcPG)mX24fg00u2XXfsqgk39z5UJUwhF zGAyhdGU!}X_9H_>T3)@FcD%$&t*tcq{em*yFFb;)(3t}kWFPxi*qUqDM&p1J!)pSE z=es_3`IuERH!-w_ZsRjR-0<v^!S6lq^BMU>0#XqO2M(QY3d1!(M8U0ek`5KlL-;t! z$T?71tal-b8~Lp-7~L364x<O;?<nLDD~Q%;w%K+-_WEB22_2A<iiM>Jpl<FF7;7M| zKvTE8-@$~H9OTmNc$^mhiR;2}%Ot-u)NAAW_PbXQ;`k2fHJ!ZdrvgdJJYk=shxrem za(OlV*z3o?+dxy8_0!bSdHD-(o~95Om(icOyqmx}7XE%2L;x6}r40DlF+5p9_zJ-b z_+Sri;T7-Fnl+BHUb>t0!wBoln9yQsziJ&71%+4-IM{+VHv$u*u)C?4JY=;8RrV8+ z2eCfl$rHCPOFJn82=QB}zxGG!8u!CPuySzbpIsY-h5-d65|6uAp#OLv(Ii3rkY-wy z>3&AaE&b}vSZ|y&orypvVb&xV6A};$DAfXDaTZ|KyH~#A1$HG1ItF>xRq*>Fw&^m2 zvmFbK!Z^c)qNvb^X&FsIX@qdyjH}#Qi7uE^rnIBtC$BXr6#>-4Qzx{J3H48yP(IvN z!?_FoND#F0j`f!2Oi=&*%6Usg#4r^?&{$^Cfl#?YcH{s^rwNH|e0@l;n&&lfK~x$k zAqteNoz&!9Tt~4OGagXtf<!VQDu`Hh_loTM3^t0{74H*&B~2TIsR;<S=QqucyeZ5O zzgw);l6d=aw)Y6f6ciL(WUJC7%9~`n?ho0RUJ&NqNeU4jeYdtB;9``HKQenR|Bo6v z9uQg6gXDgb<Q#R1mCl|Cj2eDBhH66xa3Z>-X~b-HsFnzWfX9eH>Q*PqIN0hr>)kU7 z3KY0PWst7OtdFXNeF#ZD{79QjzO0v%LK*p?*~Z!m90~%k$oPt+r*TKaq3e(1l2v{u zfT&@9(J2c1c7B|2BPQ1ScHZ;ntrR|R<{Ge}05@SfpT+xw-U~@2q-tNtSd4c5)WweE z?$TPRzr0aFr28xG=+FR=K?kBhbq0#o*tMmyO>_882pGP9NF`Lz=O6WqxZaTDt{|E6 zz`$m-En^P}1Y}bY(Ip`XPv9UiB0n#Gnot!*b{5J;Bhe$~)E~eS_g##En%uFdTT4er z$7>A*>>zMK=D2-qe!RU!2ushpVtFL-2>`?ajN}521J|kn%m*P5ZHalJk<UVF^}4{H zT`kn~@qJevHutP3#0Lo{wDs4JfGFL=S@^8Kn#eU{NRcK2gXuZ6_YesQ?K=h8Gg^f( z^&t2(o`{tq)LabeZ{%sAi*(gxI9y5S3Kj*0$KX>g4w>&Lq~Xv-s6P@OE0D$-!abgV zvKSG8JioI6V!pWd4zf~1)CX*fgOCozUY<oo9|jq5D8PjjZelWWi17d%H8w~5l8kTS zrgb75&L%o_ZMXgMkpBCd>%Vb%K>hFl&MA?rLy}RL^<i=5AHAKlg2=;DQFk#iGaogt zV<g<yh*=Yw3FRh_5TR-;5trp*T|(T#wG9pCFwi8z7ZJ*240@N4sag^j?n8F5a0H}j ztZ_Id9y6aHi1X~3=NDTd=apU=+C>N)z`4qJqLAuH@gp325fmDPl@-bcD*q#wdR$sm zT8&rNo0eBcE@)pX#zgPBcL-2#nFRxsL=Yy{8LCc|_!443ei3GnaF9uP`4VfuwDQ-& z+&m1H=2p*%Dh~<#b0Sa2y%~ixVD9@xwb<z#C!edV%$gTlAliw<<{@YAP=PnE=hmw1 ze@l6wsJjvM@fQq{NmzwVNTQ6KC@{u{7;ZR#th3mMMCW6lce^eUqm^1UU(LjIUMvT$ z#T-Cv&^g6+#)d+u`Runb$BEt$gjO-$L2z5f{#JnuCQ(tPSj~PtM@MMlBCq%TUYeo9 zPbW3Mb98i+5NU*9wsK3lsQ8e>se<`tC9XtWUIec_F#Ox2|GPt&8tD$eY*+9g!hF{L zwwLk1YAwGrxZ93E>AJws11iVRN2U3AdGoJs>EA#6XwE1CHo)bai1MmzeZrnNQPUoh zgtMT0{2<*4`<@sg5X8WaoJ4ZD?+$7}tv#Nr2?%*1NHsZ@>^=b=E@Iipjy&?#^qMGg z#e-2sniH-_Oowvng(Uv4BMYQ)m>sFXcogY@1gftvAL0-})basd^(Zn@4#_4UlcrEF z^(g77x%Q)XbHm+tF1nX!l@K{5Do52*1N!k~cW%}Av6`x&)ZkV`L?iJ(ulMGcr1pa3 zAEd&l9j_oj5h(}qSa$cvLwZI+x>qYaBGG;kDw%IiG#+yiC(<`0`ywe;I5{h$YJNAq zth3#vr#K`t-ZYP;h=sikUCVK(z-MX1qJ?vR?dE0zvO>8H;}g2Cii=~^56L3B!iiQb zuRY(kbFrYGPg;88)mNt+xNy=xlcenzrPX#{+1s=<bx4u}`|p{DJtT~eStt+nYD3nZ zYwk^{UkEXDMKddQUd%LGFGS35oXAZ6hy+%i!A?oCZ^QJM*l1|1YuN91Jo<*z#g<im z*=g=|&kBnQ(K1TCk9CDAwUOIT^AmB(m-b*kpCmx~2&g1$lkQ~_c6;va0w#YDKqsPi z1L&H3k@7z8?E`4<7}`3ynK>b;i~l~RRxRe#s;!Irs2o@G7Qz!r*VxlMmOU*66*<9q z=G@fNww?bsFMj-3C;H~*xw}_(?pR)#@^hC<Ryp_X-x=Y-2Z!qNo5oPHJcHe*9QydC zQgJoAvTfUMgt&ESY@U@y0f9-iUaUFSQVk$!{gLX|e9*aQyyWF^y=r^^O><K6q?F`{ zr;i`5a7C@%F5lVSwd~yCKJN0pfi9cq@B&%DM7{0z&my{|waGKZJyQm@4&hO2-qQ9Z zh03q~=LIa(+onCdH45)!Nq;r)$FDG4JYl8V{Po&4qCmCgW~9{6(NR3aI-nPvLR}%% zr&zB@vAmTxCT7FOFyA+zdN6ZlY!3k~pbwKr1c?E36Q{#BK7M`s;^5Lsww_=?H^-vS zs;x(6_?4ShPG}$=K3vDu8GW;JV*l0Wtxj6Pj1?0U?y)j%j7N7|8E^~KC5QO)WJ^-< z%NS!HA+b?0-GzT0{R>j`#+fyNy(86w3;t2%uU)qC1Ox;g$~sg%;g;*SxrMs2udn<p zK*8A^HtdHbWj#H2^X%k|zu90%cO>>|_D+_mPr?FEQ|==zlHM;ONosz#Qp?DQG-P>d zvMpCn;N7*}Ek)fNwURtMqS3MQ52<ZLSF?E|qIsCpBJtAzyQ9A~<5Oj<@%{S>9(!un z_=yUiUQDn~QHhUFFuAz+;mdP!n1w-x7~d^nt)}AvQ)Hxvq;VI=k>TOU<*mMT_536k zl+>z6mAQqaZ@qh{{N<5?fd#+8JDDI{K27t~3=t6`DiKJ{#?PNsKc#-qB-?-M6A1F} zFV{ceK}P<my2>oq&;DJlzsdB4!Nw`Nv(L^ySrlv3tRwIDAwO3h!4dp-LsK!Bn0%x6 z0sg|;2FaE(&iv{IASj6h4eHh7oqjj*LA{Hn4AHc;a5m8sFwqkc5XBFsc>tY4(Vkmc zBtTS9BJAm7Wlc>6E2~k=A+4I<@tMey)-U;GZM08uP-TfNcMr<2+y3p>JPIT2g_M#r zW(mZWa$>)AGk&153OxvT%bj(cxuU3q2gH~B+d-u2UoXiS*Q&R#%xkMr?jlV@vi%27 z1Y6iT*G@K5S-y;b#mK;5?5Dl@{+;~}j~>T7?4~Uz@&CdVWD;0GC8HZm>M3P>s_|af z_shh&c9Nf4DJGQa*H`J@!dR4+<J3nmsZ^4S!XH@y4M4H&-164_q__4p%JS}hrczsD zbJniY=xFrugHlovkH2dP+`Uz0DmGjHpvn}NiwH$v%5+Wmeb1pOrr}{WG3%s%qbCgr zQv%GQVXUL7ug_;bJj}=;d7(ey04@6|0(JZ||6dNssC&3EiIE{9TtQipCs|*@fG73Q z^XCuvPXs?^WZ@HH;mg!wr@dpc&-?tPL#)U%7^v@t7`Yt_WtWf@X0+CFud1yj=GtN* z>WBPWU;2Jo&<EEvkd{dk_3`Qw=ZopD`zh%-K8`JDjLv9|E~@K~CR9xDFj9s+`}uhO z3(wW7q9bcDcE_!r%RQ(M0NfTjM-Hdn?p<jy)!RXS$N%h^vk4A2opg27^%K5w%c$a3 z7&^tUE7p6XiUqYqFEY{}wr&W@cp&?sJRaSBx7G9@?nG*bAA9>t&uU(mj%O+B4Q(2$ z9HH72_b#~ivNDipJK)eQPEe_F9}yDVzrW|c6n<3-;FK-rjo3q$w`m&bzZ?JV|88En zx#d`mO|w5^6xFe#O?>Q6&sumiUTl?hh?ou+j9j={ZemqHJnfM33CETUFFIP9;#+<h z8!-=Noo?SE*-krNd0YkZf-{be$P6?u)naJe^6ciZ{ab>n_KAt@j&6OxB^2`Ip|Wxd z_X)vZttcF+dzjDY>oDu21(@u+py}k4-s=>L`x=h|6+Rz7Kk`9M9Ew|~A2l~KAWNQJ zU4Q%}a&T_tkRX5c#G<B#zJhu3p8RUq!%${^|2~~8q01&HJ`~oTNSFEjIK#l;{h(0z z)yMg7<DH?H;r@iC(~fN_XUq4MbCuQA*O{(6*6fxgo--?{uMB?UZb%I;>(R6uM@jpQ zW#BsU673=&%x-O6{pgQRpcq8AOISs8YVFC*UNvFHPt<?Qj|(@L6oe(x8}9&l(BF`H zxBq#q()R6#j^$Da>DGlQUF3Q8Y&W_Nay+sqCY&^nLJ?NNLhV4yamOEfubybCu*+{> z_CYhQbmeb!;$P0)tWQ&Fv1RcED@`e6tg`h`*xtLdohn;DgM^WJ@5^^d+c3^Pv1a!9 ztsccQ^1D?Zh12_`3^MdGM1d-JE_z-5LA^p}7j<}egkxcabG*^(-jWe(vpd=<N7HzM zqx%&GeJ>B{3+S<l5@<6s;fK@Dt<g|?Rjsn`V3nM;H5)7WPqEl7Azfk?H@E2U>rqc{ zf06!<n)*)N14@)~VBh(l-47(6NW)HyJirO*ik!SKSDn+$&=onXM?=N>c1nFWL^Oho zZXXBAt6IfMVa9QcZrfHy7AEwrt=CFz-6TdwpY@(dNPn+(K~dqLP!EMgL1?(ub8epG zM~^$Gk6kr2Z5BzBy04&sEmS{TAuP~OU$(qWK!>WfmQPPW2b+w7Lg(zSr4GhzX}=@_ zHs?L1w3PA>(D);))+oGUQ+fSid|O|&dsq9O^LCxv;b&An>?9X={b!DAtFZ_*)!pGD zk>~2dk}|(9#5~v*GBxq+k-pFOvF+z+^T~IRtG%JQd4*Lkqn|z{@nSF(2FgwKmVJwq z#=@R#(+<@aXq)yDDZ746|3t;riZEufzL^5YqU-9>6_LkJ69Lcl)gK0C_HL;?zBUII z-1k?XvYz!`&M|L2STJa7_d|7~bM5||-m+8I64{+Iq_^H^9NntA^ORg8Bk{WnIt$5a zzT+pVZ~U33+qhPsu&rWFfM`c^Klp$4q5ofP>HjM~eqkOXMbr4?uD5!)THQ#?P15TD z>G^Dz+y6HH)LHadYIav!vub_t8UNu$l3&d-<|LbR3%istO55c5ubIovY-1Sy6sp&J zvdGP`s8nsU`LUaL%@(R{XHSi{nUM=(1BxZav?hpkI~!_fPJXujc3g}8b;)UAS>siK z@LhwUHyVZ2j+bI&y~ESnm-N=oyYyp<vPt`osoZn^@wPMlyj1GH6p6u{jg#g7d(xD% aNq0BY>d3Kiu^%M(M?p?iHuJ2>?f(PED<SCs literal 73834 zcmY(q1yCHm^9Ops;qLD4PH}g)!r|`j6n8Ifr4-i!#ogU0R@~j)_0fKR|2OYt=H}); z+3aPLY_i$xMk*^xA;RIo0RR9*8EJ7<000~W0DuL<Kz$(h9`+R<U$BnSS}p(p5#`?x znCmY-<_{3sRYpMqdJ6&>6$LRDVHNlfk^s4ixVc(7I0H(5jY)q%2(BNHxS5NIvz4Q( zm4iJ19hQ{*1Bd&Ii#a%cakjFsbOn?nkMVw>NdHi0Go!zxB(7F=W&qB6WY~`y*uOPu z4(6^NM$TpcJ;(RI<naHPTe+Cn8hwyD0~)*P;yz%Qzp$o}v%QtQ1)vLmFZ=_8{;$28 zvxynt_C5Ic|H#A~?Ci|!T>*DvshuAf)L$}nD_2`HK*`xOH2{p5Q$}1w-E-;W6*3cZ zu;o5_f92i#-1nU4oW~-YaWR1q8wQU;G{BIQ8|d*-!i@}9^l&UzRzHfx9K${5^|R)! zHUtD83K|K%=;h-}`nNx;fByWbZ|QjDR}#1l12I6M|F6tk&)}D%rvI<#lNibrs!~x= z6;VeCaDV$i{U8mepo^s`zzs+Yjg5_;v|uB4oO!%G*;rXw1rQBYnyjs?0$ac1pS3h~ zZJ+7=ZR(#`n}iM*9hIX_w+N9O85wz)28ixR*xTC^eV?W*@bV<-UB*Au*O&h&_bD=2 z@YNF&EK~DR_WDH0beI%qu-@_ixWiUmU0rXQ8-Z~?F3PPbbB2cgZGl`G$B%#Y`fB8P zO$Dt*2c`8F>_h-DnVX|nn2Tm4LCCmseF!%rmWWmg52uWRk`r3KqFXX+{U0ep)rVAB zur)*1fub6l!b7U13lJ$Eos0y-`e;=9b3M_lkKrHFf0X($tt{dEpFr{-wdm*&3?K6C z?=m4E%!;N?=nauX|7-XkyuoA|-{1F903YZfWWTA(&`41#BUaL15D@*3|8?Z>7K7F& z`<1w1H1?s70W}Wj|3|*as3jpHLSSl^)cLJ7{{O=jGpSH+vr7ca1^e%ybbZkG_1*Za zgi5q@dHnxayU1^{OzI6`MVSBN3I+4gRczFx{(r*!l||nnver3=wi0M<4ON0i!yHO? zPuoGQr4_%236_F6xs%Z80zZ7dyK_&VdY8XH5>!({KtmtIz;}G#Jdnv>0w0|-HvU%p z#P2XfHz%Tj)vWk$K>u=n3w7eJV;*sKA*EK`*%eu2o;G;)*E|rv&wm!`eESY>X2hm? z%d|C;rN`aw+p5@V=-P|th6_}LbA}Zc=s?iYCw)NuRVC<4RGOd_Pq`L+4C!ksUMQNC z{XE%m)#j7TcicTO1o;E#W6Hb|Dz(H(4h9J(SQ0ZzVwZj`dcG?b-@o#AZT#(u-}?d~ zoH87^JlQmHtD34Z5ndF6gF|0yGwE12n4g9QOhcnoc^Un5Tbr^d)Y-2B3K(`alKjWC zp-YUWtnn5#K(f@vRfNao!22r|Rm>|~QpXb<x};B($NO&s7Oz8<9qL_?q-^NVMyQW6 zzl&@6clUA|(|t5l1Ci!UaGtvjaavJJU|K>P*6^bFn5vbru^r>{>FA(jM+2f{foFJ; zzp2h873@hdgsugWQDKf5X-S{c@+zwWbZxl$7MIx6XXysC#-;K1Foo50VR#yUbm{nk zJ;}-rJ5e4K4ytGpKDIAE)6L22MdVnjh9~k*L{U=iPhuQTsHk_Ph%h?ME=i0Q+)L`I z_oNik4v}AopJ^IhzP?)hAhH>zW7r{yo?zNx&_byB&;cAnR@PTRktvLLYceu!Pv=jc z!XvYY#=gdE>}>^k18ahUgHdsDBbCARIs^qBsh_nHI&2(Yd3EI#P!A6xuHsQ9cIR}| z`%><8z{)B)2+{@-yNCMIx<<!Dm9+6f7QfLnwc}>LSKd2Lk-@d^HkTkHiGNW?11r-- z%AhE9qPc<>wecbnhZTvasS%Nog{1(~WO=<FX7L~okPt4dWI<*m)sLvIm9o;s%2Sjd zXmml!J45Zti!Y#|3FGC1l^}|ZXmAm>2N9S8PcV3BOYZK)+<fRfDyCNmF3|Ipx3FXG zVhCtpW~FEH5)MtnY51geq$os10_2m@BH~TtE_Rp6ogQQHGm_Yc_9>N<u4Dx=hdS<t z5TZge>vE%n3n&<g%-)O+<mDtn8_|sk^i;m3BPL_!G0rB<4x@fCx-7_oRI2N^)v2K| zHDmjqCimTJ^))|8cjn7gG~wg-iW?9sDk@6L%8DxJ5qdrNDEiO^0>E=oz^{@jpEG|} zm%>^d9$s8s1%1mUB{*N%EZ3>?v37f`2ylx8%q@I17j}W4R7S3A$QwOm8ECtOwdbXP zC`9GvIkjO}GC@+2!Br0h7PK*KmUW|V5-7tY+~dkW*aF8^YI6{pb0NybbJ&PW8}GMU zk>3JQd&7+f$`uv_Ja9T*54rJ(z!;9KlPMlHj%p%tUb@2{+#mKI9<D1L_15uge1r&y z1aVq_Jpv>`CzG-BdOWd<5Z=H<swtJJyf#<b&RMo*a?^$H@Yy^G<jcWHqud7ORERf( z-tV(nJP+hOJ*h>0phA^>MrS>#{mtsvxBsw{l(68t1SUXPuN<~Iup&av;&I0R!r{ar z*?y1Jk=20b{^_^T=*{`X?d1K%9krT~88+l+C!&2UA2ibx6lE^c)Q^pq3JQd*gLe=> zGv7bJ^7?iJohTIaM^*xA83|l<0vI(G6N7?>6{ZdTS+z77-!&9i^ziCfsHUX!TgX>3 zF#68on|xSmDwepUlvo_X#y}c#J{!NT4dFAVy%-$GETQRk75iZ{Jip3#Lbp7V9lFdy zX|T}%q4#I7`2o#OpmVU(R(Li<`S~V+G+^|YqGL-p<TZd3lB)w3C3LL^`MfQ15#K(K ziWcnKKr!p(>3cWzj8ZP`JD8zNZK(|tqW*Dbug<wrV7m!`7fsZt(})hrpOrX4MW36` z8pd4+4rCxNC9X@P8apvCn9V5esm^PPn^2|8kJUTyOF~4E^{2dt(N;0~rYkezNRPUw zJ%0GT;2YE)Qtp9bl<2~+gy(U^Z^x7XQ-fqkbH6M9&B}EqsR#oCJl|W^_saLcPTvcN zF}vVNtnEmM^|oMAHKg3!DvY0*)Qy#4D{-peT4Ra-PAR!hBv&&t38%-=>PkuzqFp!7 zQ4QWjamb#frImH{)k2;E{k;$art!D;_fl#u>=<y6^E|ZTuNo>eNlDI@Ur0$wS^msR zH3dUp&q!?EXhO{Ch*dkE@t0F+KW+mN-k;Ym9v?7a;3mM~dYr7E8bLMl#sEXTflp#o z-JuZWY7cw)q%6(IAhk^b@qnWhV+33_<WgEp;V-z#Daeg(Calg+Mzi~ffbur7lBCS) zyXgDsqhvm1wa_)PBPMytY6BSU#8pSv9p#f|K|qzfyUEfdZbSsL@WkVnhhrhh?GZu? z^?^QgM_J*|mK=SB{g!onF}Pwyq%?s6#x>*`{+C>-*%bRFm68TdJj$ryHc3ML>6lOl zku1HLA`T|^<0Pu{UO8-u0jnf2dOyS0ta)o|U?K<iO%59IRgynLDV)vxW@<y$vUMl@ zuqBS+KpdV;bY$QbO4(u2wd}f?ndyEO&57=vo@WHmI!cJ}%-^0W9CO{>oAQgpZLdC^ zMw2BReCs+=nYt>WEH7%n8W<RGB*~G0*i2EHv4=3O>d<vUcLwKNiRte#9x@@Q@_Wc; z@kt??ZJy%(w9Ut`Z1IJ-%2ZJE@^o@o2pJSy)cuDUPQ=@<%Y)rLkF60d!{=(1j!xn# zv>E5qJI>Ki^Erfu2<_~f*Ms|HE4K~mC}iVIjtlN1!Pjx&4r(MM;vnBoXRFZVvbF8$ zf~LGd#?gTo1~?T|`*>HdZ+Ale0|%uxn<r?1FJ`ny708B9*lL@^awAb6dlhQ0<1~Lp z7n*<+5r^3~M*|)#@}eK2cImKth)+OjduUND)!2?al1u`2oOL@^Ne5OQB^53-rC(ha zmpaOcudV^N@vRpFh^C4A$iaV2u6e8~S#Ss=b8EP7qF}JNZGAUJLpQB5rRqJs<A}p& zX9Oi}&Z+czN1-G-I_Wrg&S%0)aZh^wN~sf+5A-6@ch`4!?&&(9u2cYFeb1Zm^2Z8N zDZ9yKqMTGtM>Zo3OlV=?X2c7A$7_VnyOGY!W<_)H_%5oeEfZS`d_R+k!R0{u6(}KO z(wza7769ra$ok4WSRtmOL8+V`-ch64NAx|ma-YDLW=Jo?0NkyK)*QhL+50v)aN1Zk zTyzM{XVdwPKM#Vy(Q`-Hwq>W^PE3Mz#NMG>^F!%{#RWg{q5erh5q~BXK4(Ds{f>9u zc8i$_!9IE9gCT_UEv)OonPdPQ9@;;q-HX)p9gU_bQ_rgEhY%V$maYhNY43^%@%91Z zJ9Gf27t4ShTZlF^2$nka)w=5_dqo)!4V;|Nv>F5H!#=8{G)#el>>ld_iY6S;LQ53w z(|Y}0(beObUn+wFz0%@rNxyzYK$x7I?L#b3ay#`Q4fLYKaE1*5?{=s$cXM}hir*D^ zVy+lO-(G;yu1eJl=4Lkd9!C0!I7r!rf%xVer&>EsSd;C>+&}2IIgz-SJ*ILZZ09NZ z#aecFH+kKS1;B>w1blkx$Q8$A9WR95JokVSr9jqs@J{8ut5_{Iztj+5xVs~kL>zgX zBsh3M9E<Xhhw?dKjK1umTWFwX@tkNP?hR(WyakdrwDbfA#6%q8Pt1kRI)xh{SdF&a zaF|<>JX=wL$aX&SaMZchYu1Xx(Mr_6qeQi-?+U4m5-2Cs7Dp;{CSpYuC=Kot6rhuS zce!4D^CD0}uE6?y9hb#tC}2IjwGuj;*#AG{K9~p!q{O2Wf0O-mV7b!aju>jHTy)l2 z+-xprfDo!3lmYVKUhpEVPlT>Mm>0vUPo7!~D*~Q5zq~X7o()EV-K_dr9~%AriCv22 z`(H}cSRJ-Bajx#NFS;#iH_pBVbSxR~=&y${zwa}rw-_=aF?<hiMi1Mp?TiVQa%2rT z3uirGKHp50n|tL4L3t#>bW!y9y&^x{5E~fwJ}H3s9&KK3*WVEx6nLWsf&yz{T)3k@ z|LDb)f4L#|`Q(PGSdkrvdXCg{v}%r$f=PZjEAMkLC&XfLNJXG4h^-dp8`8b5C@Jkq zI`Xw~`?_(hyN@_+bESbZU9Q2m){!}ieU#*Gz8Bg55xyg<nurzk(9)?hmNIy)r$h$c z$$Carp74eVN@+2)d=}2K$KL2g$G`iRO^0$S8VNm8*W2&4?)a3(oZRN-s9IDPN2WFW zX1vhF-GlMh+gC9K#vO>2P}@Mue`ouL`JUC|C1DbNVB0-ZLNl@YI66Nnh8#%G36y3N zigb9pfm(Z*p#V{Eid0~{TWgYH{xFlC?_(#4m$G0MY(R9m%3+WdJz4Bs==7p=XV3{d z9ZfTNuG!`G+CZBoo5`ik8y3CJnUIspn6f&dd_GzA1v`AZ-}rI|Rb%W-8s*w``YMHj zoeKFSlWz=3PgoQLN85^%ktr^&yZAfBcWc28xW)rPF2Luy!_O<n0ezGwTKAx{y_dSX z&|u4nVBZ>)rrGC9{dqAmqQgCaet)4_XXw&7Xt17sNQOq(K?Ny_@Yd0JoXvTKEt6t- zRQ0+kBtNQLyzhvx=hyD2bas@egBC7t@QGoS9cJVCqZ(9+?6{PJ6KsK#eie5ev0oNz zJoaQrel-lY6OKnrJCCEru0{TeKJllCj6B-!;9CyAAM_<xLq9o?{TLW!mHT^L{kWEX zEM0dnOem<H#G4-tcX!3`me>)w7<0Y1(|9kph~S#)z1ZF4o%p_2>qIEbWOkM&W}y@w z_tc6QlfNWDxqALpUIBC?uHTlQjTo>qrmvotXMw^8W5SsATm0^fqIT{#9W`*LPP-g4 zypQcSmo})=0B`lfBjLMkw)%DEVpUB=*jZO0aJiqE3=y!IrBQOwv+e5NZw2V1N5R+2 z_<mKAq>b({F_R2xXslPFuYUZ<(h(M{+_}s5kFIr|(iAz;QO#kDCMct!+nr$kJuz*b z;vd%0Q|Q>_1cCei-eS7Eu5x5dvR}Z#NhpJNXKn~PK(JOO;CGBTu}a~;dcq`#H@=Eo zZ>BCk$_Gd+vjpF`edqJ2gJ-MVX<;_=r~T6mPitD8{-1@}`FU15_fW#XfcR-vmL{1k z!it4G?tVlBB~F?oRfKBGrBleE%em7#Z8Y?crg|TuIJ4-DzKad`-mVq4ir;|zDdXj3 z6+4$CY3a2Zbc5Q|Gc$%5qjmUpN4MwpHqUPa5Qmb6jW-_y0-_2b(c4H-t0y5zbjwEv z3jetSyncX1&-aEaGwcSXnX%DQ7^C)~J+%VCtrJKf3e~BC#VI!KFb^9dDcPiTT#Q_8 zp*1S>zam=1Y+4_OmoHhfHAM|I*WtEUeKRJ_{{Bm8v~WLnH&Q}0qR_Ne92h7pEl6#a z_#|^+apPl5`q1{4PPF;@yU^5M@HM6^I>g)a-eD$7>Jv#cMay-PiL};|Gf<b10_~J@ zswEP*#FeveGXf`WSq-o*1ZOKvZ++Vb1J%VgaB)?&`4OTjD#CcU`jF<aztZ%5Mg`<H z=Rdh<zGB%RpMG-fHut8d=V+{R47k3Tmw!qYM}q7GgQ9<jcktnW_Q*!9vg|BmhdbmA zb49iK<DexQe&~@<Bt#_#t;L}L`=12>Uo~_tst^5B_DWe-HD+v#Kz)`Yw}An_^bqp^ z?Q&{KIkacR7Gu5+ZNpN^%!%~sntpOo8*Vv2-0`7>Q#3z+)7S^Rc3><>L4$MWKtf3k zk}VM}Aw4s6$sKHG3n>|MC%>c#$a7d)VtXhop#fJjVm&pb8hw(9#!=6e&p{0v897Yz z(>@fWNFpU{C_N;m<<9oV54+fZi&AP@ux3ZY%pk61#u-(U6rY?JdE^f6<O+)g?n&qd zxzggP-u(GA9=&ACgDbD83b4!hc}PxC+}WB)y9Kg9FT}EJDD3`re8C7U5<#^yxm>l* zeJ1er5s+G1N-IAk00WC8scg6bKP3RJX+JTMnKCG^gd7Mw`bkdKMDe3@ZcB_2^-D)b zRdvJO9NJ5Ls#0J?fSVN0gn~E3`}6VVh>`?hN>qMy!>MczZy$<4_3<QgbV1r;O+Qp+ zjWI~qXoDj0UmOQ*0W10C#X@_2<r+?41zK9ng_P03<u|UWF&`ehLrw^WT%3_C$p-_S z$jXka5T{yAqwx&Jg(fG|A_ZN@I6R`CZAvDS-eOfVl+eCcSPN(0V;ehl5#;2QK<NuP zKal}nJVzu}Ev>A{l&Qp&Oz6gte)Y9Ij#k;8`PgzFhrAT2f=;r-9XhijLZgd~Zc}|1 zY7BXce({A@8G6`i^CGkRX-6~K>=`XiYk^vJskV;1auTBBUGE7rUO2EvQ^yBizCdpz zYCwFegVKQ3Fx(0uuJY;kVaVjfhqe#Tm!b@>st00WyBp2yRV=i8ftbshmXiE|a@2sJ zyTS&sUGy4)>5^*r7I*D5Q3jwZ#2H4~uQFU=iFxp2!eZ2o*nJ*To}7cIR=&^$jIOK@ zuvS;=R=NKUfQ-v7F0rXCYsI%CBm}0*Ii9Zxq_1=!3dza2Qc}OumBod1*<^%6m%|oJ zQQG>|%PBF0=I|i4LU#rtTbxTOLQ4}Lexd5h)2N%gaC|^LIHtUPW|Vt%m3kr@n?oEw z<k9VV9IXbbAbCc@mPAGbN6cQ9>bCOKy&ckAJBr3g!GttF?(ke(wZI?dt&QmoeRu}F znqesMa#pazCvZrst8f~y8@HVu;jaWdwqM${Z`{l_FMftjB3DpRP>NmjkAwV2AucD} zn+o@XBrQqy4p%&#F`vW{FIX48LU;sqkxPgz!rhlqJCd_Nm@RfRxymC$wmIwSwG$d4 z?mD(P!ml~?55-LnW)jDdx63IYC6Z6QA=xj5k$oB^ZoMOtvTl#@S&I&Hq$l9B3PB*6 zRN06oUydbdhF6}o*q-PRi`c)<8#|_v^y5Q@MkX3a2=-<@K8|DEb_G~ymBoGPpIfCW zA??4k@u{|m!?bP*Rh9`YL1=^ReIRni;|yf#7h@W<fMj5IuKe(LHhq6M$Q%5v<BDnq zN6t2_WI5;N?d=UZJj~@0%)-CP!m4ui^)<4vdH!yEUqav9%7ifbe)HZNLAkF?br7un zU>hJo%0@yG;8Oe3AFQgN`HS*&69<_DQD`bb$q?)A)A!3wi&_+P%>aGg<yar4(b4@o zHOw8ctmlnZifsn}W?;Zo-SYJ{$@aA7O`5`;KLuxSTW9%8c;l1{zq-bI_0IWP8%EQK zPS7hgVeZd7_9s8266g9-%%|f7O_-g*o{M4!7WZx~R}4+jZ_gKQLS6z(Y;Z)$3G7wv z&bhO8YJxSVTGKw0Z<2cBuc_s4ZuEb>^KTmg{o8=D#vP(^2((G%^#BktJWvCy8Hvx4 zynx6WoU(rcn#H7*QueB?+Ig7w0UKr#<2-V7|5v^+0+NrHH|Bx$VL%fXVbRmR;WsAH z_s#|wXwYLQIU_ZC)&%QDsm(^gc_>$M?^Pz4sA^OK#yNu8O!D(!1e>1Y;0l7hJ`%Sx zU+Qzr6&^49rm<Z_*O6ddDs}H4Duf&Po+al6y_L8HB$D6m<f$if!L0@WA6N=ts5ohU z4itDs9oryc(HmywpNf0|tTgwf98ro;)yYWyxai5~eV2W-hWXrv(y!6fUQAdFgoXm= z_0L&UU0HOzTv$cG8q4X);y?x_D0&KD0~S^%DO5B7%j!5*mRa6^`@Q?2Ua}<ZUX<+N zbY3JkL3{s<myi4u+qen?QbKv(Jcoyk;PYm}!Prn>*sn(^K-sh-b=X(khzCzN&=+NF zOp%PNh@~nPbt!7$WKDpA2oYEf!wm&>J~cTuT1`6@Ke&R-p)yvQaMJg%un5Q5eku`J zYRnx=7sn}=2(>L`g^{0M6+$SoXM=<JR5fJTT54g&%qS9E5=^!eNlEurG55qUc0+yF zJA)6upXKoIB|&f=idCg61+WnZ72v44bK`BPkrp3f!fhLM*s@VEwu%GFf^>;#nVHcm zR8ULcX6BScsRfmX@|rv0oV%mrsFr(%q9x&WFa%u=wq}7VS2dGF`2xRqXoDdt_RTi& z517VCfB*MPQYnIv8Zi1x@8}C0eFJfzlsFx~{aF`lqp>(%dEbajEX}#H*wVM~<<?^3 z=~;;dw`t4@*&gZ<s0TfsXcOw2O`mh3wl+j3pKUYo<UeFWOAzx+y1_|}$UZ)dj!#3J z4+Fa-3wH!u6#|h5H5j_<ZW#JJDl7|~*u^(KD7apbqg0iFx$Vq8ubEEUTV~wQ`*{`B z;7HhUn+@U6ZS5<DK8FbQI1jlpjKX!}Jmm&X0F}>#G_iI4OIqt<%x!3PZmdo9+x!f# z!6;}r0RaId6nlR}`YOXK-?$hS%_G{Ls7#*>y35b!w(Y$*G1y42&VKaQ=zVhfy^L;w zT+!>6jQ}pbWf9wZ1YHgS=iwO2?iq=m+%A{LP%Pn$2G9Cap<}5e|I+V@y28*C0>sg4 z4P$7*%9Xz>11oE#f)RT4e}^|oH4saASY!a*JkcEJb-G6Cw7od7n$^6BN~4{1`&`TW za9YxI;IhFa`I9h1>ci>^mO=-7hDqMbUp&Qff9J*`50C9j6O%N2Or@t$AYG19-KcRx z@_R87P_)Yotc3Ot>+UV?o}NbiH8{UHm=Jt<2~A%0UPqqBU)M;3U5KPv?fwE2gC~ea z9v0gZ8~kZ1UdE(@ZKL)TS{_t|m8LP#<Ix+ok$*2VnB}5@lDbD`y-wisu>Q{c_A)00 zYA`?^-@!5K+>Pw{?1#s8b~12c6f7;!*)^GKu-#{-Gz6by)UFB-THWPTE&}$t&w$4e zUqN;dUP20bI-qc!vr<iJgmmN~6daxpl&grbxc4a|5Z)2SW;=;`_`!mWa|4O=B#$^@ z))9z9m^(ATd`C%;CbH5fqX)pCmKVChdsx3T8zH-VxO0TK3}O3}FOE>Hy-}AN?SiY7 z_>D6wx9XaO(1K5#wpJ+nKGSp08y2l8J**Rtg;<ah`#Q6w!<#9)V)j1uh}f>ReY50a z0I!{*)D&ISf}(EkZTbCaJ4}sX2{?Yy(SW}UJJc*r-81uohak|4vTGFLg3b7$@u6j{ z6Prifge$DjmCJc0!7WE#$~gAXKU!+s2|A;8crn%U@I2R7ltz}J!!LX&9`t(e2>G1G zxd?v9BI2p8ItqJ??Tz#0?x%u*Ria=O-^H6KcJt9gs}${5o9r{KTuuZilS*0mqTP7d zZpQK`9j$a1+Z+f`W9OFA1_cH4NLyOke%QyXAdHQt)%duU1xtZ8U!M(I!!AV6&g9(h zMLri~z6{(P$vQQAhriOGi40&czmB70Zgp*Zx)=`XEg@4@v|n;i;*fo^$0|*N1QRd) z<@bIfIVxpfPcWADwI@ANZex=m<cNe?SBC@4AXY1IwobJ!<75v&&)Q57MFU?>^ahJ% z%Nrh(1B0=k*SDo&VEBgR3nO>6+2I7U_Hf^6GRo>}`oO!n6(@F?_I}Pdrsa(#^Y-Sr zCJ5{QJo@PZW;AqT&FzKz1ipOX3%Z06sx&*#*X*#4a84=0-170@`6#1@xc6HN+ZA7Q zEwKBIHaE1jFBTLGzU-ut?t@v8=O#}Xqb1VvVG%b9cKn}_X8S`+8u$ZH-yis}>{~_j z;a)ae9I@7XEI2YVUkn@Vd8sO!;AB4Ik|B@vKs&^SB@}+56MNZc@PJx-x))(_RS4wX zfGR?INBFJ?%H!w72$b4OXo(B^;g5GT=5DlNLGCy_gkHbd!J@+o?*C-UL`GK2ZL`J> zk!s)V$UB;%*k}0fIn}EP#v2$<=grfYF3Ys(cdj<v<VkmwjP72aTVI5erV-b3|9sM| zSwgyVU1x<1lT+$-?tMFSX==DX1*QQk-0R-QE5rbICTc!ohr~U=Jkl@OWgAL%rPw2# z90WdvT{anHN<yOYAji!^RLkGyRCVavYmmm>=kOP*iyxIW`!i`n=c)$=zRwoe3kZ;% zcEt$}^^-}vr4%oF?%;GNN4;6!PxD@9$9<0#jia@CAKjnmo?9W{+UXE*&_WMj=VaTO z7NMY^%KNVSJO51D8q(U@KJ4-b9}Si7R$9<nsaypK3(8!<OX}QQu?u=4m%1Cq*4<@& z`qL|@?a{$u<LkQ*{JMNr<mud$?o;e~V)R$=to&dIw3QVioAyNPRIwcoNc44oZ2VX} z((zZO#FZ6PZ*StTm;2=fe`<t^hG$me9kPNVP15rf1fPpdZqVY2L`E$;o6m}2=NsS4 zptleSFCF0;e%NMy<aZU7Ntn9S+=CJ8w%dK!3;5p<N8bahmeaWo<kFi$NL_z(_&oH> zH!XORj`zb_Wu39;K0vO$`Jlo{^F5d2gfdGy2!AocRQ?RB(8h@6_d?sCj|@JN<mC27 z!XU5%KAXH2*PS>mfAR&kN}CrgxR_AfMN1&fjtG)g+O1B~3B<ynq1d~#o7PRwB$84L zp$dT>u%w++gCt!ym}f+6lI;i6!q05n^Xy>!tmR#2ikaw~l<;L97xPeyrl|p|cZ~o} z0AA?gS}s>6PB<!<{%0avGvH+(5>(B^bkXh+_wSMaILlHUruirOWo%lN;}b^=p#Z^5 zqk)KhEgaj_brkBB7)5Fh<8S<9|ICQX?P9}iL?sSanJk@v$I-;$)f9w{O?P+8*sl^| z@?$Qa^A$P3EMk(-<$vk*>S<~sMIAH~hqhk~NiQ58zZ=JvznK=!HQJMMFr1WPdF{z1 z$ItZ}%?F8i9-n$#PVF0PTq_Co@Hw;xe>P{;y?CyK)bv`5DQCc0ZwkDlE|(~ws}T9I zs}b{Z?Qe1rF_q43&M^>|hZmWU?fdn5{ycZ&j6^b4H|VC^2k3wk-1+(_5QEPbcES#~ zEfqK5K_0dhT}_XQg@QPbXma@{4th#iS)q#>S<51A^Hph|l#U9Uh90_SoMn6T+{ok@ zHtDm;g@J=##QA{VSJ;-C0mNtUZ7N1dYgwYR3Zm!)HROE3N|cN|vWWchYU_)^1)pwg z8kw%b=4_KoKW`fPs3u`AJ3}8*bt@6>yIVd`)f7SE5*y6{+9w`he8v)NNnw}IB89xR zJE~rxD{U4y$5Tt!>z2&QN;|3zRosBV+wV@3V@zU8IMvN+7p^e>D_W@6ZGo5{O~BX& zuz0K#k#8r_$I%_V@k&D7#pgZ&R@V)rL)1hyFZ=B534bRR9ilv2#Y2;NX?bZ%A<6Hm zrCuo81MBw8-qqbTudEE>lu+-tK+@AF0K}2x-I9ileNi^KTj;fx$0Ts{gq|Si^t%WA z4tUUnQx29&t(`V<WW5mori@KEPIz6=osg<2voRvAg#2fxsd)HcVy2nG>SSIR7V>3% zN5AlxWQ}TH$=PK)sFHYo{WFlwnvu(7=X-YV2z#Wi4pYb>F3PUu{7$|Nm<G-yPI<rd zZ-#*P3}#l-8}nq8g+w#6fb1;TFGjQ$MxuUb<(htxDnch>c7A_+yS&b~7h&Q?roc7Q zVf_erP`TXKSakV;*<%7BVYYB0xG1KkqAI!*TA5F>GaD_&2$J%G0U5f4h7#IF{W(fi zyNT-%UA!BBKjZ<0!!Z4am+xI;^<gNVHHE(=!Mo|xvDq;sIQ_=on+>Ypq6^tAl;&v# z=C8j4ug!n=-XZcC`Z_aHAwRKeWVwdbv=Nn*0fk1Ovn=imm&Yz29{dISCg{%&%E*>~ z%1xnd0G1(is<xh0Jg-kxSezraf{t-NVi-PxV!Xft`uE|Rz%p9G4@idnNl|+CYnp9- zcU#z?3g**rOo@EeE(ITM$3|>Af2AcjIXO)bpf3cki*hby(2SeT4=VSQsW6_Cbc zRSq)veiYckJ<K{WF+sqh8j&oJTR93ROA60EP#*Ul_08K3R$bi*o+rA8(8;Qo=>fVR zZ_0-`EKWBf`9@ZKT|3O<T@WWMs}%T?Zm1)ahK(-{!uwYa7bE6`jpQqvA>um{l?Qo( zk2Tnup9?`7L~VV5Mrxe=>npeK1=3Pf?Pm3rOaNxwb*)hMR`7)IDFim@S6VS6ytYQg zE+NTEVM#i@%oeD2)}r*+sb_A#DL9Q|bK|9>?;B=NCiB?uUx)F>h1Vhi=D28He{DW{ zyg8J2o&-W6qi3#qgF%)8N$_=GZTq(#G>MJ+qU44+1j6Ah5GFO0A?oTN4r9}=53{Rw zLg>?$wzMihf5T}$qD0#F@Y2PiqL40L5tVX-boQhgXO-UB_;2(bRcV?I_h0?j4T{1e zs6aQa9`AbC-bKNlv6ake=DE8G9PqA(Xv_`{AqxwRSe%Dy6bA(m1)cSr*yRT6lU?Jo zJ_){&4ea$HtCT1Qk`po&&Ydgn%|M)56hBj}x3_r@7XL@Tg{<Z9&|bkV?EExR+EN(A zFrAC;Vs_N;ASly^?Xl$hi#;iW&5O-wmbF?K^7kj?u|-dOaMjrHt>2f24}>KXl~fx^ z;Wy~lmj(`sB90Vb<<8)yxlj*h`KV2%-vJ7V^bK)uDCa&Lv0WpS2X^Vfq~{%xyHd8K zWn+OeJ<J!I^R3DffN0SQ?jD5ew@Z(5-fal=qTZWg<jXZ|p`O{fxGvSRR}5I$8s^{U zNT~?#_#K%INaol|M#p_|7n}Frl`)8+uPL`#+&3vN;8l%UHcVblXCk>hj^N5;?FSPb z1pEElFQGKDuZ5{;O(v+{BT<tyx^G54>*`;VhxxO>Nh&6kuq+2x`@a&)>$JhoX)<kG ztT?cEUNCq*Qd!lGvcv!9>4yRdK`TIXM~bQmG2B8V1_7WUDO$dchODi{4ir(%&d%kv z)u2gGQtEooxI!Klw5!cb$0ujTJoJh8^$n7<Q9*60sK7+Wh+B#S)9m;|=on(Y2TBRG z`s~6b!kWJ7M`Nhr<R0SKA|k-Rt6Q=U9WRCGyWo_5?@UQ?mt0dT|13=!O*Mc}-MAlg z7#$VO<5_U})OL>D{;B@<HZyvrcO^5ptk~`olZCoITH?)}$@tDWtH(5k?Sd;D53822 z3@YA_N|XJk?IER!eG+xNbLiF|axDALGU@DYToZa#5>kq&PjJ(yUgi*YXRV>BZK{?d zE-L2kaK~wcqUJtG96L{(tiQP1-Rb!SwkLH|qq1m_SJt?ZYpE3mGHG3$u4CyvANvm& zCxmYf6&Bich{t)BOmnxml~zE_1W;JHlj<0`6OU94idhlOe3iLOjL1LRGM|U#QbHju zk?VSPcWYTJrtd-RZ#0SdwNsjjQ8_cMPAAEjz`~Sx@%7NR46XFrS5pSPI$WaI3CD$6 zq(SBdG1;T#ozl4N=pv(uo#FJ`ZMKCaps)rgXsrhUBjZQ^+_xlFk1GlW-8u*n{Yzym z{$dWq|5G`yxuS4gm7S-vcOP-WA3t<8T;QNw!Il=9xI<7Ln)i=KwPY+CT=>{>W<*xI z=dfbu<{T*iTc$=}7Sj_GMMaLeWTywRX0|b{K#r$fbITIU$JOAWq?2ulyZa)t!Dnsl zJW{T^NTy%=w53Qj4E8I+g5zF-T@_N@5&E6TrRaJXPgcj`_iFKMrIcqA^)|XA;lF+{ z{W_uE-Sk>AbEE-Idt=Jw+}@3UU(t>-)>HgtkmeCdg~A9nA{(fhmuL*m&>U}SCX%6a zZGh>5MaGJ~uin*-+DQD_iPY-TDVJHookIqVdZvV4yu?cN3U8Qh)fb}2))0UmQe!87 zC&0H5dE|(mZZ?ZLI#uFGO?7A$+a6KenPIiDktA)Isn{$n1x!N7LWSZ~@yNH+)>+`_ zMfc1Fld+K|yOqm}(YMg-{(cGrBQI?(pXJ;STmzxRfEn!5w~4D_20Egu3h^}C+s9i8 zDA31~xId_?hU9rVFh$!6*wXK9V7}lrdn8`jx_&g9y<fV%B)%PVgomfBtv@l&l@BWb z0Rg@tNpvu`x5qL&AC8(p2}Udh&VL5X@PXxrM2(MfbQCVHWlvmPiQhf_>f`Uv6e<E4 zSeY>-ZJ(-7k9)zFl-MPw5K1EOqqbyHB)A94&Y*>f2&O5wK%D;R`S-!SGx8m>H61t= zM%9(&-klVHK2~?860-d5Tj-6K4H?;nsUd)Ux@gK3i@X{7#!trWUg{zQGVl4E5t7bJ z$SQ{T$7Q<c(tOYg^YU_|3Le2&f1-fRcNzbFzu)LI1<WNK)BEaSH@M6HVo^Vy2MG;V z+rA_PqhuT;YP)c2BH*rA@+<nEpkT9$lN9-jXe3OKQ5+yU`b*M0^LVUwJy3m{(33hA zhc>V#v?9B$_*Egn`lWV)D%eg{7LF`04+RAWhS|e|8(q4FEVymz_Lzl|WmDR()531N zLNjgaFj5p;8v`l>7Fb6~k(0#apO`ujDA7s(wE=bfQM~ZXVDRh2Q2uDnf%(DIYsu4g zLP-H{yFC1fU^2}OBw((~Pr@H7{?3hyYtJ0_>G6py1z?E_rnfX`dG<5#HTtc<f9Bc) zox7+Omt7i{NME0&)dgAu7&PPS(?xwR^%}AmBwv~OH|UY|l@u(xM?_7RKprN58wBc# z1Vq*bL+B3mPTZd9**jhr!yiaWl4Sv4zB1>LsDX6H`p=Xb@j`1RnCzZ_M?DD#LG6@E zrEeP-exqvMQqb7j>Yvqu6KmLZ5_zeLi^viKlCnF6R`~fhwvON|z-1KO-5tqDHY|<7 zz1d)v*IOWwue?jz1@?c^QRGO>&*ul%=t2wLSO}pY%9~u!P_&N)+|)qK`KFQD=}c$U z7rX-(7rIhci21;EV|U&ry`|3!E3=73#l)KZ_7rpGLvQ$~r=d@+g4DsyXG3KfHJtUn z)T~cU5B33$-4fNAAic~2B%k6rWUmtGjZS+%P))E@aqR1<)bxm>2$*Cbq*LuEO=cfj z04#YIrm5X{^H|$(z_AF)*q;>wMR8X^9V=%jB^aIyo8|O|Iq&E7p)LT`j>D0A9o67M z;`S+26hfUk*N%srD$=;Iy?7is8>!i3P5F>TLxHW7Y8d?DVE($DRE3hMqasDHBi0uj zH4nmiVU=U_P%y+m$RqpXMy}h|gfj?q{7Ju0U0xVFhbP={Itta*Lsa)n6N}$k(_9gG z{a4!yhc!y&xPk)&LfN!`3px{2(6@SgY?u0(JI=5_r}3)}C2_Izn0lw_%|P;gO!H*{ zCdSkuv(Y4Grys%BA2Msa1Eh^YS~_XcC%N%>tERGFkEf@)8>l%k^@fL65bChlU}g|D z-BeTvGCzlgI#tV<b$1gyU_3mNr*+{G%Gdh(5JkKxh>OGya9~10IopqXM8GmxQ9@E# zyX8SR(Yq~EQaWML;FZW75B-Uj&Ucx=Z9Pgi+unsN4`kK8(Vy~`Iwwzw(%}HLZaDaN z<_DC|`c9l-LogI!GZ(5x$!D{*wKKrO|4P}aGNMIVqwS9}`SReYC-`g7J;5Rv1Fmr5 zXJM+-@uW4zQatLJi=|Mo_Ro6HgnhXB2rHPjNb#jk@8<(|SPI>ASRTc~XB|=h_it=Z zYMb#c`AUryX|rNK>62bgW`-uq=IrJz<It<UM{a5WbIgcQsz1CHid^yqj`Y>;EZ~ac zi=KH{BoC_>`=JRu4C0)YUla7)E8z_VxJoisb)Y`1!nfUk6sJl8gHvV^QT9+8*jb=% z*LhDQ`r^ZrIiaUB>yiyGO8jE%$rx7pBPVG?rqbCrpdF^2Ba(ekpg(%gRV(R-wQzhS zX{k$JgAY_j8A^l!N-J7QS_&eAmnO%2CY!}*B%{dx{=z6Jr-gq4k>MCl6Ot^lDI;kp z^D9|+arJ9e3Dru+JTR@#y$()%5`_fa?E*DrE-EI7YX#9R#731`+nZu+Y2d~hfHgxb zhXH!7kVsVmlzX@EgRHG(jORo?;vy;`4Zp5x1}#X^KEccm4O`?LQP~P5M=N+N=LEql zz7;;0nqg59PYmXvhgQiQ3R_7E?41n{6p%xLoXD_yxpp??4WS=S85i2<@$uVqxJQ$! zN>Smli#DTO>PxUjz+jO-P3#*cXtBew<5wkS?n|le9VLCiksWD5SpuUC<To;bXVPWp z>I;Shc~_$dosIPKC*i3_z!v;zFj<_C_h}$U79t$&1zYA-Z9tIyIIBL^x}VZiU^x{X z+#?tm&CUH_eG;`l7qW(~F2Pu(!M<+G7gM2(*dP(Ck8A3OgLN13^G4F2MV#tN6g4Dl zqpJi_1WNxnA<f84F4#Z{)Ee+n7GoKvUleX4WLP4g<q!pLmy3KE0X(k|WjHUC6OAZl zF6^G-Hhg`m&~$rcXuoWN+sKp$XDg~TK8>gcEL0AK3XmHK@{`q%Cb>I&mu9$IG**)R z-oXwWxwF~)QYi$7Xz&;zy}%nuK@MZE7C5{rPbH+-kSh}Vlb*2CZ|UYMAy0~=;yz?h zn*U^TP`S5@_(6ztvOK83l2dz&hlfX`O&5NbyR~K9#LeTBgw)`$9EPJgPt8;?_E)9< zK$qLT!yznYhOf^3VR0`D%eCQD#7o}zUeUZ@xeOEx86pkfbk{`P;uQxr?O4WC4rngJ zZ|XDcZDp%-?ES2Vz;`#_7FLG7${%HYWC_g2f;HwJt=cd~P5nU^pe6FjdYX>q+7LG} zLqhtVse9wLdEsy+AfQ|^`P03yqDjX?1$UDWbT1OtR<adtEKbU1rVJ}p`9xRzcQ?yY zs{N(ZuSu7BlfqDi^7!lhXS5%uZPEH_5T(3Qcx^6eT2SyF);5*`QG8s?;I>s7LZa-Z zY}ZIqKsv~S!A9(3dHUbrl&ezIj|6nQ3A?kZ3dmjdw}1odVU<xt?-un!O0Y<=)%CGd zzFv9{ub-loz^qIz&?|UjBM}S_c-_0Z&T^UbuYu#3a`h}VVSIwXGjgs43=TE4rb?u{ zwG!FU@o)&N!d#UO9Bns0n0}#xN^)6&I~SI+Am_3l@AgQebNtgzWbxz3ajuytZ57|} z+gjwrPxo@l<+wpNQN<$$v-`wIu(_n*BeU1XlJu-f>E&syyj5CSmS*SBQF^NBUE*VC zhKz%h7KGQ=mkndvF~;X<p_#b)%}NIcC>4Y%{d$u7KCDxD0nAVA%7I}`cs}id$P+2R zD$)7?Oc_8~96&>$-q4Od#HKX;J8MZ1Ryh{9z;aC$bvb%Fnjll==pgTmv8|wHSUj)b z7Hm~TlX~npHJl?w9b$$)Y>QW)av8+|=7oy>6s-3#nNLe8ipTY_(}pmUhW8XV6Q(Ay zHBUY}@@H9GASWTHo)Ul1_^%_O>q!D0zJmEj`@qeX__fL(3CW&=qt6r+6pl`s_nWeG z5*Ul-F3((P#0o`nQ{6Ym{eUR2Ir@~M?nZ)q82&H2*OSv@VtQi8)@4hMd$vS^%UWUl z-vE!@yP47P;Hi>~q2;BJ%lG?+(?7J;-C;<M&%zqTSfT7l9MwrlSSZ9x<WL8gMh7-r zc4;(+CKFZTDnFSSUNoQq)#YHA-FkO4z|3*y@>-;TG>}6`OufqBpe!@~kR|M`q>6sW zv0V`=v^<_l*s|E2En!1y;O!64=tp7^*qmBZ<xr0JJixWd1=^m9s%iA5XUEP6%mf@X z7)K<*^+Qkk39(+6vTtyEC|7KW;mDMDPNP%5?z{yD*XeXnPR;}!_~8S<V+D1XJuLSi z__Xmrub&KcH!eG~SSnzJozMnpseXDQ5p8jRg>qmJwyZ_54h70GiC7V0o&FwpfOrH6 zcUkn!`RF1Z0<zo6RgTqtwGlfqlcG>15mD4U3_qh6{Zj1prly;sNOEqjgWI-YwbA72 zSj~<r9K2?=*CC4aY|IO{P2;HFy7~hCr9j_BY0qS<!B)OqJ2cat)%2DS)Wi$%oX1N7 z{V(1vPQhI^DGg7zHEg4b#ooxgg#&pe8XdB%q=W_s2PY>lFX&n4d{4n%<V1e%tyAl8 zM}m}z6;+ejU@!5K&UM)9+lRDuqdU@+mX*gr4nFjm`P!S}J2;DQ^AB7*e=cExGP&{5 zQ>x36lXXZOHxXyl=$~mR56Vxw+7GZmQgtM`nNkC!v^%D)A<6V-JLF9Dki(zBnHp0> zyQH+u@yTSr=yuR$n5vhe<TvL*=qE5%!P$s7>SKo#*k&lJD+1)#{(OBX&{&AKvmZV! zIiK6@KEfhlEyUFN3N8%_;QQFysUcE>OKI`&@N-p5x#uxwqLbtsb39~a;cjkj9N%8P z6ciOX!!wV9o?py|Wu9*@9;;ZmB*k1gAQ(Oly$S6Q4*VzbJR8(I3;i_O0$rcfmjv5G zT`G^&H{YLNS_^KAb5=fB;}sG@=u<Ig9Fe86S5=q_oEtB*uO)opmK(g0zDo}*ygF4v zd_LJsI{Y3??!+HMCO}kmVBD4R`SUwR>(|5n2&kr+hS-RRjVptxWJHMIwQqjymJB*N z-h5*Sh#$Jv^}o!wV>hg?op|Yv$sgHwAG7yg9O%b!@Xt*DU$)!dRs4TGj=wox|JD7M z2=`xB-QP&Ze<vi4VRbmqKR>Myk>TYdI7}9o0+<0zq;B`_i7M?*JiRFjJmkUVrQhn8 z;YVPQh4k01Z7~Kl;R+R-W6=T)TGGAiF7${T<)b&O_)h;ycZ&GS0#{_w1Ptd=>17R{ z3<_l^)Xsg6GU9*#_b=lND&iwtPdZN_zLZ3m9952l0-{!$E?kspJ8^s%Lw1OAsrx%K zg`MbI(evn##S0NQE<bOV9E|7WZ_M~8;0`-ch;hbGVPFCX3UiSvEo%5}NyOkISip=X z#TlFqNbo>b;{Y!j6Kgn}*AHqtCyTk&iw9}L$v7};QmslUj-<&viHO3K>gr%ag2BPA zh67N>^B72OH%Bz3n~yi|sFzKF8)x%B`1B`MO&}MQM3+T!$*jdDPa!}rGfJR3Q`}TW zy`VyyII@=5*=90==Xu7So(gId9hq26wF6Q+;T%aiwSyxvO6A4gdV0q1R3pi<6e~*K zkb)k-r(<R9R-czs=d_s8R++<}+oYCbRh{4a3i$h9-F*N*$Z}ygdHh(M70B!uMLb+s z&v5z3io*l2vj5KX9gD@^B*oiSaI83lF1AP%g~C!8SU5>_d90rq){`rLzDC91^c7;~ zRurPrs*pwuSC9gP1IpUrBBw}U;NV0gt<d}6cyKqoC)E?eOR5Zk;gaN)4ft^2U_US; zn|u#x?y?&tY+bpHr)4L*_t6dGa|<bOb4gv_DQ0h_C*e`IPU1}7b8TQ`Mnxa=1Q>9I z@TpV|hen4*oqYK`?Jy(aB1AM~1U!Lsz&5U(!Eh38ZX8%1iIVd3pqvUkqlvUCzjFm( zXb33>FGRha-bRwk&(Mk?d6?~^Ed6PKU?r*+?eNf$yokIm(N8%x6r!|{BP2n(#1%)^ z`_Cc8RAgk6*z-td{q0*!L!Jslad$!8{bE(pDWZ(KN$wOI)V5M0UI;<KK`1HO5%#4B zf0}8fhleED0)u*fvK5FAk}_6eiB5C%OlVVtSs!PqF3EPugzZJ?78GFSaevB6MvtmX z<b{D%cjGYcde|V%Y_<yPI-sGLd={Oc-Pnj^N}EEwpBZ&p;tYRb3N9~3@@qui3_-`W z#ndh_`!5^yBN=w?92_+3OeyLu0#vlq4ctARH||d^O|LP9U6G@dW?2iRH9+o-D{D0Q zlei1=-ed|4LlSR2GI<_gT<G+NcR%Y0$hncEnT++k|Gv;-&g|~679j>TQL=ZN$FKuc z<i`gt)|nAlZ=+#!e(P<SJVfd+68^TxxKL+8?C!7-mh=Q>X{#8X|CRQoCRCWXehsD@ z8)j-IF)BaW+$7GAz)Rbt+T@6XVc9B{szymHi1E&TE$Y?V-RQ07{BmXyMVc<($#nPA zgX54VgH8uHz55YqX;`?R7JXg?v+-MAD5%pOR-?Q%W-<amV88=u()lg?F?!zUcA!6< z#{<#ct4NrFDeP_Hl)J$norxzT|Fa~Da+g?~GStN}%Dy|ihLv#%1$aa<*(~+r#zLyX zLao10gY7E#_b!U2^_5WAe96t?X83CRT`z{rTXZfWR!RFf3?8KUYO`yslhs=2?{S$T zASd*nTNPCo%jXx{L5raJGirtvC;aAm(PXJ_MgvtwIP89SslT+o=6ju$?9r28-2^Bd zk(VP6+}VAKSDBIF{e^;7h*LN<!QF9-ceVRdb1kYLaEuF(D<oa_h5g7rq9?0vdZ&gc z*Tkx#X^UvpL9z8h^77lwc@N=)b*#A;arzF|4lG(xe2;kCZ=d`ya;DY-?-IR1g4a3> zplXP4B)i_7-|O9(VuC2bF{aD{wmRN`=f+=sCzSM?8naTurTC<0l1-bcV=3$NWkITc z!ugjg9-LonZC8C!p1H=mq5Z!jEC+Zu9b1RT(+N}VIn8lee?62y-tsATe07H5fuGDI zh*&OGP*wnxQSBkkF_5_}c4F6>Gl#2)6D5BHlI^#e{H`Y{@ouh7%x<^*df$7fhK)L( zyLqI#>jeL)92|AiAsBuDw<JO^no+WwCR#qMEQv7cOK4NI6{EW?C?>zi&yqs7zZnA3 zm}Y4N<;)dg4x`Fc^(J!EsLDdH<9izcG!kLYPvS7c$rynMMy7zp!?K}DncmzA&G@X8 z5Ef#ara>yh-wzH|hR5y%3ysJ#;qQp+M0XVRXx-aAA}e>})SYr0?pxqs^|qEdk|zqj z3($okiu6iLDxw=vF5@GdCCF_Nkj3&Ue<XQ-#Rt@?hc;xg=<>F}ilnqFN8uW_rv~h9 z!#C%p-Jrv^wD$i^&<XJ5X9fD;;?@?fJjIite#{<PRfrwp1v@ulnzQ}F-Wx2h_0$5T zNOlRXAC}aHnwZdMbVslj_LFLldqvQioQSF@zv?u*%HmvbSUES&4}qvw*hOhrmceh^ z#hXgPus^9hmsa~QTSb4JOtcu!x{abb)Il#R;ghfl;$Fha3^C9^S4P%V|FLVLY&f#c z6O~dR<OP0(aboNGW8<_^3~4XP?J<IP3vB1LiB2HGkKQTp^u){V)~J=H!GxPFSTuUZ zHJ}-OyPD7jC(@(2Y=xHFZ?!z{oHX|Mf2jJ#=t#Su+t{{k+cqcW#L2|A)6vA7Xky#O z#7-u*jfrjC&imc<t$TlVdiBbKb52$5+Iv^pdS}=+jbSVGT`uJng*^mj9t8vFMK)1s z;zDn~KnMwPZhSb&zDIsu5xNN^sI(V+qF?m3ZY6yMBXo<B{h+9+aA7e82`Mk(vj(E2 z?MQIN51gkBRvyoDCfyq~l(RjE?q!^_m3CtLz?ty4IB{oPuE>hDykon5K^N}*#b#87 zB$B5$&eowL5m4G7W`mF-L%23{5g&cZvD4KNK?)YiOUbrJS%wayz!UdT@SZWmzTe>V zPBn$dbg<x+OR%;3`?$&5hfv?~eV$%^_6|)VJ|Jb+HUOiT_wOG{W_CW<9{QJg&CS8l zYjQVlucl&)#A}ix*dk14Qst>cnwP?e&_4WW>#cxuXk-$a4gy$@OQZKcb=uy45t=nO zN9^`R^U9<F2||;GtUntv;0Xu`P&JgpUXoBUx9TyW41^s2G~qW4`A30&^Fpzf7(r?t zh&}KzvUY>U=dKPib!Ioahvf-)Kx3#R+}YoUk;XQ}Xc|{Rw}?Q8cHd1;04E@*-rfc> z5$Vds3;?)X?~S+~XA`wfW6Hj~PSE)$y4$XnOzx*T{kPTZ_Sq!U=9u7+pp~&dJqh&N zk(Me694*(_G95{RfdYR82crJEajHUFemx#vSdVx8yZ~#)l<X^!=n0}qK4;7eq)na{ z3+QMD2b1&6<W>`7L}__+f~|U#*NxlhOnlf9{?s~;bG=F)V^E(*8IJI0nk$ciWcE~} z^8+MmXlPGKN|NPkx|F{g5dcfA%B@=bl*Q`Wjz-+D%z7YO3{=ZLt$%POVtyExRA<4G z5q>DvOWtXW3l0%+l!wiWPt(v*v;nU4u062I$GyMriH@s!1$^&GZe)L7QMyt>DO)h* zoJ&j=9oZxSAd-vFH2Trn`pT2&Wjz7`EK0e1<R0!qy0TI45YM-d(V;JE2|Pp0fPiu5 zz|H*oAK4)hadLch4Y$OjoS@*ZY+5^>KMR%S)Jm#!0{3jA1KS5VD@aQddR~ySw!<AS z42igZ2Ymnb-6LLk4z5lQQqm93K1;ZCBWHwy1X&do8J6f}x!VJIGP48GXYG5dIes`) zAi-`i7>|Ll$ioJ-ATb+=%s{+MAx%u<z=z)|+XHde&(hg%r5vhe&p3N5S`Yr(kU#Ri z=Y>>uB3wvG*Ew9GYJ0x+p9~Q~{8%7a&_afOxZE4#@n0iW1Vfb&1A;9?yZV#A-ep%j z{-`W5h3J)unZ5|>@l^^QsgNUMU|RIO-H{S>83&h+fZ+Ty4E0baBd9hUnozTFym=yZ zR`h9WzZCX|C6$b!fo<x&_Iq`@nnoocvvb+5M~7RJP##Z5F>*@gr)K<YY-3+nu;0Gg zacRZJKt#s(TX#Z`j2=f^cZ?AgmuF>&J)3LVBgKKTD4-e)18f;*w!ljJo3q#x2?m+I z2$h~Ch%KZ;N1aNywWoO(=YOXRj$i7ZsKkh{F{-yfx7{r#&2PY@%#v~K1PC4lO-rt- zj|8n7G6P$<fP<X~n^Z(2^S!76GNGH3z%x8VU@(-g&U_Iv(=0Qx^+A4VsZuuB1Qjy8 z4r?&$gtEf3^adrxIC&)!qoD+|*UT)(2LG@k!MtgkhZhv1g|b&2m((kV{#~y0D9g-| zE_7FRfZ|w&I&jR~r9``s{R<GNU5%?O$4qO8uSTIFM5A97515)e%s#1!lPaQU`WLFl z08n4y&V?!Bx<pT9kD8Yj+;$0kaLH4Dp8nuSi?5K(NtfT6URxV3(pG-l$+J28EFn3< z7*$6OST5NI#4d@is<7t@SyLvpcPBgJ1`Z3|mGA5E-<QGMp|lb%gW*}nB+|GJkHK(^ z_7ZMXkN_ms0P`AJe||QSFEO=`!l5NVtbC-xC`gGhBo~y>61!7R_1ARa%Xx1B3te|W zvINNK4J0_u_f2tMf9%KY$x?L|;DQGmD_0>ekb^b72^tX9#0_Pj<hFlPA&H{I`{7MF zKy5U7`A^DJ4L>zHX=x*{_yz0A%77)s@{SXd0a;JL0)`wOOdIm6nQ6dzA7Bw<=jSA! zqg&5+DGtp2ft6af%aCt^vZF9$m@<X$!L1>X!2#8CbJqh2rv3Bqzn}dW8LL$78Hg2G zWRy=z{%~3k{rWSo^!utDU$Dhe(nV6xsG9vVDNp0TbpD_3ykXZvkx8P4%wQpEnmgjZ zD#!m@tT7{-tvrh=Z6%5<24f)A<Wrs^gKKLnEUZJ$fLIn=EX@r|)-`(*p}~b(ULG3( z?%TmMlM`JMSXkdtC0=hE2F=P~%${9RDraZiC-tA`CYj#EK~ky`60mA1(5@iCiY+h* z&&nhZtSXsY4HwO)@+Kt78a>?ml0X-UfyFUMlG<9-x;IG;=!gTvb4MJ0((G@{;D4AY z&7X7$iZ9&fON{|@{@-5tLyJq4c5>T@e-(KMU+F)OQIh)|fK~{yq7E(9^v{gKetdjf z-QWN4mh$rPDFC7w!6n1Jm>ZfpI-^a`oj#A+9fAdKZ*SZG4nixinR02FVuAl3sWwUP z{Ww<~I=yxt>PZ4)+un%ptaI1Mj~h&rskhb@i2@E7$RsgkUYt-WH~Nf^aG{p~9G;;E zq#Q-DuSnA$ITO7pH)SMI9~@1$M<f-lAZDF(DV17ywU&aCg<UIV0Jw%0>5yP>G6KTi z*`ltX`km|+C<JJIIvPYrOi80=Fr=?I27kgGXCD$O&$D%Q3O}jZI>h4>uE%_#agE-C zn#y$t5oug&VU%nDofaJS8GQZAeMApP-yF%9e^ysdwjS*TPuD6-NJyZBva@#PM~Y~B z;&@s83F{~{ocjPC))4IQ(CchYAu-<}#1hLBREk~=)GPeG+(}o4=QoL4>~(T&0Uh!6 z<KsxWH5^9w^7_hvu6(jPHo*pEl|Umf1>>C^6y?V)QxJJM5PA-dBp_tbCw7O4-SFUp zG#lS+=6HVsjzx%3YC}<^4mUMTpx12&3T_JT>GMj$NeRozxo~`P5|Z|3pj2J%n`?|p zsMzGdU8Fo{QR0Kum!pyAAN%>mMG{8F(1yi~wC{VXjO?wD<|IuDk(up6V7e#N=DsDG zh7GSNl@D4}xc`X3fM9<|l9!i=Y=kC6qOwM)GIUr8RHclC#ko^a(c`#ELKns4n92G0 zoh}$wOi4ZyO7}6^I$M2cL>aHDn%ea2Iz%8~N+;l7&m8gT2$dJhyUGG_34KC%oBz~A zioK2GH+QVc%JW<cOT?O5y~5;ip6RjDBw>G@EICSx(Gw5sSqvoR4&e4#v|-S(XBzA8 z+qSbuGK7cs{GHwx_f{Ci3JnSUnIFZHcINWFFYAei+nYfkKYm3zcK>+P6Vt>xcM7R3 zH))OeYYo)Y1{nwEHwh^zsGtB5v^qx&0ytgq5@GA{Bfy^+;*IELHvx{F9e$nFMNHis z9vefcTUx2!%!+h;H*e)@*Bc0(VzwO(LL@$%Zz76=$t19{!oVR)!l<~p-J{QOPPZhc zr{jf4O8_xc2-KMw7OLE4zcsExA0KfI<(}2Fe@&naFWV(4^xelMdUNbjMj{}5{Cp(T z%w%F&lxaY1oAGk~S?}qEl)4#&{U%p`=Lnen(9WLTPo4HO26jTT<fO*#`M^sc?qrr1 z0+O6u$0|2IHodeo{5%~%YegUTCwb2Axa-bPM-o!uVqNsG)5jKyV9o|on?pG@du@dq z_lQ|fR8^I%P?dIke0bmvBYz7W(m4L?j6tuv3^}6%H4~G*LicvyhuhyX@Wu-<FdgQK zuLplBq@CcSNDaIH{Mx@ggt)(d=zOiAlwp~KMB%mngs)XiGT0v+)ty-P(SMf?g4Luq zbIa#Fy!${Xj)95kyajs*XJ+!^w#e|(Syss~e7@#kw1Y9y*(zY4VjRGxss^XyeMsXY z%lLJ6UQ7-Ag@*wc3!5cOe#ql)lo1P3Gsgv2sDo)WA}o5O8DRI!QX!o0F=(}1;uMtC z?f8>0<8%B@^Y1)vom-ua=7)j;o*_G6Tg0jC@~2Gd{eJ_+QXu8zR}I=B^MPpJ263Zh zB#8BBetfc`a6$Zi+JVzC7n~M%jlqI$HI5!@r#T?`JM@zj_FiAnDGe=MkRFvqFa`P? zdt_Ikx`yWVOU(Bxr13qf*f$e6XgD1`1<f`2AEQ7gth<H_F{JvDt+;mh*B!c4-D)Po zLk6wCj3amLpqk&RpjdecTdN&{3I_&Wu?)YQyTEn4+S;Z&OoPJjsF<$aQ&Sf5SarDX z|GK4Arkd&y0z=a$hbPdsYpD&McLa~c^R5H3#;`4jLrKZr5ZI@x0jel<6z&4;jdp(K z=89ms3=Z6ZnE)Mt28V}teg<-?j{jJHyogAtwC4Ov2<~)S{48(!Ki8SUFaa_$me1QD zW6^zyRp>ZqQk`a?)|1Z^<)b3W!p0@;<HP?r+Y2QLyvT}=-)EYdT&?)=<>LuOo@8b- zxt=azB9r>sdh0LDVZZ>&EW?o<G4A+5S5c3qfr?to${_*Tmfe?6mUetv(6dEM!+ccV z{MgyIB%NAp?3V?)SR*$oLbO}<1ML`pjhs{{JHy~Z^*fjZ8V#pk>t~G?Y{b<{m7Sn3 zD24OQEG3qcQ~Fdzm#YY7xY_aG-bWef?xP5e2ACgRcw74)hI2-MHd&Y++5As67|LmZ zLppWmbj#b7H949*D`#&~bl8zCrFKIxnbG&e@Q{7~PTgv;^!xWiLU;;HSpRE&f8kK@ zK!&Q0_(>-9_wmF8wjOU$cx8*Hr=F=<G*F;HmoMakp+kFo!%iqXkLNZ>2|o2VlE0Hk zqKk_)cTJG-KIoT+Ls**TfcpxGsU6G|a5WcrCh^ztObK-cEzwQ2I2<K<Jpnf`YNf2O zl?_Xd8%$*x$tjlUS=)8N(uomK6-h!*h<b>racff4yiO|gNiF7IK0a6_Q<=TLLEDY@ z1Ld+27@v)6>ky@WaF>nC?`C7d$z-S}S_H`ca!2fHHhDVM?+<M#aoQb_%@inGc(y5q z87~Xgrt&LxN0+6vq>T<KiU6OrX@^;dB}Vq|W5W1xSWsB}8|19w*Hd!<FRe7SG|z_o zHdeU5Uh$(e_|^nrFpr0^({(q{PY&diS3Wx<syYb+$Dk9=hngA)GWH0wTqR>ooDrcB zL~rMkgoK86-YlWZRQLCf!)w9tG^^4>$VZQXoYKy*6>8BqjgR2{*7?m`XA`fRnq)ck z*jo*0xO1zrW%}GsxZLVY^|R}hh>B4-b{~q=!YV-qGhX(^I7(N)aW7DN<cNW69*jz> zyfxGZ)0s99_vW_*q?-p<?38{i{bQs^vzQE{k{GI)^Ep|!TxfI>>Gs&Xt`bIkVx1J3 zn&o(61aB*fteNu3LrE@$#<+5-QMj?gpTKS;yx`HTxZzf(Js!W?1@5$l69Q*%fXR{F z)A292aBFNasX$SZKZeb!q+t>ip3_)tylql!+p-7kF7hOW!H)o!C}`b#|K>`fs)g7j zO3ELyu0QUH=~2c=u(5YeB3F2J)FySx+Q-&e{%w753*mI*ba>eI7At<QwVUHpAbbYh zBw!;-4U&`1IC+T|8E8s4IXV#!bT`r;M4O%5fAgbD+Tss1CjJJHw5G?9gI%Gb6xKl2 zFOfl#p#!fozGho4ZY*d4IuS4jM}rV~d~=Rz6ll}y5H_^H#7L~)-_M4B7W|z3Q23=& zQdG3N%7{*Zbwiv1xZBz9wq|<TSO*@3xPg^evpE3)BS6F(45Wgc7S{de&(iX;oi2<! z(YNxbAw!jS)auZO$A?%XZ5;dpTCNlzNM2duj{LKPTXd@jfsoLSx$0g{1}Z?u1qw+q z0Qobm33*3SaUFy);YtPb2*7*!2|Z-jEK#5yaX99Sq1A#?OBOEz^_(3Gg@K8cTb(Qo z2qEaVk@S~CAS=jEFi?jEg=8y(Sg3n>`k2ep_Fu%+iLo;?gv3ZBQr|Bkp<{!i<vloF z?9Biy{fx{9<7o28t7gGeVRag*xd6x&h)LU#n#itLL2_=Zgp&X?h<%{RH$Skj`{_u~ z-Se87lGWtp;dR&eNRq7L13ZMKVm2dMkwAH&dB2fLnaWb-lar(7sD!%*>RA+>N@!T2 zman!?>t%-?A8VVXa*7qth)iooh8$Z`%(lZ75vZ%SWUG=&np$CLY3f;nu0lX$k8nmk zWtB3GO54d(r_(#5U}6R*tvkC$(CS^Qq+5r15&MQvV(TfdOb5m~D=GL~%AegZP_`BU z!oi9q;0(m^kd!>Jg9CWNoWUyCZhp(rirE?CExE(~E;`0|?7*X)ADy044cuS094N*t z=<LX9w1CCqdp@ol6}42xkW2TBM?*n%ohKz1N?)(h-q&mv5fl0q0XgC<6rLasWtyXd zQ@+YSqplNOz6zyoUP8u43*NTEJHlKB9(M{o?@S?LVM^(I8#z787^HkvgXme})^2J9 z@!9H}g?aj~tA>Ncz-E-qhlVN&n7M=0%8ifffSk$W39Ky7L%5KWbFc$jU-yl@=ZJt` z9t;AVe=dce4BI~#QN;2v$mfiqH+^jg{?2)E>_VF)#0OUjVXnAOfehQX{Q_;re94e9 zIUEIn@fj7V1mT-wyy_pgG)h|rjVVQIhQ>0Pzsh^M$Y8!640ouTVujuKgSC7~9NPWy z`q{gd6E{fJfnixVan;&}TJRHLcxi8FdrnEpWP?_E9>zQGpWJZvWp_`UJeTokWf>0p znV_%G4?zV20w?Qx0$)yZp3Qe71}3jUaVSo&e{G?8Kr1w>z}=kS)E61S1G@ctaLp2k z&Uz*Z-R$1Kb>ghvZ=TU4ZrYwBD9?n>rGp2pjkXw4Oxj`R@Wn>+sX2S^%-DOeS%gfN z1|bmzQt>Xxz3vq_uBhAU^86^L&UkY}(S2!`UHw<2hPx$%EeTsvCu9`^gE>-ruR0aA zHzjRPho{DcF<~Z;RXE{hZnewY$POQ`0ozqdL%W5N80qEU*L%>0CM_Pg9>^4Y<Jd93 z;e>cWb7EGa@3IZ<<i4ZYd%~zmBM&ZL@4>*t4E4=5(_AEpm8s`;(xCAN5JbcY;YTFw znVZbLK;k_A16w|H%OyRb>mqz0KXd6IwHfa_SeRomS+?}$HplrH`wZ$q7S-#(Jdo^_ zv)BE(Cwz5XN^FGo8*13Ef#oIRlErivB3i$d5L$C;D0RzDOs^mu+%h>6dJ8^^#r=U5 z1LlPU`~4I>{sovSZZf{roni=aQALTQgqqeO)vx+5{cr=8`bItZ=dX?9lPvE-`6<v} zJTCvNB)#XB=<|ex?3dXt9@r2Qn!)qhHGU}K2_66$XfBE%K_-(%=}d)+_>5Xy#pzGe zA=%F`5F0#DhVf{mq!)t0<EidY9bfQ)Ak8QJv|wbZi7<yyuvs`_2E1oPcU_7gW^D2W zU+7K00F2lb>ioJQq?yT*>w_HO9;gaik<6&7g0121fL4$cmBCWxh@ooO&%n>ejhR+U z;xM3xz`716+GXrow1P2lI~xPb#n#rqF|K@_@rHG!ZWCOEX7#{Wa)r|X1=>cs0Y*FF zHVD1!eAG~_{L@R66OR>kO!0-i`T(El^HZ<3ClkVM7u9;^2iC{!<<@Sq0~Q{gn$t~* zsOMgHm{FW0iZx#Ow(qvj+tfB?xMfNn?+F(b0&(cO=C$SdiI`+N_M$&0&MgxZx?@#; zkr(+@!21$}-h%?=RJ?O5K}J+}fB>Su23vT#7|@Z;(Uwy_1aKD@tLmZP<3Qo=je%O5 z>}W4?l2S3{+FLpG32n-)`^yG2@-k~+S&3@5UW-k)W0bdGf_3k7N85)V%S4v2`jdko znCeVS+nBJN?b3K{;PGk*f2+Uf5B~iQ_SFHk+IIR@h~>N6lk0#p1eS-$yas54o8ivf zzm5c1oDR+lq^?hEhH6O7`0Fl6cm9&y7~z<qm|TQ;&XxkE4Wc<{<U!ePXUlmy8UA`F zqahlGC8dyht&eq+v+RSSG$wJk+gM(<@}#(li;v}%PzkJWy{)386{VpKX7|ut-7?ev zdDeclaiO%k)3h70QU6V_ur)~P+ue`DYm>p6y-BU>-7rZpw?@-h5f}CavQJr_B@m<= zAgTvJ>8-J#HGD&CG}1A7c|_;wDMx4r<OMu~`6vb{t8YZdHcP2vVHZTy1eNomRdoFh zLO0L=6yptBAPsr&>raaxJ=1FJ2hd(zydoJY2!^#+3)m8K!w6?1E>4!8Cihy6lOSYx z!)avd$OWrTp+8yQnS?Z3_l(!~wSFE=;c)#R(yY;oEs{?)`Ik8OWHrM^(25>3X>bf; z!(5M{-`a8S^M~D*H9Bj3=j<3l$pf1p{axt8<<8p7wNcbz(I|S$7Fo!{o;8R`aoCW` zRsu`O2E!(%?WY4!?R@#i+cWb8G=NYD+auG@acKtBe$#+Q=n?(xU$7$0aar#Hq~Y#( zjOMWlxSt<@WeI7^mlYv3pASR_@4=rFDojA0hh9Ugh#Bi+>T^4b)X?-KN%raDR0T)C z6K5zIH)7O=iL6~0Af$-TpcxSH*sY65&+Wm(%h$g)N5o(JC#qY4Kcv-CTH)1|r&^-P z`NwPkXKxAXn}cC*aeUZIcoalX$&S4NeBxj3y-VWgVa`X1B<{xif;u8f%7f!XP{EbO zC#PA7G>SR?dDsd@^y`&3`O@UXQxcJ)6twv79AJAMd;k{S^!)p)`_#E@?P>5B^(R$` zj+T~|-kxQGoifDkmyXFnGpCeF5_@-JClz|`jw{Iy`2WZrUtMJ&6Nw?pg}ELD=^K-! zgU!Kasi7`>O1N%q*U(WzT&_fT*gC%$D{iTEBnoj>#Lyz&u^mz9iUk<yET|?B6A7n| z3o{m@_AcVA6>h=W>&A=q_<Z3;`0z(W@MD|#2KD2IIE|(+C+zV0_zd-E-$R6H?LT)g z3T3CjE4DT;Cn<T>r&Gm|(#ihph~T;_bDTmrN(@z^N-m`SrG`7@wGygYYRQBpD+R&^ z1Y<jhT2%zrw~gyoqAiJK`QoTv)b+T*gpq|+oXR@r`0<K?`%u&CrKusK#WUVCP8TZk z$;?ol26Lm{uJMt|nt>QEau%x^XwQAUc=z7Zc@AF|7wVf1n0gc$>)6iN%aXr=(%!Jq z9?=7a!UQqDZx0b^Y^bnm+9LB);E-ym&RV29v}K1BAy;SZSp2V2d9c5o(8&!|vli5S z+6xt7xhDG<4}H%unRKEbkPPh|KN0A9y}HEVJ;ib6Pu^eUP^O7;d|2y!8sBzc4Vbib z7IL1{S#_Bdv<g%{x=p*gkGra%IH#a|RQi@%Jpw8mn+AS+hQw&(#|6o?B0$66kk{ga z)b)G=|8~F}Fud&bx|5`gK-zXz?dtNzlCZwy2^Ms`4PrAe8&$eZPl_JZYV=?hrHI34 z&Z!FH8IqMA%N)=y2cm#fw|$VNII`!~zc2w#M5?onm)p(vv!1yA;(I-j$YNBz$$wtf zUj!atrYpmAf|Z1{)L~zU-1+w(Ziq6Sq)fwRB==SZTq+o=1#7<OxELy@mJCXD3rYZS zGeSZ#Bg-ZW0Xx!WFp704huN_rS6|`Go-xXjg3!zdI#(*mel_N#ZAM(n)-%Bon0202 zRPR^~)n2OwWiCxm^{9C5u`12Lyu0MKT9GEn+leg#t_O&uo!7FUF$<O+eBi#25#r$T z?<JLu3dl;aDYY~<l-dtgRPRx{LXHD*bUO+NsM07kc<t8&^76r|94XTgYxqg;pF)W9 z;5YuXp_DxQE;wCVe%KqG$RMZh#4YF}Kz*g!UrvQg0cZoA1C~_*0&%S^F=(xn^dwFa z^3+xgi^JFf4<Fl^MPzNO#iv-1#nAA>SAg4eXZ-lmf`&J?+U6&k&xOWxA25*^aqMes z`HY0cXHcfT5U(jmDCwrQs~g0mn@lV5Fa2oh#b$M$_FO(lNYRKSrA(d9vWk|?`Sz2t z4TRAsVN311+e4LstGapb_$JD$R`hTN@wcDi)i8Ym_-|M55IEHCK+8|#DCXQh(xV5{ zXyg0GbXP;WPFve2og@U$*WYdH<S3VDUQ;`ui3j)}dX|=uCxx6w%7z`XOT|RTXK5k0 z?bGs)A^*Rv&rH*eTKgCo3e8K6sOkSZbqIA714Tp9_<ZEE_o$+ptVMD}aPNQ(7Ee{5 z^|rs;bXQ2)l{SRM@D{i0=^BhKnFFZ<y;m!BNBENiGgc>N<lztC9@>G#@JLSF2F4ue zgSnDrG$fx9X<RC<zqiBnCjoJ62i0DdLo<1?=HEdNSiE1get)TPS~d{LoRFIR9_c|( zvo0MOn?e1?0;iOS9@QA;Ko^fUWXO%;oqc#Wy>9833pvEf7DYxK0H?|K+Agc06Z?<! z4FR~dRKCLK*_8S+Et?_TZwLH1!(2}G>P3y1LfG6U@1)d?Q58<co2fvyIfX605SWiX zeB0p(6@XI%I~cMFL(ms>-jB|V?`$CF<I%8oQ0NzU-E<WD_2TeWKWz<qXW>VAHl22k zLD<Anr?Metm|Oo=|J$7Zc7^PZ1^p}jZk&Ku!>yh=g;O$u+h=6Qky5GJ8UHiB^Khx; z2Y1<e1lEU%I7g;J#5dpX3b>D$2xuKvU=aae3|-1_h=Ce=f>GBK+~_POi<-c!L6i!! zn?wF6e8h#HfdONYskb|A;k}IXwD=k5r~Y+b3r9#(XjpG~bI8#?2@pN5j3e;=ArdNU zxX6+xZTq}31LAM>U|4R9PaC&^s%5^T7GrRv<WqrTFyMdj?qN5H`N2ElvilRxqgZeH zk*_!2)JAL*3X~W{n}=zA-yR=XeheBAtae~VQ6miJg#8WkvW8DjWMn<xXt_T4>&D}D z!K0}_9KlR=A?6qg;};}Akp2w2Nzee}0Vdx|k37^~ma}*3H12rzSM)C~H$<=$Qy6kg z{ZWz0V0;V9eWfsk9A+REQFLlo)KnLL*q9JvAOY=-K9bSjk_MFJRd|DR)SrK@9iFZ- zi0fRhmC}R*gi5?z%uO#=^{*JQ^4>0xeDALLBs}QztQC8A{`Fr^N}JYx9MhiZ@ep15 za$$w(x#X#;?*cW-+vA8x$5co8fCKMs`nRJNoA?FUb2$;y0UZS5Ys5;IkmK{Qz6eS3 ztEI=TzLfrwTDwsU-<us00=LPZQYtY8zl3_GW6UivD{@I{m(y*7@*Moa_j=6+v{H8d z?u&Z*EQ4u>S`^d`pl`h$L2DoBi4gr&)sN0ZkdtLZNc9c*ygzb)!MP@Jh#dZaCEl%K z9x{b5`&@)H+&hn>-U;#mO~S)fJww{N?e31lwRtf4jCFf@ne({L`Fx~kMd>L=6be-O z;KJfssTz6Yi^>Zq@tSnsKKu8cCY|ekHx@N=GA*Kl9&$kb0iQFq3Yqg)PrDK~Cg3km z>?{%HzFsynDQ_wUq=6Re@z!P!wolazg}NA>x0eCMu{IttHaxjaoCR2AAT0p{uSXs& z_R|NMIW}9*ODAYl5Au6r87Cgo6l`2DsgPHLT7j1AM4d3S^geqa3|#V0AO1qweRXTj zc{<1=;u74DUjo%T#}U73ua%@bWHJaY9>J+}g;`r{p{hRn*DPnn?Z5<+BmZ>H4)~$b zVhA$I+;I%dm{J>~W`^2>3Ig$zIe8du4Y~dK``*93#CfEmH6TV-r1Is;c@=z^SXyz$ zYsHGojX$WXS3+`&zr(eu4;*wRM)D_|07VHITqeV^=mQp1y)&CcJE7<Mxa5*<^~6l) zYe6yi+$Kk~;uIS0;#4KP*H1JNt^>V{8BXg0Py$U*f}B<?9j<`04p<-NH1ewUj9?TU zE#6Ff1Avz!k;HxnGwMCb<TY9~eps#!6Zt`ea_U7C|59bb7Ol9F8`;I#dSF%InPTH6 zxZ4$n*!Yv>#7*BqMK#SueiRrzi7jo&?F9O|P{w0skc}^|gfkdS5Y!XCVbI5h`qfAq z1{u+;AEM*fNN8hlP=i<#HsoGP7bzNDJBd~qsWs!zQ$kg&wnIh!Z`<~^s3C=n$@x-G zzYPMjzk~5vZ8FqBWMMi@cQ`_RJXh`O4$>$(_JXQj%0J{;S~38x|Is@tRs@SZkeJ6E zVxQ6=4qsPE8{uk$&|2}Uh%=p46OrC;g-<|F_S3hee2<i&&~&t)T?b)5qgrY{4HA6I zQZnkhf~}o67qgH>sm|_*X_X_wMV1(W_voq1!f$(Z+b>4H`5v<VSMql)IBm8R(6JBy zE_g2f%shNNCD8J0=HN5G3`HGKyNt;W)g9^=+qUm;@IFw$99+nTJFBLaYhgCkc_rXt z&|#fLIj(cW#9-@nfx884G)@926Gv1~?L#z97kdTD)8(y8FdE6nT$!;5{>1zN$_l+l zze93PpgE$3|4_aMi;RRJ*sRBZ$7bqF`~fs8{HI#E;RQJwv;P5vdm>!>n!xva-ABPf z1v}$mT#pJJ8um%W8g}R`o6YnWjndmv{h3lnTlvP?LR`g=K-z34;Wk*?6}kirkW-(v zzoEw_n*QS|lNdPP5@+XM8X_ejMP?+ssV|=W5p)<O!^;T6E*Oj%m1+d*1>RBY5L!Ec z(D=)HU$R~Na-Oe}?<jT%i4~h*ylRIM#aZ^Y@hDXgAZakw@AhjZEVFsi)jdi3VVkcA zZPYX{<}1fC%;?Rc;w}V8>SNSE8Qn7rlK1x%!Mx5#g6i}&ZE?1h3s1@b(JS8h{eu`G zwbo0Fz$ECfM`z|x-wU5YKiYYwO6mh4^hoH;inyeOZe}l}(vc&)(EX1(Ha_?ot;rvN zqpn}7l-{rN>n>5B15GeZyuTsPRBJw(VA`T@RZCxq^iP#u-_+v!yxrW+{<UQOvZ$1K z^hH4l|94t+`g~s#Dl>LMsGV{rs)N@Kk$?8l5Zc8sH%CXY`j8L$v`R_*BXhhg)rM$e zH3aBlrG7kyb$UYLQ}|&9pqi?!KJnDs^ue%yd~Xyf@3r=2vFGfo2!RN)GE1$#XvZKx zwolcy2|SrG&rAJx(I7=ddNnWa5dN@IKAuxd5pcvyJQzYtkE$-YD)Qj0xSxB9W?o#f z`!kU7CgaLC5&D#^%Z7A3T14~KW#VZP<kSO-0kq93OM@54IHK_9GY-L<ojSND)fRXn zR}l8au6i>!qoyJ!FTpq$gn*D^Pl(TqIk_Qw`sdJ-NS|%yBOvCt;rM=K&x3W<3XP;_ zNX;A>8r(qc%%`r~Lxv1dmkas3E@6LyA0lt(pC#4N5oa<fBPYC0*>$+mIB<{zXCgV- z2*|=1V;qTnjhLz}j@St6j_mXC_FN0FqjG3LQdNrcEb9aV8zW-xMefBCIkT`C!muX3 z?0QE>@V1MBi5i!`igdGmNV@Wl_u$YC^{MV`n}+}J!2!#U7(BzE;<CNG1a!F>H=1v{ zYFY_`1iM;2k;&?p%@Rk&%!%Q;xk7caqZaX?FSGHa5$o$iNmUE_d4hEX!!iRcDXB?O z=0ej)&aR@XADd!-PSW?4NC1uS6>6$!Y9rU+9lb_NJbmUB2s-S;$HSJ4o`j)HZ>x-4 zQD`vXbHsho1(h_wCeL*NaUXB2i-xdL$bo06#t++3P?ge*I!g}edA0HFz(8~+2815i zjZ^@~|1d~)Preawwn06n5vdPl_UFe88{1|^PyRGg_`Fg|^SWc=OZFS7T?-ez^bMr% zMYN1)4_W!HwD&hfycQu=(p?uv)w;dOUhFqo6)k9Oy@!N7H6#Px8J$E#4dsLVMtGLb zgURbjR_kFxbYwn=?fZ_rLfRX6O7-tBw+eTo=eHFghmUY0k!hfPW9T6Uzs}>+-*&kk zok~;(Wdu^DmN&#{kJ{v;QbW5V`Yd1|dYo%rA2lW_YS{SBLyg7bnyymY3&i8sDTysz zV1JVuOgX88jWuKo7gl!%y8edX`gcq}wS#2Ook$&&lkboawa2ztsMa^{PTuFbXDco6 z8C(~E5%PR|7;GaUb~26~Arq$_#-G^}PsSezwwsqwL|(V{jL`!t8x?gHmqfO@wRjDO zjG+$6A@cPjU#|w}`;J^fW#p|dsbAigBEX}!5jH5FVlp~r$Kt4Tm@=CX88UT1KrpgE zxig=#u<W~zR-}(MGT3+IO~}k{BslW)jg;QC=d91-t1bBn*0bBxNY-<Qr9g;~=ds6D zy~PS>yS6*thz?Tk4|`qVT=wS0aK6hMIAX)HYY%60BDVe$YkD)bvD{`PX#X-KD$#ih zLBjL6K@OnAl+QaG?YkzXHXSOzU-r2oaj$wuCHA{P4@&omH*$l;@~5Ry=!)9&K~y0d z8(!F0q#3*KKWW>$Mt>$F=JUn*ei+mH`pcap`<o)F`R-WWuPd1X+E+ZM*E7y_M5fT_ z)hzjSqcg%VzPiQa>53U3a*OB@dm&-gkUp=5|6PjF46QESCE$bIXa;k)$g)gks0th? zA)6MeG`s;Xp869`rdpi76y(?-uH9}$jC8pXo8zw+vF1b>Utv}{b=}jIY~#4S4Qgw^ zhiDVmQBbcYw*5;7s9ovw21vdhj|-?J{PSouix_Em>zb-Zwk|>-+i|(T7mHYwT#+}J z%yC(ns$lMx>G6)g)(5A@wo}kFHoj#aHUo;(fVopwmislTnOOvx0a3LbP8?y%wG6UT z@J^QY<ib++ZmgTURv$k(d<)m#0jn*(n@-hyx?{d?p<GTN<jGg0Snm0CO}|7k(#GQ% z7^4HD!nn)-C7pH|(BPZa+KgizuRQ@f#7L}85hEjXVyXG~D)vG$wAB(;-w4((hYG|~ z!sVgYl`{{5#Miibd&sj1&|{WEFwFK-3fjW94W!X3H~N+5N)JKCcj`%f$;L=Q6-{ho zDkgVIQ)i!h?Mf@lBz+W#Y?&@Y?C3r}`bB4F!qZQ@U11CLHd8l?QP$nV!E=g_XK32a zFJ62c`(B9H*wJ>pZ+V(8IYcOVH5WGmSM&7-h6c%aNzoo!nDz=qdD<7)TsgH!_*tQx zU}0e%8+r%*EKt5v@78Po*D5IoN#V*PLrzFYsI99D{PpXL8&5ASExo+92INoe{?-!q zoB`aEP{||GpD-21Yh2j^%b%}9-nzF;=4$9cr@^U@5ruRHw{-GhD4~j;#bT4vtSJga zgI-|rVz}>e*rboiB?%r=xoN+DzemBh;RMI_j9}Z+I9xmfd#_dt^2M7DW&02z7`>y` zd4eyKy*W(FlgoP_j$%tNRPE?~d;bK<!h*W>St7TV0Tz3)vhTvBIXs$Fr0JP}EYh#e zZdG#`T?F=z3%Ug}PS46X;^e;k?rv&$F_91*`CXmk3e@_|gtW9B370}fl%j>e49R6^ z`xthI$3-8cDfMyAMufhWf{G-cxqdzTH;1iY8?4y<aq~czSNHxAMo`8qHyDq)z<&o- zX`Qy*_PA;N+*HVf`c+qdnsJBi`F69z;J?|X$Eb*7?b@rL^I8ae`)njw(!1;%o&eQC zBJOjVvkad%2|2FniTssvb>$dVHR?sM>VyP)Z}Qb+Fre+p$K739TWb>?9Ug}EDs(VU zv|vM@t0=ClWGE~t=?@pMn46vDne<!%tst(qgoCC}Ro3g?6z))V6UL<luT1sE%0qz6 zJLK^{MtRU@k^I(xu%WZb<GW3QM93|oAWP3pUqrhL^|R}i>l^f<Se~Y+9xiex{IKKx zw*T2mL)cswx)zG+G^m#iR`e9X(54@><JGq4*;)g(mTkezH;Z>!T@*{tlMhzu5da1n zI#j<YblqnmCz^ACv9}~K=s#J<nGQJeI0hL?%-U|}w-44==8pXG0?dE@SUj#*AWS|( z`8>}=Oej6Pl}CZ~?xg!;ToSq)BuASuomz|u8zL6mk$KZs2?rJt;`_H79go|Uzp<@D z>0t2Kjoi|clumrZ_2xD^eR3}`Lb*c02sNCh*IH7~x{;3<vW#2~1#HD{rWvaPk0uKC z34CfZj{hn;%+D+{B%na<X!6L!?wt5uL4d(~uIeP%Vvz#n0tmIMtE<~5Cy@j<1jR@B zIY26>bv_pTOQoBWlc=@z2|c*>`$eDaq&`l0li9nJ2k<vrxV5Fvh7@X#Q@;;QLY_<p z!LfC<=ua}nw_R<ahQ9HIM7vWKnh1G^%;sdZGf=O2`m)Z)`A#azA3EDwmCy>O9aIJ? z(9JQm%f%+nmMyH`+0d%{`K_y4+YRjm4qM*l-6@G)sL8<6oSdx7w<O$NLBu~!%@og7 zg|6BhTpzpIPXyO<m<6P(t6xpIT_`243g6?l7m**&(BUe=l7`$Qct^O}(WTfB(M4r& zP3(QahWBG&SWRHl2gb`M@Cr5gmg|^)T>Sj}-OhjohtaWWLJ%ED#csTM;AzY8d;MRd z9;`0<d7a6Qg2L}BMyhX{VYxS&;YDQnNZ3><mS57tFK0JwL~ZcYg*s<g^7tRc4Q5sr zz&h1iGIeZ6Z5d6rHB=E-`-^+}Wfuu@`UqVaI4V;GYo^~}9~oq54CMIS&w>K=%<s?Q zPyeG({Nkws?wNtL?}eDn5)05A5TKr0B7Gh8b+{ncF0=nfOZ^|>YNw@q3f>~qPHUM( zU_M!UW$ar-!~YAM)5B@&+B{BuZ+~U)`&_mA5<zAQbX>(2L7$!d8NI(xXczoa|9nBI zz$gsdbSgb)Fp|J3^<^b=BET!-sSZA${Y&5Mb-)QS*(J-u=_YMMKf(zt#5X|4vk^8q z@9(EAIrN4-lO<lkL*uFa14ppKF8T?@9|DrAmC97}8Y<vZsHnc~tTP=znUtGq2whSz zcinq5zWr-Sp)1U!N;0zgjKnTz`1!}vb}(-3R7G%W!1p+qu}vfhy)6K<5Ds|oGM-E! zn)&G0b4ePjf+q0WH8wkrXy?mqP<zwn2ChVG5N)6rN2|*L+@JTicm+O9Uz1&W^7eTJ zXE``LeEha=?}f}t;GiQI&VEic)AuTriLdB*sDTy0QC^flo-44((L%1ZB;xf4|5H;r z)GFJ7qBjp#rU0$t%c`De4za!x;k38dQ&0+OvI5?tTFQ@N><yzfJQ1kqEI5G1`k#8Z z8>}`H#t0Y3Grt}0_!vc)%MKj8^634F+K!sc4(D(i#K+IC6%ViP05dV8j+Kc}I5vDl z=EC@sXCyIkk_Zdy=V^&j|MO&))&*adOjhvOS<lo6Ao|_|C>F?#0+QINw+ln0ssJ*% z`giZ5Vy5+q<p8OIkTly<FU#-95~{rOc<r^9{cB%TXF;GlPuqE5IUSrf8Zg`CHlvmG zp}V~?;LR(90OjI>0m^7l;BsKJfit&Ynp(oxxUtK%uDll@AuDUT%>k0e5tC3adw<Ca zhXrY2vOhDLfjWk-t)q$z)<|gRu99l*pn~cR56_#I57rBj-q+V3fLaT5l|kJ(4mSX! z^J`~2R)R}S)Y^H`5%xO=p>I+MN>Z(}H{_L{>jCZo;9{G*#deEnqNXIBTf)YDyda$z zhv)V8XX$c<?d|PF5$ctc;rD@A8NPXOEA;jz+gQWL6%vx66s{m6=XEr-`+LU*s_7ns z_rW?i&0a4q28ztv<oCZsZtstL`_8^x5&}V27%olCD^kFL(<2j57Ne}E_cri5q;U%a z1EXhQ5Yi*U7shO5W!3oyWow7a1^42R0yDbNkA=HFeg<giIHG<#HE4?c+xYKG!$2YN ze=_6ZBVu~0$uY6k0&<0zXk{J!i8jcN_Kr5@;W^)k_R%iidIvi{K?OyHZ3k0u(sS`j zzuyLYJ*xfe9Qfaus$s~Ov04!9P;<6oGWl5k+vdQn_m8&&)(YTlKtz_6X=G(RR%DS& z_*{lnM3t3|1j1-0QrlPy06O0txhFL=LMt%S8hM47^{y<$+&RI%y}#v2lSJv(J7*h> zdh3G#M>Jx{73!^BjrNR?1pePEW<5<1K}FQ&=H`;}^An^%8)fznwA|WZ%SUIqZK$8^ z!;I=Q@g4;opIO0Fo$Zz+BL#B6fzQR#w4MlDhZ)ld6$UMQARY}SQO0bauTiJ)Um<#g z_6Q}&1!{O}cafeyJrRT$EN*5YP#>+NFiN5!tCE2iS38a2T7V7bY@ZN6g_!8toG-)B znNyj{zXagB4qbH_D@41%qhLF)L*V$2m=6Gs8hwvH*zOV4)YsoYCp}eZO=N2|@eT!% zS0Dil;XH^hGLmNux5FC}_3WZ+@8*@2LwI>%meNd!X*zN0rdubZ{*KL0M}m<Ab8VT= z&&@@7mi%FPij~{coF=dprL3`pkgW~n=D_^&@^T?xpen*}EUM)LtH+$#Q=N5$s-h|a z)nKd6(fG?f-v*fE7BgVun&m3Uj*H0JL6>F7bmW7B3L0yX-^{AUr>lh@P9mxAn-^48 zBLaDk!H8eyCh#ss-JUy2JEj$&b=JW@P(47;*%c=ykhdcVDvTTl?;?RNLhVUpWC2-} z^6)x-$VHBxULf)?ZT0wNM5(Ozx2#Y87u;!W*5K|J%h9323d4zlQl%;PdF+!Q<eOgT za}U1@@;k8Gs$W_5=K_pMB-uPS2Co{M0ilE7yz5aC;7UJjFJ033+%bM4;s^hZ^6z_- z%rGW0fGUy$&a;8FovQBLRm`Zf+rYEswF?|r{U$T03ez#Z?dAu4IHecjMUQ3jUZ0%C z;SGmCK291hv*I20-%a(Hc#r7wfYeif6WwGUMD`@(23EYXY9RnAs46`t#4t3L&#$jG z8=-LnW}OO5VnlJ(l*>pZf)!4i-0(&I+;u-bz06V;`!D{wLoCwf?PB-7P3vYhGfNS3 zSVnpbriY%Qu2Y1zlHq9qHO-ry$gVfd<Z$0Hk0EiP*Uv|Kc7Ae!ShoQO#^4Bwv3jrJ zqnJ2@*&q`Sj=ry5_a|8`@1;pUB$BPX(lryah!hYU|JvWaLsqN%=L^z4+9vtGYwPYQ zty0%|G*O1ci{mg7fEi3*tVLM+0u6q`bQT7TvVE!WwIRy+ga*<zWchjc3p<l6b#7u_ zcHp*?=hCiGP}4LjInLOx4+LUToe;5M7AA95mNFb{Fd?d7`f+b_r6fR-YcUqt!X`n> zogfSWXlEi3$NWN&bTej%w#iY~sUz}TSa$}cyX|K5>E?l14G{#7LBG>n<40e-u>~MX zYh!x8<bR0~#W`-+C+67cxVTOY@ZZ<gcw28Sku5D6Ab)?50Nl3ppHR%)fSvMGS}1vn z!-6~xgxBJULDV&63a<>~%LltF#gYDd#9vOM%*gs+lpN_;5G$KQqX)Mv#=XW8O|Ycc zaM`W<u@aP05jo)BE(F1b<BfPui2DxxQWG?`g6}$xSRIZqDJZDPZZ-+u?%uW1I;TM0 z1X!(S|2WwX8>D$dl8?-x;TJ0mHse3SK(PVC!hhMr96I=x=}7<P$TZ3jL?hVm@A3bT z;j|wab$}n<z#HQ=rY8iI4Uu}#M2e54e%8>s+pk1tQ7fWmVT68{cJCKrfWP2w*`8+9 zQg<!OJ%i*Z+Dv;npk8)q!Ep`+do#qt2t}jer+0juRI%0WCi)($C!tpa;rtupZBdR# ze`Ub0%kI(uCk@Z!=s_N4)FChupyOZ42~>6m*@Yn+KOU;FuscZ$HhgJ-zOMIQDk*)s zuPjfiiM?pCFpCkQE4Fj|52J}Tc=!?U_X9`N2N4D}>rSUmIT;Ed{s<DPjt~lUtVTaQ zxAK$AfV!Rl$*8y7MaDW&l*&JS#aH0!iHv5RkJ=;$N>wF}OEFjkqDblp^6WHNx9V^` zP&IuhFAO<PM&X1Edj9;X!wuB}L40PT0uUbv^_6wia2d@|8Xk-F;}v6**`ppOqS=#L z&@ECaeBOL$>xJC;2(@}{;tXkm%Fv=0)Z&iVc>aMKanBhEGK8pvz7Ru&)&T~Uc<p6y z`labqff*WJ12S=yZAOM{Zgli6qCnOy+rR)F`~lS&=I^!szn<c025I0phkxR-v)T-~ zR`MGC)XPRe104_kdXbCt@Y;>p`IQVwVWCd&NOOacbHB4YTHTAHc+u;)%)N1wWMA^5 z@<5RYd7@lW6}I;?K!7R`PY4S^&FnnhR=XV}{O>;YeM55yDD(P2)0FTv^KaAaPEuwP z1M)eeSxXDCDTi2%ZmxM14e%SxeDwS|*$v=TjEt7{R+1Lnow3x^oIk!^(diH5fyr@k zX=gSChxP3gYo`vM)bGAunu|Eb_MTRFFGqepzTVMM+)1WtN2gAB>{RMeOeC|<!oq!O zCbN$z;A0UJ>#sF^^p}v76fc<hvo3#d)nrB8i1vqMd_g!zEtkIppi}+jQTqZYA^|L* z5hL4(izjKQJ4PYRg+>A=q<lQh>Y975i)S+NZEkGbN9DiHhTYc?(j2?Y4zJ<={3&H= zZM{qMU|VPLHC{Hrv!@<7yUR@xv855dvka)nR*3u0e=&{Wr4j)SZnr*Xu8|VM-+;4c zHv7mz$R|>}BA~j4i6whDOd@Zws5epksvh|RyxMqsA2d*c+bdTIu}=9F7o74dyucV~ zB+_HPi*3^ZElTDZ5OD5r#ZBw~PD~iWn00CccNN1gane+=ktHw)Lz+WX9+|em3}WI6 zN)*{vr=VinT;_VTG6d%`2(dsEHWhlb^-H7S*bN>#yb$lM_@vJo7xbIaXG+!UDKT<= znv7}%QFQ9L=H!Ia+$AP7IOWvspbdU^<1I@3{RKC1Dy(|{ssAY$fU<}!^m;HbFd#7_ zy9CJD0mU+u=_%#Kw9xtpDf*76B5|T1T2aLS_G<9~sCx0YL<9Bfv@XS1y$1^Gc{$Pz zEX~9yR*8H6;tHD#owaGVdctB&<^)4R-?b`S<LPimCW;%|JLB9Q>Pxu$AP=+`7Gvy6 zpz#7bd#S6UMe(8{BC$#?_GL-yA)rO7kiSEs#p&wfF4kR*u)=>l#;MW&fH-VCm>De6 zu!gkq2zAepLrMTl5t1j;k!=6ypP_-MqC<S)z#E|?Ln8Xu9u6#^Tf4kK4<~?pRs5-* zkx{&quD1O@XdKujJsZ0M=2gq^aZgZ|7|2v&(>BUm-BABP=m`T=!Ccuw?eX<n67-_N zYuxnbmO0AAiq?vEPx|zMu0mfg4`_v)<}VZq?uM-@uPH9x?*i10vcO{z9*1Vhu<J&& z4F3%^Ai<?15zn50LU=Y8y6d+gv8NYTSB3#Iots(j756hHYa22$OW_n(MvG-1_Sj8y zKpkT<N!YOniFrlt<!!*X{tcr_nTt}g-RDle&*9;MMOt+l50JOw^A%j*K0J)=2@$y3 zw|3RCNT@fBk4K5w?h)D7S|FQQ0)I?|n~{t~A6MUA*e4lTBfPM;ze1Q2DG~W5QVFfW z3kw6QAm(q+Ah0po+@sFn22Y9_HEoau?eO|5P1uWFVO?<N;9ua#ncN*pPm=pV&(pG$ zUR{h7aKLoEV719|trF|I2~RH7GzGb0KEvQWe#;KJ8hEna-!>`QD~+S!zTtlGiwmNw zD8?WWx|w#F(H^>8HxlZxs1BikPZ*4a#oX$wZyY4&eGbwFLBuPEP+L7lW*QuMZAGU| zX)rxs%kXPMI5eBxi!a_fV|Vdjljg`Ps-Sxz-Zm2s+@DU;kOg<I1!^q2?SSdINTQf8 zZ&y5i;G@U#<cBhghfc}*K3(%Kn<qyYc%h$7)(pNe4%b=jz<E-clhN@JSZN5zNV-Dh zK@c*c@-!`=@G|Q5phW^Ln-qgqX3m%EA8BHV1jFsVbN7u2<0B4=YIECRNJXawab_Hv z4&F>G*E=)%YdfOUCF?7@CihA?Aaglv#F0zKnv6FS@|@yC*aN{BW2v<J6%^kFBO)&Q zmDr-&l$}gzFi;9kyxBjFp8X2ZFD76q)m!1fZt-@x1sz1BL8DaKcCn8@x`dx{BC8VP zx#+h-{>nZ$l2jPjkkRS2-+{NO_I=dNDc}rzPI7&hQu)s+3_#<Mu*b{(6vAO60*wKk z@<KA9vN+CW`!$*BOO%J2oTwstkDj7jY~=(yR;J|^H}n;Eh}V{h!M_Wyj@)I4cx^y6 z?AK!cI@Y=|e%=28+cKmvLPepw>x@7j(lm2y{Ryx2t-o&;6YFQHal$+#jjrS44Urz( zw-5pmze>o(8lIpubIfTqgj<)>I@c}AGo5w_F5GiHfmXeILWxh<S_u=HWWjLGjnJK( zfKZLKN2951LT#RF7vHCT(4_ICk%z8GQ|imSGIscqfYm^XWQ^Xhsh)yDC`wRlR{Ied z2E7*W4v)*;b{*5J!}tT3vcq2uk=st5^s&4H)~E6Lah$2PDl>FJVhixb9t2F69uh8} z<%@pSBN}o^-ne}fEV$<;lp*t>OXMKf88!b0BSGB0l4xh7{tRHzfOx5(2Su*e@Y9wp z*tLB-mQVj06OVawkS3S%Q5b24bxT&0>)VCZ3#VcBrrW6PRzR*0qcH9+cCJ`LwvlUC zI1{thUqo)F1TrDBU@^dAfW^eb#Pqwl3tt#u@p>SWD^MGH6Q=^IP#tNCC5yHptGo~{ zwzuGvC7>jN?%aDgu=gb5a*Lq1_b2Q!O@W$xj_y)8ll|N)DX~Z)?^S@;+JeT0Ht@w# z^iocdrQz~k8&u2sxUza>?eMobgN;W_kX=}e+}u1A=On{BJQ;1$E+qLo!P+hxJzY64 zIbeu#bijS@1%$RVq0rp`J9l41czzKIa&wVil!ZvINaQzmK?5FqPuxIgMLnqrId8Td z_E`j>l`rRl*Bh#RaeSLCnmM`>p*%Acr7h&1WVqtcRRVx*y*l#hMSE=lvdbDEBm<;^ zexxqP4Sf?tWb?T_lyVtb(jBp3`wfI;<fF7G6E>H3VB?KQZmA-EPd6H>@{ymNi-N*Z z<VN}6$br>x${_WW3eZ$rLasZTY%4)o;yvs=v<qf2b?8-y8DKHMVu1DhXSh5vZT$Xh z8$M@_epP()+;u$FOriekdSw4crb$2hwCjP>$+c7Q`P`KJm$Ch5-TEIKPp;!XwKMsh zOEvI>Y4{JPC3r9ezrXMCUy?Q$m^Pum4PIy+e<nr2^L7`Sk!R?$K-P-_EP+UduCjPs z+x$I7E!>ZLv4!Z6b|BU21m@0|h<O+8p|wj)U`mV}yW7~b>^pq7_$;#86$G5bs0`7^ z{FxImd;0|#8ydmL=oEhXaXrifiox$Jg1ey}E??M!@grvA;DxKWY3qlo4mrBZV_|S+ zGtOMIfw_eRtS+9wjvG$ME{Mdj6?5_9%+m<Z3c`UYKfy2|9v0h{WAkY<R8<$?&h-;G zdhr%4%*<h8au!E+7$U8{6E)c$ST%M$mY*_5MQbZUuPw#M87pBPUIGOf%etCVaB1UK z9KWuQo0s=t^P1i8qOoEMDPrvQVb|UhxOqz-`qwUC{m$($3@U;~UXNfKa~P8SCrz1- zHQUeNj;SpYEBWZo@x-!q8*tOW4CW>mv1#5{_+-LPgyl3s(o>IXtG~dag9fm)Fo)6Q zQ#g3;A`<F)(c4`P{oNDs<Mu1Cvb2EpjkDN$`WpO;yP=c_7+^8LVt_SpAymFVo2i)p z3}y5`<au18MBQLXANr&t^16AyI}`|nB5nrGuU?Kr2TuH_7)1F!+C-4NhnDQ%J@WT& zAE@cVyaN7%U|x|}#GO|tqBC~*&vnTT+FrtEg<!6ZVh(=p*YOG0H*g;T`CY`#(E9nd z<MR3FW>j_S`jZyWwCzpZBEsLXf8GDi@E*Q?F`WX>qsc*gxL6&r?wYiHg8zbEG-z82 zUnpetr*QbKkoCd<ODsccK?Dr0U&Q6}7vK<_iylP_g3Yhu!i9@CZ|;rCHW9aQH0u2@ zbNB?D4KL@QL?qxLJH(pX@50$rIC1hMPM$c0bJy&UQP+j;hD_LAI*C)K&f?PL3pjI% zY&UR2NdpfGl@j$CfzUg30w>9FC(fE6vAi9f6|uN|?gA;(1d+L!@Ut+2V_*_eBAuXr z-2yos1obLoafbj4J?`YmO9;rShl0A@qTF!h(j{EfcSdn#8T{;S5xBbm>##g7&P+o3 zQbD8*PIJfIL`-=XWKuEr-4zQO5oCHnSLP|01m#01SCH>l1@0MK!HH96aPi_roTJxy z=?)@`+96lSkn3-NQ`|A9;q2=R!)r$Hh%bX!#z&Ip9h^UNQrj-4ufjdK4jP37!k!MK z2Uu#`>;&0<>N4&|mqDtOycWv{F~E9F0E@zaM6N<#UmrBRbgHa2mkXT&ED>lQJ{q!3 zLEkFqAS5K)G<{@$4b*BSq;v@gvJbbiJQ*BR<RR3nR_LbU(m{`|XixX=<;vi5$J1%M zy-+Jv<e{L@n$X({VX%KTzMnh=Gv+M7Pcy&A)Lpkw*rh^St`GLio{mW?t{}a!o7^1j zT3&nsDXX_nTX*uM)lU1>P6_T+tDscKp(J%x$wXY;>9wePwRKUFH&6PRSf=Er2&+_T z?dMVvS8s__P98X2=n|_qlfGImc_JM0_#!AYS{FgA(Pk_>Vu2F!Ae51|RO;%eR!TXb zqHRuE9L-st*uP{6R;*Zt?T4*VES92Aqe6XV2+Zta(az<o(asuDlZP?ACtN#9wb#Sb zZKGxP^=cp!@gJJvES1X;XRQavh;;Bs<z)F@SigKe&RgHZ(Yaq?uSFb$&`v*BlhH#- zzN9KrzKUEczefl~Z}0s&i|BdCel&3P(IkW1baT><lAccVkTxcltDREbqlFfFPiP%` z$$ggydvq{E`<?c48n2<E_e-fj7pddA#mjNs(gnv?e1)xM$>50;<V*Un<w`8%!{^dc z%vpC5Y0YXtDL}gO5sdkEHC)oQ4iGxMoKNquTzg;Qtd3*agh}{u=4{MgFb5OHu7i6? z8&ute&_A#k)2GaYS!^q$Vv+Vfk@Luu8eQF$q)!vzk?N+uYe-)qeOF2PjYchpQ1{)S zpL6$`Tt7WGUqt#GcWo-}dqk(y({>S%drbqNc{~AVs0;U<5zttmE@XP@W6|^(m^E`g z_TIP#J*#wRc!jvVYYC=JTL|OG8gj3+eV|96jjiFn1EdV0ZVEh)`!4j?oqVt5<bH5d z<7q$D?oa!@LPEa35(R4F%wTXg0WCeUhuZo@S+eTu>wk3$hZpA}B=?DQlK!wHHFZ&u z`y$u$$0@16Yb-}jehGZ^)?)Hc`;p!(=Hj;K_f33%$ASMe<k?6-m^`D@k8UE*S&^Ve zmpVZ?a0BFG`izw6>O%h}&ktRHl5r0h4aEG1>&v<8xaXGkd)gmcMc0Z{X!>)Uign*R z@@!M|-ak$*);`yJbbUklU=#W%>~P;<;X|M6wrZa@<hw6bJ*bIBrRKKvKS%qk)Blgo zs_g&%OO<^OZ<A}E$t({R1FSy;VDb3m3n<~EJjEC0<oX;OgOOcPh~oSV1l$WiVRH`} z@?+p?=Y)jf7A~QltgQsTu2$qt)Cs-;Q7CSyM{9E_EcUF!s*T%l%hCakULh!Nm2d-m zPfI>LEzMzWVU6fA@|Ikm1%G#c1o}F`BRmXAaZzxw_C#ry6vbYK(0BACH>w<2K`yvu z<BarL0XJ~hS104v34O$s*K=>$0{XVyRf#}rOU}IR8dr`!aXXSiJrNk-4?Fij#3ZF5 zl+@KXy&56{k=>PP@UXQYb+<)ib{!OIDGFl)5E2%Juz<Uy92<n^H*>KC)rqb+zGWd6 z9k>YxTPwIm<#IV){`n1`JS@mVR3mIcyuSl1teg?%Yyf>*N5nS(3R1@qM{-UJOL#;T zL87MMCPZ1R9S-eSiKXk0;rg{}aE>e@gSP<1vEDE>A#Z@uMd%@bCE<6XAl?tYQBer@ zaVO>2Bbu7u2_Vv7(5lQJSel!|($)pJ&2kQ6IRFwVp=gM}u{|f?meK$j0Zmz^H6{+5 z0)209Y#lcWYfPe$lM#Uc-(Yxq+8~1Tn*bXJ1SS@vQ&5K}S2y^Dr=f)}Mpc?W9Lasl zDsLrk!omSxZUQ^f9@G{j;NseOSa;wQ%&ctT9+rxx9tnZ;7Gy+v!OGkM)-FCMZkLmR zN5GX)mf%SSTML9`W+T!s81Y4I5Ek2G>KEU_)GHV}z8#L$#_<pkkP$r6?ji}PQ}$h~ zm_8RqzBv#nJ7BbWCgyBDhP3K>M0j{1ATk>r<U3p(>j@XX5M&kw;p_!_<RzD&ASVpA zS4|L7P(@x4_-L&wM}qYcTnwxy11GsY0xmK^2eKlZNq@0`oog5x6-v})gu&}x5PV%6 z5t@*M$N+D+xDzlTK(6c{1F)+#x4(B>5kv&6+R75)=@Wst2+}9X=bmAi=#t6t|8MUt zz^uBqbnTqJ|GnLPZ};irmUH6n?jcS>a0`$?kPry&Zow&ccXxNC+}+*Xwrk1v&$)IL z6bU3ifD|xzp7)_@@8xUNp6{Mx%rS@B^I*Dl9llz&o;~x<aP^Et{h$UtSuWVL`UJwu z8`0Ku9>>?M#Af4oC>0X)G?ydH^$hg9%h)q26^>Ed(}08^C)luUdjy?FI}=<fd%omD zy(mcZ6pqEwCl>j6W$0qpLdx!IqPrto-WDNIaY(Q1VB2A$(wm86>vkc$xDzs|<fi6i zMMg$m7+uJ}%uVU3azrBGS*?pP$AUR?@%g78<Ff@D5mwrx`#YdqJAwp@1nb9wC4!87 zdu_=I!j6@zuxa;Bd^hW3yfbGZ>_StqYxa9EN^L|_b}%-4{1m>i%Y%GGi6S2}Y}~jG zhxYHroEKliM*DCyG-l%9=hN`k`yXS?<{j8~))vKG!w~o8!D7odSozHkY+t_y>-HZ< zLV5=FfBrIFo&6!c{$?J&nDs4IFI^7(m^SohdSc_(^RRHy7dYlu%fCYD8dfGSN>wx5 z&RHXk3l?uEm|UcK9K?pzTX10CZhX0MI~+q(5U2koo_+Bne6nIa=6^98->mrxYYus$ zueTQ77W=Vg{T>`TunB8c96?ZCBXa$Y;geTi#K&K6#HMv?uy&s@8YH7A4?crMAH9rM zX05`GZCh~6?Yz)i@T1%+UPw>Tk6d<LR(`b-yLN5Gy1DOR;b9w;GRe#dID&O+**^De zW5==s`e8+oX;sMaJczk7Kf;W~-(k<5eQ-{$g<2&-wx0o3eYF5<4|<_%L<5a%2!)<| z@z#s4;*&48V)M7lu<o!q%EiD?QyL65ZouY)2e5s^m)Ls11UbzLp_fUn)u7z>B=(=N zLFFKzkSQSVNx-HLwjwq=8vC|xz{#*mWZLb(n=d|x`5Wfp%Z1Cadd?Djd&CYo6`5G| z)bH`>K0gdGIm>hU4lg|Z4s5gg*w<9G(75SfVxbkGJlPv7-+ckoW-Y>oE!%LyAskI& z4Tjsw;jXuXozFgOTDunKY|dkVt>2dIhqd3X!tUKnG8Rt5BTvkSeMTEJgX!2iV>v?d z(r{$S1{j8yvg@VzQ9~wW&u(LNE}V95g}$d3{6cK8XVV#285<&}JQj2Q`DZLWl?0wS zlW4pIPdvH+p>2gQ-S`cb&t8a)hi%cuzBQ|PxQ+Kz$)%_ZKZCPTEle<^P_XUSWCdc! z`n5Q8Xg@Z7`wfm81tBrQ8uMOx9JA&x!^(MIVA0am_-6G^1a<VWYh;LT*KWXpLwm7q z&1%@il%cIE5?{anGNyg71lu=nz#=AqAw_+V)+b;)`+Ix)%}?;n&h6Ouy$#9+hLK~d z5BKa+NSVyZW&FA4^^GLsUxxaT7i$MozjCORQlU4kzdQ|k2UcUpp<P(NVHfO!%9%{7 z&|DddqwBwA$G#V<W`2(MW*tBYM$wdHg>7p$W8cB;ST+3xe0(sF$+QA0COU~0>{)j& z5JE|!o7k{$sfvn<f;sza;&T`B&!(w97a_0e&KofmyDz+FTq-6>AV{!Cu&y9jJpV)5 z*N$-Wqp(Wu6uM~DeHBPb$VR6WNYLL3yW}!q^hj&uAsqM0f=H`HX^=72EMJPX-+X~t zUu=X=dM9`<bYp})%w2piaG}3fhMKSw*lnDIAzddn5`#{{#H$`<ZU%74O~rX%E1WzL ziT1V#7<v?=J=qNhnTYH=xEBTiRlulP5UHUdDLei;IG?c+1WTq=L)4d!O|LwQ4;L?I z;<5^#zWNYe-sA^uV=#_ehoc}T1NsNIAgOx*p_bmrh_l1u_n*UbUQ>o0`)dzAf|W)| zkPbG%{>%Xc)bl7(6P!=3gLAPK&<-Ni>o`s&^j_!^myL(FgfPpn7Al2Q2!V=gGhuo5 z6e1dQ{pbxLN3r^#0kSH}aNv_i@$Nz<ZfjQHQ`RuQ`L#7#$Jlb3KBPvu!9PPcB1fx~ z2*n3^z@Vo-8%`$PXi>6<lZPm~GGTG@6uhc=pME(k3=Y7fK!j?at$6r}5AgNcZ?NKv zPw~W)FTyaX8>1=(wCF+5v3)pj%pYAmT)^|fB%LVBC`L<L6N*ZUP}?Jiq_z~+XOAOS zR*thPPNJx>2tHo!IG^8v1hdUdPW`}xScOd1zC9fZX@3b$uV0FpGiQ!72S>g0gl8bv z_Ane13NaB);D0-smJ-+>UW>)-7{8qJIhL%_L*1APAxBr?OnkGjT#?sdELdfUHjNsR zfo@dh<)X2p6{UqGsBP`l<s1nG7S+%QAvT?0)fFefh27gA_B^d#y$SAt0We|rp>#lu zh?6U^(lCi#Pc>4V_F|`D3Y1JSPVYE?6Wb5sgn=U(`BNzs3%wLF@gS;#PYHr0mn)za zb;9i+yQXi=V}iT}i)X%pCtq5Egl-7}&z?nYeF@BupM-m48Jf~<;TRH)4YS_HN3)h; z?b_9t{=z@;)^`r<+Q|{-d=^%Y#X`s@!pR8dOjCuhQEh||EKLI-x)3DMBKC|P0?SL8 zJjuuNgA}@I+dSka?nYLm^(4Vkp{Fbf$2Kj*%5|$T@6*rm?a>fO*xl%=O~bL3vxQ?> zG<^>CyJTT-co=OdcI*oc`_i%YYrH#e6+9Bk*%vJ)axyWB*q4pDCqsl9MmH<haiSNC zS9`a!vtu8?y}CTK+hDS1(Pif8BM1^K60FM$R!=K}jrYU0SUO=vXsOOYO~)Vtk1U5x zcDGQ`IOx<D*y~-!K7?7LUR{Bzsz!7Vv>@=rHk`7GKtEfm%1<AsZM`wbeja3vc7Aak zDq{6<(y#GCenC~f2h7~7P~qW)jNU@T_`AT?J{#?|zAy`Ifh0Q=e#yDQ@M6B-u7(CQ zu?AKy#PR##Z{~*5Ufr>Zdy;W*#ddgS)uOef2`%lN=#`9Mq|6%*@ntB_%!aMOX%q~0 z!_P7Rc`2UQzk4sDi`voN(v0@5E(}N%kknTo!p9i}GHx~%@Uq+u&vN#&tQjG;hj28! zL%1$=xydML>=%-#2l^V39iNQc@+J(anCw-h!P?vyX}a<^5artA$QeuIRaL`e-FI*< zs6|I}vv7?4{rwma$=N3R1;O%5*EO$d84uaYgrB)!x!Xp7|28trbfq~Ne!)S=<l7%C zg1wDCd<*+g<9`$@k9nc4y%kMOE$Ha!)77kDLaIeK0*`XR3SfezWrC%fZ%v_A=&C5Q z#!017p}VveAx`e7M-k3!abd@p16L1k<Ti{zSsj6I7JmW9=r|nydKL_ldoUvFL1l3P za&vRX$wOsR7v!2@B%5r7aa6Hz4vl#QsBURQa)d389S=qu6Q>L}YwZ7?_Z(>vc4Red z^7@5k2P(X<eyusGMC_U5bET<NLYPaTR0z3Nx&-<`G!$ndIWZTlJbz0eLu(zoPWB1t z?@2{iQXQJ}Q(<j%29@kvL4TejRxMf$kMuZfo4W+=d0g|$U}h5wg+%u}%K95n-Pi$< z?g2x0qA|?Vb<fv`xDCGgYp~xo8?7D9Xl`ypcR!cBHuzZwqq{dB`exRMPpw65ye+(< zlW}6-UbvnwM_Vhu*Inr86SKXr<wJv!A$*CEAlB0!HrAO;{6<jhV-J0OH{lD2q^TI0 zrR^w-uz-PmEc(a)Y82g7NGYs^L^&*cNvTS6heNb3$BeB6FT2w??VgRn-Uj%X9>)pW z1oro%K~F;^3M*^S(bbB)1V`*zVt`_`1np(zsI09)TW2rMJMF-?CPC;KQV6+NMZU){ z=S1*L6RZij3JD2;v$L}xSNt<}N{0vuf&_~M>)JzvVko6UD2lYgSKqF~i4(`Mf7?c^ z+`b1%brR$|uf^;yw&28$o%rn4f8y1zjZxQ<huy1|V8!|atYJ8TE#GW_U05-Ov?Gv~ zd9mM@W9$9{_<HsVob@Y0x2O=t-)+L?!-sKn-wy0Ka0Y&9IXF7&V=O;v1ZT%Xm_Pjx zLL*J^)t8&F{ma?-WZq(IJ$MSIPHw<^Z?A^W`AU>0yW!BmE%^MMPq1>+cARqzMq|Ge z#bGD0W$QtlK6xC+j-7#PU?Reec@pYc*m#6t$K1DZA}|uiSFeSsPXxT2^|52yUYt37 zf-Qd<AsJQ3@jH!K(?7uJuqsr>n&Q)G&tkoG4x}Se<c1q#>FhN)e&|~){&FqCiwA{y zzB;RH@Yp@~;FYxw=)@RC<UNS-G{SdlH?r$^7`wmv058A#DNLhlP!MH<_1kvgoUqU1 za0tjkud*L$PDk;@yif4?lC3!Q{c(g9_e0rT0e8z2*tB*TroTTIJB}PiKx#G0{J+O% zGd{!dpeoeGnd8Iv-oUqZndon=g5#bo*mn9fP98gkV+K}8sp=6XXjQP|Eb(Ob^t3Ii znZxnq@*j@YlS##hH`|7pAI^qth7UH(_!<VbPB?e)TWmE>WDT_har*o4>2nX`-CbU2 z7Au4aY-MuAq!6J(8098WXwe*h8cV-gha(3!VDaoN@XxPdjk^QZtXR*Um($qx#R5G4 z@=Q4AHlQWn7aKQ!hm$8yVCC1J;WH)xwS2_f<$4F0c&bMmac0Kjc>LW1sFbUrQFI_s z?>l@lZ8pqfiZLi{hV8ctG40Jy;E>k^X!{UwZYy4W^byQH9mI}Lfue{r_~4yc*s^6W zzCV5fYd>fA+Bpx+WvQ?@ydN7EzKwU6Y{wxcff<cGXswFJiS=7?=-eqBXV=%r#TPLl z_E`At44iRt!|~lKv3!>UVobilqEjA-va`d1Jv(sh^eKGLmbZ=0Lu+jWR?nP)FZOw( zxhVxZKm7pjFV#n#Xaqy0(b)IRY;4(o2y5mq$HBltCcw3D+_VMjcCceSatIs0{SJqM ziqKP*0Q2v6WA&2h_;B6^96f4>f`(c|yB@-qYYsyH411pDyoa|x+m5vQcBI>`#fuBJ zLSOF`_OQR}gGWNpG1d;tC9|+(>n@x+tA|aS*W$Ea28JZO2TO(&>u<2tHSeZ`2q(*x zqoboBSJ#q%MS?|;V3A<mUZV(kBCn(mIbk+9ckUeYjIEGdJt&OG6LnU?$J~J3Fdw9* z#KF%u2<2@Z$dB@bk)b|YUJp(Y+31yNArtetyt<GU<O~BnJvauZp@%iND%OBE<OB<^ zozv5YQ)D?h8*|`kZ3aunNaU3y!NuAS8Tnc8vonRhu?b8~jM?(%*!B%z>KKl?&Ms7( z_ko@s``z3WMh5z@^o&H~fD($qCPdonv-k8ECh!T4M@+aI%uFm0ms5sVPa6a#W+ExX z8$NLr80sj5yEQv@VR>UjWLBUk)gLCNW(Y|xMp;%E+lM85qqET?S3=xTfe;%*w!9&N z^IC;G9WiSt`n$>y?BI%sv<md|*Q6?;ry<DMK)5a*-XRDHc7=ah9YlQ{h;cC(-=_iG z!}8Fl=tH`n9gIy(VQS3YGcZAX`2Z9>)$n&Rg@K_lOwCMK<EY1uu@c28p)fTyMQBP1 zDl(&CW@gULrvO6=HJS^eU@UB#Vc~>~nqDCXYlz(!RZ}E(Z#@M6oDRs9(n}jnUQ=mk z067uXY+tsB$;w7t5TCm&4ViI1a0y96mxOIU_AH)$;BlOYX@Od$ymG_Kd!PF15$0$n zoM#}rHe#&?@}5S-xEZnQVh9J{SVVd`AS|;EQk4X$o~M~~9>cDq+wk39AM{D2KT2j7 zdRzIq)cIld3-94jWQA}X5>W?I{cMHn<P%qj&faPSSsKI4+!;y5jSwr<DD~Nk2k(0d z4jH`|8y2G|E&$f%CNN;nkRE&94Na_YzN#A?m1%G?(1U@oIn0gOd&cZTudWvw6`wA| z9s1{V*VoD`5Q#C7uw&1mM??nlk^^Al6^Eh}KByuR&0TGXa55i%9`)cFpO1#hEV#3K zXUgQiraBkCyiSs56nn14?C+xs>ESNI--n%d8u~PRG_C@JEjh5)*FC4^o+%hmYtdPr z3<nc^7#W+g=i87SzbkUv2Qb)H%(lsv)i-0$Rt!R1J&{(~fsV37n49RHM`KGLRI$Go zwR`}@@jfs$Fc8k)$Tt=JB01zz_V?bOkCW@SA*i7Jh9|jmx#9!|2Maw{eSLjXs!Rhx zkYJHu-Gnj?y5Zca3&U*3#z&zI3Ny@)jE4=?e2DolA6l#%wtjK6u}U`-e^57+S2e85 zz8U4i)`xUu8f25k>5gdR?1NS=)RP$-<uj}E5)H%bf2FR*%#TI_>-H)A!B}5Dq+KG^ z&5}(TK0F4kMg^5{eC#|F>^=6QR;7SiJ1k7?Am-;ZX+ON&!Nl?LvJJBFA=48>?D;qQ ziA%!^3Qp7_5(z`E$8_^?4UX3*;>(U7%gA^c3Z7TRL$Q-C*?8#y5fs|dONKnFgb<-r zD1kBg-w%&bs!(6p&X6!Hd(trPv5`q-6xbh~N{%>-Q*eyV!T`?|yNtZ(hD!76rGRF5 zgk3|W?s;HB5^J>upS=GTo_}#B>{1)q^^yNX=x9)w+;!r#CQ2l5iJv%sUh06C)zGMw zkoUJC%yI{oE?tVn3wFb|yj2*Lb=d}5IfBk)D{MY)h0<<069AE}2X=gCysU(nU%Ro1 z^uGZFo>`8Mr@et^Us(p<BDQU|3@=CW!+&a-SjeNhWT5@nurS1)=fo-0lb-is4f{M$ z3&Z1w**PeA`3d$c^6d&`79>)kB*(>J=j?f(*f#rHkxIvh?2lZWjzl$n4x=OEr5*-# zrBOyN+)~}&m`Es>a><}}$a$eu_Dm0tKSLv0Erv%&bo1ZI)t8))T&ydnA;08dR0(yz z#BvQ9lbIMgC!u4A$*cJ0$d!|m(}kX^ALcZXU=bu(Bv@2vl(>Ch@+=vzw{tz~_xE(6 zqpL@kH+IA8(+r}IZ@;4hon3uQa(=pcvrhW2wnF|8`no&WcKNXn+=OGl^B83Jcxb$G z{Ee2YprD{j<Z9~8MMw}NSR_~^Sj2Tq+jG5*Ca-ip(MaBmr00oB<`T(OO#i~Cxw(e( zxMbTRdJe8`s+^l6R}*2uUm{l|SOf_c2^I+!K@fNSB+tA7`C-o0^@IhlSFkS36fmlR zOnm9=1A{`z4-Lk~bYa$^!AoZ);O~u&huiOlX<G;qED|gdEP^0z1G$>qbM;HZg4ZQj ze1z;!FDkR5;l~FTbo2{7nHSy@_n|sB5q^F#DDUWnc;Y=icc*Lsbp_`U<QIzKrXHao zr29&cV3A;vU=ai{CFF|dT-}JU;B^U>L<xxMVYKM4xaXc{VV~6swPt)a0I>p4wZLli zGwi*;<6Krf6cg_a$uNR$xNdrjy>}1xgw;a%QzK^yf&_~Miv)`xh+837fq{WHMXs)= z2dgS44nZNwsO{*#*h|IUlZyLLlb_5)Fdmhc>A|WmN=0Z;1WKBFsRxT7!6L!>X~C** zXt<_|$pk^%om@|2A)O>wlf#0)H0SC{g5~Aqh0@YejE#*64a?<FC{-6qZw#wdKYDMX zEX>Fc-&0(CkC&mj()On^6E()Big@3S*YIYeR_o?-<<D|vW+n;NjT9`tjVp2k1*?M# zmYEqETUvzkkn%~A34*xe;qwd1$I*SDNq?4!Wv{0~yO*~&Y;0_Vk{&m@=W4QG_4M=z za~Qh0xgkA09m&bb#5hSwNdkNdE8c_nYfBd2e^XNvQdm30kBjcnMb4i;kHo}8p&&8! zVEsbD;_Il2ilAZJ;o>7~BR^l*o|OGDNZJ4VcP>|aIqmpzO7`>h3YLnk-@`tDj8C4# z*>mS$X<-2iCR+qS-1(T9n!<$76u|yBGdE{g{4{3fFg7+pLPEk-rxQ$!77Pmu$HvV& zSi_Nmk&%&`*1IMiuhW&0kpT}65BT}{5tHCOh_0@#FfuYib93{rnij(E6MsIUqoZM9 zU?7YrrF(QKK0ZDO2nZ1F)h~@O-Iao+WXq0}l|ju!sW&YRbulr>^7Ta=`y&W<bcDaH zEj%nO;cab=U<U_8ySU)Irzgt8!qCnvSIp!~Sf9z#^+=YCNn0B;<*JAXR5Gdvg1Dop zX4FJQBEZTLJGURhvD3Eji!DM#S|h^F*ItqEw0c-Lhr!;_S(uCPs&lS_f?(m`2NPTN zxfT}-jYe}*Lzv?6+H4cWXNkcJg@n0K)z;PuJ&6qs4ZpfzaroSmT>SVwn>bFoUl-xe z^TZbi60EBfEWXT0X{qpY5i|EdCQz;x7O-aDB%Pg{*f+i~#K*@YEj=CiY?<tw9H9#} zDl!s2-rlfa%Q>*+y_tNSXW!JiQ&TZoUVdGorD5yv9x;L-?tF$Bqh+PY4h+EYW9Bfo z4Mj$!1SM@iVe{A(DQ52n#1+HU-4n8(X_zPEDj*;bCe|Lvsa3$vJrXf7(KlVNCQBA^ z5gwM!XJ4qz%*<fT+MCwa)?Zz)_<iE-8V`f<9vhxN$B&cl*F|oGT-`N-#oyx}a$+V- z8NR--)7OU`lcW$PR3%KfdU|`IWZM&R9mew=_#Xj>|IA-kunQ$&zw?oQsZ7A!nP6G5 z?f9|nw4XmO2-7bK9TEg_=b}q9C`7uSFTOu&3RCMKq?GofpmF3UKN#~Hhv6HQ|FeRn zYZOF6Xv4(X9a+_KLEfyKLvNX25tq+TD`9QVzJ2@P;^J~iPv5TvPvYi1YJ5U>-itNy z{LuZn@!au(#ifV$Fg3-;!_mkHb~ZN1&do(vSC_C2E>BlG<ago^hOfuhsjRLRV(X`m z96>S@E`A(5pNkq4f*@{{U`fZnaZmJIWmd^h*gT4Yrcn~CDbmPRR8&BpeIe($bQ5_! zw|rj9!9k(D<82==*}?O$`0u<;qx(dHb<Kjs6VrLVRRT{iJa<kQ9l$4;<p%#tyJ`6c z+Ju~ym6yZG!2!-DCTLAc!ti()k{}4;W(wAYu%Le+jJaG@GPz=6l~=DJ!J1+XZCP0v zPMta>q@hfV=)9GJ#rMg>f%f+HLORSuq=xPf3Dz|W7MCmjTBx0!FnXuDwia?GRyVpp z9lwYZq7@Vp0{vsh&=3~~ElCzZ5I0e<Bo}(F0@(JLTvhAjimyk4HMQXPi8r?8?8`Wp zEZ&oKEzy%-3U4#HT=7yGT&^ZkVCdeEU|q9dDaUJ91>4%f*2V_y9UV7)hIjs9$B!#A zIvVGW9z{KqED9GA1aUJ2Ya(YRz<)gFs!D!Au1K(^zGR&~efmOA*3FhIzK_n%PU^WL z!MZVm#S_{S-P~YhZjR2bu4^dL$Nm6@aml|?mF&VW)~g8{@+A52s3=&TJu8%RxZY9@ z1VNBsT~4rcVL>tc{rzEL<1XY}6*P@qvK|T6)DIU<maLl*E}WcmHPLfLaz%pmiv)|y zRdZq@Oqk%5S5#b>8scX|eG&ymM`b7uw#FIu;PZ$7%oziC=e7bPDu{*#uev8o#6-)> z(^IIarJ5*UN{tLbkYN2n!4l+3%;hS8$(6^rT#f!{Jrb;`4Uecy^khwh3vaY!O_r<h z@Nhw_XtW>+)^!V(avZyJ=MWhcC7j&VJhURI62rX}Fxs~S5B<kI!i?<`{N}-rpy!f_ z0j(0^Yk06*+uC5Lr-$n3XhHg@ks$~YtY0En%JCdhKR<sV=ZcqND7=hZkzn0kqYJrY z#l^)5joXb17xHcKu;7GTP1L!f>rR4o-GVh-R))&RNLUyfqpiLDszQTYuCxQSF#YCv zL8u;@^*s^_OHff>h7`9$_}jnTga7^V*GOztU|4?j4?nM~#jE9p*xO&o38RLFAV{#T zN3cA+d{`qX(<QVEJy#QQrTQ7c3L(L|4J7N#nKKt8>zDLoO@sv}%N2zMNw9vgU~!4z z`A(s>w(#@!7iPu2s=O(g65_TZm~ESbd3)_p*`vVNh!)zBF^tK(VYK)j-1E<m;F8x1 zsHE4F^xn|e2unjlbf%;TqZ)tw!J7|RK_Nz}YJi3Y2xmT->I!IzeyNz{Gm3%QTA;jG zn5O3^C!;PY!)Pg6?iMvX{CHHQl|WrJG==Q<f+A=u%7ycm<rhFxQ4Q2oLdBQ;ne8Y_ z%Gq{mFjA~rml}5BP7o~rm_oR^x(oBhnc8>?3GD?}=(!@nx;?{%lO^kyB)(4$3r0jl z2n{CnT#;b?V!`5a)t8<wOnt*&mtAG<)ez6E5=o#M9s@?ykV!=BTL61d)mkX~^0DP% zCRk6*MsTGVqYBBjO{&ShH8`;cy&x#)^2zRn#n2X~A@;;htX;SOE9cIg#A2L0VTIOQ zKF!AUOO~Rj1j@V!*sWa$6WeeMmtHwssVdAzL%1(ueAowa@vW&!uP&=Xi|0ukTDco} zsRhs$WunN&6=lg8&{h?r#QXq`?lwYGZjsPHU4A=-Latk1m_1Hz*n#-y9B50Zsy=c1 z3l@JrfC<*_J$qqc?~SZ##TCPXBv^MwxG*+0_PWA_6Fpb9wzh&?QCN@!>xKyyFNwe> zVzxCmM@w7Vbx%hyI3$KjqlIj+9?o0e!N1>g4?fuBfey6>GSRiq`4q~&btZXuTwbt> z%7D^%9G~_8{@?v?W8bE2II(#XPHfqNoeMs|qks4lK3s7O&3WZa#0mwG(3Dr|dZTJ< zFjiI~d~jbVPf^UaSEGAxl)X1nQ3X_1LY3o#O)tEJ<;T1*R#D3KTZ~cOYsR-zQ^f?1 z%SZ`ZHXWAB-oc_H-atbQ+qSNUO<P_yzHBu{N{cVNt|_koD#|fhSuMObe4*!vz0c%v ztg0HLrEJ^z`9jas2>TtCrNS}G1i51CH?^Y1^lMCe;#0(=v3(?4V)1jc;1g8<bX6d9 z<xBYc6H8HCz<c@XbjR=`d1A*{R)#kFZFulc55vGa4`^;+$6PJ+#tFxhKfb@p3U<6z z!h0hn{CF?DrYJ8F&QD%c3RG7K*InrKW9P&7&EMCZ58G!&<@oOfm)XYT`%*f7Ul^6; zOk~G<+}J+Gswy$cuOol2qV$sW2ofybgB6-w2~%6|@lp&UR}2f1VBOyEHtl*OYa%Sz z(a~{<Tv1q%1nY(g7EdH^U=O9ai3yXWq3erdvmI(jM$uCdjPE{qO32B&@6)wNY1BZY zxc2RdndBuVB_YV({>p+?5|1-%UvDfs2~l~SAS}bY!L2Dp){%v{_y0W)NB?w;u!fm8 z&V5nd2t0Qd?uJ$<PRwD#R0bsz0%b`#G&zY#vo?VHIWrW+r=c;_9Xa7CP!^>k)7l2- z!;+yYEn{MlgHksuxSu@>UrQG>W-+;{E<%HwJ{CXyH#|T4J0$pqVxWjgLv=YiL*3xR z_UU14i|UkoCMaAIa?lX$hn(OD6uH^J-N*_hNm)=aAyF`aQ)VS1!`YenV<r=f64tn6 zq1@dCiN3Lr78MC0)1H_>ocD}GYn&fqt=-X*k%5%s^YG}Op2WJH`pD19M#82K@cf(W zkQWn*2*Y#mHg`l#S^>1BML!a(cBegf`SI6a=@x-pTLX9)+Mwcm9!A+UQWfQ+HOvS3 zL7^!3aD<1xIr8E%F;-K7zGz>B=(B5TV1fLY42)J+L!J_WBqw(?r03~Ig65t_j)N02 z`SmO*X4}g{Ly$L8+4-oLB=v-Q!e5VX!wk968SEbFWJyz2iQ(KNq*&;~?W`VRe4`*Q ztz@EF1W{THay@-f6%mL?{d0(Li^LG0eSn071ZxsGwK}27Zy3Jn4^$GYJ0mCS=SCO) zFz0F_EJ$)if_1|Mt2R0srcAKp*HKhdB#|?@k|N*rAl`cT-<Vwe1)qI;2$?N1CRb7n z4PIaI(X{k*cw1ZltYE$Q<td0N#s!N>5Sm-i<FXYm{>LLQ_DBU9%TQ>t7qg#v6mP!% z9zK5l3B2&?C$RTSz;I<XhO@$OYQbx`@1Kw0qgP(WM{j?GS0DW==4^FiLgbI-|9SwQ z@AUv`a}m9BDc*SOF?=-bJ-q(Fzwp+qZ&8?=jg-C1@x<@{3xB%*8Eo5YjPBwp6dA9@ z$Im^1H{N_7??3+-UVLRS0s=Ca0OrDT%?J3)KOV-%Z@q!{Kb!+6-*k+XF&QagVwUNR z)zAJ53%A)pUeyF-dt$-AevAKlbS>)m`(-(BTk$GhnXiW|voG<&Ki)@RU;s=OJ&Hg4 z$M5j;>z~7#$xGI*>3HBDPhr+apJ3Jp@8Fp~{SL3qT#JJAQlZCevS4+(AHi#X`#WBJ z^=-^}<5j%%<b!zfr6q_6&SKZE2$7pV!-N0057XXw2k*Qy3wEAKXm&b?xlccU=U;vs zpFI5_?tk(Fm^hq=Hr^B;Jn$g)n?*6ntb-!r93H*r|KPcqryy=%PiSs9_I<#PYoi02 z15e?LmmbGUuf2=uFFb??pZx@8&hZ#!;w6o9!|qvc;)SPP!0dNl!?TY*i4A+q&|g)D zp^!89{D1z4r`Yj+_{wWoz0m^wr6ocS7fA^T)?``AtJhxB2Pz5H?Olv?a!=Mz<z!9B zm5q%J<y?_q-P{mib3%epT$Il@cuhT65(Tv42H5XfDvTQZ&qv?EIlnRtDn~IaB(@J; z-+YDaL62qMLL!`<e^Ri{PJbFN&)b8_#58myC80Y#3tf?p*z?Zc@#p84Av>!Es#r5D zc=|D{+-ZZpk}{~W6X3G)H9Y<1H>hTfa?;jM@vr;dhl^JN<asHG*fk6P@tfac!45Ab zSOHk|&?A_4H~=_rg=znK7+X*KVYId$gFyzE|MU~sZ63wsC>BRPdJ>=Qu!Xj=3cY^k z@Y&-JvSmFXDlUgQCkzHNU&YIxY(ZO55h6CdiF^L`BJADcAkEFdKu+O!?@KYpn1J~% ze;qH*+=Z@+R!Dpg;)Q?y2EYIFJBUuIVo#bMHoWjCwwooR*<u-<|HnHBJ6{E9z)?(l zXc}z1&tt5y6bT#O!(aZ-AF=hgI|kS_thd{NXa9IFHX1SUsVuofu)4jD;L(5kE#927 z4;7gO7)tiQ=2suYbF=p|p(#h|p4s@#|9c9jY{MWfF2zu!6~1`#kN9xK_o&TcvX&YO zlP_MxU!I+Z?DX?6n*Jm{*<gjS`X<zvF2(Qu{T@91;#VjyZH6LD53`?q8P<W3aQNgA zygvURI!bDQyl9-B^&H+`q7N~XS@$Kc;>i!!AvYlxBV|P>H`|PN9(@|;oKhiAGQs=z z{14t;eg=)~86L>YrVt?s)(wFK>-KM$D=RC1GF&(j7M$q0qMR!dteYoTtnuwiNr8>2 zDXME~Aie79?GmW8GUR#e#(nqPgFigC14%8t(2k5iF`n>#y>k@uhuzcD6DeL^Kaqo# z0E5q;$N&5NKk@Q&FW~j3AH_d@_gnnqzQ^$4=gZ+6m<BXepybpF-1lD(V&%8HV6<x+ z&g|NU;|pKG|M%bb!okG{yWe>TGdD3Ys%-#xepOx|HoW*C=5KSu2otQ;4?l`|hx~vX zZ+!Xey?ExmRq*A><T1(U%gBP5=SUUB<J632Fnhln&{&VG!_)ECKR=F*TXw@>`&Q`h z--kV)J%iu;pO+96l8oSuuj7Fa)}pbb4XC)Z=S5ppiw5&mc<$+$NXacj(UFCiH{(Oh zd*vmZbjgAy@GxF~;v<A6)uNHf3m2^L)Ea0aPU3?{KZZ+C7SL9X==Ja7$>+a9X<;=` zU5&Ba0Bn5rLCoFi#Ll&RT<FGgu$=ecwTEAZQ*bd*SIMqh1L}>x#*+`dkJyB4B=4Gm z2VeaXMY(lAYXhqFmg2F8-$PhJi7;XlwRKQN8sdY0K7zegiO4%T6VJW90WCEp2w(dS z=6wDMX1_5F-qB@fH2NAZy|RMIRsjN*zKVa{{|5BWSt2_qnhA0Sh6>7{O?JY(hyQ{X zKVAXDJv(uF$8H#J{TeU+_iyn28e_Cand9BRJcA>SDL_NjEgM)s+&zM2$pkBw1nag> ze2<BVxzLj}IV{L?t|B8NNv=q+ZvH4jaZU~#4Gj?&AAi+l8h9P7(ZMPlU-}U4`P19* zDd+_-0-02DVWxUMErm#Q?SjR7()7-pK^6N0xN;9xg3yEY^v4^J78r@L0B0C}`7Zu> z?_034Pt+xLSLPvZ*IfMdua9Ekyf5(W!ueP|e?Goh^aVDq+kx{QR#@@s^VoJa2-?aD zsESK4lAi*DMUOMVa>Yo6PO#?g_W<fEQ15mU8)v-7q~>?{um5=vUwpj>Y4Q2&SmJQ} z)2A_WuQOY&7UADLhrj>n87y0}7~in{t>XJ!`~@~FJA|V6B>1d<4Uc@d2DSN(7%l!m zgHlonO@b9>Kk+<FoP6Q1XfAebGlcQlkFa=;8!}GJ#!DY>L`y|0YK@oZ1S_Q)%FyF@ z|B(-cyfd_vA^N*%c<R+PD9vH#R9+5MI#1Yt5DS=KX?`GBEsneK$#d@@B96&eNdYvK zP3ZI7jdve=89rfYNZS259(#Qm@-mowHC7_;&|EzE)|bdlD;1LQ)n(;SBspUFV-I5O z@em9KAH$oEy@!yH0DS-6OqiTC#`d|>u-h;IKI>k`2P^cUsHuf4(Fb~8&&J13--rMC z&)?#WkCwvS?L3B~Oz`ppzsGCu&1Ls&p>WSuFIb50mM(*pl{eagjqvv0pT!}5pQ~tc za1tyMEaJx{947Z<agpMU_C!KEmn#Yjl3?AEI#}A$Qlxl#!o$PkLXzLl=1D0ukT#`Z z-K+QDzh@mqWuFQvi7t8Y0s{kAJs;uZ?%TqmA~=|s2;!%_T%pk)<zUqU)r_(fST1-0 z|NiH9;U1U`w3Z`l|2+Ktp_$0YYXiF4gd8ojG&2EX<oIIcOZQ>%Zf6YF)G-lZ0#Oi& zeeXP?6RgS!!E(n~c_}m%d<0=BTEct~a(Wl$KKwhpwdgE{DpPRgv!^lp0Pn%7L(G=f z@#xbFQB~Umv^9_Kvq_LIlxM?Z)ysJ3gVm_HoM095@)Aifoc#(Gt@sve=FEkOa~!fy zti_z^Ut#l%cd&MkJ+$?ms5V?YNwB_Wg7q<6c@GvlZ$YqLS%u>43BmHl#^;$}ZFByS zV6{5!!P`%~4(|wdU8~B3+G5S-Yw+w-A0RF<N9e(N^tGkP6$GmqC8rkQ@h7GuE~%7B zY#BzXYoLrZ!>12Cimj$`7|rv;ckjG{_1~?-{Fy6}7##<<l?$+B(JFlX_M7<LG8$ui zlwxtYaJ^*bBamXHhy9;FiN8KGAE`bznDO|%_|BLKR8JSs#I9XytFFdbT@?m`PU4Nf zK7)gH2_#q~SR`1)&xQ;6+=UZiLF&08!MdfD+<6{WTXHh2jEqoGRdrSK5K0tU$eL2I z_EkPL&i}%1fB#4P;SayZ?|(muN9MpjwUvEH$soGQ-YZ_o-Ob%ym~@)=UR^e~W|CmN zzT|uK7U>F$^5UAqsjgV@*#E}g-d&Hz@@6PP&*8m4{udT(GDCMs1xAW<k#uA+-u_@I za?*1Vvg$4T>xub@i_HZpicn_00r&sMU$9_@hmeEC1#7|4Kq$fuvE=m+Va;Smkh6;O zIP=kcc>a_9=q^vg>5m`5C);e;d-dpXKY*wH{1<$=&keG&a*URwB4qP?y!Y{UsLISi zz_+hnQLyAfW&KiQ9$$=m|L|u#HFFM<m_QBse2)cx{J;3Wf0+&!?_?$&ZKyQ3C|IhH zV|ep{H(}wOCWHuMu0gQ6JPzT}|M)BBZnDBaSrs&yfjIEN!+3h;ZuC@?BWc^G<APNo zh^!=34<A4HCw#HX8UyT_juoaNVABWq<HOSs7*oQoO$J=ovfuysN4&9W8(Pb1P<CcD z-ul1)k3AF1k($cHEI$IL=Ddkjd#oYmqd=Rhk$rd${_)Veh>AZCyU!lOKc8HTj6~gN z#x8#YeEr5N_}(lMgHZ-}`)?#zBv>R^#LqX>Rjf_pqYF=-Jb9rvi$)8QVBIpo;vZtX z7c1Dt2F^}Sg4zFU9TBz@ji?QwHV3g_-W+`X`3%gM@dMT#Lwr>~H1eyft;M@_vvP7^ zcJ3UyQd5QeF!>b)D-K8A`WK#<a}Yg6mAcC9g+&;vu0VsuCfxs<-(dPid&sH^5r6P2 zJpHFX;nnwM;_DAy#v}JXhE)d~AS$ngCea0J-+cuCc<>dhm^mFEz48nm_}$;Ic!wuO zDt)o|&ws;5yF7v7Xq=w;Iv%+1Nz9+S0E^y!22Z~<9oFtiOgi%5yXqDE>3<%?x`USJ z&do#2o=@@EU;c@A-k*(S@4tkH?|m8vPJ3g79gpj>$MJh6ELHhU7%Tp9@lP!iqW*y6 zcz{nq^x+n?Rd-@E*%{0J&SduK<tXB!Q{RlzGc$4jf4zW!q;eq570aLfBmVl_3^;m5 zB6|Jnxc7-AC}4s$T2TR2ng>=s^hbQM-X5B|iXY@)?Zu1#{eSWFD<5LPCo}N*^Y`KY z=jOvNNH>ZwZ0+0l(^GSim0k&ymSDKN5Lw5+##;~GhiRY8!SZ*W!Tk@th@B_AA!kB1 zR#k#hgH`x9cKn}hG>4+O3u52Hc<z7QgWt_Oj^5%bCa<|j-oFSh-uq7`yR)!r#=Cg- z;pebvw>>1)HRumC#Js2P!-J2$h!yib$J-D71Fz0nhn$RZNJGBIlmBr)wp+!sYfpkj zf<=P$!x44FMJB?9$;rurSWU<kT^k)FST|X)grbf`MHtG?hP|O7QkmTR{4C{zLUB=r zdKg#yH=>1H2peAIB%57bFlGDC^!3F^=}$DAg~d#$GLUJ079RG25V7Bt6N%zQr5G(t zMXccw=$~;xPa%`Bib7Pnn!sSwMjYF;6TYqykeBHSS86J&p-vBh*MV&~vGouVeH^j< z?I-ZX0dFP>X^1*?8o|Et&{R}Ho0EvBa|iML#*O%X=Mf}Fq%qkj6MEVP;{D;ca~sZ` zwMJV$FC?0W68m#F!}qymA40uipswHrICD|zYybx{XY>@5Lw%Xj0!l8HIdKTze;9#| z5s)!K(&VS%yx9S`*!y9qs2rNoa&(2-!S#C+RAunGQ3a@RF~pfI+u`jIg?b+gxEMI2 zBd<tTkBS|8oZd-<c*a6mcClxWzt<n*gJ2U2lmz?1br(OkW5|fk5^9KPit|zHVF5=& z2ejoDkBe+EleQw%dzr&{GdsVn`w->FuF-fgP*rI$L`ebg+H(X6LCH|DYp2ePLGanV z2=a-AqPT?JuVRdp<)Pfs5a+gR#L<o0;BFrbNh!Z3x?-&2M1Qy)+=^rDdYhcKLPJi8 zFepHj90bo}=a3Se2@O@AC&41Y5*o@0c_3-{F%vmh6P*XdMff$DYWZk)oL~tf*x2iJ zv9ZuUc@la2!;P8$brl}Hjv37R2L|Bk=7wN9J0WEG(~~^wDuR#lysOGGT?O&U@A2y4 zwd`utlncc~g=*-P<MS4B*gDF>64t<{z~kEm_-?y7l#LxgcPsk54&$}^AICArM4+6{ z(RXn!LItlZ&bKSfe^>{MSA^%)&Xpw<y4S1u{C~QAj#kx<?~|=lp*v2#>@YtTww&(R zE^~fD1@sc#dX-Ex^Yeu5jn(jxj^pPf%tcrw%ps^1Dx4SUw#(NkFJXc*X)eNvit4p> z7b>bxo{NwdTSZNc5K2USgD^mV*X0r_uTP%WuyFG67Gapbe&PH|FBJOJU8{24>wG)x zITI?p^O2erCFAov>b7xVKFJ2%xe3+UC*-fRV*Ge?)#ZoBtHUdJ4`zKW#!6`JL=r3# zEZ#73fv9IKKw@Gd{QUgj#y(5k-Q5Y|ituNI=Us<|g&~i9M)PM$HeN-51nVXUmQX>P zy;l$%48t>Lke!<=EPuVz=Uff^LJD%_;(`EMTV2CibSru#m>^UZqu}gnym|jWFm1*X z>|H(^Z$9!UK3jMM4SA(EV8UpEAV{!oZqF6}T+hzVhJk^BuDnf33Ub+JcTP?YL0l33 zjAUkJB0M}C*4Ea7nD_Pd3C|M=)=dyB-6*y~440Oolv%CmxpP9nPd<f?bo`><2&tO* z*2O25=1KL|>{xiu72mh|N_kf|OR~xfQR`}eV{4XU>+-K*a?S~z`K9A?7*YdA5F}Vr zSFm``RROz3`uh4PWuMy<)4g0Ql|v9$hCeI(8RDb;ot>Qp$(jneS$C{pO~56qB{30> zMn<qOGZRK)h{wC4ueV2Zy=6d@&lfhV(%s#Sbc3WUEhyd6C@CFF=hCTkcQ?}AT}mqr z(p^ixH~RZO&-3N|1{*Vb&zw1P;yTx{%0c<MGJTXmE-59`105xzZE8Uo$ZpPe;C)^E z5z(19Dj3R?Rgl5#PuZ2S?%yXCe0O&TY5veU7dFSyiuanV7vK;{M1Y4kw6J)Mcvra; z?mU1p8)$l}qxR94Wr3fTot=HNcFQA)w0NF^y8}^7o!`pA+c(8a>GWZ4b_U6~k0J4j zhhN6Sp$0QS4PUv2OB{GGO_ZmDFE%zo)z#IQi#H3gE3l{ByMh3vASk^mwCe?+BbBS@ zr3ub9ub02`^tLp2-~N6hASCeI{&|;($lTl-7Zf5)1<2d_6Z3puatymDS5-(k1s)Cz zhN9xUL-o3du|f?rxKL@oB*r}g5qP#{jV>m3b^>~q3~;2RAC#_5tJUAPva-_VgCXFl zvuoj;^q$AoaAnJsQZgd0xwxFvd=G>PP{jSxWoKCF*4)xFv!Fd#S_4r0v3jgTVi|sk zq~+(QIuIDHKR>5|Ljq<1pbu}lY8o0kFgYoeDJuvbh4TUK+kt^#*nJI@*-dg*HXUJ4 zM&p{9l(@i@B1W~q;M|x{P5jywQXikVpuj9aF6>Bq`<+kxktmB=Za4Aa!Pw8KyuTP2 z*HXg=rFw8kbTH<dR?T-0J#+IDA1jI)!YKa&>tDk`G~}uZN&qOxb1Kf=UtL2(+W(T7 z3i}*+=SOLZSt3w|77pZ2D+tQE|8UZ4Wru`?(RMY575|Wyk;zsc4xF=L&Q`KiPBru| zr>`&CPXN(3-R?7BhjLCUN9UATtJTX>;(aq*GVdB58uo2Z=6<&*TLmnujYrpdT#fDM ztW7K;I&y0%oRwV+uTzhSSc<WWwH6#wW=};2&cf7Dm9vwS(+4zoDNnW*136511gfu0 z*+x08??v7P!0b@$40Oi8?isOu*8wmyif&r0!69E<?UYdST{gRKFiK68isFjGYdRBa z(Q{Q^n$rfvFit0aWGDwwkM@)*MH&W*$Sh8s?iZ>@*e1$FsQHEK&VuNPvBSK>XptlI zlYVNVz4m!v!)DQ6d`<TT>CaU=BYhV&fN9`{4fio|ITgbYGcdRkXTO^%)p=6sN<sW2 zmtRH|^DfYT%JVaNv1zMKf~>Iq3mxjgP}$K^59X{GXUfG}fUSByv^<sHWCWlbsc~k$ zNH>|Hp8@es`r8GY%vYU|c{a`wu|6QzkA)9Vl4nXne|)K(%WF3NsX~;Qbc-<H0J)^k z43?yxX=86=bTUrH&RN8T&5t*V84C4Z;tz!uLR7nFEru|H-pjJwy8pu5$BXcNA?E30 zEyVX_0sT73I3&)}d^%tdwW=%OJxR62IaMPqABe7`bAer~JK(xK<WeJhCx&q<g(M6n zmEY(m(E6li8}=SqC`&mc25b9OVGLzs+Mj*f;A~sbUu;6&qI0$$<Yf&uUDEaA89ky! zL~(Dkr{69sBmQjrRb{b3Z(WBh(V~R}QFGEnOt5)n$(fUzv$~20S;v1yGld9&s={<% zW`=wOyStg#*}Y|K2Dcys>lSiU|Cxu^H7B=@{IYzBaAzMRp~tGzf&hm^bZ`iAlt)R? zS)Al&1lgK#-?fpo1uPAo@O1xBT<Li!L;-GY?6f<kXECTFBJwg(de?_}YyB>*dTJ1* zF8v3JKb_G4-}GG6Vu__1H}NlbN_D2mm8ppSSq-NulaflSo>e6bV#~eB*%^kAj6kGm zLtBKslG4CS;zbWCqZ$S*G{o(x`5%$X75LLN*H)=59KEJW-Q%$YI;`i5!8Zuj%1X-7 z&5NO5^tIn@>SRrRdXoWlM-W`xw=+FLfj<1QGF&@EX`wM#jg0O9N!G%m*~4o+>?U$t zpalOaM$`K4fbb(#XVujXPTzZvo3Ix*r;UoJkYKFe#fv>K5V|@)+;F<t?NvlX95fQ- zaoV6M=HHacK#In1yoge}`f(aTHq6d$+{yF%0f(?iT9x;#2ee<9=tq>(fnE!8%LgGU zmQezaS)g*q@o@*oet}>K&%du{%ul@Q1o4BE5%)7Zt(S~S>t2GFF&lNff_!K9sGUQ% z?~p+Y2thu`+Kc!{XJiB^614hFv@iRL2+f*|2UDz<dX1ZFM(1#My_gWYc=7qj{_Vpm zqk~?1kE5cP-_lWEjQlU7T1O%UP^<k}2s0Nq*V?glXtzGvrg6Pu6TCz*zLwc4q?s+< zFcgfTZj0urc+kJD&RlIdqY3@|^IDeeSjuhwwdd9H2-xiQ6${kv%@ye{$imN+p4O%M zqJtUG>k_|}WHPA34O9Ixa@nFgW;LCNQV~Mznmwj%s{o3D=joe2Kp#Gg&y_(k4rp;Y zZyaDEt9Ql<?Vq@Tdd~^bfe4~-BP{jdC`F`GyzYd9N#*rA@=9BQ!0{+S(x-I^&l-jo z@7N-9cv###ILG_uD1TXqEQ2is)7DXxdten=jvxx<(#}O#`0rPuk>6wy8?W;-21);b ztdG(*X6X1~EZ@E=PB%IEeM!CiIF3)<uBT0QRq08-0#%bp`Rq?%un-9K)-zZBts2~n zjx_whx6!73Zn%}{8#jH9$e|Tncyx#R_z6a7nAWw`@RXeg2Ik@9<jl{<$u9;+&R+@> z)*b;7pF)Z-bM7U#JOU3dAL0#VgKdZsGNc4f!|IPohXMVW2)aq%pX1nM1NhPa60D!1 z$j*v<<DRvM1FidRL0CFCOI4;vDzN;;*}FxZp`X}|`)d}!YnPWH<%a>%j><aTEPw#a zP@4)Ib&o`Q2SzePZ}bj5XkB&Hg8$@t6_F82?o_L5Ina}{CgUfyuku*xs8(H9Vf|nd zRNkovQZ_tj`xt4a`(#~b807sl+*dhyR!L;KFcAy(6>qR#{P8O~S@bJ6BUAb*h73`G zRDdPQxY0qnnUXuZSg>mhf$J(=CEe9h1}5ol@SDF~1iw{#E+UggmjxTg=xuE5S9xBM zG#*b82^b#)e64>Ohmg_Jis4FWYezVo4d45V(731OO;U#)oyNEq$+34M_Ch+1ozOk{ zpQK)6Coo}H#XHh@DDmvwY?i1wg8suIBCqkAypJrVAHU;<h}OKA5V^%~|JVl4tXbAM z%xhKsse#i$H;D3E$T4!)-u|IqbuylDjc$w&&eN>i^X=Bv4DpZGEfhEUiHOSjF*ZI~ zG#{??`*$_WGUoU3+yaac%RH22Aw}v6)re+9nWPqQc74UmdKp*B;_&3*5cs;&tNHJT zh{NvFC%?IIR?_5skxd9o*n@jQVHgd$erW55AH771L*4~b*Q4%nzD>6Zj{NLrP7rOV zmD^p_h*Dj!vL0X?-PP4kjE|qt?Ic<+9=fx;Cz-R2L|B0OR{by_(#*s+gXKWT2(ms5 zFFAkEpN5C9W@_6rTk9KH&N}M3J~d5eayEt7a?FYuKZRPMtA}(e@R`CtsEd<6miVG~ z-y~fMH%QHdaAt67<!3;<UzZhT86LEs7SB_0N48t@XTrwaB-h~dJ0l-LGEhM@Cw@DW zZ#FYrO1$wkzUOxYb!(w=WwX<J1JVBKPM!kUw;uCGqo(_2E>T=v?j*ISG@NBy{_1`Y zEB0L_{f6DztryFpo3iupL3K)J_gpiSIp|~kj^Q0Lb9sR`MlPt>Q%kX%<0AR3Ww^KW z^#Jw`iN@paJ{%!-{qU-4M#!(~?|%a64+2VzS~kzvi6?EKJ=tK@$(*mo>wUH3wRf)> z{@TH!Hiy{Ci&(Xu-XbK?&t@kNDR@xBBm7=xIgXsKS;GA&sU1*KcfZ}iu@UhPfjC!W zBFHP<-i+>+G47&dr}(Ly55FW%!ev39jp%N*g;W!dB2^JS&<Iu{Z*9d7M!N*G2QVW$ zs2Y8@LefaekZ~*!!S^%?DOo2xn6H7EeWWWIy6W1+k-<vV4zD>wR_k?Nje!un)9EEV z2<a*4v$C7!!Ebwq^rKvJBYaE-Q<W2z4yUZ$iMec{GP<glCC!z;b5DJRrXpWcHmE}d zT_biMS-8%DKyZ<{%C`R%i%?=2PT7^fsD}krdo-hr98}x0$r?uZ8;VjqnJ?Oi=BlYI z-Qrn#6#!y4{5l=z@T3ZUXxlm&W|6X~!I>4k#JE3%B!}3lby-ZDgP)ujrGsR$c367q z@f26(6IBc;adgG*2}v%!V$<VaO>oOpU&%7+SoKsvzY$cQMPU4>tywK^z!{k(%+4}E zUC@gO$X6P~BE*Fy=m2l>M<5!2ZG^hcKCduJFHkTrF$KQ122N1{@v52zB|l>fQo;}` zPT75s5$&dPSLfg>ktID<uBnG@IQduk1sE0?X4R%$ugd0)!sdIGNFT4P=4C$jc(1%F z6Fc;~^=6&U_01V1I~KiBw6<dp1`swM7sGsil2rSaw-~O0ST<RbqHlCRP?buB9SPf( z;ppoE7>$(`yI~^rHUQs`dG;#u<kJ82vV9S`GUD^}K(gTisQ%v7EOs#J(^J8hD#S3z zadJ7-vJ@s|h6@*g$atpLJ-nfdwGN$$_gLfy&Q<M&F1JfGvXR$`{M8*O4T;59p~CoV z3ikMTF7o)85_C>Xl^|b1NFT?<QzT#Ctxw|W5}mr5Z}uvD5?hvs*t|L1&}ouz`OO!l zFe@VuW12rG+s(K#EZ9>MJzfeNdg$Xl_hk5tR)_s=b4%T)EFZ7%%9eiH-_P3z#ye5Y zY-4_a-+r5KIxznWQL}W3L$L_rq7_+j#z>mRZy@l8y@L-VEl<&MMeMYFYj}gb#G5X5 z{h}LLcfRTO@0<cv@hYgO8+dN|H}=|VXa0xd`yiAAopNa;oU&sK^1$Fwq*hjz)h{+5 zFkv|_t0o_89oAu^$T%U%?@w5<Sg2T(D<OVOG&Qwc3k{ZiUx=wq(HOo($4)7uTEzi| zvP93OZ*XqhqO!SqS(o9+(03-ayQ7|Nb%xlPY}4cLKtU~scnvMrz;bRD4u7n29ZfA& zYO}AM`XoeMJ3ApK?b7*%zc!>~rD9%BZ|vKBR~qaEy@9O7Do4~j$bItkVg<<Pa4lJd zL|q~m+*Rr`Tz<HNjQNEyhM;Z{=5CD<BQ(F*e>J>g!vZA;W=}^|78>1syZ;_j<=o4K z7o`3!+pb6@H%NyHOMjcUZTdhM@&oa}j4cgk?rm-Y$~I%`c*Po`kc~cpLUwZ_>ha(z zZ`~%g3t60wd4EqyfTviAQPBbb{FJ6veap?o<vq%jJ^#AWl`d@`x=%wxyta61Wmg!C z=;k-Io&zG(o~J2Sp!J+;Du)f<#z93zr4(X7*j81I{hAPj>!J*Ji3Ow<yCI4SQXf5E zdbT<mnjd+{!^+FLnBAR(v-!qWhfeN%sM9Yi#VX584OZ-54EVart;KWg*n0E32YkC_ zi>bYW(X>9E{3@tX1UCH1D|F#03LX6faR@*$?^H5r0;L3`k6$7*8UM6t!-`|7;>Euk z69v!g?7qyQ-ZwJb^BRF=?hp?@u!M^!{~d!#!Eo{Jx3WL4=vh@|EzwN8dQrJ8NY#Y7 z`3}Lm#v51M-`UZ<5_fQHD9A4vhKq@=!ySCm4EO9vy7+2RP!Pssx9NqSRPE_9Y2ir8 z1mG|kT3h-ZRgAyp%{h@qob5y2#hLr)-q)-Qi!?jtnc#NFY(*jjmHzWka*px!*;(~> zMiDiH3}vPU8SN5=ybv?Urb=SU?ndgWsjY39B>c*V*^p{@`fyUD^U)eLf<=%0&)dJ> z``zT9&nztHznLRSDrDiinJ39uDBCS$i<z2|VrXv8sDLNoFLjR%_IHz%gas0512X5K zw#w#8kb?uDJ+D<rW136$<gr=|^Rw>)#Cl#r-kXHT7WY_)n8azuiI+cKo>vEk%_)?z zu(HO+$J1?=#WG^f{qpF0YN)T5*4NKCX>cu-Mw^|PS)aBLfezrJ{9NCBj|HG30lyM< zKOqZ?J{>KD)ju>DFC~RI+c>hPQqMQeAU7?I6yRFUYHrp+tebR{_{b_;Xh&Tc6AbSr zN>RyWSG&EEhKS<g;?mhYOiV6b>_4gyKS}v)%hPH#U_P!HOmo2>pRf=nC*^+sE(wKy zwEAOu>UG}F!Ni1IP*4yO8Y-@=jK##nq@=I^0aFYqbA*eA24;MGyn9+QGBT3iixL3< zK)b4HYro`1k#B_dqZoCyx*x`U{oguNo1St=8(MRINaqF_dy-nkm^QHFIpo8K^M|!o zZ?<6ykD7e?Bn6D@^8w&AURz!Dg+jqpzddU+O&&k_UVr?QSGd+|Ap#D{L-84Dr5#rL z_TR|fkr`#5DXGiJ2NX$qCMFQP+S>d#e;-T^Pe4%ICORc&ZbBuuT8Nf=__5$|khOpC zHqrW}i&fqyCpU`ntCm4UZ|~f(h_Ir*nMGpZ8Wf<Qd{F-1Vr$-?yk|NHsB^?bjZlb< zi}Mwo^|k9-iyW#<&XjsZ)gBYwFHs;&%BO6aS}_(awg365%)yUj=U778UGU;E5~x%N z==CRGJ7#bVdxrNsOC>KHtd+4KS%wgHh6)Ofm1~l=77gpAa7rpMmDxb0aw+5-TK8@3 zm>#T%N})U?uLbt-=$W4<l$Mr0xxSXs)lF53^<nz3?8VTT>A0-hS1DFGy8Pn@%jlMc zi3tJ>w@e_dI(4CjNd7y{nE&R3+c)O?p={)^)7glfG!O3nvG@`w_mB;VmXVMU$tx4r zWZVR`&q|Kt+vm#k4#B#uZ@~k_ACP-$Hg!Ecy@MMI0IQY7fl0~7=b~aBQSmFX@rd-% z^E~-QN@{9MS{f`suB5df*f}_i<{j%cSgee+^`XF+OX#0ysVY^mk$pnUei=Gu1Cf!X zFH6(PwJ}04!BN%H(&<^~LwkJb=l`Pj8B;BCI<h*)$@!WH2`TjC@)DAqoUCNy%kZEW zah8Tz;_v@zesK}`Y-@X)p)4^eDR5q(Icm;v>85C=vy<}bQ#VY41|Ns<L{o7-D+}4f z8gWwCP6U1SfF)CcArL@&K016@WfW07n-t><2f7|AM(oC1x>)Y*@ZOvdz_AVZ=E_1U zoV&IPob5EPjWyyJR4+&V0}(JO!-ouziUSus0s?y+Ns@4NU5xqC%7iJ)%fb)o{mU>b zJ(E9Rj>KQvorUIFxwBSn&&7%i9Elg7L^8cKci_$8(ha<45|tD5d4zOlHz-HXR5EKF z==v(;`(gV!s4+VsEPut&X~IUXSA<9pMfnkv0nPz&6RT*J+s4<4sQB$P#GWY#)oxGs zelNSPp2RZrQ+3eqc-|8;R2ED^+`x>CWt2Cznk71-u`gDZmSBLGX&U$UKr?gtnj}<$ zI?z0y-iB2R!A)dO_qoVv+RC`fWhqjECzx>k_S{^n2@@?!E{0KtQuFsFv_b`L_br;v z_<@9sF&VB79<T7T7ESd5TZLFjGn9cU5v`^rzA@R)4#I!<FkVzq(yU~;YFQW@i|A&L z9G95bHNH%K`{x6qVlfu1*4%kcwuf{4_11^2S)_!?@I1-N9-B=7vV5km6*;c)W>aSi zte60r8{x_M^mcBf&qs5}S;WAT2=Y!#8f<G#7`CQ-1@yT%kWd?+RaUqNlVe~N;zG61 zq#s^!gRQG?vet_{(&}eBk_hEY-#NYHp=sVA^fAEXD!!-@F(#O!Xsc@f*b^Q4CE&|; z_nRWTjbAY+zqSV4PDy2Kn@zESOCz0LtM@Wuesld>%nF>UE(IZRDwU9sJR*XFa&yKT zD0n`G!R-8tscGKE=o=U<K{)E-BF%Y%<K%2BpKFJGSoywQ>5rj{$+p?Xmo9N_cdtsy z9g_$x;EZDBJf<=+qnE#azW5ZJ^Yizs^hddap4hfRWB(k(edgfF#GL?iM@J{Rc%v*f z0ujy|Ol~BS(I|1n&rLSE@96Si#tz!-Q2D~CNCsuLA`+F3KX&#;AVq3KJx16$=_F<M zbR+9kH(|a`s;YhnDXp3M7U#cw0b5T&a<R!PUZN6}iSUiKDMc=h@Zq)5ftPB1J8LsG zGL;Iag-S7H$>3W>(CgdOv#C#g^~d;8e)@2mJqOTFFod#3+gg)>?f$Y$Z=|>0=9zvS zoQUmC1omI*_sOy-6{!|oaGNH}I8h1>4-aZO*&)GR<in4lC^vx8V_9(V7bY%lU@iP- zJ0yYV1LAxRgst>tRf+pyf4Vtzi8Q0292o;id1+>yhBio!#jh!5B0rGOtK>ZR%kxZ` zHIw6<i_#m$hkGyF`>jgGUu&UM3xsjG5<5KezBxWi!RtiaO809{aqUnJWCP&{@}kL_ zQ|CBOlVM5gK)GLtw2{h;UJv#>aD1R*MnKf$Il&zo!CN}GVo$j5KC^;$5hiG!fWya> zt0c=2CVni!c>j>8bg{;Q>r?;2SrjhDVrD}`)B4MMc0t8*nJJTrEbur1WAYX4+2aXp zN#xgs+qVrpmbj0xUp$tb;yk<SPe&gZ^}l0?uv#((2~9QbIpYdL;osqpzTJ(8p1%=| z2<urU{Ay06Ib5tv3xv?u;nDCh&)kV+urPHaYJ+C&oSkJpeafHQcVb=Zw8CO#`+|qJ zW#{11CFdod?V@Ug<J6{oNvi|oDRinfk?BR4z8|__Kx}O!qv0_JNDXT)P>EIV0x{DS zenj+FK0@xzKIhVO;HX5B>Y<k^U0h#JE@t%_79hQQyd<=={>hoAVZt~^hUfD{hMXbf zuU|CPyiXJNrT()&FUzL8T*|uA;}o+wx>b;hD4UkemQon9^1}^t5oaVMkSy5R6jKjD zROT^Ueu^J91cZ^hDn=pIW`!=vMAS<is&t|lBYDY4%Nknbeat$oMF$c_m7M{|l||9u zD$8UVuy@XNBJWoo@zoh5IP)eAi?~qLEAP=h-MykDSI==C!5Mr&5vnM%l$}PtfRIWL z!C+*wHKve_aI|PlGXf_R|1`YEj}<7~wFyX0$50q^dpQ?}g0#o4Q|67xzRSTQ5OO{= z#KBwZ-_$0ye%=xYpV%D)teQrZ8cob)Ue?)`jPe%^#!d3#N#B&YBQupv_&>Zc@_SQN zJ4kV5uKpnp6`w<f)0D0@&&_2^W#&#HjGjIu^Ja8$Ce8N+^)x?~FBV1VwMt5HSjeeK z*Rlm7V<hONWU2Ow#J8vD7{TtM?z%IWa7R*WwcJxP9HaHa_4$q8HRYIyjj{6}Y31zd zVI0#ck>d~NO3<@cPFJ-kJI(M?>^_jFc1|kNVt;&*Lj3I2L$sY^vbQ76{7S9e$N?a4 z!WQ)0G4rHT)OQVy+}b2JQ;*NVBI=6vxspaaS!SHBE+PEeetbj}GznMDIW!ameP`R* z#?jL%BReGyA$)lk1^dCWueo`6P91>l8ECkR-Qoe`n!VHU#6OI0^LAvp&3w5I4^Q!) zeN%*&La)3>$(%UZP$b~%aT-T2PN$4t_A8G#k#lTfZ05<PeH`4%>4BIOhW2x;(A*uD zNA$j9a)9q=8fjJ|HQawD&G$?ZK*zB`6u{CPF>8=NV=Gz4Qy+0Bptya}PiSt@6B3H) zs5x0)jGo@`f>yXnmhoZ&1aP=IaJL&vQ;o6ZV#kiS6KPTF!B1iS+hQOy1cI_lM(=IJ zW?qGLuxu=nMrIE_u5dlBS0t<XjSKy|2FOmH%J9mu#CeScqrN%fYXbgfD;roJG;(xn zVmxUi_<nqem0o>Dd>u_qge~a3U&FgHHqBW-3W-lra6q{(;1&gD1)iOrkz9~|HGIJC zQZY|1`kw37C(j6m;;0?|4jpDqRc<mNC~4OX>wdb&DLF)@l;S5Q;O^2n7LcntP`bJZ zH<vA!nwxTCgxa-KAXqtR?Q~g+apFi-9?wA#8`^@uZqZ|+?MrXVkpw8;ZpxdZ+cq(3 zk*h25$YkBuAt>D*S~%Upn^0CFrq`#&Jgts~`(Kjcl<iTVBzT&}k$vMH&bTKS=F1ds z@Zq?1l%KMwL4~k;g^atfX{}`K)Lrhxy()>t(!-b?0wmU!`SuQBs^&^BuFM$^R(>c- zop;thh-f0mDKWYNAsiI=tinHf2~^1?n&GAXgjdyNCrs5w%!OgVp73F<zNNwuF&9>| zu(o`Og5cA;?SlBTWAa?q-&xPUZ-gP_U7PY_<w{Psu(~X4qUCf<&0KzsAkX*>!`X^R z#N)CH539$~fdA#Rqe7KCN0N>Ix(9_sqzS$xF{>nAc9A>OmJ$4i5~qyQDGiDWiDr4L z+Xjm*#os*6BC%|c0diE^hwHLDDGp$~!9;$7!V-V=pxiL(uAu(zdBfsBkrCc5eWQq& zK#E+SX_Htt_;ik9K1?=UzM>xzl<Xt^`19xF0@{UJC8#U&$xnyGrDD$rHU2giz>eqK zOQQCgAb+=ZM|D&5jHn-V0le;=(<R7yaE6qGHI8YIjwSAML3-mbby@36d1iv1A^w*P z6FW3aOvEB0OAW%LVAeM6`+4vn7p(wn;W%+8D<j@6-j81{f`sdH*nmPH!O!043?6*g zS8(Dvxm6_|#6!-0!H6+;*=#HIDB>ga-i~YUk62JQ-Yg;UmYaqG(7ILG;rO9wtxZW` zOmLz?d~M}O;`DbD<IN^_obU}lZifrzlC_(hIwjMJ7b2XZSHusgbEVrGYFzIV*c1>r zr0T`iv8cb!fC?kRnG*j#9q#?UTby?tZocDu&2d}A{oTr2U41e5hX$HsKi4T`w`6jb zF^*nm&Z3M{#4`$SoKNxuxlTvcaUIv#XU86RUuG;X;H=+H0m!QyS5fJqGB`%>TdFuu zN74tcTqSdl$<{4(+~p^MFtPNWs|O@x3LjE+X(LSL;Mc;>{06=1S30MdsRm9|<Age0 zV`J&OhR)q09Ynb>wmd&h7o+Oxc<r2=0yC;v{nzE4jU?Rp<f<xMF0vG6qy50PPV}4N zOmiQxUwtc`j=9jt{<T6b(&r5H3zX8dgrikx-(<q0P2bu<N0c-$p)h@iX3B(hi|q*! z)DqFIGZ%cs`j)h@qkf)~tAjf8IqT;zESby8oiCO$wl1{rdkB<?&e;rtgkJIKAUQ;P z8O~->)=3-Fu!=xz)C-;*hL~fs7wbW!PViDDA$lPrNYNilAw|_M^sYWPUrr<%6&3oC znF+wR%<S0fg|E*gX1$>y(ff0tC2Y*e_~R{A1g5pj&%HUN8W05;(bNtPueg~fQg5q3 z@mFGrXFcSNEcz;%;3Q(iA|Rs}ho#IqHZfIbtJ_bLjL&pnG(7(Er%&CzqpzeBj%3*m zKE0BYdIziv*N~oQL8;bbZWBUNA9LLX-p`rlz1>{mrTvZLU8Vx7scj$REl2*WN<B>r zJ<+)6lm>F~g=|XMI-Mo&?<NGLg;w)d(hCljY;xbWsW)e4*)_BYn7T`y@32bxOPzrs zY7J~erP#D{6U*2&qcdSJsLp<1v$ILcMBC8jod{Oi<|}avCK<K`u79Ejp(h-94YyD~ z8!p@3ex6Q-mb;V(!a0yBKjqlioxQ!lFamG}&+GHUpcvRnwVc{EGOV>V0W(8*nM`n= zrYxg1pghjkK(r;H(wCz$O3=MRMuP@;x=OL=b&T2U+|Ry9Q4YwSN!(o|L=uTJ#+zaS zWM5jViY!$ylD?v72od9pMffiiPKk~7h8GM1rMN8X3~TX|ZabqiJgSKKZeVbhU!BH% z`0gPldTV`EHYzXg3}{ewVjf;J_68J9rWjag2GmUap(LB|*<%zBo+0{9DjK07Z*bvq zwoH3Dee+hcghP!m)Fsgn^@5o#-6SShehX$N+)2vAoUd1*v1mIC2-<`&LttbAf1oH6 zz2~Sq4JuB~=MapUOIYV}C=8jwNKQ&%6%oPvj6d7m8d|;ZMR3YGs|qOA7~30C!B9*w zbo0dCD!%X=?}^q~s@Bub*xaB}6cw+FBYyi=L>M&`sKGsPAEz-qD$S`(@yYP|hzs=@ z<HLkB%De?ac`!&^TwSZT`EYNg@$D|6BrJC^!`$Yp#N{WDpM7e;FtU$FQ{j$LEyb5c z$e8602rp$`)X^O{&flzvDII~Jkr3~#?QGHp%08Hc1$LK6jj5q!JVP`9g$GU6XBKr} zqpw8@!ndia`YvuH?nkNqk;`VA_KIXGmDirk0f3Aee`do~iyX7TbEtjZPat{te2EAO zR*5sy+MB757#$NK!O(E$<>w=*a0-{<g*hPaQk|7bHQcM=b9q}gJAO4-dNb5-G;(gm z#lsWQn<r^Ro3H!!tKA`#H*X3s(t!9OtyUnVruGaM5YO3|j8)~};*r#`<gyB}RMu66 zgoSabX~Y@udfp&kiLnbTuB?dB(S=i}0*wKL`rXyy67@FT>?Kr|7fb7XK~quvnq62J z9B{CBBeg|Us6iK3n`QPFlLGks6>J?GVbI@vY16g6#g3n=s+<EL=?DttdPc@u4r3>m z7w-?V%nXNV^Q3o9lN}&Z3!DJHrMq)dAt~lIF^#!H;}4&WfZHr;A=($a_99I}XSs>L z{49V2sfT{-JXH3TIu{gn;ZV&{X{ZBm>nOjLvHpM%!J4kDug~`ht~9R^@$;-r$jGkg z0887^`PN*R0k`)d*MbYQF3&9Nzg;mj52QULd0B}QufyaIN#BkmV6l?175@r8nvN9o zaZmV*hXJHARVC@d^Yq2&7m<QiL+v+Us(jO!KP0pOJm@*T@s}cn`oGUUlg<K%$Nw3` z^Y5*{cI5wg`T39k^Uwe9XMi{Uef_`T{~P@8%m1imfM3-jRV5j7W+p}5J-Ir;&YmDk zi68pk<p1WVpw-Oj68+B4pIcsvAtA=_!I)Fh>tTn25Kx$ZM|^&Ou3IdH0$MJ-X_19_ zPDjDn)B<s?0)NwcFDwrO!*$otS6?%*=Z^&8GDnF+;%mZ>-?Q9t`%C|Y!UFOMoQYuM z1Vk<fHgP1-gZl-%<LQ!zt?^CMdCXh1WJ#a{CR$xeSHhI#w32LJ4C70;NPbbbb($T9 zI%C{-^lI3H@k~oKsF4~l@gR6k;FLYfJTT@QVuCCx98Ojk*sLu54ofus9IdQ1t?Kj} zM)e{G99M++qB3&f&s2`>pA#nw7tx$POZL5UAz25Nep>|ur`u1DI2oQ+d{Ke%Mp`1i zJQLhnO{<Qh&;wOZJ~O(qoN#~@NvJyH89((b2!N`KB4E**P*)9mQ}A$k40hf9pruW0 zyy4$)I<X=e{eISM(lXVkYES+CG&EVjW(^jhM<nTL^4NYQr<U=U7!<VO3jT8(ZL+5C zNIO?gGvJO!?z1ZH>DGyBgI=I@*<}Jf@3HLyIy_l61^z#iq7$&h!Xmp7SkJcl4w#X? zjWmVrWNdaw<2a1QFiuxTrwwD8&lE&&*!-+;Z*}r3h#@ltvRZ(J%73$QzAYLc?jYo0 zhA4+#Xg|#RGJtrg#$>5F>7f^AepB7wC_m!=nP?oJB~}Z)iIzfW#S{Jf0y}$#kut%8 zgG(tSJ<}_&@^V~4kWKx^BmHJRJ<a48b}GJbfY^gQyeHr|%-k9F*Z#EUE5LUsM_yE> zS3eV-#x<kln#S3#XX`cbX~h^haO5b^_#bQ0bKC;WKR)0~rEoAE{p-n+O-wm;LY(;3 z&ekR^ix~LJofoe@l=m^Sw?#Fq+`OpWuI!#eS?TohfnpxTJ20{%YKVL{A&!&TGx_t2 zeSNH9rQaiyt#i%_e|@(@%pVSam+<HRJJqQ_9RxIs`T$YffT$-BuC^(f_%_p_hf{bE zuV`;)xAnfPe0)H%wjVQ_h{Dx*k#9qC3iauL)1=o56J+<i8bwVixP}QcF7r7SZEasB zu505ORL@o7gIg;PChsHt$@AYK1SG^p&OtL<82Up0b_7N%cRQf<o;FSQM)2`GL(C-A zL{ul7>}2uyF`|#5O-V&R3Vd9fbUD3ZHz7jNRVoe7ic_SR=}sDcK|Q7KL%v_Q6g?oi z5YU)|yh(R!yy8z_H_`D#Udzh;^7(8(E05>Xovjcc%Mt`yjK;m|fnIDeoOH|E8Xv9a zC*2&O9@I=gRD?pz+b+R3QwS&BrMBxo+4*{uY}rLU9R(Gzbva6`12)Eq8n3g>s+U=? z@RG-qo`!M2XMLI{e;81zw)0-{O}OKPcVGm|mfkCi{GIl{iG^w=i!hngWG9yveN$50 zovzSwDqBd>MIJEappG;k8AlPz606DSDU3I|^@XMHuiLd=Df?ig>{(4s&Y~pyix}v! z76BK;7Zaf%Q{)hLp{eDmfUXfW=Vx5?e+skFv2YkG6oQno<sdp#D>>NkHAHITRlj%Q z5ailag<j25`?1~JxW??Ysr9e!%}EIW8Ng*^z?H0)1gq1X5dW@MZ73bkVb993QJ2A^ zz3%_YgmdaQ)l%&7+V5nHO(=}}uWCx-tDH`f&-_1a90VT_$J>q49rhj~KmB5|g#Q;Q zcl~CF$AeBoRS7fhjZ}3VX4JbpB>?U1>3)sNFix1AlVd!Ltf6i3`on%Q;=pk9&4&(l z*9-1#vf!%CcWWaGHf=$Fl}K3&kdSS#V$<9n&ybe2qohIX68Cdu$)@T$IXer?SZ;dF zs+F%$g^Gr{Iu;dAah~p}cx2k$4KlR)f<z-vV5%`3vyw&kFJNwiS@xB$bBLcjJ3Cvc zR85HqSE&mA@q<*kMm2mHfsKs~BXepqRd-GfHQ3!fr?OH};E&Kv#_u6i3@hc2YA>u9 z!~l!%Ke$T^Eb~ioaq$B|*?EK(Lh9I^C`k0h{?3kXc=!l#-vLPkCl?pw0Z)dNZ$d<H zcimqTQ-M4ipoM3b09aAzhl+v}yWg_3*hnoChYgX2_C%Zieb$@(-wc0u^}h>6w(4xJ zt{cJ0e*aQ=2BonE<GQMf!<@&m2uz-!;x>>oWj?vG!ag{nM!*8Z%dbA7BmNz%7#ZXE zH0I6oe)Q_mYkjQvG17+^!W!tI#3bzhvw~=4kTi|2CIA9~`}*x$Y*JE4U|^t7LS7!N zq@-jgkfZ?^$W+~Nvx|$1?aJ<xjyFBH@Is@bWj=o{h=IA5r~Rkp%YG?UA*T*trcVVr z!WW!eoV-<1;&}B6rZSciiU3O)^FTW2J^SFZjZI3*5-~31YO|MU!NI|S`FFFt4GOS@ zKOP+(qDcUaO5@@XGXWMmz?yPRHk8Vn?OE=^`%*sE&3_2Movln)K_+&G`^%o-kce%_ z`#@{&*OqlUj9zvvaTcp<3f`mq>%ZT4-rc8s=<^U!U!5R1Zd!M9hl7LrH)5&b8-b?W z+_u9g((#FjP=@@%ygW)88VO2PRy5!V=im&)fS#v7UP@I^au6;&nA60>1Y**@4A?l9 z>&>St9`5c%2R##=2zXAet|)Hq5D4Voz_o^T4Ry=0xns}=3roxHp>GV;UUx3@3kyg_ z09@Gz3Wa_oXf+EV&`2+#xuBO83<?ZH9B^;jCc?y|G_<k`FV}4VIz$=lBxfs!ilH4N z9qsL5yTAD>1hQ2}^FiOPne2#=F)#?uzOJvY2a*Sc21N(AR>X%chZTE{r|rMtZx=nz zU;m1UhX<)Oo6v9k?CMU0{;YL?D|oXSL$^Kpem`)oD(s!De{L;8v!GBQh9jG{EAdBs z`k?W-TKvJ889a1!bVfEd{PE--l0K_77fdwoh&gxtd!3VyrT6y$)kzqG6+a)J{-99{ zPG&T-2=|=OZS?c`T<60tYjsDv>%^nsYk4p8;g0v4)+7wjJ~t^zI~On(0p7Br($W@_ zHHVqszgg}_d(7P3-R)dl@byz;%3A8?Ao6eojE|@%98AZ%8+BvQ<NMnaD^~_F60yAc z`m1JnmcLoQ-v$2hD;z9?@x_saO2%E?i&%d&(C5%~C+0`tfi0`5tM+SaYnyCb-aT1n zUWT3uDhH#Jbpy2am}F$Ew00|Ba{4CX!|@1Sk%PA8jGrDKKziI6d0q{|IAWfn;7~ZW z70=$CI#G<j8`@B8czQ^WchxmIj0Cx9D#O|_TB#SR2ymIjbV6?8B_m4*W&Buz6|-IT zJ##?ulx+io12r`@Y=LOUPE9F@H>Xp68X6k@m};7uDEVYg6OsdZNIvv{9}<YUdr5ow z?KzG4`;Y&pPse_HCGV)jf+k?V53)y=P?0oDG<kXX?Cqf7P@7&g2320tL6RdNDGmmM z5k=fu_XK<*x5<|dCtxy<LJ4A>9UT7Z{YG85(wdxm0xw@20-WxqqO+jbM0*ZyZk+C* z`)eUOYk}BaQO=wn06ibHqoF}FMvj;YtZWIcr2o(R;*H=(Tn^}|WKeW)adN^1nKd;v z`Fs8zH|hyB+1~C(i8+g5q#!Hu@XmKS{!c1_P^`D@Y%j;d!GSeZV84Wgu(g2l@VW~M z!r5=8jPGL-S*@@zVhy2T2Tl|J_bbKbr;|jA(5R3Q%z}Znr}G%%jz6kztOuhbDQFbu z|IEza6bXoaL8o{vxAyiw@dfD7aQM>FaK~km-_KO7^>UuN!H$iML5#ES=bN;Y1!7>s zMZf>6C`eIh)5e)g4n}j6Ls))sK1re&m5B_zM6=pRdZP28b@Z*i{xW2lr8)Y!F7aQv z!28`QDvY{QJ1UAVgt)jDrTDMYg#|eT1hfR`MFnFfm}Q@T$iMp=c;wPe`(@o;k1FsI z%W`gfMn+T@z|*GOil@R&<<ZKqBZ<bYsHkY<o?85)^sgcR&&|}FkKr$By?>dhAEZb- z7Ou8@;K|VbWf^+r1qg~TdxWCCh_XODz`6F<4}1P?u7T#K%gp2{8_oq#$su7=*W8{U zoVCuYD;FxBp>Rk)kX&AS%hdAr*;#nLP*@3Au=0?3zv~>*nXA1Uq)oJq>r(+b3P;*# zM-n3wS#>gmLnPrNtI*(jB?1W3E|w`*GSiL~%YQwtE^*sCh*)jWD~dbPbO(K-i;70) z;o$Ji%%n(3NjaK-?e*8E0^EF{-i6K>?cznsutSW4D3X13HRyfbd?Pq-TQf^0$Nybd zk9NR@18tB>Im96g56<Eg#O3Ow0&gh<&p8?>$Ml02`f%thEB{`~MGo&)l8auO;F`f` z<oom%4KFW(b9tLWf3K@L%vdD`#=<EVQY*Fa#7y&Y$u7<(YH+TtnHfU_Itvq1^JJ=& zisb(uyOL6iIu;jM3WbG0)Zgc>;i-3p0{j9)6iRv2avcplq&Vsut%D!5A@>E16Jy5` zBFDdq)YhMGH6+gPK5|p=coJ#7@BRti&1E;-F?bRC6)9OIG@%FwdhK!4<s;mJseJhk zmAQ9A!~mJ`j@jP*@fa{WqgU^IRR(3$zrh|H?ToEQ(opCPN`PDW!wK#;(T-=L4pNgS zVuNAYT3cbY<z;0t!-AJfB;EhX5J1D0iCZR3==~@_?tMiPh)X~%#z2z1yNzY-18e(m zs0emBB2q(R%2FwwO5P8P&Uhfu*YbSPMU=m@bMW?y5we1dXVl8W1Khy{OZVVBV+wWj z#`4pR0o35>1|HoVAM_^Y8za#-|0rRDQRv81m#z0XY}8HSlCwW=Q}x!@-kzZL_IA+t z^v(IUk3&hy&{`+ZxD}-j<R%bf8{P}}?*Htq*R)!<nIe$w!gOhFU(PyY%P|gU$GfL= z=$!#YXP4}ioXBtFo|}mcKi8`q1wP~m^T0!9UK8JX0+$uh@Q&7IRH8PM9aOOhGXpo` z%nx^%nLcI_(z}S8DjC7F(s8?jtv9C%t(Sv1^T*ombI7xsL0?huD839zcnVt&lAMN` znV&h_yOO`!>;oMh9<uZN;7RiPKR=C83!XcpyVjOMB3=Wo$^2fV7`dcfjm6_0%M;9k z)$=75{50gV#+*tTQMD!c?W_csn0N6T+Q|+@M&DYJ#zjAAzlp8asOUV#TKRP%b)NAH zOM08LM-XYo(;FA!wB8&BiXIyb?6M&v3G(%gH+HRM0UaG;I=Z?G&Z;PFs(|7FF~&wq zZmzvu4(~f=zts6hDGPuK0CdP5WkUFfo!z1;*w%`05t;S0+r+0owhF%p_e@?I?OpN< zR5b+SD=~@zojdC9bfkR}?B2e<5o(^-v!(O983<d1lgXAL(c1?SPOZ#;M9w&nX7PYV zNUW@&B^H1#g_eN<1;mSmzUijPBM4}{e|z;yt*RIM&D|S})Jz}JpY<|XrSl0$vj)}d zc~~g`SdJD^!=MQRzyslE9jk;zL36<;3k{fB%u<6D7T`k?D^w6<5XP};r-&kD1cu`- z8v)?m`|L!CfpE6WLN2(8CghV&{|Tu7`DZ=z;j@H#5}pOU@Ptl!X_?1jT;v-*{sh>6 zWvH`=r$AhCRnv<`({P7fZP)Fv8)f1bQe?dk6Yc1kOj+E22=%=!@Kj2<s+?zq(@-q~ z^TsK-DQLTHoBESh#6%aX8X6M2{r)Lt%m%NoEiQ2nl;W#?$<U>?<IY^`7bdyXfd{F6 z9lwRhDsI{c$w-1!vVGmbsKZeTp4V$_VDn`oo?*X))i#AH{Q$EC4(aBfRTllaTJ1)7 z_+EABQ>?j4Y98z72mldby>fva02KRc6@OvSde3ox;e9`mxzcSzBSE;cyLNH<pv8OV zeE-lv-rL}gM5x3>70=mxW^cDU0=+XiHteyml9ZI{UOFKB(|(EgcstAl#lL)&t22FT zGmuH)jXy5M^j0XObK`g|!{d>^eSQN-kiPx69*FUDrfKc`+Rqb+Apl<1^P)E9!pe7x z7X4bQ_2A3!xYBMtSq}%F<|m$XpHHlpD{6MKP@+62l$jb&f#;Rrv=v!FtmuZ17p|w{ zEywF)*Jj2)k!0$Ry^GWw)&e?S&m#ULV39C~kkaVD5o0TyUdh*HQRoH7PGO;{K@58e zGrK6ukh#kL7g+<QKd1M=mj|DHmrQJATmQKoLKQm%nX*(l&36;SE+%~kA;mt8;fOt< z)YYKZd`p$dLy>KsqxDC!Cr5rUK|vwB=ZebcIQ(^C$p0Qk6)qfQMzUf;N-{CdxDl3K z`di|I^4TTyE{EcgErkbRovs51h(rBddNO(~So<YZbWo0xI8}?lYk_~SKi_APPN{rl zs^!Ant1*ZUV~o#4(b<1Y#InDJatJ_w?iWeVf7PMGeaEV6g6eQOsaSD-jtXK?&CTV( zal@<IA&|5E<)Pp&MKS+;$u9|aVari|8=-6`$`+b!Jb~Z6vhtMzIBF#inq|GU!o(X1 znuQy~2dO??tI_RAH*Z^5|G0kZ?N0%K-J@3T(Tg?{*|#aNYY#D8Xr@gWJ}gSFdj{gP zi-BLgzLbao5QX;w)jMXDFa{r(lE0H$mC2ZnRS7gxL}A^;RGG9+8Lf=yr|!2#|0oqy z{AbgYk<e<jx=Iuf_gA%I)ZxvTQ+zc61JrQOC4IbB^Xh~|M1Cst_}KIDDOeGxrGdt| z#>KC6t}-<2A(&IEn0Y12vL#$t$w~enSOZnik&CsG6r&Y~a>>cD>czOq{Nk=lP<P!m z=<7uQ2rlY@SJNh!2(Pt}r*@=WtF>DsGIBn04}diSb=Ncay%QRp)vPu7d>6+Ad9aA% zGFoDWv;%ExWPgRP+V1-L+cZ@S1YeUE^Gue^95e<)4vX-b_x2oI(CV1zaG5TlH$_w% z`yqKs(Wu-n*U@SSON^E{-$`0i(7d&JhrG_sO|`*oZRNZ@zp@k-woaX$a%XC(<Ib70 z2ig9Ucske6KsoBp@BI`VY{zGhnah-H^UJ!!)9zJAA&qB;!f2et7lF$KFYxD3xZkJ* ztIJ~TFIVtgSbm7|XlUl@<^)O81@9otnb_SgqDPlZsvAHS|5TuKzt+UaWt&9`p3uoD ziPrN#Yhlx2^>Fz<S#;w(S@U2;iDR$)bw2|qU+uc}HE(zI5M3exxp#DY?psyRE9|qg zEX;~XoommJXVwuwX-OdXzVXK6$LV%_N5$%$(Y}3GS!J=&_E41aCC+vFvkC?x@<BjM zbzG+c>q4Wj>lVuA`7lEc%}|t7@MNKu@W&!ei7F}KX>7X9%F4$0+U{aX2iwU{i#PTl zu~Rf8Bk4<#<6udp9JLz!6g0zi;jG?se1czg?*el{+PZdx<y%(rVGVlws}yT{pNU6@ z{1M4KmJtG<tk^-b$0k!%OOw`yt)yxYvbxHMJAM6@t?j#v1WSBwtsqIPIA=)sg|C?t z{I_o`u;3P|_EwbPF8VylASy;$tjh<k3pF!JN=ihajtA3%&2d!WRWCMCN;uByo*{}^ zCYT3pFfao*xe-BXI~OxK!!PfJt$<(?bzNTa(!TiSzzro=3n^amshz9oz+q-c!b`f% zwwaL2Q!_Lp5}{>$+MA{>26_~|0PG81f^KjReA!YBoQA%>-D%|8PldP-pQz@)+wpxK zOW_S&fG*SFITRRE1t*vsIdGdYXs@-I5m1$>!^Ib24S9>6M1K(X(!|)~%3a$g^BvtI zM;%!-s&<1H6~d3EUWo+n{Y+;((&T(o7C3fQS>@fr>%rF&c&_<zXA8@3Ma9{N##mT! z?H7A{x5Wx5J5iN3!Njx*-i1Ec2umlr+6ZZwI|qx1EV9$rP_hs=mqiG*;;7o3kPxJ4 z!fAZ}fSIh0R$WApPh^jHfg&ZYO7X3mV%bmGe3Sb7+#k@>FWb|@@$@RAxqe<s<oGWV z2TieAxqKLYHXja}?4^|ysNm~>%Ieb+yqz)y2ujOiJ13kui@cwK6BDrxlVOW1-Rv<x zNaH>GFBmaEH~e!mY`z;JwY_*}E+dF#;Y4ahz}{OTG0S)ylf^%WbZ+1VcdYP)Y_-kS z-#TMe?YZkzR;yqP(trf~JRZO~CI=NO1hl_mXnop7sGb*iMOW-S-{K`y|K%6oI4A7( zOl}Ju8Uy}l=N*OOKusOV=~6<^$%JK)M(JA<3&N<18+eba!`@q4zSXo(T+MZsA$Q0| zEgQNl22F4zi9V5vV%|j23M+nbCFJyQiG0@B5aL4!mKOh^b}Q$#35(thT>^`qKVA5r z_5G!z9aSE~<KXM{sfp`sW5k`|>i%EX5BMmTj+1JHAsa3A?*;#)S4FZ0_=jqKY89ym z+C}#<UsD%Lpv5Z;@ASFd9fB|8`8jMK1+BGPFy*fns)Kwm<r1t;{(RRwy;;AUZ**gx z^}M7*ZyLyLDMgei^zlC)hs%{;LO%ZDcrx6L7E<<ku9=b0s!(x2hWoSOOn;=pi;Ebw z8H~EGE2+v6QTkyzRKXwL_||M{1qT1gE~dg6*Dxwde4Q1i(P=kS3+-7Ela#a)EBpL} z_5^l*<A1iea0MTeNs3x|LGOeY*eOhj<OPGhMuc}g*J<+P4p4bv>t5bZ2`~oh0PQl$ z#U;W->dOuM*%Pe;%q-Eqndf8viGPh}&WzqS<W(5EfMSlPz_H}AHb!93Clo$wvYXQf zbvU&2JiTEd%$v?;7(uUm*q|Eam+L>N!bQ532kNfd(J~_}^KMcN@9O2Q4Lj&+NCc;n zc7xR^d?KRF#(Rmqzo3)Q<bLSQNcG00*D*QQ6sq=_`0QD0$$o&%l%-TUsYe(f!K}Gn zTCQ8YTS^DM8)G=>mqwYs#E_U#MM(TMQVpKs7qCl9FAPJXKUOFGUl#6JzaetfkvdzD z&+}aCjT#IEG8Aggd2|u)aZ1s6vPP`NPe&Bss#^06cAK{mwEuLJ2v7)b&QjGnS+Y<I z_sbSGE7Pe)lDiBrXAKRGgg`jNtI^G9@%TY}$b(@Ut3;%JSIT-6ee+deyx0eeYV;eu zL48n{2OXC5b5YU90|84;|Jz9ut?CsNiEeTAwaxxdTA#l4Xs96@l~M#%$Mtl&{gkj{ zDUvV=WR6Om&(0}EO-PNR$vmuOgTmreIu?B%k#kJ1z8Lu;YcrSC!h$tE`z?9_*=WHT zWWu<;HtL5TC`3%%to$<G6f*!Dt^f9i-C5@w+Ub*uM1Z_cD8M%ky?)I&ZN7!rEa#UK z!)x}S$2D$Qi$ihkETK__w#jY-g2c|>AdHMRUfsr#YgmX8(E;}$geYP?h1PmcP7KFq zT4v!iyZ6$GYG`zcFfJH$*l<BIU_=Fi+vx}=%5FoUf{rVA{G)1d3w|N}IyJ=fp?G3? z5H=O3ms&0k-I`8Ve78+YSdRVeuY9oAn$EmCLf78pyH-9&q6iTj$~6@8yynT25IqtL z{_b+u^$0UGHDY>Vh5D&jbX61XUJW$LC3}P@Y0m5rAzv7_WToQU)mGQnE;@xEG&Jmp zdc&EQiWhRdj8WGaP7g#bevH-!FFTr@Uy36FY>bvUuF7=5Al{HLH5qH&d$e}l4rK0? z)F3I304j=al<%HM4!*Na>Gh|`mg&F2kltRX9gDJ8Vu2-|N+$E)DDCL{o@`}^rw*Si z?XBJfnD>A4<YK=9fKY<2tp^Tr?Y*7l2*1E*LjUz3?}$@;S(WfAI||b{wCp!?XfD-d zeoR$;(&v=l(V}Yln@CsK^&+@MtE*NXd1v<_CU$WX?+1yGsyQR{3}Km)VX^b^59P=? zT+bz#SGts7!p_1c7p7ibt6BkV(@4?}FGFes!!AiilWJbfh!0eC33{|@t5g555#u9f zFbd=iN*qa4F&~IA`V<_IO|BL!LnH7S-TD0j$C6DT6FKZ*MSo~Kx1BI0nvKVw|F5m{ z4r=0$*1pmST?ic{D7`8u9R;Na2)&39iu4kyG^GZJQX)k_YA7Nd1f(Mnq!T)#0@9m+ z1O#d7UC`e<@7%eWO#a&0%<g8tdvc!7a~^o>MgXNiGP>W0xp6tIC$gnH402=qQWjjL z$qZu96{2@<kjSOrn|xU-{pj3~TQ&Ki+8}Mp_>lR|{q?LHsy_RX0#xna=2;?5jIRy# zF$D4|DQ8bQHqzYQQH)w=Mbc6WA-tmuV3Ay=Zx00-mW}gjnp0*oC<}^;bh!x&>&lsF zA3m)LHO0l78q)lvFU7A%B+S=QG4gxRNnAE~*sFK4z~8P^EqY(rS>Rp_R>t*{AFYn3 z*&7dcrH5wJnLmD7k1HxfG8j^H%9JtGIH-l;n(ngC*hh6*ri)6&p`^@lSgGqoJmsL| zsGCZa)+Rk6a`C53_xeRs_{Txssawj1d3UCSe_hcj&SIY8PZOuI^7_@ITBq#((n2nl zo%BJ&{qBf_lw?Vh+&2xEx9bALr`xXVq>HROibf6nWUKxLm9M3}HsQm8<Bjo6wHoi; z846^l@qpt>=x{YfZOkvG9PrzZ)#hJiMg;P{=SHOkR;?3e0L|<&HYRQcR3Xf%j@Fm4 z)8?1S(PHU=v^`t=qM=l<!gudr-_ENnm-(vflE5HrEdDrgrRrHFc6XO~Q=bw)=Ur)g z(o#t`nb#F_)*qK_sz|A!!gW~o=SoKWruFx3v8vNpDd*-7G2)+qu_d_9!Cm&YhkG}& zgN_WQA4$P;g_xqgx_zifD)QXhl?~p*`;<v(eMmFL=WlB*Yx)>v_r&Wec0Egqk2&<} zI;>-x_f}-inES<k;#mlb6V&6hc`jz<PcZz%mzmtx<_&|1BiAu|+&%3WzxuAxhZ)to z67Oae_;MZC!lp2n8IIVyNOMFwi`#>1Up83dO203a+G3cu2D^%l_VJ_rtw+BzId!%_ z#VD*o9A7w(FnUDPJ!iD}lU^fzHtFEMew<p>Aquux<>5e4AGxn^Z+(=Da4R)gigXf| zO~JxSlVO5lDybodwq}bOU*9&_xjy;x^lTLqpuUyd5%g>SXgmKZR<W8gLhv}D=(<f@ zd2KVn)7M4S_<>{7hGPc(k`w<$c02uIbPRO>O=4yOygQF)+H;-AMk^4*s>iM8A%u%$ ztO_cn1x*STavPpp?H-izMofzk-%u^BHWZ`Q@XHYQp7iT777)+dzBm0-0>3=)ec_v% z`}$ZsDB@DZj~VqzTgSM!?VnS$5bEC<-c?u-DirzD)}><oPF1%gC8Mf;dj{h_dHe5d zmrH-0j(#1^<$CHafy<JMu$6n?75#mvyYYxRR={~aWR-bJ>_IH?w*$2CSDNjZSE$T1 z<;cI?-`N7q9evKw7y07-#DTA$_728|6=o~q8r3lJV&piTxn7ap=$snj;PG!a<Ux*w zc+=ek(yFbQ0RE03^{0X_vZa6t;$&Xk8%a>Zt+R6vf1GCc+{<9;EJYMOpAPn>I0$1r zwW})_ZBY&cmeW#F#=)KJ$rNfNrfn0wK5+_*nr;`Os-$j*hCSli)AXLV-3~2CB#8X< z04w*-lo|QjO{Y7&=uf1W_Bhvg{9UiYM1rMo@RBtusYqujv+Xi2TQ<zwPtTEUUD-XE zkMhTG2Skx+(oC;PTr#x!G0FXdzTN%XJx&rH%vlOy^hLsG)6d+?BE`|>bZags13sPh zNeL3qQJtz?U8OZN`(}q~WOD}jce4N<kQWcr!!P_&H$tXL4B*ywL=tOvlj|R2_&Zs6 zRZq6go{v<vWWqHd+kz3z={L5NpJBSw+zZy1cZHfC4|;QzXhs%xXhf#Q+?ctNaE+7_ zZ8$!}8i+!Kfb%RFc>I-gb!l)fSok%lL*q=YgZ9Vf?OfuM&5K8hCpKG&L;R2KNi$K| zKn3VjV=WtNqbW<;%!y>!maaG7e)qe0UGE0oFlN+{nd-^mXY#|$KoynF$!T)@BaRXN zXf&HO=@VY7_}BL0;?vLR^~#x3j5>eSUY_CBLe7b&{Mh{P4^R3g`wdR@HcChMx}PnS z5UE^F0p81|M1u0=?XH=GCe)9|$m+e!L8|9_;771IoyFk^FnX)WL!-}lqOwuz-mZux z>~;!s2-p^DPFbU{k2&kijEQJ<EGfI|>&ZB%<JMK2>vfpD^%kOB?HVkX&$?h5-J^<0 z?1LC0(LR{6>lBJnR!hgEU!z?x%&Z5xlgq3VDSphHtv-k^G3Lz0-2?Pw?@N}^AfzJl z>qwSseAX#Vhd?paGrX^_#zcg2G0D(wntLCeB@PbdKM`PM4e_vBWL?+PptMv|Ie_?y z^!Tt@e>5o*Qtkhs&vUAGjHFl-NUV0b6{T0c2pU-5tG(_uE775)A0x{K8=ZL8rqoC5 zl)-<1X@-I@cEop>j{PAMm_xzk*F}rFOvCeiV)6M#1z=6lvn_9I<ou#-{@6n{3`4}~ zqT8tRr`D_B0#x)VNst`up;_EmEh2NKnU(W+>!}1}K}{;JaWCM)gbGYr5(FlDUi)H| zfvjO$v)<V<OS=^UhUWKU^fW#EJ$2Ld<KHbJ*iB_=_E(3nyw4qDj$-Ovgiiz#i*w6# zyD@QE;tq$<!R%I&L-G~c>L}x2>@(|ruJ0cA(4&D6mM3#e4`?k02VgU(l%d9C4X#v; z%C}r1Opoa_ZQQD(W_!$P>}~MfSoLBPko5<)AlIfR;GSvttuG&EhzH=b#stJ-LP{w! z7g|-vt0sdLN)Wgk>`YaQ#WHiS*vAzdG3nIrNyyl+ib$H1(0HOMOvnmgpdNW{hI&J? z1xyE<7!nj$ako^JINdZ-&bL3!CHu1j%%l`L^c=mnnA@^jv@RRCQQ>6Ok_sbCIqTLC z{inWZA3|vj{6#wx6M<PHn_7xuM~5L~Ih-3~8;L%M7h(dU;c+#0&bPg2j(R?(Fn;`4 z%EH0|P+?d^M6}<O0z+7Q!6kx1=TR(sZ}pQ?7%BD)EevDwItdsUm-D&q=yKfwE^2@b zpzq$#eNPiB@(`^jaP2SV0rW6-EIT&0w~=*m9JtMlPFx@T)ZtE5t#>rCTy9Wo{;~wy z<Ft5No1rS!o)hj9`}keZ5bf{7{mondX=rp^vjV07WM1WsK)S$Wuj~iW=6pl~Hqq-$ z2MYk*cN)yBY~IMc0ltE95UkORFLNe->yk_$Qzsb3Didz#q&F=YX!g&bdfwLF$)mMq zVz-c|%hrz`yPccsbpNP%Wm$^)n`7EtA+%KbiPmxPFyViq9NFRyov;H9;1VTo)s<TE z4n6P6{QWcix5awSvs@{A9?r8UK`q`Ouib8y6Kg04o(Hn=es+w0Nc!8w0b<-J!i~&H zOiWCaN}{6cl(Pgk{B@_=@7_5H3_@C#RN$z6YU}e`%K;vt+|kX+`cHlC>(`){Q-{zh z!G8)TS@?Xok(m(^$dc{o?k3TRk4GR7p@gSj=feJMbv^ZqQt0U*_KRmXnU-w;T_fFQ zpCxLPb%BSa4ch<h3<8QhQAbHxd!P4f#1A=|oL+(>RdD;Acg$h<M`Su>=k7}&LX2C! zj{1cYRSeYQzM*Q;UCAUt9c4?tx20ec;YvUfybv8}AE&_an%`FaID1R<@&IPX9m#c* zp5eB4w`ieLxZc8_@SHafFVw?xGVpOBJpFS6qz-z0qNM3lA|SB+-O0apJaC~sr4Wt! zpgY1v;(D43n!E3L;#4C5?K<sK(}kLihU*b(LEZ3;?01rL`|_|0ts3k|<;y&3eR|3t z^gIn=68<d27)$V%uYe007F|+buf|_EB9N@_NZ-#_D=CF3uBHPL0~}r7s1fG3wNW4V z*1fTvn3~EhE~XRcLy3!fUr<S09eGii4RvFZX7Nw?RnHu<B=L_Lp!frl8<NueWFzx; z?~tSs9UL6w=I3jpvr0-dlV85f<+?*-W|pq5t*xYQLjd@I=~x+~LPIYBR7NK-Kfa>E z9pL)Iv&uQj%F29Azlgh9yV;Vm9X8dKE1Z4}TOf0h<C~tA!FJEFOdX1Dg_s=vq4Bg0 zF>tT){Sn&sLS}F)82vE+<Wu9N|9%9ECB)9knW8_q1X5t7lbypBulzfPva{Wl(Eh`) zdrvr=OG<$|RZv~uUR9R901y&XApHEymX?ZuWzJ!7>5_rB%R1Yu#X*^SnG%u_FVd-? zA{^H4OC(yP9;R}qSllh5L(T=nUVPYdt2{0`P6*2`XdwLYebL~2&;pY|Z0ONVA|7LI zyF4FdO%Cp{O}g|sM7683F@;Ud1G?1l_=XwkE(#xR#e{Jrk&a>!8;bI`xA~_L5f<YA zxab*ch@7Y%J*I&?Y!MN*xw*xl>;wis>Kz_dF?R+nF4@r1adt-v&?>gIA@+BpT9f32 z-7MgC?g`$iQ_{AMRD|9RX<ts;aUu-3HqUb-vWFdK_?7;&OOxEZrC=1Xg1P{UvU57~ z#>y2tLrs>OcE)`#jLPr&#Q`xSg0tRMl`59lD%y$xhvASg7|7a?KLIvD88(orJtAVV zdrj3x((>{<=+mX$<kWwDc>wBrz}}Vw1$})8{lRDzx+ZYzMwp<0fNEeMD{#T**S?YR z@u@wW^ip$}mTe**PH)U&g1S9{+kB&NNfnnq<pC*Zgn9BPS8LB*OE#B{WIqhvbiTh4 zSp;w4Om1&zS*C~`(2p?YN-(&?GL+B@4os4)NB+3rQh<;80A>#_8iqePYjOua4?z3N z_^zFkCRPlo;0?%SrH&4SpJ#M>BN*`8!=0^3wd8cC8;CmQBtW9S`*tY@tQQRhV+>sV z*b<+epe-Tbu4twi29U?QIHuWU?pva|7HRI$Xx4v^3UWqBdr-mAlhtG0;0bmy9xnUv z4{E*mQ4gLED!u(sHRWJ-<$L!QHdYAPNST<KA1u_iu|Ugb;omuVCA)r)s>G<f+*N)` zgJYuMDz^}hT=DA8DMyv8G;zM^+biG!h&n)#0&X<-;S+6oYXzk@{^<k&tuEE>BJs$< zfjoaR_({vc<|>IA(`>Jlfso01Msxe%91ZR%e)oC5nq8oRz9vb}eyXbIve=3)^<-T1 z25+YqL-@s$=3F3ZdZM-(7kzLvEML&0wv2Dm25h(C>W}R0xa7IRHIhjO2Swn{?!;OT zOibmDJEla~<J(ZXsKI;F$Ig&HC_dCaXAvr3-=8`e{bn||u!`gV115~!8E7`hKZs8{ zFWj=6%55yBGfDyT_YQwJ-q#?bponfRk{T@ELZ}WiMA`d=tIHgBWBIsE_!Vd~#>0TQ z7<OchFjl2JQLsRN$OU%yudiPh5e<7B!zZ;rGPWZ4C~0@5<=Ju)Ho)uH|7o&0G0SPz znkqghDK+&P!vG}}d3a?djm4}yk~>v(HD21mMvS4x2d@<x0u6&z3bb0pZkeZ`X+B{6 z=y}L_`$=F4z|4>fd_$X|Y&q{KbNZ)i5JhADz3ItG0mGhEqqhMcTsi#~>tc@(!5amc z*(kv;NzprhU^sqKO)m}3WY;tEjf$iSZkhMER)twd*D^IdJqW<@(Xq1=@bNjAnwygw zbp^O57e>$sb40+m886r88e+<np!O7F{awo6$9Y;|TWzbiEQIy$9>V}t?qYHVtjb@S zKVO-Ew30u~RJNn5lX{I3n%h%V^)@2EMlLw`EONv^IavPY&9TV-&n=yPZrUj@&*pRu zv!DlTP3dWP$S(`lhWooMT%2QL7>2+e|6$6IU(sH-A=eG`21P#(_&_`@FhWk^p4n$J zM_v(xvQCQuuyT>1PT!J>lDpPQocabh3UJ?(UuO&R%OH9Qq0C9Cs29al!rL>*@K-IL z8y@?MhSLinL5nEjS>*%<-J4=g5uxI;9`Xfh1VFerz*a$lh(pS&mc#U!0SW3h)?zNx zY;>709P0^t!wFx<oPx!hH*WCN$Z--VD7Fmw><i-*uF4k?@jQc1zV*q%_wNbldAQ#h zCI%JH5ZK*dX!qz5nU}G#Irnud?+r)mz0r>Ak!$o+;sOh;b{3sLuyLHKf+f|NzQ#C) z_GNR-S*Kl_33l06EbE7f)PmU8N_%#I_KEoT^&{Vpow|4L$a*Zz%;JIKY@r3m#|OF1 zt10bZnLhLJBh3z{Wq7Xnr%l169P5vR?Gtn_b$%lbQQ&7TBz(qPyv;_;n4WL<@Im4? z95_<>N~r!G?M!!gAqCGy3H+O&4Gl$rEOFAFpFfY=>;$9<#xVSS0bEbNCrg(;)ozEe zV2)emOa}4g_)j+=v4ap=UcaZxEAA3<9++qK$X3#_t=aVCMl5a=d>AjPT<Afn#wRT+ z-8nj{^yU%(B@&$Hs~#P3akX2KWgw%YDGG@J9+CFy)r5kA`vsZ0j6|XeB1UO7@wz)g z=yXWCRR-5J1?{xgJS)M8;`JO~Rb5?UVF8&x#{eX=V|dsj_zK*_Pk76pojtNI^cat~ ztph5^xQGk{HKSj4XFxjH+8T|^M+C4yw@XOUU#?aGVsi57-;60Od}h3*TS9&dqC<ZS zqe?aAEF#IdC=eP51A&~u{)QO5ZL@glgXf}5>SVTcgoPYUUyr?l6&rqlP%v~N)9dA= zl|4IG#dP=eV`m~hL!iWp)G!Z&U7opiox;6i1M%qU5$?AJVoy6X|6+&+{5u`F+)spR z8m)efFI8B%mbhysA<JcgDFXWUq?-tGhL?5TOI5xK+;G51L|W-6ebPlf{;q-OI`$Sn z)ea=R({p!;JVr=GUB6KLSPUSXY;^^<RLs-WrNu<G&NBG~ldR0)Nr5>);d%~jma*ZE z*bz$#wn=;)S+o*!*Lb0+H$@%qlwGRO`pn6hb5BPEIx`S7(lBFZB!nb?B2fyA_}yNc zAK3FfYU<=~{!DJ&;vby!$aB$D6iP7jBcfzkk~QI93Dv|wEb{Xv{h{SDY0~L!Xx{Il zhO<L{>&){N`mgKe!W;AV<NwvA|6yQ%pAZ+1iT`V}iv#%I+n!h0Hk%YLY4it3^(N%~ zoRD6?5L7nG9Ni?{DIH)9?BWnI<>0WWDnU&3f>B70-r|-0H4U^8usV8r_qxCUGb^=f zl%=EN`5`P)+ak~uFG(~|<<edgSE3UhESwtPqyxvu)pUWfb%tnqZ2&KUo38oJzO|J< zIw9Fjqy^A;v|U-)5j161mKRVr&~nTYI;`=UKDdRQX(6_^2inq7jK4qGIE_*UHQOH@ z)pALA(+&-3{`fh-_2PU@@r-VNf8+3=Z(2%SMpJ9Dw|9g~KqDg3pK1|c58Vk+DAt14 z&gh&<CG9x<qr{%~TliYy^K-Y8CNKO#o!4i${$0P`10gk|6!w&q^KVOd#VW(fwz9sC zrfAGH*=#*O_lxhqW#oOV%xDVKYXt?_rsnf~3)AO_W&VEJh$ih18mpWL;vsu!AxaAH z+}kmRCHJ@?0L0<DJIs;3Rdgq3X9KuN0Ye?|_FOvpbGcY&-GgmTlH(Ha(ooU4U!e>S F{~w1s(kB1_ From 32ce8b1326fa72f1b9decedf35d53fabfd60238f Mon Sep 17 00:00:00 2001 From: JoostK <joost.koehoorn@gmail.com> Date: Wed, 26 Feb 2020 22:05:44 +0100 Subject: [PATCH 029/262] feat(compiler): add dependency info and ng-content selectors to metadata (#35695) This commit augments the `FactoryDef` declaration of Angular decorated classes to contain information about the parameter decorators used in the constructor. If no constructor is present, or none of the parameters have any Angular decorators, then this will be represented using the `null` type. Otherwise, a tuple type is used where the entry at index `i` corresponds with parameter `i`. Each tuple entry can be one of two types: 1. If the associated parameter does not have any Angular decorators, the tuple entry will be the `null` type. 2. Otherwise, a type literal is used that may declare at least one of the following properties: - "attribute": if `@Attribute` is present. The injected attribute's name is used as string literal type, or the `unknown` type if the attribute name is not a string literal. - "self": if `@Self` is present, always of type `true`. - "skipSelf": if `@SkipSelf` is present, always of type `true`. - "host": if `@Host` is present, always of type `true`. - "optional": if `@Optional` is present, always of type `true`. A property is only present if the corresponding decorator is used. Note that the `@Inject` decorator is currently not included, as it's non-trivial to properly convert the token's value expression to a type that is valid in a declaration file. Additionally, the `ComponentDefWithMeta` declaration that is created for Angular components has been extended to include all selectors on `ng-content` elements within the component's template. This additional metadata is useful for tooling such as the Angular Language Service, as it provides the ability to offer suggestions for directives/components defined in libraries. At the moment, such tooling extracts the necessary information from the _metadata.json_ manifest file as generated by ngc, however this metadata representation is being replaced by the information emitted into the declaration files. Resolves FW-1870 PR Close #35695 --- goldens/public-api/core/core.d.ts | 4 +- .../ngcc/src/rendering/dts_renderer.ts | 6 + .../ngcc/test/integration/ngcc_spec.ts | 17 +- .../ngcc/test/rendering/dts_renderer_spec.ts | 2 +- .../src/ngtsc/annotations/src/component.ts | 20 +- .../src/ngtsc/annotations/src/injectable.ts | 1 + .../src/ngtsc/annotations/src/util.ts | 16 +- .../src/ngtsc/transform/src/declaration.ts | 6 +- .../src/ngtsc/translator/src/translator.ts | 24 ++- .../test/ngtsc/fake_core/index.ts | 4 +- .../compiler-cli/test/ngtsc/ngtsc_spec.ts | 176 ++++++++++++++++-- packages/compiler/src/jit_compiler_facade.ts | 3 +- packages/compiler/src/render3/r3_factory.ts | 60 +++++- .../src/render3/r3_template_transform.ts | 5 + packages/compiler/src/render3/view/api.ts | 6 + .../compiler/src/render3/view/compiler.ts | 22 ++- .../compiler/src/render3/view/template.ts | 24 ++- .../core/src/render3/interfaces/definition.ts | 38 +++- .../test/strict_types/inheritance_spec.ts | 4 +- 19 files changed, 371 insertions(+), 67 deletions(-) diff --git a/goldens/public-api/core/core.d.ts b/goldens/public-api/core/core.d.ts index f47b73703b5bd..bdb2bf34df06f 100644 --- a/goldens/public-api/core/core.d.ts +++ b/goldens/public-api/core/core.d.ts @@ -715,7 +715,7 @@ export declare type ɵɵComponentDefWithMeta<T, Selector extends String, ExportA [key: string]: string; }, OutputMap extends { [key: string]: string; -}, QueryFields extends string[]> = ɵComponentDef<T>; +}, QueryFields extends string[], NgContentSelectors extends string[]> = ɵComponentDef<T>; export declare function ɵɵcomponentHostSyntheticListener(eventName: string, listenerFn: (e?: any) => any, useCapture?: boolean, eventTargetResolver?: GlobalTargetResolver): typeof ɵɵcomponentHostSyntheticListener; @@ -834,7 +834,7 @@ export declare function ɵɵembeddedViewStart(viewBlockId: number, decls: number export declare function ɵɵenableBindings(): void; -export declare type ɵɵFactoryDef<T> = () => T; +export declare type ɵɵFactoryDef<T, CtorDependencies extends CtorDependency[]> = () => T; export declare function ɵɵgetCurrentView(): OpaqueViewState; diff --git a/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts b/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts index 746145f6893c6..25cc214d529d0 100644 --- a/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts +++ b/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts @@ -91,6 +91,7 @@ export class DtsRenderer { const endOfClass = dtsClass.dtsDeclaration.getEnd(); dtsClass.compilation.forEach(declaration => { const type = translateType(declaration.type, importManager); + markForEmitAsSingleLine(type); const typeStr = printer.printNode(ts.EmitHint.Unspecified, type, dtsFile); const newStatement = ` static ${declaration.name}: ${typeStr};\n`; outputText.appendRight(endOfClass - 1, newStatement); @@ -176,3 +177,8 @@ export class DtsRenderer { return dtsMap; } } + +function markForEmitAsSingleLine(node: ts.Node) { + ts.setEmitFlags(node, ts.EmitFlags.SingleLine); + ts.forEachChild(node, markForEmitAsSingleLine); +} diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index bde8f468a03f6..328ea2ee4406a 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -399,9 +399,22 @@ runInEachFileSystem(() => { expect(dtsContents) .toContain(`export declare class ${exportedName} extends PlatformLocation`); // And that ngcc's modifications to that class use the correct (exported) name - expect(dtsContents).toContain(`static ɵfac: ɵngcc0.ɵɵFactoryDef<${exportedName}>`); + expect(dtsContents).toContain(`static ɵfac: ɵngcc0.ɵɵFactoryDef<${exportedName}, never>`); }); + it('should include constructor metadata in factory definitions', () => { + mainNgcc({ + basePath: '/node_modules', + targetEntryPointPath: '@angular/common', + propertiesToConsider: ['esm2015'] + }); + + const dtsContents = fs.readFile(_('/node_modules/@angular/common/common.d.ts')); + expect(dtsContents) + .toContain( + `static ɵfac: ɵngcc0.ɵɵFactoryDef<NgPluralCase, [{ attribute: "ngPluralCase"; }, null, null, { host: true; }]>`); + }); + it('should add generic type for ModuleWithProviders and generate exports for private modules', () => { compileIntoApf('test-package', { @@ -1589,7 +1602,7 @@ runInEachFileSystem(() => { const dtsContents = fs.readFile(_(`/node_modules/test-package/index.d.ts`)); expect(dtsContents) .toContain( - 'static ɵcmp: ɵngcc0.ɵɵComponentDefWithMeta<DerivedCmp, "[base]", never, {}, {}, never>;'); + 'static ɵcmp: ɵngcc0.ɵɵComponentDefWithMeta<DerivedCmp, "[base]", never, {}, {}, never, never>;'); }); it('should generate directive definitions with CopyDefinitionFeature for undecorated child directives in a long inheritance chain', diff --git a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts index ac4294d51fb22..cb78fa5f42766 100644 --- a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts @@ -130,7 +130,7 @@ runInEachFileSystem(() => { result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !; expect(typingsFile.contents) .toContain( - 'foo(x: number): number;\n static ɵfac: ɵngcc0.ɵɵFactoryDef<A>;\n static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta'); + 'foo(x: number): number;\n static ɵfac: ɵngcc0.ɵɵFactoryDef<A, never>;\n static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta'); }); it('should render imports into typings files', () => { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 246b1ab0311c0..3568e4f20a8ab 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -313,6 +313,7 @@ export class ComponentDecoratorHandler implements ...metadata, template: { nodes: template.emitNodes, + ngContentSelectors: template.ngContentSelectors, }, encapsulation, interpolation: template.interpolation, @@ -770,12 +771,13 @@ export class ComponentDecoratorHandler implements interpolation = InterpolationConfig.fromArray(value as[string, string]); } - const {errors, nodes: emitNodes, styleUrls, styles} = parseTemplate(templateStr, templateUrl, { - preserveWhitespaces, - interpolationConfig: interpolation, - range: templateRange, escapedString, - enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, - }); + const {errors, nodes: emitNodes, styleUrls, styles, ngContentSelectors} = + parseTemplate(templateStr, templateUrl, { + preserveWhitespaces, + interpolationConfig: interpolation, + range: templateRange, escapedString, + enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, + }); // Unfortunately, the primary parse of the template above may not contain accurate source map // information. If used directly, it would result in incorrect code locations in template @@ -804,6 +806,7 @@ export class ComponentDecoratorHandler implements diagNodes, styleUrls, styles, + ngContentSelectors, errors, template: templateStr, templateUrl, isInline: component.has('template'), @@ -923,6 +926,11 @@ export interface ParsedTemplate { */ styles: string[]; + /** + * Any ng-content selectors extracted from the template. + */ + ngContentSelectors: string[]; + /** * Whether the template was inline. */ diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index 3f67fafcad817..98b81843f9767 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -274,6 +274,7 @@ function extractInjectableCtorDeps( function getDep(dep: ts.Expression, reflector: ReflectionHost): R3DependencyMetadata { const meta: R3DependencyMetadata = { token: new WrappedNodeExpr(dep), + attribute: null, host: false, resolved: R3ResolvedDependencyType.Token, optional: false, diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts index 6cca49f67bba4..7cddaae9f8d75 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, ExternalExpr, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; +import {Expression, ExternalExpr, LiteralExpr, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics'; @@ -48,6 +48,7 @@ export function getConstructorDependencies( } ctorParams.forEach((param, idx) => { let token = valueReferenceToExpression(param.typeValueReference, defaultImportRecorder); + let attribute: Expression|null = null; let optional = false, self = false, skipSelf = false, host = false; let resolved = R3ResolvedDependencyType.Token; @@ -74,7 +75,13 @@ export function getConstructorDependencies( ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(dec), `Unexpected number of arguments to @Attribute().`); } - token = new WrappedNodeExpr(dec.args[0]); + const attributeName = dec.args[0]; + token = new WrappedNodeExpr(attributeName); + if (ts.isStringLiteralLike(attributeName)) { + attribute = new LiteralExpr(attributeName.text); + } else { + attribute = new WrappedNodeExpr(ts.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)); + } resolved = R3ResolvedDependencyType.Attribute; } else { throw new FatalDiagnosticError( @@ -93,7 +100,7 @@ export function getConstructorDependencies( kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN, param, }); } else { - deps.push({token, optional, self, skipSelf, host, resolved}); + deps.push({token, attribute, optional, self, skipSelf, host, resolved}); } }); if (errors.length === 0) { @@ -369,7 +376,8 @@ const parensWrapperTransformerFactory: ts.TransformerFactory<ts.Expression> = /** * Wraps all functions in a given expression in parentheses. This is needed to avoid problems * where Tsickle annotations added between analyse and transform phases in Angular may trigger - * automatic semicolon insertion, e.g. if a function is the expression in a `return` statement. More + * automatic semicolon insertion, e.g. if a function is the expression in a `return` statement. + * More * info can be found in Tsickle source code here: * https://github.com/angular/tsickle/blob/d7974262571c8a17d684e5ba07680e1b1993afdd/src/jsdoc_transformer.ts#L1021 * diff --git a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts index ee4e47b795829..6e8c9abaedfbe 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts @@ -205,7 +205,7 @@ export class IvyDeclarationDtsTransform implements DtsTransform { const newMembers = fields.map(decl => { const modifiers = [ts.createModifier(ts.SyntaxKind.StaticKeyword)]; const typeRef = translateType(decl.type, imports); - emitAsSingleLine(typeRef); + markForEmitAsSingleLine(typeRef); return ts.createProperty( /* decorators */ undefined, /* modifiers */ modifiers, @@ -226,9 +226,9 @@ export class IvyDeclarationDtsTransform implements DtsTransform { } } -function emitAsSingleLine(node: ts.Node) { +function markForEmitAsSingleLine(node: ts.Node) { ts.setEmitFlags(node, ts.EmitFlags.SingleLine); - ts.forEachChild(node, emitAsSingleLine); + ts.forEachChild(node, markForEmitAsSingleLine); } export class ReturnTypeTransform implements DtsTransform { diff --git a/packages/compiler-cli/src/ngtsc/translator/src/translator.ts b/packages/compiler-cli/src/ngtsc/translator/src/translator.ts index a41a9fc8a3a73..a55348229d11a 100644 --- a/packages/compiler-cli/src/ngtsc/translator/src/translator.ts +++ b/packages/compiler-cli/src/ngtsc/translator/src/translator.ts @@ -447,12 +447,12 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { `An ExpressionType with type arguments cannot have multiple levels of type arguments`); } - const typeArgs = type.typeParams.map(param => param.visitType(this, context)); + const typeArgs = type.typeParams.map(param => this.translateType(param, context)); return ts.createTypeReferenceNode(typeNode.typeName, typeArgs); } visitArrayType(type: ArrayType, context: Context): ts.ArrayTypeNode { - return ts.createArrayTypeNode(this.translateType(type, context)); + return ts.createArrayTypeNode(this.translateType(type.of, context)); } visitMapType(type: MapType, context: Context): ts.TypeLiteralNode { @@ -497,8 +497,18 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { throw new Error('Method not implemented.'); } - visitLiteralExpr(ast: LiteralExpr, context: Context): ts.LiteralTypeNode { - return ts.createLiteralTypeNode(ts.createLiteral(ast.value as string)); + visitLiteralExpr(ast: LiteralExpr, context: Context): ts.TypeNode { + if (ast.value === null) { + return ts.createKeywordTypeNode(ts.SyntaxKind.NullKeyword); + } else if (ast.value === undefined) { + return ts.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword); + } else if (typeof ast.value === 'boolean') { + return ts.createLiteralTypeNode(ts.createLiteral(ast.value)); + } else if (typeof ast.value === 'number') { + return ts.createLiteralTypeNode(ts.createLiteral(ast.value)); + } else { + return ts.createLiteralTypeNode(ts.createLiteral(ast.value)); + } } visitLocalizedString(ast: LocalizedString, context: Context): never { @@ -578,6 +588,8 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { return ts.createTypeReferenceNode(node, /* typeArguments */ undefined); } else if (ts.isTypeNode(node)) { return node; + } else if (ts.isLiteralExpression(node)) { + return ts.createLiteralTypeNode(node); } else { throw new Error( `Unsupported WrappedNodeExpr in TypeTranslatorVisitor: ${ts.SyntaxKind[node.kind]}`); @@ -590,8 +602,8 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { return ts.createTypeQueryNode(expr as ts.Identifier); } - private translateType(expr: Type, context: Context): ts.TypeNode { - const typeNode = expr.visitType(this, context); + private translateType(type: Type, context: Context): ts.TypeNode { + const typeNode = type.visitType(this, context); if (!ts.isTypeNode(typeNode)) { throw new Error( `A Type must translate to a TypeNode, but was ${ts.SyntaxKind[typeNode.kind]}`); diff --git a/packages/compiler-cli/test/ngtsc/fake_core/index.ts b/packages/compiler-cli/test/ngtsc/fake_core/index.ts index 6c296d213747b..17ae37d6bce7b 100644 --- a/packages/compiler-cli/test/ngtsc/fake_core/index.ts +++ b/packages/compiler-cli/test/ngtsc/fake_core/index.ts @@ -34,6 +34,7 @@ export const Inject = callableParamDecorator(); export const Self = callableParamDecorator(); export const SkipSelf = callableParamDecorator(); export const Optional = callableParamDecorator(); +export const Host = callableParamDecorator(); export const ContentChild = callablePropDecorator(); export const ContentChildren = callablePropDecorator(); @@ -68,7 +69,8 @@ export function forwardRef<T>(fn: () => T): T { export interface SimpleChanges { [propName: string]: any; } export type ɵɵNgModuleDefWithMeta<ModuleT, DeclarationsT, ImportsT, ExportsT> = any; -export type ɵɵDirectiveDefWithMeta<DirT, SelectorT, ExportAsT, InputsT, OutputsT, QueriesT> = any; +export type ɵɵDirectiveDefWithMeta< + DirT, SelectorT, ExportAsT, InputsT, OutputsT, QueriesT, NgContentSelectorsT> = any; export type ɵɵPipeDefWithMeta<PipeT, NameT> = any; export enum ViewEncapsulation { diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 9921e67f1ab54..db54ed8e055ac 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -68,8 +68,8 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Dep>;'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Service>;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Dep>;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Dep, never>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service, never>;'); }); it('should compile Injectables with a generic service', () => { @@ -86,7 +86,7 @@ runInEachFileSystem(os => { const jsContents = env.getContents('test.js'); expect(jsContents).toContain('Store.ɵprov ='); const dtsContents = env.getContents('test.d.ts'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Store<any>>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Store<any>, never>;'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Store<any>>;'); }); @@ -117,8 +117,8 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Dep>;'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Service>;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Dep>;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Dep, never>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service, never>;'); }); it('should compile Injectables with providedIn and factory without errors', () => { @@ -143,7 +143,7 @@ runInEachFileSystem(os => { expect(jsContents).not.toContain('__decorate'); const dtsContents = env.getContents('test.d.ts'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Service>;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service, never>;'); }); it('should compile Injectables with providedIn and factory with deps without errors', () => { @@ -172,7 +172,7 @@ runInEachFileSystem(os => { expect(jsContents).not.toContain('__decorate'); const dtsContents = env.getContents('test.d.ts'); expect(dtsContents).toContain('static ɵprov: i0.ɵɵInjectableDef<Service>;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<Service, never>;'); }); it('should compile @Injectable with an @Optional dependency', () => { @@ -237,7 +237,7 @@ runInEachFileSystem(os => { expect(dtsContents) .toContain( 'static ɵdir: i0.ɵɵDirectiveDefWithMeta<TestDir, "[dir]", never, {}, {}, never>'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestDir>'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestDir, never>'); }); it('should compile abstract Directives without errors', () => { @@ -259,7 +259,7 @@ runInEachFileSystem(os => { expect(dtsContents) .toContain( 'static ɵdir: i0.ɵɵDirectiveDefWithMeta<TestDir, never, never, {}, {}, never>'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestDir>'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestDir, never>'); }); it('should compile Components (inline template) without errors', () => { @@ -283,8 +283,8 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( - 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never>'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestCmp>'); + 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never, never>'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestCmp, never>'); }); it('should compile Components (dynamic inline template) without errors', () => { @@ -309,8 +309,9 @@ runInEachFileSystem(os => { expect(dtsContents) .toContain( - 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never>'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestCmp>'); + 'static ɵcmp: i0.ɵɵComponentDefWithMeta' + + '<TestCmp, "test-cmp", never, {}, {}, never, never>'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestCmp, never>'); }); it('should compile Components (function call inline template) without errors', () => { @@ -337,8 +338,8 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( - 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never>'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestCmp>'); + 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never, never>'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestCmp, never>'); }); it('should compile Components (external template) without errors', () => { @@ -935,7 +936,7 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain( - 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never>'); + 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test-cmp", never, {}, {}, never, never>'); expect(dtsContents) .toContain( 'static ɵmod: i0.ɵɵNgModuleDefWithMeta<TestModule, [typeof TestCmp], never, never>'); @@ -1327,7 +1328,7 @@ runInEachFileSystem(os => { .toContain( 'TestPipe.ɵfac = function TestPipe_Factory(t) { return new (t || TestPipe)(); }'); expect(dtsContents).toContain('static ɵpipe: i0.ɵɵPipeDefWithMeta<TestPipe, "test-pipe">;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestPipe>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestPipe, never>;'); }); it('should compile pure Pipes without errors', () => { @@ -1352,7 +1353,7 @@ runInEachFileSystem(os => { .toContain( 'TestPipe.ɵfac = function TestPipe_Factory(t) { return new (t || TestPipe)(); }'); expect(dtsContents).toContain('static ɵpipe: i0.ɵɵPipeDefWithMeta<TestPipe, "test-pipe">;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestPipe>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestPipe, never>;'); }); it('should compile Pipes with dependencies', () => { @@ -1393,7 +1394,7 @@ runInEachFileSystem(os => { const dtsContents = env.getContents('test.d.ts'); expect(dtsContents) .toContain('static ɵpipe: i0.ɵɵPipeDefWithMeta<TestPipe<any>, "test-pipe">;'); - expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestPipe<any>>;'); + expect(dtsContents).toContain('static ɵfac: i0.ɵɵFactoryDef<TestPipe<any>, never>;'); }); it('should include @Pipes in @NgModule scopes', () => { @@ -2574,6 +2575,141 @@ runInEachFileSystem(os => { `FooCmp.ɵfac = function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵɵinjectAttribute("test"), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.Injector), i0.ɵɵdirectiveInject(i0.Renderer2), i0.ɵɵdirectiveInject(i0.TemplateRef), i0.ɵɵdirectiveInject(i0.ViewContainerRef)); }`); }); + it('should include constructor dependency metadata for directives/components/pipes', () => { + env.write(`test.ts`, ` + import {Attribute, Component, Directive, Pipe, Self, SkipSelf, Host, Optional} from '@angular/core'; + + export class MyService {} + export function dynamic() {}; + + @Directive() + export class WithDecorators { + constructor( + @Self() withSelf: MyService, + @SkipSelf() withSkipSelf: MyService, + @Host() withHost: MyService, + @Optional() withOptional: MyService, + @Attribute("attr") withAttribute: string, + @Attribute(dynamic()) withAttributeDynamic: string, + @Optional() @SkipSelf() @Host() withMany: MyService, + noDecorators: MyService) {} + } + + @Directive() + export class NoCtor {} + + @Directive() + export class EmptyCtor { + constructor() {} + } + + @Directive() + export class WithoutDecorators { + constructor(noDecorators: MyService) {} + } + + @Component({ template: 'test' }) + export class MyCmp { + constructor(@Host() withHost: MyService) {} + } + + @Pipe({ name: 'test' }) + export class MyPipe { + constructor(@Host() withHost: MyService) {} + } + `); + + env.driveMain(); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain( + 'static ɵfac: i0.ɵɵFactoryDef<WithDecorators, [' + + '{ self: true; }, { skipSelf: true; }, { host: true; }, ' + + '{ optional: true; }, { attribute: "attr"; }, { attribute: unknown; }, ' + + '{ optional: true; host: true; skipSelf: true; }, null]>'); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<NoCtor, never>`); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<EmptyCtor, never>`); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<WithoutDecorators, never>`); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<MyCmp, [{ host: true; }]>`); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<MyPipe, [{ host: true; }]>`); + }); + + it('should include constructor dependency metadata for @Injectable', () => { + env.write(`test.ts`, ` + import {Injectable, Self, Host} from '@angular/core'; + + export class MyService {} + + @Injectable() + export class Inj { + constructor(@Self() service: MyService) {} + } + + @Injectable({ useExisting: MyService }) + export class InjUseExisting { + constructor(@Self() service: MyService) {} + } + + @Injectable({ useClass: MyService }) + export class InjUseClass { + constructor(@Self() service: MyService) {} + } + + @Injectable({ useClass: MyService, deps: [[new Host(), MyService]] }) + export class InjUseClassWithDeps { + constructor(@Self() service: MyService) {} + } + + @Injectable({ useFactory: () => new Injectable(new MyService()) }) + export class InjUseFactory { + constructor(@Self() service: MyService) {} + } + + @Injectable({ useFactory: (service: MyService) => new Injectable(service), deps: [[new Host(), MyService]] }) + export class InjUseFactoryWithDeps { + constructor(@Self() service: MyService) {} + } + + @Injectable({ useValue: new Injectable(new MyService()) }) + export class InjUseValue { + constructor(@Self() service: MyService) {} + } + `); + + env.driveMain(); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<Inj, [{ self: true; }]>`); + expect(dtsContents) + .toContain(`static ɵfac: i0.ɵɵFactoryDef<InjUseExisting, [{ self: true; }]>`); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<InjUseClass, [{ self: true; }]>`); + expect(dtsContents) + .toContain(`static ɵfac: i0.ɵɵFactoryDef<InjUseClassWithDeps, [{ self: true; }]>`); + expect(dtsContents) + .toContain(`static ɵfac: i0.ɵɵFactoryDef<InjUseFactory, [{ self: true; }]>`); + expect(dtsContents) + .toContain(`static ɵfac: i0.ɵɵFactoryDef<InjUseFactoryWithDeps, [{ self: true; }]>`); + expect(dtsContents).toContain(`static ɵfac: i0.ɵɵFactoryDef<InjUseValue, [{ self: true; }]>`); + }); + + it('should include ng-content selectors in the metadata', () => { + env.write(`test.ts`, ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '<ng-content></ng-content> <ng-content select=".foo"></ng-content>', + }) + export class TestCmp { + } + `); + + env.driveMain(); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain( + 'static ɵcmp: i0.ɵɵComponentDefWithMeta<TestCmp, "test", never, {}, {}, never, ["*", ".foo"]>'); + }); + it('should generate queries for components', () => { env.write(`test.ts`, ` import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core'; @@ -6520,7 +6656,7 @@ export const Foo = Foo__PRE_R3__; export declare class NgZone {} export declare class Testability { - static ɵfac: i0.ɵɵFactoryDef<Testability>; + static ɵfac: i0.ɵɵFactoryDef<Testability, never>; constructor(ngZone: NgZone) {} } `); diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index b1095f801d183..172eaa2a3f736 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -296,11 +296,12 @@ function convertR3DependencyMetadata(facade: R3DependencyMetadataFacade): R3Depe } return { token: tokenExpr, + attribute: null, resolved: facade.resolved, host: facade.host, optional: facade.optional, self: facade.self, - skipSelf: facade.skipSelf + skipSelf: facade.skipSelf, }; } diff --git a/packages/compiler/src/render3/r3_factory.ts b/packages/compiler/src/render3/r3_factory.ts index c3ede764a51aa..e0bcc39ad817a 100644 --- a/packages/compiler/src/render3/r3_factory.ts +++ b/packages/compiler/src/render3/r3_factory.ts @@ -141,6 +141,13 @@ export interface R3DependencyMetadata { */ token: o.Expression; + /** + * If an @Attribute decorator is present, this is the literal type of the attribute name, or + * the unknown type if no literal type is available (e.g. the attribute name is an expression). + * Will be null otherwise. + */ + attribute: o.Expression|null; + /** * An enum indicating whether this dependency has special meaning to Angular and needs to be * injected specially. @@ -180,6 +187,7 @@ export interface R3FactoryFn { export function compileFactoryFunction(meta: R3FactoryMetadata): R3FactoryFn { const t = o.variable('t'); const statements: o.Statement[] = []; + let ctorDepsType: o.Type = o.NONE_TYPE; // The type to instantiate via constructor invocation. If there is no delegated factory, meaning // this type is always created by constructor invocation, then this is the type-to-create @@ -197,6 +205,8 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): R3FactoryFn { ctorExpr = new o.InstantiateExpr( typeForCtor, injectDependencies(meta.deps, meta.injectFn, meta.target === R3FactoryTarget.Pipe)); + + ctorDepsType = createCtorDepsType(meta.deps); } } else { const baseFactory = o.variable(`ɵ${meta.name}_BaseFactory`); @@ -269,8 +279,9 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): R3FactoryFn { [new o.FnParam('t', o.DYNAMIC_TYPE)], body, o.INFERRED_TYPE, undefined, `${meta.name}_Factory`), statements, - type: o.expressionType( - o.importExpr(R3.FactoryDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount)])) + type: o.expressionType(o.importExpr( + R3.FactoryDef, + [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType])) }; } @@ -319,6 +330,49 @@ function compileInjectDependency( } } +function createCtorDepsType(deps: R3DependencyMetadata[]): o.Type { + let hasTypes = false; + const attributeTypes = deps.map(dep => { + const type = createCtorDepType(dep); + if (type !== null) { + hasTypes = true; + return type; + } else { + return o.literal(null); + } + }); + + if (hasTypes) { + return o.expressionType(o.literalArr(attributeTypes)); + } else { + return o.NONE_TYPE; + } +} + +function createCtorDepType(dep: R3DependencyMetadata): o.LiteralMapExpr|null { + const entries: {key: string, quoted: boolean, value: o.Expression}[] = []; + + if (dep.resolved === R3ResolvedDependencyType.Attribute) { + if (dep.attribute !== null) { + entries.push({key: 'attribute', value: dep.attribute, quoted: false}); + } + } + if (dep.optional) { + entries.push({key: 'optional', value: o.literal(true), quoted: false}); + } + if (dep.host) { + entries.push({key: 'host', value: o.literal(true), quoted: false}); + } + if (dep.self) { + entries.push({key: 'self', value: o.literal(true), quoted: false}); + } + if (dep.skipSelf) { + entries.push({key: 'skipSelf', value: o.literal(true), quoted: false}); + } + + return entries.length > 0 ? o.literalMap(entries) : null; +} + /** * A helper function useful for extracting `R3DependencyMetadata` from a Render2 * `CompileTypeMetadata` instance. @@ -348,7 +402,7 @@ export function dependenciesFromGlobalMetadata( // Construct the dependency. deps.push({ token, - resolved, + attribute: null, resolved, host: !!dependency.isHost, optional: !!dependency.isOptional, self: !!dependency.isSelf, diff --git a/packages/compiler/src/render3/r3_template_transform.ts b/packages/compiler/src/render3/r3_template_transform.ts index a75d384ebc247..84245d0066f76 100644 --- a/packages/compiler/src/render3/r3_template_transform.ts +++ b/packages/compiler/src/render3/r3_template_transform.ts @@ -52,6 +52,7 @@ export interface Render3ParseResult { errors: ParseError[]; styles: string[]; styleUrls: string[]; + ngContentSelectors: string[]; } export function htmlAstToRender3Ast( @@ -73,6 +74,7 @@ export function htmlAstToRender3Ast( errors: allErrors, styleUrls: transformer.styleUrls, styles: transformer.styles, + ngContentSelectors: transformer.ngContentSelectors, }; } @@ -80,6 +82,7 @@ class HtmlAstToIvyAst implements html.Visitor { errors: ParseError[] = []; styles: string[] = []; styleUrls: string[] = []; + ngContentSelectors: string[] = []; private inI18nBlock: boolean = false; constructor(private bindingParser: BindingParser) {} @@ -189,6 +192,8 @@ class HtmlAstToIvyAst implements html.Visitor { const selector = preparsedElement.selectAttr; const attrs: t.TextAttribute[] = element.attrs.map(attr => this.visitAttribute(attr)); parsedElement = new t.Content(selector, attrs, element.sourceSpan, element.i18n); + + this.ngContentSelectors.push(selector); } else if (isTemplateElement) { // `<ng-template>` const attrs = this.extractAttributes(element.name, parsedProperties, i18nAttrsMeta); diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index 5b38e0a6a6776..5b6a2d55945b1 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -129,6 +129,12 @@ export interface R3ComponentMetadata extends R3DirectiveMetadata { * Parsed nodes of the template. */ nodes: t.Node[]; + + /** + * Any ng-content selectors extracted from the template. Contains `null` when an ng-content + * element without selector is present. + */ + ngContentSelectors: string[]; }; /** diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index a481bdb67482b..eb924357e82ce 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -22,7 +22,7 @@ import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler'; import {BindingParser} from '../../template_parser/binding_parser'; import {OutputContext, error} from '../../util'; import {BoundEvent} from '../r3_ast'; -import {R3FactoryTarget, compileFactoryFunction} from '../r3_factory'; +import {R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType, compileFactoryFunction} from '../r3_factory'; import {Identifiers as R3} from '../r3_identifiers'; import {Render3ParseResult} from '../r3_template_transform'; import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util'; @@ -124,7 +124,9 @@ export function compileDirectiveFromMetadata( addFeatures(definitionMap, meta); const expression = o.importExpr(R3.defineDirective).callFn([definitionMap.toLiteralMap()]); - const type = createTypeForDef(meta, R3.DirectiveDefWithMeta); + const typeParams = createDirectiveTypeParams(meta); + const type = o.expressionType(o.importExpr(R3.DirectiveDefWithMeta, typeParams)); + return {expression, type}; } @@ -252,7 +254,11 @@ export function compileComponentFromMetadata( } const expression = o.importExpr(R3.defineComponent).callFn([definitionMap.toLiteralMap()]); - const type = createTypeForDef(meta, R3.ComponentDefWithMeta); + + + const typeParams = createDirectiveTypeParams(meta); + typeParams.push(stringArrayAsType(meta.template.ngContentSelectors)); + const type = o.expressionType(o.importExpr(R3.ComponentDefWithMeta, typeParams)); return {expression, type}; } @@ -311,7 +317,7 @@ export function compileComponentFromRender2( const meta: R3ComponentMetadata = { ...directiveMetadataFromGlobalMetadata(component, outputCtx, reflector), selector: component.selector, - template: {nodes: render3Ast.nodes}, + template: {nodes: render3Ast.nodes, ngContentSelectors: render3Ast.ngContentSelectors}, directives: [], pipes: typeMapToExpressionMap(pipeTypeByName, outputCtx), viewQueries: queriesFromGlobalMetadata(component.viewQueries, outputCtx), @@ -470,24 +476,24 @@ function stringMapAsType(map: {[key: string]: string | string[]}): o.Type { return o.expressionType(o.literalMap(mapValues)); } -function stringArrayAsType(arr: string[]): o.Type { +function stringArrayAsType(arr: ReadonlyArray<string|null>): o.Type { return arr.length > 0 ? o.expressionType(o.literalArr(arr.map(value => o.literal(value)))) : o.NONE_TYPE; } -function createTypeForDef(meta: R3DirectiveMetadata, typeBase: o.ExternalReference): o.Type { +function createDirectiveTypeParams(meta: R3DirectiveMetadata): o.Type[] { // On the type side, remove newlines from the selector as it will need to fit into a TypeScript // string literal, which must be on one line. const selectorForType = meta.selector !== null ? meta.selector.replace(/\n/g, '') : null; - return o.expressionType(o.importExpr(typeBase, [ + return [ typeWithParameters(meta.type.type, meta.typeArgumentCount), selectorForType !== null ? stringAsType(selectorForType) : o.NONE_TYPE, meta.exportAs !== null ? stringArrayAsType(meta.exportAs) : o.NONE_TYPE, stringMapAsType(meta.inputs), stringMapAsType(meta.outputs), stringArrayAsType(meta.queries.map(q => q.propertyName)), - ])); + ]; } // Define and update any view queries diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index 18ad2a784d03f..afbee7b6d4cec 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -1983,8 +1983,13 @@ export interface ParseTemplateOptions { * @param options options to modify how the template is parsed */ export function parseTemplate( - template: string, templateUrl: string, options: ParseTemplateOptions = {}): - {errors?: ParseError[], nodes: t.Node[], styleUrls: string[], styles: string[]} { + template: string, templateUrl: string, options: ParseTemplateOptions = {}): { + errors?: ParseError[], + nodes: t.Node[], + styleUrls: string[], + styles: string[], + ngContentSelectors: string[] +} { const {interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat} = options; const bindingParser = makeBindingParser(interpolationConfig); const htmlParser = new HtmlParser(); @@ -1993,7 +1998,13 @@ export function parseTemplate( {leadingTriviaChars: LEADING_TRIVIA_CHARS, ...options, tokenizeExpansionForms: true}); if (parseResult.errors && parseResult.errors.length > 0) { - return {errors: parseResult.errors, nodes: [], styleUrls: [], styles: []}; + return { + errors: parseResult.errors, + nodes: [], + styleUrls: [], + styles: [], + ngContentSelectors: [] + }; } let rootNodes: html.Node[] = parseResult.rootNodes; @@ -2020,12 +2031,13 @@ export function parseTemplate( } } - const {nodes, errors, styleUrls, styles} = htmlAstToRender3Ast(rootNodes, bindingParser); + const {nodes, errors, styleUrls, styles, ngContentSelectors} = + htmlAstToRender3Ast(rootNodes, bindingParser); if (errors && errors.length > 0) { - return {errors, nodes: [], styleUrls: [], styles: []}; + return {errors, nodes: [], styleUrls: [], styles: [], ngContentSelectors: []}; } - return {nodes, styleUrls, styles}; + return {nodes, styleUrls, styles, ngContentSelectors}; } const elementRegistry = new DomElementSchemaRegistry(); diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index 34f5538cb8899..f89895e2d880f 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -89,6 +89,39 @@ export interface DirectiveType<T> extends Type<T> { */ export interface PipeType<T> extends Type<T> { ɵpipe: never; } +/** + * An object literal of this type is used to represent the metadata of a constructor dependency. + * The type itself is never referred to from generated code. + */ +export type CtorDependency = { + /** + * If an `@Attribute` decorator is used, this represents the injected attribute's name. If the + * attribute name is a dynamic expression instead of a string literal, this will be the unknown + * type. + */ + attribute?: string | unknown; + + /** + * If `@Optional()` is used, this key is set to true. + */ + optional?: true; + + /** + * If `@Host` is used, this key is set to true. + */ + host?: true; + + /** + * If `@Self` is used, this key is set to true. + */ + self?: true; + + /** + * If `@SkipSelf` is used, this key is set to true. + */ + skipSelf?: true; +} | null; + /** * @codeGenApi */ @@ -236,12 +269,13 @@ export interface DirectiveDef<T> { */ export type ɵɵComponentDefWithMeta< T, Selector extends String, ExportAs extends string[], InputMap extends{[key: string]: string}, - OutputMap extends{[key: string]: string}, QueryFields extends string[]> = ComponentDef<T>; + OutputMap extends{[key: string]: string}, QueryFields extends string[], + NgContentSelectors extends string[]> = ComponentDef<T>; /** * @codeGenApi */ -export type ɵɵFactoryDef<T> = () => T; +export type ɵɵFactoryDef<T, CtorDependencies extends CtorDependency[]> = () => T; /** * Runtime link information for Components. diff --git a/packages/core/test/strict_types/inheritance_spec.ts b/packages/core/test/strict_types/inheritance_spec.ts index 29edf027953fc..c49fc0a9ed695 100644 --- a/packages/core/test/strict_types/inheritance_spec.ts +++ b/packages/core/test/strict_types/inheritance_spec.ts @@ -9,7 +9,7 @@ import {ɵɵComponentDefWithMeta, ɵɵPipeDefWithMeta as PipeDefWithMeta} from '@angular/core'; declare class SuperComponent { - static ɵcmp: ɵɵComponentDefWithMeta<SuperComponent, '[super]', never, {}, {}, never>; + static ɵcmp: ɵɵComponentDefWithMeta<SuperComponent, '[super]', never, {}, {}, never, never>; } declare class SubComponent extends SuperComponent { @@ -18,7 +18,7 @@ declare class SubComponent extends SuperComponent { // would produce type errors when the "strictFunctionTypes" option is enabled. onlyInSubtype: string; - static ɵcmp: ɵɵComponentDefWithMeta<SubComponent, '[sub]', never, {}, {}, never>; + static ɵcmp: ɵɵComponentDefWithMeta<SubComponent, '[sub]', never, {}, {}, never, never>; } declare class SuperPipe { static ɵpipe: PipeDefWithMeta<SuperPipe, 'super'>; } From b8e9a30d3b6f67073165712e1d3fb8ed7a6b7acc Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Sat, 21 Mar 2020 22:18:50 +0000 Subject: [PATCH 030/262] fix(ngcc): use preserve whitespaces from tsconfig if provided (#36189) Previously ngcc never preserved whitespaces but this is at odds with how the ViewEngine compiler works. In ViewEngine, library templates are recompiled with the current application's tsconfig settings, which meant that whitespace preservation could be set in the application tsconfig file. This commit allows ngcc to use the `preserveWhitespaces` setting from tsconfig when compiling library templates. One should be aware that this disallows different projects with different tsconfig settings to share the same node_modules folder, with regard to whitespace preservation. But this is already the case in the current ngcc since this configuration is hard coded right now. Fixes #35871 PR Close #36189 --- .../ngcc/src/analysis/decoration_analyzer.ts | 7 +++- packages/compiler-cli/ngcc/src/main.ts | 2 +- .../ngcc/src/packages/transformer.ts | 7 +++- .../ngcc/test/integration/ngcc_spec.ts | 40 ++++++++++++++++++- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts index a4c5f105f6678..a8e02ccc3f141 100644 --- a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts @@ -8,6 +8,7 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; +import {ParsedConfiguration} from '../../..'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations'; import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles'; import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics'; @@ -55,6 +56,7 @@ export class DecorationAnalyzer { private rootDirs = this.bundle.rootDirs; private packagePath = this.bundle.entryPoint.package; private isCore = this.bundle.isCore; + private compilerOptions = this.tsConfig !== null? this.tsConfig.options: {}; moduleResolver = new ModuleResolver(this.program, this.options, this.host, /* moduleResolutionCache */ null); @@ -87,7 +89,7 @@ export class DecorationAnalyzer { new ComponentDecoratorHandler( this.reflectionHost, this.evaluator, this.fullRegistry, this.fullMetaReader, this.scopeRegistry, this.scopeRegistry, this.isCore, this.resourceManager, this.rootDirs, - /* defaultPreserveWhitespaces */ false, + !!this.compilerOptions.preserveWhitespaces, /* i18nUseExternalIds */ true, this.bundle.enableI18nLegacyMessageIdFormat, this.moduleResolver, this.cycleAnalyzer, this.refEmitter, NOOP_DEFAULT_IMPORT_RECORDER, NOOP_DEPENDENCY_TRACKER, this.injectableRegistry, /* annotateForClosureCompiler */ false), @@ -123,7 +125,8 @@ export class DecorationAnalyzer { constructor( private fs: FileSystem, private bundle: EntryPointBundle, private reflectionHost: NgccReflectionHost, private referencesRegistry: ReferencesRegistry, - private diagnosticHandler: (error: ts.Diagnostic) => void = () => {}) {} + private diagnosticHandler: (error: ts.Diagnostic) => void = () => {}, + private tsConfig: ParsedConfiguration|null = null) {} /** * Analyze a program to find all the decorated files should be transformed. diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 6a202be471355..a069b8b03b63d 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -307,7 +307,7 @@ export function mainNgcc( const createCompileFn: CreateCompileFn = onTaskCompleted => { const fileWriter = getFileWriter( fileSystem, logger, pkgJsonUpdater, createNewEntryPointFormats, errorOnFailedEntryPoint); - const transformer = new Transformer(fileSystem, logger); + const transformer = new Transformer(fileSystem, logger, tsConfig); return (task: Task) => { const {entryPoint, formatProperty, formatPropertiesToMarkAsProcessed, processDts} = task; diff --git a/packages/compiler-cli/ngcc/src/packages/transformer.ts b/packages/compiler-cli/ngcc/src/packages/transformer.ts index 6ae9785929eef..f7a30944f7851 100644 --- a/packages/compiler-cli/ngcc/src/packages/transformer.ts +++ b/packages/compiler-cli/ngcc/src/packages/transformer.ts @@ -7,6 +7,7 @@ */ import * as ts from 'typescript'; +import {ParsedConfiguration} from '../../..'; import {FileSystem} from '../../../src/ngtsc/file_system'; import {TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; import {DecorationAnalyzer} from '../analysis/decoration_analyzer'; @@ -63,7 +64,9 @@ export type TransformResult = { * - Some formats may contain multiple "modules" in a single file. */ export class Transformer { - constructor(private fs: FileSystem, private logger: Logger) {} + constructor( + private fs: FileSystem, private logger: Logger, + private tsConfig: ParsedConfiguration|null = null) {} /** * Transform the source (and typings) files of a bundle. @@ -146,7 +149,7 @@ export class Transformer { const diagnostics: ts.Diagnostic[] = []; const decorationAnalyzer = new DecorationAnalyzer( this.fs, bundle, reflectionHost, referencesRegistry, - diagnostic => diagnostics.push(diagnostic)); + diagnostic => diagnostics.push(diagnostic), this.tsConfig); const decorationAnalyses = decorationAnalyzer.analyzeProgram(); const moduleWithProvidersAnalyzer = diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 328ea2ee4406a..4cc67792d5820 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -1373,6 +1373,44 @@ runInEachFileSystem(() => { }); }); + describe('whitespace preservation', () => { + it('should default not to preserve whitespace', () => { + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(fs.readFile(_('/dist/local-package/index.js'))) + .toMatch(/ɵɵtext\(\d+, " Hello\\n"\);/); + }); + + it('should preserve whitespace if set in a loaded tsconfig.json', () => { + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({angularCompilerOptions: {preserveWhitespaces: true}})); + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(fs.readFile(_('/dist/local-package/index.js'))) + .toMatch(/ɵɵtext\(\d+, "\\n Hello\\n"\);/); + }); + + it('should not preserve whitespace if set to false in a loaded tsconfig.json', () => { + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({angularCompilerOptions: {preserveWhitespaces: false}})); + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(fs.readFile(_('/dist/local-package/index.js'))) + .toMatch(/ɵɵtext\(\d+, " Hello\\n"\);/); + }); + }); + describe('with configuration files', () => { it('should process a configured deep-import as an entry-point', () => { loadTestFiles([ @@ -1883,7 +1921,7 @@ runInEachFileSystem(() => { { name: _('/dist/local-package/index.js'), contents: - `import {Component} from '@angular/core';\nexport class AppComponent {};\nAppComponent.decorators = [\n{ type: Component, args: [{selector: 'app', template: '<h2>Hello</h2>'}] }\n];` + `import {Component} from '@angular/core';\nexport class AppComponent {};\nAppComponent.decorators = [\n{ type: Component, args: [{selector: 'app', template: '<h2>\\n Hello\\n</h2>'}] }\n];` }, { name: _('/dist/local-package/index.d.ts'), From d78351983584483f4dc71234a6dbb9e1f5d72dcd Mon Sep 17 00:00:00 2001 From: JoostK <joost.koehoorn@gmail.com> Date: Mon, 16 Mar 2020 22:48:45 +0100 Subject: [PATCH 031/262] fix(common): let `KeyValuePipe` accept type unions with `null` (#36093) `KeyValuePipe` currently accepts `null` values as well as `Map`s and a few others. However, due to the way in which TS overloads work, a type of `T|null` will not be accepted by `KeyValuePipe`'s signatures, even though both `T` and `null` individually would be. To make this work, each signature that accepts some type `T` has been duplicated with a second one below it that accepts a `T|null` and includes `null` in its return type. Fixes #35743 PR Close #36093 --- goldens/public-api/common/common.d.ts | 7 +++++++ packages/common/src/pipes/keyvalue_pipe.ts | 11 +++++++++++ packages/common/test/pipes/keyvalue_pipe_spec.ts | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/goldens/public-api/common/common.d.ts b/goldens/public-api/common/common.d.ts index 3cbe877311fb5..c36711e0fd71c 100644 --- a/goldens/public-api/common/common.d.ts +++ b/goldens/public-api/common/common.d.ts @@ -139,10 +139,17 @@ export declare class KeyValuePipe implements PipeTransform { transform<V>(input: { [key: string]: V; } | Map<string, V>, compareFn?: (a: KeyValue<string, V>, b: KeyValue<string, V>) => number): Array<KeyValue<string, V>>; + transform<V>(input: { + [key: string]: V; + } | Map<string, V> | null, compareFn?: (a: KeyValue<string, V>, b: KeyValue<string, V>) => number): Array<KeyValue<string, V>> | null; transform<V>(input: { [key: number]: V; } | Map<number, V>, compareFn?: (a: KeyValue<number, V>, b: KeyValue<number, V>) => number): Array<KeyValue<number, V>>; + transform<V>(input: { + [key: number]: V; + } | Map<number, V> | null, compareFn?: (a: KeyValue<number, V>, b: KeyValue<number, V>) => number): Array<KeyValue<number, V>> | null; transform<K, V>(input: Map<K, V>, compareFn?: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number): Array<KeyValue<K, V>>; + transform<K, V>(input: Map<K, V> | null, compareFn?: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number): Array<KeyValue<K, V>> | null; } export declare class Location { diff --git a/packages/common/src/pipes/keyvalue_pipe.ts b/packages/common/src/pipes/keyvalue_pipe.ts index 5770f6a75bd18..592e57f95849a 100644 --- a/packages/common/src/pipes/keyvalue_pipe.ts +++ b/packages/common/src/pipes/keyvalue_pipe.ts @@ -55,12 +55,23 @@ export class KeyValuePipe implements PipeTransform { input: {[key: string]: V}|Map<string, V>, compareFn?: (a: KeyValue<string, V>, b: KeyValue<string, V>) => number): Array<KeyValue<string, V>>; + transform<V>( + input: {[key: string]: V}|Map<string, V>|null, + compareFn?: (a: KeyValue<string, V>, b: KeyValue<string, V>) => number): + Array<KeyValue<string, V>>|null; transform<V>( input: {[key: number]: V}|Map<number, V>, compareFn?: (a: KeyValue<number, V>, b: KeyValue<number, V>) => number): Array<KeyValue<number, V>>; + transform<V>( + input: {[key: number]: V}|Map<number, V>|null, + compareFn?: (a: KeyValue<number, V>, b: KeyValue<number, V>) => number): + Array<KeyValue<number, V>>|null; transform<K, V>(input: Map<K, V>, compareFn?: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number): Array<KeyValue<K, V>>; + transform<K, V>( + input: Map<K, V>|null, + compareFn?: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number): Array<KeyValue<K, V>>|null; transform<K, V>( input: null|{[key: string]: V, [key: number]: V}|Map<K, V>, compareFn: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number = defaultComparator): diff --git a/packages/common/test/pipes/keyvalue_pipe_spec.ts b/packages/common/test/pipes/keyvalue_pipe_spec.ts index 082fce6712212..4433f9c98d052 100644 --- a/packages/common/test/pipes/keyvalue_pipe_spec.ts +++ b/packages/common/test/pipes/keyvalue_pipe_spec.ts @@ -63,6 +63,16 @@ describe('KeyValuePipe', () => { const transform2 = pipe.transform({1: 3}); expect(transform1 !== transform2).toEqual(true); }); + it('should accept a type union of an object with string keys and null', () => { + let value !: {[key: string]: string} | null; + const pipe = new KeyValuePipe(defaultKeyValueDiffers); + expect(pipe.transform(value)).toEqual(null); + }); + it('should accept a type union of an object with number keys and null', () => { + let value !: {[key: number]: string} | null; + const pipe = new KeyValuePipe(defaultKeyValueDiffers); + expect(pipe.transform(value)).toEqual(null); + }); }); describe('Map', () => { @@ -115,6 +125,11 @@ describe('KeyValuePipe', () => { const transform2 = pipe.transform(new Map([[1, 3]])); expect(transform1 !== transform2).toEqual(true); }); + it('should accept a type union of a Map and null', () => { + let value !: Map<number, number>| null; + const pipe = new KeyValuePipe(defaultKeyValueDiffers); + expect(pipe.transform(value)).toEqual(null); + }); }); }); From 4f66250618834046c2339ef21754aadfcf876a6b Mon Sep 17 00:00:00 2001 From: Misko Hevery <misko@hevery.com> Date: Tue, 24 Mar 2020 16:18:10 -0700 Subject: [PATCH 032/262] docs: release notes for the v9.1.0-rc.2 release --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d3522e593426..d08bef340d38a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +<a name="9.1.0-rc.2"></a> +# [9.1.0-rc.2](https://github.com/angular/angular/compare/9.1.0-rc.1...9.1.0-rc.2) (2020-03-24) + + +### Bug Fixes + +* **common:** let `KeyValuePipe` accept type unions with `null` ([#36093](https://github.com/angular/angular/issues/36093)) ([407fa42](https://github.com/angular/angular/commit/407fa42)), closes [#35743](https://github.com/angular/angular/issues/35743) +* **elements:** correctly handle setting inputs to `undefined` ([#36140](https://github.com/angular/angular/issues/36140)) ([e066bdd](https://github.com/angular/angular/commit/e066bdd)) +* **elements:** correctly set `SimpleChange#firstChange` for pre-existing inputs ([#36140](https://github.com/angular/angular/issues/36140)) ([447a600](https://github.com/angular/angular/commit/447a600)), closes [#36130](https://github.com/angular/angular/issues/36130) +* **ngcc:** use path-mappings from tsconfig in dependency resolution ([#36180](https://github.com/angular/angular/issues/36180)) ([6defe96](https://github.com/angular/angular/commit/6defe96)), closes [#36119](https://github.com/angular/angular/issues/36119) +* **ngcc:** use preserve whitespaces from tsconfig if provided ([#36189](https://github.com/angular/angular/issues/36189)) ([aef4323](https://github.com/angular/angular/commit/aef4323)), closes [#35871](https://github.com/angular/angular/issues/35871) + + +### Features + +* **compiler:** add dependency info and ng-content selectors to metadata ([#35695](https://github.com/angular/angular/issues/35695)) ([fb70083](https://github.com/angular/angular/commit/fb70083)) + + + <a name="9.1.0-rc.1"></a> # [9.1.0-rc.1](https://github.com/angular/angular/compare/9.1.0-rc.0...9.1.0-rc.1) (2020-03-23) From 22710fc3534868342c4fc93984b22d0dc86975d7 Mon Sep 17 00:00:00 2001 From: Misko Hevery <misko@hevery.com> Date: Wed, 25 Mar 2020 09:44:22 -0700 Subject: [PATCH 033/262] docs: release notes for the v9.1.0 release --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d08bef340d38a..060e923a54b0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +<a name="9.1.0"></a> +# [9.1.0](https://github.com/angular/angular/compare/9.1.0-rc.2...9.1.0) (2020-03-25) + +Promoted `9.1.0-rc.2` to `9.1.0`. + + <a name="9.1.0-rc.2"></a> # [9.1.0-rc.2](https://github.com/angular/angular/compare/9.1.0-rc.1...9.1.0-rc.2) (2020-03-24) From d37dad82f10a14a223e004b2cf8403cbf27e6f6d Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 23 Mar 2020 11:22:57 -0700 Subject: [PATCH 034/262] build: ensure that refs and shas for PRs only need to be requested once (#36207) This is done by requesting the refs and shas for the PR when the env.sh script is run. Additionally, the env.sh script is now setup to write all of the environment variables created to a cache file and subsequent loads of the environment load the values from there. The get-refs-and-shas-for-target.js script now also first attempts to load the refs and shas from an environment variable before falling back to requesting from github via the API. PR Close #36207 --- .circleci/config.yml | 2 +- .circleci/env.sh | 147 +++++++++++--------- tools/utils/get-refs-and-shas-for-target.js | 49 ++++++- 3 files changed, 126 insertions(+), 72 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2a73417bdc414..6f61ffbc6f39c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -226,6 +226,7 @@ jobs: executor: default-executor steps: - checkout + - init_environment - run: name: Rebase PR on target branch # After checkout, rebase on top of target branch. @@ -244,7 +245,6 @@ jobs: keys: - *cache_key - *cache_key_fallback - - init_environment - run: name: Running Yarn install command: yarn install --frozen-lockfile --non-interactive diff --git a/.circleci/env.sh b/.circleci/env.sh index 2b20833205eb7..84affc8b57b06 100755 --- a/.circleci/env.sh +++ b/.circleci/env.sh @@ -3,72 +3,87 @@ # Variables readonly projectDir=$(realpath "$(dirname ${BASH_SOURCE[0]})/..") readonly envHelpersPath="$projectDir/.circleci/env-helpers.inc.sh"; - -# Load helpers and make them available everywhere (through `$BASH_ENV`). -source $envHelpersPath; -echo "source $envHelpersPath;" >> $BASH_ENV; - - -#################################################################################################### -# Define PUBLIC environment variables for CircleCI. -#################################################################################################### -# See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info. -#################################################################################################### -setPublicVar PROJECT_ROOT "$projectDir"; -setPublicVar CI_AIO_MIN_PWA_SCORE "95"; -# This is the branch being built; e.g. `pull/12345` for PR builds. -setPublicVar CI_BRANCH "$CIRCLE_BRANCH"; -setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL"; -setPublicVar CI_COMMIT "$CIRCLE_SHA1"; -# `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun -# workflows of such builds). -setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION"; -setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}"; -setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME"; -setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME"; - - -#################################################################################################### -# Define "lazy" PUBLIC environment variables for CircleCI. -# (I.e. functions to set an environment variable when called.) -#################################################################################################### -createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')"; - - -#################################################################################################### -# Define SECRET environment variables for CircleCI. -#################################################################################################### -setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN"; -setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN"; - - -#################################################################################################### -# Define SauceLabs environment variables for CircleCI. -#################################################################################################### -setPublicVar SAUCE_USERNAME "angular-framework"; -setSecretVar SAUCE_ACCESS_KEY "0c731274ed5f-cbc9-16f4-021a-9835e39f"; -# TODO(josephperrott): Remove environment variables once all saucelabs tests are via bazel method. -setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log -setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock -setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock -setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}" -# Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not -# acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout. -setPublicVar SAUCE_READY_FILE_TIMEOUT 120 - - -#################################################################################################### -# Define environment variables for the `angular/components` repo unit tests job. -#################################################################################################### -# We specifically use a directory within "/tmp" here because we want the cloned repo to be -# completely isolated from angular/angular in order to avoid any bad interactions between -# their separate build setups. **NOTE**: When updating the temporary directory, also update -# the `save_cache` path configuration in `config.yml` -setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo" -setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git" -setPublicVar COMPONENTS_REPO_BRANCH "master" -# **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`. -setPublicVar COMPONENTS_REPO_COMMIT "598db096e668aa7e9debd56eedfd127b7a55e371" +readonly bashEnvCachePath="$projectDir/.circleci/bash_env_cache"; + +if [ -f $bashEnvCachePath ]; then + # Since a bash env cache is present, load this into the $BASH_ENV + cat "$bashEnvCachePath" >> $BASH_ENV; + echo "BASH environment loaded from cached value at $bashEnvCachePath"; +else + # Since no bash env cache is present, build out $BASH_ENV values. + + # Load helpers and make them available everywhere (through `$BASH_ENV`). + source $envHelpersPath; + echo "source $envHelpersPath;" >> $BASH_ENV; + + + #################################################################################################### + # Define PUBLIC environment variables for CircleCI. + #################################################################################################### + # See https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables for more info. + #################################################################################################### + setPublicVar PROJECT_ROOT "$projectDir"; + setPublicVar CI_AIO_MIN_PWA_SCORE "95"; + # This is the branch being built; e.g. `pull/12345` for PR builds. + setPublicVar CI_BRANCH "$CIRCLE_BRANCH"; + setPublicVar CI_BUILD_URL "$CIRCLE_BUILD_URL"; + setPublicVar CI_COMMIT "$CIRCLE_SHA1"; + # `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun + # workflows of such builds). + setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION"; + setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}"; + setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME"; + setPublicVar CI_REPO_OWNER "$CIRCLE_PROJECT_USERNAME"; + + # Store a PR's refs and shas so they don't need to be requested multiple times. + setPublicVar GITHUB_REFS_AND_SHAS $(node tools/utils/get-refs-and-shas-for-target.js ${CIRCLE_PR_NUMBER:-false} | awk '{ gsub(/"/,"\\\"") } 1'); + + + #################################################################################################### + # Define "lazy" PUBLIC environment variables for CircleCI. + # (I.e. functions to set an environment variable when called.) + #################################################################################################### + createPublicVarSetter CI_STABLE_BRANCH "\$(npm info @angular/core dist-tags.latest | sed -r 's/^\\s*([0-9]+\\.[0-9]+)\\.[0-9]+.*$/\\1.x/')"; + + + #################################################################################################### + # Define SECRET environment variables for CircleCI. + #################################################################################################### + setSecretVar CI_SECRET_AIO_DEPLOY_FIREBASE_TOKEN "$AIO_DEPLOY_TOKEN"; + setSecretVar CI_SECRET_PAYLOAD_FIREBASE_TOKEN "$ANGULAR_PAYLOAD_TOKEN"; + + + #################################################################################################### + # Define SauceLabs environment variables for CircleCI. + #################################################################################################### + setPublicVar SAUCE_USERNAME "angular-framework"; + setSecretVar SAUCE_ACCESS_KEY "0c731274ed5f-cbc9-16f4-021a-9835e39f"; + # TODO(josephperrott): Remove environment variables once all saucelabs tests are via bazel method. + setPublicVar SAUCE_LOG_FILE /tmp/angular/sauce-connect.log + setPublicVar SAUCE_READY_FILE /tmp/angular/sauce-connect-ready-file.lock + setPublicVar SAUCE_PID_FILE /tmp/angular/sauce-connect-pid-file.lock + setPublicVar SAUCE_TUNNEL_IDENTIFIER "angular-framework-${CIRCLE_BUILD_NUM}-${CIRCLE_NODE_INDEX}" + # Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not + # acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout. + setPublicVar SAUCE_READY_FILE_TIMEOUT 120 + + + #################################################################################################### + # Define environment variables for the `angular/components` repo unit tests job. + #################################################################################################### + # We specifically use a directory within "/tmp" here because we want the cloned repo to be + # completely isolated from angular/angular in order to avoid any bad interactions between + # their separate build setups. **NOTE**: When updating the temporary directory, also update + # the `save_cache` path configuration in `config.yml` + setPublicVar COMPONENTS_REPO_TMP_DIR "/tmp/angular-components-repo" + setPublicVar COMPONENTS_REPO_URL "https://github.com/angular/components.git" + setPublicVar COMPONENTS_REPO_BRANCH "master" + # **NOTE**: When updating the commit SHA, also update the cache key in the CircleCI `config.yml`. + setPublicVar COMPONENTS_REPO_COMMIT "598db096e668aa7e9debd56eedfd127b7a55e371" + + # Save the created BASH_ENV into the bash env cache file. + cat "$BASH_ENV" >> $bashEnvCachePath; +fi #################################################################################################### diff --git a/tools/utils/get-refs-and-shas-for-target.js b/tools/utils/get-refs-and-shas-for-target.js index 42a8989069659..7ee356a7f0564 100644 --- a/tools/utils/get-refs-and-shas-for-target.js +++ b/tools/utils/get-refs-and-shas-for-target.js @@ -6,6 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ +// NOTE: When invoked directly via node, this script will take the first positional +// arguement as to be the PR number, and log out the ref and sha information in its +// JSON format. For other usages, the function to get the ref and sha information +// may be imported by another script to be invoked. + // This script uses `console` to print messages to the user. // tslint:disable:no-console @@ -16,7 +21,18 @@ const exec = util.promisify(child_process.exec); async function requestDataFromGithub(url) { // GitHub requires a user agent: https://developer.github.com/v3/#user-agent-required - const options = {headers: {'User-Agent': 'angular'}}; + let options = {headers: {'User-Agent': 'angular'}}; + + // If a github token is present, use it for authorization. + const githubToken = process.env.TOKEN || process.env.GITHUB_TOKEN || ''; + if (githubToken) { + options = { + headers: { + Authorization: `token ${githubToken}`, + ...options.headers, + } + }; + } return new Promise((resolve, reject) => { https @@ -54,9 +70,19 @@ async function requestDataFromGithub(url) { .on('error', (e) => { reject(e); }); }); } +// clang-format off +// clang keeps trying to put the function name on the next line. +async function getRefsAndShasForTarget(prNumber, suppressLog) { + // clang-format on + // If the environment variable already contains the refs and shas, reuse them. + if (process.env['GITHUB_REFS_AND_SHAS']) { + suppressLog || + console.info(`Retrieved refs and SHAs for PR ${prNumber} from environment variables.`); + return JSON.parse(process.env['GITHUB_REFS_AND_SHAS']); + } -module.exports = async function getRefsAndShasForTarget(prNumber) { - console.log(`Getting refs and SHAs for PR ${prNumber} on angular/angular.`); + suppressLog || + console.info(`Getting refs and SHAs for PR ${prNumber} on angular/angular from Github.`); const pullsUrl = `https://api.github.com/repos/angular/angular/pulls/${prNumber}`; const result = await requestDataFromGithub(pullsUrl); @@ -84,6 +110,19 @@ module.exports = async function getRefsAndShasForTarget(prNumber) { latestShaOfTargetBranch: latestShaOfTargetBranch.trim(), latestShaOfPrBranch: latestShaOfPrBranch.trim(), }; - return output; -}; +} + +// If the script is called directly, log the output of the refs and sha for the +// requested PR. +if (require.main === module) { + const run = async() => { + const prNumber = Number.parseInt(process.argv[2], 10); + if (!!prNumber) { + console.info(JSON.stringify(await getRefsAndShasForTarget(prNumber, true))); + } + }; + run(); +} + +module.exports = getRefsAndShasForTarget; From fc3e5cb6d3ef61aaa13bd9788b9b1c7b97af94fe Mon Sep 17 00:00:00 2001 From: Misko Hevery <misko@hevery.com> Date: Wed, 25 Mar 2020 12:08:49 -0700 Subject: [PATCH 035/262] docs: coalesce release notes for the v9.1.0 release (#36247) Merge all of the release notes across all v9.1.0 releases into a single one. PR Close #36247 --- CHANGELOG.md | 369 ++++++++++++++++++--------------------------------- 1 file changed, 128 insertions(+), 241 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 060e923a54b0b..abafe22d46f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,42 +1,5 @@ <a name="9.1.0"></a> -# [9.1.0](https://github.com/angular/angular/compare/9.1.0-rc.2...9.1.0) (2020-03-25) - -Promoted `9.1.0-rc.2` to `9.1.0`. - - -<a name="9.1.0-rc.2"></a> -# [9.1.0-rc.2](https://github.com/angular/angular/compare/9.1.0-rc.1...9.1.0-rc.2) (2020-03-24) - - -### Bug Fixes - -* **common:** let `KeyValuePipe` accept type unions with `null` ([#36093](https://github.com/angular/angular/issues/36093)) ([407fa42](https://github.com/angular/angular/commit/407fa42)), closes [#35743](https://github.com/angular/angular/issues/35743) -* **elements:** correctly handle setting inputs to `undefined` ([#36140](https://github.com/angular/angular/issues/36140)) ([e066bdd](https://github.com/angular/angular/commit/e066bdd)) -* **elements:** correctly set `SimpleChange#firstChange` for pre-existing inputs ([#36140](https://github.com/angular/angular/issues/36140)) ([447a600](https://github.com/angular/angular/commit/447a600)), closes [#36130](https://github.com/angular/angular/issues/36130) -* **ngcc:** use path-mappings from tsconfig in dependency resolution ([#36180](https://github.com/angular/angular/issues/36180)) ([6defe96](https://github.com/angular/angular/commit/6defe96)), closes [#36119](https://github.com/angular/angular/issues/36119) -* **ngcc:** use preserve whitespaces from tsconfig if provided ([#36189](https://github.com/angular/angular/issues/36189)) ([aef4323](https://github.com/angular/angular/commit/aef4323)), closes [#35871](https://github.com/angular/angular/issues/35871) - - -### Features - -* **compiler:** add dependency info and ng-content selectors to metadata ([#35695](https://github.com/angular/angular/issues/35695)) ([fb70083](https://github.com/angular/angular/commit/fb70083)) - - - -<a name="9.1.0-rc.1"></a> -# [9.1.0-rc.1](https://github.com/angular/angular/compare/9.1.0-rc.0...9.1.0-rc.1) (2020-03-23) - - -### Bug Fixes - -* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477) -* **core:** workaround Terser inlining bug ([#36200](https://github.com/angular/angular/issues/36200)) ([f71d132](https://github.com/angular/angular/commit/f71d132)) -* **localize:** allow ICU expansion case to start with any character except `}` ([#36123](https://github.com/angular/angular/issues/36123)) ([0767d37](https://github.com/angular/angular/commit/0767d37)), closes [#31586](https://github.com/angular/angular/issues/31586) -* **compiler:** Propagate value span of ExpressionBinding to ParsedProperty ([#36133](https://github.com/angular/angular/issues/36133)) ([2ce5fa3](https://github.com/angular/angular/commit/2ce5fa3)) - - -<a name="9.1.0-rc.0"></a> -# [9.1.0-rc.0](https://github.com/angular/angular/compare/9.1.0-next.5...9.1.0-rc.0) (2020-03-19) +# [9.1.0](https://github.com/angular/angular/compare/9.0.0...9.1.0) (2020-03-25) ### Release Highlights @@ -48,53 +11,153 @@ Promoted `9.1.0-rc.2` to `9.1.0`. * Ivy compatibility fixes -### Bug Fixes +### Features -* **core:** adhere to bootstrap options for JIT compiled components ([#35534](https://github.com/angular/angular/issues/35534)) ([e342ffd](https://github.com/angular/angular/commit/e342ffd)), closes [#35230](https://github.com/angular/angular/issues/35230) -* **ngcc:** do not crash on entry-point that fails to compile ([#36083](https://github.com/angular/angular/issues/36083)) ([ff665b9](https://github.com/angular/angular/commit/ff665b9)) -* **ngcc:** do not crash on overlapping entry-points ([#36083](https://github.com/angular/angular/issues/36083)) ([c9f554c](https://github.com/angular/angular/commit/c9f554c)) +* **bazel:** enable ivy template type-checking in g3 ([#35672](https://github.com/angular/angular/issues/35672)) ([8f5b7f3](https://github.com/angular/angular/commit/8f5b7f3)) +* **bazel:** transform generated shims (in Ivy) with tsickle ([#35975](https://github.com/angular/angular/issues/35975)) ([e3ecdc6](https://github.com/angular/angular/commit/e3ecdc6)), closes [#35848](https://github.com/angular/angular/issues/35848) +* **compiler-cli:** implement NgTscPlugin on top of the NgCompiler API ([#34792](https://github.com/angular/angular/issues/34792)) ([3c69442dbd](https://github.com/angular/angular/commit/3c69442dbd)) +* **compiler:** Add sourceSpan and keySpan to TemplateBinding ([#35897](https://github.com/angular/angular/issues/35897)) ([06779cf](https://github.com/angular/angular/commit/06779cf)) +* **compiler:** Propagate source span and value span to Variable AST ([#36047](https://github.com/angular/angular/issues/36047)) ([31bec8c](https://github.com/angular/angular/commit/31bec8c)) +* **compiler:** add dependency info and ng-content selectors to metadata ([#35695](https://github.com/angular/angular/issues/35695)) ([fb70083](https://github.com/angular/angular/commit/fb70083)) +* **language-service:** improve non-callable error message ([#35271](https://github.com/angular/angular/issues/35271)) ([acc483e](https://github.com/angular/angular/commit/acc483e)) +* **language-service:** modularize error messages ([#35678](https://github.com/angular/angular/issues/35678)) ([47a1811](https://github.com/angular/angular/commit/47a1811)), closes [#32663](https://github.com/angular/angular/issues/32663) +* **ngcc:** implement source-map flattening ([#35132](https://github.com/angular/angular/issues/35132)) ([df816c9](https://github.com/angular/angular/commit/df816c9)) +* **ngcc:** pause async ngcc processing if another process has the lockfile ([#35131](https://github.com/angular/angular/issues/35131)) ([eef0753](https://github.com/angular/angular/commit/eef0753)) +* **ngcc:** support invalidating the entry-point manifest ([#35931](https://github.com/angular/angular/issues/35931)) ([8ea61a1](https://github.com/angular/angular/commit/8ea61a1)) +* **zone.js** add a temp solution to support passive event listeners. ([#34503](https://github.com/angular/angular/issues/34503)) ([f9d483e](https://github.com/angular/angular/commit/f9d483e)) +* **zone.js** add an tickOptions parameter with property processNewMacroTasksSynchronously. ([#33838](https://github.com/angular/angular/issues/33838)) ([17b862c](https://github.com/angular/angular/commit/17b862c)), closes [#33799](https://github.com/angular/angular/issues/33799) +* **zone.js** add interface definitions which zone extends EventTarget ([#35304](https://github.com/angular/angular/issues/35304)) ([4acb676](https://github.com/angular/angular/commit/4acb676)), closes [#35173](https://github.com/angular/angular/issues/35173) +* **zone.js** support passive event options by defining global variables in zone.js config file ([#34503](https://github.com/angular/angular/issues/34503)) ([d7d359e](https://github.com/angular/angular/commit/d7d359e)) +* define all zone.js configurations to typescript interfaces ([#35329](https://github.com/angular/angular/issues/35329)) ([03d88c7](https://github.com/angular/angular/commit/03d88c7)) +* typescript 3.8 support ([#35864](https://github.com/angular/angular/issues/35864)) ([95c729f](https://github.com/angular/angular/commit/95c729f)) +### Performance Improvements -<a name="9.1.0-next.5"></a> -# [9.1.0-next.5](https://github.com/angular/angular/compare/9.1.0-next.4...9.1.0-next.5) (2020-03-18) +* **core:** add micro benchmark for destroy hook invocation ([#35784](https://github.com/angular/angular/issues/35784)) ([0653db1](https://github.com/angular/angular/commit/0653db1)) +* **core:** adding micro benchmark for host bindings ([#35705](https://github.com/angular/angular/issues/35705)) ([8fed1fe](https://github.com/angular/angular/commit/8fed1fe)), closes [#35568](https://github.com/angular/angular/issues/35568) +* **core:** avoid recursive scope recalculation when TestBed.overrideModule is used ([#35454](https://github.com/angular/angular/issues/35454)) ([0a1a989](https://github.com/angular/angular/commit/0a1a989)) +* **core:** use multiple directives in host bindings micro benchmark ([#35736](https://github.com/angular/angular/issues/35736)) ([5bc39f8](https://github.com/angular/angular/commit/5bc39f8)) +* **ivy:** remove unused event argument in listener instructions ([#35097](https://github.com/angular/angular/issues/35097)) ([9228d7f](https://github.com/angular/angular/commit/9228d7f)) +* **ngcc:** link segment markers for faster traversal ([#36027](https://github.com/angular/angular/issues/36027)) ([47025e0](https://github.com/angular/angular/commit/47025e0)) +* **ngcc:** only create tasks for non-processed formats ([#35719](https://github.com/angular/angular/issues/35719)) ([d7efc45](https://github.com/angular/angular/commit/d7efc45)) +* **ngcc:** reduce directory traversing ([#35756](https://github.com/angular/angular/issues/35756)) ([e0a35e1](https://github.com/angular/angular/commit/e0a35e1)), closes [#35717](https://github.com/angular/angular/issues/35717) +* **ngcc:** spawn workers lazily ([#35719](https://github.com/angular/angular/issues/35719)) ([dc40a93](https://github.com/angular/angular/commit/dc40a93)), closes [#35717](https://github.com/angular/angular/issues/35717) +* **ngcc:** store the position of SegmentMarkers to avoid unnecessary computation ([#36027](https://github.com/angular/angular/issues/36027)) ([772bb5e](https://github.com/angular/angular/commit/772bb5e)) +* **ngcc:** use binary search when flattening mappings ([#36027](https://github.com/angular/angular/issues/36027)) ([348ff0c](https://github.com/angular/angular/commit/348ff0c)) +* **ngcc:** use line start positions for computing offsets in source-map flattening ([#36027](https://github.com/angular/angular/issues/36027)) ([e890082](https://github.com/angular/angular/commit/e890082)) +* **ngcc:** use the `EntryPointManifest` in `DirectoryWalkerEntryPointFinder` ([#35931](https://github.com/angular/angular/issues/35931)) ([ec9f4d5](https://github.com/angular/angular/commit/ec9f4d5)) ### Bug Fixes +* **animations:** Remove ɵAnimationDriver from private exports ([#35690](https://github.com/angular/angular/issues/35690)) ([ec789b0](https://github.com/angular/angular/commit/ec789b0)) +* **animations:** allow computeStyle to work on elements created in Node ([#35810](https://github.com/angular/angular/issues/35810)) ([17cf04e](https://github.com/angular/angular/commit/17cf04e)) +* **animations:** false positive when detecting Node in Webpack builds ([#35134](https://github.com/angular/angular/issues/35134)) ([dc4ae4b](https://github.com/angular/angular/commit/dc4ae4b)), closes [#35117](https://github.com/angular/angular/issues/35117) +* **animations:** process shorthand `margin` and `padding` styles correctly ([#35701](https://github.com/angular/angular/issues/35701)) ([35c9f0d](https://github.com/angular/angular/commit/35c9f0d)), closes [#35463](https://github.com/angular/angular/issues/35463) +* **bazel:** devserver shows blank page in Windows ([#35159](https://github.com/angular/angular/issues/35159)) ([727f92f](https://github.com/angular/angular/commit/727f92f)) +* **bazel:** do not use manifest paths for generated imports within compilation unit ([#35841](https://github.com/angular/angular/issues/35841)) ([9581658](https://github.com/angular/angular/commit/9581658)) +* **bazel:** ng_package rule creates incorrect UMD module exports ([#35792](https://github.com/angular/angular/issues/35792)) ([5c2a908](https://github.com/angular/angular/commit/5c2a908)), closes [angular/components#18652](https://github.com/angular/components/issues/18652) * **bazel:** prod server doesn't serve files in windows ([#35991](https://github.com/angular/angular/issues/35991)) ([96e3449](https://github.com/angular/angular/commit/96e3449)) +* **bazel:** spawn prod server using port 4200 ([#35160](https://github.com/angular/angular/issues/35160)) ([829f506](https://github.com/angular/angular/commit/829f506)) +* **bazel:** update ibazel to 0.11.1 ([#35158](https://github.com/angular/angular/issues/35158)) ([4e6d237](https://github.com/angular/angular/commit/4e6d237)) * **bazel:** update several packages for better windows support ([#35991](https://github.com/angular/angular/issues/35991)) ([32f099a](https://github.com/angular/angular/commit/32f099a)) * **bazel:** update typescript peer dependency range ([#36013](https://github.com/angular/angular/issues/36013)) ([5e3a898](https://github.com/angular/angular/commit/5e3a898)) +* **common:** let `KeyValuePipe` accept type unions with `null` ([#36093](https://github.com/angular/angular/issues/36093)) ([407fa42](https://github.com/angular/angular/commit/407fa42)), closes [#35743](https://github.com/angular/angular/issues/35743) +* **compiler-cli:** TypeScript peer dependency range ([#36008](https://github.com/angular/angular/issues/36008)) ([5f7d066](https://github.com/angular/angular/commit/5f7d066)) +* **compiler-cli:** suppress extraRequire errors in Closure Compiler ([#35737](https://github.com/angular/angular/issues/35737)) ([c296bfc](https://github.com/angular/angular/commit/c296bfc)) +* **compiler:** Propagate value span of ExpressionBinding to ParsedProperty ([#36133](https://github.com/angular/angular/issues/36133)) ([2ce5fa3](https://github.com/angular/angular/commit/2ce5fa3)) * **compiler:** do not recurse to find static symbols of same module ([#35262](https://github.com/angular/angular/issues/35262)) ([e179c58](https://github.com/angular/angular/commit/e179c58)) +* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477) +* **compiler:** report errors for missing binding names ([#34595](https://github.com/angular/angular/issues/34595)) ([d13cab7](https://github.com/angular/angular/commit/d13cab7)) * **compiler:** support directive inputs with interpolations on `<ng-template>`s ([#35984](https://github.com/angular/angular/issues/35984)) ([79659ee](https://github.com/angular/angular/commit/79659ee)), closes [#35752](https://github.com/angular/angular/issues/35752) -* **compiler-cli:** TypeScript peer dependency range ([#36008](https://github.com/angular/angular/issues/36008)) ([5f7d066](https://github.com/angular/angular/commit/5f7d066)) +* **compiler:** support i18n attributes on `<ng-template>` tags ([#35681](https://github.com/angular/angular/issues/35681)) ([40da51f](https://github.com/angular/angular/commit/40da51f)) +* **compiler:** type-checking error for duplicate variables in templates ([#35674](https://github.com/angular/angular/issues/35674)) ([2c41bb8](https://github.com/angular/angular/commit/2c41bb8)), closes [#35186](https://github.com/angular/angular/issues/35186) +* **compiler:** use FatalDiagnosticError to generate better error messages ([#35244](https://github.com/angular/angular/issues/35244)) ([646655d](https://github.com/angular/angular/commit/646655d)) +* **core:** Add `style="{{exp}}"` based interpolation ([#34202](https://github.com/angular/angular/issues/34202)) ([2562a3b](https://github.com/angular/angular/commit/2562a3b)), closes [#33575](https://github.com/angular/angular/issues/33575) +* **core:** Remove `debugger` statement ([#35763](https://github.com/angular/angular/issues/35763)) ([8f38eb7](https://github.com/angular/angular/commit/8f38eb7)), closes [#35470](https://github.com/angular/angular/issues/35470) +* **core:** Remove `debugger` statement when assert is thrown ([#35763](https://github.com/angular/angular/issues/35763)) ([4003538](https://github.com/angular/angular/commit/4003538)), closes [#35470](https://github.com/angular/angular/issues/35470) +* **core:** add `noSideEffects()` to `make*Decorator()` functions ([#35769](https://github.com/angular/angular/issues/35769)) ([dc6a791](https://github.com/angular/angular/commit/dc6a791)) +* **core:** add `noSideEffects()` to `ɵɵdefineComponent()` ([#35769](https://github.com/angular/angular/issues/35769)) ([ba36127](https://github.com/angular/angular/commit/ba36127)) +* **core:** add strictLiteralTypes to align core + VE checking of literals ([#35462](https://github.com/angular/angular/issues/35462)) ([4253662](https://github.com/angular/angular/commit/4253662)) +* **core:** adhere to bootstrap options for JIT compiled components ([#35534](https://github.com/angular/angular/issues/35534)) ([e342ffd](https://github.com/angular/angular/commit/e342ffd)), closes [#35230](https://github.com/angular/angular/issues/35230) +* **core:** allow null / undefined values in query results ([#35796](https://github.com/angular/angular/issues/35796)) ([5652fb1](https://github.com/angular/angular/commit/5652fb1)), closes [#35673](https://github.com/angular/angular/issues/35673) +* **core:** better handing of ICUs outside of i18n blocks ([#35347](https://github.com/angular/angular/issues/35347)) ([c013dd4](https://github.com/angular/angular/commit/c013dd4)) +* **core:** better inference for circularly referenced directive types ([#35622](https://github.com/angular/angular/issues/35622)) ([173a1ac](https://github.com/angular/angular/commit/173a1ac)), closes [#35372](https://github.com/angular/angular/issues/35372) [#35603](https://github.com/angular/angular/issues/35603) [#35522](https://github.com/angular/angular/issues/35522) +* **core:** correctly concatenate static and dynamic binding to `class` when shadowed ([#35350](https://github.com/angular/angular/issues/35350)) ([8c75f21](https://github.com/angular/angular/commit/8c75f21)), closes [#35335](https://github.com/angular/angular/issues/35335) * **core:** don't re-invoke pure pipes that throw and arguments are the same ([#35827](https://github.com/angular/angular/issues/35827)) ([19cfaf7](https://github.com/angular/angular/commit/19cfaf7)) +* **core:** emulate a View Engine type-checking bug with safe navigation ([#35462](https://github.com/angular/angular/issues/35462)) ([a61fe41](https://github.com/angular/angular/commit/a61fe41)) +* **core:** error in AOT when pipe inherits constructor from injectable that uses DI ([#35468](https://github.com/angular/angular/issues/35468)) ([e17bde9](https://github.com/angular/angular/commit/e17bde9)), closes [#35277](https://github.com/angular/angular/issues/35277) +* **core:** error when accessing NgModuleRef.componentFactoryResolver in constructor ([#35637](https://github.com/angular/angular/issues/35637)) ([835618c](https://github.com/angular/angular/commit/835618c)), closes [#35580](https://github.com/angular/angular/issues/35580) +* **core:** handle `<ng-template>` with local refs in i18n blocks ([#35758](https://github.com/angular/angular/issues/35758)) ([ef75875](https://github.com/angular/angular/commit/ef75875)) +* **core:** incorrectly generating shared pure function between null and object literal ([#35481](https://github.com/angular/angular/issues/35481)) ([22786c8](https://github.com/angular/angular/commit/22786c8)), closes [#33705](https://github.com/angular/angular/issues/33705) [#35298](https://github.com/angular/angular/issues/35298) +* **core:** injecting incorrect provider when re-providing injectable with useClass ([#34574](https://github.com/angular/angular/issues/34574)) ([0bc35a7](https://github.com/angular/angular/commit/0bc35a7)), closes [#34110](https://github.com/angular/angular/issues/34110) +* **core:** log error instead of warning for unknown properties and elements ([#35798](https://github.com/angular/angular/issues/35798)) ([00f3c58](https://github.com/angular/angular/commit/00f3c58)), closes [#35699](https://github.com/angular/angular/issues/35699) +* **core:** make subclass inherit developer-defined data ([#35105](https://github.com/angular/angular/issues/35105)) ([a756161](https://github.com/angular/angular/commit/a756161)) +* **core:** provide a more detailed error message for NG6002/NG6003 ([#35620](https://github.com/angular/angular/issues/35620)) ([2d89b5d](https://github.com/angular/angular/commit/2d89b5d)) +* **core:** remove side effects from `ɵɵNgOnChangesFeature()` ([#35769](https://github.com/angular/angular/issues/35769)) ([9cf85d2](https://github.com/angular/angular/commit/9cf85d2)) +* **core:** remove side effects from `ɵɵgetInheritedFactory()` ([#35769](https://github.com/angular/angular/issues/35769)) ([c195d22](https://github.com/angular/angular/commit/c195d22)) +* **core:** remove support for `Map`/`Set` in `[class]`/`[style]` bindings ([#35392](https://github.com/angular/angular/issues/35392)) ([2ca7984](https://github.com/angular/angular/commit/2ca7984)) +* **core:** support sanitizer value in the [style] bindings ([#35564](https://github.com/angular/angular/issues/35564)) ([3af103a](https://github.com/angular/angular/commit/3af103a)), closes [#35476](https://github.com/angular/angular/issues/35476) +* **core:** treat `[class]` and `[className]` as unrelated bindings ([#35668](https://github.com/angular/angular/issues/35668)) ([a153b61](https://github.com/angular/angular/commit/a153b61)), closes [#35577](https://github.com/angular/angular/issues/35577) +* **core:** unable to NgModuleRef.injector in module constructor ([#35731](https://github.com/angular/angular/issues/35731)) ([1f8a243](https://github.com/angular/angular/commit/1f8a243)), closes [#35677](https://github.com/angular/angular/issues/35677) [#35639](https://github.com/angular/angular/issues/35639) +* **core:** undecorated-classes-with-di migration should handle libraries generated with CLI versions past v6.2.0 ([#35824](https://github.com/angular/angular/issues/35824)) ([59607dc](https://github.com/angular/angular/commit/59607dc)), closes [#34985](https://github.com/angular/angular/issues/34985) +* **core:** use proper configuration to compile Injectable in JIT ([#35706](https://github.com/angular/angular/issues/35706)) ([7b13977](https://github.com/angular/angular/commit/7b13977)) * **core:** verify parsed ICU expression at runtime before executing it ([#35923](https://github.com/angular/angular/issues/35923)) ([8c2d842](https://github.com/angular/angular/commit/8c2d842)), closes [#35689](https://github.com/angular/angular/issues/35689) +* **core:** workaround Terser inlining bug ([#36200](https://github.com/angular/angular/issues/36200)) ([f71d132](https://github.com/angular/angular/commit/f71d132)) +* **elements:** correctly handle setting inputs to `undefined` ([#36140](https://github.com/angular/angular/issues/36140)) ([e066bdd](https://github.com/angular/angular/commit/e066bdd)) +* **elements:** correctly set `SimpleChange#firstChange` for pre-existing inputs ([#36140](https://github.com/angular/angular/issues/36140)) ([447a600](https://github.com/angular/angular/commit/447a600)), closes [#36130](https://github.com/angular/angular/issues/36130) +* **elements:** schematics fail with schema.json not found error ([#35211](https://github.com/angular/angular/issues/35211)) ([94d002b](https://github.com/angular/angular/commit/94d002b)), closes [#35154](https://github.com/angular/angular/issues/35154) +* **forms:** change Array.reduce usage to Array.forEach ([#35349](https://github.com/angular/angular/issues/35349)) ([554c2cb](https://github.com/angular/angular/commit/554c2cb)) +* **ivy:** `LFrame` needs to release memory on `leaveView()` ([#35156](https://github.com/angular/angular/issues/35156)) ([b9b512f](https://github.com/angular/angular/commit/b9b512f)), closes [#35148](https://github.com/angular/angular/issues/35148) +* **ivy:** add attributes and classes to host elements based on selector ([#34481](https://github.com/angular/angular/issues/34481)) ([f95b8ce](https://github.com/angular/angular/commit/f95b8ce)) +* **ivy:** ensure module imports are instantiated before the module being declared ([#35172](https://github.com/angular/angular/issues/35172)) ([b6a3a73](https://github.com/angular/angular/commit/b6a3a73)) +* **ivy:** error if directive with synthetic property binding is on same node as directive that injects ViewContainerRef ([#35343](https://github.com/angular/angular/issues/35343)) ([d6bc63f](https://github.com/angular/angular/commit/d6bc63f)), closes [#35342](https://github.com/angular/angular/issues/35342) +* **ivy:** narrow `NgIf` context variables in template type checker ([#35125](https://github.com/angular/angular/issues/35125)) ([40039d8](https://github.com/angular/angular/commit/40039d8)), closes [#34572](https://github.com/angular/angular/issues/34572) +* **ivy:** queries should match elements inside ng-container with the descendants: false option ([#35384](https://github.com/angular/angular/issues/35384)) ([3f4e02b](https://github.com/angular/angular/commit/3f4e02b)), closes [#34768](https://github.com/angular/angular/issues/34768) +* **ivy:** repeat template guards to narrow types in event handlers ([#35193](https://github.com/angular/angular/issues/35193)) ([dea1b96](https://github.com/angular/angular/commit/dea1b96)), closes [#35073](https://github.com/angular/angular/issues/35073) +* **ivy:** set namespace for host elements of dynamically created components ([#35136](https://github.com/angular/angular/issues/35136)) ([480a4c3](https://github.com/angular/angular/commit/480a4c3)) +* **ivy:** support dynamic query tokens in AOT mode ([#35307](https://github.com/angular/angular/issues/35307)) ([3e3a1ef](https://github.com/angular/angular/commit/3e3a1ef)), closes [#34267](https://github.com/angular/angular/issues/34267) +* **ivy:** wrong context passed to ngOnDestroy when resolved multiple times ([#35249](https://github.com/angular/angular/issues/35249)) ([5fbfe69](https://github.com/angular/angular/commit/5fbfe69)), closes [#35167](https://github.com/angular/angular/issues/35167) +* **language-service:** Suggest ? and ! operator on nullable receiver ([#35200](https://github.com/angular/angular/issues/35200)) ([3cc24a9](https://github.com/angular/angular/commit/3cc24a9)) +* **language-service:** fix calculation of pipe spans ([#35986](https://github.com/angular/angular/issues/35986)) ([406419b](https://github.com/angular/angular/commit/406419b)) +* **language-service:** get the right 'ElementAst' in the nested HTML tag ([#35317](https://github.com/angular/angular/issues/35317)) ([8e354da](https://github.com/angular/angular/commit/8e354da)) * **language-service:** infer $implicit value for ngIf template contexts ([#35941](https://github.com/angular/angular/issues/35941)) ([18b1bd4](https://github.com/angular/angular/commit/18b1bd4)) +* **language-service:** infer context type of structural directives ([#35537](https://github.com/angular/angular/issues/35537)) ([#35561](https://github.com/angular/angular/issues/35561)) ([54fd33f](https://github.com/angular/angular/commit/54fd33f)) +* **language-service:** provide completions for the structural directive that only injects the 'ViewContainerRef' ([#35466](https://github.com/angular/angular/issues/35466)) ([66c06eb](https://github.com/angular/angular/commit/66c06eb)) +* **language-service:** provide hover for interpolation in attribute value ([#35494](https://github.com/angular/angular/issues/35494)) ([049f118](https://github.com/angular/angular/commit/049f118)), closes [PR#34847](https://github.com/PR/issues/34847) +* **language-service:** resolve the real path for symlink ([#35895](https://github.com/angular/angular/issues/35895)) ([4e1d780](https://github.com/angular/angular/commit/4e1d780)) +* **language-service:** resolve the variable from the template context first ([#35982](https://github.com/angular/angular/issues/35982)) ([3d46a45](https://github.com/angular/angular/commit/3d46a45)) +* **localize:** allow ICU expansion case to start with any character except `}` ([#36123](https://github.com/angular/angular/issues/36123)) ([0767d37](https://github.com/angular/angular/commit/0767d37)), closes [#31586](https://github.com/angular/angular/issues/31586) +* **localize:** improve matching and parsing of XLIFF 1.2 translation files ([#35793](https://github.com/angular/angular/issues/35793)) ([350ac11](https://github.com/angular/angular/commit/350ac11)) +* **localize:** improve matching and parsing of XLIFF 2.0 translation files ([#35793](https://github.com/angular/angular/issues/35793)) ([08071e5](https://github.com/angular/angular/commit/08071e5)) +* **localize:** improve matching and parsing of XTB translation files ([#35793](https://github.com/angular/angular/issues/35793)) ([0e2a577](https://github.com/angular/angular/commit/0e2a577)) +* **localize:** improve placeholder mismatch error message ([#35593](https://github.com/angular/angular/issues/35593)) ([53f059e](https://github.com/angular/angular/commit/53f059e)) +* **localize:** merge translation from all XLIFF `<file>` elements ([#35936](https://github.com/angular/angular/issues/35936)) ([fc4c3c3](https://github.com/angular/angular/commit/fc4c3c3)), closes [#35839](https://github.com/angular/angular/issues/35839) * **localize:** show helpful error when providing an invalid cli option ([#36010](https://github.com/angular/angular/issues/36010)) ([aad02e8](https://github.com/angular/angular/commit/aad02e8)) +* **localize:** support minified ES5 `$localize` calls ([#35562](https://github.com/angular/angular/issues/35562)) ([df75451](https://github.com/angular/angular/commit/df75451)), closes [#35376](https://github.com/angular/angular/issues/35376) +* **ngcc:** add default config for `angular2-highcharts` ([#35527](https://github.com/angular/angular/issues/35527)) ([3cc8127](https://github.com/angular/angular/commit/3cc8127)), closes [#35399](https://github.com/angular/angular/issues/35399) +* **ngcc:** allow deep-import warnings to be ignored ([#35683](https://github.com/angular/angular/issues/35683)) ([20b0c80](https://github.com/angular/angular/commit/20b0c80)), closes [#35615](https://github.com/angular/angular/issues/35615) +* **ngcc:** capture path-mapped entry-points that start with same string ([#35592](https://github.com/angular/angular/issues/35592)) ([71b5970](https://github.com/angular/angular/commit/71b5970)), closes [#35536](https://github.com/angular/angular/issues/35536) * **ngcc:** consistently delegate to TypeScript host for typing files ([#36089](https://github.com/angular/angular/issues/36089)) ([9e70bcb](https://github.com/angular/angular/commit/9e70bcb)), closes [#35078](https://github.com/angular/angular/issues/35078) +* **ngcc:** correctly detect emitted TS helpers in ES5 ([#35191](https://github.com/angular/angular/issues/35191)) ([bd6a39c](https://github.com/angular/angular/commit/bd6a39c)) +* **ngcc:** correctly detect outer aliased class identifiers in ES5 ([#35527](https://github.com/angular/angular/issues/35527)) ([fde8915](https://github.com/angular/angular/commit/fde8915)), closes [#35399](https://github.com/angular/angular/issues/35399) +* **ngcc:** do not crash on entry-point that fails to compile ([#36083](https://github.com/angular/angular/issues/36083)) ([ff665b9](https://github.com/angular/angular/commit/ff665b9)) +* **ngcc:** do not crash on overlapping entry-points ([#36083](https://github.com/angular/angular/issues/36083)) ([c9f554c](https://github.com/angular/angular/commit/c9f554c)) +* **ngcc:** ensure that path-mapped secondary entry-points are processed correctly ([#35227](https://github.com/angular/angular/issues/35227)) ([c3c1140](https://github.com/angular/angular/commit/c3c1140)), closes [#35188](https://github.com/angular/angular/issues/35188) +* **ngcc:** handle imports in dts files when processing CommonJS ([#35191](https://github.com/angular/angular/issues/35191)) ([b6e8847](https://github.com/angular/angular/commit/b6e8847)), closes [#34356](https://github.com/angular/angular/issues/34356) +* **ngcc:** handle mappings outside the content when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([73cf7d5](https://github.com/angular/angular/commit/73cf7d5)), closes [#35709](https://github.com/angular/angular/issues/35709) +* **ngcc:** handle missing sources when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([72c4fda](https://github.com/angular/angular/commit/72c4fda)), closes [#35709](https://github.com/angular/angular/issues/35709) * **ngcc:** handle multiple original sources when flattening source-maps ([#36027](https://github.com/angular/angular/issues/36027)) ([a40be00](https://github.com/angular/angular/commit/a40be00)) +* **ngcc:** introduce a new LockFile implementation that uses a child-process ([#35861](https://github.com/angular/angular/issues/35861)) ([c55f900](https://github.com/angular/angular/commit/c55f900)), closes [#35761](https://github.com/angular/angular/issues/35761) * **ngcc:** show helpful error when providing an invalid option ([#36010](https://github.com/angular/angular/issues/36010)) ([1f89c61](https://github.com/angular/angular/commit/1f89c61)) - - -### Features - -* **bazel:** transform generated shims (in Ivy) with tsickle ([#35975](https://github.com/angular/angular/issues/35975)) ([e3ecdc6](https://github.com/angular/angular/commit/e3ecdc6)), closes [#35848](https://github.com/angular/angular/issues/35848) -* **compiler:** Add sourceSpan and keySpan to TemplateBinding ([#35897](https://github.com/angular/angular/issues/35897)) ([06779cf](https://github.com/angular/angular/commit/06779cf)) -* **compiler:** Propagate source span and value span to Variable AST ([#36047](https://github.com/angular/angular/issues/36047)) ([31bec8c](https://github.com/angular/angular/commit/31bec8c)) -* **language-service:** improve non-callable error message ([#35271](https://github.com/angular/angular/issues/35271)) ([acc483e](https://github.com/angular/angular/commit/acc483e)) -* **ngcc:** support invalidating the entry-point manifest ([#35931](https://github.com/angular/angular/issues/35931)) ([8ea61a1](https://github.com/angular/angular/commit/8ea61a1)) - - -### Performance Improvements - -* **ngcc:** link segment markers for faster traversal ([#36027](https://github.com/angular/angular/issues/36027)) ([47025e0](https://github.com/angular/angular/commit/47025e0)) -* **ngcc:** store the position of SegmentMarkers to avoid unnecessary computation ([#36027](https://github.com/angular/angular/issues/36027)) ([772bb5e](https://github.com/angular/angular/commit/772bb5e)) -* **ngcc:** use binary search when flattening mappings ([#36027](https://github.com/angular/angular/issues/36027)) ([348ff0c](https://github.com/angular/angular/commit/348ff0c)) -* **ngcc:** use line start positions for computing offsets in source-map flattening ([#36027](https://github.com/angular/angular/issues/36027)) ([e890082](https://github.com/angular/angular/commit/e890082)) -* **ngcc:** use the `EntryPointManifest` in `DirectoryWalkerEntryPointFinder` ([#35931](https://github.com/angular/angular/issues/35931)) ([ec9f4d5](https://github.com/angular/angular/commit/ec9f4d5)) - - +* **ngcc:** use path-mappings from tsconfig in dependency resolution ([#36180](https://github.com/angular/angular/issues/36180)) ([6defe96](https://github.com/angular/angular/commit/6defe96)), closes [#36119](https://github.com/angular/angular/issues/36119) +* **ngcc:** use preserve whitespaces from tsconfig if provided ([#36189](https://github.com/angular/angular/issues/36189)) ([aef4323](https://github.com/angular/angular/commit/aef4323)), closes [#35871](https://github.com/angular/angular/issues/35871) +* **platform-browser:** add missing peerDependency on `[@angular](https://github.com/angular)/animations` ([#35949](https://github.com/angular/angular/issues/35949)) ([64d6f13](https://github.com/angular/angular/commit/64d6f13)), closes [#35888](https://github.com/angular/angular/issues/35888) +* **router:** removed unused ApplicationRef dependency ([#35642](https://github.com/angular/angular/issues/35642)) ([c839c05](https://github.com/angular/angular/commit/c839c05)), closes [/github.com/angular/angular/commit/5a849829c42330d7e88e83e916e6e36380c97a97#diff-c0baae5e1df628e1a217e8dc38557](https://github.com//github.com/angular/angular/commit/5a849829c42330d7e88e83e916e6e36380c97a97/issues/diff-c0baae5e1df628e1a217e8dc38557) +* **router:** state data missing in routerLink ([#33203](https://github.com/angular/angular/issues/33203)) ([de67978](https://github.com/angular/angular/commit/de67978)) +* **service-worker:** treat 503 as offline ([#35595](https://github.com/angular/angular/issues/35595)) ([96cdf03](https://github.com/angular/angular/commit/96cdf03)), closes [#35571](https://github.com/angular/angular/issues/35571) +* fix flaky test cases of passive events ([#35679](https://github.com/angular/angular/issues/35679)) ([8ef29b6](https://github.com/angular/angular/commit/8ef29b6)) <a name="9.0.7"></a> ## [9.0.7](https://github.com/angular/angular/compare/9.0.6...9.0.7) (2020-03-18) @@ -121,38 +184,6 @@ Promoted `9.1.0-rc.2` to `9.1.0`. -<a name="9.1.0-next.4"></a> -# [9.1.0-next.4](https://github.com/angular/angular/compare/9.1.0-next.2...9.1.0-next.4) (2020-03-10) - - -### Bug Fixes - -* **bazel:** do not use manifest paths for generated imports within compilation unit ([#35841](https://github.com/angular/angular/issues/35841)) ([9581658](https://github.com/angular/angular/commit/9581658)) -* **core:** undecorated-classes-with-di migration should handle libraries generated with CLI versions past v6.2.0 ([#35824](https://github.com/angular/angular/issues/35824)) ([59607dc](https://github.com/angular/angular/commit/59607dc)), closes [#34985](https://github.com/angular/angular/issues/34985) -* **language-service:** fix calculation of pipe spans ([#35986](https://github.com/angular/angular/issues/35986)) ([406419b](https://github.com/angular/angular/commit/406419b)) -* **language-service:** resolve the real path for symlink ([#35895](https://github.com/angular/angular/issues/35895)) ([4e1d780](https://github.com/angular/angular/commit/4e1d780)) -* **language-service:** resolve the variable from the template context first ([#35982](https://github.com/angular/angular/issues/35982)) ([3d46a45](https://github.com/angular/angular/commit/3d46a45)) -* **localize:** improve matching and parsing of XLIFF 1.2 translation files ([#35793](https://github.com/angular/angular/issues/35793)) ([350ac11](https://github.com/angular/angular/commit/350ac11)) -* fix flaky test cases of passive events ([#35679](https://github.com/angular/angular/issues/35679)) ([8ef29b6](https://github.com/angular/angular/commit/8ef29b6)) -* **localize:** improve matching and parsing of XLIFF 2.0 translation files ([#35793](https://github.com/angular/angular/issues/35793)) ([08071e5](https://github.com/angular/angular/commit/08071e5)) -* **localize:** improve matching and parsing of XTB translation files ([#35793](https://github.com/angular/angular/issues/35793)) ([0e2a577](https://github.com/angular/angular/commit/0e2a577)) -* **localize:** merge translation from all XLIFF `<file>` elements ([#35936](https://github.com/angular/angular/issues/35936)) ([fc4c3c3](https://github.com/angular/angular/commit/fc4c3c3)), closes [#35839](https://github.com/angular/angular/issues/35839) -* **ngcc:** introduce a new LockFile implementation that uses a child-process ([#35861](https://github.com/angular/angular/issues/35861)) ([c55f900](https://github.com/angular/angular/commit/c55f900)), closes [#35761](https://github.com/angular/angular/issues/35761) -* **platform-browser:** add missing peerDependency on `[@angular](https://github.com/angular)/animations` ([#35949](https://github.com/angular/angular/issues/35949)) ([64d6f13](https://github.com/angular/angular/commit/64d6f13)), closes [#35888](https://github.com/angular/angular/issues/35888) -* **router:** state data missing in routerLink ([#33203](https://github.com/angular/angular/issues/33203)) ([de67978](https://github.com/angular/angular/commit/de67978)) - - -### Features - -* typescript 3.8 support ([#35864](https://github.com/angular/angular/issues/35864)) ([95c729f](https://github.com/angular/angular/commit/95c729f)) - - -### Performance Improvements - -* **ngcc:** reduce directory traversing ([#35756](https://github.com/angular/angular/issues/35756)) ([e0a35e1](https://github.com/angular/angular/commit/e0a35e1)), closes [#35717](https://github.com/angular/angular/issues/35717) - - - <a name="9.0.6"></a> ## [9.0.6](https://github.com/angular/angular/compare/9.0.5...9.0.6) (2020-03-10) @@ -180,53 +211,6 @@ Promoted `9.1.0-rc.2` to `9.1.0`. * **ngcc:** reduce directory traversing ([#35756](https://github.com/angular/angular/issues/35756)) ([2eaf420](https://github.com/angular/angular/commit/2eaf420)), closes [#35717](https://github.com/angular/angular/issues/35717) - -<a name="9.1.0-next.3"></a> -# [9.1.0-next.3](https://github.com/angular/angular/compare/9.1.0-next.2...9.1.0-next.3) (2020-03-04) - - -### Bug Fixes - -* **animations:** allow computeStyle to work on elements created in Node ([#35810](https://github.com/angular/angular/issues/35810)) ([17cf04e](https://github.com/angular/angular/commit/17cf04e)) -* **animations:** process shorthand `margin` and `padding` styles correctly ([#35701](https://github.com/angular/angular/issues/35701)) ([35c9f0d](https://github.com/angular/angular/commit/35c9f0d)), closes [#35463](https://github.com/angular/angular/issues/35463) -* **bazel:** ng_package rule creates incorrect UMD module exports ([#35792](https://github.com/angular/angular/issues/35792)) ([5c2a908](https://github.com/angular/angular/commit/5c2a908)), closes [angular/components#18652](https://github.com/angular/components/issues/18652) -* **compiler:** support i18n attributes on `<ng-template>` tags ([#35681](https://github.com/angular/angular/issues/35681)) ([40da51f](https://github.com/angular/angular/commit/40da51f)) -* **compiler:** type-checking error for duplicate variables in templates ([#35674](https://github.com/angular/angular/issues/35674)) ([2c41bb8](https://github.com/angular/angular/commit/2c41bb8)), closes [#35186](https://github.com/angular/angular/issues/35186) -* **compiler-cli:** suppress extraRequire errors in Closure Compiler ([#35737](https://github.com/angular/angular/issues/35737)) ([c296bfc](https://github.com/angular/angular/commit/c296bfc)) -* **core:** add `noSideEffects()` to `make*Decorator()` functions ([#35769](https://github.com/angular/angular/issues/35769)) ([dc6a791](https://github.com/angular/angular/commit/dc6a791)) -* **core:** add `noSideEffects()` to `ɵɵdefineComponent()` ([#35769](https://github.com/angular/angular/issues/35769)) ([ba36127](https://github.com/angular/angular/commit/ba36127)) -* **core:** allow null / undefined values in query results ([#35796](https://github.com/angular/angular/issues/35796)) ([5652fb1](https://github.com/angular/angular/commit/5652fb1)), closes [#35673](https://github.com/angular/angular/issues/35673) -* **core:** handle `<ng-template>` with local refs in i18n blocks ([#35758](https://github.com/angular/angular/issues/35758)) ([ef75875](https://github.com/angular/angular/commit/ef75875)) -* **core:** log error instead of warning for unknown properties and elements ([#35798](https://github.com/angular/angular/issues/35798)) ([00f3c58](https://github.com/angular/angular/commit/00f3c58)), closes [#35699](https://github.com/angular/angular/issues/35699) -* **core:** Remove `debugger` statement ([#35763](https://github.com/angular/angular/issues/35763)) ([8f38eb7](https://github.com/angular/angular/commit/8f38eb7)), closes [#35470](https://github.com/angular/angular/issues/35470) -* **core:** Remove `debugger` statement when assert is thrown ([#35763](https://github.com/angular/angular/issues/35763)) ([4003538](https://github.com/angular/angular/commit/4003538)), closes [#35470](https://github.com/angular/angular/issues/35470) -* **core:** remove side effects from `ɵɵgetInheritedFactory()` ([#35769](https://github.com/angular/angular/issues/35769)) ([c195d22](https://github.com/angular/angular/commit/c195d22)) -* **core:** remove side effects from `ɵɵNgOnChangesFeature()` ([#35769](https://github.com/angular/angular/issues/35769)) ([9cf85d2](https://github.com/angular/angular/commit/9cf85d2)) -* **core:** treat `[class]` and `[className]` as unrelated bindings ([#35668](https://github.com/angular/angular/issues/35668)) ([a153b61](https://github.com/angular/angular/commit/a153b61)), closes [#35577](https://github.com/angular/angular/issues/35577) -* **core:** unable to NgModuleRef.injector in module constructor ([#35731](https://github.com/angular/angular/issues/35731)) ([1f8a243](https://github.com/angular/angular/commit/1f8a243)), closes [#35677](https://github.com/angular/angular/issues/35677) [#35639](https://github.com/angular/angular/issues/35639) -* **core:** use proper configuration to compile Injectable in JIT ([#35706](https://github.com/angular/angular/issues/35706)) ([7b13977](https://github.com/angular/angular/commit/7b13977)) -* **ivy:** narrow `NgIf` context variables in template type checker ([#35125](https://github.com/angular/angular/issues/35125)) ([40039d8](https://github.com/angular/angular/commit/40039d8)), closes [#34572](https://github.com/angular/angular/issues/34572) -* **ivy:** support dynamic query tokens in AOT mode ([#35307](https://github.com/angular/angular/issues/35307)) ([3e3a1ef](https://github.com/angular/angular/commit/3e3a1ef)), closes [#34267](https://github.com/angular/angular/issues/34267) -* **ngcc:** allow deep-import warnings to be ignored ([#35683](https://github.com/angular/angular/issues/35683)) ([20b0c80](https://github.com/angular/angular/commit/20b0c80)), closes [#35615](https://github.com/angular/angular/issues/35615) -* **ngcc:** handle mappings outside the content when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([73cf7d5](https://github.com/angular/angular/commit/73cf7d5)), closes [#35709](https://github.com/angular/angular/issues/35709) -* **ngcc:** handle missing sources when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([72c4fda](https://github.com/angular/angular/commit/72c4fda)), closes [#35709](https://github.com/angular/angular/issues/35709) - - -### Features - -* **language-service:** modularize error messages ([#35678](https://github.com/angular/angular/issues/35678)) ([47a1811](https://github.com/angular/angular/commit/47a1811)), closes [#32663](https://github.com/angular/angular/issues/32663) -* define all zone.js configurations to typescript interfaces ([#35329](https://github.com/angular/angular/issues/35329)) ([03d88c7](https://github.com/angular/angular/commit/03d88c7)) - - -### Performance Improvements - -* **core:** add micro benchmark for destroy hook invocation ([#35784](https://github.com/angular/angular/issues/35784)) ([0653db1](https://github.com/angular/angular/commit/0653db1)) -* **core:** adding micro benchmark for host bindings ([#35705](https://github.com/angular/angular/issues/35705)) ([8fed1fe](https://github.com/angular/angular/commit/8fed1fe)), closes [#35568](https://github.com/angular/angular/issues/35568) -* **core:** use multiple directives in host bindings micro benchmark ([#35736](https://github.com/angular/angular/issues/35736)) ([5bc39f8](https://github.com/angular/angular/commit/5bc39f8)) -* **ngcc:** only create tasks for non-processed formats ([#35719](https://github.com/angular/angular/issues/35719)) ([d7efc45](https://github.com/angular/angular/commit/d7efc45)) -* **ngcc:** spawn workers lazily ([#35719](https://github.com/angular/angular/issues/35719)) ([dc40a93](https://github.com/angular/angular/commit/dc40a93)), closes [#35717](https://github.com/angular/angular/issues/35717) - - <a name="9.0.5"></a> ## [9.0.5](https://github.com/angular/angular/compare/9.0.4...9.0.5) (2020-03-04) @@ -275,58 +259,6 @@ Promoted `9.1.0-rc.2` to `9.1.0`. * **ngcc:** handle missing sources when flattening source-maps ([#35718](https://github.com/angular/angular/issues/35718)) ([7ff845b](https://github.com/angular/angular/commit/7ff845b)), closes [#35709](https://github.com/angular/angular/issues/35709) -<a name="9.1.0-next.2"></a> -# [9.1.0-next.2](https://github.com/angular/angular/compare/9.1.0-next.1...9.1.0-next.2) (2020-02-27) - - -### Bug Fixes - -* **animations:** false positive when detecting Node in Webpack builds ([#35134](https://github.com/angular/angular/issues/35134)) ([dc4ae4b](https://github.com/angular/angular/commit/dc4ae4b)), closes [#35117](https://github.com/angular/angular/issues/35117) -* **animations:** Remove ɵAnimationDriver from private exports ([#35690](https://github.com/angular/angular/issues/35690)) ([ec789b0](https://github.com/angular/angular/commit/ec789b0)) -* **compiler:** use FatalDiagnosticError to generate better error messages ([#35244](https://github.com/angular/angular/issues/35244)) ([646655d](https://github.com/angular/angular/commit/646655d)) -* **core:** make subclass inherit developer-defined data ([#35105](https://github.com/angular/angular/issues/35105)) ([a756161](https://github.com/angular/angular/commit/a756161)) -* **core:** support sanitizer value in the [style] bindings ([#35564](https://github.com/angular/angular/issues/35564)) ([3af103a](https://github.com/angular/angular/commit/3af103a)), closes [#35476](https://github.com/angular/angular/issues/35476) -* **core:** Add `style="{{exp}}"` based interpolation ([#34202](https://github.com/angular/angular/issues/34202)) ([2562a3b](https://github.com/angular/angular/commit/2562a3b)), closes [#33575](https://github.com/angular/angular/issues/33575) -* **core:** add strictLiteralTypes to align core + VE checking of literals ([#35462](https://github.com/angular/angular/issues/35462)) ([4253662](https://github.com/angular/angular/commit/4253662)) -* **core:** better inference for circularly referenced directive types ([#35622](https://github.com/angular/angular/issues/35622)) ([173a1ac](https://github.com/angular/angular/commit/173a1ac)), closes [#35372](https://github.com/angular/angular/issues/35372) [#35603](https://github.com/angular/angular/issues/35603) [#35522](https://github.com/angular/angular/issues/35522) -* **core:** emulate a View Engine type-checking bug with safe navigation ([#35462](https://github.com/angular/angular/issues/35462)) ([a61fe41](https://github.com/angular/angular/commit/a61fe41)) -* **core:** error in AOT when pipe inherits constructor from injectable that uses DI ([#35468](https://github.com/angular/angular/issues/35468)) ([e17bde9](https://github.com/angular/angular/commit/e17bde9)), closes [#35277](https://github.com/angular/angular/issues/35277) -* **core:** error when accessing NgModuleRef.componentFactoryResolver in constructor ([#35637](https://github.com/angular/angular/issues/35637)) ([835618c](https://github.com/angular/angular/commit/835618c)), closes [#35580](https://github.com/angular/angular/issues/35580) -* **core:** incorrectly generating shared pure function between null and object literal ([#35481](https://github.com/angular/angular/issues/35481)) ([22786c8](https://github.com/angular/angular/commit/22786c8)), closes [#33705](https://github.com/angular/angular/issues/33705) [#35298](https://github.com/angular/angular/issues/35298) -* **core:** injecting incorrect provider when re-providing injectable with useClass ([#34574](https://github.com/angular/angular/issues/34574)) ([0bc35a7](https://github.com/angular/angular/commit/0bc35a7)), closes [#34110](https://github.com/angular/angular/issues/34110) -* **core:** provide a more detailed error message for NG6002/NG6003 ([#35620](https://github.com/angular/angular/issues/35620)) ([2d89b5d](https://github.com/angular/angular/commit/2d89b5d)) -* **language-service:** get the right 'ElementAst' in the nested HTML tag ([#35317](https://github.com/angular/angular/issues/35317)) ([8e354da](https://github.com/angular/angular/commit/8e354da)) -* **language-service:** infer context type of structural directives ([#35537](https://github.com/angular/angular/issues/35537)) ([#35561](https://github.com/angular/angular/issues/35561)) ([54fd33f](https://github.com/angular/angular/commit/54fd33f)) -* **language-service:** provide completions for the structural directive that only injects the 'ViewContainerRef' ([#35466](https://github.com/angular/angular/issues/35466)) ([66c06eb](https://github.com/angular/angular/commit/66c06eb)) -* **language-service:** provide hover for interpolation in attribute value ([#35494](https://github.com/angular/angular/issues/35494)) ([049f118](https://github.com/angular/angular/commit/049f118)), closes [PR#34847](https://github.com/PR/issues/34847) -* **localize:** improve placeholder mismatch error message ([#35593](https://github.com/angular/angular/issues/35593)) ([53f059e](https://github.com/angular/angular/commit/53f059e)) -* **localize:** support minified ES5 `$localize` calls ([#35562](https://github.com/angular/angular/issues/35562)) ([df75451](https://github.com/angular/angular/commit/df75451)), closes [#35376](https://github.com/angular/angular/issues/35376) -* **ngcc:** add default config for `angular2-highcharts` ([#35527](https://github.com/angular/angular/issues/35527)) ([3cc8127](https://github.com/angular/angular/commit/3cc8127)), closes [#35399](https://github.com/angular/angular/issues/35399) -* **ngcc:** capture path-mapped entry-points that start with same string ([#35592](https://github.com/angular/angular/issues/35592)) ([71b5970](https://github.com/angular/angular/commit/71b5970)), closes [#35536](https://github.com/angular/angular/issues/35536) -* **ngcc:** correctly detect emitted TS helpers in ES5 ([#35191](https://github.com/angular/angular/issues/35191)) ([bd6a39c](https://github.com/angular/angular/commit/bd6a39c)) -* **ngcc:** correctly detect outer aliased class identifiers in ES5 ([#35527](https://github.com/angular/angular/issues/35527)) ([fde8915](https://github.com/angular/angular/commit/fde8915)), closes [#35399](https://github.com/angular/angular/issues/35399) -* **ngcc:** handle imports in dts files when processing CommonJS ([#35191](https://github.com/angular/angular/issues/35191)) ([b6e8847](https://github.com/angular/angular/commit/b6e8847)), closes [#34356](https://github.com/angular/angular/issues/34356) -* **router:** removed unused ApplicationRef dependency ([#35642](https://github.com/angular/angular/issues/35642)) ([c839c05](https://github.com/angular/angular/commit/c839c05)), closes [/github.com/angular/angular/commit/5a849829c42330d7e88e83e916e6e36380c97a97#diff-c0baae5e1df628e1a217e8dc38557](https://github.com//github.com/angular/angular/commit/5a849829c42330d7e88e83e916e6e36380c97a97/issues/diff-c0baae5e1df628e1a217e8dc38557) -* **service-worker:** treat 503 as offline ([#35595](https://github.com/angular/angular/issues/35595)) ([96cdf03](https://github.com/angular/angular/commit/96cdf03)), closes [#35571](https://github.com/angular/angular/issues/35571) - - -### Features - -* **ngcc:** implement source-map flattening ([#35132](https://github.com/angular/angular/issues/35132)) ([df816c9](https://github.com/angular/angular/commit/df816c9)) -* **bazel:** enable ivy template type-checking in g3 ([#35672](https://github.com/angular/angular/issues/35672)) ([8f5b7f3](https://github.com/angular/angular/commit/8f5b7f3)) -* **zone.js** add interface definitions which zone extends EventTarget ([#35304](https://github.com/angular/angular/issues/35304)) ([4acb676](https://github.com/angular/angular/commit/4acb676)), closes [#35173](https://github.com/angular/angular/issues/35173) -* **zone.js** add a temp solution to support passive event listeners. ([#34503](https://github.com/angular/angular/issues/34503)) ([f9d483e](https://github.com/angular/angular/commit/f9d483e)) -* **zone.js** add an tickOptions parameter with property processNewMacroTasksSynchronously. ([#33838](https://github.com/angular/angular/issues/33838)) ([17b862c](https://github.com/angular/angular/commit/17b862c)), closes [#33799](https://github.com/angular/angular/issues/33799) -* **zone.js** support passive event options by defining global variables in zone.js config file ([#34503](https://github.com/angular/angular/issues/34503)) ([d7d359e](https://github.com/angular/angular/commit/d7d359e)) - - -### Performance Improvements - -* **core:** avoid recursive scope recalculation when TestBed.overrideModule is used ([#35454](https://github.com/angular/angular/issues/35454)) ([0a1a989](https://github.com/angular/angular/commit/0a1a989)) -* **ivy:** remove unused event argument in listener instructions ([#35097](https://github.com/angular/angular/issues/35097)) ([9228d7f](https://github.com/angular/angular/commit/9228d7f)) - - - <a name="9.0.3"></a> ## [9.0.3](https://github.com/angular/angular/compare/9.0.2...9.0.3) (2020-02-27) @@ -374,28 +306,6 @@ Promoted `9.1.0-rc.2` to `9.1.0`. -<a name="9.1.0-next.1"></a> -# [9.1.0-next.1](https://github.com/angular/angular/compare/9.1.0-next.0...9.1.0-next.1) (2020-02-19) - - -### Bug Fixes - -* **core:** better handing of ICUs outside of i18n blocks ([#35347](https://github.com/angular/angular/issues/35347)) ([c013dd4](https://github.com/angular/angular/commit/c013dd4)) -* **core:** correctly concatenate static and dynamic binding to `class` when shadowed ([#35350](https://github.com/angular/angular/issues/35350)) ([8c75f21](https://github.com/angular/angular/commit/8c75f21)), closes [#35335](https://github.com/angular/angular/issues/35335) -* **core:** remove support for `Map`/`Set` in `[class]`/`[style]` bindings ([#35392](https://github.com/angular/angular/issues/35392)) ([2ca7984](https://github.com/angular/angular/commit/2ca7984)) -* **ivy:** `LFrame` needs to release memory on `leaveView()` ([#35156](https://github.com/angular/angular/issues/35156)) ([b9b512f](https://github.com/angular/angular/commit/b9b512f)), closes [#35148](https://github.com/angular/angular/issues/35148) -* **ivy:** add attributes and classes to host elements based on selector ([#34481](https://github.com/angular/angular/issues/34481)) ([f95b8ce](https://github.com/angular/angular/commit/f95b8ce)) -* **ivy:** error if directive with synthetic property binding is on same node as directive that injects ViewContainerRef ([#35343](https://github.com/angular/angular/issues/35343)) ([d6bc63f](https://github.com/angular/angular/commit/d6bc63f)), closes [#35342](https://github.com/angular/angular/issues/35342) -* **ivy:** queries should match elements inside ng-container with the descendants: false option ([#35384](https://github.com/angular/angular/issues/35384)) ([3f4e02b](https://github.com/angular/angular/commit/3f4e02b)), closes [#34768](https://github.com/angular/angular/issues/34768) -* **ivy:** wrong context passed to ngOnDestroy when resolved multiple times ([#35249](https://github.com/angular/angular/issues/35249)) ([5fbfe69](https://github.com/angular/angular/commit/5fbfe69)), closes [#35167](https://github.com/angular/angular/issues/35167) - - -### Features - -* **ngcc:** pause async ngcc processing if another process has the lockfile ([#35131](https://github.com/angular/angular/issues/35131)) ([eef0753](https://github.com/angular/angular/commit/eef0753)) - - - <a name="9.0.2"></a> ## [9.0.2](https://github.com/angular/angular/compare/9.0.1...9.0.2) (2020-02-19) @@ -413,29 +323,6 @@ Promoted `9.1.0-rc.2` to `9.1.0`. -<a name="9.1.0-next.0"></a> -## [9.1.0-next.0](https://github.com/angular/angular/compare/9.0.0...9.1.0-next.0) (2020-02-12) - -### Bug Fixes - -* **bazel:** devserver shows blank page in Windows ([#35159](https://github.com/angular/angular/issues/35159)) ([727f92f](https://github.com/angular/angular/commit/727f92f)) -* **bazel:** spawn prod server using port 4200 ([#35160](https://github.com/angular/angular/issues/35160)) ([829f506](https://github.com/angular/angular/commit/829f506)) -* **bazel:** update ibazel to 0.11.1 ([#35158](https://github.com/angular/angular/issues/35158)) ([4e6d237](https://github.com/angular/angular/commit/4e6d237)) -* **compiler:** report errors for missing binding names ([#34595](https://github.com/angular/angular/issues/34595)) ([d13cab7](https://github.com/angular/angular/commit/d13cab7)) -* **elements:** schematics fail with schema.json not found error ([#35211](https://github.com/angular/angular/issues/35211)) ([94d002b](https://github.com/angular/angular/commit/94d002b)), closes [#35154](https://github.com/angular/angular/issues/35154) -* **forms:** change Array.reduce usage to Array.forEach ([#35349](https://github.com/angular/angular/issues/35349)) ([554c2cb](https://github.com/angular/angular/commit/554c2cb)) -* **ivy:** ensure module imports are instantiated before the module being declared ([#35172](https://github.com/angular/angular/issues/35172)) ([b6a3a73](https://github.com/angular/angular/commit/b6a3a73)) -* **ivy:** repeat template guards to narrow types in event handlers ([#35193](https://github.com/angular/angular/issues/35193)) ([dea1b96](https://github.com/angular/angular/commit/dea1b96)), closes [#35073](https://github.com/angular/angular/issues/35073) -* **ivy:** set namespace for host elements of dynamically created components ([#35136](https://github.com/angular/angular/issues/35136)) ([480a4c3](https://github.com/angular/angular/commit/480a4c3)) -* **language-service:** Suggest ? and ! operator on nullable receiver ([#35200](https://github.com/angular/angular/issues/35200)) ([3cc24a9](https://github.com/angular/angular/commit/3cc24a9)) -* **ngcc:** ensure that path-mapped secondary entry-points are processed correctly ([#35227](https://github.com/angular/angular/issues/35227)) ([c3c1140](https://github.com/angular/angular/commit/c3c1140)), closes [#35188](https://github.com/angular/angular/issues/35188) - -### Features - -* **compiler-cli:** implement NgTscPlugin on top of the NgCompiler API ([#34792](https://github.com/angular/angular/issues/34792)) ([3c69442dbd](https://github.com/angular/angular/commit/3c69442dbd)) - - - <a name="9.0.1"></a> ## [9.0.1](https://github.com/angular/angular/compare/9.0.0...9.0.1) (2020-02-12) From d96995b4e35bfc49222473cd0e4523f8625c3b50 Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 19 Feb 2020 09:22:05 -0800 Subject: [PATCH 036/262] docs: update glossary defs for components, templates, and views (#35559) PR Close #35559 --- aio/content/guide/glossary.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/aio/content/guide/glossary.md b/aio/content/guide/glossary.md index 5cabe26ed20af..256f402d8e614 100644 --- a/aio/content/guide/glossary.md +++ b/aio/content/guide/glossary.md @@ -202,13 +202,13 @@ See also [Schematics CLI](#schematics-cli). ## component -A class with the `@Component()` [decorator](#decorator) that associates it with a companion [template](#template). Together, the component and template define a [view](#view). +A class with the `@Component()` [decorator](#decorator) that associates it with a companion [template](#template). Together, the component class and template define a [view](#view). A component is a special type of [directive](#directive). The `@Component()` decorator extends the `@Directive()` decorator with template-oriented features. An Angular component class is responsible for exposing data and handling most of the view's display and user-interaction logic through [data binding](#data-binding). -Read more about components, templates, and views in [Architecture Overview](guide/architecture). +Read more about component classes, templates, and views in [Introduction to Angular concepts](guide/architecture). ## configuration @@ -878,13 +878,13 @@ You can also define a custom builder, and add a target to the project configurat ## template -Code associated with a component that defines how to render the component's [view](#view). +Code that defines how to render a component's [view](#view). A template combines straight HTML with Angular [data-binding](#data-binding) syntax, [directives](#directive), and [template expressions](#template-expression) (logical constructs). -The Angular elements insert or calculate values that modify the HTML elements before the page is displayed. +The Angular elements insert or calculate values that modify the HTML elements before the page is displayed. Learn more about Angular template language in the [Template Syntax](guide/template-syntax) guide. -A template is associated with a [component](#component) class through the `@Component()` [decorator](#decorator). The HTML can be provided inline, as the value of the `template` property, or in a separate HTML file linked through the `templateUrl` property. +A template is associated with a [component class](#component) through the `@Component()` [decorator](#decorator). The template code can be provided inline, as the value of the `template` property, or in a separate HTML file linked through the `templateUrl` property. Additional templates, represented by `TemplateRef` objects, can define alternative or *embedded* views, which can be referenced from multiple components. @@ -963,12 +963,12 @@ To learn more, see [Angular Universal: server-side rendering](guide/universal). ## view The smallest grouping of display elements that can be created and destroyed together. -Angular renders a view under the control of one or more [directives](#directive), -especially [component](#component) directives and their companion [templates](#template). +Angular renders a view under the control of one or more [directives](#directive). -A view is specifically represented by a `ViewRef` instance associated with the component. -A view that belongs to a component is called a *host view*. -Views are typically collected into [view hierarchies](#view-tree). +A [component](#component) class and its associated [template](#template) define a view. +A view is specifically represented by a `ViewRef` instance associated with a component. +A view that belongs immediately to a component is called a *host view*. +Views are typically collected into [view hierarchies](#view-tree). Properties of elements in a view can change dynamically, in response to user actions; the structure (number and order) of elements in a view can't. From 00efacf561e8e935dcfbf48bab153aab3247df9d Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Tue, 24 Mar 2020 22:54:51 +0200 Subject: [PATCH 037/262] feat(service-worker): support timeout in `registerWhenStable` SW registration strategy (#35870) Previously, when using the `registerWhenStable` ServiceWorker registration strategy (which is also the default) Angular would wait indefinitely for the [app to stabilize][1], before registering the ServiceWorker script. This could lead to a situation where the ServiceWorker would never be registered when there was a long-running task (such as an interval or recurring timeout). Such tasks can often be started by a 3rd-party dependency (beyond the developer's control or even without them realizing). In addition, this situation is particularly hard to detect, because the ServiceWorker is typically not used during development and on production builds a previous ServiceWorker instance might be already active. This commit enhances the `registerWhenStable` registration strategy by adding support for an optional `<timeout>` argument, which guarantees that the ServiceWorker will be registered when the timeout expires, even if the app has not stabilized yet. For example, with `registerWhenStable:5000` the ServiceWorker will be registered as soon as the app stabilizes or after 5 seconds if the app has not stabilized by then. Related to #34464. [1]: https://angular.io/api/core/ApplicationRef#is-stable-examples PR Close #35870 --- packages/service-worker/src/module.ts | 25 +++++-- packages/service-worker/test/module_spec.ts | 74 ++++++++++++++++++++- 2 files changed, 91 insertions(+), 8 deletions(-) diff --git a/packages/service-worker/src/module.ts b/packages/service-worker/src/module.ts index 4979f2d6925eb..7e7779f5d769c 100644 --- a/packages/service-worker/src/module.ts +++ b/packages/service-worker/src/module.ts @@ -8,7 +8,7 @@ import {isPlatformBrowser} from '@angular/common'; import {APP_INITIALIZER, ApplicationRef, InjectionToken, Injector, ModuleWithProviders, NgModule, PLATFORM_ID} from '@angular/core'; -import {Observable, of } from 'rxjs'; +import {Observable, merge, of } from 'rxjs'; import {delay, filter, take} from 'rxjs/operators'; import {NgswCommChannel} from './low_level'; @@ -55,8 +55,12 @@ export abstract class SwRegistrationOptions { * registered (e.g. there might be a long-running timeout or polling interval, preventing the app * to stabilize). The available option are: * - * - `registerWhenStable`: Register as soon as the application stabilizes (no pending - * micro-/macro-tasks). + * - `registerWhenStable:<timeout>`: Register as soon as the application stabilizes (no pending + * micro-/macro-tasks) but no later than `<timeout>` milliseconds. If the app hasn't + * stabilized after `<timeout>` milliseconds (for example, due to a recurrent asynchronous + * task), the ServiceWorker will be registered anyway. + * If `<timeout>` is omitted, the ServiceWorker will only be registered once the app + * stabilizes. * - `registerImmediately`: Register immediately. * - `registerWithDelay:<timeout>`: Register with a delay of `<timeout>` milliseconds. For * example, use `registerWithDelay:5000` to register the ServiceWorker after 5 seconds. If @@ -102,11 +106,11 @@ export function ngswAppInitializer( readyToRegister$ = of (null); break; case 'registerWithDelay': - readyToRegister$ = of (null).pipe(delay(+args[0] || 0)); + readyToRegister$ = delayWithTimeout(+args[0] || 0); break; case 'registerWhenStable': - const appRef = injector.get<ApplicationRef>(ApplicationRef); - readyToRegister$ = appRef.isStable.pipe(filter(stable => stable)); + readyToRegister$ = !args[0] ? whenStable(injector) : + merge(whenStable(injector), delayWithTimeout(+args[0])); break; default: // Unknown strategy. @@ -124,6 +128,15 @@ export function ngswAppInitializer( return initializer; } +function delayWithTimeout(timeout: number): Observable<unknown> { + return of (null).pipe(delay(timeout)); +} + +function whenStable(injector: Injector): Observable<unknown> { + const appRef = injector.get(ApplicationRef); + return appRef.isStable.pipe(filter(stable => stable)); +} + export function ngswCommChannelFactory( opts: SwRegistrationOptions, platformId: string): NgswCommChannel { return new NgswCommChannel( diff --git a/packages/service-worker/test/module_spec.ts b/packages/service-worker/test/module_spec.ts index 0276d0b875571..46591e100fc04 100644 --- a/packages/service-worker/test/module_spec.ts +++ b/packages/service-worker/test/module_spec.ts @@ -141,7 +141,7 @@ describe('ServiceWorkerModule', () => { ], }); - // Dummy `get()` call to initialize the test "app". + // Dummy `inject()` call to initialize the test "app". TestBed.inject(ApplicationRef); return isStableSub; @@ -156,13 +156,80 @@ describe('ServiceWorkerModule', () => { tick(); expect(swRegisterSpy).not.toHaveBeenCalled(); + tick(60000); + expect(swRegisterSpy).not.toHaveBeenCalled(); + isStableSub.next(true); tick(); expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); })); - it('registers the SW when the app stabilizes with `registerWhenStable`', fakeAsync(() => { + it('registers the SW when the app stabilizes with `registerWhenStable:<timeout>`', + fakeAsync(() => { + const isStableSub = configTestBedWithMockedStability('registerWhenStable:1000'); + + isStableSub.next(false); + isStableSub.next(false); + + tick(); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + tick(500); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + isStableSub.next(true); + + tick(); + expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); + })); + + it('registers the SW after `timeout` if the app does not stabilize with `registerWhenStable:<timeout>`', + fakeAsync(() => { + configTestBedWithMockedStability('registerWhenStable:1000'); + + tick(999); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + tick(1); + expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); + })); + + it('registers the SW asap (asynchronously) before the app stabilizes with `registerWhenStable:0`', + fakeAsync(() => { + const isStableSub = configTestBedWithMockedStability('registerWhenStable:0'); + + // Create a microtask. + Promise.resolve(); + + flushMicrotasks(); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + tick(0); + expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); + })); + + it('registers the SW only when the app stabilizes with `registerWhenStable:`', + fakeAsync(() => { + const isStableSub = configTestBedWithMockedStability('registerWhenStable:'); + + isStableSub.next(false); + isStableSub.next(false); + + tick(); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + tick(60000); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + isStableSub.next(true); + + tick(); + expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); + })); + + it('registers the SW only when the app stabilizes with `registerWhenStable`', + fakeAsync(() => { const isStableSub = configTestBedWithMockedStability('registerWhenStable'); isStableSub.next(false); @@ -171,6 +238,9 @@ describe('ServiceWorkerModule', () => { tick(); expect(swRegisterSpy).not.toHaveBeenCalled(); + tick(60000); + expect(swRegisterSpy).not.toHaveBeenCalled(); + isStableSub.next(true); tick(); From 29e8a64cf02fa9b80d38c30091e0b730403c54c8 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Tue, 24 Mar 2020 22:54:53 +0200 Subject: [PATCH 038/262] fix(service-worker): by default register the SW after 30s even the app never stabilizes (#35870) Previously, when using the default ServiceWorker registration strategy Angular would wait indefinitely for the [app to stabilize][1], before registering the ServiceWorker script. This could lead to a situation where the ServiceWorker would never be registered when there was a long-running task (such as an interval or recurring timeout). Such tasks can often be started by a 3rd-party dependency (beyond the developer's control or even without them realizing). In addition, this situation is particularly hard to detect, because the ServiceWorker is typically not used during development and on production builds a previous ServiceWorker instance might be already active. This commit fixes this by changing the default registration strategy from `registerWhenStable` to `registerWhenStable:30000`, which will ensure that the ServiceWorker will be registered after 30s at the latest, even if the app has not stabilized by then. Fixes #34464 PR Close #35870 --- packages/service-worker/src/module.ts | 4 +++- packages/service-worker/test/module_spec.ts | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/service-worker/src/module.ts b/packages/service-worker/src/module.ts index 7e7779f5d769c..85eef4f67cffb 100644 --- a/packages/service-worker/src/module.ts +++ b/packages/service-worker/src/module.ts @@ -100,7 +100,9 @@ export function ngswAppInitializer( if (typeof options.registrationStrategy === 'function') { readyToRegister$ = options.registrationStrategy(); } else { - const [strategy, ...args] = (options.registrationStrategy || 'registerWhenStable').split(':'); + const [strategy, ...args] = + (options.registrationStrategy || 'registerWhenStable:30000').split(':'); + switch (strategy) { case 'registerImmediately': readyToRegister$ = of (null); diff --git a/packages/service-worker/test/module_spec.ts b/packages/service-worker/test/module_spec.ts index 46591e100fc04..2f6d8a3768225 100644 --- a/packages/service-worker/test/module_spec.ts +++ b/packages/service-worker/test/module_spec.ts @@ -147,7 +147,7 @@ describe('ServiceWorkerModule', () => { return isStableSub; }; - it('defaults to registering the SW when the app stabilizes', fakeAsync(() => { + it('defaults to registering the SW when the app stabilizes (under 30s)', fakeAsync(() => { const isStableSub = configTestBedWithMockedStability(); isStableSub.next(false); @@ -156,7 +156,7 @@ describe('ServiceWorkerModule', () => { tick(); expect(swRegisterSpy).not.toHaveBeenCalled(); - tick(60000); + tick(20000); expect(swRegisterSpy).not.toHaveBeenCalled(); isStableSub.next(true); @@ -165,6 +165,17 @@ describe('ServiceWorkerModule', () => { expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); })); + it('defaults to registering the SW after 30s if the app does not stabilize sooner', + fakeAsync(() => { + const isStableSub = configTestBedWithMockedStability(); + + tick(29999); + expect(swRegisterSpy).not.toHaveBeenCalled(); + + tick(1); + expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); + })); + it('registers the SW when the app stabilizes with `registerWhenStable:<timeout>`', fakeAsync(() => { const isStableSub = configTestBedWithMockedStability('registerWhenStable:1000'); From 2d7c95fb701b4a8263b18c662c4e6993223229c3 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Tue, 24 Mar 2020 22:54:54 +0200 Subject: [PATCH 039/262] fix(service-worker): prevent SW registration strategies from affecting app stabilization (#35870) Previously, some of the built-in ServiceWorker registration strategies, namely `registerWithDelay:<timeout>` and `registerWhenStable:<timeout>`, would register potentially long-running timeout, thus preventing the app from stabilizing before the timeouts expired. This was especially problematic for the `registerWhenStable:<timeout>` strategy, which waits for the app to stabilize, because the strategy itself would prevent the app from stabilizing and thus the ServiceWorker would always be registered after the timeout. This commit fixes this by subscribing to the registration strategy observable outside the Angular zone, thus not affecting the app's stabilization. PR Close #35870 --- packages/service-worker/src/module.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/service-worker/src/module.ts b/packages/service-worker/src/module.ts index 85eef4f67cffb..d707a58e33a0f 100644 --- a/packages/service-worker/src/module.ts +++ b/packages/service-worker/src/module.ts @@ -7,7 +7,7 @@ */ import {isPlatformBrowser} from '@angular/common'; -import {APP_INITIALIZER, ApplicationRef, InjectionToken, Injector, ModuleWithProviders, NgModule, PLATFORM_ID} from '@angular/core'; +import {APP_INITIALIZER, ApplicationRef, InjectionToken, Injector, ModuleWithProviders, NgModule, NgZone, PLATFORM_ID} from '@angular/core'; import {Observable, merge, of } from 'rxjs'; import {delay, filter, take} from 'rxjs/operators'; @@ -122,10 +122,15 @@ export function ngswAppInitializer( } // Don't return anything to avoid blocking the application until the SW is registered. + // Also, run outside the Angular zone to avoid preventing the app from stabilizing (especially + // given that some registration strategies wait for the app to stabilize). // Catch and log the error if SW registration fails to avoid uncaught rejection warning. - readyToRegister$.pipe(take(1)).subscribe( - () => navigator.serviceWorker.register(script, {scope: options.scope}) - .catch(err => console.error('Service worker registration failed with:', err))); + const ngZone = injector.get(NgZone); + ngZone.runOutsideAngular( + () => readyToRegister$.pipe(take(1)).subscribe( + () => + navigator.serviceWorker.register(script, {scope: options.scope}) + .catch(err => console.error('Service worker registration failed with:', err)))); }; return initializer; } From f9bc84cd9934c9faf950c8f71cadeb7799b018f6 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Mon, 16 Mar 2020 16:32:30 +0200 Subject: [PATCH 040/262] build(docs-infra): remove obsolete properties from `zipper.json` files (#36018) The `removeSystemJsConfig` and `type` properties (present in some `zipper.json` files) are now obsolete and are not taken into account by the example zipper: - `removeSystemJsConfig` is no longer relevant since most examples have been migrated to use the CLI. - `type` is no longer relevant, because the project type is determined based on the `projectType` property in `example-config.json` files. This commit removes these properties from `zipper.json` files and updates the `example-zipper` docs to not mention them. PR Close #36018 --- aio/content/examples/i18n/zipper.json | 6 ++---- aio/content/examples/universal/zipper.json | 6 ++---- aio/tools/example-zipper/README.md | 15 --------------- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/aio/content/examples/i18n/zipper.json b/aio/content/examples/i18n/zipper.json index 7f9c0a43ccfbc..ecd77116fa70e 100644 --- a/aio/content/examples/i18n/zipper.json +++ b/aio/content/examples/i18n/zipper.json @@ -1,11 +1,9 @@ { - "files":[ + "files": [ "!dist/", "!**/*.d.ts", "!src/**/*.js", "!doc-files/**/*", "**/*.xlf" - ], - "removeSystemJsConfig": true, - "type": "i18n" + ] } diff --git a/aio/content/examples/universal/zipper.json b/aio/content/examples/universal/zipper.json index 37b42ad64318c..ce44927d99cc7 100644 --- a/aio/content/examples/universal/zipper.json +++ b/aio/content/examples/universal/zipper.json @@ -1,9 +1,7 @@ { - "files":[ + "files": [ "!dist/", "!**/*.d.ts", "!**/src/**/*.js" - ], - "removeSystemJsConfig": false, - "type": "universal" + ] } diff --git a/aio/tools/example-zipper/README.md b/aio/tools/example-zipper/README.md index e4d728a661a7b..3979c8698fd12 100644 --- a/aio/tools/example-zipper/README.md +++ b/aio/tools/example-zipper/README.md @@ -59,21 +59,6 @@ The problem is that not all examples have a stackblitz but they could offer a zi In those cases, you can create a `zipper.json` file with the same syntax. It will be ignored by the stackblitz tool. -## Choosing the zip "type" - -In both `stackblitz.json` and `zipper.json` you can use two extra properties for the zipper configuration: - -``` -{ - ... - "removeSystemJsConfig": true, - "type": "testing" -} -``` - -This would generate a zip for a testing application and it will also remove everything related with -SystemJS. - ## Executing the zip generation `generateZips.js` will create a zip for each `stackblitz.json` or `zipper.json` it finds. From 1c385a1c2200ffc90b2848b6a07c19c0293cae82 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Mon, 16 Mar 2020 16:32:31 +0200 Subject: [PATCH 041/262] build(docs-infra): do not include CI-specific config in docs examples ZIP archives (#36018) In #35381, a new Protractor config file was introduced in docs examples, `protractor-puppeteer.conf.js`, that was only supposed to be used on CI and not be shipped with the ZIP archives provided for users to download and experiment with the docs examples locally. The logic to ignore the `protractor-puppeteer.conf.js` file was incorrect, resulting in the file being retained in some examples (e.g. [universal][1]). The problem was not immediately obvious, because most examples explicitly specify all `**/*.js` files as ignored, but for other examples the file was retained in the ZIP archive. This commit fixes the logic to ensure the file is excluded from all docs examples ZIP archives. [1]: https://v9.angular.io/generated/zips/universal/universal.zip PR Close #36018 --- aio/tools/example-zipper/exampleZipper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/tools/example-zipper/exampleZipper.js b/aio/tools/example-zipper/exampleZipper.js index 563b0d7d5d477..061c404f36c90 100644 --- a/aio/tools/example-zipper/exampleZipper.js +++ b/aio/tools/example-zipper/exampleZipper.js @@ -112,7 +112,7 @@ class ExampleZipper { '!**/npm-debug.log', '!**/example-config.json', '!**/wallaby.js', - '!e2e/protractor-puppeteer.conf.js', + '!**/e2e/protractor-puppeteer.conf.js', // AOT related files '!**/aot/**/*.*', '!**/*-aot.*' From 8e0dec538e328836ab8e10c5e25beb237fb898a7 Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 11 Mar 2020 09:41:54 -0700 Subject: [PATCH 042/262] docs: clarify observables doc with new titles and tooltips (#36023) PR Close #36023 --- aio/content/guide/observables.md | 10 +++++++--- aio/content/navigation.json | 12 ++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/aio/content/guide/observables.md b/aio/content/guide/observables.md index 648673233f055..345f0c76db902 100644 --- a/aio/content/guide/observables.md +++ b/aio/content/guide/observables.md @@ -1,9 +1,13 @@ +# Using observables to pass values -# Observables +Observables provide support for passing messages between parts of your application. +They are used frequently in Angular and are the recommended technique for event handling, asynchronous programming, and handling multiple values. -Observables provide support for passing messages between publishers and subscribers in your application. Observables offer significant benefits over other techniques for event handling, asynchronous programming, and handling multiple values. +The observer pattern is a software design pattern in which an object, called the *subject*, maintains a list of its dependents, called *observers*, and notifies them automatically of state changes. +This pattern is similar (but not identical) to the [publish/subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) design pattern. -Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. The subscribed consumer then receives notifications until the function completes, or until they unsubscribe. +Observables are declarative—that is, you define a function for publishing values, but it is not executed until a consumer subscribes to it. +The subscribed consumer then receives notifications until the function completes, or until they unsubscribe. An observable can deliver multiple values of any type—literals, messages, or events, depending on the context. The API for receiving values is the same whether the values are delivered synchronously or asynchronously. Because setup and teardown logic are both handled by the observable, your application code only needs to worry about subscribing to consume values, and when done, unsubscribing. Whether the stream was keystrokes, an HTTP response, or an interval timer, the interface for listening to values and stopping listening is the same. diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 97b0c263a0544..7efa978a67335 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -272,28 +272,28 @@ "children": [ { "url": "guide/observables", - "title": "Observables", - "tooltip": "" + "title": "Observables Overview", + "tooltip": "Using observables to pass values synchronously or asynchronously." }, { "url": "guide/rx-library", "title": "The RxJS Library", - "tooltip": "" + "tooltip": "The RxJS library provides useful operators." }, { "url": "guide/observables-in-angular", "title": "Observables in Angular", - "tooltip": "" + "tooltip": "How Angular subsystems make us of observables." }, { "url": "guide/practical-observable-usage", "title": "Practical Usage", - "tooltip": "" + "tooltip": "Domains in which observables are useful." }, { "url": "guide/comparing-observables", "title": "Compare to Other Techniques", - "tooltip": "" + "tooltip": "How observables compare to promises and other message passing techniques." } ] }, From bfa7b1a49453d0fbcaff33976951958069bc5b3d Mon Sep 17 00:00:00 2001 From: Faouzi Medebbeb <faouzi.medebbeb@gmail.com> Date: Fri, 20 Mar 2020 12:54:15 +0100 Subject: [PATCH 043/262] docs: correct a misleading sentence (#36155) (#36158) Fixes #36155 PR Close #36158 --- aio/content/guide/testing.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index 4fd661ae45530..a6a7945e72998 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -507,10 +507,11 @@ Consider this `LightswitchComponent` which toggles a light on and off You might decide only to test that the `clicked()` method toggles the light's _on/off_ state and sets the message appropriately. -This component class has no dependencies. -To test a service with no dependencies, you create it with `new`, poke at its API, -and assert expectations on its public state. -Do the same with the component class. +This component class has no dependencies. To test these types of classes, follow the same steps as you would for a service that has no dependencies: + +1. Create a component using the new keyword. +2. Poke at its API. +3. Assert expectations on its public state. <code-example path="testing/src/app/demo/demo.spec.ts" From 83e4a76afa273f9af8f75947ad0c99f98e04c83a Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Fri, 20 Mar 2020 06:59:35 -0700 Subject: [PATCH 044/262] feat(dev-infra): handle excluding files via globs in pullapprove (#36162) Updates the pullapprove verification script to handle cases of excluding globs from groups. PR Close #36162 --- dev-infra/pullapprove/BUILD.bazel | 4 + dev-infra/pullapprove/group.ts | 158 ++++++++++++++++ dev-infra/pullapprove/logging.ts | 42 +++++ dev-infra/pullapprove/parse-yaml.ts | 33 ++++ dev-infra/pullapprove/verify.ts | 280 +++++++++------------------- 5 files changed, 329 insertions(+), 188 deletions(-) create mode 100644 dev-infra/pullapprove/group.ts create mode 100644 dev-infra/pullapprove/logging.ts create mode 100644 dev-infra/pullapprove/parse-yaml.ts diff --git a/dev-infra/pullapprove/BUILD.bazel b/dev-infra/pullapprove/BUILD.bazel index 5989f338e6446..9d1ffb6d7dcb9 100644 --- a/dev-infra/pullapprove/BUILD.bazel +++ b/dev-infra/pullapprove/BUILD.bazel @@ -3,11 +3,15 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library") ts_library( name = "pullapprove", srcs = [ + "group.ts", + "logging.ts", + "parse-yaml.ts", "verify.ts", ], module_name = "@angular/dev-infra-private/pullapprove", visibility = ["//dev-infra:__subpackages__"], deps = [ + "//dev-infra/utils:config", "@npm//@types/minimatch", "@npm//@types/node", "@npm//@types/shelljs", diff --git a/dev-infra/pullapprove/group.ts b/dev-infra/pullapprove/group.ts new file mode 100644 index 0000000000000..4a4630ad21cb0 --- /dev/null +++ b/dev-infra/pullapprove/group.ts @@ -0,0 +1,158 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {IMinimatch, Minimatch, match} from 'minimatch'; + +import {PullApproveGroupConfig} from './parse-yaml'; + +/** A condition for a group. */ +interface GroupCondition { + glob: string; + matcher: IMinimatch; + matchedFiles: Set<string>; +} + +/** Result of testing files against the group. */ +export interface PullApproveGroupResult { + groupName: string; + matchedIncludes: GroupCondition[]; + matchedExcludes: GroupCondition[]; + matchedCount: number; + unmatchedIncludes: GroupCondition[]; + unmatchedExcludes: GroupCondition[]; + unmatchedCount: number; +} + +// Regex Matcher for contains_any_globs conditions +const CONTAINS_ANY_GLOBS_REGEX = /^'([^']+)',?$/; + +const CONDITION_TYPES = { + INCLUDE_GLOBS: /^contains_any_globs/, + EXCLUDE_GLOBS: /^not contains_any_globs/, + ATTR_LENGTH: /^len\(.*\)/, +}; + +/** A PullApprove group to be able to test files against. */ +export class PullApproveGroup { + // Lines which were not able to be parsed as expected. + private misconfiguredLines: string[] = []; + // Conditions for the group for including files. + private includeConditions: GroupCondition[] = []; + // Conditions for the group for excluding files. + private excludeConditions: GroupCondition[] = []; + // Whether the group has file matchers. + public hasMatchers = false; + + constructor(public groupName: string, group: PullApproveGroupConfig) { + for (let condition of group.conditions) { + condition = condition.trim(); + + if (condition.match(CONDITION_TYPES.INCLUDE_GLOBS)) { + const [conditions, misconfiguredLines] = getLinesForContainsAnyGlobs(condition); + conditions.forEach(globString => this.includeConditions.push({ + glob: globString, + matcher: new Minimatch(globString, {dot: true}), + matchedFiles: new Set<string>(), + })); + this.misconfiguredLines.push(...misconfiguredLines); + this.hasMatchers = true; + } else if (condition.match(CONDITION_TYPES.EXCLUDE_GLOBS)) { + const [conditions, misconfiguredLines] = getLinesForContainsAnyGlobs(condition); + conditions.forEach(globString => this.excludeConditions.push({ + glob: globString, + matcher: new Minimatch(globString, {dot: true}), + matchedFiles: new Set<string>(), + })); + this.misconfiguredLines.push(...misconfiguredLines); + this.hasMatchers = true; + } else if (condition.match(CONDITION_TYPES.ATTR_LENGTH)) { + // Currently a noop as we do not take any action on this condition type. + } else { + const errMessage = `Unrecognized condition found, unable to parse the following condition: \n\n` + + `From the [${groupName}] group:\n` + + ` - ${condition}` + + `\n\n` + + `Known condition regexs:\n` + + `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - ${v}`).join('\n')}` + + `\n\n`; + console.error(errMessage); + process.exit(1); + } + } + } + + /** Retrieve all of the lines which were not able to be parsed. */ + getBadLines(): string[] { return this.misconfiguredLines; } + + /** Retrieve the results for the Group, all matched and unmatched conditions. */ + getResults(): PullApproveGroupResult { + const matchedIncludes = this.includeConditions.filter(c => !!c.matchedFiles.size); + const matchedExcludes = this.excludeConditions.filter(c => !!c.matchedFiles.size); + const unmatchedIncludes = this.includeConditions.filter(c => !c.matchedFiles.size); + const unmatchedExcludes = this.excludeConditions.filter(c => !c.matchedFiles.size); + const unmatchedCount = unmatchedIncludes.length + unmatchedExcludes.length; + const matchedCount = matchedIncludes.length + matchedExcludes.length; + return { + matchedIncludes, + matchedExcludes, + matchedCount, + unmatchedIncludes, + unmatchedExcludes, + unmatchedCount, + groupName: this.groupName, + }; + } + + /** + * Tests a provided file path to determine if it would be considered matched by + * the pull approve group's conditions. + */ + testFile(file: string) { + let matched = false; + this.includeConditions.forEach((includeCondition: GroupCondition) => { + if (includeCondition.matcher.match(file)) { + let matchedExclude = false; + this.excludeConditions.forEach((excludeCondition: GroupCondition) => { + if (excludeCondition.matcher.match(file)) { + // Add file as a discovered exclude as it is negating a matched + // include condition. + excludeCondition.matchedFiles.add(file); + matchedExclude = true; + } + }); + // An include condition is only considered matched if no exclude + // conditions are found to matched the file. + if (!matchedExclude) { + includeCondition.matchedFiles.add(file); + matched = true; + } + } + }); + return matched; + } +} + +/** + * Extract all of the individual globs from a group condition, + * providing both the valid and invalid lines. + */ +function getLinesForContainsAnyGlobs(lines: string) { + const invalidLines: string[] = []; + const validLines = lines.split('\n') + .slice(1, -1) + .map((glob: string) => { + const trimmedGlob = glob.trim(); + const match = trimmedGlob.match(CONTAINS_ANY_GLOBS_REGEX); + if (!match) { + invalidLines.push(trimmedGlob); + return ''; + } + return match[1]; + }) + .filter(globString => !!globString); + return [validLines, invalidLines]; +} diff --git a/dev-infra/pullapprove/logging.ts b/dev-infra/pullapprove/logging.ts new file mode 100644 index 0000000000000..af0f649094328 --- /dev/null +++ b/dev-infra/pullapprove/logging.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {PullApproveGroupResult} from './group'; + +/** Create logs for each pullapprove group result. */ +export function logGroup(group: PullApproveGroupResult, matched = true) { + const includeConditions = matched ? group.matchedIncludes : group.unmatchedIncludes; + const excludeConditions = matched ? group.matchedExcludes : group.unmatchedExcludes; + console.groupCollapsed(`[${group.groupName}]`); + if (includeConditions.length) { + console.group('includes'); + includeConditions.forEach( + matcher => console.info(`${matcher.glob} - ${matcher.matchedFiles.size}`)); + console.groupEnd(); + } + if (excludeConditions.length) { + console.group('excludes'); + excludeConditions.forEach( + matcher => console.info(`${matcher.glob} - ${matcher.matchedFiles.size}`)); + console.groupEnd(); + } + console.groupEnd(); +} + +/** Logs a header within a text drawn box. */ +export function logHeader(...params: string[]) { + const totalWidth = 80; + const fillWidth = totalWidth - 2; + const headerText = params.join(' ').substr(0, fillWidth); + const leftSpace = Math.ceil((fillWidth - headerText.length) / 2); + const rightSpace = fillWidth - leftSpace - headerText.length; + const fill = (count: number, content: string) => content.repeat(count); + + console.info(`┌${fill(fillWidth, '─')}┐`); + console.info(`│${fill(leftSpace, ' ')}${headerText}${fill(rightSpace, ' ')}│`); + console.info(`└${fill(fillWidth, '─')}┘`); +} \ No newline at end of file diff --git a/dev-infra/pullapprove/parse-yaml.ts b/dev-infra/pullapprove/parse-yaml.ts new file mode 100644 index 0000000000000..a74eb3a0cb907 --- /dev/null +++ b/dev-infra/pullapprove/parse-yaml.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {parse as parseYaml} from 'yaml'; + +export interface PullApproveGroupConfig { + conditions: string; + reviewers: { + users: string[], + teams: string[], + }; +} + +export interface PullApproveConfig { + version: number; + github_api_version?: string; + pullapprove_conditions?: { + condition: string, + unmet_status: string, + explanation: string, + }[]; + groups: { + [key: string]: PullApproveGroupConfig, + }; +} + +export function parsePullApproveYaml(rawYaml: string): PullApproveConfig { + return parseYaml(rawYaml) as PullApproveConfig; +} \ No newline at end of file diff --git a/dev-infra/pullapprove/verify.ts b/dev-infra/pullapprove/verify.ts index e43c4f8287edd..5566e78734cf9 100644 --- a/dev-infra/pullapprove/verify.ts +++ b/dev-infra/pullapprove/verify.ts @@ -6,210 +6,114 @@ * found in the LICENSE file at https://angular.io/license */ import {readFileSync} from 'fs'; -import {IMinimatch, Minimatch} from 'minimatch'; import * as path from 'path'; import {cd, exec, set} from 'shelljs'; -import {parse as parseYaml} from 'yaml'; -interface GlobMatcher { - group: string; - glob: string; - matcher: IMinimatch; - matchCount: number; -} +import {PullApproveGroup} from './group'; +import {logGroup, logHeader} from './logging'; +import {parsePullApproveYaml} from './parse-yaml'; +import {getRepoBaseDir} from '../utils/config'; export function verify() { // Exit early on shelljs errors set('-e'); - - // Regex Matcher for contains_any_globs conditions - const CONTAINS_ANY_GLOBS_REGEX = /^'([^']+)',?$/; - // Full path of the angular project directory - const ANGULAR_PROJECT_DIR = process.cwd(); - // Change to the Angular project directory - cd(ANGULAR_PROJECT_DIR); - // Whether to log verbosely const VERBOSE_MODE = process.argv.includes('-v'); + // Full path of the angular project directory + const PROJECT_DIR = getRepoBaseDir(); + // Change to the Angular project directory + cd(PROJECT_DIR); // Full path to PullApprove config file - const PULL_APPROVE_YAML_PATH = path.resolve(ANGULAR_PROJECT_DIR, '.pullapprove.yml'); + const PULL_APPROVE_YAML_PATH = path.resolve(PROJECT_DIR, '.pullapprove.yml'); // All relative path file names in the git repo, this is retrieved using git rather // that a glob so that we only get files that are checked in, ignoring things like // node_modules, .bazelrc.user, etc - const ALL_FILES = exec('git ls-tree --full-tree -r --name-only HEAD', {silent: true}) - .trim() - .split('\n') - .filter((_: string) => !!_); - if (!ALL_FILES.length) { - console.error( - `No files were found to be in the git tree, did you run this command from \n` + - `inside the angular repository?`); - process.exit(1); - } - - /** Gets the glob matching information from each group's condition. */ - function getGlobMatchersFromCondition( - groupName: string, condition: string): [GlobMatcher[], string[]] { - const trimmedCondition = condition.trim(); - const globMatchers: GlobMatcher[] = []; - const badConditionLines: string[] = []; - - // If the condition starts with contains_any_globs, evaluate all of the globs - if (trimmedCondition.startsWith('contains_any_globs')) { - trimmedCondition.split('\n') - .slice(1, -1) - .map(glob => { - const trimmedGlob = glob.trim(); - const match = trimmedGlob.match(CONTAINS_ANY_GLOBS_REGEX); - if (!match) { - badConditionLines.push(trimmedGlob); - return ''; - } - return match[1]; - }) - .filter(globString => !!globString) - .forEach(globString => globMatchers.push({ - group: groupName, - glob: globString, - matcher: new Minimatch(globString, {dot: true}), - matchCount: 0, - })); - } - return [globMatchers, badConditionLines]; - } - - /** Create logs for each review group. */ - function logGroups(groups: Map<string, Map<string, GlobMatcher>>) { - Array.from(groups.entries()).sort().forEach(([groupName, globs]) => { - console.groupCollapsed(groupName); - Array.from(globs.values()) - .sort((a, b) => b.matchCount - a.matchCount) - .forEach(glob => console.info(`${glob.glob} - ${glob.matchCount}`)); - console.groupEnd(); + const REPO_FILES = + exec('git ls-files', {silent: true}).trim().split('\n').filter((_: string) => !!_); + // The pull approve config file. + const pullApproveYamlRaw = readFileSync(PULL_APPROVE_YAML_PATH, 'utf8'); + // JSON representation of the pullapprove yaml file. + const pullApprove = parsePullApproveYaml(pullApproveYamlRaw); + // All of the groups defined in the pullapprove yaml. + const groups = Object.entries(pullApprove.groups).map(([groupName, group]) => { + return new PullApproveGroup(groupName, group); + }); + // PullApprove groups without matchers. + const groupsWithoutMatchers = groups.filter(group => !group.hasMatchers); + // PullApprove groups with matchers. + const groupsWithMatchers = groups.filter(group => group.hasMatchers); + // All lines from group conditions which are not parsable. + const groupsWithBadLines = groups.filter(g => !!g.getBadLines().length); + // If any groups contains bad lines, log bad lines and exit failing. + if (groupsWithBadLines.length) { + logHeader('PullApprove config file parsing failure'); + console.info(`Discovered errors in ${groupsWithBadLines.length} groups`); + groupsWithBadLines.forEach(group => { + console.info(` - [${group.groupName}]`); + group.getBadLines().forEach(line => console.info(` ${line}`)); }); + console.info( + `Correct the invalid conditions, before PullApprove verification can be completed`); + process.exit(1); } - - /** Logs a header within a text drawn box. */ - function logHeader(...params: string[]) { - const totalWidth = 80; - const fillWidth = totalWidth - 2; - const headerText = params.join(' ').substr(0, fillWidth); - const leftSpace = Math.ceil((fillWidth - headerText.length) / 2); - const rightSpace = fillWidth - leftSpace - headerText.length; - const fill = (count: number, content: string) => content.repeat(count); - - console.info(`┌${fill(fillWidth, '─')}┐`); - console.info(`│${fill(leftSpace, ' ')}${headerText}${fill(rightSpace, ' ')}│`); - console.info(`└${fill(fillWidth, '─')}┘`); - } - - /** Runs the pull approve verification check on provided files. */ - function runVerification(files: string[]) { - // All of the globs created for each group's conditions. - const allGlobs: GlobMatcher[] = []; - // The pull approve config file. - const pullApprove = readFileSync(PULL_APPROVE_YAML_PATH, {encoding: 'utf8'}); - // All of the PullApprove groups, parsed from the PullApprove yaml file. - const parsedPullApproveGroups = - parseYaml(pullApprove).groups as{[key: string]: {conditions: string}}; - // All files which were found to match a condition in PullApprove. - const matchedFiles = new Set<string>(); - // All files which were not found to match a condition in PullApprove. - const unmatchedFiles = new Set<string>(); - // All PullApprove groups which matched at least one file. - const matchedGroups = new Map<string, Map<string, GlobMatcher>>(); - // All PullApprove groups which did not match at least one file. - const unmatchedGroups = new Map<string, Map<string, GlobMatcher>>(); - // All condition lines which were not able to be correctly parsed, by group. - const badConditionLinesByGroup = new Map<string, string[]>(); - // Total number of condition lines which were not able to be correctly parsed. - let badConditionLineCount = 0; - - // Get all of the globs from the PullApprove group conditions. - Object.entries(parsedPullApproveGroups).forEach(([groupName, group]) => { - for (const condition of group.conditions) { - const [matchers, badConditions] = getGlobMatchersFromCondition(groupName, condition); - if (badConditions.length) { - badConditionLinesByGroup.set(groupName, badConditions); - badConditionLineCount += badConditions.length; - } - allGlobs.push(...matchers); - } - }); - - if (badConditionLineCount) { - console.info(`Discovered ${badConditionLineCount} parsing errors in PullApprove conditions`); - console.info(`Attempted parsing using: ${CONTAINS_ANY_GLOBS_REGEX}`); - console.info(); - console.info(`Unable to properly parse the following line(s) by group:`); - badConditionLinesByGroup.forEach((badConditionLines, groupName) => { - console.info(`- ${groupName}:`); - badConditionLines.forEach(line => console.info(` ${line}`)); - }); - console.info(); - console.info( - `Please correct the invalid conditions, before PullApprove verification can be completed`); - process.exit(1); - } - - // Check each file for if it is matched by a PullApprove condition. - for (let file of files) { - const matched = allGlobs.filter(glob => glob.matcher.match(file)); - matched.length ? matchedFiles.add(file) : unmatchedFiles.add(file); - matched.forEach(glob => glob.matchCount++); - } - - // Add each glob for each group to a map either matched or unmatched. - allGlobs.forEach(glob => { - const groups = glob.matchCount ? matchedGroups : unmatchedGroups; - const globs = groups.get(glob.group) || new Map<string, GlobMatcher>(); - // Set the globs map in the groups map - groups.set(glob.group, globs); - // Set the glob in the globs map - globs.set(glob.glob, glob); - }); - - // PullApprove is considered verified if no files or groups are found to be unsed. - const verificationSucceeded = !(unmatchedFiles.size || unmatchedGroups.size); - - /** - * Overall result - */ - logHeader('Result'); - if (verificationSucceeded) { - console.info('PullApprove verification succeeded!'); + // Files which are matched by at least one group. + const matchedFiles: string[] = []; + // Files which are not matched by at least one group. + const unmatchedFiles: string[] = []; + + // Test each file in the repo against each group for being matched. + REPO_FILES.forEach((file: string) => { + if (groupsWithMatchers.filter(group => group.testFile(file)).length) { + matchedFiles.push(file); } else { - console.info(`PullApprove verification failed.\n`); - console.info(`Please update '.pullapprove.yml' to ensure that all necessary`); - console.info(`files/directories have owners and all patterns that appear in`); - console.info(`the file correspond to actual files/directories in the repo.`); + unmatchedFiles.push(file); } - /** - * File by file Summary - */ - logHeader('PullApprove file match results'); - console.groupCollapsed(`Matched Files (${matchedFiles.size} files)`); - VERBOSE_MODE && matchedFiles.forEach(file => console.info(file)); - console.groupEnd(); - console.groupCollapsed(`Unmatched Files (${unmatchedFiles.size} files)`); - unmatchedFiles.forEach(file => console.info(file)); - console.groupEnd(); - - /** - * Group by group Summary - */ - logHeader('PullApprove group matches'); - console.groupCollapsed(`Matched Groups (${matchedGroups.size} groups)`); - VERBOSE_MODE && logGroups(matchedGroups); - console.groupEnd(); - console.groupCollapsed(`Unmatched Groups (${unmatchedGroups.size} groups)`); - logGroups(unmatchedGroups); - console.groupEnd(); - - // Provide correct exit code based on verification success. - process.exit(verificationSucceeded ? 0 : 1); + }); + // Results for each group + const resultsByGroup = groupsWithMatchers.map(group => group.getResults()); + // Whether all group condition lines match at least one file and all files + // are matched by at least one group. + const verificationSucceeded = + resultsByGroup.every(r => !r.unmatchedCount) && !unmatchedFiles.length; + + /** + * Overall result + */ + logHeader('Overall Result'); + if (verificationSucceeded) { + console.info('PullApprove verification succeeded!'); + } else { + console.info(`PullApprove verification failed.\n`); + console.info(`Please update '.pullapprove.yml' to ensure that all necessary`); + console.info(`files/directories have owners and all patterns that appear in`); + console.info(`the file correspond to actual files/directories in the repo.`); } - - - runVerification(ALL_FILES); + /** + * File by file Summary + */ + logHeader('PullApprove results by file'); + console.groupCollapsed(`Matched Files (${matchedFiles.length} files)`); + VERBOSE_MODE && matchedFiles.forEach(file => console.info(file)); + console.groupEnd(); + console.groupCollapsed(`Unmatched Files (${unmatchedFiles.length} files)`); + unmatchedFiles.forEach(file => console.info(file)); + console.groupEnd(); + /** + * Group by group Summary + */ + logHeader('PullApprove results by group'); + console.groupCollapsed(`Groups without matchers (${groupsWithoutMatchers.length} groups)`); + VERBOSE_MODE && groupsWithoutMatchers.forEach(group => console.info(`${group.groupName}`)); + console.groupEnd(); + const matchedGroups = resultsByGroup.filter(group => !group.unmatchedCount); + console.groupCollapsed(`Matched conditions by Group (${matchedGroups.length} groups)`); + VERBOSE_MODE && matchedGroups.forEach(group => logGroup(group)); + console.groupEnd(); + const unmatchedGroups = resultsByGroup.filter(group => group.unmatchedCount); + console.groupCollapsed(`Unmatched conditions by Group (${unmatchedGroups.length} groups)`); + unmatchedGroups.forEach(group => logGroup(group, false)); + console.groupEnd(); + + // Provide correct exit code based on verification success. + process.exit(verificationSucceeded ? 0 : 1); } From b07b6edc2a71346491b2a7827cc3b30faa110397 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 23 Mar 2020 09:29:27 -0700 Subject: [PATCH 045/262] build: add dev-infra to clang format sources to format (#36204) PR Close #36204 --- tools/gulp-tasks/format.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/gulp-tasks/format.js b/tools/gulp-tasks/format.js index 11f5393934971..90db154597d57 100644 --- a/tools/gulp-tasks/format.js +++ b/tools/gulp-tasks/format.js @@ -10,6 +10,7 @@ const {I18N_FOLDER, I18N_DATA_FOLDER} = require('./cldr/extract'); // clang-format entry points const srcsToFmt = [ + 'dev-infra/**/*.{js,ts}', 'packages/**/*.{js,ts}', '!packages/zone.js', // Ignore the `zone.js/` directory itself. (The contents are still matched.) `!${I18N_DATA_FOLDER}/**/*.{js,ts}`, From 44acf6734b5b925d04c2ccc85d292c05094bcd7f Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Tue, 24 Mar 2020 15:43:54 +0100 Subject: [PATCH 046/262] build: allow custom module resolution for ts-circular-deps tests (#36226) Currently the `ts-circular-deps` tool uses a hard-coded module resolver that only works in the `angular/angular` repository. If the tool is consumed in other repositories through the shared dev-infra package, the module resolution won't work, and a few resolvable imports (usually cross-entry-points) are accidentally skipped. For each test, the resolution might differ, so tests can now configure their module resolution in a configuration file. Note that we intentionally don't rely on tsconfig's for module resolution as parsing their mappings rather complicates the circular dependency tool. Additionally, not every test has a corresponding tsconfig file. Also, hard-coding mappings to `@angular/*` while accepting a path to the packages folder would work, but it would mean that the circular deps tool is no longer self-contained. Rather, and also for better flexibility, a custom resolver should be specified. PR Close #36226 --- dev-infra/ts-circular-dependencies/config.ts | 59 +++++++++++++++ dev-infra/ts-circular-dependencies/index.ts | 79 ++++++-------------- package.json | 6 +- packages/circular-deps-test.conf.js | 31 ++++++++ 4 files changed, 117 insertions(+), 58 deletions(-) create mode 100644 dev-infra/ts-circular-dependencies/config.ts create mode 100644 packages/circular-deps-test.conf.js diff --git a/dev-infra/ts-circular-dependencies/config.ts b/dev-infra/ts-circular-dependencies/config.ts new file mode 100644 index 0000000000000..cb06ef8171a6b --- /dev/null +++ b/dev-infra/ts-circular-dependencies/config.ts @@ -0,0 +1,59 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {dirname, isAbsolute, resolve} from 'path'; + +import {ModuleResolver} from './analyzer'; + + +/** Configuration for a circular dependencies test. */ +export interface CircularDependenciesTestConfig { + /** Base directory used for shortening paths in the golden file. */ + baseDir: string; + /** Path to the golden file that is used for checking and approving. */ + goldenFile: string; + /** Glob that resolves source files which should be checked. */ + glob: string + /** + * Optional module resolver function that can be used to resolve modules + * to absolute file paths. + */ + resolveModule?: ModuleResolver; + /** + * Optional command that will be displayed if the golden check failed. This can be used + * to consistently use script aliases for checking/approving the golden. + */ + approveCommand?: string; +} + +/** + * Loads the configuration for the circular dependencies test. If the config cannot be + * loaded, an error will be printed and the process exists with a non-zero exit code. + */ +export function loadTestConfig(configPath: string): CircularDependenciesTestConfig { + const configBaseDir = dirname(configPath); + const resolveRelativePath = (relativePath: string) => resolve(configBaseDir, relativePath); + + try { + const config = require(configPath) as CircularDependenciesTestConfig; + if (!isAbsolute(config.baseDir)) { + config.baseDir = resolveRelativePath(config.baseDir); + } + if (!isAbsolute(config.goldenFile)) { + config.goldenFile = resolveRelativePath(config.goldenFile); + } + if (!isAbsolute(config.glob)) { + config.glob = resolveRelativePath(config.glob); + } + return config; + } catch (e) { + console.error('Could not load test configuration file at: ' + configPath); + console.error(`Failed with: ${e.message}`); + process.exit(1); + } +} diff --git a/dev-infra/ts-circular-dependencies/index.ts b/dev-infra/ts-circular-dependencies/index.ts index f55d8be5c0a73..f4a5cb3591129 100644 --- a/dev-infra/ts-circular-dependencies/index.ts +++ b/dev-infra/ts-circular-dependencies/index.ts @@ -9,7 +9,7 @@ import {existsSync, readFileSync, writeFileSync} from 'fs'; import {sync as globSync} from 'glob'; -import {join, relative, resolve} from 'path'; +import {isAbsolute, relative, resolve} from 'path'; import * as ts from 'typescript'; import * as yargs from 'yargs'; import chalk from 'chalk'; @@ -17,56 +17,36 @@ import chalk from 'chalk'; import {Analyzer, ReferenceChain} from './analyzer'; import {compareGoldens, convertReferenceChainToGolden, Golden} from './golden'; import {convertPathToForwardSlash} from './file_system'; - -import {getRepoBaseDir} from '../utils/config'; - -const projectDir = getRepoBaseDir(); -const packagesDir = join(projectDir, 'packages/'); -// The default glob does not capture deprecated packages such as http, or the webworker platform. -const defaultGlob = - join(packagesDir, '!(http|platform-webworker|platform-webworker-dynamic)/**/*.ts'); +import {loadTestConfig, CircularDependenciesTestConfig} from './config'; if (require.main === module) { - const {_: command, goldenFile, glob, baseDir, warnings} = + const {_: command, config: configArg, warnings} = yargs.help() .strict() - .command('check <goldenFile>', 'Checks if the circular dependencies have changed.') - .command('approve <goldenFile>', 'Approves the current circular dependencies.') + .command('check', 'Checks if the circular dependencies have changed.') + .command('approve', 'Approves the current circular dependencies.') .demandCommand() .option( - 'approve', - {type: 'boolean', description: 'Approves the current circular dependencies.'}) + 'config', + {type: 'string', demandOption: true, description: 'Path to the configuration file.'}) .option('warnings', {type: 'boolean', description: 'Prints all warnings.'}) - .option('base-dir', { - type: 'string', - description: 'Base directory used for shortening paths in the golden file.', - default: projectDir, - defaultDescription: 'Project directory' - }) - .option('glob', { - type: 'string', - description: 'Glob that matches source files which should be checked.', - default: defaultGlob, - defaultDescription: 'All release packages' - }) .argv; + const configPath = isAbsolute(configArg) ? configArg : resolve(configArg); + const config = loadTestConfig(configPath); const isApprove = command.includes('approve'); - process.exit(main(baseDir, isApprove, goldenFile, glob, warnings)); + process.exit(main(isApprove, config, warnings)); } /** * Runs the ts-circular-dependencies tool. - * @param baseDir Base directory which is used to build up relative file paths in goldens. * @param approve Whether the detected circular dependencies should be approved. - * @param goldenFile Path to the golden file. - * @param glob Glob that is used to collect all source files which should be checked/approved. - * @param printWarnings Whether warnings should be printed. Warnings for unresolved modules/files - * are not printed by default. + * @param config Configuration for the current circular dependencies test. + * @param printWarnings Whether warnings should be printed out. * @returns Status code. */ export function main( - baseDir: string, approve: boolean, goldenFile: string, glob: string, - printWarnings: boolean): number { + approve: boolean, config: CircularDependenciesTestConfig, printWarnings: boolean): number { + const {baseDir, goldenFile, glob, resolveModule, approveCommand} = config; const analyzer = new Analyzer(resolveModule); const cycles: ReferenceChain[] = []; const checkedNodes = new WeakSet<ts.SourceFile>(); @@ -90,17 +70,21 @@ export function main( return 1; } + const warningsCount = analyzer.unresolvedFiles.size + analyzer.unresolvedModules.size; + // By default, warnings for unresolved files or modules are not printed. This is because // it's common that third-party modules are not resolved/visited. Also generated files // from the View Engine compiler (i.e. factories, summaries) cannot be resolved. - if (printWarnings && - (analyzer.unresolvedFiles.size !== 0 || analyzer.unresolvedModules.size !== 0)) { - console.info(chalk.yellow('The following imports could not be resolved:')); + if (printWarnings && warningsCount !== 0) { + console.info(chalk.yellow('⚠ The following imports could not be resolved:')); analyzer.unresolvedModules.forEach(specifier => console.info(` • ${specifier}`)); analyzer.unresolvedFiles.forEach((value, key) => { console.info(` • ${getRelativePath(baseDir, key)}`); value.forEach(specifier => console.info(` ${specifier}`)); }); + } else { + console.info(chalk.yellow(`⚠ ${warningsCount} imports could not be resolved.`)); + console.info(chalk.yellow(` Please rerun with "--warnings" to inspect unresolved imports.`)); } const expected: Golden = JSON.parse(readFileSync(goldenFile, 'utf8')); @@ -122,16 +106,12 @@ export function main( chalk.yellow(` Fixed circular dependencies that need to be removed from the golden:`)); fixedCircularDeps.forEach(c => console.error(` • ${convertReferenceChainToString(c)}`)); console.info(); - // Print the command for updating the golden. Note that we hard-code the script name for - // approving default packages golden in `goldens/`. We cannot infer the script name passed to - // Yarn automatically since script are launched in a child process where `argv0` is different. - if (resolve(goldenFile) === resolve(projectDir, 'goldens/packages-circular-deps.json')) { - console.info( - chalk.yellow(` Please approve the new golden with: yarn ts-circular-deps:approve`)); + if (approveCommand) { + console.info(chalk.yellow(` Please approve the new golden with: ${approveCommand}`)); } else { console.info(chalk.yellow( ` Please update the golden. The following command can be ` + - `run: yarn ts-circular-deps approve ${getRelativePath(baseDir, goldenFile)}.`)); + `run: yarn ts-circular-deps approve ${getRelativePath(process.cwd(), goldenFile)}.`)); } } return 1; @@ -146,14 +126,3 @@ function getRelativePath(baseDir: string, path: string) { function convertReferenceChainToString(chain: ReferenceChain<string>) { return chain.join(' → '); } - -/** - * Custom module resolver that maps specifiers starting with `@angular/` to the - * local packages folder. - */ -function resolveModule(specifier: string) { - if (specifier.startsWith('@angular/')) { - return packagesDir + specifier.substr('@angular/'.length); - } - return null; -} diff --git a/package.json b/package.json index 5a831ab9b6f1c..13c597d34c02b 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,9 @@ "tslint": "tsc -p tools/tsconfig.json && tslint -c tslint.json \"+(packages|modules|scripts|tools)/**/*.+(js|ts)\"", "public-api:check": "node goldens/public-api/manage.js test", "public-api:update": "node goldens/public-api/manage.js accept", - "ts-circular-deps": "ts-node dev-infra/ts-circular-dependencies/index.ts", - "ts-circular-deps:check": "yarn -s ts-circular-deps check ./goldens/packages-circular-deps.json", - "ts-circular-deps:approve": "yarn -s ts-circular-deps approve ./goldens/packages-circular-deps.json" + "ts-circular-deps": "ts-node dev-infra/ts-circular-dependencies/index.ts --config ./packages/circular-deps-test.conf.js", + "ts-circular-deps:check": "yarn -s ts-circular-deps check", + "ts-circular-deps:approve": "yarn -s ts-circular-deps approve" }, "// 1": "dependencies are used locally and by bazel", "dependencies": { diff --git a/packages/circular-deps-test.conf.js b/packages/circular-deps-test.conf.js new file mode 100644 index 0000000000000..83f9a1d5f4872 --- /dev/null +++ b/packages/circular-deps-test.conf.js @@ -0,0 +1,31 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const path = require('path'); + +module.exports = { + baseDir: '../', + goldenFile: '../goldens/packages-circular-deps.json', + // The test should not capture deprecated packages such as `http`, or the `webworker` platform. + glob: `./!(http|platform-webworker|platform-webworker-dynamic)/**/*.ts`, + // Command that will be displayed if the golden needs to be updated. + approveCommand: 'yarn ts-circular-deps:approve', + resolveModule: resolveModule +}; + +/** + * Custom module resolver that maps specifiers starting with `@angular/` to the + * local packages folder. This ensures that cross package/entry-point dependencies + * can be detected. + */ +function resolveModule(specifier) { + if (specifier.startsWith('@angular/')) { + return path.join(__dirname, specifier.substr('@angular/'.length)); + } + return null; +} From b54db86f43e10f4e372f337b9823632ef7202ebf Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Tue, 24 Mar 2020 10:52:07 -0700 Subject: [PATCH 047/262] build: fix bad pullapprove rule (#36232) The dev-infra pull approve group contained a condition with the glob having a string concatenation rather than a comma separated list. This corrects this error, and in another PR we will correct the verification scripts failure to catch this. PR Close #36232 --- .pullapprove.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pullapprove.yml b/.pullapprove.yml index 1f63de638543a..ef53b80c4c729 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -952,7 +952,7 @@ groups: 'tools/build/**', 'tools/circular_dependency_test/**', 'tools/contributing-stats/**', - 'tools/components/**' + 'tools/components/**', 'tools/gulp-tasks/**', 'tools/ng_rollup_bundle/**', 'tools/ngcontainer/**', From 16497438d6656c044c4974cbbe4ed32a9127f392 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir <akushnir@google.com> Date: Tue, 24 Mar 2020 17:19:47 -0700 Subject: [PATCH 048/262] fix(core): run `APP_INITIALIZER`s before accessing `LOCALE_ID` token in Ivy TestBed (#36237) Prior to this commit, Ivy TestBed was accessing locale ID before `APP_INITIALIZER` functions were called. This execution order is not consistent with the app bootstrap logic in `application_ref.ts`. This commit updates Ivy TestBed execution order to call initializers first (since they might affect `LOCALE_ID` token value) and accessing and setting locale ID after that. Fixes #36230. PR Close #36237 --- packages/core/test/test_bed_spec.ts | 17 ++++++++++++++++- .../core/testing/src/r3_test_bed_compiler.ts | 10 ++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 5ec2d3f55671c..6a3eecf9271e7 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core'; +import {APP_INITIALIZER, ChangeDetectorRef, Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core'; import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -245,6 +245,21 @@ describe('TestBed', () => { expect(hello.nativeElement).toHaveText('Hello World!'); }); + it('should run `APP_INITIALIZER` before accessing `LOCALE_ID` provider', () => { + let locale: string = ''; + @NgModule({ + providers: [ + {provide: APP_INITIALIZER, useValue: () => locale = 'fr-FR', multi: true}, + {provide: LOCALE_ID, useFactory: () => locale} + ] + }) + class TestModule { + } + + TestBed.configureTestingModule({imports: [TestModule]}); + expect(TestBed.inject(LOCALE_ID)).toBe('fr-FR'); + }); + it('allow to override a provider', () => { TestBed.overrideProvider(NAME, {useValue: 'injected World!'}); const hello = TestBed.createComponent(HelloWorld); diff --git a/packages/core/testing/src/r3_test_bed_compiler.ts b/packages/core/testing/src/r3_test_bed_compiler.ts index 5a46e92403f9f..a01aec19cf6a4 100644 --- a/packages/core/testing/src/r3_test_bed_compiler.ts +++ b/packages/core/testing/src/r3_test_bed_compiler.ts @@ -257,14 +257,16 @@ export class R3TestBedCompiler { const parentInjector = this.platform.injector; this.testModuleRef = new NgModuleRef(this.testModuleType, parentInjector); - // Set the locale ID, it can be overridden for the tests - const localeId = this.testModuleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID); - setLocaleId(localeId); - // ApplicationInitStatus.runInitializers() is marked @internal to core. // Cast it to any before accessing it. (this.testModuleRef.injector.get(ApplicationInitStatus) as any).runInitializers(); + // Set locale ID after running app initializers, since locale information might be updated while + // running initializers. This is also consistent with the execution order while bootstrapping an + // app (see `packages/core/src/application_ref.ts` file). + const localeId = this.testModuleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID); + setLocaleId(localeId); + return this.testModuleRef; } From 995cd15a69cb672b66c5413c587b114aa5745ebd Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Wed, 25 Mar 2020 21:37:20 +0000 Subject: [PATCH 049/262] fix(ngcc): correctly identify the package path of secondary entry-points (#36249) Previously we only searched for package paths below the set of `basePaths` that were computed from the `basePath` provided to ngcc and the set of `pathMappings`. In some scenarios, such as hoisted packages, the entry-point is not within any of the `basePaths` identified above. For example: ``` project packages app node_modules app-lib (depends on lib1) node_modules lib1 (depends on lib2) node_modules lib2 (depends on lib3/entry-point) lib3 entry-point ``` When CLI is compiling `app-lib` ngcc will be given `project/packages/app/node_modules` as the `basePath. If ngcc is asked to target `lib2`, the `targetPath` will be `project/node_modules/lib1/node_modules/lib2`. Since `lib2` depends upon `lib3/entry-point`, ngcc will need to compute the package path for `project/node_modules/lib3/entry-point`. Since `project/node_modules/lib3/entry-point` is not contained in the `basePath` `project/packages/app/node_modules`, ngcc failed to compute the `packagePath` correctly, instead assuming that it was the same as the entry-point path. Now we also consider the nearest `node_modules` folder to the entry-point path as an additional `basePath`. If one is found then we use the first directory directly below that `node_modules` directory as the package path. In the case of our example this extra `basePath` would be `project/node_modules` which allows us to compute the `packagePath` of `project/node_modules/lib3`. Fixes #35747 PR Close #36249 --- .../targeted_entry_point_finder.ts | 34 +++++++-- .../ngcc/src/entry_point_finder/utils.ts | 2 +- .../targeted_entry_point_finder_spec.ts | 75 +++++++++++++++++++ 3 files changed, 104 insertions(+), 7 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index 35a63a5698179..2dcffe8942a91 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -150,13 +150,35 @@ export class TargetedEntryPointFinder implements EntryPointFinder { break; } } - // If we get here then none of the `basePaths` matched the `entryPointPath`, which - // is somewhat unexpected and means that this entry-point lives completely outside - // any of the `basePaths`. - // All we can do is assume that his entry-point is a primary entry-point to a package. - return entryPointPath; - } + // We couldn't find a `packagePath` using `basePaths` so try to find the nearest `node_modules` + // that contains the `entryPointPath`, if there is one, and use it as a `basePath`. + let packagePath = entryPointPath; + let scopedPackagePath = packagePath; + let containerPath = this.fs.dirname(packagePath); + while (!this.fs.isRoot(containerPath) && !containerPath.endsWith('node_modules')) { + scopedPackagePath = packagePath; + packagePath = containerPath; + containerPath = this.fs.dirname(containerPath); + } + + if (this.fs.exists(join(packagePath, 'package.json'))) { + // The directory directly below `node_modules` is a package - use it + return packagePath; + } else if ( + this.fs.basename(packagePath).startsWith('@') && + this.fs.exists(join(scopedPackagePath, 'package.json'))) { + // The directory directly below the `node_modules` is a scope and the directory directly + // below that is a scoped package - use it + return scopedPackagePath; + } else { + // If we get here then none of the `basePaths` contained the `entryPointPath` and the + // `entryPointPath` contains no `node_modules` that contains a package or a scoped + // package. All we can do is assume that this entry-point is a primary entry-point to a + // package. + return entryPointPath; + } + } /** * Split the given `path` into path segments using an FS independent algorithm. diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts index 7a43c237a7fc8..2f8329eae47a5 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts @@ -30,7 +30,7 @@ import {PathMappings} from '../utils'; export function getBasePaths( sourceDirectory: AbsoluteFsPath, pathMappings: PathMappings | undefined): AbsoluteFsPath[] { const fs = getFileSystem(); - let basePaths = [sourceDirectory]; + const basePaths = [sourceDirectory]; if (pathMappings) { const baseUrl = resolve(pathMappings.baseUrl); Object.values(pathMappings.paths).forEach(paths => paths.forEach(path => { diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts index 63d317fd2d021..0bbd51fbfbe71 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts @@ -166,6 +166,81 @@ runInEachFileSystem(() => { ]); }); + it('should handle external node_modules folders (e.g. in a yarn workspace)', () => { + // Note that neither the basePath and targetPath contain each other + const basePath = _Abs('/nested_node_modules/packages/app/node_modules'); + const targetPath = _Abs('/nested_node_modules/node_modules/package/entry-point'); + loadTestFiles([ + ...createPackage(_Abs('/nested_node_modules/node_modules'), 'package'), + ...createPackage(_Abs('/nested_node_modules/node_modules/package'), 'entry-point'), + ]); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(_Abs('/nested_node_modules'), entryPoints)).toEqual([ + ['node_modules/package', 'node_modules/package/entry-point'], + ]); + }); + + it('should handle external node_modules folders (e.g. in a yarn workspace) for dependencies', + () => { + // The application being compiled is at `/project/packages/app` so the basePath sent to + // ngcc is the `node_modules` below it + const basePath = _Abs('/project/packages/app/node_modules'); + // `packages/app` depends upon lib1, which has a private dependency on lib2 in its + // own `node_modules` folder + const lib2 = createPackage( + _Abs('/project/node_modules/lib1/node_modules'), 'lib2', ['lib3/entry-point']); + // `lib2` depends upon `lib3/entry-point` which has been hoisted all the way up to the + // top level `node_modules` + const lib3 = createPackage(_Abs('/project/node_modules'), 'lib3'); + const lib3EntryPoint = createPackage(_Abs('/project/node_modules/lib3'), 'entry-point'); + loadTestFiles([...lib2, ...lib3, ...lib3EntryPoint]); + // The targetPath being processed is `lib2` and we expect it to find the correct + // entry-point info for the `lib3/entry-point` dependency. + const targetPath = _Abs('/project/node_modules/lib1/node_modules/lib2'); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(_Abs('/project/node_modules'), entryPoints)).toEqual([ + ['lib3', 'lib3/entry-point'], + ['lib1/node_modules/lib2', 'lib1/node_modules/lib2'], + ]); + }); + + it('should handle external node_modules folders (e.g. in a yarn workspace) for scoped dependencies', + () => { + // The application being compiled is at `/project/packages/app` so the basePath sent to + // ngcc is the `node_modules` below it + const basePath = _Abs('/project/packages/app/node_modules'); + // `packages/app` depends upon lib1, which has a private dependency on lib2 in its + // own `node_modules` folder + const lib2 = createPackage( + _Abs('/project/node_modules/lib1/node_modules'), 'lib2', + ['@scope/lib3/entry-point']); + // `lib2` depends upon `lib3/entry-point` which has been hoisted all the way up to the + // top level `node_modules` + const lib3 = createPackage(_Abs('/project/node_modules/@scope'), 'lib3'); + const lib3EntryPoint = createPackage( + _Abs('/project/node_modules/@scope/lib3'), 'entry-point', ['lib4/entry-point']); + const lib4 = + createPackage(_Abs('/project/node_modules/@scope/lib3/node_modules'), 'lib4'); + const lib4EntryPoint = createPackage( + _Abs('/project/node_modules/@scope/lib3/node_modules/lib4'), 'entry-point'); + loadTestFiles([...lib2, ...lib3, ...lib3EntryPoint, ...lib4, ...lib4EntryPoint]); + // The targetPath being processed is `lib2` and we expect it to find the correct + // entry-point info for the `lib3/entry-point` dependency. + const targetPath = _Abs('/project/node_modules/lib1/node_modules/lib2'); + const finder = new TargetedEntryPointFinder( + fs, config, logger, resolver, basePath, targetPath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(_Abs('/project/node_modules'), entryPoints)).toEqual([ + ['@scope/lib3/node_modules/lib4', '@scope/lib3/node_modules/lib4/entry-point'], + ['@scope/lib3', '@scope/lib3/entry-point'], + ['lib1/node_modules/lib2', 'lib1/node_modules/lib2'], + ]); + }); + it('should handle dependencies via pathMappings', () => { const basePath = _Abs('/path_mapped/node_modules'); const targetPath = _Abs('/path_mapped/node_modules/test'); From 2d0847c307c92378f5355b7e7b055962fa0b6739 Mon Sep 17 00:00:00 2001 From: Misko Hevery <misko@hevery.com> Date: Thu, 26 Mar 2020 14:47:49 -0700 Subject: [PATCH 050/262] docs: update release nots with blog post (#36268) PR Close #36268 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abafe22d46f80..b3e1f514dcfcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ ### Release Highlights +To learn about the release highlights and our CLI-powered automated update workflow for your projects please check out the [v9.1 release announcement](https://blog.angular.io/version-9-1-of-angular-now-available-typescript-3-8-faster-builds-and-more-eb292f989428). + * TypeScript 3.8 update * ngcc improvements * performance optimizations From 5cee709266504d685626d01a3858296bc3722f33 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Fri, 27 Mar 2020 19:30:39 +0200 Subject: [PATCH 051/262] fix(ngcc): do not spawn more processes than intended in parallel mode (#36280) When running in parallel mode, ngcc spawns multiple worker processed to process the various entry-points. The number of max allowed processes is determined by the number of CPU cores available to the OS. There is also currently an [upper limit of 8][1]. The number of active workers is in turn inferred by the number of [task assignments][2]. In the past, counting the entries of `ClusterMaster#taskAssignments` was enough, because worker processes were spawned eagerly at the beginning and corresponding entries were created in `taskAssignments`. Since #35719 however, worker processes are spawned lazily on an as needed basis. Because there is some delay between [spawning a process][3] and [inserting it][4] into `taskAssignments`, there is a short period of time when `taskAssignment.size` does not actually represent the number of spawned processes. This can result in spawning more than `ClusterMaster#workerCount` processes. An example of this can be seen in #36278, where the debug logs indicate 9 worker processes had been spawned (`All 9 workers are currently busy`) despite the hard limit of 8. This commit fixes this by using `cluster.workers` to compute the number of spawned worker processes. `cluster.workers` is updated synchronously with `cluster.fork()` and thus reflects the number of spawned workers accurately at all times. [1]: https://github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/main.ts#L429 [2]: https://github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L108 [3]: https://github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L110 [4]: https://github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L199 PR Close #36280 --- packages/compiler-cli/ngcc/src/execution/cluster/master.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts index b3a0abec4fe1a..6de28f0d73fd6 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts @@ -105,14 +105,14 @@ export class ClusterMaster { } if (!isWorkerAvailable) { - if (this.taskAssignments.size < this.workerCount) { + const spawnedWorkerCount = Object.keys(cluster.workers).length; + if (spawnedWorkerCount < this.workerCount) { this.logger.debug('Spawning another worker process as there is more work to be done.'); cluster.fork(); } else { // If there are no available workers or no available tasks, log (for debugging purposes). this.logger.debug( - `All ${this.taskAssignments.size} workers are currently busy and cannot take on more ` + - 'work.'); + `All ${spawnedWorkerCount} workers are currently busy and cannot take on more work.`); } } else { const busyWorkers = Array.from(this.taskAssignments) From c94a33c525d2375286790228882c3997639d6e99 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir <akushnir@google.com> Date: Fri, 27 Mar 2020 18:14:52 -0700 Subject: [PATCH 052/262] refactor(dev-infra): fix lint warnings for Pullapprove-related scripts (#36287) The `dev-infra` scripts were added to the list of sources that should be verified with clang (https://github.com/angular/angular/commit/b07b6edc2a71346491b2a7827cc3b30faa110397), but the Pullapprove-related scripts that were merged before (https://github.com/angular/angular/commit/83e4a76afa273f9af8f75947ad0c99f98e04c83a) doesn't pass these checks. This commit updates a couple scripts to have a proper formatting. PR Close #36287 --- dev-infra/pullapprove/group.ts | 18 +++++++++++------- dev-infra/pullapprove/verify.ts | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/dev-infra/pullapprove/group.ts b/dev-infra/pullapprove/group.ts index 4a4630ad21cb0..247ea4054a03c 100644 --- a/dev-infra/pullapprove/group.ts +++ b/dev-infra/pullapprove/group.ts @@ -72,13 +72,17 @@ export class PullApproveGroup { } else if (condition.match(CONDITION_TYPES.ATTR_LENGTH)) { // Currently a noop as we do not take any action on this condition type. } else { - const errMessage = `Unrecognized condition found, unable to parse the following condition: \n\n` + - `From the [${groupName}] group:\n` + - ` - ${condition}` + - `\n\n` + - `Known condition regexs:\n` + - `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - ${v}`).join('\n')}` + - `\n\n`; + const errMessage = + `Unrecognized condition found, unable to parse the following condition: \n\n` + + `From the [${groupName}] group:\n` + + ` - ${condition}` + + `\n\n` + + `Known condition regexs:\n` + + `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - $ { + v + } + `).join('\n')}` + + `\n\n`; console.error(errMessage); process.exit(1); } diff --git a/dev-infra/pullapprove/verify.ts b/dev-infra/pullapprove/verify.ts index 5566e78734cf9..f92fd073a3308 100644 --- a/dev-infra/pullapprove/verify.ts +++ b/dev-infra/pullapprove/verify.ts @@ -9,10 +9,11 @@ import {readFileSync} from 'fs'; import * as path from 'path'; import {cd, exec, set} from 'shelljs'; +import {getRepoBaseDir} from '../utils/config'; + import {PullApproveGroup} from './group'; import {logGroup, logHeader} from './logging'; import {parsePullApproveYaml} from './parse-yaml'; -import {getRepoBaseDir} from '../utils/config'; export function verify() { // Exit early on shelljs errors From bc089abd3288de2b85fe484c2feb9b3bb74caa76 Mon Sep 17 00:00:00 2001 From: John Papa <papa@Johns-MacBook-Pro-16.local> Date: Sat, 22 Feb 2020 12:30:23 -0500 Subject: [PATCH 053/262] docs: add strictTemplates in place of fullTemplateTypeCheck (#35628) Co-Authored-By: Igor Minar <iminar@google.com> Updating the recommended defaults for template typechecking strictness to the most strict in order to catch most of the errors at compile time. See https://angular.io/guide/template-typecheck for more info. PR Close #35628 --- aio/content/guide/typescript-configuration.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aio/content/guide/typescript-configuration.md b/aio/content/guide/typescript-configuration.md index 19900e19b0505..08d58b04438f4 100644 --- a/aio/content/guide/typescript-configuration.md +++ b/aio/content/guide/typescript-configuration.md @@ -53,7 +53,7 @@ The initial `tsconfig.json` for an Angular app typically looks like the followin ] }, "angularCompilerOptions": { - "fullTemplateTypeCheck": true, + "strictTemplates": true, "strictInjectionParameters": true } } @@ -62,7 +62,6 @@ The initial `tsconfig.json` for an Angular app typically looks like the followin {@a noImplicitAny} - ### *noImplicitAny* and *suppressImplicitAnyIndexErrors* TypeScript developers disagree about whether the `noImplicitAny` flag should be `true` or `false`. @@ -96,6 +95,7 @@ For more information about how the TypeScript configuration affects compilation, </div> + {@a typings} ## TypeScript typings @@ -146,7 +146,6 @@ For instance, to install typings for `jasmine` you run `npm install @types/jasmi {@a target} - ### *target* By default, the target is `es2015`, which is supported only in modern browsers. You can configure the target to `es5` to specifically support legacy browsers. [Differential loading](guide/deployment#differential-loading) is also provided by the Angular CLI to support modern, and legacy browsers with separate bundles. From 5ac308060d781b68d5c2018701a01c57ed8928d8 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Sat, 28 Mar 2020 16:57:49 +0000 Subject: [PATCH 054/262] refactor(ngcc): rename `workerCount` to `maxWorkerCount` (#36298) Now that we spawn workers lazily as needed, this private property is really the upper limit on how many workers we might spawn. PR Close #36298 --- packages/compiler-cli/ngcc/src/execution/cluster/master.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts index 6de28f0d73fd6..9976b4b3270ba 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts @@ -33,7 +33,7 @@ export class ClusterMaster { private onTaskCompleted: TaskCompletedCallback; constructor( - private workerCount: number, private logger: Logger, + private maxWorkerCount: number, private logger: Logger, private pkgJsonUpdater: PackageJsonUpdater, analyzeEntryPoints: AnalyzeEntryPointsFn, createTaskCompletedCallback: CreateTaskCompletedCallback) { if (!cluster.isMaster) { @@ -106,7 +106,7 @@ export class ClusterMaster { if (!isWorkerAvailable) { const spawnedWorkerCount = Object.keys(cluster.workers).length; - if (spawnedWorkerCount < this.workerCount) { + if (spawnedWorkerCount < this.maxWorkerCount) { this.logger.debug('Spawning another worker process as there is more work to be done.'); cluster.fork(); } else { From c6dd900f60812c4bc5aabc6dcadce07b1b76efcd Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Sat, 28 Mar 2020 17:32:15 +0000 Subject: [PATCH 055/262] fix(ngcc): do not write entry-point manifest outside node_modules (#36299) Fixes #36296 PR Close #36299 --- .../ngcc/src/packages/entry_point_manifest.ts | 4 +++ ...irectory_walker_entry_point_finder_spec.ts | 33 +++++++++++++++---- .../packages/entry_point_manifest_spec.ts | 6 ++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts index 8df1af790027b..7cfdf8ca903ff 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts @@ -99,6 +99,10 @@ export class EntryPointManifest { * @param entryPoints A collection of entry-points to record in the manifest. */ writeEntryPointManifest(basePath: AbsoluteFsPath, entryPoints: EntryPoint[]): void { + if (this.fs.basename(basePath) !== 'node_modules') { + return; + } + const lockFileHash = this.computeLockFileHash(basePath); if (lockFileHash === null) { return; diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts index 9eaf0499d6807..386da54f37e80 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts @@ -103,15 +103,37 @@ runInEachFileSystem(() => { expect(entryPoints).toEqual([]); }); - it('should write an entry-point manifest file if none was found', () => { - const basePath = _Abs('/sub_entry_points/node_modules'); + it('should write an entry-point manifest file if none was found and basePath is `node_modules`', + () => { + const basePath = _Abs('/sub_entry_points/node_modules'); + loadTestFiles([ + ...createPackage(basePath, 'common'), + ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), + ...createPackage( + fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), + ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), + {name: _Abs('/sub_entry_points/yarn.lock'), contents: 'MOCK LOCK FILE'}, + ]); + spyOn(manifest, 'readEntryPointsUsingManifest').and.callThrough(); + spyOn(manifest, 'writeEntryPointManifest').and.callThrough(); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, manifest, basePath, undefined); + finder.findEntryPoints(); + expect(manifest.readEntryPointsUsingManifest).toHaveBeenCalled(); + expect(manifest.writeEntryPointManifest).toHaveBeenCalled(); + expect(fs.exists(_Abs('/sub_entry_points/node_modules/__ngcc_entry_points__.json'))) + .toBe(true); + }); + + it('should not write an entry-point manifest file if basePath is not `node_modules`', () => { + const basePath = _Abs('/sub_entry_points/dist'); loadTestFiles([ ...createPackage(basePath, 'common'), ...createPackage(fs.resolve(basePath, 'common'), 'http', ['common']), ...createPackage( fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), - {name: _Abs('/sub_entry_points/yarn.lock'), contents: 'MOCM LOCK FILE'}, + {name: _Abs('/sub_entry_points/yarn.lock'), contents: 'MOCK LOCK FILE'}, ]); spyOn(manifest, 'readEntryPointsUsingManifest').and.callThrough(); spyOn(manifest, 'writeEntryPointManifest').and.callThrough(); @@ -120,8 +142,7 @@ runInEachFileSystem(() => { finder.findEntryPoints(); expect(manifest.readEntryPointsUsingManifest).toHaveBeenCalled(); expect(manifest.writeEntryPointManifest).toHaveBeenCalled(); - expect(fs.exists(_Abs('/sub_entry_points/node_modules/__ngcc_entry_points__.json'))) - .toBe(true); + expect(fs.exists(_Abs('/sub_entry_points/dist/__ngcc_entry_points__.json'))).toBe(false); }); it('should read from the entry-point manifest file if found', () => { @@ -132,7 +153,7 @@ runInEachFileSystem(() => { ...createPackage( fs.resolve(basePath, 'common/http'), 'testing', ['common/http', 'common/testing']), ...createPackage(fs.resolve(basePath, 'common'), 'testing', ['common']), - {name: _Abs('/sub_entry_points/yarn.lock'), contents: 'MOCM LOCK FILE'}, + {name: _Abs('/sub_entry_points/yarn.lock'), contents: 'MOCK LOCK FILE'}, ]); const finder = new DirectoryWalkerEntryPointFinder( fs, config, logger, resolver, manifest, basePath, undefined); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts index 928c32d9019a1..b67eaa73c929f 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts @@ -165,6 +165,12 @@ runInEachFileSystem(() => { expect(fs.exists(_Abs('/project/node_modules/__ngcc_entry_points__.json'))).toBe(false); }); + it('should do nothing if the basePath is not node_modules', () => { + fs.writeFile(_Abs('/project/yarn.lock'), 'LOCK FILE CONTENTS'); + manifest.writeEntryPointManifest(_Abs('/project/dist'), []); + expect(fs.exists(_Abs('/project/dist/__ngcc_entry_points__.json'))).toBe(false); + }); + it('should write an __ngcc_entry_points__.json file below the base path if there is a yarn.lock file', () => { fs.writeFile(_Abs('/project/yarn.lock'), 'LOCK FILE CONTENTS'); From a383116b43019d4ceaa79c27236cdcee55bfe515 Mon Sep 17 00:00:00 2001 From: Alexey Okhrimenko <ai_boy@live.ru> Date: Sun, 29 Mar 2020 18:14:39 +0300 Subject: [PATCH 056/262] docs: fix typo in Dependency Injection guide (#36304) Fixing typo in dependency-injection-navtree.md PR Close #36304 --- aio/content/guide/dependency-injection-navtree.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/dependency-injection-navtree.md b/aio/content/guide/dependency-injection-navtree.md index 52f7a8e54ad94..076c1e9d728ec 100644 --- a/aio/content/guide/dependency-injection-navtree.md +++ b/aio/content/guide/dependency-injection-navtree.md @@ -157,7 +157,7 @@ Here's *Alex* and family in action. ### Find a parent in a tree with _@SkipSelf()_ Imagine one branch of a component hierarchy: *Alice* -> *Barry* -> *Carol*. -Both *Alice* and *Barry* implement the `Parent' class interface. +Both *Alice* and *Barry* implement the `Parent` class interface. *Barry* is the problem. He needs to reach his parent, *Alice*, and also be a parent to *Carol*. That means he must both *inject* the `Parent` class interface to get *Alice* and From 5b6ced5599a2d3358dc4096540ff8eab2304bdc2 Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Sun, 29 Mar 2020 13:22:56 -0700 Subject: [PATCH 057/262] build: update to rules_nodejs 1.5.0 (#36307) ### New stuff * The `ts_project` rule is a simple wrapper around the TypeScript compiler, `tsc`. This is an alternative to `ts_library` but not a replacement. Read more about the trade-offs at https://bazelbuild.github.io/rules_nodejs/TypeScript#alternatives or read the [API docs](https://bazelbuild.github.io/rules_nodejs/TypeScript#ts_project) * `pkg_npm` can now be used as a dependency within your repo as well as for publishing to npm. It provides a `LinkablePackageInfo` which is our internal API to pass package name/path to downstream compilations, essentially providing the "Lerna" feature. * There is experimental support for Bazel's "worker mode" in `rollup_bundle`, which essentially puts Rollup in watch mode. Add the `supports_workers = True` attribute to opt-in. * Better support for [pre-defined label variables](https://docs.bazel.build/versions/master/be/make-variables.html#predefined_label_variables) like `$(rootpath)` and `$(execpath)` - we no longer recommend using `$(location)` at all. See release notes https://github.com/bazelbuild/rules_nodejs/releases/tag/1.5.0 for more info. PR Close #36307 --- WORKSPACE | 6 +- integration/bazel/WORKSPACE | 4 +- integration/bazel/package.json | 10 ++-- integration/bazel/yarn.lock | 60 +++++++++---------- package.json | 12 ++-- .../src/builders/files/WORKSPACE.template | 4 +- packages/bazel/src/schematics/ng-add/index.ts | 10 ++-- yarn.lock | 48 +++++++-------- 8 files changed, 77 insertions(+), 77 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index 8c462c4766415..f5a55ddde0e70 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Fetch rules_nodejs so we can install our npm dependencies http_archive( name = "build_bazel_rules_nodejs", - sha256 = "2eca5b934dee47b5ff304f502ae187c40ec4e33e12bcbce872a2eeb786e23269", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.4.1/rules_nodejs-1.4.1.tar.gz"], + sha256 = "d0c4bb8b902c1658f42eb5563809c70a06e46015d64057d25560b0eb4bdc9007", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.5.0/rules_nodejs-1.5.0.tar.gz"], ) # Check the rules_nodejs version and download npm dependencies @@ -17,7 +17,7 @@ http_archive( # assert on that. load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install") -check_rules_nodejs_version(minimum_version_string = "1.4.1") +check_rules_nodejs_version(minimum_version_string = "1.5.0") # Setup the Node.js toolchain node_repositories( diff --git a/integration/bazel/WORKSPACE b/integration/bazel/WORKSPACE index 0e1727733210a..b0148cd3f6b46 100644 --- a/integration/bazel/WORKSPACE +++ b/integration/bazel/WORKSPACE @@ -5,8 +5,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Fetch rules_nodejs so we can install our npm dependencies http_archive( name = "build_bazel_rules_nodejs", - sha256 = "2eca5b934dee47b5ff304f502ae187c40ec4e33e12bcbce872a2eeb786e23269", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.4.1/rules_nodejs-1.4.1.tar.gz"], + sha256 = "d0c4bb8b902c1658f42eb5563809c70a06e46015d64057d25560b0eb4bdc9007", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.5.0/rules_nodejs-1.5.0.tar.gz"], ) # Fetch sass rules for compiling sass files diff --git a/integration/bazel/package.json b/integration/bazel/package.json index b367c3fb328f5..b9517b79c2af1 100644 --- a/integration/bazel/package.json +++ b/integration/bazel/package.json @@ -23,11 +23,11 @@ "@angular/compiler": "file:../../dist/packages-dist/compiler", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@bazel/bazelisk": "file:../../node_modules/@bazel/bazelisk", - "@bazel/karma": "1.4.1", - "@bazel/protractor": "1.4.1", - "@bazel/rollup": "1.4.1", - "@bazel/terser": "1.4.1", - "@bazel/typescript": "1.4.1", + "@bazel/karma": "1.5.0", + "@bazel/protractor": "1.5.0", + "@bazel/rollup": "1.5.0", + "@bazel/terser": "1.5.0", + "@bazel/typescript": "1.5.0", "@types/jasmine": "2.8.8", "http-server": "0.12.0", "karma": "4.4.1", diff --git a/integration/bazel/yarn.lock b/integration/bazel/yarn.lock index 9e305a7d4906d..e2ad61f98529e 100644 --- a/integration/bazel/yarn.lock +++ b/integration/bazel/yarn.lock @@ -3,10 +3,10 @@ "@angular/animations@file:../../dist/packages-dist/animations": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/bazel@file:../../dist/packages-dist/bazel": - version "9.1.0-next.4" + version "9.1.0-rc.0" dependencies: "@microsoft/api-extractor" "^7.3.9" shelljs "0.8.2" @@ -22,10 +22,10 @@ parse5 "^5.0.0" "@angular/common@file:../../dist/packages-dist/common": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "9.1.0-next.4" + version "9.1.0-rc.0" dependencies: canonical-path "1.0.0" chokidar "^3.0.0" @@ -41,13 +41,13 @@ yargs "15.3.0" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/core@file:../../dist/packages-dist/core": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/forms@file:../../dist/packages-dist/forms": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/material@8.0.1": version "8.0.1" @@ -57,43 +57,43 @@ tslib "^1.7.1" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@angular/router@file:../../dist/packages-dist/router": - version "9.1.0-next.4" + version "9.1.0-rc.0" "@bazel/bazelisk@file:../../node_modules/@bazel/bazelisk": version "1.3.0" -"@bazel/karma@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.4.1.tgz#12106dfd50ffd8ce98a35a0000badcb9d730c5c4" - integrity sha512-6VecxKGyMam1kA4mGX1GHPgustw8hdyR6v9LTvPWJQ7P5drZbvXUTMz+MLEzbElWdB2KDMljkJRlspbCXuTWew== +"@bazel/karma@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.5.0.tgz#75ea27c3c2a8a7fadbb5c5ab644c3acd3bc22702" + integrity sha512-j5S2Xya4Rr7vK0DzTaZ8FKDHBydtTNldwlx+rihjKJgbEBt76wQM7ucXD6aSA23lC+JM/dPRSKkpIIGeWf2JdQ== dependencies: tmp "0.1.0" -"@bazel/protractor@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.4.1.tgz#fb668429ddc7d1d725d9ce9cf16a29e0e39ab2e0" - integrity sha512-AkgKdd+6cv6tSmCyop11jgfkpCGWsmykgBOAUftBPK2qtn5iHDSpI2xrZUQQv1/F9vhFFvy+09sIslGWP/TyEA== +"@bazel/protractor@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.5.0.tgz#ac92442bf38f5cd718812e4cca41ba2e5ebf1fa5" + integrity sha512-nUwOOUjNGJUU18JiE3sPOBzIul0jvGApEEikntKTLLwQ7w7/1TnOdXDWvHXrXRW3nwit6flWIzEUoFtWgwtCeg== -"@bazel/rollup@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.4.1.tgz#395fbd2611867a54be154ecff1239fcde261371b" - integrity sha512-CU0D+xPQbspuVsKhv2sP0kWhIuEQo8eYjhQXP9BXVZ02uc+YCOkW/5JHIhF946QYljp++W6mcVUGFdBYcrVZow== +"@bazel/rollup@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.5.0.tgz#d0933d167e682470b90f8149eecf4c5bd7511369" + integrity sha512-/FEJfNi9dbbH8oQbf7LHyd0uhGSB0CQQhOpz8d4b2WLnYLhK0NZhoNF4afFjju5kQkrbrOfKaho64BfVxvNppA== -"@bazel/terser@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.4.1.tgz#af4d63c768e72d57674a4514857fea5d9984378d" - integrity sha512-JGhv22d2IOGePE0VwmF6c88GOP3Ij621qtLoI7ZVLDRTElSRAknqj09qX6Zni2DkjT2c/+Ldm2qE8P6hOCXpEg== +"@bazel/terser@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.5.0.tgz#141e1492043231001da3f3ef67b575dd9c2df0be" + integrity sha512-ajT2roE+tiW+xm2YOSfUG55MaUHv0hHYlQneNV1GI3lZoowWPbToOaZiuVza90ulHFHP7lDXn/5MC4UF5/piOQ== -"@bazel/typescript@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.4.1.tgz#1c718ce6de694e1bb90f894fa6320a0cadd90850" - integrity sha512-+R/cZcQpuvGfxqc9s/qu/LBWGNV93iSPTt/mvXq6hfH+sABmrrC/E0+WxapuQaaPdKqR3zSdDIIBV70FUMozsg== +"@bazel/typescript@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.5.0.tgz#d69324c08e7dbfe10b21a6fcb7b4d66c71c8d171" + integrity sha512-Vi8n1p35EhxGC22TEnmnVPlyakrALyH2ccVN5J6YeZXE1oWlSMSqQEhXKTjqUfQ3FT76nW1K91AdH4TG3me5nQ== dependencies: protobufjs "6.8.8" semver "5.6.0" diff --git a/package.json b/package.json index 13c597d34c02b..52317d0147c06 100644 --- a/package.json +++ b/package.json @@ -51,12 +51,12 @@ "@babel/template": "^7.8.6", "@babel/traverse": "^7.8.6", "@babel/types": "^7.8.6", - "@bazel/jasmine": "1.4.1", - "@bazel/karma": "1.4.1", - "@bazel/protractor": "1.4.1", - "@bazel/rollup": "1.4.1", - "@bazel/terser": "1.4.1", - "@bazel/typescript": "1.4.1", + "@bazel/jasmine": "1.5.0", + "@bazel/karma": "1.5.0", + "@bazel/protractor": "1.5.0", + "@bazel/rollup": "1.5.0", + "@bazel/terser": "1.5.0", + "@bazel/typescript": "1.5.0", "@microsoft/api-extractor": "^7.3.9", "@schematics/angular": "9.0.3", "@types/angular": "^1.6.47", diff --git a/packages/bazel/src/builders/files/WORKSPACE.template b/packages/bazel/src/builders/files/WORKSPACE.template index 873c0fe46b208..4648ee555430a 100644 --- a/packages/bazel/src/builders/files/WORKSPACE.template +++ b/packages/bazel/src/builders/files/WORKSPACE.template @@ -15,8 +15,8 @@ workspace( load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -RULES_NODEJS_VERSION = "1.4.1" -RULES_NODEJS_SHA256 = "2eca5b934dee47b5ff304f502ae187c40ec4e33e12bcbce872a2eeb786e23269" +RULES_NODEJS_VERSION = "1.5.0" +RULES_NODEJS_SHA256 = "d0c4bb8b902c1658f42eb5563809c70a06e46015d64057d25560b0eb4bdc9007" http_archive( name = "build_bazel_rules_nodejs", sha256 = RULES_NODEJS_SHA256, diff --git a/packages/bazel/src/schematics/ng-add/index.ts b/packages/bazel/src/schematics/ng-add/index.ts index 2998bbf16c4ab..5b72330363cfd 100644 --- a/packages/bazel/src/schematics/ng-add/index.ts +++ b/packages/bazel/src/schematics/ng-add/index.ts @@ -40,11 +40,11 @@ function addDevDependenciesToPackageJson(options: Schema) { ['@angular/bazel', angularCore.version], ['@bazel/bazel', '2.1.0'], ['@bazel/ibazel', '0.12.3'], - ['@bazel/karma', '1.4.1'], - ['@bazel/protractor', '1.4.1'], - ['@bazel/rollup', '1.4.1'], - ['@bazel/terser', '1.4.1'], - ['@bazel/typescript', '1.4.1'], + ['@bazel/karma', '1.5.0'], + ['@bazel/protractor', '1.5.0'], + ['@bazel/rollup', '1.5.0'], + ['@bazel/terser', '1.5.0'], + ['@bazel/typescript', '1.5.0'], ['history-server', '1.3.1'], ['html-insert-assets', '0.5.0'], ['karma', '4.4.1'], diff --git a/yarn.lock b/yarn.lock index 19c11e9b38a20..55922087c0007 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1079,42 +1079,42 @@ resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.12.3.tgz#c8c82647f920cd529c7793c50e087e1a754a5973" integrity sha512-dyx62Uo5kogrxFmqFNpGvbavfr8yjmuQlOyZczOuA60piULwlUsO7Oh3/1OUWKDSXaMMqHhFQfpdl+z0HjI6TQ== -"@bazel/jasmine@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.4.1.tgz#eb70ad8099eb82505ee5841981fe4f3b7c8c47d0" - integrity sha512-fslF86VzSoQ5ir2aQScKbROqlVdoS0A4zeSslngIwbfhgrXZVbErXtuS43O5FgGCF+1zEfeTgXAgtwtjNdjs6Q== +"@bazel/jasmine@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.5.0.tgz#be980cb8e9f82a87036e27f86278bd7a54d74c43" + integrity sha512-r06GTWKxZYs6msPTbIJ+vcHLQke6wMULo3p4w3ecDybRzKq54syjSzlmejIm9wJ8OHrVyRRSvHgvygxCGJfhTA== dependencies: jasmine "~3.5.0" jasmine-core "~3.5.0" jasmine-reporters "~2.3.2" v8-coverage "1.0.9" -"@bazel/karma@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.4.1.tgz#12106dfd50ffd8ce98a35a0000badcb9d730c5c4" - integrity sha512-6VecxKGyMam1kA4mGX1GHPgustw8hdyR6v9LTvPWJQ7P5drZbvXUTMz+MLEzbElWdB2KDMljkJRlspbCXuTWew== +"@bazel/karma@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.5.0.tgz#75ea27c3c2a8a7fadbb5c5ab644c3acd3bc22702" + integrity sha512-j5S2Xya4Rr7vK0DzTaZ8FKDHBydtTNldwlx+rihjKJgbEBt76wQM7ucXD6aSA23lC+JM/dPRSKkpIIGeWf2JdQ== dependencies: tmp "0.1.0" -"@bazel/protractor@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.4.1.tgz#fb668429ddc7d1d725d9ce9cf16a29e0e39ab2e0" - integrity sha512-AkgKdd+6cv6tSmCyop11jgfkpCGWsmykgBOAUftBPK2qtn5iHDSpI2xrZUQQv1/F9vhFFvy+09sIslGWP/TyEA== +"@bazel/protractor@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.5.0.tgz#ac92442bf38f5cd718812e4cca41ba2e5ebf1fa5" + integrity sha512-nUwOOUjNGJUU18JiE3sPOBzIul0jvGApEEikntKTLLwQ7w7/1TnOdXDWvHXrXRW3nwit6flWIzEUoFtWgwtCeg== -"@bazel/rollup@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.4.1.tgz#395fbd2611867a54be154ecff1239fcde261371b" - integrity sha512-CU0D+xPQbspuVsKhv2sP0kWhIuEQo8eYjhQXP9BXVZ02uc+YCOkW/5JHIhF946QYljp++W6mcVUGFdBYcrVZow== +"@bazel/rollup@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.5.0.tgz#d0933d167e682470b90f8149eecf4c5bd7511369" + integrity sha512-/FEJfNi9dbbH8oQbf7LHyd0uhGSB0CQQhOpz8d4b2WLnYLhK0NZhoNF4afFjju5kQkrbrOfKaho64BfVxvNppA== -"@bazel/terser@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.4.1.tgz#af4d63c768e72d57674a4514857fea5d9984378d" - integrity sha512-JGhv22d2IOGePE0VwmF6c88GOP3Ij621qtLoI7ZVLDRTElSRAknqj09qX6Zni2DkjT2c/+Ldm2qE8P6hOCXpEg== +"@bazel/terser@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.5.0.tgz#141e1492043231001da3f3ef67b575dd9c2df0be" + integrity sha512-ajT2roE+tiW+xm2YOSfUG55MaUHv0hHYlQneNV1GI3lZoowWPbToOaZiuVza90ulHFHP7lDXn/5MC4UF5/piOQ== -"@bazel/typescript@1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.4.1.tgz#1c718ce6de694e1bb90f894fa6320a0cadd90850" - integrity sha512-+R/cZcQpuvGfxqc9s/qu/LBWGNV93iSPTt/mvXq6hfH+sABmrrC/E0+WxapuQaaPdKqR3zSdDIIBV70FUMozsg== +"@bazel/typescript@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.5.0.tgz#d69324c08e7dbfe10b21a6fcb7b4d66c71c8d171" + integrity sha512-Vi8n1p35EhxGC22TEnmnVPlyakrALyH2ccVN5J6YeZXE1oWlSMSqQEhXKTjqUfQ3FT76nW1K91AdH4TG3me5nQ== dependencies: protobufjs "6.8.8" semver "5.6.0" From 80c68583d1160f2d43a6af52a6f078384f979a70 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir <akushnir@google.com> Date: Fri, 27 Mar 2020 17:39:14 -0700 Subject: [PATCH 058/262] refactor(core): use more narrow `QueryList` import to avoid circular deps issue (#36286) Prior to this commit, the `packages/core/src/render3/interfaces/query.ts` file used to import `QueryList` using `../../linker`, which contains a lot of re-exports and as a result, this one import caused a lot of circular deps cycles reported by the tool that checks such deps. In other places in the code the `QueryList` is imported using more narrow import (`linker/query_list`), so this commit uses the same pattern. This change allowed to reduce the number of known cycles from 343 to 207, the golden file was updated accordingly. PR Close #36286 --- goldens/packages-circular-deps.json | 4941 +++-------------- packages/core/src/render3/interfaces/query.ts | 2 +- 2 files changed, 649 insertions(+), 4294 deletions(-) diff --git a/goldens/packages-circular-deps.json b/goldens/packages-circular-deps.json index bcad2a7b04ac8..c2bb283d29ec3 100644 --- a/goldens/packages-circular-deps.json +++ b/goldens/packages-circular-deps.json @@ -270,30 +270,17 @@ "packages/core/src/render3/interfaces/view.ts" ], [ - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", "packages/core/src/render3/interfaces/node.ts", "packages/core/src/render3/interfaces/definition.ts", "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts" + "packages/core/src/render3/interfaces/query.ts" + ], + [ + "packages/core/src/render3/interfaces/view.ts", + "packages/core/src/render3/interfaces/query.ts" ], [ + "packages/core/src/core.ts", "packages/core/src/metadata.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", @@ -312,26 +299,9 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts" - ], - [ - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts" ], [ "packages/core/src/di/injector.ts", @@ -345,52 +315,31 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts" ], [ - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts" ], [ + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", @@ -402,17 +351,17 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts" ], [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -420,36 +369,19 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts" ], [ - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", @@ -459,59 +391,59 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts" ], [ - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts", + "packages/core/src/render3/state.ts" + ], + [ + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts", + "packages/core/src/render3/state.ts", + "packages/core/src/render3/util/view_utils.ts" + ], + [ + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts", + "packages/core/src/render3/state.ts", + "packages/core/src/render3/util/view_utils.ts" + ], + [ + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts" ], [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", @@ -524,17 +456,10 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts" ], [ "packages/core/src/di.ts", @@ -554,74 +479,48 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/element.ts", "packages/core/src/view/types.ts" ], [ - "packages/core/src/view/types.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts" + "packages/core/src/view/element.ts", + "packages/core/src/view/types.ts" ], [ + "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/element.ts", - "packages/core/src/view/util.ts" + "packages/core/src/view/types.ts" ], [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", @@ -629,29 +528,35 @@ "packages/core/src/view/util.ts" ], [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/element.ts", - "packages/core/src/view/util.ts", - "packages/core/src/view/errors.ts" + "packages/core/src/view/util.ts" ], [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/element.ts", "packages/core/src/view/util.ts", "packages/core/src/view/errors.ts" ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts", - "packages/core/src/view/util.ts" - ], [ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", @@ -664,18 +569,10 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", @@ -687,18 +584,10 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", @@ -722,38 +611,10 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", @@ -762,17 +623,10 @@ "packages/core/src/debug/debug_node.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", @@ -781,14 +635,6 @@ "packages/core/src/debug/debug_node.ts" ], [ - "packages/core/src/core.ts", - "packages/core/src/metadata.ts", - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", @@ -800,87 +646,56 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" + "packages/core/src/render3/util/discovery_utils.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" + "packages/core/src/render3/util/discovery_utils.ts" ], [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/instructions/lview_debug.ts" ], [ + "packages/core/src/core.ts", + "packages/core/src/metadata.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", @@ -890,64 +705,73 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/instructions/lview_debug.ts" + ], + [ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/util/view_traversal_utils.ts" + ], + [ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/util/view_traversal_utils.ts" + ], + [ + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/debug/debug_node.ts" ], [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", @@ -960,583 +784,305 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/view/services.ts" ], [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/view/services.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/services.ts" + ], + [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/provider.ts" + ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/provider.ts" + ], + [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts" + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts" + ], + [ + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts" + ], + [ + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts" + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts" ], [ + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts", + "packages/core/src/view/ng_module.ts" + ], + [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts", + "packages/core/src/view/ng_module.ts" + ], + [ + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts", - "packages/core/src/render3/interfaces/context.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/render3/instructions/shared.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/interfaces/injector.ts" + "packages/core/src/render3/instructions/shared.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/interfaces/injector.ts" + "packages/core/src/render3/instructions/shared.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/core.ts", + "packages/core/src/metadata.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/render3/node_manipulation.ts" ], [ + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/render3/node_manipulation.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/render3/node_manipulation.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/node_assert.ts" + "packages/core/src/render3/styling/static_styling.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/util/attrs_utils.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/container.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/util/injector_utils.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/container.ts" ], [ "packages/core/src/di.ts", @@ -1556,3434 +1102,170 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/di.ts" ], [ - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/sanitization/sanitization.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/di.ts" ], [ "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/context_discovery.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/context_discovery.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element_container.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/errors.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element_container.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/errors.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/embedded_view.ts" ], [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/listener.ts" ], [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/styling.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/styling.ts", + "packages/core/src/render3/styling/style_binding_list.ts" ], [ + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/index.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/features/copy_definition_feature.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/node_selector_matcher.ts" + "packages/core/src/render3/features/copy_definition_feature.ts", + "packages/core/src/render3/features/inherit_definition_feature.ts" ], [ + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/util/view_traversal_utils.ts" - ], - [ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/util/view_traversal_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/util/view_traversal_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/advance.ts" - ], - [ - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/core.ts", - "packages/core/src/metadata.ts", - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" - ], - [ - "packages/core/src/core.ts", - "packages/core/src/metadata.ts", - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/styling/static_styling.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/styling/static_styling.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/attribute.ts", - "packages/core/src/render3/bindings.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/attribute_interpolation.ts", - "packages/core/src/render3/instructions/interpolation.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/change_detection.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/storage.ts" - ], - [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/di.ts" - ], - [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/di.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/di.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts", - "packages/core/src/render3/instructions/property.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts", - "packages/core/src/render3/instructions/property.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element_container.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element_container.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element_container.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element_container.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/embedded_view.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/embedded_view.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/embedded_view.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/embedded_view.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/embedded_view.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/get_current_view.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/listener.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/listener.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/listener.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/projection.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/projection.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/property_interpolation.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts", - "packages/core/src/render3/styling/style_binding_list.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts", - "packages/core/src/render3/styling/style_binding_list.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts", - "packages/core/src/render3/styling/style_binding_list.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/text.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/text.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/host_property.ts" - ], - [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts", - "packages/core/src/render3/features/inherit_definition_feature.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts", - "packages/core/src/render3/features/inherit_definition_feature.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts", - "packages/core/src/render3/features/inherit_definition_feature.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/ng_onchanges_feature.ts" - ], - [ - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts" - ], - [ - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/i18n.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/i18n.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/i18n.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/i18n.ts" - ], - [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts", - "packages/core/src/linker/ng_module_factory_registration.ts" - ], - [ - "packages/core/src/render3/ng_module_ref.ts", - "packages/core/src/linker/ng_module_factory_registration.ts" - ], - [ - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts" - ], - [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts", - "packages/core/src/render3/pure_function.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/view_engine_compatibility_prebound.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/view_engine_compatibility_prebound.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/view_engine_compatibility_prebound.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/view_engine_compatibility_prebound.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/interfaces/type_checks.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts" - ], - [ - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts" - ], - [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/query.ts" - ], - [ - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts", - "packages/core/src/view/ng_content.ts" - ], - [ - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts", - "packages/core/src/view/pure_expression.ts" - ], - [ - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts", - "packages/core/src/view/text.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/view.ts", - "packages/core/src/view/view_attach.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts" - ], - [ - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts" - ], - [ - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts" - ], - [ - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts" - ], - [ - "packages/core/src/view/types.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts" - ], - [ - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts", - "packages/core/src/view/types.ts" + "packages/core/src/render3/features/providers_feature.ts", + "packages/core/src/render3/di_setup.ts" + ], + [ + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/features/providers_feature.ts", + "packages/core/src/render3/di_setup.ts" ], [ + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts" ], [ + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", @@ -4993,49 +1275,45 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts" ], [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts" ], [ "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts" ], [ @@ -5046,13 +1324,8 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts", "packages/core/src/render3/view_ref.ts" ], @@ -5060,46 +1333,42 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts", "packages/core/src/render3/view_ref.ts" ], [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", "packages/core/src/render3/component_ref.ts", "packages/core/src/render3/view_ref.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/render3/view_ref.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/i18n.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/render3/view_ref.ts" + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/ng_module_ref.ts" ], [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", @@ -5109,47 +1378,72 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/ng_module_ref.ts" ], [ + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/compiler.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/ng_module_ref.ts" + ], + [ + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/linker/ng_module_factory_registration.ts" + ], + [ + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/linker/ng_module_factory_registration.ts" ], [ + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/ng_module_ref.ts" + ], + [ + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/ng_module_ref.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", @@ -5162,23 +1456,51 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts", - "packages/core/src/linker.ts", - "packages/core/src/linker/system_js_ng_module_factory_loader.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/pipe.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts" + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/pipe.ts" ], [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/query.ts" + ], + [ + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/query.ts" + ], + [ + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/view_engine_compatibility_prebound.ts" + ], + [ + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/view_engine_compatibility_prebound.ts" ], [ "packages/core/src/di/injector.ts", @@ -5216,6 +1538,39 @@ "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts" ], + [ + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/linker/compiler.ts" + ], + [ + "packages/core/src/metadata.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/linker/compiler.ts" + ], + [ + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/linker/compiler.ts" + ], [ "packages/core/src/di.ts", "packages/core/src/di/index.ts", diff --git a/packages/core/src/render3/interfaces/query.ts b/packages/core/src/render3/interfaces/query.ts index bb19958d30b3a..2c5d14df12d6a 100644 --- a/packages/core/src/render3/interfaces/query.ts +++ b/packages/core/src/render3/interfaces/query.ts @@ -7,7 +7,7 @@ */ import {Type} from '../../interface/type'; -import {QueryList} from '../../linker'; +import {QueryList} from '../../linker/query_list'; import {TNode} from './node'; import {TView} from './view'; From 2510e7dad6d583d9fa76369e53b88cd0e52f17b3 Mon Sep 17 00:00:00 2001 From: Alexey Okhrimenko <ai_boy@live.ru> Date: Mon, 30 Mar 2020 20:57:06 +0300 Subject: [PATCH 059/262] docs: fix typo in Schematics guide (#36328) Fixing typo in schematics-for-libraries.md PR Close #36328 --- aio/content/guide/schematics-for-libraries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/schematics-for-libraries.md b/aio/content/guide/schematics-for-libraries.md index 5800099e2ffbb..7b9e682a3d1ae 100644 --- a/aio/content/guide/schematics-for-libraries.md +++ b/aio/content/guide/schematics-for-libraries.md @@ -249,7 +249,7 @@ A `Rule` can use external template files, transform them, and return another `Ru * The `url()` method reads source files from your filesystem, relative to the schematic. * The `applyTemplates()` method receives an argument of methods and properties you want make available to the schematic template and the schematic filenames. It returns a `Rule`. This is where you define the `classify()` and `dasherize()` methods, and the `name` property. * The `classify()` method takes a value and returns the value in title case. For example, if the provided name is `my service`, it is returned as `MyService` - * The `dasherize()` method takes a value and returns the value in dashed and lowercase. For example, if the provided name is MyService, it is returned as `my-service. + * The `dasherize()` method takes a value and returns the value in dashed and lowercase. For example, if the provided name is MyService, it is returned as `my-service`. * The `move` method moves the provided source files to their destination when the schematic is applied. 1. Finally, the rule factory must return a rule. From c5df9ce474064b197b96575b9195405cb939601a Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Tue, 24 Mar 2020 10:22:41 +0900 Subject: [PATCH 060/262] build(zone.js): update zone.js version to 0.10.3 (#36214) PR Close #36214 --- aio/package.json | 2 +- .../examples/shared/boilerplate/systemjs/package.json | 4 +--- aio/yarn.lock | 8 ++++---- integration/bazel/package.json | 2 +- integration/bazel/yarn.lock | 8 ++++---- integration/cli-hello-world-ivy-compat/yarn.lock | 2 +- integration/cli-hello-world-ivy-i18n/yarn.lock | 2 +- integration/cli-hello-world-ivy-minimal/yarn.lock | 2 +- integration/cli-hello-world-lazy-rollup/yarn.lock | 2 +- integration/cli-hello-world-lazy/yarn.lock | 2 +- integration/cli-hello-world/yarn.lock | 2 +- integration/dynamic-compiler/yarn.lock | 2 +- integration/hello_world__closure/yarn.lock | 2 +- integration/hello_world__systemjs_umd/yarn.lock | 2 +- integration/i18n/yarn.lock | 2 +- integration/injectable-def/yarn.lock | 2 +- integration/ivy-i18n/yarn.lock | 2 +- integration/ng_elements/yarn.lock | 2 +- integration/ng_update/yarn.lock | 2 +- integration/ng_update_migrations/yarn.lock | 2 +- integration/ngcc/yarn.lock | 2 +- integration/platform-server/yarn.lock | 2 +- integration/service-worker-schema/yarn.lock | 2 +- integration/terser/yarn.lock | 2 +- integration/typings_test_ts36/yarn.lock | 2 +- integration/typings_test_ts37/yarn.lock | 2 +- integration/typings_test_ts38/yarn.lock | 2 +- packages/core/package.json | 6 +++--- scripts/release/post-check | 2 +- scripts/release/post-check-next | 2 +- 30 files changed, 38 insertions(+), 40 deletions(-) diff --git a/aio/package.json b/aio/package.json index 4645a2b6dc248..5316812276ef7 100644 --- a/aio/package.json +++ b/aio/package.json @@ -102,7 +102,7 @@ "@webcomponents/custom-elements": "1.2.1", "rxjs": "^6.5.3", "tslib": "^1.10.0", - "zone.js": "~0.10.2" + "zone.js": "~0.10.3" }, "devDependencies": { "@angular-devkit/build-angular": "0.900.1", diff --git a/aio/tools/examples/shared/boilerplate/systemjs/package.json b/aio/tools/examples/shared/boilerplate/systemjs/package.json index 5f1a830d67c8e..8bee75863e913 100644 --- a/aio/tools/examples/shared/boilerplate/systemjs/package.json +++ b/aio/tools/examples/shared/boilerplate/systemjs/package.json @@ -19,12 +19,10 @@ "pretest:once": "npm run build", "test:once": "karma start karma.conf.js --single-run", "lint": "tslint ./src/**/*.ts -t verbose", - "build:upgrade": "tsc", "serve:upgrade": "http-server", "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js", "serve:aot": "lite-server -c bs-config.aot.json", - "copy-dist-files": "node ./copy-dist-files.js" }, "keywords": [], @@ -42,7 +40,7 @@ "@angular/upgrade": "~9.0.3", "rxjs": "~6.5.4", "tslib": "^1.10.0", - "zone.js": "~0.10.2" + "zone.js": "~0.10.3" }, "devDependencies": { "@angular/compiler-cli": "~9.0.3", diff --git a/aio/yarn.lock b/aio/yarn.lock index 66019a47f200e..e76383732aeb1 100644 --- a/aio/yarn.lock +++ b/aio/yarn.lock @@ -13032,7 +13032,7 @@ zip-stream@^2.1.2: compress-commons "^2.1.1" readable-stream "^3.4.0" -zone.js@~0.10.2: - version "0.10.2" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.2.tgz#67ca084b3116fc33fc40435e0d5ea40a207e392e" - integrity sha512-UAYfiuvxLN4oyuqhJwd21Uxb4CNawrq6fPS/05Su5L4G+1TN+HVDJMUHNMobVQDFJRir2cLAODXwluaOKB7HFg== +zone.js@~0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16" + integrity sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg== diff --git a/integration/bazel/package.json b/integration/bazel/package.json index b9517b79c2af1..2ec53ac0a4e75 100644 --- a/integration/bazel/package.json +++ b/integration/bazel/package.json @@ -16,7 +16,7 @@ "reflect-metadata": "0.1.12", "rxjs": "file:../../node_modules/rxjs", "tslib": "file:../../node_modules/tslib", - "zone.js": "0.10.2" + "zone.js": "0.10.3" }, "devDependencies": { "@angular/bazel": "file:../../dist/packages-dist/bazel", diff --git a/integration/bazel/yarn.lock b/integration/bazel/yarn.lock index e2ad61f98529e..3234081c24381 100644 --- a/integration/bazel/yarn.lock +++ b/integration/bazel/yarn.lock @@ -2700,7 +2700,7 @@ z-schema@~3.18.3: optionalDependencies: commander "^2.7.1" -zone.js@0.10.2: - version "0.10.2" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.2.tgz#67ca084b3116fc33fc40435e0d5ea40a207e392e" - integrity sha512-UAYfiuvxLN4oyuqhJwd21Uxb4CNawrq6fPS/05Su5L4G+1TN+HVDJMUHNMobVQDFJRir2cLAODXwluaOKB7HFg== +zone.js@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.10.3.tgz#3e5e4da03c607c9dcd92e37dd35687a14a140c16" + integrity sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg== diff --git a/integration/cli-hello-world-ivy-compat/yarn.lock b/integration/cli-hello-world-ivy-compat/yarn.lock index 4b3eb4f1f90ef..a9b3ba8f71af9 100644 --- a/integration/cli-hello-world-ivy-compat/yarn.lock +++ b/integration/cli-hello-world-ivy-compat/yarn.lock @@ -9470,4 +9470,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/cli-hello-world-ivy-i18n/yarn.lock b/integration/cli-hello-world-ivy-i18n/yarn.lock index 3e1ccb8077246..db8afee3a5800 100644 --- a/integration/cli-hello-world-ivy-i18n/yarn.lock +++ b/integration/cli-hello-world-ivy-i18n/yarn.lock @@ -9393,4 +9393,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/cli-hello-world-ivy-minimal/yarn.lock b/integration/cli-hello-world-ivy-minimal/yarn.lock index 4b3eb4f1f90ef..a9b3ba8f71af9 100644 --- a/integration/cli-hello-world-ivy-minimal/yarn.lock +++ b/integration/cli-hello-world-ivy-minimal/yarn.lock @@ -9470,4 +9470,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/cli-hello-world-lazy-rollup/yarn.lock b/integration/cli-hello-world-lazy-rollup/yarn.lock index 064f1f2696a6c..f622c33cac979 100644 --- a/integration/cli-hello-world-lazy-rollup/yarn.lock +++ b/integration/cli-hello-world-lazy-rollup/yarn.lock @@ -9045,4 +9045,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/cli-hello-world-lazy/yarn.lock b/integration/cli-hello-world-lazy/yarn.lock index 064f1f2696a6c..f622c33cac979 100644 --- a/integration/cli-hello-world-lazy/yarn.lock +++ b/integration/cli-hello-world-lazy/yarn.lock @@ -9045,4 +9045,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/cli-hello-world/yarn.lock b/integration/cli-hello-world/yarn.lock index b790bbb84f8a6..5d07c26fe88d8 100644 --- a/integration/cli-hello-world/yarn.lock +++ b/integration/cli-hello-world/yarn.lock @@ -10007,4 +10007,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/dynamic-compiler/yarn.lock b/integration/dynamic-compiler/yarn.lock index 1970e297e6f36..9bd3256ed91ba 100644 --- a/integration/dynamic-compiler/yarn.lock +++ b/integration/dynamic-compiler/yarn.lock @@ -3777,4 +3777,4 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/hello_world__closure/yarn.lock b/integration/hello_world__closure/yarn.lock index ce10897b7f593..adb6bfa7c7174 100644 --- a/integration/hello_world__closure/yarn.lock +++ b/integration/hello_world__closure/yarn.lock @@ -4501,4 +4501,4 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/hello_world__systemjs_umd/yarn.lock b/integration/hello_world__systemjs_umd/yarn.lock index eaa4596ddaf74..b2cb772e30c0e 100644 --- a/integration/hello_world__systemjs_umd/yarn.lock +++ b/integration/hello_world__systemjs_umd/yarn.lock @@ -2533,4 +2533,4 @@ yeast@0.1.2: resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/i18n/yarn.lock b/integration/i18n/yarn.lock index 83ab2e0abcd93..5bd6915145f9b 100644 --- a/integration/i18n/yarn.lock +++ b/integration/i18n/yarn.lock @@ -3734,4 +3734,4 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/injectable-def/yarn.lock b/integration/injectable-def/yarn.lock index 560d8e352912d..6226f0a31ca57 100644 --- a/integration/injectable-def/yarn.lock +++ b/integration/injectable-def/yarn.lock @@ -2860,4 +2860,4 @@ yeast@0.1.2: resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/ivy-i18n/yarn.lock b/integration/ivy-i18n/yarn.lock index 3e1ccb8077246..db8afee3a5800 100644 --- a/integration/ivy-i18n/yarn.lock +++ b/integration/ivy-i18n/yarn.lock @@ -9393,4 +9393,4 @@ yn@^3.0.0: integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/ng_elements/yarn.lock b/integration/ng_elements/yarn.lock index 56d748992c530..fa26bd58643ac 100644 --- a/integration/ng_elements/yarn.lock +++ b/integration/ng_elements/yarn.lock @@ -3527,4 +3527,4 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/ng_update/yarn.lock b/integration/ng_update/yarn.lock index 5fc4704d53453..5fc241b94f720 100644 --- a/integration/ng_update/yarn.lock +++ b/integration/ng_update/yarn.lock @@ -640,4 +640,4 @@ yargs@13.1.0: yargs-parser "^13.0.0" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/ng_update_migrations/yarn.lock b/integration/ng_update_migrations/yarn.lock index 6ef1f8a8d162f..bd6d6037aa1e5 100644 --- a/integration/ng_update_migrations/yarn.lock +++ b/integration/ng_update_migrations/yarn.lock @@ -8662,4 +8662,4 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/ngcc/yarn.lock b/integration/ngcc/yarn.lock index 2e1b49e3671e3..bb53f3ac796c6 100644 --- a/integration/ngcc/yarn.lock +++ b/integration/ngcc/yarn.lock @@ -3677,4 +3677,4 @@ yeast@0.1.2: integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/platform-server/yarn.lock b/integration/platform-server/yarn.lock index e57c215266865..134fd16666705 100644 --- a/integration/platform-server/yarn.lock +++ b/integration/platform-server/yarn.lock @@ -4590,4 +4590,4 @@ yauzl@2.4.1: fd-slicer "~1.0.1" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/service-worker-schema/yarn.lock b/integration/service-worker-schema/yarn.lock index bd15cb087cf8b..e6488235d8636 100644 --- a/integration/service-worker-schema/yarn.lock +++ b/integration/service-worker-schema/yarn.lock @@ -22,4 +22,4 @@ tslib@^1.9.0: integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/terser/yarn.lock b/integration/terser/yarn.lock index 078eecb5ee0d2..6125bf4471dec 100644 --- a/integration/terser/yarn.lock +++ b/integration/terser/yarn.lock @@ -629,4 +629,4 @@ yargs@13.1.0: yargs-parser "^13.0.0" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/typings_test_ts36/yarn.lock b/integration/typings_test_ts36/yarn.lock index 6bf9eca15c64e..5d1b417ce890c 100644 --- a/integration/typings_test_ts36/yarn.lock +++ b/integration/typings_test_ts36/yarn.lock @@ -659,4 +659,4 @@ yargs@13.1.0: yargs-parser "^13.0.0" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/typings_test_ts37/yarn.lock b/integration/typings_test_ts37/yarn.lock index 447a2a2ef8128..22c5a59ec65dd 100644 --- a/integration/typings_test_ts37/yarn.lock +++ b/integration/typings_test_ts37/yarn.lock @@ -659,4 +659,4 @@ yargs@13.1.0: yargs-parser "^13.0.0" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/integration/typings_test_ts38/yarn.lock b/integration/typings_test_ts38/yarn.lock index 0105c7d5f5261..6c3fd3dfdbdc3 100644 --- a/integration/typings_test_ts38/yarn.lock +++ b/integration/typings_test_ts38/yarn.lock @@ -660,4 +660,4 @@ yargs@13.1.0: yargs-parser "^13.0.0" "zone.js@file:../../dist/zone.js-dist/zone.js": - version "0.10.2" + version "0.10.3" diff --git a/packages/core/package.json b/packages/core/package.json index d0bbdd9760758..e2de2562cecac 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -15,7 +15,7 @@ "peerDependencies": { "rxjs": "^6.5.3", "tslib": "^1.10.0", - "zone.js": "~0.10.2" + "zone.js": "~0.10.3" }, "repository": { "type": "git", @@ -27,7 +27,7 @@ "packageGroup": "NG_UPDATE_PACKAGE_GROUP" }, "sideEffects": false, - "publishConfig":{ - "registry":"https://wombat-dressing-room.appspot.com" + "publishConfig": { + "registry": "https://wombat-dressing-room.appspot.com" } } diff --git a/scripts/release/post-check b/scripts/release/post-check index 8fa0f4e8330e9..f1624ecde8cf8 100755 --- a/scripts/release/post-check +++ b/scripts/release/post-check @@ -7,7 +7,7 @@ mkdir tmp cd tmp npm init -y -npm install typescript@~3.7.4 rxjs@^6.5.3 zone.js@~0.10.2 @bazel/typescript@^1.0.0 rollup@^1.20.0 rollup-plugin-commonjs@^9.0.0 rollup-plugin-node-resolve@^4.2.0 rollup-plugin-sourcemaps@0.4.0 @angular/{animations,bazel,common,compiler,compiler-cli,core,elements,forms,language-service,localize,platform-browser,platform-browser-dynamic,platform-server,platform-webworker,platform-webworker-dynamic,router,service-worker,upgrade} --save +npm install typescript@~3.7.4 rxjs@^6.5.3 zone.js@~0.10.3 @bazel/typescript@^1.0.0 rollup@^1.20.0 rollup-plugin-commonjs@^9.0.0 rollup-plugin-node-resolve@^4.2.0 rollup-plugin-sourcemaps@0.4.0 @angular/{animations,bazel,common,compiler,compiler-cli,core,elements,forms,language-service,localize,platform-browser,platform-browser-dynamic,platform-server,platform-webworker,platform-webworker-dynamic,router,service-worker,upgrade} --save cd .. rm -rf tmp diff --git a/scripts/release/post-check-next b/scripts/release/post-check-next index c05e3cfb45bad..2bb6248b3d057 100755 --- a/scripts/release/post-check-next +++ b/scripts/release/post-check-next @@ -7,7 +7,7 @@ mkdir tmp cd tmp npm init -y -npm install typescript@~3.7.4 rxjs@^6.5.3 zone.js@~0.10.2 @bazel/typescript@^1.0.0 rollup@^1.20.0 rollup-plugin-commonjs@^9.0.0 rollup-plugin-node-resolve@^4.2.0 rollup-plugin-sourcemaps@0.4.0 @angular/{animations,bazel,common,compiler,compiler-cli,core,elements,forms,language-service,localize,platform-browser,platform-browser-dynamic,platform-server,platform-webworker,platform-webworker-dynamic,router,service-worker,upgrade}@next --save +npm install typescript@~3.7.4 rxjs@^6.5.3 zone.js@~0.10.3 @bazel/typescript@^1.0.0 rollup@^1.20.0 rollup-plugin-commonjs@^9.0.0 rollup-plugin-node-resolve@^4.2.0 rollup-plugin-sourcemaps@0.4.0 @angular/{animations,bazel,common,compiler,compiler-cli,core,elements,forms,language-service,localize,platform-browser,platform-browser-dynamic,platform-server,platform-webworker,platform-webworker-dynamic,router,service-worker,upgrade}@next --save cd .. rm -rf tmp From b44f7b5e16b6bc2ae7d6a52b04676213c526146a Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Sat, 28 Mar 2020 19:26:53 +0900 Subject: [PATCH 061/262] fix(zone.js): fix 2 bluebird test cases for each/mapSeries (#36295) `Bluebird.each` and `Bluebird.mapSeries` will accept a callback with `value` parameter, the `value` should be the item in the array, not array itself. For example: ``` const arr = [1, 2]; Bluebird.each(arr, function(value, idx) { console.log(`value: ${value}, idx: ${idx}`); }) ``` the output will be ``` value: 1, idx: 0 value: 2, idx: 1 ``` This PR fix the test cases for `each` and `mapSeries` APIs. PR Close #36295 --- packages/zone.js/test/extra/bluebird.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/zone.js/test/extra/bluebird.spec.ts b/packages/zone.js/test/extra/bluebird.spec.ts index 8e8e5993ff53f..a7db2845eece1 100644 --- a/packages/zone.js/test/extra/bluebird.spec.ts +++ b/packages/zone.js/test/extra/bluebird.spec.ts @@ -283,8 +283,8 @@ describe('bluebird promise', () => { BluebirdPromise .each( BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), - (r: number[], idx: number) => { - expect(r[idx] === arr[idx]); + (r: number, idx: number) => { + expect(r).toBe(arr[idx]); expect(Zone.current.name).toEqual('bluebird'); }) .then((r: any) => { @@ -304,8 +304,8 @@ describe('bluebird promise', () => { BluebirdPromise .mapSeries( BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), - (r: number[], idx: number) => { - expect(r[idx] === arr[idx]); + (r: number, idx: number) => { + expect(r).toBe(arr[idx]); expect(Zone.current.name).toEqual('bluebird'); }) .then((r: any) => { From 63fbc714393b6aa93b716cb3f074c9396cb2ddde Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Sun, 29 Mar 2020 13:29:50 -0700 Subject: [PATCH 062/262] build: don't use deprecated $(location) pre-declared variable (#36308) $(location) is not recommended in the bazel docs as depending on context it will either return the value of $(execpath) or $(rootpath). rules_nodejs now supports $(rootpath) and $(execpath) in templated_args of nodejs_binary. PR Close #36308 --- dev-infra/BUILD.bazel | 4 ++-- tools/circular_dependency_test/index.bzl | 6 +++--- tools/defaults.bzl | 2 +- tools/npm_integration_test/npm_integration_test.bzl | 4 ++-- tools/npm_integration_test/test_runner.js | 2 +- tools/saucelabs/BUILD.bazel | 2 +- tools/symbol-extractor/cli.ts | 6 ++++-- tools/symbol-extractor/index.bzl | 4 ++-- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/dev-infra/BUILD.bazel b/dev-infra/BUILD.bazel index 348009afd6607..60d60aa480a87 100644 --- a/dev-infra/BUILD.bazel +++ b/dev-infra/BUILD.bazel @@ -23,8 +23,8 @@ genrule( ], outs = ["package.json"], cmd = """ - $(location //tools:inline-package-json-deps) $(location tmpl-package.json) \ - $(location //:package.json) $@ + $(execpath //tools:inline-package-json-deps) $(execpath tmpl-package.json) \ + $(execpath //:package.json) $@ """, tools = ["//tools:inline-package-json-deps"], ) diff --git a/tools/circular_dependency_test/index.bzl b/tools/circular_dependency_test/index.bzl index 1eb66b266916d..f0d187866341d 100644 --- a/tools/circular_dependency_test/index.bzl +++ b/tools/circular_dependency_test/index.bzl @@ -20,16 +20,16 @@ def circular_dependency_test(name, deps, entry_point, **kwargs): templated_args = [ "--circular", "--no-spinner", - # NOTE: We cannot use `$(location)` to resolve labels. This is because `ts_library` + # NOTE: We cannot use `$(rootpath)` to resolve labels. This is because `ts_library` # does not pre-declare outputs in the rule. Hence, the outputs cannot be referenced # through labels (i.e. `//packages/core:index.js`). Read more here: # https://docs.bazel.build/versions/2.0.0/skylark/rules.html#outputs # TODO: revisit once https://github.com/bazelbuild/rules_nodejs/issues/1563 is solved. - "$(rlocation %s)" % entry_point, + "$$(rlocation %s)" % entry_point, # Madge supports custom module resolution, but expects a configuration file # similar to a Webpack configuration file setting the `resolve` option. "--webpack-config", - "$(rlocation $(location %s))" % MADGE_CONFIG_LABEL, + "$$(rlocation $(rootpath %s))" % MADGE_CONFIG_LABEL, ], testonly = 1, expected_exit_code = 0, diff --git a/tools/defaults.bzl b/tools/defaults.bzl index a6f7fa256934d..0b164ad215653 100644 --- a/tools/defaults.bzl +++ b/tools/defaults.bzl @@ -340,7 +340,7 @@ def jasmine_node_test(bootstrap = [], **kwargs): templated_args = kwargs.pop("templated_args", []) for label in bootstrap: deps += [label] - templated_args += ["--node_options=--require=$(rlocation $(location %s))" % label] + templated_args += ["--node_options=--require=$$(rlocation $(rootpath %s))" % label] if label.endswith("_es5"): # If this label is a filegroup derived from a ts_library then automatically # add the ts_library target (which is the label sans `_es5`) to deps so we pull diff --git a/tools/npm_integration_test/npm_integration_test.bzl b/tools/npm_integration_test/npm_integration_test.bzl index 92f4aeb7c531e..00fe9cda0befe 100644 --- a/tools/npm_integration_test/npm_integration_test.bzl +++ b/tools/npm_integration_test/npm_integration_test.bzl @@ -181,7 +181,7 @@ def npm_integration_test(name, **kwargs): name = name, data = data + npm_deps + [":%s.config" % name, ":%s.config.js" % name], tags = tags, - templated_args = ["$(location :%s.config.js)" % name], + templated_args = ["$(rootpath :%s.config.js)" % name], entry_point = "//tools/npm_integration_test:test_runner.js", **kwargs ) @@ -192,7 +192,7 @@ def npm_integration_test(name, **kwargs): name = name + ".debug", data = data + npm_deps + [":%s.debug.config" % name, ":%s.debug.config.js" % name], tags = tags + ["manual", "local"], - templated_args = ["$(location :%s.debug.config.js)" % name], + templated_args = ["$(rootpath :%s.debug.config.js)" % name], entry_point = "//tools/npm_integration_test:test_runner.js", **kwargs ) diff --git a/tools/npm_integration_test/test_runner.js b/tools/npm_integration_test/test_runner.js index 61a9843414d96..e42f30898c23b 100644 --- a/tools/npm_integration_test/test_runner.js +++ b/tools/npm_integration_test/test_runner.js @@ -340,7 +340,7 @@ class TestRunner { } } -const config = require(process.argv[2]); +const config = require(runfiles.resolveWorkspaceRelative(process.argv[2])); // set env vars passed from --define for (const k of Object.keys(config.envVars)) { diff --git a/tools/saucelabs/BUILD.bazel b/tools/saucelabs/BUILD.bazel index da7dd957b569d..d4f09c286820f 100644 --- a/tools/saucelabs/BUILD.bazel +++ b/tools/saucelabs/BUILD.bazel @@ -60,5 +60,5 @@ nodejs_binary( "@npm//shelljs", ], entry_point = "karma-saucelabs.js", - templated_args = ["$(location sauce-service.sh)"], + templated_args = ["$(rootpath sauce-service.sh)"], ) diff --git a/tools/symbol-extractor/cli.ts b/tools/symbol-extractor/cli.ts index bbecd3756d422..595f653664344 100644 --- a/tools/symbol-extractor/cli.ts +++ b/tools/symbol-extractor/cli.ts @@ -9,6 +9,8 @@ import * as fs from 'fs'; import {SymbolExtractor} from './symbol_extractor'; +const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER'] as string); + if (require.main === module) { const args = process.argv.slice(2) as[string, string]; process.exitCode = main(args) ? 0 : 1; @@ -22,8 +24,8 @@ if (require.main === module) { * ``` */ function main(argv: [string, string, string] | [string, string]): boolean { - const javascriptFilePath = require.resolve(argv[0]); - const goldenFilePath = require.resolve(argv[1]); + const javascriptFilePath = runfiles.resolveWorkspaceRelative(argv[0]); + const goldenFilePath = runfiles.resolveWorkspaceRelative(argv[1]); const doUpdate = argv[2] == '--accept'; const javascriptContent = fs.readFileSync(javascriptFilePath).toString(); diff --git a/tools/symbol-extractor/index.bzl b/tools/symbol-extractor/index.bzl index f361b3c6f4704..34926a15e834c 100644 --- a/tools/symbol-extractor/index.bzl +++ b/tools/symbol-extractor/index.bzl @@ -24,7 +24,7 @@ def js_expected_symbol_test(name, src, golden, data = [], **kwargs): name = name, data = all_data, entry_point = entry_point, - templated_args = ["$(location %s)" % src, "$(location %s)" % golden], + templated_args = ["$(rootpath %s)" % src, "$(rootpath %s)" % golden], configuration_env_vars = ["angular_ivy_enabled"], **kwargs ) @@ -35,6 +35,6 @@ def js_expected_symbol_test(name, src, golden, data = [], **kwargs): data = all_data, entry_point = entry_point, configuration_env_vars = ["angular_ivy_enabled"], - templated_args = ["$(location %s)" % src, "$(location %s)" % golden, "--accept"], + templated_args = ["$(rootpath %s)" % src, "$(rootpath %s)" % golden, "--accept"], **kwargs ) From 08348fc2e8b48d58a30063b0b5b03d21158a315b Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Tue, 31 Mar 2020 06:24:30 -0400 Subject: [PATCH 063/262] build(docs-infra): rename duplicate test name (#36348) When running `docs-test` for the docs generation, a warning is printed for a duplicate test. This commit fixes this issue. PR Close #36348 --- .../cli-docs-package/processors/processCliCommands.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js b/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js index 7cb300c3987da..97413d647e1e3 100644 --- a/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js +++ b/aio/tools/transforms/cli-docs-package/processors/processCliCommands.spec.js @@ -302,7 +302,7 @@ describe('processCliCommands processor', () => { navigation)); }); - it('should collect potential search terms from options for indexing', () => { + it('should collect potential search terms from options and its subcommands for indexing', () => { const doc = { docType: 'cli-command', name: 'name', From ec8bae1b2772b68416e1469ff680caaf433aac28 Mon Sep 17 00:00:00 2001 From: Stephen Fluin <stephen.fluin@gmail.com> Date: Mon, 30 Mar 2020 19:59:11 -0700 Subject: [PATCH 064/262] docs: update end date of survey to middle of April (#36339) PR Close #36339 --- aio/src/app/app.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/src/app/app.component.html b/aio/src/app/app.component.html index b1bb759cf61d3..5e8a2d8d000d8 100644 --- a/aio/src/app/app.component.html +++ b/aio/src/app/app.component.html @@ -6,7 +6,7 @@ <mat-toolbar color="primary" class="app-toolbar no-print" [class.transitioning]="isTransitioning"> <mat-toolbar-row class="notification-container"> - <aio-notification notificationId="survey-march-2020" expirationDate="2020-04-01" [dismissOnContentClick]="true" (dismissed)="notificationDismissed()"> + <aio-notification notificationId="survey-march-2020" expirationDate="2020-04-15" [dismissOnContentClick]="true" (dismissed)="notificationDismissed()"> <a href="https://goo.gle/angular-survey-2020"> <mat-icon class="icon" svgIcon="insert_comment" aria-label="Announcement"></mat-icon> <span class="message">Help Angular by taking a <b>1 minute survey</b>!</span> From 4d1d0fa03bf15e34681109ca1d64fd05f09c0336 Mon Sep 17 00:00:00 2001 From: Kara Erickson <karakara@google.com> Date: Wed, 1 Apr 2020 12:31:56 -0700 Subject: [PATCH 065/262] docs: update ng-conf announcement to remove livestream link (#36382) Since the livestream for ng-conf is not public this year, (and is only available to ng-conf attendees), we are removing the link from the angular.io homepage. Instead, we are now pointing to the ng-conf homepage for more information. PR Close #36382 --- aio/content/marketing/announcements.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aio/content/marketing/announcements.json b/aio/content/marketing/announcements.json index 4bbd2cbbc18b6..78e961a32e666 100644 --- a/aio/content/marketing/announcements.json +++ b/aio/content/marketing/announcements.json @@ -9,9 +9,9 @@ { "startDate": "2020-04-01", "endDate": "2020-04-03", - "message": "Watch ng-conf live stream <br/>April 1st-3rd, 2020", + "message": "ng-conf: Hardwired is happening! <br/>April 1st-3rd, 2020", "imageUrl": "generated/images/marketing/home/ng-conf.png", - "linkUrl": "https://www.ng-conf.org/livestream/?utm_source=angular.io&utm_medium=referral" + "linkUrl": "https://www.ng-conf.org" }, { "startDate": "2019-05-03", From 702e17cfe2d3f8c08780760cdce2f2fb4e5bc18a Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 11 Mar 2020 09:15:44 -0700 Subject: [PATCH 066/262] docs: change page title and minor edit (#36021) PR Close #36021 --- aio/content/guide/bootstrapping.md | 12 ++++++------ aio/content/navigation.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aio/content/guide/bootstrapping.md b/aio/content/guide/bootstrapping.md index f6a8b19d5a569..2b5dd9d4dbae3 100644 --- a/aio/content/guide/bootstrapping.md +++ b/aio/content/guide/bootstrapping.md @@ -1,4 +1,4 @@ -# Bootstrapping +# Launching your app with a root module #### Prerequisites @@ -7,12 +7,12 @@ A basic understanding of the following: <hr /> -An `NgModule` describes how the application parts fit together. -Every application has at least one Angular module, the _root_ module -that you bootstrap to launch the application. -By convention, it is usually called `AppModule`. +An NgModule describes how the application parts fit together. +Every application has at least one Angular module, the _root_ module, +which must be present for bootstrapping the application on launch. +By convention and by default, this NgModule is named `AppModule`. -If you use the [Angular CLI](cli) to generate an app, the default `AppModule` is as follows: +When you use the [Angular CLI](cli) command `ng new` to generate an app, the default `AppModule` is as follows. ```typescript /* JavaScript imports */ diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 7efa978a67335..49b240d645c86 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -313,7 +313,7 @@ }, { "url": "guide/bootstrapping", - "title": "App Root NgModule", + "title": "Launching Apps with a Root Module", "tooltip": "Tell Angular how to construct and bootstrap the app in the root \"AppModule\"." }, { From e1ac2efe4a42e0ebd59b55fe93b23cf8e14e341b Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 11 Mar 2020 10:05:35 -0700 Subject: [PATCH 067/262] docs: make page titles and toc task-oriented (#36024) PR Close #36024 --- aio/content/guide/architecture-components.md | 2 +- aio/content/guide/http.md | 2 +- aio/content/guide/providers.md | 2 +- aio/content/guide/router.md | 6 +++--- aio/content/guide/schematics.md | 2 +- aio/content/navigation.json | 10 +++++----- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/aio/content/guide/architecture-components.md b/aio/content/guide/architecture-components.md index bbffd9ae34d59..d1377ff9f345e 100644 --- a/aio/content/guide/architecture-components.md +++ b/aio/content/guide/architecture-components.md @@ -1,4 +1,4 @@ -# Introduction to components +# Introduction to components and templates A *component* controls a patch of screen called a *view*. For example, individual components define and control each of the following views from the [Tutorial](tutorial): diff --git a/aio/content/guide/http.md b/aio/content/guide/http.md index 1949597c0d842..ddebe2969ea69 100644 --- a/aio/content/guide/http.md +++ b/aio/content/guide/http.md @@ -1,4 +1,4 @@ -# HttpClient +# Communicating with backend services using HTTP Most front-end applications communicate with backend services over the HTTP protocol. Modern browsers support two different APIs for making HTTP requests: the `XMLHttpRequest` interface and the `fetch()` API. diff --git a/aio/content/guide/providers.md b/aio/content/guide/providers.md index f7a6090c83487..7dfb695e81e87 100644 --- a/aio/content/guide/providers.md +++ b/aio/content/guide/providers.md @@ -1,4 +1,4 @@ -# Providers +# Providing dependencies in modules A provider is an instruction to the [Dependency Injection](/guide/dependency-injection) system on how to obtain a value for a dependency. Most of the time, these dependencies are services that you create and provide. diff --git a/aio/content/guide/router.md b/aio/content/guide/router.md index 15711db70255b..f8bbda36b24f6 100644 --- a/aio/content/guide/router.md +++ b/aio/content/guide/router.md @@ -1,6 +1,6 @@ -# Routing and navigation +# In-app navigation with routing -The Angular **`Router`** enables navigation from one [view](guide/glossary#view) to the next +The Angular **`Router`** enables navigation from one [view](guide/glossary#view "View definition") to the next as users perform application tasks. This guide covers the router's primary features, illustrating them through the evolution @@ -3306,7 +3306,7 @@ The `redirectUrl` property stores the URL that the user wanted to access so you <div class="alert is-helpful"> -To keep things simple, this example redirects unauthenticated users to `/admin`. +To keep things simple, this example redirects unauthenticated users to `/admin`. </div> diff --git a/aio/content/guide/schematics.md b/aio/content/guide/schematics.md index b76e0710e356f..d85d83dbc97e2 100644 --- a/aio/content/guide/schematics.md +++ b/aio/content/guide/schematics.md @@ -1,4 +1,4 @@ -# Schematics +# Generating code using schematics A schematic is a template-based code generator that supports complex logic. It is a set of instructions for transforming a software project by generating or modifying code. diff --git a/aio/content/navigation.json b/aio/content/navigation.json index 49b240d645c86..d2b4a3e5a2956 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -338,8 +338,8 @@ }, { "url": "guide/providers", - "title": "Providers", - "tooltip": "Providers and NgModules." + "title": "Providing Dependencies", + "tooltip": "Providing dependencies to NgModules." }, { "url": "guide/singleton-services", @@ -401,7 +401,7 @@ }, { "url": "guide/http", - "title": "HttpClient", + "title": "Access Servers over HTTP", "tooltip": "Use HTTP to talk to a remote server." }, { @@ -557,12 +557,12 @@ }, { "title": "Schematics", - "tooltip": "Understanding schematics.", + "tooltip": "Using CLI schematics for code generation.", "children": [ { "url": "guide/schematics", "title": "Schematics Overview", - "tooltip": "Understand how schematics are used in Angular." + "tooltip": "How the CLI uses schematics to generate code." }, { "url": "guide/schematics-authoring", From 51a89c32c4b10b69a409a5665198aa870b3adcd8 Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 11 Mar 2020 10:14:10 -0700 Subject: [PATCH 068/262] docs: update and edit web-worker page (#36026) PR Close #36026 --- aio/content/guide/web-worker.md | 39 ++++++++++++++++++++++----------- aio/content/navigation.json | 4 ++-- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/aio/content/guide/web-worker.md b/aio/content/guide/web-worker.md index 2bec5b635c580..c05bae8093a73 100644 --- a/aio/content/guide/web-worker.md +++ b/aio/content/guide/web-worker.md @@ -1,17 +1,31 @@ -# Using web workers with Angular CLI +# Background processing using web workers -[Web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) allow you to run CPU intensive computations in a background thread, freeing the main thread to update the user interface. +[Web workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) allow you to run CPU-intensive computations in a background thread, +freeing the main thread to update the user interface. +If you find your application performs a lot of computations, such as generating CAD drawings or doing heavy geometrical calculations, using web workers can help increase your application's performance. -If you find your application becomes unresponsive while processing data, using web workers can help. +<div class="alert is-helpful> + +The CLI does not support running Angular itself in a web worker. + +</div> ## Adding a web worker -You can add a web worker anywhere in your application. If the file that contains your expensive computation is `src/app/app.component.ts`, you can add a web worker using `ng generate web-worker app`. +To add a web worker to an existing project, use the Angular CLI `ng generate` command. + +`ng generate web-worker` *location* + +You can add a web worker anywhere in your application. +For example, to add a web worker to the root component, `src/app/app.component.ts`, run the following command. + + `ng generate web-worker app`. + -Running this command will: +The command performs the following actions. -- configure your project to use web workers, if it isn't already. -- add `src/app/app.worker.ts` with scaffolded code to receive messages: +- Configures your project to use web workers, if it isn't already. +- Adds the following scaffold code to `src/app/app.worker.ts` to receive messages. <code-example language="typescript" header="src/app/app.worker.ts"> addEventListener('message', ({ data }) => { @@ -20,7 +34,7 @@ Running this command will: }); </code-example> -- add scaffolded code to `src/app/app.component.ts` to use the worker: +- Adds the following scaffold code to `src/app/app.component.ts` to use the worker. <code-example language="typescript" header="src/app/app.component.ts"> if (typeof Worker !== 'undefined') { @@ -36,11 +50,10 @@ Running this command will: } </code-example> -After the initial scaffolding, you will need to refactor your code to use the web worker by sending messages to and from. +After you generate this initial scaffold, you must refactor your code to use the web worker by sending messages to and from the worker. -## Caveats +<div class="alert is-important> -There are two important things to keep in mind when using web workers in Angular projects: +Some environments or platforms, such as `@angular/platform-server` used in [Server-side Rendering](guide/universal), don't support web workers. To ensure that your application will work in these environments, you must provide a fallback mechanism to perform the computations that the worker would otherwise perform. -- Some environments or platforms, like `@angular/platform-server` used in [Server-side Rendering](guide/universal), don't support web workers. You have to provide a fallback mechanism to perform the computations that the worker would perform to ensure your application will work in these environments. -- Running Angular itself in a web worker via [**@angular/platform-webworker**](api/platform-webworker) is not yet supported in Angular CLI. +</div> diff --git a/aio/content/navigation.json b/aio/content/navigation.json index d2b4a3e5a2956..6f50a13020a7e 100644 --- a/aio/content/navigation.json +++ b/aio/content/navigation.json @@ -583,8 +583,8 @@ }, { "url": "guide/web-worker", - "title": "Web Workers", - "tooltip": "Using Web Workers with Angular CLI." + "title": "Web Workers in Angular", + "tooltip": "Implement background processing with web workers." } ] }, From c5c57f673745e9b66a771c49e778a7d2e8d8c56a Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 23 Mar 2020 08:53:42 -0700 Subject: [PATCH 069/262] build: update to clang 1.4.0 and only run clang format on changed files (#36203) Update to clang@1.4.0 to gain support for optional changing and nullish coalescing. Because this would trigger a change on >1800 files in the repository, also changes our format enforcement to only be run against changed files. This will allow us to incramentally roll out the value add of the upgraded clang format. PR Close #36203 --- .circleci/config.yml | 2 +- .circleci/env.sh | 2 ++ gulpfile.js | 20 +++++++++++------- package.json | 4 ++-- tools/gulp-tasks/format.js | 30 +++++++++++++++++++++++++- yarn.lock | 43 +++++++++++++------------------------- 6 files changed, 60 insertions(+), 41 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6f61ffbc6f39c..b6b5065b7152b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -278,7 +278,7 @@ jobs: - run: 'yarn bazel:lint || (echo -e "\n.bzl files have lint errors. Please run ''yarn bazel:lint-fix''"; exit 1)' - - run: yarn lint + - run: yarn lint --branch $CI_GIT_BASE_REVISION - run: yarn ts-circular-deps:check - run: yarn -s ng-dev pullapprove:verify diff --git a/.circleci/env.sh b/.circleci/env.sh index 84affc8b57b06..7c65f56ddfca4 100755 --- a/.circleci/env.sh +++ b/.circleci/env.sh @@ -30,6 +30,8 @@ else setPublicVar CI_COMMIT "$CIRCLE_SHA1"; # `CI_COMMIT_RANGE` is only used on push builds (a.k.a. non-PR, non-scheduled builds and rerun # workflows of such builds). + setPublicVar CI_GIT_BASE_REVISION "${CIRCLE_GIT_BASE_REVISION}"; + setPublicVar CI_GIT_REVISION "${CIRCLE_GIT_REVISION}"; setPublicVar CI_COMMIT_RANGE "$CIRCLE_GIT_BASE_REVISION..$CIRCLE_GIT_REVISION"; setPublicVar CI_PULL_REQUEST "${CIRCLE_PR_NUMBER:-false}"; setPublicVar CI_REPO_NAME "$CIRCLE_PROJECT_REPONAME"; diff --git a/gulpfile.js b/gulpfile.js index 49157e466e6e6..35852b3103169 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -26,26 +26,30 @@ function loadTask(fileName, taskName) { return task(gulp); } -// Check source code for formatting errors in all source files. -gulp.task('format:enforce', loadTask('format', 'enforce')); +//####################################################### +// A format and enforce task for different sets of files. +//####################################################### -// Format all source files. +// All source files. gulp.task('format:all', loadTask('format', 'format')); +gulp.task('format:all:enforce', loadTask('format', 'enforce')); -// Format only untracked source code files. +// Untracked source code files. gulp.task('format:untracked', loadTask('format', 'format-untracked')); +gulp.task('format:untracked:enforce', loadTask('format', 'enforce-untracked')); -// Format only the changed, tracked source code files. +// Changed, tracked source code files. gulp.task('format:diff', loadTask('format', 'format-diff')); +gulp.task('format:diff:enforce', loadTask('format', 'enforce-diff')); -// Format only changed lines based on the diff from the provided --branch -// argument (or `master` by default). +// Changed, both tracked and untracked, source code files. gulp.task('format:changed', ['format:untracked', 'format:diff']); +gulp.task('format:changed:enforce', ['format:untracked:enforce', 'format:diff:enforce']); // Alias for `format:changed` that formerly formatted all files. gulp.task('format', ['format:changed']); -gulp.task('lint', ['format:enforce', 'validate-commit-messages']); +gulp.task('lint', ['format:changed:enforce', 'validate-commit-messages']); gulp.task('validate-commit-messages', loadTask('validate-commit-message')); gulp.task('source-map-test', loadTask('source-map-test')); gulp.task('changelog', loadTask('changelog')); diff --git a/package.json b/package.json index 52317d0147c06..d485e098e534a 100644 --- a/package.json +++ b/package.json @@ -157,7 +157,7 @@ "@yarnpkg/lockfile": "^1.1.0", "browserstacktunnel-wrapper": "2.0.1", "check-side-effects": "0.0.21", - "clang-format": "1.0.41", + "clang-format": "^1.4.0", "cldr": "4.10.0", "cldr-data": "36.0.0", "cldrjs": "0.5.0", @@ -167,7 +167,7 @@ "firefox-profile": "1.0.3", "glob": "7.1.2", "gulp": "3.9.1", - "gulp-clang-format": "1.0.23", + "gulp-clang-format": "^1.0.27", "gulp-conventional-changelog": "^2.0.3", "gulp-filter": "^5.1.0", "gulp-git": "^2.7.0", diff --git a/tools/gulp-tasks/format.js b/tools/gulp-tasks/format.js index 90db154597d57..a9d168f535db0 100644 --- a/tools/gulp-tasks/format.js +++ b/tools/gulp-tasks/format.js @@ -85,7 +85,7 @@ function gulpStatus() { } module.exports = { - // Check source code for formatting errors (clang-format) + // Check source code for formatting errors with clang-format enforce: (gulp) => () => { const format = require('gulp-clang-format'); const clangFormat = require('clang-format'); @@ -93,6 +93,34 @@ module.exports = { format.checkFormat('file', clangFormat, {verbose: true, fail: true})); }, + // Check only the untracked source code files for formatting errors with .clang-format + 'enforce-untracked': (gulp) => () => { + const format = require('gulp-clang-format'); + const clangFormat = require('clang-format'); + const gulpFilter = require('gulp-filter'); + + return gulpStatus() + .pipe(gulpFilter(srcsToFmt)) + .pipe(format.checkFormat('file', clangFormat, {verbose: true, fail: true})); + }, + + // Check only the changed source code files diffed from the provided branch for formatting + // errors with clang-format + 'enforce-diff': (gulp) => () => { + const format = require('gulp-clang-format'); + const clangFormat = require('clang-format'); + const gulpFilter = require('gulp-filter'); + const minimist = require('minimist'); + const gulpGit = require('gulp-git'); + + const args = minimist(process.argv.slice(2)); + const branch = args.branch || 'master'; + + return gulpGit.diff(branch, {log: false}) + .pipe(gulpFilter(srcsToFmt)) + .pipe(format.checkFormat('file', clangFormat, {verbose: true, fail: true})); + }, + // Format the source code with clang-format (see .clang-format) format: (gulp) => () => { const format = require('gulp-clang-format'); diff --git a/yarn.lock b/yarn.lock index 55922087c0007..d7300351b8352 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3570,19 +3570,10 @@ cjson@^0.3.1: dependencies: json-parse-helpfulerror "^1.0.3" -clang-format@1.0.41: - version "1.0.41" - resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.0.41.tgz#28552e50b0c9e44d23f85aebe3d2fbd06c93620c" - integrity sha1-KFUuULDJ5E0j+Frr49L70GyTYgw= - dependencies: - async "^1.5.2" - glob "^7.0.0" - resolve "^1.1.6" - -clang-format@^1.0.32: - version "1.2.3" - resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.2.3.tgz#2763561aa7449c43737480f8df3a2b5b66e6cf37" - integrity sha512-x90Hac4ERacGDcZSvHKK58Ga0STuMD+Doi5g0iG2zf7wlJef5Huvhs/3BvMRFxwRYyYSdl6mpQNrtfMxE8MQzw== +clang-format@^1.0.32, clang-format@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/clang-format/-/clang-format-1.4.0.tgz#1ee2f10637eb5bb0bd7d0b82c949af68e848367e" + integrity sha512-NrdyUnHJOGvMa60vbWk7GJTvOdhibj3uK5C0FlwdNG4301OUvqEJTFce9I9x8qw2odBbIVrJ+9xbsFS3a4FbDA== dependencies: async "^1.5.2" glob "^7.0.0" @@ -7020,18 +7011,17 @@ gtoken@^4.1.0: jws "^4.0.0" mime "^2.2.0" -gulp-clang-format@1.0.23: - version "1.0.23" - resolved "https://registry.yarnpkg.com/gulp-clang-format/-/gulp-clang-format-1.0.23.tgz#fe258586b83998491e632fc0c4fc0ecdfa10c89f" - integrity sha1-/iWFhrg5mEkeYy/AxPwOzfoQyJ8= +gulp-clang-format@^1.0.27: + version "1.0.27" + resolved "https://registry.yarnpkg.com/gulp-clang-format/-/gulp-clang-format-1.0.27.tgz#c89716c26745703356c4ff3f2b0964393c73969e" + integrity sha512-Jj4PGuNXKdqVCh9fijvL7wdzma5TQRJz1vv8FjOjnSkfq3s/mvbdE/jq+5HG1c/q+jcYkXTEGkYT3CrdnJOLaQ== dependencies: clang-format "^1.0.32" + fancy-log "^1.3.2" gulp-diff "^1.0.0" - gulp-util "^3.0.4" - pkginfo "^0.3.0" + plugin-error "^1.0.1" stream-combiner2 "^1.1.1" - stream-equal "0.1.6" - through2 "^0.6.3" + through2 "^2.0.3" gulp-conventional-changelog@^2.0.3: version "2.0.3" @@ -7089,7 +7079,7 @@ gulp-tslint@8.1.2: map-stream "~0.0.7" through "~2.3.8" -gulp-util@^3.0.0, gulp-util@^3.0.4, gulp-util@^3.0.6, gulp-util@~3.0.8: +gulp-util@^3.0.0, gulp-util@^3.0.6, gulp-util@~3.0.8: version "3.0.8" resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= @@ -11459,7 +11449,7 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pkginfo@0.3.x, pkginfo@^0.3.0: +pkginfo@0.3.x: version "0.3.1" resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= @@ -13853,11 +13843,6 @@ stream-each@^1.1.0: end-of-stream "^1.1.0" stream-shift "^1.0.0" -stream-equal@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/stream-equal/-/stream-equal-0.1.6.tgz#cc522fab38516012e4d4ee47513b147b72359019" - integrity sha1-zFIvqzhRYBLk1O5HUTsUe3I1kBk= - stream-http@^2.7.2: version "2.8.3" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" @@ -14445,7 +14430,7 @@ through2@2.0.1: readable-stream "~2.0.0" xtend "~4.0.0" -through2@^0.6.1, through2@^0.6.3: +through2@^0.6.1: version "0.6.5" resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg= From 9d8bb634f983f0f150b484401b8803bd73b129f0 Mon Sep 17 00:00:00 2001 From: Wagner Maciel <wagnermaciel@google.com> Date: Mon, 23 Mar 2020 09:34:12 -0700 Subject: [PATCH 070/262] fix(benchpress): update dependencies (#36205) * updated, added, and removed dependencies in package.json * added dependencies to BUILD.bazel PR Close #36205 --- packages/benchpress/BUILD.bazel | 2 ++ packages/benchpress/package.json | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/benchpress/BUILD.bazel b/packages/benchpress/BUILD.bazel index 8ac5a7c81dbb9..7a5e3d727c8ac 100644 --- a/packages/benchpress/BUILD.bazel +++ b/packages/benchpress/BUILD.bazel @@ -14,6 +14,8 @@ ts_library( "//packages:types", "//packages/core", "@npm//@types/node", + "@npm//@types/q", + "@npm//q", "@npm//reflect-metadata", ], ) diff --git a/packages/benchpress/package.json b/packages/benchpress/package.json index 98c522fda30ca..66f304ffa0ea5 100644 --- a/packages/benchpress/package.json +++ b/packages/benchpress/package.json @@ -6,11 +6,12 @@ "typings": "./index.d.ts", "strictNullChecks": true, "dependencies": { - "@angular/core": "^2.0.0-rc.7", + "@angular/core": "^9.0.0", + "@types/node": "^12.11.1", + "@types/q": "^1.5.2", + "protractor": "^5.4.2", + "q": "^1.5.1", "reflect-metadata": "^0.1.2", - "rxjs": "^6.5.3", - "jpm": "1.1.4", - "firefox-profile": "0.4.0", "selenium-webdriver": "^2.53.3" }, "repository": { From 36e927a8c6cb0f3031c610bd41bfbbd2c76ba4cb Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Thu, 26 Mar 2020 21:46:46 +0900 Subject: [PATCH 071/262] fix(zone.js): UNPATCHED_EVENTS and PASSIVE_EVENTS should be string[] not boolean (#36258) __zone_symbol__UNPATCHED_EVENTS and __zone_symbol__PASSIVE_EVENTS should be string[] type not boolean. For example: ``` const config = window as ZoneGlobalConfigurations; config.__zone_symbol__UNPATCHED_EVENTS = ['scroll']; config.__zone_symbol__PASSIVE_EVENTS = ['scroll']; ``` PR Close #36258 --- packages/zone.js/lib/zone.configurations.api.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/zone.js/lib/zone.configurations.api.ts b/packages/zone.js/lib/zone.configurations.api.ts index 88629890eff8a..4691f5d740eab 100644 --- a/packages/zone.js/lib/zone.configurations.api.ts +++ b/packages/zone.js/lib/zone.configurations.api.ts @@ -512,7 +512,7 @@ interface ZoneGlobalConfigurations { * Users can achieve this goal by defining `__zone_symbol__UNPATCHED_EVENTS = ['scroll', * 'mousemove'];` before importing `zone.js`. */ - __zone_symbol__UNPATCHED_EVENTS?: boolean; + __zone_symbol__UNPATCHED_EVENTS?: string[]; /** * Define the event names of the passive listeners. @@ -528,7 +528,7 @@ interface ZoneGlobalConfigurations { * * The preceding code makes all scroll event listeners passive. */ - __zone_symbol__PASSIVE_EVENTS?: boolean; + __zone_symbol__PASSIVE_EVENTS?: string[]; /** * Disable wrapping uncaught promise rejection. From 7e62aa0c6e611c78703a5cd04cebb12e13087577 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Mon, 30 Mar 2020 11:12:54 +0100 Subject: [PATCH 072/262] refactor(ngcc): rename INVALID_ENTRY_POINT to INCOMPATIBLE_ENTRY_POINT (#36305) This name better reflects its meaning. PR Close #36305 --- .../directory_walker_entry_point_finder.ts | 6 +++--- .../targeted_entry_point_finder.ts | 4 ++-- .../ngcc/src/packages/entry_point.ts | 16 +++++++++------- .../ngcc/src/packages/entry_point_manifest.ts | 4 ++-- .../ngcc/test/packages/entry_point_spec.ts | 16 ++++++++-------- .../writing/new_entry_point_file_writer_spec.ts | 8 ++++---- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index 50a67e8100920..a63cadf2707a0 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -9,7 +9,7 @@ import {AbsoluteFsPath, FileSystem, join, resolve} from '../../../src/ngtsc/file import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, INVALID_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point'; +import {EntryPoint, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point'; import {EntryPointManifest} from '../packages/entry_point_manifest'; import {PathMappings} from '../utils'; import {NGCC_DIRECTORY} from '../writing/new_entry_point_file_writer'; @@ -111,7 +111,7 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { return []; } - if (topLevelEntryPoint === INVALID_ENTRY_POINT) { + if (topLevelEntryPoint === INCOMPATIBLE_ENTRY_POINT) { return null; } @@ -126,7 +126,7 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { const possibleEntryPointPath = isDirectory ? path : stripJsExtension(path); const subEntryPoint = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, possibleEntryPointPath); - if (subEntryPoint === NO_ENTRY_POINT || subEntryPoint === INVALID_ENTRY_POINT) { + if (subEntryPoint === NO_ENTRY_POINT || subEntryPoint === INCOMPATIBLE_ENTRY_POINT) { return false; } entryPoints.push(subEntryPoint); diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index 2dcffe8942a91..7014c247cf356 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -10,7 +10,7 @@ import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/depende import {Logger} from '../logging/logger'; import {hasBeenProcessed} from '../packages/build_marker'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, EntryPointJsonProperty, INVALID_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point'; +import {EntryPoint, EntryPointJsonProperty, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point'; import {PathMappings} from '../utils'; import {EntryPointFinder} from './interface'; import {getBasePaths} from './utils'; @@ -94,7 +94,7 @@ export class TargetedEntryPointFinder implements EntryPointFinder { const packagePath = this.computePackagePath(entryPointPath); const entryPoint = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, entryPointPath); - if (entryPoint === NO_ENTRY_POINT || entryPoint === INVALID_ENTRY_POINT) { + if (entryPoint === NO_ENTRY_POINT || entryPoint === INCOMPATIBLE_ENTRY_POINT) { return null; } return entryPoint; diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point.ts b/packages/compiler-cli/ngcc/src/packages/entry_point.ts index ea64e05ed2058..08bcf8e4f1887 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point.ts @@ -86,7 +86,7 @@ export const NO_ENTRY_POINT = 'no-entry-point'; /** * The path has a package.json, but it is not a valid entry-point for ngcc processing. */ -export const INVALID_ENTRY_POINT = 'invalid-entry-point'; +export const INCOMPATIBLE_ENTRY_POINT = 'incompatible-entry-point'; /** * The result of calling `getEntryPointInfo()`. @@ -94,10 +94,11 @@ export const INVALID_ENTRY_POINT = 'invalid-entry-point'; * This will be an `EntryPoint` object if an Angular entry-point was identified; * Otherwise it will be a flag indicating one of: * * NO_ENTRY_POINT - the path is not an entry-point or ngcc is configured to ignore it - * * INVALID_ENTRY_POINT - the path was a non-processable entry-point that should be searched + * * INCOMPATIBLE_ENTRY_POINT - the path was a non-processable entry-point that should be searched * for sub-entry-points */ -export type GetEntryPointResult = EntryPoint | typeof INVALID_ENTRY_POINT | typeof NO_ENTRY_POINT; +export type GetEntryPointResult = + EntryPoint | typeof INCOMPATIBLE_ENTRY_POINT | typeof NO_ENTRY_POINT; /** @@ -107,9 +108,10 @@ export type GetEntryPointResult = EntryPoint | typeof INVALID_ENTRY_POINT | type * @param entryPointPath the absolute path to the potential entry-point. * @returns * - An entry-point if it is valid. - * - `undefined` when there is no package.json at the path and there is no config to force an + * - `NO_ENTRY_POINT` when there is no package.json at the path and there is no config to force an * entry-point or the entrypoint is `ignored`. - * - `null` there is a package.json but it is not a valid Angular compiled entry-point. + * - `INCOMPATIBLE_ENTRY_POINT` there is a package.json but it is not a valid Angular compiled + * entry-point. */ export function getEntryPointInfo( fs: FileSystem, config: NgccConfiguration, logger: Logger, packagePath: AbsoluteFsPath, @@ -138,14 +140,14 @@ export function getEntryPointInfo( if (entryPointPackageJson === null) { // package.json exists but could not be parsed and there was no redeeming config - return INVALID_ENTRY_POINT; + return INCOMPATIBLE_ENTRY_POINT; } const typings = entryPointPackageJson.typings || entryPointPackageJson.types || guessTypingsFromPackageJson(fs, entryPointPath, entryPointPackageJson); if (typeof typings !== 'string') { // Missing the required `typings` property - return INVALID_ENTRY_POINT; + return INCOMPATIBLE_ENTRY_POINT; } // An entry-point is assumed to be compiled by Angular if there is either: diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts index 7cfdf8ca903ff..ab9c3cc6697b3 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts @@ -12,7 +12,7 @@ import {Logger} from '../logging/logger'; import {NGCC_VERSION} from './build_marker'; import {NgccConfiguration} from './configuration'; -import {EntryPoint, INVALID_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from './entry_point'; +import {EntryPoint, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from './entry_point'; /** * Manages reading and writing a manifest file that contains a list of all the entry-points that @@ -71,7 +71,7 @@ export class EntryPointManifest { for (const [packagePath, entryPointPath] of entryPointPaths) { const result = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, entryPointPath); - if (result === NO_ENTRY_POINT || result === INVALID_ENTRY_POINT) { + if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { throw new Error( `The entry-point manifest at ${manifestPath} contained an invalid pair of package paths: [${packagePath}, ${entryPointPath}]`); } else { diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index f3917ff7736b7..9a0e7957b7b98 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -10,7 +10,7 @@ import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../ import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint, INVALID_ENTRY_POINT, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat, getEntryPointInfo} from '../../src/packages/entry_point'; +import {EntryPoint, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat, getEntryPointInfo} from '../../src/packages/entry_point'; import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { @@ -165,7 +165,7 @@ runInEachFileSystem(() => { }); - it('should return `INVALID_ENTRY_POINT` if there is no typings or types field in the package.json', + it('should return `INCOMPATIBLE_ENTRY_POINT` if there is no typings or types field in the package.json', () => { loadTestFiles([ { @@ -182,10 +182,10 @@ runInEachFileSystem(() => { const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, _('/project/node_modules/some_package/missing_typings')); - expect(entryPoint).toBe(INVALID_ENTRY_POINT); + expect(entryPoint).toBe(INCOMPATIBLE_ENTRY_POINT); }); - it('should return `INVALID_ENTRY_POINT` if the typings or types field is not a string in the package.json', + it('should return `INCOMPATIBLE_ENTRY_POINT` if the typings or types field is not a string in the package.json', () => { loadTestFiles([ { @@ -202,7 +202,7 @@ runInEachFileSystem(() => { const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, _('/project/node_modules/some_package/typings_array')); - expect(entryPoint).toBe(INVALID_ENTRY_POINT); + expect(entryPoint).toBe(INCOMPATIBLE_ENTRY_POINT); }); for (let prop of SUPPORTED_FORMAT_PROPERTIES) { @@ -359,7 +359,7 @@ runInEachFileSystem(() => { }); }); - it('should return `INVALID_ENTRY_POINT` if the package.json is not valid JSON', () => { + it('should return `INCOMPATIBLE_ENTRY_POINT` if the package.json is not valid JSON', () => { loadTestFiles([ // package.json might not be a valid JSON // for example, @schematics/angular contains a package.json blueprint @@ -373,7 +373,7 @@ runInEachFileSystem(() => { const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, _('/project/node_modules/some_package/unexpected_symbols')); - expect(entryPoint).toBe(INVALID_ENTRY_POINT); + expect(entryPoint).toBe(INCOMPATIBLE_ENTRY_POINT); }); }); @@ -395,7 +395,7 @@ runInEachFileSystem(() => { const result = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, _('/project/node_modules/some_package/valid_entry_point')); - if (result === NO_ENTRY_POINT || result === INVALID_ENTRY_POINT) { + if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } entryPoint = result; diff --git a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts index f8e1e77d42d0d..a0a01c0911b37 100644 --- a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts @@ -9,7 +9,7 @@ import {FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_s import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, INVALID_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../../src/packages/entry_point'; +import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../../src/packages/entry_point'; import {EntryPointBundle, makeEntryPointBundle} from '../../src/packages/entry_point_bundle'; import {FileWriter} from '../../src/writing/file_writer'; import {NewEntryPointFileWriter} from '../../src/writing/new_entry_point_file_writer'; @@ -108,7 +108,7 @@ runInEachFileSystem(() => { const config = new NgccConfiguration(fs, _('/')); const result = getEntryPointInfo( fs, config, logger, _('/node_modules/test'), _('/node_modules/test')) !; - if (result === NO_ENTRY_POINT || result === INVALID_ENTRY_POINT) { + if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } entryPoint = result; @@ -248,7 +248,7 @@ runInEachFileSystem(() => { const config = new NgccConfiguration(fs, _('/')); const result = getEntryPointInfo( fs, config, logger, _('/node_modules/test'), _('/node_modules/test/a')) !; - if (result === NO_ENTRY_POINT || result === INVALID_ENTRY_POINT) { + if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } entryPoint = result; @@ -377,7 +377,7 @@ runInEachFileSystem(() => { const config = new NgccConfiguration(fs, _('/')); const result = getEntryPointInfo( fs, config, new MockLogger(), _('/node_modules/test'), _('/node_modules/test/b')) !; - if (result === NO_ENTRY_POINT || result === INVALID_ENTRY_POINT) { + if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } entryPoint = result; From 372b9101e26caf463813d688e2a62f463f8846e9 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Sun, 29 Mar 2020 17:13:43 +0100 Subject: [PATCH 073/262] refactor(ngcc): simplify `DirectoryWalkerEntryPointFinder` (#36305) This commit simplifies the `DirectoryWalkerEntryPointFinder` inter-method calling to make it easier to follow, and also to support controlling walking of a directory based on its children. PR Close #36305 --- .../directory_walker_entry_point_finder.ts | 199 +++++++++--------- .../ngcc/src/entry_point_finder/utils.ts | 16 ++ ...irectory_walker_entry_point_finder_spec.ts | 6 +- 3 files changed, 120 insertions(+), 101 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index a63cadf2707a0..4ebecb69aeda2 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, join, resolve} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, FileSystem, PathSegment} from '../../../src/ngtsc/file_system'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; import {NgccConfiguration} from '../packages/configuration'; @@ -14,7 +14,7 @@ import {EntryPointManifest} from '../packages/entry_point_manifest'; import {PathMappings} from '../utils'; import {NGCC_DIRECTORY} from '../writing/new_entry_point_file_writer'; import {EntryPointFinder} from './interface'; -import {getBasePaths} from './utils'; +import {getBasePaths, trackDuration} from './utils'; /** * An EntryPointFinder that searches for all entry-points that can be found given a `basePath` and @@ -33,141 +33,144 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { findEntryPoints(): SortedEntryPointsInfo { const unsortedEntryPoints: EntryPoint[] = []; for (const basePath of this.basePaths) { - let entryPoints = this.entryPointManifest.readEntryPointsUsingManifest(basePath); - if (entryPoints === null) { - this.logger.debug( - `No manifest found for ${basePath} so walking the directories for entry-points.`); - const startTime = Date.now(); - entryPoints = this.walkDirectoryForEntryPoints(basePath); - const duration = Math.round((Date.now() - startTime) / 100) / 10; - this.logger.debug(`Walking directories took ${duration}s.`); - - this.entryPointManifest.writeEntryPointManifest(basePath, entryPoints); - } + const entryPoints = this.entryPointManifest.readEntryPointsUsingManifest(basePath) || + this.walkBasePathForPackages(basePath); unsortedEntryPoints.push(...entryPoints); } return this.resolver.sortEntryPointsByDependency(unsortedEntryPoints); } /** - * Look for entry points that need to be compiled, starting at the source directory. + * Search the `basePath` for possible Angular packages and entry-points. + * + * @param basePath The path at which to start the search + * @returns an array of `EntryPoint`s that were found within `basePath`. + */ + walkBasePathForPackages(basePath: AbsoluteFsPath): EntryPoint[] { + this.logger.debug( + `No manifest found for ${basePath} so walking the directories for entry-points.`); + const entryPoints: EntryPoint[] = trackDuration( + () => this.walkDirectoryForPackages(basePath), + duration => this.logger.debug(`Walking ${basePath} for entry-points took ${duration}s.`)); + this.entryPointManifest.writeEntryPointManifest(basePath, entryPoints); + return entryPoints; + } + + /** + * Look for Angular packages that need to be compiled, starting at the source directory. * The function will recurse into directories that start with `@...`, e.g. `@angular/...`. + * * @param sourceDirectory An absolute path to the root directory where searching begins. + * @returns an array of `EntryPoint`s that were found within `sourceDirectory`. */ - walkDirectoryForEntryPoints(sourceDirectory: AbsoluteFsPath): EntryPoint[] { - const entryPoints = this.getEntryPointsForPackage(sourceDirectory); - if (entryPoints === null) { + walkDirectoryForPackages(sourceDirectory: AbsoluteFsPath): EntryPoint[] { + // Try to get a primary entry point from this directory + const primaryEntryPoint = + getEntryPointInfo(this.fs, this.config, this.logger, sourceDirectory, sourceDirectory); + + // If there is an entry-point but it is not compatible with ngcc (it has a bad package.json or + // invalid typings) then exit. It is unlikely that such an entry point has a dependency on an + // Angular library. + if (primaryEntryPoint === INCOMPATIBLE_ENTRY_POINT) { return []; } - if (entryPoints.length > 0) { - // The `sourceDirectory` is an entry point itself so no need to search its sub-directories. - // Also check for any nested node_modules in this package but only if it was compiled by - // Angular. - // It is unlikely that a non Angular entry point has a dependency on an Angular library. + const entryPoints: EntryPoint[] = []; + if (primaryEntryPoint !== NO_ENTRY_POINT) { + entryPoints.push(primaryEntryPoint); + this.collectSecondaryEntryPoints( + entryPoints, sourceDirectory, sourceDirectory, this.fs.readdir(sourceDirectory)); + + // Also check for any nested node_modules in this package but only if at least one of the + // entry-points was compiled by Angular. if (entryPoints.some(e => e.compiledByAngular)) { const nestedNodeModulesPath = this.fs.join(sourceDirectory, 'node_modules'); if (this.fs.exists(nestedNodeModulesPath)) { - entryPoints.push(...this.walkDirectoryForEntryPoints(nestedNodeModulesPath)); + entryPoints.push(...this.walkDirectoryForPackages(nestedNodeModulesPath)); } } return entryPoints; } - this.fs - .readdir(sourceDirectory) - // Not interested in hidden files - .filter(p => !p.startsWith('.')) - // Ignore node_modules - .filter(p => p !== 'node_modules' && p !== NGCC_DIRECTORY) - // Only interested in directories (and only those that are not symlinks) - .filter(p => { - const stat = this.fs.lstat(resolve(sourceDirectory, p)); - return stat.isDirectory() && !stat.isSymbolicLink(); - }) - .forEach(p => { - // Package is a potential namespace containing packages (e.g `@angular`). - const packagePath = join(sourceDirectory, p); - entryPoints.push(...this.walkDirectoryForEntryPoints(packagePath)); - }); + // The `sourceDirectory` was not a package (i.e. there was no package.json) + // So search its sub-directories for Angular packages and entry-points + for (const path of this.fs.readdir(sourceDirectory)) { + if (isIgnorablePath(path)) { + // Ignore hidden files, node_modules and ngcc directory + continue; + } + + const absolutePath = this.fs.resolve(sourceDirectory, path); + const stat = this.fs.lstat(absolutePath); + if (stat.isSymbolicLink() || !stat.isDirectory()) { + // Ignore symbolic links and non-directories + continue; + } + + entryPoints.push(...this.walkDirectoryForPackages(this.fs.join(sourceDirectory, path))); + } + return entryPoints; } /** - * Recurse the folder structure looking for all the entry points - * @param packagePath The absolute path to an npm package that may contain entry points - * @returns An array of entry points that were discovered or null when it's not a valid entrypoint + * Search the `directory` looking for any secondary entry-points for a package, adding any that + * are found to the `entryPoints` array. + * + * @param entryPoints An array where we will add any entry-points found in this directory + * @param packagePath The absolute path to the package that may contain entry-points + * @param directory The current directory being searched + * @param paths The paths contained in the current `directory`. */ - private getEntryPointsForPackage(packagePath: AbsoluteFsPath): EntryPoint[]|null { - const entryPoints: EntryPoint[] = []; - - // Try to get an entry point from the top level package directory - const topLevelEntryPoint = - getEntryPointInfo(this.fs, this.config, this.logger, packagePath, packagePath); - - // If there is no primary entry-point then exit - if (topLevelEntryPoint === NO_ENTRY_POINT) { - return []; - } + private collectSecondaryEntryPoints( + entryPoints: EntryPoint[], packagePath: AbsoluteFsPath, directory: AbsoluteFsPath, + paths: PathSegment[]): void { + for (const path of paths) { + if (isIgnorablePath(path)) { + // Ignore hidden files, node_modules and ngcc directory + continue; + } - if (topLevelEntryPoint === INCOMPATIBLE_ENTRY_POINT) { - return null; - } + const absolutePath = this.fs.resolve(directory, path); + const stat = this.fs.lstat(absolutePath); + if (stat.isSymbolicLink()) { + // Ignore symbolic links + continue; + } - // Otherwise store it and search for secondary entry-points - entryPoints.push(topLevelEntryPoint); - this.walkDirectory(packagePath, packagePath, (path, isDirectory) => { + const isDirectory = stat.isDirectory(); if (!path.endsWith('.js') && !isDirectory) { - return false; + // Ignore files that do not end in `.js` + continue; } - // If the path is a JS file then strip its extension and see if we can match an entry-point. - const possibleEntryPointPath = isDirectory ? path : stripJsExtension(path); + // If the path is a JS file then strip its extension and see if we can match an + // entry-point. + const possibleEntryPointPath = isDirectory ? absolutePath : stripJsExtension(absolutePath); + let isEntryPoint = false; const subEntryPoint = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, possibleEntryPointPath); - if (subEntryPoint === NO_ENTRY_POINT || subEntryPoint === INCOMPATIBLE_ENTRY_POINT) { - return false; + if (subEntryPoint !== NO_ENTRY_POINT && subEntryPoint !== INCOMPATIBLE_ENTRY_POINT) { + entryPoints.push(subEntryPoint); + isEntryPoint = true; } - entryPoints.push(subEntryPoint); - return true; - }); - return entryPoints; - } + if (!isDirectory || !isEntryPoint) { + // This path is not an entry-point directory so we are done + continue; + } - /** - * Recursively walk a directory and its sub-directories, applying a given - * function to each directory. - * @param dir the directory to recursively walk. - * @param fn the function to apply to each directory. - */ - private walkDirectory( - packagePath: AbsoluteFsPath, dir: AbsoluteFsPath, - fn: (path: AbsoluteFsPath, isDirectory: boolean) => boolean) { - return this.fs - .readdir(dir) - // Not interested in hidden files - .filter(path => !path.startsWith('.')) - // Ignore node_modules - .filter(path => path !== 'node_modules' && path !== NGCC_DIRECTORY) - .forEach(path => { - const absolutePath = resolve(dir, path); - const stat = this.fs.lstat(absolutePath); - - if (stat.isSymbolicLink()) { - // We are not interested in symbolic links - return; - } - - const containsEntryPoint = fn(absolutePath, stat.isDirectory()); - if (containsEntryPoint) { - this.walkDirectory(packagePath, absolutePath, fn); - } - }); + const childPaths = this.fs.readdir(absolutePath); + this.collectSecondaryEntryPoints(entryPoints, packagePath, absolutePath, childPaths); + } } } function stripJsExtension<T extends string>(filePath: T): T { return filePath.replace(/\.js$/, '') as T; } + +function isIgnorablePath(path: PathSegment): boolean { + return path.startsWith('.') || path === 'node_modules' || path === NGCC_DIRECTORY; +} diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts index 2f8329eae47a5..c81e5cc01f65d 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts @@ -78,3 +78,19 @@ function removeContainedPaths(value: AbsoluteFsPath, index: number, array: Absol } return true; } + +/** + * Run a task and track how long it takes. + * + * @param task The task whose duration we are tracking + * @param log The function to call with the duration of the task + * @returns The result of calling `task`. + */ +export function trackDuration<T = void>( + task: () => T extends Promise<unknown>? never : T, log: (duration: number) => void): T { + const startTime = Date.now(); + const result = task(); + const duration = Math.round((Date.now() - startTime) / 100) / 10; + log(duration); + return result; +} diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts index 386da54f37e80..bfd297dfddfa9 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts @@ -230,7 +230,7 @@ runInEachFileSystem(() => { const finder = new DirectoryWalkerEntryPointFinder( fs, config, logger, resolver, manifest, _Abs('/nested_node_modules/node_modules'), undefined); - const spy = spyOn(finder, 'walkDirectoryForEntryPoints').and.callThrough(); + const spy = spyOn(finder, 'walkDirectoryForPackages').and.callThrough(); const {entryPoints} = finder.findEntryPoints(); expect(spy.calls.allArgs()).toEqual([ [_Abs(basePath)], @@ -252,7 +252,7 @@ runInEachFileSystem(() => { const finder = new DirectoryWalkerEntryPointFinder( fs, config, logger, resolver, manifest, basePath, undefined); - const spy = spyOn(finder, 'walkDirectoryForEntryPoints').and.callThrough(); + const spy = spyOn(finder, 'walkDirectoryForPackages').and.callThrough(); const {entryPoints} = finder.findEntryPoints(); expect(spy.calls.allArgs()).toEqual([ [_Abs(basePath)], @@ -276,7 +276,7 @@ runInEachFileSystem(() => { const finder = new DirectoryWalkerEntryPointFinder( fs, config, logger, resolver, manifest, basePath, undefined); - const spy = spyOn(finder, 'walkDirectoryForEntryPoints').and.callThrough(); + const spy = spyOn(finder, 'walkDirectoryForPackages').and.callThrough(); const {entryPoints} = finder.findEntryPoints(); expect(spy.calls.allArgs()).toEqual([ [_Abs(basePath)], From 38ad1d97abef2db0a99079cdd4d2391d96009597 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Mon, 30 Mar 2020 11:40:00 +0100 Subject: [PATCH 074/262] fix(ngcc): handle entry-points within container folders (#36305) The previous optimizations in #35756 to the `DirectoryWalkerEntryPointFinder` were over zealous with regard to packages that have entry-points stored in "container" directories in the package, where the container directory was not an entry-point itself. Now we will also walk such "container" folders as long as they do not contain `.js` files, which we regard as an indicator that the directory will not contain entry-points. Fixes #36216 PR Close #36305 --- .../directory_walker_entry_point_finder.ts | 13 +++++++++++-- .../directory_walker_entry_point_finder_spec.ts | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index 4ebecb69aeda2..f2b00325ae82c 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -156,12 +156,21 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { isEntryPoint = true; } - if (!isDirectory || !isEntryPoint) { - // This path is not an entry-point directory so we are done + if (!isDirectory) { + // This path is not a directory so we are done. continue; } + // This directory may contain entry-points of its own. const childPaths = this.fs.readdir(absolutePath); + if (!isEntryPoint && + childPaths.some( + childPath => childPath.endsWith('.js') && + this.fs.stat(this.fs.resolve(absolutePath, childPath)).isFile())) { + // We do not consider non-entry-point directories that contain JS files as they are very + // unlikely to be containers for sub-entry-points. + continue; + } this.collectSecondaryEntryPoints(entryPoints, packagePath, absolutePath, childPaths); } } diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts index bfd297dfddfa9..e10784bec74b7 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts @@ -287,6 +287,22 @@ runInEachFileSystem(() => { expect(entryPoints).toEqual([]); }); + it('should process sub-entry-points within a non-entry-point containing folder in a package', + () => { + const basePath = _Abs('/containing_folders/node_modules'); + loadTestFiles([ + ...createPackage(basePath, 'package'), + ...createPackage(fs.resolve(basePath, 'package/container'), 'entry-point-1'), + ]); + const finder = new DirectoryWalkerEntryPointFinder( + fs, config, logger, resolver, manifest, basePath, undefined); + const {entryPoints} = finder.findEntryPoints(); + expect(dumpEntryPointPaths(basePath, entryPoints)).toEqual([ + ['package', 'package'], + ['package', 'package/container/entry-point-1'], + ]); + }); + it('should handle dependencies via pathMappings', () => { const basePath = _Abs('/path_mapped/node_modules'); const pathMappings: PathMappings = { From fe2b6923baee06f7348005ce76c4640b776ec0da Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz <ayazhafiz@lyft.com> Date: Mon, 30 Mar 2020 00:10:34 -0700 Subject: [PATCH 075/262] fix(language-service): infer type of elements of array-like objects (#36312) Currently the language service only provides support for determining the type of array-like members when the array-like object is an `Array`. However, there are other kinds of array-like objects, including `ReadonlyArray`s and `readonly`-property arrays. This commit adds support for retrieving the element type of arbitrary array-like objects. Closes #36191 PR Close #36312 --- .../src/typescript_symbols.ts | 10 ++-- packages/language-service/test/hover_spec.ts | 50 +++++++++++++++---- .../test/project/app/parsing-cases.ts | 2 + 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/packages/language-service/src/typescript_symbols.ts b/packages/language-service/src/typescript_symbols.ts index 69812f295fc1f..f018a092c6b3b 100644 --- a/packages/language-service/src/typescript_symbols.ts +++ b/packages/language-service/src/typescript_symbols.ts @@ -127,10 +127,12 @@ class TypeScriptSymbolQuery implements SymbolQuery { getElementType(type: Symbol): Symbol|undefined { if (type instanceof TypeWrapper) { - const tSymbol = type.tsType.symbol; - const tArgs = type.typeArguments(); - if (!tSymbol || tSymbol.name !== 'Array' || !tArgs || tArgs.length != 1) return; - return tArgs[0]; + const ty = type.tsType; + const tyArgs = type.typeArguments(); + // TODO(ayazhafiz): Track https://github.com/microsoft/TypeScript/issues/37711 to expose + // `isArrayLikeType` as a public method. + if (!(this.checker as any).isArrayLikeType(ty) || tyArgs?.length !== 1) return; + return tyArgs[0]; } } diff --git a/packages/language-service/test/hover_spec.ts b/packages/language-service/test/hover_spec.ts index dc3bb7098b4fa..9a22801c065cf 100644 --- a/packages/language-service/test/hover_spec.ts +++ b/packages/language-service/test/hover_spec.ts @@ -96,15 +96,47 @@ describe('hover', () => { expect(documentation).toBe('This is the title of the `TemplateReference` Component.'); }); - it('should work for property reads', () => { - mockHost.override(TEST_TEMPLATE, `<div>{{«title»}}</div>`); - const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); - const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); - expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; - expect(textSpan).toEqual(marker); - expect(textSpan.length).toBe('title'.length); - expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); + describe('property reads', () => { + it('should work for class members', () => { + mockHost.override(TEST_TEMPLATE, `<div>{{«title»}}</div>`); + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); + }); + + it('should work for array members', () => { + mockHost.override(TEST_TEMPLATE, `<div *ngFor="let hero of heroes">{{«hero»}}</div>`); + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(variable) hero: Hero'); + }); + + it('should work for ReadonlyArray members (#36191)', () => { + mockHost.override( + TEST_TEMPLATE, `<div *ngFor="let hero of readonlyHeroes">{{«hero»}}</div>`); + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(variable) hero: Readonly<Hero>'); + }); + + it('should work for const array members (#36191)', () => { + mockHost.override(TEST_TEMPLATE, `<div *ngFor="let name of constNames">{{«name»}}</div>`); + const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'name'); + const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); + expect(quickInfo).toBeTruthy(); + const {textSpan, displayParts} = quickInfo !; + expect(textSpan).toEqual(marker); + expect(toText(displayParts)).toBe('(variable) name: { readonly name: "name"; }'); + }); }); it('should work for method calls', () => { diff --git a/packages/language-service/test/project/app/parsing-cases.ts b/packages/language-service/test/project/app/parsing-cases.ts index 1d5c01c70e5f0..3239e008cf836 100644 --- a/packages/language-service/test/project/app/parsing-cases.ts +++ b/packages/language-service/test/project/app/parsing-cases.ts @@ -174,6 +174,8 @@ export class TemplateReference { index = null; myClick(event: any) {} birthday = new Date(); + readonlyHeroes: ReadonlyArray<Readonly<Hero>> = this.heroes; + constNames = [{name: 'name'}] as const ; } @Component({ From 719224bffdb0c22b2430e09935b8f08af8c91fe0 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 30 Mar 2020 08:44:30 -0700 Subject: [PATCH 076/262] feat(dev-infra): add support for new global approvers in pullapprove (#36324) Pullapprove as added a few new features to allow for us to better execute our expectation for global approvals. We need to allow for an expectation that our global approver groups are not in the list of approved groups. Additionally, since approval groups apply to all files in the repo, the global approval groups also do not have conditions defined for them, which means pullapprove verification need to allow for no conditions need to be defined. PR Close #36324 --- dev-infra/pullapprove/group.ts | 75 +++++++++++++++-------------- dev-infra/pullapprove/parse-yaml.ts | 6 ++- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/dev-infra/pullapprove/group.ts b/dev-infra/pullapprove/group.ts index 247ea4054a03c..4dc34d012ce0f 100644 --- a/dev-infra/pullapprove/group.ts +++ b/dev-infra/pullapprove/group.ts @@ -34,6 +34,7 @@ const CONDITION_TYPES = { INCLUDE_GLOBS: /^contains_any_globs/, EXCLUDE_GLOBS: /^not contains_any_globs/, ATTR_LENGTH: /^len\(.*\)/, + GLOBAL_APPROVAL: /^global-(docs-)?approvers not in groups.approved$/, }; /** A PullApprove group to be able to test files against. */ @@ -48,43 +49,47 @@ export class PullApproveGroup { public hasMatchers = false; constructor(public groupName: string, group: PullApproveGroupConfig) { - for (let condition of group.conditions) { - condition = condition.trim(); + if (group.conditions) { + for (let condition of group.conditions) { + condition = condition.trim(); - if (condition.match(CONDITION_TYPES.INCLUDE_GLOBS)) { - const [conditions, misconfiguredLines] = getLinesForContainsAnyGlobs(condition); - conditions.forEach(globString => this.includeConditions.push({ - glob: globString, - matcher: new Minimatch(globString, {dot: true}), - matchedFiles: new Set<string>(), - })); - this.misconfiguredLines.push(...misconfiguredLines); - this.hasMatchers = true; - } else if (condition.match(CONDITION_TYPES.EXCLUDE_GLOBS)) { - const [conditions, misconfiguredLines] = getLinesForContainsAnyGlobs(condition); - conditions.forEach(globString => this.excludeConditions.push({ - glob: globString, - matcher: new Minimatch(globString, {dot: true}), - matchedFiles: new Set<string>(), - })); - this.misconfiguredLines.push(...misconfiguredLines); - this.hasMatchers = true; - } else if (condition.match(CONDITION_TYPES.ATTR_LENGTH)) { - // Currently a noop as we do not take any action on this condition type. - } else { - const errMessage = - `Unrecognized condition found, unable to parse the following condition: \n\n` + - `From the [${groupName}] group:\n` + - ` - ${condition}` + - `\n\n` + - `Known condition regexs:\n` + - `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - $ { - v + if (condition.match(CONDITION_TYPES.INCLUDE_GLOBS)) { + const [conditions, misconfiguredLines] = getLinesForContainsAnyGlobs(condition); + conditions.forEach(globString => this.includeConditions.push({ + glob: globString, + matcher: new Minimatch(globString, {dot: true}), + matchedFiles: new Set<string>(), + })); + this.misconfiguredLines.push(...misconfiguredLines); + this.hasMatchers = true; + } else if (condition.match(CONDITION_TYPES.EXCLUDE_GLOBS)) { + const [conditions, misconfiguredLines] = getLinesForContainsAnyGlobs(condition); + conditions.forEach(globString => this.excludeConditions.push({ + glob: globString, + matcher: new Minimatch(globString, {dot: true}), + matchedFiles: new Set<string>(), + })); + this.misconfiguredLines.push(...misconfiguredLines); + this.hasMatchers = true; + } else if (condition.match(CONDITION_TYPES.ATTR_LENGTH)) { + // Currently a noop as we do not take any action on this condition type. + } else if (condition.match(CONDITION_TYPES.GLOBAL_APPROVAL)) { + // Currently a noop as we don't take any action for global approval conditions. + } else { + const errMessage = + `Unrecognized condition found, unable to parse the following condition: \n\n` + + `From the [${groupName}] group:\n` + + ` - ${condition}` + + `\n\n` + + `Known condition regexs:\n` + + `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - $ { + v + } + `).join('\n')}` + + `\n\n`; + console.error(errMessage); + process.exit(1); } - `).join('\n')}` + - `\n\n`; - console.error(errMessage); - process.exit(1); } } } diff --git a/dev-infra/pullapprove/parse-yaml.ts b/dev-infra/pullapprove/parse-yaml.ts index a74eb3a0cb907..5b3d89d47e955 100644 --- a/dev-infra/pullapprove/parse-yaml.ts +++ b/dev-infra/pullapprove/parse-yaml.ts @@ -8,9 +8,11 @@ import {parse as parseYaml} from 'yaml'; export interface PullApproveGroupConfig { - conditions: string; + conditions?: string; reviewers: { users: string[], + teams?: string[], + }|{ teams: string[], }; } @@ -30,4 +32,4 @@ export interface PullApproveConfig { export function parsePullApproveYaml(rawYaml: string): PullApproveConfig { return parseYaml(rawYaml) as PullApproveConfig; -} \ No newline at end of file +} From 64631063aece248575dad228d0bd993ddf196918 Mon Sep 17 00:00:00 2001 From: Alexey Okhrimenko <ai_boy@live.ru> Date: Mon, 30 Mar 2020 23:31:37 +0300 Subject: [PATCH 077/262] docs: fix typo in Tests guide (#36330) Fixing typo in testing.md PR Close #36330 --- aio/content/guide/testing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index a6a7945e72998..6d5a2ef7ebf73 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -1242,7 +1242,7 @@ The following test confirms the expected behavior when the service returns an `E Note that the `it()` function receives an argument of the following form. ```javascript -fakeAsync(() => { /* test body */ })` +fakeAsync(() => { /* test body */ }) ``` The `fakeAsync()` function enables a linear coding style by running the test body in a special `fakeAsync test zone`. @@ -3159,7 +3159,7 @@ Here are the most important static methods, in order of likely utility. </td> </tr> -</table +</table> A few of the `TestBed` instance methods are not covered by static `TestBed` _class_ methods. These are rarely needed. From cc4b813e759f16fb0f4dfa92a0e6464ed768a629 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Mon, 30 Mar 2020 21:32:04 +0100 Subject: [PATCH 078/262] fix(ngcc): handle bad path mappings when finding entry-points (#36331) Previously, a bad baseUrl or path mapping passed to an `EntryPointFinder` could cause the original `sourceDirectory` to be superceded by a higher directory. This could result in none of the sourceDirectory entry-points being processed. Now missing basePaths computed from path-mappings are discarded with a warning. Further, if the `baseUrl` is the root directory then a warning is given as this is most likely an error in the tsconfig.json. Resolves #36313 Resolves #36283 PR Close #36331 --- .../directory_walker_entry_point_finder.ts | 2 +- .../targeted_entry_point_finder.ts | 2 +- .../ngcc/src/entry_point_finder/utils.ts | 35 ++++- ...irectory_walker_entry_point_finder_spec.ts | 6 +- .../test/entry_point_finder/utils_spec.ts | 142 ++++++++++++++++++ 5 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index f2b00325ae82c..bf9e6cca9c4f8 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -21,7 +21,7 @@ import {getBasePaths, trackDuration} from './utils'; * `pathMappings`. */ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { - private basePaths = getBasePaths(this.sourceDirectory, this.pathMappings); + private basePaths = getBasePaths(this.logger, this.sourceDirectory, this.pathMappings); constructor( private fs: FileSystem, private config: NgccConfiguration, private logger: Logger, private resolver: DependencyResolver, private entryPointManifest: EntryPointManifest, diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index 7014c247cf356..f21d4cd64cbf7 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -25,7 +25,7 @@ import {getBasePaths} from './utils'; export class TargetedEntryPointFinder implements EntryPointFinder { private unprocessedPaths: AbsoluteFsPath[] = []; private unsortedEntryPoints = new Map<AbsoluteFsPath, EntryPoint>(); - private basePaths = getBasePaths(this.basePath, this.pathMappings); + private basePaths = getBasePaths(this.logger, this.basePath, this.pathMappings); constructor( private fs: FileSystem, private config: NgccConfiguration, private logger: Logger, diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts index c81e5cc01f65d..f2ea90da10241 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts @@ -5,7 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, getFileSystem, join, relative, resolve} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, getFileSystem, relative, resolve} from '../../../src/ngtsc/file_system'; +import {Logger} from '../logging/logger'; import {PathMappings} from '../utils'; /** @@ -28,22 +29,44 @@ import {PathMappings} from '../utils'; * @param pathMappings Path mapping configuration, from which to extract additional base-paths. */ export function getBasePaths( - sourceDirectory: AbsoluteFsPath, pathMappings: PathMappings | undefined): AbsoluteFsPath[] { + logger: Logger, sourceDirectory: AbsoluteFsPath, + pathMappings: PathMappings | undefined): AbsoluteFsPath[] { const fs = getFileSystem(); const basePaths = [sourceDirectory]; if (pathMappings) { const baseUrl = resolve(pathMappings.baseUrl); + if (fs.isRoot(baseUrl)) { + logger.warn( + `The provided pathMappings baseUrl is the root path ${baseUrl}.\n` + + `This is likely to mess up how ngcc finds entry-points and is probably not correct.\n` + + `Please check your path mappings configuration such as in the tsconfig.json file.`); + } Object.values(pathMappings.paths).forEach(paths => paths.forEach(path => { // We only want base paths that exist and are not files - let basePath = join(baseUrl, extractPathPrefix(path)); - while (basePath !== baseUrl && (!fs.exists(basePath) || fs.stat(basePath).isFile())) { + let basePath = fs.resolve(baseUrl, extractPathPrefix(path)); + if (fs.exists(basePath) && fs.stat(basePath).isFile()) { basePath = fs.dirname(basePath); } - basePaths.push(basePath); + if (fs.exists(basePath)) { + basePaths.push(basePath); + } else { + logger.warn( + `The basePath "${basePath}" computed from baseUrl "${baseUrl}" and path mapping "${path}" does not exist in the file-system.\n` + + `It will not be scanned for entry-points.`); + } })); } basePaths.sort().reverse(); // Get the paths in order with the longer ones first. - return basePaths.filter(removeContainedPaths); + const dedupedBasePaths = basePaths.filter(removeContainedPaths); + + // We want to ensure that the `sourceDirectory` is included when it is a node_modules folder. + // Otherwise our entry-point finding algorithm would fail to walk that folder. + if (fs.basename(sourceDirectory) === 'node_modules' && + !dedupedBasePaths.includes(sourceDirectory)) { + dedupedBasePaths.unshift(sourceDirectory); + } + + return dedupedBasePaths; } /** diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts index e10784bec74b7..9d9c873faba53 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts @@ -340,7 +340,7 @@ runInEachFileSystem(() => { const pathMappings: PathMappings = { baseUrl: '/path_mapped/dist', paths: { - '@test': ['pkg2/fesm2015/pkg2.js'], + '@test': ['pkg2/pkg2.d.ts'], '@missing': ['pkg3'], } }; @@ -371,6 +371,10 @@ runInEachFileSystem(() => { fesm2015: `./fesm2015/${packageName}.js`, }) }, + { + name: _Abs(`${basePath}/${packageName}/${packageName}.d.ts`), + contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), + }, { name: _Abs(`${basePath}/${packageName}/fesm2015/${packageName}.js`), contents: deps.map((dep, i) => `import * as i${i} from '${dep}';`).join('\n'), diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts new file mode 100644 index 0000000000000..996370b9da2a1 --- /dev/null +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts @@ -0,0 +1,142 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {absoluteFrom, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; + +import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {getBasePaths} from '../../src/entry_point_finder/utils'; +import {MockLogger} from '../helpers/mock_logger'; + +runInEachFileSystem(() => { + let _: typeof absoluteFrom; + let logger: MockLogger; + + beforeEach(() => { + _ = absoluteFrom; + logger = new MockLogger(); + }); + + describe('getBasePaths', () => { + it('should just return the `sourceDirectory if there are no `pathMappings', () => { + const sourceDirectory = _('/path/to/project/node_modules'); + const basePaths = getBasePaths(logger, sourceDirectory, undefined); + expect(basePaths).toEqual([sourceDirectory]); + }); + + it('should use each path mapping prefix and sort in descending order', () => { + const projectDirectory = _('/path/to/project'); + const fs = getFileSystem(); + fs.ensureDir(fs.resolve(projectDirectory, 'dist-1')); + fs.ensureDir(fs.resolve(projectDirectory, 'sub-folder/dist-2')); + fs.ensureDir(fs.resolve(projectDirectory, 'libs')); + + const sourceDirectory = _('/path/to/project/node_modules'); + const pathMappings = { + baseUrl: projectDirectory, + paths: {'@dist': ['dist-1', 'sub-folder/dist-2'], '@lib/*': ['libs/*']} + }; + const basePaths = getBasePaths(logger, sourceDirectory, pathMappings); + expect(basePaths).toEqual([ + fs.resolve(projectDirectory, 'sub-folder/dist-2'), + sourceDirectory, + fs.resolve(projectDirectory, 'libs'), + fs.resolve(projectDirectory, 'dist-1'), + ]); + }); + + it('should discard paths that are already contained by another path', () => { + const projectDirectory = _('/path/to/project'); + const fs = getFileSystem(); + fs.ensureDir(fs.resolve(projectDirectory, 'dist-1')); + fs.ensureDir(fs.resolve(projectDirectory, 'dist-1/sub-folder')); + fs.ensureDir(fs.resolve(projectDirectory, 'node_modules/libs')); + + const sourceDirectory = _('/path/to/project/node_modules'); + const pathMappings = { + baseUrl: projectDirectory, + paths: {'@dist': ['dist-1', 'dist-1/sub-folder'], '@lib/*': ['node_modules/libs/*']} + }; + const basePaths = getBasePaths(logger, sourceDirectory, pathMappings); + expect(basePaths).toEqual([ + sourceDirectory, + fs.resolve(projectDirectory, 'dist-1'), + ]); + }); + + it('should use the containing directory of path mapped files', () => { + const projectDirectory = _('/path/to/project'); + const fs = getFileSystem(); + fs.ensureDir(fs.resolve(projectDirectory, 'dist-1')); + fs.writeFile(fs.resolve(projectDirectory, 'dist-1/file.js'), 'dummy content'); + + const sourceDirectory = _('/path/to/project/node_modules'); + const pathMappings = {baseUrl: projectDirectory, paths: {'@dist': ['dist-1/file.js']}}; + const basePaths = getBasePaths(logger, sourceDirectory, pathMappings); + expect(basePaths).toEqual([ + sourceDirectory, + fs.resolve(projectDirectory, 'dist-1'), + ]); + }); + + it('should always include the `sourceDirectory` if it is a node_modules directory in the returned basePaths, even if it is contained by another basePath', + () => { + const projectDirectory = _('/path/to/project'); + const sourceDirectory = _('/path/to/project/node_modules'); + const fs = getFileSystem(); + fs.ensureDir(fs.resolve(sourceDirectory)); + + const pathMappings = {baseUrl: projectDirectory, paths: {'*': ['./*']}}; + const basePaths = getBasePaths(logger, sourceDirectory, pathMappings); + expect(basePaths).toEqual([ + sourceDirectory, + projectDirectory, + ]); + }); + + it('should log a warning if baseUrl is the root path', () => { + const fs = getFileSystem(); + fs.ensureDir(fs.resolve('/dist')); + + const sourceDirectory = _('/path/to/project/node_modules'); + const pathMappings = {baseUrl: _('/'), paths: {'@dist': ['dist']}}; + const basePaths = getBasePaths(logger, sourceDirectory, pathMappings); + expect(basePaths).toEqual([ + sourceDirectory, + fs.resolve('/dist'), + ]); + expect(logger.logs.warn).toEqual([ + [`The provided pathMappings baseUrl is the root path ${_('/')}.\n` + + `This is likely to mess up how ngcc finds entry-points and is probably not correct.\n` + + `Please check your path mappings configuration such as in the tsconfig.json file.`] + ]); + }); + + it('should discard basePaths that do not exists and log a warning', () => { + const projectDirectory = _('/path/to/project'); + const fs = getFileSystem(); + fs.ensureDir(fs.resolve(projectDirectory, 'dist-1')); + fs.ensureDir(fs.resolve(projectDirectory, 'sub-folder')); + + const sourceDirectory = _('/path/to/project/node_modules'); + const pathMappings = { + baseUrl: projectDirectory, + paths: {'@dist': ['dist-1', 'sub-folder/dist-2'], '@lib/*': ['libs/*']} + }; + const basePaths = getBasePaths(logger, sourceDirectory, pathMappings); + expect(basePaths).toEqual([ + sourceDirectory, + fs.resolve(projectDirectory, 'dist-1'), + ]); + expect(logger.logs.warn).toEqual([ + [`The basePath "${fs.resolve(projectDirectory, 'sub-folder/dist-2')}" computed from baseUrl "${projectDirectory}" and path mapping "sub-folder/dist-2" does not exist in the file-system.\n` + + `It will not be scanned for entry-points.`], + [`The basePath "${fs.resolve(projectDirectory, 'libs')}" computed from baseUrl "${projectDirectory}" and path mapping "libs/*" does not exist in the file-system.\n` + + `It will not be scanned for entry-points.`], + ]); + }); + }); +}); \ No newline at end of file From 55168021423e58895cb0bba956883cab04c641c4 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@google.com> Date: Mon, 30 Mar 2020 22:35:29 -0700 Subject: [PATCH 079/262] fix(compiler): avoid undefined expressions in holey array (#36343) From G3 bug ID: 116443331 The View Engine compiler crashes when it tries to compile a test in JIT mode that includes the d3-scale-chromatic library [1]. The d3 package initializes some arrays using the following pattern: ```js export var scheme = new Array(3).concat( "d8b365f5f5f55ab4ac", // ... more entries ).map(colors); ``` The stack trace from the crash is as follows: ``` TypeError: Cannot read property 'visitExpression' of undefined at ../../../third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts:505:39 at JitEmitterVisitor.AbstractEmitterVisitor.visitAllObjects third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=526 at JitEmitterVisitor.AbstractEmitterVisitor.visitAllExpressions third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=505 at JitEmitterVisitor.AbstractEmitterVisitor.visitLiteralArrayExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=484 at LiteralArrayExpr.visitExpression third_party/javascript/angular2/rc/packages/compiler/src/output/output_ast.ts?l=791 at ../../../third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts:492:19 at JitEmitterVisitor.AbstractEmitterVisitor.visitAllObjects third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=526 at JitEmitterVisitor.AbstractEmitterVisitor.visitLiteralMapExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=490 at LiteralMapExpr.visitExpression third_party/javascript/angular2/rc/packages/compiler/src/output/output_ast.ts?l=819 at ../../../third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts:505:39 at JitEmitterVisitor.AbstractEmitterVisitor.visitAllObjects third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=526 at JitEmitterVisitor.AbstractEmitterVisitor.visitAllExpressions third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=505 at JitEmitterVisitor.AbstractEmitterVisitor.visitInvokeFunctionExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=318 at JitEmitterVisitor.AbstractJsEmitterVisitor.visitInvokeFunctionExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_js_emitter.ts?l=112 at InvokeFunctionExpr.visitExpression third_party/javascript/angular2/rc/packages/compiler/src/output/output_ast.ts?l=440 ``` This is because the corresponding output AST for the array is of the form ```ts [ undefined, undefined, undefined, o.LiteralExpr, // ... ] ``` The output AST is clearly malformed and breaks the type representation of `LiteralArrayExpr` in which every entry is expected to be of type `Expression`. This commit fixes the bug by using a plain `for` loop to iterate over the entire length of the holey array and convert undefined elements to `LiteralExpr`. [1]: https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/BrBG.js PR Close #36343 --- packages/compiler/src/output/value_util.ts | 11 ++++++++- .../compiler/test/output/value_util_spec.ts | 23 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/output/value_util_spec.ts diff --git a/packages/compiler/src/output/value_util.ts b/packages/compiler/src/output/value_util.ts index c043800a6f350..dd621c3817505 100644 --- a/packages/compiler/src/output/value_util.ts +++ b/packages/compiler/src/output/value_util.ts @@ -21,7 +21,16 @@ export function convertValueToOutputAst( class _ValueOutputAstTransformer implements ValueTransformer { constructor(private ctx: OutputContext) {} visitArray(arr: any[], type: o.Type): o.Expression { - return o.literalArr(arr.map(value => visitValue(value, this, null)), type); + const values: o.Expression[] = []; + // Note Array.map() must not be used to convert the values because it will + // skip over empty elements in arrays constructed using `new Array(length)`, + // resulting in `undefined` elements. This breaks the type guarantee that + // all values in `o.LiteralArrayExpr` are of type `o.Expression`. + // See test case in `value_util_spec.ts`. + for (let i = 0; i < arr.length; ++i) { + values.push(visitValue(arr[i], this, null /* context */)); + } + return o.literalArr(values, type); } visitStringMap(map: {[key: string]: any}, type: o.MapType): o.Expression { diff --git a/packages/compiler/test/output/value_util_spec.ts b/packages/compiler/test/output/value_util_spec.ts new file mode 100644 index 0000000000000..536cf81527e7c --- /dev/null +++ b/packages/compiler/test/output/value_util_spec.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as o from '../../src/output/output_ast'; +import {convertValueToOutputAst} from '../../src/output/value_util'; + +describe('convertValueToOutputAst', () => { + it('should convert all array elements, including undefined', () => { + const ctx = null; + const value = new Array(3).concat('foo'); + const expr = convertValueToOutputAst(ctx !, value) as o.LiteralArrayExpr; + expect(expr instanceof o.LiteralArrayExpr); + expect(expr.entries.length).toBe(4); + for (let i = 0; i < 4; ++i) { + expect(expr.entries[i] instanceof o.Expression).toBe(true); + } + }); +}); From b59bc0e38c5a008a8d8649afc109865f65b9b73b Mon Sep 17 00:00:00 2001 From: Alan Agius <alan.agius4@gmail.com> Date: Wed, 1 Apr 2020 13:35:30 +0200 Subject: [PATCH 080/262] fix(platform-server): update `xhr2` dependency (#36366) Previous versions of xhr2 used the depreciated "new Buffer()". Closes #36358 PR Close #36366 --- package.json | 2 +- packages/platform-server/package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index d485e098e534a..7aca79ee8b310 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "tslib": "^1.10.0", "tslint": "6.0.0", "typescript": "~3.8.3", - "xhr2": "0.1.4", + "xhr2": "0.2.0", "yaml": "^1.7.2", "yargs": "15.3.0" }, diff --git a/packages/platform-server/package.json b/packages/platform-server/package.json index 3ed7d778ffde8..2ada1e723ca4d 100644 --- a/packages/platform-server/package.json +++ b/packages/platform-server/package.json @@ -23,7 +23,7 @@ }, "dependencies": { "domino": "^2.1.2", - "xhr2": "^0.1.4" + "xhr2": "^0.2.0" }, "repository": { "type": "git", diff --git a/yarn.lock b/yarn.lock index d7300351b8352..f2cf823a84032 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15707,10 +15707,10 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= -xhr2@0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f" - integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8= +xhr2@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.2.0.tgz#eddeff782f3b7551061b8d75645085269396e521" + integrity sha512-BDtiD0i2iKPK/S8OAZfpk6tyzEDnKKSjxWHcMBVmh+LuqJ8A32qXTyOx+TVOg2dKvq6zGBq2sgKPkEeRs1qTRA== xml2js@0.4.16: version "0.4.16" From 326240eb91fe5eee2b12755d4aa70684130008cf Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Wed, 1 Apr 2020 16:16:02 +0300 Subject: [PATCH 081/262] fix(ngcc): allow ngcc configuration to match pre-release versions of packages (#36370) Ngcc supports providing a project-level configuration to affect how certain dependencies are processed and also has a built-in fallback configuration for some unmaintained packages. Each entry in these configurations could be scoped to specific versions of a package by providing a version range. If no version range is provided for a package, it defaults to `*` (with the intention of matching any version). Previously, the installed version of a package was tested against the version range using the [semver][1] package's `satisfies()` function with the default options. By default, `satisfies()` does not match pre-releases (see [here][2] for more details on reasoning). While this makes sense when determining what version of a dependency to install (trying to avoid unexpected breaking changes), it is not desired in the case of ngcc. This commit fixes it by explicitly specifying that pre-release versions should be matched normally. [1]: https://www.npmjs.com/package/semver [2]: https://github.com/npm/node-semver#prerelease-tags PR Close #36370 --- .../ngcc/src/packages/configuration.ts | 4 +- .../ngcc/test/packages/configuration_spec.ts | 211 +++++++++++++++++- 2 files changed, 212 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/configuration.ts b/packages/compiler-cli/ngcc/src/packages/configuration.ts index 133d1ad2a8ffe..ea1660e917ea7 100644 --- a/packages/compiler-cli/ngcc/src/packages/configuration.ts +++ b/packages/compiler-cli/ngcc/src/packages/configuration.ts @@ -304,5 +304,7 @@ function findSatisfactoryVersion( // So just return the first config that matches the package name. return configs[0]; } - return configs.find(config => satisfies(version, config.versionRange)) || null; + return configs.find( + config => satisfies(version, config.versionRange, {includePrerelease: true})) || + null; } diff --git a/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts b/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts index c74a2d2f87b56..f91abd6c7de4c 100644 --- a/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts @@ -214,6 +214,114 @@ runInEachFileSystem(() => { .toEqual({versionRange: '*', entryPoints: {}}); }); + it('should correctly handle pre-release versions and version ranges', () => { + loadTestFiles([ + { + name: _Abs('/project-1/ngcc.config.js'), + contents: ` + module.exports = { + packages: { + 'package-1': { + entryPoints: { + './entry-point-1': {}, + }, + }, + 'package-2@1.0.0-beta.2': { + entryPoints: { + './entry-point-2': {}, + }, + }, + 'package-3@>=1.0.0-beta.2': { + entryPoints: { + './entry-point-3': {}, + }, + }, + }, + }; + `, + }, + ]); + + const configuration = new NgccConfiguration(fs, _Abs('/project-1')); + const getConfig = (packageName: string, version: string | null) => + configuration.getConfig(_Abs(`/project-1/node_modules/${packageName}`), version); + + // Default version range: * + expect(getConfig('package-1', '1.0.0-beta.2')) + .toEqual( + { + versionRange: '*', + entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}, + }, + 'Config for package-1@1.0.0-beta.2'); + + // Version range: 1.0.0-beta.2 + expect(getConfig('package-2', '1.0.0-beta.2')) + .toEqual( + { + versionRange: '1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-2/entry-point-2')]: {}}, + }, + 'Config for package-2@1.0.0-beta.2'); + + expect(getConfig('package-2', '1.0.0')) + .toEqual( + { + versionRange: '*', + entryPoints: {}, + }, + 'Config for package-2@1.0.0'); + + expect(getConfig('package-2', null)) + .toEqual( + { + versionRange: '1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-2/entry-point-2')]: {}}, + }, + 'Config for package-2@null'); + + // Version range: >=1.0.0-beta.2 + expect(getConfig('package-3', '1.0.0-beta.2')) + .toEqual( + { + versionRange: '>=1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-3/entry-point-3')]: {}}, + }, + 'Config for package-3@1.0.0-beta.2'); + + expect(getConfig('package-3', '1.0.0')) + .toEqual( + { + versionRange: '>=1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-3/entry-point-3')]: {}}, + }, + 'Config for package-3@1.0.0'); + + expect(getConfig('package-3', '2.0.0')) + .toEqual( + { + versionRange: '>=1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-3/entry-point-3')]: {}}, + }, + 'Config for package-3@2.0.0'); + + expect(getConfig('package-3', '1.0.0-beta.1')) + .toEqual( + { + versionRange: '*', + entryPoints: {}, + }, + 'Config for package-3@1.0.0-beta.1'); + + expect(getConfig('package-3', '0.9.99')) + .toEqual( + { + versionRange: '*', + entryPoints: {}, + }, + 'Config for package-3@0.9.99'); + }); + it('should not get confused by the @ in namespaced packages', () => { loadTestFiles([{ name: _Abs('/project-1/ngcc.config.js'), @@ -287,13 +395,13 @@ runInEachFileSystem(() => { }); describe('at the default level', () => { - const originalDefaultConfig = DEFAULT_NGCC_CONFIG.packages['package-1']; + const originalDefaultConfig = JSON.stringify(DEFAULT_NGCC_CONFIG.packages); beforeEach(() => { DEFAULT_NGCC_CONFIG.packages['package-1'] = { entryPoints: {'./default-level-entry-point': {}}, }; }); - afterEach(() => { DEFAULT_NGCC_CONFIG.packages['package-1'] = originalDefaultConfig; }); + afterEach(() => DEFAULT_NGCC_CONFIG.packages = JSON.parse(originalDefaultConfig)); it('should return configuration for a package found in the default config', () => { const readFileSpy = spyOn(fs, 'readFile').and.callThrough(); @@ -361,6 +469,105 @@ runInEachFileSystem(() => { {[_Abs('/project-1/node_modules/package-1/project-level-entry-point')]: {}} }); }); + + it('should correctly handle pre-release versions and version ranges', () => { + Object.assign(DEFAULT_NGCC_CONFIG.packages, { + 'package-1': { + entryPoints: { + './entry-point-1': {}, + }, + }, + 'package-2@1.0.0-beta.2': { + entryPoints: { + './entry-point-2': {}, + }, + }, + 'package-3@>=1.0.0-beta.2': { + entryPoints: { + './entry-point-3': {}, + }, + }, + }); + + const configuration = new NgccConfiguration(fs, _Abs('/project-1')); + const getConfig = (packageName: string, version: string | null) => + configuration.getConfig(_Abs(`/project-1/node_modules/${packageName}`), version); + + // Default version range: * + expect(getConfig('package-1', '1.0.0-beta.2')) + .toEqual( + { + versionRange: '*', + entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}, + }, + 'Config for package-1@1.0.0-beta.2'); + + // Version range: 1.0.0-beta.2 + expect(getConfig('package-2', '1.0.0-beta.2')) + .toEqual( + { + versionRange: '1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-2/entry-point-2')]: {}}, + }, + 'Config for package-2@1.0.0-beta.2'); + + expect(getConfig('package-2', '1.0.0')) + .toEqual( + { + versionRange: '*', + entryPoints: {}, + }, + 'Config for package-2@1.0.0'); + + expect(getConfig('package-2', null)) + .toEqual( + { + versionRange: '1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-2/entry-point-2')]: {}}, + }, + 'Config for package-2@null'); + + // Version range: >=1.0.0-beta.2 + expect(getConfig('package-3', '1.0.0-beta.2')) + .toEqual( + { + versionRange: '>=1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-3/entry-point-3')]: {}}, + }, + 'Config for package-3@1.0.0-beta.2'); + + expect(getConfig('package-3', '1.0.0')) + .toEqual( + { + versionRange: '>=1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-3/entry-point-3')]: {}}, + }, + 'Config for package-3@1.0.0'); + + expect(getConfig('package-3', '2.0.0')) + .toEqual( + { + versionRange: '>=1.0.0-beta.2', + entryPoints: {[_Abs('/project-1/node_modules/package-3/entry-point-3')]: {}}, + }, + 'Config for package-3@2.0.0'); + + expect(getConfig('package-3', '1.0.0-beta.1')) + .toEqual( + { + versionRange: '*', + entryPoints: {}, + }, + 'Config for package-3@1.0.0-beta.1'); + + expect(getConfig('package-3', '0.9.99')) + .toEqual( + { + versionRange: '*', + entryPoints: {}, + }, + 'Config for package-3@0.9.99'); + }); }); }); }); From 43006bcc456c7561c063b700c4ee2fedf44c60e0 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Thu, 26 Mar 2020 10:45:09 -0700 Subject: [PATCH 082/262] feat(dev-infra): standard CLI commands using yargs (#36326) Creates a standard model for CLI commands provided by ng-dev. Allows for us to have any of the tools/scripts extend to be included in the ng-dev command, or be standalone using the same yargs parser. PR Close #36326 --- dev-infra/BUILD.bazel | 3 ++ dev-infra/cli.ts | 35 ++++++---------- dev-infra/commit-message/BUILD.bazel | 4 ++ dev-infra/commit-message/cli.ts | 20 ++++++++++ dev-infra/commit-message/validate-file.ts | 21 ++++++++++ dev-infra/pullapprove/BUILD.bazel | 3 ++ dev-infra/pullapprove/cli.ts | 19 +++++++++ dev-infra/ts-circular-dependencies/index.ts | 44 +++++++++++++-------- package.json | 5 ++- 9 files changed, 114 insertions(+), 40 deletions(-) create mode 100644 dev-infra/commit-message/cli.ts create mode 100644 dev-infra/commit-message/validate-file.ts create mode 100644 dev-infra/pullapprove/cli.ts diff --git a/dev-infra/BUILD.bazel b/dev-infra/BUILD.bazel index 60d60aa480a87..57897870bff31 100644 --- a/dev-infra/BUILD.bazel +++ b/dev-infra/BUILD.bazel @@ -10,8 +10,11 @@ ts_library( deps = [ "//dev-infra/commit-message", "//dev-infra/pullapprove", + "//dev-infra/ts-circular-dependencies", "//dev-infra/utils:config", "@npm//@types/node", + "@npm//@types/yargs", + "@npm//yargs", ], ) diff --git a/dev-infra/cli.ts b/dev-infra/cli.ts index 3aa6d2e73364b..0c30ac4ae6199 100644 --- a/dev-infra/cli.ts +++ b/dev-infra/cli.ts @@ -6,26 +6,17 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {readFileSync} from 'fs'; -import {join} from 'path'; -import {verify} from './pullapprove/verify'; -import {validateCommitMessage} from './commit-message/validate'; -import {getRepoBaseDir} from './utils/config'; +import * as yargs from 'yargs'; +import {tsCircularDependenciesBuilder} from './ts-circular-dependencies/index'; +import {buildPullapproveParser} from './pullapprove/cli'; +import {buildCommitMessageParser} from './commit-message/cli'; -const args = process.argv.slice(2); - - -// TODO(josephperrott): Set up proper cli flag/command handling -switch (args[0]) { - case 'pullapprove:verify': - verify(); - break; - case 'commit-message:pre-commit-validate': - const commitMessage = readFileSync(join(getRepoBaseDir(), '.git/COMMIT_EDITMSG'), 'utf8'); - if (validateCommitMessage(commitMessage)) { - console.info('√ Valid commit message'); - } - break; - default: - console.info('No commands were matched'); -} +yargs.scriptName('ng-dev') + .demandCommand() + .recommendCommands() + .command('ts-circular-deps <command>', '', tsCircularDependenciesBuilder) + .command('pullapprove <command>', '', buildPullapproveParser) + .command('commit-message <command>', '', buildCommitMessageParser) + .wrap(120) + .strict() + .parse(); diff --git a/dev-infra/commit-message/BUILD.bazel b/dev-infra/commit-message/BUILD.bazel index e6029084c3e66..fe11b49270bfb 100644 --- a/dev-infra/commit-message/BUILD.bazel +++ b/dev-infra/commit-message/BUILD.bazel @@ -4,15 +4,19 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library") ts_library( name = "commit-message", srcs = [ + "cli.ts", "config.ts", "validate.ts", + "validate-file.ts", ], module_name = "@angular/dev-infra-private/commit-message", visibility = ["//dev-infra:__subpackages__"], deps = [ "//dev-infra/utils:config", "@npm//@types/node", + "@npm//@types/yargs", "@npm//tslib", + "@npm//yargs", ], ) diff --git a/dev-infra/commit-message/cli.ts b/dev-infra/commit-message/cli.ts new file mode 100644 index 0000000000000..c4443396bec41 --- /dev/null +++ b/dev-infra/commit-message/cli.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import * as yargs from 'yargs'; +import {validateFile} from './validate-file'; + +/** Build the parser for the commit-message commands. */ +export function buildCommitMessageParser(localYargs: yargs.Argv) { + return localYargs.help().strict().command( + 'pre-commit-validate', 'Validate the most recent commit message', {}, + () => { validateFile('.git/COMMIT_EDITMSG'); }); +} + +if (require.main == module) { + buildCommitMessageParser(yargs).parse(); +} diff --git a/dev-infra/commit-message/validate-file.ts b/dev-infra/commit-message/validate-file.ts new file mode 100644 index 0000000000000..1bac796df1dfb --- /dev/null +++ b/dev-infra/commit-message/validate-file.ts @@ -0,0 +1,21 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {readFileSync} from 'fs'; +import {join} from 'path'; + +import {getRepoBaseDir} from '../utils/config'; + +import {validateCommitMessage} from './validate'; + +/** Validate commit message at the provided file path. */ +export function validateFile(filePath: string) { + const commitMessage = readFileSync(join(getRepoBaseDir(), filePath), 'utf8'); + if (validateCommitMessage(commitMessage)) { + console.info('√ Valid commit message'); + } +} diff --git a/dev-infra/pullapprove/BUILD.bazel b/dev-infra/pullapprove/BUILD.bazel index 9d1ffb6d7dcb9..6b341553ae16b 100644 --- a/dev-infra/pullapprove/BUILD.bazel +++ b/dev-infra/pullapprove/BUILD.bazel @@ -3,6 +3,7 @@ load("@npm_bazel_typescript//:index.bzl", "ts_library") ts_library( name = "pullapprove", srcs = [ + "cli.ts", "group.ts", "logging.ts", "parse-yaml.ts", @@ -16,9 +17,11 @@ ts_library( "@npm//@types/node", "@npm//@types/shelljs", "@npm//@types/yaml", + "@npm//@types/yargs", "@npm//minimatch", "@npm//shelljs", "@npm//tslib", "@npm//yaml", + "@npm//yargs", ], ) diff --git a/dev-infra/pullapprove/cli.ts b/dev-infra/pullapprove/cli.ts new file mode 100644 index 0000000000000..d1036e644e57e --- /dev/null +++ b/dev-infra/pullapprove/cli.ts @@ -0,0 +1,19 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import * as yargs from 'yargs'; +import {verify} from './verify'; + +/** Build the parser for the pullapprove commands. */ +export function buildPullapproveParser(localYargs: yargs.Argv) { + return localYargs.help().strict().demandCommand().command( + 'verify', 'Verify the pullapprove config', {}, () => verify()); +} + +if (require.main === module) { + buildPullapproveParser(yargs).parse(); +} diff --git a/dev-infra/ts-circular-dependencies/index.ts b/dev-infra/ts-circular-dependencies/index.ts index f4a5cb3591129..50f8a903b79fd 100644 --- a/dev-infra/ts-circular-dependencies/index.ts +++ b/dev-infra/ts-circular-dependencies/index.ts @@ -19,22 +19,30 @@ import {compareGoldens, convertReferenceChainToGolden, Golden} from './golden'; import {convertPathToForwardSlash} from './file_system'; import {loadTestConfig, CircularDependenciesTestConfig} from './config'; -if (require.main === module) { - const {_: command, config: configArg, warnings} = - yargs.help() - .strict() - .command('check', 'Checks if the circular dependencies have changed.') - .command('approve', 'Approves the current circular dependencies.') - .demandCommand() - .option( - 'config', - {type: 'string', demandOption: true, description: 'Path to the configuration file.'}) - .option('warnings', {type: 'boolean', description: 'Prints all warnings.'}) - .argv; - const configPath = isAbsolute(configArg) ? configArg : resolve(configArg); - const config = loadTestConfig(configPath); - const isApprove = command.includes('approve'); - process.exit(main(isApprove, config, warnings)); + +export function tsCircularDependenciesBuilder(localYargs: yargs.Argv) { + return localYargs.help() + .strict() + .demandCommand() + .option( + 'config', + {type: 'string', demandOption: true, description: 'Path to the configuration file.'}) + .option('warnings', {type: 'boolean', description: 'Prints all warnings.'}) + .command( + 'check', 'Checks if the circular dependencies have changed.', {}, + (argv: yargs.Arguments) => { + const {config: configArg, warnings} = argv; + const configPath = isAbsolute(configArg) ? configArg : resolve(configArg); + const config = loadTestConfig(configPath); + process.exit(main(false, config, warnings)); + }) + .command( + 'approve', 'Approves the current circular dependencies.', {}, (argv: yargs.Arguments) => { + const {config: configArg, warnings} = argv; + const configPath = isAbsolute(configArg) ? configArg : resolve(configArg); + const config = loadTestConfig(configPath); + process.exit(main(true, config, warnings)); + }); } /** @@ -126,3 +134,7 @@ function getRelativePath(baseDir: string, path: string) { function convertReferenceChainToString(chain: ReferenceChain<string>) { return chain.join(' → '); } + +if (require.main === module) { + tsCircularDependenciesBuilder(yargs).parse(); +} diff --git a/package.json b/package.json index 7aca79ee8b310..c6f06d854dcdd 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,10 @@ "tslint": "tsc -p tools/tsconfig.json && tslint -c tslint.json \"+(packages|modules|scripts|tools)/**/*.+(js|ts)\"", "public-api:check": "node goldens/public-api/manage.js test", "public-api:update": "node goldens/public-api/manage.js accept", - "ts-circular-deps": "ts-node dev-infra/ts-circular-dependencies/index.ts --config ./packages/circular-deps-test.conf.js", + "ts-circular-deps": "ts-node --transpile-only -- dev-infra/ts-circular-dependencies/index.ts --config ./packages/circular-deps-test.conf.js", "ts-circular-deps:check": "yarn -s ts-circular-deps check", - "ts-circular-deps:approve": "yarn -s ts-circular-deps approve" + "ts-circular-deps:approve": "yarn -s ts-circular-deps approve", + "ng-dev": "ts-node --transpile-only -- dev-infra/cli.ts" }, "// 1": "dependencies are used locally and by bazel", "dependencies": { From 24a92472bf06e5473ce4fe1d7566bd6a480a6992 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 30 Mar 2020 10:33:37 -0700 Subject: [PATCH 083/262] ci: use dev-infra cli from local sources (#36326) Use dev-infra cli from local sources rather than loading from @angular/dev-infra-private builds. PR Close #36326 --- .circleci/config.yml | 2 +- dev-infra/commit-message/cli.ts | 5 +++-- dev-infra/ng-dev | 11 +++++++++++ package.json | 1 - yarn.lock | 4 ---- 5 files changed, 15 insertions(+), 8 deletions(-) create mode 100755 dev-infra/ng-dev diff --git a/.circleci/config.yml b/.circleci/config.yml index b6b5065b7152b..3b564587e1f1d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -280,7 +280,7 @@ jobs: - run: yarn lint --branch $CI_GIT_BASE_REVISION - run: yarn ts-circular-deps:check - - run: yarn -s ng-dev pullapprove:verify + - run: yarn -s ng-dev pullapprove verify test: executor: diff --git a/dev-infra/commit-message/cli.ts b/dev-infra/commit-message/cli.ts index c4443396bec41..83bd1b8a664b8 100644 --- a/dev-infra/commit-message/cli.ts +++ b/dev-infra/commit-message/cli.ts @@ -11,8 +11,9 @@ import {validateFile} from './validate-file'; /** Build the parser for the commit-message commands. */ export function buildCommitMessageParser(localYargs: yargs.Argv) { return localYargs.help().strict().command( - 'pre-commit-validate', 'Validate the most recent commit message', {}, - () => { validateFile('.git/COMMIT_EDITMSG'); }); + 'pre-commit-validate', 'Validate the most recent commit message', {}, () => { + validateFile('.git/COMMIT_EDITMSG'); + }); } if (require.main == module) { diff --git a/dev-infra/ng-dev b/dev-infra/ng-dev new file mode 100755 index 0000000000000..819654870af25 --- /dev/null +++ b/dev-infra/ng-dev @@ -0,0 +1,11 @@ +#!/usr/bin/env ts-node +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// Loads the ng-dev cli, automatically executing it. +require('./cli.ts'); diff --git a/package.json b/package.json index c6f06d854dcdd..820fe626f1b56 100644 --- a/package.json +++ b/package.json @@ -148,7 +148,6 @@ "// 2": "devDependencies are not used under Bazel. Many can be removed after test.sh is deleted.", "devDependencies": { "@angular/cli": "9.0.3", - "@angular/dev-infra-private": "angular/dev-infra-private-builds#3724a71", "@bazel/bazelisk": "^1.3.0", "@bazel/buildifier": "^0.29.0", "@bazel/ibazel": "^0.12.3", diff --git a/yarn.lock b/yarn.lock index f2cf823a84032..4f7cb92181697 100644 --- a/yarn.lock +++ b/yarn.lock @@ -153,10 +153,6 @@ universal-analytics "^0.4.20" uuid "^3.3.2" -"@angular/dev-infra-private@angular/dev-infra-private-builds#3724a71": - version "0.0.0" - resolved "https://codeload.github.com/angular/dev-infra-private-builds/tar.gz/3724a71047361d85f4131d990f00a5aecdbc3ddc" - "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" From 4d458db1b59d81764bd13f86f8ff8327d1b9cedd Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 11 Mar 2020 10:14:10 -0700 Subject: [PATCH 084/262] docs: update and edit web-worker page (#36383) PR Close #36383 --- aio/content/guide/web-worker.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/aio/content/guide/web-worker.md b/aio/content/guide/web-worker.md index c05bae8093a73..2b62794139dbd 100644 --- a/aio/content/guide/web-worker.md +++ b/aio/content/guide/web-worker.md @@ -4,7 +4,7 @@ freeing the main thread to update the user interface. If you find your application performs a lot of computations, such as generating CAD drawings or doing heavy geometrical calculations, using web workers can help increase your application's performance. -<div class="alert is-helpful> +<div class="alert is-helpful"> The CLI does not support running Angular itself in a web worker. @@ -19,9 +19,6 @@ To add a web worker to an existing project, use the Angular CLI `ng generate` co You can add a web worker anywhere in your application. For example, to add a web worker to the root component, `src/app/app.component.ts`, run the following command. - `ng generate web-worker app`. - - The command performs the following actions. - Configures your project to use web workers, if it isn't already. @@ -52,7 +49,7 @@ The command performs the following actions. After you generate this initial scaffold, you must refactor your code to use the web worker by sending messages to and from the worker. -<div class="alert is-important> +<div class="alert is-important"> Some environments or platforms, such as `@angular/platform-server` used in [Server-side Rendering](guide/universal), don't support web workers. To ensure that your application will work in these environments, you must provide a fallback mechanism to perform the computations that the worker would otherwise perform. From a5eb0e56b6b532ebf85c2ecd37deaa76371c9d08 Mon Sep 17 00:00:00 2001 From: Ferdinand Malcher <ferdinand@malcher.media> Date: Fri, 6 Mar 2020 13:39:16 +0100 Subject: [PATCH 085/262] docs(zone.js): fix typos and align formatting (#35907) PR Close #35907 --- aio/content/guide/zone.md | 103 +++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 52 deletions(-) diff --git a/aio/content/guide/zone.md b/aio/content/guide/zone.md index 9297acd1601ca..68aa2faec1b5b 100644 --- a/aio/content/guide/zone.md +++ b/aio/content/guide/zone.md @@ -47,7 +47,7 @@ To clarify how changes are detected and values updated, consider the following c } } - // example 1: update data inside button click event handler + // Example 1: update data inside button click event handler document.getElementById('btn').addEventListener('click', () => { // update value value = 'button update value'; @@ -55,7 +55,7 @@ To clarify how changes are detected and values updated, consider the following c detectChange(); }); - // example 2: Http Request + // Example 2: HTTP Request const xhr = new XMLHttpRequest(); xhr.addEventListener('load', function() { // get response from server @@ -66,7 +66,7 @@ To clarify how changes are detected and values updated, consider the following c xhr.open('GET', serverUrl); xhr.send(); - // example 3: setTimeout + // Example 3: setTimeout setTimeout(() => { // update value inside setTimeout callback value = 'timeout update value'; @@ -74,18 +74,18 @@ To clarify how changes are detected and values updated, consider the following c detectChange(); }, 100); - // example 4: Promise.then - Promise.resolve('promise resolved a value').then((v) => { + // Example 4: Promise.then + Promise.resolve('promise resolved a value').then(v => { // update value inside Promise thenCallback value = v; // call detectChange manually detectChange(); }, 100); - // example 5: some other asynchronous APIs + // Example 5: some other asynchronous APIs document.getElementById('canvas').toBlob(blob => { // update value when blob data is created from the canvas - value = `value updated by canvas, size is ${blog.size}`; + value = `value updated by canvas, size is ${blob.size}`; // call detectChange manually detectChange(); }); @@ -108,7 +108,7 @@ To understand how change detection works, first consider when the application ne <code-example path="user-input/src/app/click-me.component.ts" region="click-me-component" header="src/app/click-me.component.ts"></code-example> -3. Http Data Request. You can also get data from a server through an Http request. For example: +3. HTTP Data Request. You can also get data from a server through an HTTP request. For example: ```typescript @Component({ @@ -129,7 +129,7 @@ export class AppComponent implements OnInit { } ``` -4. MacroTasks, such as `setTimeout()`/`setInterval()`. You can also update the data in the callback function of `macroTask` such as `setTimeout()`. For example: +4. MacroTasks, such as `setTimeout()` or `setInterval()`. You can also update the data in the callback function of a `macroTask` such as `setTimeout()`. For example: ```typescript @Component({ @@ -148,7 +148,7 @@ export class AppComponent implements OnInit { } ``` -5. MicroTask, such as `Promise.then()`. Other asynchronous APIs return a Promise object (such as `fetch`), so the `then()` callback function can also update the data. For example: +5. MicroTasks, such as `Promise.then()`. Other asynchronous APIs return a Promise object (such as `fetch`), so the `then()` callback function can also update the data. For example: ```typescript @Component({ @@ -167,27 +167,23 @@ export class AppComponent implements OnInit { } ``` -6. Other async operations. In addition to `addEventListener()`/`setTimeout()`/`Promise.then()`, there are other operations that can update the data asynchronously. Some examples include `WebSocket.onmessage()` and `Canvas.toBlob()`. +6. Other async operations. In addition to `addEventListener()`, `setTimeout()` and `Promise.then()`, there are other operations that can update the data asynchronously. Some examples include `WebSocket.onmessage()` and `Canvas.toBlob()`. The preceding list contains most common scenarios in which the application might change the data. Angular runs change detection whenever it detects that data could have changed. -The result of change detection is that DOM is updated with new data. Angular detects the changes in different ways. For component initialization, Angular calls change detection explicitly. For [asynchronous operations](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous), Angular uses a Zone to detect changes in places where the data could have possibly mutated and it runs change detection automatically. +The result of change detection is that the DOM is updated with new data. Angular detects the changes in different ways. For component initialization, Angular calls change detection explicitly. For [asynchronous operations](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous), Angular uses a zone to detect changes in places where the data could have possibly mutated and it runs change detection automatically. ## Zones and execution contexts -A zone provides an execution context that persists across async tasks. [Execution Context](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) is an abstract concept that holds information about the environment within the current code being executed. Consider the following example. +A zone provides an execution context that persists across async tasks. [Execution Context](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) is an abstract concept that holds information about the environment within the current code being executed. Consider the following example: ```javascript const callback = function() { console.log('setTimeout callback context is', this); } -const ctx1 = { - name: 'ctx1' -}; -const ctx2 = { - name: 'ctx2' -}; +const ctx1 = { name: 'ctx1' }; +const ctx2 = { name: 'ctx2' }; const func = function() { console.log('caller context is', this); @@ -198,8 +194,8 @@ func.apply(ctx1); func.apply(ctx2); ``` -The value of `this` in the callback of `setTimeout` might differ depending on when `setTimeout` is called. -Thus you can lose the context in asynchronous operations. +The value of `this` in the callback of `setTimeout()` might differ depending on when `setTimeout()` is called. +Thus, you can lose the context in asynchronous operations. A zone provides a new zone context other than `this`, the zone context that persists across asynchronous operations. In the following example, the new zone context is called `zoneThis`. @@ -227,19 +223,19 @@ Zone.js can create contexts that persist across asynchronous operations as well const zone = Zone.current.fork({ name: 'zone', onScheduleTask: function(delegate, curr, target, task) { - console.log('new task is scheduled: ', task.type, task.source); + console.log('new task is scheduled:', task.type, task.source); return delegate.scheduleTask(target, task); }, onInvokeTask: function(delegate, curr, target, task, applyThis, applyArgs) { - console.log('task will be invoked', task.type, task.source); + console.log('task will be invoked:', task.type, task.source); return delegate.invokeTask(target, task, applyThis, applyArgs); }, onHasTask: function(delegate, curr, target, hasTaskState) { - console.log('task state changed in the zone', hasTaskState); + console.log('task state changed in the zone:', hasTaskState); return delegate.hasTask(target, hasTaskState); }, onInvoke: function(delegate, curr, target, callback, applyThis, applyArgs) { - console.log('the callback will be invoked', callback); + console.log('the callback will be invoked:', callback); return delegate.invoke(target, callback, applyThis, applyArgs); } }); @@ -252,43 +248,43 @@ zone.run(() => { The above example creates a zone with several hooks. -`onXXXTask` hooks trigger when the status of Task changes. -The Zone Task concept is very similar to the Javascript VM Task concept. -- `macroTask`: such as `setTimeout()`. -- `microTask`: such as `Promise.then()`. -- `eventTask`: such as `element.addEventListener()`. +The `onXXXTask` hooks trigger when the status of the task changes. +The concept of a *Zone Task* is very similar to the JavaScript VM Task concept: +- `macroTask`: such as `setTimeout()` +- `microTask`: such as `Promise.then()` +- `eventTask`: such as `element.addEventListener()` These hooks trigger under the following circumstances: - `onScheduleTask`: triggers when a new asynchronous task is scheduled, such as when you call `setTimeout()`. - `onInvokeTask`: triggers when an asynchronous task is about to execute, such as when the callback of `setTimeout()` is about to execute. -- `onHasTask`: triggers when the status of one kind of task inside a zone changes from stable to unstable or from unstable to stable. A status of stable means there are no tasks inside the Zone, while unstable means a new task is scheduled in the zone. +- `onHasTask`: triggers when the status of one kind of task inside a zone changes from stable to unstable or from unstable to stable. A status of "stable" means there are no tasks inside the zone, while "unstable" means a new task is scheduled in the zone. - `onInvoke`: triggers when a synchronous function is going to execute in the zone. With these hooks, `Zone` can monitor the status of all synchronous and asynchronous operations inside a zone. -The above example returns the following output. +The above example returns the following output: ``` -the callback will be invoked () => { +the callback will be invoked: () => { setTimeout(() => { console.log('timeout callback is invoked.'); }); } -new task is scheduled: macroTask setTimeout -task state changed in the zone { microTask: false, +new task is scheduled: macroTask setTimeout +task state changed in the zone: { microTask: false, macroTask: true, eventTask: false, change: 'macroTask' } -task will be invoked macroTask setTimeout +task will be invoked macroTask: setTimeout timeout callback is invoked. -task state changed in the zone { microTask: false, +task state changed in the zone: { microTask: false, macroTask: false, eventTask: false, change: 'macroTask' } ``` -All of the functions of Zone are provided by a library called [zone.js](https://github.com/angular/angular/tree/master/packages/zone.js/README.md). +All of the functions of `Zone` are provided by a library called [Zone.js](https://github.com/angular/angular/tree/master/packages/zone.js/README.md). This library implements those features by intercepting asynchronous APIs through monkey patching. Monkey patching is a technique to add or modify the default behavior of a function at runtime without changing the source code. @@ -300,14 +296,14 @@ This service creates a zone named `angular` to automatically trigger change dete 1. When a sync or async function is executed. 1. When there is no `microTask` scheduled. -### NgZone `run()`/`runOutsideOfAngular()` +### NgZone `run()` and `runOutsideOfAngular()` `Zone` handles most asynchronous APIs such as `setTimeout()`, `Promise.then()`, and `addEventListener()`. For the full list, see the [Zone Module document](https://github.com/angular/angular/blob/master/packages/zone.js/MODULE.md). Therefore in those asynchronous APIs, you don't need to trigger change detection manually. There are still some third party APIs that Zone does not handle. -In those cases, the NgZone service provides a [`run()`](api/core/NgZone#run) method that allows you to execute a function inside the angular zone. +In those cases, the `NgZone` service provides a [`run()`](api/core/NgZone#run) method that allows you to execute a function inside the angular zone. This function, and all asynchronous operations in that function, trigger change detection automatically at the correct time. ```typescript @@ -328,7 +324,7 @@ export class AppComponent implements OnInit { By default, all asynchronous operations are inside the angular zone, which triggers change detection automatically. Another common case is when you don't want to trigger change detection. -In that situation, you can use another NgZone method: [runOutsideAngular()](api/core/NgZone#runoutsideangular). +In that situation, you can use another `NgZone` method: [`runOutsideAngular()`](api/core/NgZone#runoutsideangular). ```typescript export class AppComponent implements OnInit { @@ -349,7 +345,7 @@ export class AppComponent implements OnInit { ### Setting up Zone.js -To make Zone.js available in Angular, you need to import the zone.js package. +To make Zone.js available in Angular, you need to import the `zone.js` package. If you are using the Angular CLI, this step is done automatically, and you will see the following line in the `src/polyfills.ts`: ```typescript @@ -364,17 +360,20 @@ Before importing the `zone.js` package, you can set the following configuration - You can disable some asynchronous API monkey patching for better performance. For example, you can disable the `requestAnimationFrame()` monkey patch, so the callback of `requestAnimationFrame()` will not trigger change detection. This is useful if, in your application, the callback of the `requestAnimationFrame()` will not update any data. -- You can specify that certain DOM events not run inside the angular zone; for example, to prevent a `mousemove` or `scroll` event to trigger change detection. +- You can specify that certain DOM events do not run inside the angular zone; for example, to prevent a `mousemove` or `scroll` event to trigger change detection. There are several other settings you can change. To make these changes, you need to create a `zone-flags.ts` file, such as the following. ```typescript - (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames +// disable patching requestAnimationFrame +(window as any).__Zone_disable_requestAnimationFrame = true; + +// disable patching specified eventNames +(window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; ``` -Next, import `zone-flags` before you import `zone` in the `polyfills.ts`. +Next, import `zone-flags` before you import `zone.js` in the `polyfills.ts`: ```typescript /*************************************************************************************************** @@ -384,12 +383,12 @@ import `./zone-flags`; import 'zone.js/dist/zone'; // Included with Angular CLI. ``` -For more information of what you can configure, see the [zone.js](https://github.com/angular/angular/tree/master/packages/zone.js) documentation. +For more information about what you can configure, see the [Zone.js](https://github.com/angular/angular/tree/master/packages/zone.js) documentation. ### NoopZone `Zone` helps Angular know when to trigger change detection and let the developers focus on the application development. -By default, `Zone` is loaded and works without additional configuration. However, you don't have to use `Zone` to make Angular work, instead opting to trigger change detection on your own. +By default, `Zone` is loaded and works without additional configuration. However, you don't necessarily have to use `Zone` to make Angular work. Instead, you can opt to trigger change detection on your own. <div class="alert is-helpful"> @@ -399,9 +398,9 @@ By default, `Zone` is loaded and works without additional configuration. However </div> -To remove `zone.js`, make the following changes. +To remove Zone.js, make the following changes. -1. Remove the `zone.js` import from `polyfills.ts`. +1. Remove the `zone.js` import from `polyfills.ts`: ```typescript /*************************************************************************************************** @@ -410,9 +409,9 @@ To remove `zone.js`, make the following changes. // import 'zone.js/dist/zone'; // Included with Angular CLI. ``` -2. Bootstrap Angular with `noop zone` in `src/main.ts`. +2. Bootstrap Angular with the `noop` zone in `src/main.ts`: ```typescript - platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'}) + platformBrowserDynamic().bootstrapModule(AppModule, { ngZone: 'noop' }) .catch(err => console.error(err)); ``` From 75afd80ae8382bf7e2031ae7cf6f4d199f93fe1b Mon Sep 17 00:00:00 2001 From: JoostK <joost.koehoorn@gmail.com> Date: Sat, 7 Mar 2020 17:14:25 +0100 Subject: [PATCH 086/262] refactor(compiler): add `@nocollapse` annotation using a synthetic comment (#35932) In Ivy, Angular decorators are compiled into static fields that are inserted into a class declaration in a TypeScript transform. When targeting Closure compiler such fields need to be annotated with `@nocollapse` to prevent them from being lifted from a static field into a variable, as that would prevent the Ivy runtime from being able to find the compiled definitions. Previously, there was a bug in TypeScript where synthetic comments added in a transform would not be emitted at all, so as a workaround a global regex-replace was done in the emit's `writeFile` callback that would add the `@nocollapse` annotation to all static Ivy definition fields. This approach is no longer possible when ngtsc is running as TypeScript plugin, as a plugin cannot control emit behavior. The workaround is no longer necessary, as synthetic comments are now properly emitted, likely as of https://github.com/microsoft/TypeScript/pull/22141 which has been released with TypeScript 2.8. This change is required for running ngtsc as TypeScript plugin in Bazel's `ts_library` rule, to move away from the custom `ngc_wrapped` approach. Resolves FW-1952 PR Close #35932 --- packages/compiler-cli/src/ngtsc/program.ts | 11 ---- .../src/ngtsc/transform/src/transform.ts | 16 ++++- .../src/transformers/nocollapse_hack.ts | 58 ------------------- .../src/transformers/node_emitter.ts | 39 +++++++++---- .../transformers/node_emitter_transform.ts | 6 +- .../compiler-cli/src/transformers/program.ts | 16 ++--- .../src/transformers/r3_transform.ts | 5 +- .../test/transformers/nocollapse_hack_spec.ts | 26 --------- .../test/transformers/node_emitter_spec.ts | 2 +- .../test/transformers/r3_transform_spec.ts | 22 +++---- 10 files changed, 65 insertions(+), 136 deletions(-) delete mode 100644 packages/compiler-cli/src/transformers/nocollapse_hack.ts delete mode 100644 packages/compiler-cli/test/transformers/nocollapse_hack_spec.ts diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index 4ed3fb4a854fe..84a3f75397a53 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -10,7 +10,6 @@ import {GeneratedFile} from '@angular/compiler'; import * as ts from 'typescript'; import * as api from '../transformers/api'; -import {nocollapseHack} from '../transformers/nocollapse_hack'; import {verifySupportedTypeScriptVersion} from '../typescript_support'; import {NgCompilerHost} from './core'; @@ -193,16 +192,6 @@ export class NgtscProgram implements api.Program { this.compiler.incrementalDriver.recordSuccessfulEmit(writtenSf); } } - - // If Closure annotations are being produced, tsickle should be adding `@nocollapse` to - // any static fields present. However, tsickle doesn't yet handle synthetic fields added - // during other transformations, so this hack is in place to ensure Ivy definitions get - // properly annotated, pending an upstream fix in tsickle. - // - // TODO(alxhub): remove when tsickle properly annotates synthetic fields. - if (this.closureCompilerEnabled && fileName.endsWith('.js')) { - data = nocollapseHack(data); - } this.host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles); }; diff --git a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts index 23c7198e9749c..00ada93a58165 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts @@ -47,7 +47,8 @@ class IvyVisitor extends Visitor { constructor( private compilation: TraitCompiler, private reflector: ReflectionHost, private importManager: ImportManager, private defaultImportRecorder: DefaultImportRecorder, - private isCore: boolean, private constantPool: ConstantPool) { + private isClosureCompilerEnabled: boolean, private isCore: boolean, + private constantPool: ConstantPool) { super(); } @@ -73,6 +74,16 @@ class IvyVisitor extends Visitor { undefined, [ts.createToken(ts.SyntaxKind.StaticKeyword)], field.name, undefined, undefined, exprNode); + if (this.isClosureCompilerEnabled) { + // Closure compiler transforms the form `Service.ɵprov = X` into `Service$ɵprov = X`. To + // prevent this transformation, such assignments need to be annotated with @nocollapse. + // Note that tsickle is typically responsible for adding such annotations, however it + // doesn't yet handle synthetic fields added during other transformations. + ts.addSyntheticLeadingComment( + property, ts.SyntaxKind.MultiLineCommentTrivia, '* @nocollapse ', + /* hasTrailingNewLine */ false); + } + field.statements .map( stmt => translateStatement( @@ -215,7 +226,8 @@ function transformIvySourceFile( // Recursively scan through the AST and perform any updates requested by the IvyCompilation. const visitor = new IvyVisitor( - compilation, reflector, importManager, defaultImportRecorder, isCore, constantPool); + compilation, reflector, importManager, defaultImportRecorder, isClosureCompilerEnabled, + isCore, constantPool); let sf = visit(file, visitor, context); // Generate the constant statements first, as they may involve adding additional imports diff --git a/packages/compiler-cli/src/transformers/nocollapse_hack.ts b/packages/compiler-cli/src/transformers/nocollapse_hack.ts deleted file mode 100644 index 59cd5de80efe0..0000000000000 --- a/packages/compiler-cli/src/transformers/nocollapse_hack.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Closure compiler transforms the form `Service.ɵprov = X` into -// `Service$ɵprov = X`. To prevent this transformation, such assignments need to be -// annotated with @nocollapse. Unfortunately, a bug in Typescript where comments aren't propagated -// through the TS transformations precludes adding the comment via the AST. This workaround detects -// the static assignments to R3 properties such as ɵprov using a regex, as output files -// are written, and applies the annotation through regex replacement. -// -// TODO(alxhub): clean up once fix for TS transformers lands in upstream -// -// Typescript reference issue: https://github.com/Microsoft/TypeScript/issues/22497 - -// Pattern matching all Render3 property names. -const R3_DEF_NAME_PATTERN = [ - 'ɵcmp', - 'ɵdir', - 'ɵprov', - 'ɵinj', - 'ɵmod', - 'ɵpipe', - 'ɵfac', -].join('|'); - -// Pattern matching `Identifier.property` where property is a Render3 property. -const R3_DEF_ACCESS_PATTERN = `[^\\s\\.()[\\]]+\.(${R3_DEF_NAME_PATTERN})`; - -// Pattern matching a source line that contains a Render3 static property assignment. -// It declares two matching groups - one for the preceding whitespace, the second for the rest -// of the assignment expression. -const R3_DEF_LINE_PATTERN = `^(\\s*)(${R3_DEF_ACCESS_PATTERN} = .*)$`; - -// Regex compilation of R3_DEF_LINE_PATTERN. Matching group 1 yields the whitespace preceding the -// assignment, matching group 2 gives the rest of the assignment expressions. -const R3_MATCH_DEFS = new RegExp(R3_DEF_LINE_PATTERN, 'gmu'); - -const R3_TSICKLE_DECL_PATTERN = - `(\\/\\*\\*[*\\s]*)(@[^*]+\\*\\/\\s+[^.]+\\.(?:${R3_DEF_NAME_PATTERN});)`; - -const R3_MATCH_TSICKLE_DECL = new RegExp(R3_TSICKLE_DECL_PATTERN, 'gmu'); - -// Replacement string that complements R3_MATCH_DEFS. It inserts `/** @nocollapse */` before the -// assignment but after any indentation. Note that this will mess up any sourcemaps on this line -// (though there shouldn't be any, since Render3 properties are synthetic). -const R3_NOCOLLAPSE_DEFS = '$1\/** @nocollapse *\/ $2'; - -const R3_NOCOLLAPSE_TSICKLE_DECL = '$1@nocollapse $2'; - -export function nocollapseHack(contents: string): string { - return contents.replace(R3_MATCH_DEFS, R3_NOCOLLAPSE_DEFS) - .replace(R3_MATCH_TSICKLE_DECL, R3_NOCOLLAPSE_TSICKLE_DECL); -} diff --git a/packages/compiler-cli/src/transformers/node_emitter.ts b/packages/compiler-cli/src/transformers/node_emitter.ts index 1cd37b45e8e9d..9171982655197 100644 --- a/packages/compiler-cli/src/transformers/node_emitter.ts +++ b/packages/compiler-cli/src/transformers/node_emitter.ts @@ -20,9 +20,11 @@ const CATCH_STACK_NAME = 'stack'; const _VALID_IDENTIFIER_RE = /^[$A-Z_][0-9A-Z_$]*$/i; export class TypeScriptNodeEmitter { + constructor(private annotateForClosureCompiler: boolean) {} + updateSourceFile(sourceFile: ts.SourceFile, stmts: Statement[], preamble?: string): [ts.SourceFile, Map<ts.Node, Node>] { - const converter = new NodeEmitterVisitor(); + const converter = new NodeEmitterVisitor(this.annotateForClosureCompiler); // [].concat flattens the result so that each `visit...` method can also return an array of // stmts. const statements: any[] = [].concat( @@ -63,8 +65,8 @@ export class TypeScriptNodeEmitter { */ export function updateSourceFile( sourceFile: ts.SourceFile, module: PartialModule, - context: ts.TransformationContext): [ts.SourceFile, Map<ts.Node, Node>] { - const converter = new NodeEmitterVisitor(); + annotateForClosureCompiler: boolean): [ts.SourceFile, Map<ts.Node, Node>] { + const converter = new NodeEmitterVisitor(annotateForClosureCompiler); converter.loadExportedVariableIdentifiers(sourceFile); const prefixStatements = module.statements.filter(statement => !(statement instanceof ClassStmt)); @@ -192,6 +194,8 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { private _templateSources = new Map<ParseSourceFile, ts.SourceMapSource>(); private _exportedVariableIdentifiers = new Map<string, ts.Identifier>(); + constructor(private annotateForClosureCompiler: boolean) {} + /** * Process the source file and collect exported identifiers that refer to variables. * @@ -367,14 +371,27 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitDeclareClassStmt(stmt: ClassStmt) { const modifiers = this.getModifiers(stmt); - const fields = stmt.fields.map( - field => ts.createProperty( - /* decorators */ undefined, /* modifiers */ translateModifiers(field.modifiers), - field.name, - /* questionToken */ undefined, - /* type */ undefined, - field.initializer == null ? ts.createNull() : - field.initializer.visitExpression(this, null))); + const fields = stmt.fields.map(field => { + const property = ts.createProperty( + /* decorators */ undefined, /* modifiers */ translateModifiers(field.modifiers), + field.name, + /* questionToken */ undefined, + /* type */ undefined, + field.initializer == null ? ts.createNull() : + field.initializer.visitExpression(this, null)); + + if (this.annotateForClosureCompiler) { + // Closure compiler transforms the form `Service.ɵprov = X` into `Service$ɵprov = X`. To + // prevent this transformation, such assignments need to be annotated with @nocollapse. + // Note that tsickle is typically responsible for adding such annotations, however it + // doesn't yet handle synthetic fields added during other transformations. + ts.addSyntheticLeadingComment( + property, ts.SyntaxKind.MultiLineCommentTrivia, '* @nocollapse ', + /* hasTrailingNewLine */ false); + } + + return property; + }); const getters = stmt.getters.map( getter => ts.createGetAccessor( /* decorators */ undefined, /* modifiers */ undefined, getter.name, /* parameters */[], diff --git a/packages/compiler-cli/src/transformers/node_emitter_transform.ts b/packages/compiler-cli/src/transformers/node_emitter_transform.ts index fffdc8e13e32a..bd72bd06e269e 100644 --- a/packages/compiler-cli/src/transformers/node_emitter_transform.ts +++ b/packages/compiler-cli/src/transformers/node_emitter_transform.ts @@ -30,10 +30,10 @@ function getPreamble(original: string) { * list of statements as their body. */ export function getAngularEmitterTransformFactory( - generatedFiles: Map<string, GeneratedFile>, program: ts.Program): () => - (sourceFile: ts.SourceFile) => ts.SourceFile { + generatedFiles: Map<string, GeneratedFile>, program: ts.Program, + annotateForClosureCompiler: boolean): () => (sourceFile: ts.SourceFile) => ts.SourceFile { return function() { - const emitter = new TypeScriptNodeEmitter(); + const emitter = new TypeScriptNodeEmitter(annotateForClosureCompiler); return function(sourceFile: ts.SourceFile): ts.SourceFile { const g = generatedFiles.get(sourceFile.fileName); const orig = g && program.getSourceFile(g.srcFileUrl); diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index 3855bddf1bc76..eb631c4c2dae4 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -22,7 +22,6 @@ import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalRef import {InlineResourcesMetadataTransformer, getInlineResourcesTransformFactory} from './inline_resources'; import {LowerMetadataTransform, getExpressionLoweringTransformFactory} from './lower_expressions'; import {MetadataCache, MetadataTransformer} from './metadata_cache'; -import {nocollapseHack} from './nocollapse_hack'; import {getAngularEmitterTransformFactory} from './node_emitter_transform'; import {PartialModuleMetadataTransformer} from './r3_metadata_transform'; import {StripDecoratorsMetadataTransformer, getDecoratorStripTransformerFactory} from './r3_strip_decorators'; @@ -281,12 +280,6 @@ class AngularCompilerProgram implements Program { const writeTsFile: ts.WriteFileCallback = (outFileName, outData, writeByteOrderMark, onError?, sourceFiles?) => { - const sourceFile = sourceFiles && sourceFiles.length == 1 ? sourceFiles[0] : null; - let genFile: GeneratedFile|undefined; - if (this.options.annotateForClosureCompiler && sourceFile && - TS.test(sourceFile.fileName)) { - outData = nocollapseHack(outData); - } this.writeFile(outFileName, outData, writeByteOrderMark, onError, undefined, sourceFiles); }; @@ -377,9 +370,6 @@ class AngularCompilerProgram implements Program { emittedSourceFiles.push(originalFile); } } - if (this.options.annotateForClosureCompiler && TS.test(sourceFile.fileName)) { - outData = nocollapseHack(outData); - } } this.writeFile(outFileName, outData, writeByteOrderMark, onError, genFile, sourceFiles); }; @@ -572,11 +562,13 @@ class AngularCompilerProgram implements Program { getExpressionLoweringTransformFactory(this.loweringMetadataTransform, this.tsProgram)); metadataTransforms.push(this.loweringMetadataTransform); } + const annotateForClosureCompiler = this.options.annotateForClosureCompiler || false; if (genFiles) { - beforeTs.push(getAngularEmitterTransformFactory(genFiles, this.getTsProgram())); + beforeTs.push(getAngularEmitterTransformFactory( + genFiles, this.getTsProgram(), annotateForClosureCompiler)); } if (partialModules) { - beforeTs.push(getAngularClassTransformerFactory(partialModules)); + beforeTs.push(getAngularClassTransformerFactory(partialModules, annotateForClosureCompiler)); // If we have partial modules, the cached metadata might be incorrect as it doesn't reflect // the partial module transforms. diff --git a/packages/compiler-cli/src/transformers/r3_transform.ts b/packages/compiler-cli/src/transformers/r3_transform.ts index 5c21b8bc82e22..cf61b8ad2f312 100644 --- a/packages/compiler-cli/src/transformers/r3_transform.ts +++ b/packages/compiler-cli/src/transformers/r3_transform.ts @@ -17,7 +17,8 @@ export type TransformerFactory = (context: ts.TransformationContext) => Transfor /** * Returns a transformer that adds the requested static methods specified by modules. */ -export function getAngularClassTransformerFactory(modules: PartialModule[]): TransformerFactory { +export function getAngularClassTransformerFactory( + modules: PartialModule[], annotateForClosureCompiler: boolean): TransformerFactory { if (modules.length === 0) { // If no modules are specified, just return an identity transform. return () => sf => sf; @@ -27,7 +28,7 @@ export function getAngularClassTransformerFactory(modules: PartialModule[]): Tra return function(sourceFile: ts.SourceFile): ts.SourceFile { const module = moduleMap.get(sourceFile.fileName); if (module && module.statements.length > 0) { - const [newSourceFile] = updateSourceFile(sourceFile, module, context); + const [newSourceFile] = updateSourceFile(sourceFile, module, annotateForClosureCompiler); return newSourceFile; } return sourceFile; diff --git a/packages/compiler-cli/test/transformers/nocollapse_hack_spec.ts b/packages/compiler-cli/test/transformers/nocollapse_hack_spec.ts deleted file mode 100644 index 38742da4399e7..0000000000000 --- a/packages/compiler-cli/test/transformers/nocollapse_hack_spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {nocollapseHack} from '../../src/transformers/nocollapse_hack'; - -describe('@nocollapse hack', () => { - it('should add @nocollapse to a basic class', () => { - const decl = `Foo.ɵinj = define(...);`; - expect(nocollapseHack(decl)).toEqual('/** @nocollapse */ ' + decl); - }); - - it('should add nocollapse to an if (false) declaration of the kind generated by tsickle', () => { - const decl = ` - if (false) { - /** @type {?} */ - Foo.ɵinj; - } - `; - expect(nocollapseHack(decl)).toContain('/** @nocollapse @type {?} */'); - }); -}); diff --git a/packages/compiler-cli/test/transformers/node_emitter_spec.ts b/packages/compiler-cli/test/transformers/node_emitter_spec.ts index 9fdbe6ccbb009..c5e3ce09cb6b3 100644 --- a/packages/compiler-cli/test/transformers/node_emitter_spec.ts +++ b/packages/compiler-cli/test/transformers/node_emitter_spec.ts @@ -33,7 +33,7 @@ describe('TypeScriptNodeEmitter', () => { beforeEach(() => { context = new MockAotContext('/', FILES); host = new MockCompilerHost(context); - emitter = new TypeScriptNodeEmitter(); + emitter = new TypeScriptNodeEmitter(false); someVar = o.variable('someVar', null, null); }); diff --git a/packages/compiler-cli/test/transformers/r3_transform_spec.ts b/packages/compiler-cli/test/transformers/r3_transform_spec.ts index 992165f0867fb..5b893cf6dee69 100644 --- a/packages/compiler-cli/test/transformers/r3_transform_spec.ts +++ b/packages/compiler-cli/test/transformers/r3_transform_spec.ts @@ -40,14 +40,16 @@ describe('r3_transform_spec', () => { }); it('should be able to modify multiple classes in the same module', () => { - const result = emit(getAngularClassTransformerFactory([{ - fileName: someGenFileName, - statements: [ - classMethod(new o.ReturnStatement(o.variable('v')), ['v'], 'someMethod', 'SomeClass'), - classMethod( - new o.ReturnStatement(o.variable('v')), ['v'], 'someOtherMethod', 'SomeOtherClass') - ] - }])); + const result = emit(getAngularClassTransformerFactory( + [{ + fileName: someGenFileName, + statements: [ + classMethod(new o.ReturnStatement(o.variable('v')), ['v'], 'someMethod', 'SomeClass'), + classMethod( + new o.ReturnStatement(o.variable('v')), ['v'], 'someOtherMethod', 'SomeOtherClass') + ] + }], + false)); expect(result).toContain('static someMethod(v) { return v; }'); expect(result).toContain('static someOtherMethod(v) { return v; }'); }); @@ -94,7 +96,7 @@ describe('r3_transform_spec', () => { fileName: someGenFileName, statements: [classMethod(stmt, parameters, methodName, className)] }; - return emit(getAngularClassTransformerFactory([module])); + return emit(getAngularClassTransformerFactory([module], false)); } function emitStaticField( @@ -104,7 +106,7 @@ describe('r3_transform_spec', () => { fileName: someGenFileName, statements: [classField(initializer, fieldName, className)] }; - return emit(getAngularClassTransformerFactory([module])); + return emit(getAngularClassTransformerFactory([module], false)); } }); From e9de28111dbdede31181547c8686683203030ca0 Mon Sep 17 00:00:00 2001 From: crisbeto <crisbeto@abv.bg> Date: Thu, 19 Mar 2020 17:52:11 +0100 Subject: [PATCH 087/262] build: enable service-worker tests on saucelabs (#36129) Enables the `service-worker` tests on Saucelabs and fixes some issues that were preventing them from running on IE. The issues were: 1. We were serving es2017 code during tests. I've set it to es5. 2. The check which was verifying whether the environment is supported ended up hitting a `require` call in the browser which caused it to fail on browsers that don't support the `URL` API. PR Close #36129 --- packages/service-worker/test/BUILD.bazel | 8 ------ packages/service-worker/worker/BUILD.bazel | 2 -- .../service-worker/worker/testing/scope.ts | 6 +++++ packages/service-worker/worker/tsconfig.json | 27 ------------------- 4 files changed, 6 insertions(+), 37 deletions(-) delete mode 100644 packages/service-worker/worker/tsconfig.json diff --git a/packages/service-worker/test/BUILD.bazel b/packages/service-worker/test/BUILD.bazel index ab1c58812c5b4..16956f533a1a0 100644 --- a/packages/service-worker/test/BUILD.bazel +++ b/packages/service-worker/test/BUILD.bazel @@ -33,14 +33,6 @@ jasmine_node_test( karma_web_test_suite( name = "test_web", - tags = [ - # FIXME: fix on saucelabs - # ERROR: 'There is no timestamp for @angular/service-worker/worker/src/db-cache.js!' - # ERROR: 'There is no timestamp for @angular/service-worker/worker/src/driver.js!' - # ERROR: 'There is no timestamp for @angular/service-worker/worker/src/sha1.js!' - "fixme-saucelabs-ivy", - "fixme-saucelabs-ve", - ], deps = [ ":test_lib", ], diff --git a/packages/service-worker/worker/BUILD.bazel b/packages/service-worker/worker/BUILD.bazel index d520920c8795d..ac6bc10444d40 100644 --- a/packages/service-worker/worker/BUILD.bazel +++ b/packages/service-worker/worker/BUILD.bazel @@ -13,14 +13,12 @@ ts_library( "main.ts", ], ), - tsconfig = ":tsconfig.json", deps = ["@npm//@types/node"], ) ts_library( name = "main", srcs = ["main.ts"], - tsconfig = ":tsconfig.json", deps = [":worker"], ) diff --git a/packages/service-worker/worker/testing/scope.ts b/packages/service-worker/worker/testing/scope.ts index 0ae7d384a61ab..8b1bfb6f2b8ba 100644 --- a/packages/service-worker/worker/testing/scope.ts +++ b/packages/service-worker/worker/testing/scope.ts @@ -100,6 +100,12 @@ export class SwTestHarness implements ServiceWorkerGlobalScope, Adapter, Context return true; } + // If we're in a browser that doesn't support URL at this point, don't go any further + // since browser builds use requirejs which will fail on the `require` call below. + if (typeof window !== 'undefined' && window) { + return false; + } + // In older Node.js versions, the `URL` global does not exist. We can use `url` instead. const url = (typeof require === 'function') && require('url'); return url && (typeof url.parse === 'function') && (typeof url.resolve === 'function'); diff --git a/packages/service-worker/worker/tsconfig.json b/packages/service-worker/worker/tsconfig.json deleted file mode 100644 index f07a5d3baa907..0000000000000 --- a/packages/service-worker/worker/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "declaration": false, - "strict": true, - "module": "es2015", - "moduleResolution": "node", - "strictNullChecks": true, - "strictPropertyInitialization": true, - "outDir": "../../../dist/all/@angular/service-worker/worker-es2017", - "noImplicitAny": true, - "noFallthroughCasesInSwitch": true, - "rootDir": ".", - "inlineSourceMap": true, - "lib": ["es2015", "dom"], - "target": "es2017", - "typeRoots": [], - "types": [] - }, - "bazelOptions": { - "suppressTsconfigOverrideWarnings": true - }, - "files": [ - "main.ts", - "src/service-worker.d.ts" - ] -} From 8e55a112831dd255265f7cf0320d7fb82d36d7bb Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Tue, 11 Feb 2020 10:45:58 +0100 Subject: [PATCH 088/262] refactor(core): move schematic base classes logic into shared utils (#35339) Moves the `findBaseClassDeclarations` method into the shared schematic utilities. This method will be useful for future migrations, and for planned changes to the `undecorated-classes-with-decorated-fields` migration. PR Close #35339 --- .../migrations/undecorated-classes-with-di/transform.ts | 2 +- .../typescript}/find_base_classes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename packages/core/schematics/{migrations/undecorated-classes-with-di => utils/typescript}/find_base_classes.ts (92%) diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts index 32baa7d1b9e60..ac3d92e16dd32 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts @@ -13,11 +13,11 @@ import * as ts from 'typescript'; import {getAngularDecorators} from '../../utils/ng_decorators'; import {hasExplicitConstructor} from '../../utils/typescript/class_declaration'; +import {findBaseClassDeclarations} from '../../utils/typescript/find_base_classes'; import {getImportOfIdentifier} from '../../utils/typescript/imports'; import {UnexpectedMetadataValueError, convertDirectiveMetadataToExpression} from './decorator_rewrite/convert_directive_metadata'; import {DecoratorRewriter} from './decorator_rewrite/decorator_rewriter'; -import {findBaseClassDeclarations} from './find_base_classes'; import {ImportManager} from './import_manager'; import {hasDirectiveDecorator, hasInjectableDecorator} from './ng_declaration_collector'; import {UpdateRecorder} from './update_recorder'; diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/find_base_classes.ts b/packages/core/schematics/utils/typescript/find_base_classes.ts similarity index 92% rename from packages/core/schematics/migrations/undecorated-classes-with-di/find_base_classes.ts rename to packages/core/schematics/utils/typescript/find_base_classes.ts index 01467b745d93c..ae075bce15bb2 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/find_base_classes.ts +++ b/packages/core/schematics/utils/typescript/find_base_classes.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {getBaseTypeIdentifiers} from '../../utils/typescript/class_declaration'; +import {getBaseTypeIdentifiers} from './class_declaration'; /** Gets all base class declarations of the specified class declaration. */ export function findBaseClassDeclarations(node: ts.ClassDeclaration, typeChecker: ts.TypeChecker) { From 23664802504d6b4bfd6869fbe6a982ff21c22ab2 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Tue, 11 Feb 2020 10:50:29 +0100 Subject: [PATCH 089/262] refactor(core): move schematic import manager to shared utils (#35339) The import manager has been created for both the `missing-injectable` and `undecorated-classes-with-di` migration. Both initial PRs brought in the manager class, so the manager is duplicated in the schematics. In order to reduce this duplication, and to expose the manager to other schematics/migrations, we move it into the shared schematic utils. PR Close #35339 --- .../missing-injectable/transform.ts | 3 +- .../missing-injectable/update_recorder.ts | 5 +- .../decorator_rewrite/decorator_rewriter.ts | 3 +- .../import_rewrite_visitor.ts | 3 +- .../import_manager.ts | 254 ------------------ .../undecorated-classes-with-di/transform.ts | 2 +- .../update_recorder.ts | 5 +- .../import_manager.ts | 9 +- 8 files changed, 18 insertions(+), 266 deletions(-) delete mode 100644 packages/core/schematics/migrations/undecorated-classes-with-di/import_manager.ts rename packages/core/schematics/{migrations/missing-injectable => utils}/import_manager.ts (97%) diff --git a/packages/core/schematics/migrations/missing-injectable/transform.ts b/packages/core/schematics/migrations/missing-injectable/transform.ts index d0412974e0032..c70e75b12dc5d 100644 --- a/packages/core/schematics/migrations/missing-injectable/transform.ts +++ b/packages/core/schematics/migrations/missing-injectable/transform.ts @@ -11,14 +11,15 @@ import {DynamicValue, ResolvedValue} from '@angular/compiler-cli/src/ngtsc/parti import {TypeScriptReflectionHost} from '@angular/compiler-cli/src/ngtsc/reflection'; import * as ts from 'typescript'; +import {ImportManager} from '../../utils/import_manager'; import {getAngularDecorators} from '../../utils/ng_decorators'; import {ResolvedDirective, ResolvedNgModule} from './definition_collector'; -import {ImportManager} from './import_manager'; import {ProviderLiteral, ProvidersEvaluator} from './providers_evaluator'; import {UpdateRecorder} from './update_recorder'; + /** Name of decorators which imply that a given class does not need to be migrated. */ const NO_MIGRATE_DECORATORS = ['Injectable', 'Directive', 'Component', 'Pipe']; diff --git a/packages/core/schematics/migrations/missing-injectable/update_recorder.ts b/packages/core/schematics/migrations/missing-injectable/update_recorder.ts index 80fc670f1505a..0e2ad3ee0db50 100644 --- a/packages/core/schematics/migrations/missing-injectable/update_recorder.ts +++ b/packages/core/schematics/migrations/missing-injectable/update_recorder.ts @@ -7,15 +7,14 @@ */ import * as ts from 'typescript'; +import {ImportManagerUpdateRecorder} from '../../utils/import_manager'; /** * Update recorder interface that is used to transform source files in a non-colliding * way. Also this indirection makes it possible to re-use logic for both TSLint rules * and CLI devkit schematic updates. */ -export interface UpdateRecorder { - addNewImport(start: number, importText: string): void; - updateExistingImport(namedBindings: ts.NamedImports, newNamedBindings: string): void; +export interface UpdateRecorder extends ImportManagerUpdateRecorder { addClassDecorator(node: ts.ClassDeclaration, text: string, className: string): void; replaceDecorator(node: ts.Decorator, newText: string, className: string): void; updateObjectLiteral(node: ts.ObjectLiteralExpression, newText: string): void; diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts index f2b2c4cf3244d..fa34c27d63463 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts @@ -10,12 +10,13 @@ import {AotCompiler} from '@angular/compiler'; import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluator'; import * as ts from 'typescript'; +import {ImportManager} from '../../../utils/import_manager'; import {NgDecorator} from '../../../utils/ng_decorators'; import {unwrapExpression} from '../../../utils/typescript/functions'; -import {ImportManager} from '../import_manager'; import {ImportRewriteTransformerFactory, UnresolvedIdentifierError} from './import_rewrite_visitor'; + /** * Class that can be used to copy decorators to a new location. The rewriter ensures that * identifiers and imports are rewritten to work in the new file location. Fields in a diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts index 417687615885c..3003e9cc276a7 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts @@ -10,13 +10,14 @@ import {AotCompilerHost} from '@angular/compiler'; import {dirname, resolve} from 'path'; import * as ts from 'typescript'; +import {ImportManager} from '../../../utils/import_manager'; import {Import, getImportOfIdentifier} from '../../../utils/typescript/imports'; import {getValueSymbolOfDeclaration} from '../../../utils/typescript/symbol'; -import {ImportManager} from '../import_manager'; import {getPosixPath} from './path_format'; import {ResolvedExport, getExportSymbolsOfFile} from './source_file_exports'; + /** * Factory that creates a TypeScript transformer which ensures that * referenced identifiers are available at the target file location. diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/import_manager.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/import_manager.ts deleted file mode 100644 index 8bc46eca1f9ff..0000000000000 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/import_manager.ts +++ /dev/null @@ -1,254 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {dirname, resolve} from 'path'; -import * as ts from 'typescript'; -import {UpdateRecorder} from './update_recorder'; - -/** - * Import manager that can be used to add TypeScript imports to given source - * files. The manager ensures that multiple transformations are applied properly - * without shifted offsets and that similar existing import declarations are re-used. - */ -export class ImportManager { - /** Map of import declarations that need to be updated to include the given symbols. */ - private updatedImports = - new Map<ts.ImportDeclaration, {propertyName?: ts.Identifier, importName: ts.Identifier}[]>(); - /** Map of source-files and their previously used identifier names. */ - private usedIdentifierNames = new Map<ts.SourceFile, string[]>(); - /** - * Array of previously resolved symbol imports. Cache can be re-used to return - * the same identifier without checking the source-file again. - */ - private importCache: { - sourceFile: ts.SourceFile, - symbolName: string|null, - moduleName: string, - identifier: ts.Identifier - }[] = []; - - constructor( - private getUpdateRecorder: (sf: ts.SourceFile) => UpdateRecorder, - private printer: ts.Printer) {} - - /** - * Adds an import to the given source-file and returns the TypeScript - * identifier that can be used to access the newly imported symbol. - */ - addImportToSourceFile( - sourceFile: ts.SourceFile, symbolName: string|null, moduleName: string, - typeImport = false): ts.Expression { - const sourceDir = dirname(sourceFile.fileName); - let importStartIndex = 0; - let existingImport: ts.ImportDeclaration|null = null; - - // In case the given import has been already generated previously, we just return - // the previous generated identifier in order to avoid duplicate generated imports. - const cachedImport = this.importCache.find( - c => c.sourceFile === sourceFile && c.symbolName === symbolName && - c.moduleName === moduleName); - if (cachedImport) { - return cachedImport.identifier; - } - - // Walk through all source-file top-level statements and search for import declarations - // that already match the specified "moduleName" and can be updated to import the - // given symbol. If no matching import can be found, the last import in the source-file - // will be used as starting point for a new import that will be generated. - for (let i = sourceFile.statements.length - 1; i >= 0; i--) { - const statement = sourceFile.statements[i]; - - if (!ts.isImportDeclaration(statement) || !ts.isStringLiteral(statement.moduleSpecifier) || - !statement.importClause) { - continue; - } - - if (importStartIndex === 0) { - importStartIndex = this._getEndPositionOfNode(statement); - } - - const moduleSpecifier = statement.moduleSpecifier.text; - - if (moduleSpecifier.startsWith('.') && - resolve(sourceDir, moduleSpecifier) !== resolve(sourceDir, moduleName) || - moduleSpecifier !== moduleName) { - continue; - } - - if (statement.importClause.namedBindings) { - const namedBindings = statement.importClause.namedBindings; - - // In case a "Type" symbol is imported, we can't use namespace imports - // because these only export symbols available at runtime (no types) - if (ts.isNamespaceImport(namedBindings) && !typeImport) { - return ts.createPropertyAccess( - ts.createIdentifier(namedBindings.name.text), - ts.createIdentifier(symbolName || 'default')); - } else if (ts.isNamedImports(namedBindings) && symbolName) { - const existingElement = namedBindings.elements.find( - e => - e.propertyName ? e.propertyName.text === symbolName : e.name.text === symbolName); - - if (existingElement) { - return ts.createIdentifier(existingElement.name.text); - } - - // In case the symbol could not be found in an existing import, we - // keep track of the import declaration as it can be updated to include - // the specified symbol name without having to create a new import. - existingImport = statement; - } - } else if (statement.importClause.name && !symbolName) { - return ts.createIdentifier(statement.importClause.name.text); - } - } - - if (existingImport) { - const propertyIdentifier = ts.createIdentifier(symbolName !); - const generatedUniqueIdentifier = this._getUniqueIdentifier(sourceFile, symbolName !); - const needsGeneratedUniqueName = generatedUniqueIdentifier.text !== symbolName; - const importName = needsGeneratedUniqueName ? generatedUniqueIdentifier : propertyIdentifier; - - // Since it can happen that multiple classes need to be imported within the - // specified source file and we want to add the identifiers to the existing - // import declaration, we need to keep track of the updated import declarations. - // We can't directly update the import declaration for each identifier as this - // would throw off the recorder offsets. We need to keep track of the new identifiers - // for the import and perform the import transformation as batches per source-file. - this.updatedImports.set( - existingImport, (this.updatedImports.get(existingImport) || []).concat({ - propertyName: needsGeneratedUniqueName ? propertyIdentifier : undefined, - importName: importName, - })); - - // Keep track of all updated imports so that we don't generate duplicate - // similar imports as these can't be statically analyzed in the source-file yet. - this.importCache.push({sourceFile, moduleName, symbolName, identifier: importName}); - - return importName; - } - - let identifier: ts.Identifier|null = null; - let newImport: ts.ImportDeclaration|null = null; - - if (symbolName) { - const propertyIdentifier = ts.createIdentifier(symbolName); - const generatedUniqueIdentifier = this._getUniqueIdentifier(sourceFile, symbolName); - const needsGeneratedUniqueName = generatedUniqueIdentifier.text !== symbolName; - identifier = needsGeneratedUniqueName ? generatedUniqueIdentifier : propertyIdentifier; - - newImport = ts.createImportDeclaration( - undefined, undefined, - ts.createImportClause( - undefined, - ts.createNamedImports([ts.createImportSpecifier( - needsGeneratedUniqueName ? propertyIdentifier : undefined, identifier)])), - ts.createStringLiteral(moduleName)); - } else { - identifier = this._getUniqueIdentifier(sourceFile, 'defaultExport'); - newImport = ts.createImportDeclaration( - undefined, undefined, ts.createImportClause(identifier, undefined), - ts.createStringLiteral(moduleName)); - } - - const newImportText = this.printer.printNode(ts.EmitHint.Unspecified, newImport, sourceFile); - // If the import is generated at the start of the source file, we want to add - // a new-line after the import. Otherwise if the import is generated after an - // existing import, we need to prepend a new-line so that the import is not on - // the same line as the existing import anchor. - this.getUpdateRecorder(sourceFile) - .addNewImport( - importStartIndex, importStartIndex === 0 ? `${newImportText}\n` : `\n${newImportText}`); - - // Keep track of all generated imports so that we don't generate duplicate - // similar imports as these can't be statically analyzed in the source-file yet. - this.importCache.push({sourceFile, symbolName, moduleName, identifier}); - - return identifier; - } - - /** - * Stores the collected import changes within the appropriate update recorders. The - * updated imports can only be updated *once* per source-file because previous updates - * could otherwise shift the source-file offsets. - */ - recordChanges() { - this.updatedImports.forEach((expressions, importDecl) => { - const sourceFile = importDecl.getSourceFile(); - const recorder = this.getUpdateRecorder(sourceFile); - const namedBindings = importDecl.importClause !.namedBindings as ts.NamedImports; - const newNamedBindings = ts.updateNamedImports( - namedBindings, - namedBindings.elements.concat(expressions.map( - ({propertyName, importName}) => ts.createImportSpecifier(propertyName, importName)))); - - const newNamedBindingsText = - this.printer.printNode(ts.EmitHint.Unspecified, newNamedBindings, sourceFile); - recorder.updateExistingImport(namedBindings, newNamedBindingsText); - }); - } - - /** Gets an unique identifier with a base name for the given source file. */ - private _getUniqueIdentifier(sourceFile: ts.SourceFile, baseName: string): ts.Identifier { - if (this.isUniqueIdentifierName(sourceFile, baseName)) { - this._recordUsedIdentifier(sourceFile, baseName); - return ts.createIdentifier(baseName); - } - - let name = null; - let counter = 1; - do { - name = `${baseName}_${counter++}`; - } while (!this.isUniqueIdentifierName(sourceFile, name)); - - this._recordUsedIdentifier(sourceFile, name !); - return ts.createIdentifier(name !); - } - - /** - * Checks whether the specified identifier name is used within the given - * source file. - */ - private isUniqueIdentifierName(sourceFile: ts.SourceFile, name: string) { - if (this.usedIdentifierNames.has(sourceFile) && - this.usedIdentifierNames.get(sourceFile) !.indexOf(name) !== -1) { - return false; - } - - // Walk through the source file and search for an identifier matching - // the given name. In that case, it's not guaranteed that this name - // is unique in the given declaration scope and we just return false. - const nodeQueue: ts.Node[] = [sourceFile]; - while (nodeQueue.length) { - const node = nodeQueue.shift() !; - if (ts.isIdentifier(node) && node.text === name) { - return false; - } - nodeQueue.push(...node.getChildren()); - } - return true; - } - - private _recordUsedIdentifier(sourceFile: ts.SourceFile, identifierName: string) { - this.usedIdentifierNames.set( - sourceFile, (this.usedIdentifierNames.get(sourceFile) || []).concat(identifierName)); - } - - /** - * Determines the full end of a given node. By default the end position of a node is - * before all trailing comments. This could mean that generated imports shift comments. - */ - private _getEndPositionOfNode(node: ts.Node) { - const nodeEndPos = node.getEnd(); - const commentRanges = ts.getTrailingCommentRanges(node.getSourceFile().text, nodeEndPos); - if (!commentRanges || !commentRanges.length) { - return nodeEndPos; - } - return commentRanges[commentRanges.length - 1] !.end; - } -} diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts index ac3d92e16dd32..5ec39b6e3eb7a 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts @@ -11,6 +11,7 @@ import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluato import {ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core'; import * as ts from 'typescript'; +import {ImportManager} from '../../utils/import_manager'; import {getAngularDecorators} from '../../utils/ng_decorators'; import {hasExplicitConstructor} from '../../utils/typescript/class_declaration'; import {findBaseClassDeclarations} from '../../utils/typescript/find_base_classes'; @@ -18,7 +19,6 @@ import {getImportOfIdentifier} from '../../utils/typescript/imports'; import {UnexpectedMetadataValueError, convertDirectiveMetadataToExpression} from './decorator_rewrite/convert_directive_metadata'; import {DecoratorRewriter} from './decorator_rewrite/decorator_rewriter'; -import {ImportManager} from './import_manager'; import {hasDirectiveDecorator, hasInjectableDecorator} from './ng_declaration_collector'; import {UpdateRecorder} from './update_recorder'; diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/update_recorder.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/update_recorder.ts index baa341ecce2f8..ed5ee2b2a942d 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/update_recorder.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/update_recorder.ts @@ -8,15 +8,14 @@ */ import * as ts from 'typescript'; +import {ImportManagerUpdateRecorder} from '../../utils/import_manager'; /** * Update recorder interface that is used to transform source files in a non-colliding * way. Also this indirection makes it possible to re-use transformation logic with * different replacement tools (e.g. TSLint or CLI devkit). */ -export interface UpdateRecorder { - addNewImport(start: number, importText: string): void; - updateExistingImport(namedBindings: ts.NamedImports, newNamedBindings: string): void; +export interface UpdateRecorder extends ImportManagerUpdateRecorder { addClassDecorator(node: ts.ClassDeclaration, text: string): void; addClassComment(node: ts.ClassDeclaration, text: string): void; commitUpdate(): void; diff --git a/packages/core/schematics/migrations/missing-injectable/import_manager.ts b/packages/core/schematics/utils/import_manager.ts similarity index 97% rename from packages/core/schematics/migrations/missing-injectable/import_manager.ts rename to packages/core/schematics/utils/import_manager.ts index 8bc46eca1f9ff..12a9b6cbcc33b 100644 --- a/packages/core/schematics/migrations/missing-injectable/import_manager.ts +++ b/packages/core/schematics/utils/import_manager.ts @@ -8,7 +8,12 @@ import {dirname, resolve} from 'path'; import * as ts from 'typescript'; -import {UpdateRecorder} from './update_recorder'; + +/** Update recorder for managing imports. */ +export interface ImportManagerUpdateRecorder { + addNewImport(start: number, importText: string): void; + updateExistingImport(namedBindings: ts.NamedImports, newNamedBindings: string): void; +} /** * Import manager that can be used to add TypeScript imports to given source @@ -33,7 +38,7 @@ export class ImportManager { }[] = []; constructor( - private getUpdateRecorder: (sf: ts.SourceFile) => UpdateRecorder, + private getUpdateRecorder: (sf: ts.SourceFile) => ImportManagerUpdateRecorder, private printer: ts.Printer) {} /** From 32eafef6a715d25a939f757f9c0b149b4a4113a4 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Tue, 11 Feb 2020 16:33:20 +0100 Subject: [PATCH 090/262] fix(core): undecorated-classes-with-decorated-fields migration does not decorate derived classes (#35339) The `undecorated-classes-with-decorated-fields` migration has been introduced with 904a2018e0d3394ad91ffb6472f8271af7845295, but misses logic for decorating derived classes of undecorated classes which use Angular features. Example scenario: ```ts export abstract class MyBaseClass { @Input() someInput = true; } export abstract class BaseClassTwo extends MyBaseClass {} @Component(...) export class MyButton extends BaseClassTwo {} ``` Both abstract classes would need to be migrated. Previously, the migration only added `@Directive()` to `MyBaseClass`, but with this change, it also decorates `BaseClassTwo`. This is necessary because the Angular Compiler requires `BaseClassTwo` to have a directive definition when it flattens the directive metadata for `MyButton` in order to perform type checking. Technically, not decorating `BaseClassTwo` does not break at runtime. We basically want to enforce consistent use of `@Directive` to simplify the mental model. [See the migration guide](https://angular.io/guide/migration-undecorated-classes#migrating-classes-that-use-field-decorators). Fixes #34376. PR Close #35339 --- .../schematics/migrations/google3/BUILD.bazel | 1 + ...decoratedClassesWithDecoratedFieldsRule.ts | 65 +++++------- .../BUILD.bazel | 1 + .../google3/BUILD.bazel | 13 +++ .../google3/tslint_update_recorder.ts | 49 +++++++++ .../index.ts | 76 +++++++------ .../transform.ts | 100 ++++++++++++++++++ .../update_recorder.ts | 19 ++++ .../utils.ts | 71 ------------- ...ated_classes_with_decorated_fields_spec.ts | 54 +++++++++- ...es_with_decorated_fields_migration_spec.ts | 53 ++++++++++ 11 files changed, 361 insertions(+), 141 deletions(-) create mode 100644 packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/BUILD.bazel create mode 100644 packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts create mode 100644 packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts create mode 100644 packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/update_recorder.ts delete mode 100644 packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/utils.ts diff --git a/packages/core/schematics/migrations/google3/BUILD.bazel b/packages/core/schematics/migrations/google3/BUILD.bazel index d078463aefbc9..1a68dcf1d0aad 100644 --- a/packages/core/schematics/migrations/google3/BUILD.bazel +++ b/packages/core/schematics/migrations/google3/BUILD.bazel @@ -13,6 +13,7 @@ ts_library( "//packages/core/schematics/migrations/static-queries", "//packages/core/schematics/migrations/template-var-assignment", "//packages/core/schematics/migrations/undecorated-classes-with-decorated-fields", + "//packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3", "//packages/core/schematics/utils", "//packages/core/schematics/utils/tslint", "@npm//tslint", diff --git a/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts b/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts index b260f63b99a00..9a1150a9aad44 100644 --- a/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts +++ b/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts @@ -6,12 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Replacement, RuleFailure, Rules} from 'tslint'; +import {RuleFailure, Rules} from 'tslint'; import * as ts from 'typescript'; - -import {FALLBACK_DECORATOR, addImport, getNamedImports, getUndecoratedClassesWithDecoratedFields, hasNamedImport} from '../undecorated-classes-with-decorated-fields/utils'; - - +import {TslintUpdateRecorder} from '../undecorated-classes-with-decorated-fields/google3/tslint_update_recorder'; +import {UndecoratedClassesWithDecoratedFieldsTransform} from '../undecorated-classes-with-decorated-fields/transform'; /** * TSLint rule that adds an Angular decorator to classes that have Angular field decorators. @@ -20,37 +18,32 @@ import {FALLBACK_DECORATOR, addImport, getNamedImports, getUndecoratedClassesWit export class Rule extends Rules.TypedRule { applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] { const typeChecker = program.getTypeChecker(); - const printer = ts.createPrinter(); - const classes = getUndecoratedClassesWithDecoratedFields(sourceFile, typeChecker); - - return classes.map((current, index) => { - const {classDeclaration: declaration, importDeclaration} = current; - const name = declaration.name; - - // Set the class identifier node (if available) as the failing node so IDEs don't highlight - // the entire class with red. This is similar to how errors are shown for classes in other - // cases like an interface not being implemented correctly. - const start = (name || declaration).getStart(); - const end = (name || declaration).getEnd(); - const fixes = [Replacement.appendText(declaration.getStart(), `@${FALLBACK_DECORATOR}()\n`)]; - - // If it's the first class that we're processing in this file, add `Directive` to the imports. - if (index === 0 && !hasNamedImport(importDeclaration, FALLBACK_DECORATOR)) { - const namedImports = getNamedImports(importDeclaration); - - if (namedImports) { - fixes.push(new Replacement( - namedImports.getStart(), namedImports.getWidth(), - printer.printNode( - ts.EmitHint.Unspecified, addImport(namedImports, FALLBACK_DECORATOR), - sourceFile))); - } + const ruleName = this.ruleName; + const sourceFiles = program.getSourceFiles().filter( + s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s)); + const updateRecorders = new Map<ts.SourceFile, TslintUpdateRecorder>(); + const transform = + new UndecoratedClassesWithDecoratedFieldsTransform(typeChecker, getUpdateRecorder); + + // Migrate all source files in the project. + transform.migrate(sourceFiles); + + // Record the changes collected in the import manager. + transform.recordChanges(); + + if (updateRecorders.has(sourceFile)) { + return updateRecorders.get(sourceFile) !.failures; + } + return []; + + /** Gets the update recorder for the specified source file. */ + function getUpdateRecorder(sourceFile: ts.SourceFile): TslintUpdateRecorder { + if (updateRecorders.has(sourceFile)) { + return updateRecorders.get(sourceFile) !; } - - return new RuleFailure( - sourceFile, start, end, - 'Classes with decorated fields must have an Angular decorator as well.', - 'undecorated-classes-with-decorated-fields', fixes); - }); + const recorder = new TslintUpdateRecorder(ruleName, sourceFile); + updateRecorders.set(sourceFile, recorder); + return recorder; + } } } diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel index 3bfb1119043cf..9831bbf557c74 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel @@ -7,6 +7,7 @@ ts_library( visibility = [ "//packages/core/schematics:__pkg__", "//packages/core/schematics/migrations/google3:__pkg__", + "//packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3:__pkg__", "//packages/core/schematics/test:__pkg__", ], deps = [ diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/BUILD.bazel b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/BUILD.bazel new file mode 100644 index 0000000000000..8950f5665253e --- /dev/null +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/BUILD.bazel @@ -0,0 +1,13 @@ +load("//tools:defaults.bzl", "ts_library") + +ts_library( + name = "google3", + srcs = glob(["**/*.ts"]), + tsconfig = "//packages/core/schematics:tsconfig.json", + visibility = ["//packages/core/schematics/migrations/google3:__pkg__"], + deps = [ + "//packages/core/schematics/migrations/undecorated-classes-with-decorated-fields", + "@npm//tslint", + "@npm//typescript", + ], +) diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts new file mode 100644 index 0000000000000..5dc825721b668 --- /dev/null +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts @@ -0,0 +1,49 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Replacement, RuleFailure} from 'tslint'; +import * as ts from 'typescript'; + +import {UpdateRecorder} from '../update_recorder'; + +export class TslintUpdateRecorder implements UpdateRecorder { + failures: RuleFailure[] = []; + + constructor(private ruleName: string, private sourceFile: ts.SourceFile) {} + + /** Adds the specified decorator to the given class declaration. */ + addClassDecorator(node: ts.ClassDeclaration, decoratorText: string) { + // Adding a decorator should be the last replacement. Replacements/rule failures + // are handled in reverse and in case a decorator and import are inserted at + // the start of the file, the class decorator should come after the import. + this.failures.unshift(new RuleFailure( + this.sourceFile, node.getStart(), 0, `Class needs to be decorated with ` + + `"${decoratorText}" because it uses Angular features.`, + this.ruleName, Replacement.appendText(node.getStart(), `${decoratorText}\n`))); + } + + /** Adds the specified import to the source file at the given position */ + addNewImport(start: number, importText: string) { + this.failures.push(new RuleFailure( + this.sourceFile, start, 0, `Source file needs to have import: "${importText}"`, + this.ruleName, Replacement.appendText(start, importText))); + } + + /** Updates existing named imports to the given new named imports. */ + updateExistingImport(namedBindings: ts.NamedImports, newNamedBindings: string): void { + const fix = [ + Replacement.deleteText(namedBindings.getStart(), namedBindings.getWidth()), + Replacement.appendText(namedBindings.getStart(), newNamedBindings), + ]; + this.failures.push(new RuleFailure( + this.sourceFile, namedBindings.getStart(), namedBindings.getEnd(), + `Import needs to be updated to import symbols: "${newNamedBindings}"`, this.ruleName, fix)); + } + + commitUpdate() {} +} diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts index 87dafe4f60a54..a911f4c79bd51 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts @@ -6,21 +6,21 @@ * found in the LICENSE file at https://angular.io/license */ -import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; +import {Rule, SchematicsException, Tree,} from '@angular-devkit/schematics'; import {dirname, relative} from 'path'; import * as ts from 'typescript'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; -import {FALLBACK_DECORATOR, addImport, getNamedImports, getUndecoratedClassesWithDecoratedFields, hasNamedImport} from './utils'; - +import {UpdateRecorder} from './update_recorder'; +import {UndecoratedClassesWithDecoratedFieldsTransform} from './transform'; /** * Migration that adds an Angular decorator to classes that have Angular field decorators. * https://hackmd.io/vuQfavzfRG6KUCtU7oK_EA */ export default function(): Rule { - return (tree: Tree, context: SchematicContext) => { + return (tree: Tree) => { const {buildPaths, testPaths} = getProjectTsConfigPaths(tree); const basePath = process.cwd(); const allPaths = [...buildPaths, ...testPaths]; @@ -41,39 +41,49 @@ function runUndecoratedClassesMigration(tree: Tree, tsconfigPath: string, basePa const host = createMigrationCompilerHost(tree, parsed.options, basePath); const program = ts.createProgram(parsed.fileNames, parsed.options, host); const typeChecker = program.getTypeChecker(); - const printer = ts.createPrinter(); const sourceFiles = program.getSourceFiles().filter( file => !file.isDeclarationFile && !program.isSourceFileFromExternalLibrary(file)); + const updateRecorders = new Map<ts.SourceFile, UpdateRecorder>(); + const transform = + new UndecoratedClassesWithDecoratedFieldsTransform(typeChecker, getUpdateRecorder); - sourceFiles.forEach(sourceFile => { - const classes = getUndecoratedClassesWithDecoratedFields(sourceFile, typeChecker); - - if (classes.length === 0) { - return; - } - - const update = tree.beginUpdate(relative(basePath, sourceFile.fileName)); - - classes.forEach((current, index) => { - // If it's the first class that we're processing in this file, add `Directive` to the imports. - if (index === 0 && !hasNamedImport(current.importDeclaration, FALLBACK_DECORATOR)) { - const namedImports = getNamedImports(current.importDeclaration); + // Migrate all source files in the project. + transform.migrate(sourceFiles); - if (namedImports) { - update.remove(namedImports.getStart(), namedImports.getWidth()); - update.insertRight( - namedImports.getStart(), - printer.printNode( - ts.EmitHint.Unspecified, addImport(namedImports, FALLBACK_DECORATOR), - sourceFile)); - } - } + // Record the changes collected in the import manager. + transform.recordChanges(); - // We don't need to go through the AST to insert the decorator, because the change - // is pretty basic. Also this has a better chance of preserving the user's formatting. - update.insertLeft(current.classDeclaration.getStart(), `@${FALLBACK_DECORATOR}()\n`); - }); + // Walk through each update recorder and commit the update. We need to commit the + // updates in batches per source file as there can be only one recorder per source + // file in order to avoid shifted character offsets. + updateRecorders.forEach(recorder => recorder.commitUpdate()); - tree.commitUpdate(update); - }); + /** Gets the update recorder for the specified source file. */ + function getUpdateRecorder(sourceFile: ts.SourceFile): UpdateRecorder { + if (updateRecorders.has(sourceFile)) { + return updateRecorders.get(sourceFile) !; + } + const treeRecorder = tree.beginUpdate(relative(basePath, sourceFile.fileName)); + const recorder: UpdateRecorder = { + addClassDecorator(node: ts.ClassDeclaration, text: string) { + // New imports should be inserted at the left while decorators should be inserted + // at the right in order to ensure that imports are inserted before the decorator + // if the start position of import and decorator is the source file start. + treeRecorder.insertRight(node.getStart(), `${text}\n`); + }, + addNewImport(start: number, importText: string) { + // New imports should be inserted at the left while decorators should be inserted + // at the right in order to ensure that imports are inserted before the decorator + // if the start position of import and decorator is the source file start. + treeRecorder.insertLeft(start, importText); + }, + updateExistingImport(namedBindings: ts.NamedImports, newNamedBindings: string) { + treeRecorder.remove(namedBindings.getStart(), namedBindings.getWidth()); + treeRecorder.insertRight(namedBindings.getStart(), newNamedBindings); + }, + commitUpdate() { tree.commitUpdate(treeRecorder); } + }; + updateRecorders.set(sourceFile, recorder); + return recorder; + } } diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts new file mode 100644 index 0000000000000..990323a76cef3 --- /dev/null +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts @@ -0,0 +1,100 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; + +import {ImportManager} from '../../utils/import_manager'; +import {getAngularDecorators} from '../../utils/ng_decorators'; +import {findBaseClassDeclarations} from '../../utils/typescript/find_base_classes'; + +import {UpdateRecorder} from './update_recorder'; + +export class UndecoratedClassesWithDecoratedFieldsTransform { + private printer = ts.createPrinter(); + private importManager = new ImportManager(this.getUpdateRecorder, this.printer); + + constructor( + private typeChecker: ts.TypeChecker, + private getUpdateRecorder: (sf: ts.SourceFile) => UpdateRecorder) {} + + /** + * Migrates the specified source files. The transform adds the abstract `@Directive` + * decorator to classes that have Angular field decorators but are not decorated. + * https://hackmd.io/vuQfavzfRG6KUCtU7oK_EA + */ + migrate(sourceFiles: ts.SourceFile[]) { + this._findUndecoratedDirectives(sourceFiles).forEach(node => { + const sourceFile = node.getSourceFile(); + const recorder = this.getUpdateRecorder(sourceFile); + const directiveExpr = + this.importManager.addImportToSourceFile(sourceFile, 'Directive', '@angular/core'); + const decoratorExpr = ts.createDecorator(ts.createCall(directiveExpr, undefined, undefined)); + recorder.addClassDecorator( + node, this.printer.printNode(ts.EmitHint.Unspecified, decoratorExpr, sourceFile)); + }); + } + + /** Records all changes that were made in the import manager. */ + recordChanges() { this.importManager.recordChanges(); } + + /** Finds undecorated directives in the specified source files. */ + private _findUndecoratedDirectives(sourceFiles: ts.SourceFile[]) { + const typeChecker = this.typeChecker; + const undecoratedDirectives = new Set<ts.ClassDeclaration>(); + const undecoratedClasses = new Set<ts.ClassDeclaration>(); + const decoratedDirectives = new WeakSet<ts.ClassDeclaration>(); + + const visitNode = (node: ts.Node) => { + node.forEachChild(visitNode); + if (!ts.isClassDeclaration(node)) { + return; + } + const ngDecorators = node.decorators && getAngularDecorators(typeChecker, node.decorators); + const isDirectiveOrComponent = ngDecorators !== undefined && + ngDecorators.some(({name}) => name === 'Directive' || name === 'Component'); + if (isDirectiveOrComponent) { + decoratedDirectives.add(node); + } else { + if (this._hasAngularDecoratedClassMember(node)) { + undecoratedDirectives.add(node); + } else { + undecoratedClasses.add(node); + } + } + }; + + sourceFiles.forEach(sourceFile => sourceFile.forEachChild(visitNode)); + + // We collected all class declarations that use Angular features but are not decorated. For + // such undecorated directives, the derived classes also need to be migrated. To achieve this, + // we walk through all undecorated classes and mark those which extend from an undecorated + // directive as undecorated directive too. + undecoratedClasses.forEach(node => { + for (const {node: baseClass} of findBaseClassDeclarations(node, this.typeChecker)) { + // If the undecorated class inherits from a decorated directive, skip the current class. + // We do this because undecorated classes which inherit from directives/components are + // handled as part of the the `undecorated-classes-with-di` migration which copies + // inherited metadata. + if (decoratedDirectives.has(baseClass)) { + break; + } else if (undecoratedDirectives.has(baseClass)) { + undecoratedDirectives.add(node); + undecoratedClasses.delete(node); + break; + } + } + }); + + return undecoratedDirectives; + } + + private _hasAngularDecoratedClassMember(node: ts.ClassDeclaration): boolean { + return node.members.some( + m => m.decorators && getAngularDecorators(this.typeChecker, m.decorators).length !== 0); + } +} diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/update_recorder.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/update_recorder.ts new file mode 100644 index 0000000000000..7568256c35362 --- /dev/null +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/update_recorder.ts @@ -0,0 +1,19 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import * as ts from 'typescript'; +import {ImportManagerUpdateRecorder} from '../../utils/import_manager'; + +/** + * Update recorder interface that is used to transform source files + * in a non-colliding way. + */ +export interface UpdateRecorder extends ImportManagerUpdateRecorder { + addClassDecorator(node: ts.ClassDeclaration, text: string): void; + commitUpdate(): void; +} diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/utils.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/utils.ts deleted file mode 100644 index 746f8676d68c5..0000000000000 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/utils.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as ts from 'typescript'; -import {getAngularDecorators} from '../../utils/ng_decorators'; - -/** Name of the decorator that should be added to undecorated classes. */ -export const FALLBACK_DECORATOR = 'Directive'; - -/** Finds all of the undecorated classes that have decorated fields within a file. */ -export function getUndecoratedClassesWithDecoratedFields( - sourceFile: ts.SourceFile, typeChecker: ts.TypeChecker) { - const classes: UndecoratedClassWithDecoratedFields[] = []; - - sourceFile.forEachChild(function walk(node: ts.Node) { - if (ts.isClassDeclaration(node) && - (!node.decorators || !getAngularDecorators(typeChecker, node.decorators).length)) { - for (const member of node.members) { - const angularDecorators = - member.decorators && getAngularDecorators(typeChecker, member.decorators); - - if (angularDecorators && angularDecorators.length) { - classes.push( - {classDeclaration: node, importDeclaration: angularDecorators[0].importNode}); - return; - } - } - } - - node.forEachChild(walk); - }); - - return classes; -} - -/** Checks whether an import declaration has an import with a certain name. */ -export function hasNamedImport(declaration: ts.ImportDeclaration, symbolName: string): boolean { - const namedImports = getNamedImports(declaration); - - if (namedImports) { - return namedImports.elements.some(element => { - const {name, propertyName} = element; - return propertyName ? propertyName.text === symbolName : name.text === symbolName; - }); - } - - return false; -} - -/** Extracts the NamedImports node from an import declaration. */ -export function getNamedImports(declaration: ts.ImportDeclaration): ts.NamedImports|null { - const namedBindings = declaration.importClause && declaration.importClause.namedBindings; - return (namedBindings && ts.isNamedImports(namedBindings)) ? namedBindings : null; -} - -/** Adds a new import to a NamedImports node. */ -export function addImport(declaration: ts.NamedImports, symbolName: string) { - return ts.updateNamedImports(declaration, [ - ...declaration.elements, ts.createImportSpecifier(undefined, ts.createIdentifier(symbolName)) - ]); -} - -interface UndecoratedClassWithDecoratedFields { - classDeclaration: ts.ClassDeclaration; - importDeclaration: ts.ImportDeclaration; -} diff --git a/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts b/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts index 68718ca8e15af..c78cdfcad0307 100644 --- a/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts +++ b/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts @@ -64,7 +64,7 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => expect(failures.length).toBe(1); expect(failures[0]) - .toBe('Classes with decorated fields must have an Angular decorator as well.'); + .toBe('Class needs to be decorated with "@Directive()" because it uses Angular features.'); }); it(`should add an import for Directive if there isn't one already`, () => { @@ -97,6 +97,27 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => expect(getFile('/index.ts')).toContain(`import { Directive, Input } from '@angular/core';`); }); + it('should not generate conflicting imports there is a different `Directive` symbol', async() => { + writeFile('/index.ts', ` + import { HostBinding } from '@angular/core'; + + export class Directive { + // Simulates a scenario where a library defines a class named "Directive". + // We don't want to generate a conflicting import. + } + + export class MyLibrarySharedBaseClass { + @HostBinding('class.active') isActive: boolean; + } + `); + + runTSLint(true); + const fileContent = getFile('/index.ts'); + expect(fileContent) + .toContain(`import { HostBinding, Directive as Directive_1 } from '@angular/core';`); + expect(fileContent).toMatch(/@Directive_1\(\)\s+export class MyLibrarySharedBaseClass/); + }); + it('should add @Directive to undecorated classes that have @Input', () => { writeFile('/index.ts', ` import { Input } from '@angular/core'; @@ -229,4 +250,35 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => expect(getFile('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); + it('should add @Directive to undecorated derived classes of a migrated class', async() => { + writeFile('/index.ts', ` + import { Input, Directive, NgModule } from '@angular/core'; + + export class Base { + @Input() isActive: boolean; + } + + export class DerivedA extends Base {} + export class DerivedB extends DerivedA {} + export class DerivedC extends DerivedB {} + + @Directive({selector: 'my-comp'}) + export class MyComp extends DerivedC {} + + export class MyCompWrapped extends MyComp {} + + @NgModule({declarations: [MyComp, MyCompWrapped]}) + export class AppModule {} + `); + + runTSLint(true); + const fileContent = getFile('/index.ts'); + expect(fileContent).toContain(`import { Input, Directive, NgModule } from '@angular/core';`); + expect(fileContent).toMatch(/@Directive\(\)\s+export class Base/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedA/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedB/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedC/); + expect(fileContent).toMatch(/}\s+@Directive\(\{selector: 'my-comp'}\)\s+export class MyComp/); + expect(fileContent).toMatch(/}\s+export class MyCompWrapped/); + }); }); diff --git a/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts b/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts index ed04c675d17dd..c141898803aed 100644 --- a/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts +++ b/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts @@ -74,6 +74,27 @@ describe('Undecorated classes with decorated fields migration', () => { .toContain(`import { Directive, Input } from '@angular/core';`); }); + it('should not generate conflicting imports there is a different `Directive` symbol', async() => { + writeFile('/index.ts', ` + import { HostBinding } from '@angular/core'; + + export class Directive { + // Simulates a scenario where a library defines a class named "Directive". + // We don't want to generate a conflicting import. + } + + export class MyLibrarySharedBaseClass { + @HostBinding('class.active') isActive: boolean; + } + `); + + await runMigration(); + const fileContent = tree.readContent('/index.ts'); + expect(fileContent) + .toContain(`import { HostBinding, Directive as Directive_1 } from '@angular/core';`); + expect(fileContent).toMatch(/@Directive_1\(\)\s+export class MyLibrarySharedBaseClass/); + }); + it('should add @Directive to undecorated classes that have @Input', async() => { writeFile('/index.ts', ` import { Input } from '@angular/core'; @@ -206,6 +227,38 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); + it('should add @Directive to undecorated derived classes of a migrated class', async() => { + writeFile('/index.ts', ` + import { Input, Directive, NgModule } from '@angular/core'; + + export class Base { + @Input() isActive: boolean; + } + + export class DerivedA extends Base {} + export class DerivedB extends DerivedA {} + export class DerivedC extends DerivedB {} + + @Directive({selector: 'my-comp'}) + export class MyComp extends DerivedC {} + + export class MyCompWrapped extends MyComp {} + + @NgModule({declarations: [MyComp, MyCompWrapped]}) + export class AppModule {} + `); + + await runMigration(); + const fileContent = tree.readContent('/index.ts'); + expect(fileContent).toContain(`import { Input, Directive, NgModule } from '@angular/core';`); + expect(fileContent).toMatch(/@Directive\(\)\s+export class Base/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedA/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedB/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedC/); + expect(fileContent).toMatch(/}\s+@Directive\(\{selector: 'my-comp'}\)\s+export class MyComp/); + expect(fileContent).toMatch(/}\s+export class MyCompWrapped/); + }); + function writeFile(filePath: string, contents: string) { host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); } From 3d2db5c5f0240d87a9c52beaa33e91ac65d99035 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Tue, 11 Feb 2020 18:03:13 +0100 Subject: [PATCH 091/262] test: add integration test for undecorated-classes-with-decorated-fields migration (#35339) We don't have an integration test for the `undecorated-classes-with-decorated-fields migration. For consistency and to cover for the latest changes, we add it to the `ng update` integration test. PR Close #35339 --- .../undecorated-classes-with-fields.ts | 47 ++++ ...ndecorated-classes-with-fields_expected.ts | 57 +++++ integration/ng_update_migrations/yarn.lock | 200 +++++++++--------- .../transform.ts | 3 +- 4 files changed, 205 insertions(+), 102 deletions(-) create mode 100644 integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts create mode 100644 integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts diff --git a/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts new file mode 100644 index 0000000000000..8988a6cd25475 --- /dev/null +++ b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts @@ -0,0 +1,47 @@ +import {Component, ElementRef, HostBinding, HostListener, Input, NgModule} from '@angular/core'; + +export class NonAngularBaseClass { + greet() {} +} + +export class BaseClass extends NonAngularBaseClass { + @Input() enabled = true; +} + +export class SecondBaseClass extends BaseClass { + toggleEnabled() { + this.enabled = !this.enabled; + } +} + +export class ThirdBaseClass extends SecondBaseClass { + @HostListener('focus') onFocus() {} +} + +export class FourthBaseClass extends ThirdBaseClass { + focus() { + this.onFocus(); + } +} + +export class FifthBaseClass { + constructor(private _elementRef: ElementRef) {} + protected calculatePosition(): any {} +} + +export class MyCompSuperBase { + @HostBinding('class.hello') hello = true; +} + +export class MyCompBase extends MyCompSuperBase {} + +@Component({ + selector: 'my-comp', + template: '', +}) +export class MyComp extends MyCompBase {} + +export class WrappedMyComp extends MyComp {} + +@NgModule({declarations: [MyComp, WrappedMyComp]}) +export class TestModule {} diff --git a/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts new file mode 100644 index 0000000000000..37cb721ec51f1 --- /dev/null +++ b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts @@ -0,0 +1,57 @@ +import { Component, ElementRef, HostBinding, HostListener, Input, NgModule, Directive } from '@angular/core'; + +export class NonAngularBaseClass { + greet() {} +} + +@Directive() +export class BaseClass extends NonAngularBaseClass { + @Input() enabled = true; +} + +@Directive() +export class SecondBaseClass extends BaseClass { + toggleEnabled() { + this.enabled = !this.enabled; + } +} + +@Directive() +export class ThirdBaseClass extends SecondBaseClass { + @HostListener('focus') onFocus() {} +} + +@Directive() +export class FourthBaseClass extends ThirdBaseClass { + focus() { + this.onFocus(); + } +} + +export class FifthBaseClass { + constructor(private _elementRef: ElementRef) {} + protected calculatePosition(): any {} +} + +@Directive() +export class MyCompSuperBase { + @HostBinding('class.hello') hello = true; +} + +@Directive() +export class MyCompBase extends MyCompSuperBase {} + +@Component({ + selector: 'my-comp', + template: '', +}) +export class MyComp extends MyCompBase {} + +@Component({ + selector: 'my-comp', + template: '', +}) +export class WrappedMyComp extends MyComp {} + +@NgModule({declarations: [MyComp, WrappedMyComp]}) +export class TestModule {} diff --git a/integration/ng_update_migrations/yarn.lock b/integration/ng_update_migrations/yarn.lock index bd6d6037aa1e5..74b2fe5c60e63 100644 --- a/integration/ng_update_migrations/yarn.lock +++ b/integration/ng_update_migrations/yarn.lock @@ -2,25 +2,25 @@ # yarn lockfile v1 -"@angular-devkit/architect@0.900.0-rc.11": - version "0.900.0-rc.11" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.900.0-rc.11.tgz#e9f3e5e372d467a220027cf53231b88e8e857fbc" - integrity sha512-rRbq4ipppnY4FvVo89Cv+yC7rlt1/VFE/jaB77Ra2tI6zVlFWCTjnMzuc9TYz/3jK1ssThzgEA2sebPDmjH47w== +"@angular-devkit/architect@0.900.0-rc.14": + version "0.900.0-rc.14" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.900.0-rc.14.tgz#cfdbee7899b9addfd9d43c638b0dbc21188f0a79" + integrity sha512-dgEc/zYE0uzv+m8JTdv3FDc7bViJKbxs8FY3zdkArc6MXIXpoMzgvveEEHvhrpO0iu6njW/xRSZYtYnTIY4xlw== dependencies: - "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.14" rxjs "6.5.3" "@angular-devkit/build-angular@file:../../node_modules/@angular-devkit/build-angular": - version "0.900.0-rc.11" + version "0.900.0-rc.14" dependencies: - "@angular-devkit/architect" "0.900.0-rc.11" - "@angular-devkit/build-optimizer" "0.900.0-rc.11" - "@angular-devkit/build-webpack" "0.900.0-rc.11" - "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/architect" "0.900.0-rc.14" + "@angular-devkit/build-optimizer" "0.900.0-rc.14" + "@angular-devkit/build-webpack" "0.900.0-rc.14" + "@angular-devkit/core" "9.0.0-rc.14" "@babel/core" "7.7.7" "@babel/generator" "7.7.7" "@babel/preset-env" "7.7.7" - "@ngtools/webpack" "9.0.0-rc.11" + "@ngtools/webpack" "9.0.0-rc.14" ajv "6.10.2" autoprefixer "9.7.1" babel-loader "8.0.6" @@ -75,10 +75,10 @@ webpack-subresource-integrity "1.3.4" worker-plugin "3.2.0" -"@angular-devkit/build-optimizer@0.900.0-rc.11": - version "0.900.0-rc.11" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.900.0-rc.11.tgz#96c2446fa9cd2e90700ab8a68312b28b3907f6d9" - integrity sha512-GJC+7H7ER6bxDC2UdAGwW357EYHpv8ISKKmS19wdJV5gZPMPANcpbg9FIpl27SDhUyZX9C2DOrcATvYYFoYgDQ== +"@angular-devkit/build-optimizer@0.900.0-rc.14": + version "0.900.0-rc.14" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.900.0-rc.14.tgz#e90e955e1daf5689ad198a5253134187c99b7b5a" + integrity sha512-MA2g8N9/cvzMvudEEjeaNV6STwSr8NI/znpv+nU6sQa4PdegIotBbqxGUmHMKtLH5cOwDy9hI47ANN+XADbIbQ== dependencies: loader-utils "1.2.3" source-map "0.7.3" @@ -86,19 +86,19 @@ typescript "3.6.4" webpack-sources "1.4.3" -"@angular-devkit/build-webpack@0.900.0-rc.11": - version "0.900.0-rc.11" - resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.900.0-rc.11.tgz#d9a91c2b67a629f6adfe87980d26e495f2e30e0a" - integrity sha512-utBAnkO6WLi323Rto1s7TJpaDRqDNR8jkD0C0PG5Zm3y1U9ARbAjTkugkrB/7bc4gEIqWZD+1dLYaaJCidye2Q== +"@angular-devkit/build-webpack@0.900.0-rc.14": + version "0.900.0-rc.14" + resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.900.0-rc.14.tgz#b932148f14ed0056f1885c98c330411a80d31331" + integrity sha512-HvrDapIKr4k2a7Tf7MdW0miGOUUzHxRkGyDIWJBDXLbfOIt9BnhKfFGxP/SyDlwJnLyat9yYZjcDu1AI0E1Dmw== dependencies: - "@angular-devkit/architect" "0.900.0-rc.11" - "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/architect" "0.900.0-rc.14" + "@angular-devkit/core" "9.0.0-rc.14" rxjs "6.5.3" -"@angular-devkit/core@9.0.0-rc.11": - version "9.0.0-rc.11" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.0-rc.11.tgz#9e69545eb21284a573ad78e4c33003f2ea25afd5" - integrity sha512-ki7Sln+mQdCctJNBalzy70tiFn2hOCY2Yyte8B0xKWVHnofZySvG+ANzoLgodnKFOBH18AQy35FhgzZM++N9tQ== +"@angular-devkit/core@9.0.0-rc.14": + version "9.0.0-rc.14" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-9.0.0-rc.14.tgz#5cff058750c0b063a6f5fa1a2e830f1f48ffa56b" + integrity sha512-hFiKoAPtnOqqYv97Y22OgyeTFxjNU/6WDhmuXkfbZDKychvuBLDOdgUhL43heEzavSfCCl23E0JmilwCUcepmw== dependencies: ajv "6.10.2" fast-json-stable-stringify "2.0.0" @@ -106,12 +106,12 @@ rxjs "6.5.3" source-map "0.7.3" -"@angular-devkit/schematics@9.0.0-rc.11": - version "9.0.0-rc.11" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.0-rc.11.tgz#e0d4d271d8d783ebf05eced576262f20e6c3562c" - integrity sha512-aJqOLzsoAkVj3AVTf1ehH2hA9wHHz1+7TTtfqI+Yx+S3jFyvGmnKrNBCKtMuIV5JdEHiXmhhuGbNBHwRFWpOow== +"@angular-devkit/schematics@9.0.0-rc.14": + version "9.0.0-rc.14" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-9.0.0-rc.14.tgz#4605b1ee9f18b772094697f9b35258fdac76d4b3" + integrity sha512-i/XTxo7hTXTFKus51Qry3rRGHL2uS4SgufGqdvOcy2qZbjyh/wt0UDOGJu/w8dcA9pJm+vFBLAbnro5oFyIsVw== dependencies: - "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.14" ora "4.0.2" rxjs "6.5.3" @@ -119,13 +119,13 @@ version "9.0.0-rc.1" "@angular/cli@file:../../node_modules/@angular/cli": - version "9.0.0-rc.11" + version "9.0.0-rc.14" dependencies: - "@angular-devkit/architect" "0.900.0-rc.11" - "@angular-devkit/core" "9.0.0-rc.11" - "@angular-devkit/schematics" "9.0.0-rc.11" - "@schematics/angular" "9.0.0-rc.11" - "@schematics/update" "0.900.0-rc.11" + "@angular-devkit/architect" "0.900.0-rc.14" + "@angular-devkit/core" "9.0.0-rc.14" + "@angular-devkit/schematics" "9.0.0-rc.14" + "@schematics/angular" "9.0.0-rc.14" + "@schematics/update" "0.900.0-rc.14" "@yarnpkg/lockfile" "1.1.0" ansi-colors "4.1.1" debug "^4.1.1" @@ -216,16 +216,16 @@ source-map "^0.5.0" "@babel/core@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" - integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" + integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" - "@babel/helpers" "^7.8.3" - "@babel/parser" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.4" "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" + "@babel/traverse" "^7.8.4" "@babel/types" "^7.8.3" convert-source-map "^1.7.0" debug "^4.1.0" @@ -256,10 +256,10 @@ lodash "^4.17.13" source-map "^0.5.0" -"@babel/generator@^7.7.7", "@babel/generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" - integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug== +"@babel/generator@^7.7.7", "@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== dependencies: "@babel/types" "^7.8.3" jsesc "^2.5.1" @@ -464,13 +464,13 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helpers@^7.7.4", "@babel/helpers@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85" - integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ== +"@babel/helpers@^7.7.4", "@babel/helpers@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" + integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== dependencies: "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" + "@babel/traverse" "^7.8.4" "@babel/types" "^7.8.3" "@babel/highlight@^7.0.0": @@ -496,10 +496,10 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== -"@babel/parser@^7.7.5", "@babel/parser@^7.7.7", "@babel/parser@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" - integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== +"@babel/parser@^7.7.5", "@babel/parser@^7.7.7", "@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== "@babel/plugin-proposal-async-generator-functions@^7.7.4": version "7.8.3" @@ -689,9 +689,9 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-for-of@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz#15f17bce2fc95c7d59a24b299e83e81cedc22e18" - integrity sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.4.tgz#6fe8eae5d6875086ee185dd0b098a8513783b47d" + integrity sha512-iAXNlOWvcYUYoV8YIxwS7TxGRJcxyl8eQCfT+A5j8sKUzRFvJdcyjp97jL2IghWSRDaL2PU2O2tX8Cu9dTBq5A== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -777,9 +777,9 @@ "@babel/helper-replace-supers" "^7.8.3" "@babel/plugin-transform-parameters@^7.7.7": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz#7890576a13b17325d8b7d44cb37f21dc3bbdda59" - integrity sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.4.tgz#1d5155de0b65db0ccf9971165745d3bb990d77d3" + integrity sha512-IsS3oTxeTsZlE5KqzTbcC2sV0P9pXdec53SU+Yxv7o/6dvGM5AkTotQKhoSffhNgZ/dftsSiOoxy7evCYJXzVA== dependencies: "@babel/helper-call-delegate" "^7.8.3" "@babel/helper-get-function-arity" "^7.8.3" @@ -837,9 +837,9 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-typeof-symbol@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz#5cffb216fb25c8c64ba6bf5f76ce49d3ab079f4d" - integrity sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -941,16 +941,16 @@ globals "^11.1.0" lodash "^4.17.13" -"@babel/traverse@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" - integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== +"@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" + "@babel/generator" "^7.8.4" "@babel/helper-function-name" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.3" + "@babel/parser" "^7.8.4" "@babel/types" "^7.8.3" debug "^4.1.0" globals "^11.1.0" @@ -979,31 +979,31 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@ngtools/webpack@9.0.0-rc.11": - version "9.0.0-rc.11" - resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-9.0.0-rc.11.tgz#10b5997bec7cf48d1b144c8b4d46ffd0039c522a" - integrity sha512-qeW81ISiO8GVEndOaCYv0k6fzRIxzZs6jrXGl1pcLH1H6qv2mxhA5DA0vC/9TN6wenrS43RGjDIQpp+RvkiLwA== +"@ngtools/webpack@9.0.0-rc.14": + version "9.0.0-rc.14" + resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-9.0.0-rc.14.tgz#6a764138347d2ff3846753a141eaacdab3b0658c" + integrity sha512-G98u14exE36kR4LflWB20ClJ6ql9B0qMcyokepjwpVAgaoDfpJRR7mKAZliMPd0KFXktdnct2QEyF6pbLevO7w== dependencies: - "@angular-devkit/core" "9.0.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.14" enhanced-resolve "4.1.1" rxjs "6.5.3" webpack-sources "1.4.3" -"@schematics/angular@9.0.0-rc.11": - version "9.0.0-rc.11" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.0.0-rc.11.tgz#d544c0d4e7b3dd59ed56be5183e038ebe06a165e" - integrity sha512-9InC+F71KiPXE0jl7Ow4iPFJ2AZZDbfTM6yWZoYLk3hzTCohAZZciBl00Tfyu2uerGshx8akbJMLySjXtf+q0g== +"@schematics/angular@9.0.0-rc.14": + version "9.0.0-rc.14" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-9.0.0-rc.14.tgz#4112aeb6c76144893d65cab9f53ca8422adc3bbb" + integrity sha512-NWxDLym2Sst5lTvV7QYkVUjy3N0CfCohhdWC4DGRtjUyTD2eUepAg1PZCQcq8U2iRtd78Lm1n4obDWO1tW3pXQ== dependencies: - "@angular-devkit/core" "9.0.0-rc.11" - "@angular-devkit/schematics" "9.0.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.14" + "@angular-devkit/schematics" "9.0.0-rc.14" -"@schematics/update@0.900.0-rc.11": - version "0.900.0-rc.11" - resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.900.0-rc.11.tgz#d22df30f13a6f38970b759db61ad84d3f9b03a78" - integrity sha512-nV0oCPzzd0vi2Exo1910rWXwz/RnMc4zF9FxSOCZzsIv+AkwIehhL815OKyjUSCzU9+IM0/o1LKkPPrSWK7QEA== +"@schematics/update@0.900.0-rc.14": + version "0.900.0-rc.14" + resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.900.0-rc.14.tgz#1debea3eb90559d25838e7b256b48bac216e19d9" + integrity sha512-ZlsneHwpvrtpt0D10g4S8JftLaSFQtSO+kOD1uP26OxNMg9w54jrlr7xWSwAmT69/ETjNy8BFKXdcU9yvYixPA== dependencies: - "@angular-devkit/core" "9.0.0-rc.11" - "@angular-devkit/schematics" "9.0.0-rc.11" + "@angular-devkit/core" "9.0.0-rc.14" + "@angular-devkit/schematics" "9.0.0-rc.14" "@yarnpkg/lockfile" "1.1.0" ini "1.3.5" npm-package-arg "^7.0.0" @@ -2029,9 +2029,9 @@ caniuse-lite@1.0.30001020: integrity sha512-yWIvwA68wRHKanAVS1GjN8vajAv7MBFshullKCeq/eKpK7pJBVDgFFEqvgWTkcP2+wIDeQGYFRXECjKZnLkUjA== caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001023: - version "1.0.30001023" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001023.tgz#b82155827f3f5009077bdd2df3d8968bcbcc6fc4" - integrity sha512-C5TDMiYG11EOhVOA62W1p3UsJ2z4DsHtMBQtjzp3ZsUglcQn62WOUgW0y795c7A5uZ+GCEIvzkMatLIlAsbNTA== + version "1.0.30001027" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz#283e2ef17d94889cc216a22c6f85303d78ca852d" + integrity sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg== caniuse-lite@^1.0.30000984: version "1.0.30000989" @@ -3037,9 +3037,9 @@ electron-to-chromium@^1.3.306: integrity sha512-7GH6RKCzziLzJ9ejmbiBEdzHZsc6C3eRpav14dmRfTWMpNgMqpP1ukw/FU/Le2fR+ep642naq7a23xNdmh2s+A== electron-to-chromium@^1.3.322, electron-to-chromium@^1.3.341: - version "1.3.342" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.342.tgz#138317aa7399e268735b9269fe374a8566425090" - integrity sha512-An/MLhGLIG/g7lZ5vqs4lar96zv74agd3ZcADDHLpjAa16T7Y/pO/33Q31JOwpmHeyjithtHtUcn7XLuaz78lw== + version "1.3.348" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.348.tgz#61fa7d43f6c4fd8b046b0b69213cb55b7a4c76a5" + integrity sha512-6O0IInybavGdYtcbI4ryF/9e3Qi8/soi6C68ELRseJuTwQPKq39uGgVVeQHG28t69Sgsky09nXBRhUiFXsZyFQ== elliptic@^6.0.0: version "6.5.0" @@ -4626,9 +4626,9 @@ istanbul-lib-coverage@^3.0.0: integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== istanbul-lib-instrument@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz#53321a7970f076262fd3292c8f9b2e4ac544aae1" - integrity sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ== + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" + integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== dependencies: "@babel/core" "^7.7.5" "@babel/parser" "^7.7.5" @@ -5498,9 +5498,9 @@ node-releases@^1.1.40: semver "^6.3.0" node-releases@^1.1.44, node-releases@^1.1.47: - version "1.1.47" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4" - integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA== + version "1.1.48" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.48.tgz#7f647f0c453a0495bcd64cbd4778c26035c2f03a" + integrity sha512-Hr8BbmUl1ujAST0K0snItzEA5zkJTQup8VNTKNfT6Zw8vTJkIiagUPNfxHmgDOyfFYNfKAul40sD0UEYTvwebw== dependencies: semver "^6.3.0" diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts index 990323a76cef3..c8e30ec86a264 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts @@ -78,8 +78,7 @@ export class UndecoratedClassesWithDecoratedFieldsTransform { for (const {node: baseClass} of findBaseClassDeclarations(node, this.typeChecker)) { // If the undecorated class inherits from a decorated directive, skip the current class. // We do this because undecorated classes which inherit from directives/components are - // handled as part of the the `undecorated-classes-with-di` migration which copies - // inherited metadata. + // handled in the `undecorated-classes-with-di` migration which copies inherited metadata. if (decoratedDirectives.has(baseClass)) { break; } else if (undecoratedDirectives.has(baseClass)) { From c24ad560fa6a14d067969d5588749ba1261bcb98 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Fri, 14 Feb 2020 18:59:29 +0100 Subject: [PATCH 092/262] feat(core): undecorated-classes migration should handle derived abstract classes (#35339) In version 10, undecorated base classes that use Angular features need to be decorated explicitly with `@Directive()`. Additionally, derived classes of abstract directives need to be decorated. The migration already handles this for undecorated classes that are not explicitly decorated, but since in V9, abstract directives can be used, we also need to handle this for explicitly decorated abstract directives. e.g. ``` @Directive() export class Base {...} // needs to be decorated by migration when updating from v9 to v10 export class Wrapped extends Base {} @Component(...) export class Cmp extends Wrapped {} ``` PR Close #35339 --- .../undecorated-classes-with-fields.ts | 17 ++- ...ndecorated-classes-with-fields_expected.ts | 19 ++- .../BUILD.bazel | 2 + .../transform.ts | 112 +++++++++++++----- ...es_with_decorated_fields_migration_spec.ts | 33 ++++++ .../schematics/utils/typescript/functions.ts | 6 +- 6 files changed, 157 insertions(+), 32 deletions(-) diff --git a/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts index 8988a6cd25475..c3ea7d460e25c 100644 --- a/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts +++ b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields.ts @@ -1,4 +1,12 @@ -import {Component, ElementRef, HostBinding, HostListener, Input, NgModule} from '@angular/core'; +import { + Component, + Directive, + ElementRef, + HostBinding, + HostListener, + Input, + NgModule +} from '@angular/core'; export class NonAngularBaseClass { greet() {} @@ -45,3 +53,10 @@ export class WrappedMyComp extends MyComp {} @NgModule({declarations: [MyComp, WrappedMyComp]}) export class TestModule {} + +@Directive({selector: null}) +export class AbstractDir {} + +export class DerivedAbstractDir extends AbstractDir {} + +export class WrappedDerivedAbstractDir extends DerivedAbstractDir {} diff --git a/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts index 37cb721ec51f1..ebc267f02adc7 100644 --- a/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts +++ b/integration/ng_update_migrations/src/app/migration-tests/undecorated-classes-with-fields_expected.ts @@ -1,4 +1,12 @@ -import { Component, ElementRef, HostBinding, HostListener, Input, NgModule, Directive } from '@angular/core'; +import { + Component, + Directive, + ElementRef, + HostBinding, + HostListener, + Input, + NgModule +} from '@angular/core'; export class NonAngularBaseClass { greet() {} @@ -55,3 +63,12 @@ export class WrappedMyComp extends MyComp {} @NgModule({declarations: [MyComp, WrappedMyComp]}) export class TestModule {} + +@Directive({selector: null}) +export class AbstractDir {} + +@Directive() +export class DerivedAbstractDir extends AbstractDir {} + +@Directive() +export class WrappedDerivedAbstractDir extends DerivedAbstractDir {} diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel index 9831bbf557c74..040810b57e7c2 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/BUILD.bazel @@ -11,6 +11,8 @@ ts_library( "//packages/core/schematics/test:__pkg__", ], deps = [ + "//packages/compiler-cli/src/ngtsc/partial_evaluator", + "//packages/compiler-cli/src/ngtsc/reflection", "//packages/core/schematics/utils", "@npm//@angular-devkit/schematics", "@npm//@types/node", diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts index c8e30ec86a264..159f65d6c81ed 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts @@ -6,17 +6,33 @@ * found in the LICENSE file at https://angular.io/license */ +import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluator'; +import {TypeScriptReflectionHost, reflectObjectLiteral} from '@angular/compiler-cli/src/ngtsc/reflection'; import * as ts from 'typescript'; import {ImportManager} from '../../utils/import_manager'; -import {getAngularDecorators} from '../../utils/ng_decorators'; +import {NgDecorator, getAngularDecorators} from '../../utils/ng_decorators'; import {findBaseClassDeclarations} from '../../utils/typescript/find_base_classes'; +import {unwrapExpression} from '../../utils/typescript/functions'; import {UpdateRecorder} from './update_recorder'; + +/** Analyzed class declaration. */ +interface AnalyzedClass { + /** Whether the class is decorated with @Directive or @Component. */ + isDirectiveOrComponent: boolean; + /** Whether the class is an abstract directive. */ + isAbstractDirective: boolean; + /** Whether the class uses any Angular features. */ + usesAngularFeatures: boolean; +} + export class UndecoratedClassesWithDecoratedFieldsTransform { private printer = ts.createPrinter(); private importManager = new ImportManager(this.getUpdateRecorder, this.printer); + private reflectionHost = new TypeScriptReflectionHost(this.typeChecker); + private partialEvaluator = new PartialEvaluator(this.reflectionHost, this.typeChecker, null); constructor( private typeChecker: ts.TypeChecker, @@ -28,7 +44,7 @@ export class UndecoratedClassesWithDecoratedFieldsTransform { * https://hackmd.io/vuQfavzfRG6KUCtU7oK_EA */ migrate(sourceFiles: ts.SourceFile[]) { - this._findUndecoratedDirectives(sourceFiles).forEach(node => { + this._findUndecoratedAbstractDirectives(sourceFiles).forEach(node => { const sourceFile = node.getSourceFile(); const recorder = this.getUpdateRecorder(sourceFile); const directiveExpr = @@ -42,54 +58,96 @@ export class UndecoratedClassesWithDecoratedFieldsTransform { /** Records all changes that were made in the import manager. */ recordChanges() { this.importManager.recordChanges(); } - /** Finds undecorated directives in the specified source files. */ - private _findUndecoratedDirectives(sourceFiles: ts.SourceFile[]) { - const typeChecker = this.typeChecker; - const undecoratedDirectives = new Set<ts.ClassDeclaration>(); + /** Finds undecorated abstract directives in the specified source files. */ + private _findUndecoratedAbstractDirectives(sourceFiles: ts.SourceFile[]) { + const result = new Set<ts.ClassDeclaration>(); const undecoratedClasses = new Set<ts.ClassDeclaration>(); - const decoratedDirectives = new WeakSet<ts.ClassDeclaration>(); + const nonAbstractDirectives = new WeakSet<ts.ClassDeclaration>(); + const abstractDirectives = new WeakSet<ts.ClassDeclaration>(); const visitNode = (node: ts.Node) => { node.forEachChild(visitNode); if (!ts.isClassDeclaration(node)) { return; } - const ngDecorators = node.decorators && getAngularDecorators(typeChecker, node.decorators); - const isDirectiveOrComponent = ngDecorators !== undefined && - ngDecorators.some(({name}) => name === 'Directive' || name === 'Component'); + const {isDirectiveOrComponent, isAbstractDirective, usesAngularFeatures} = + this._analyzeClassDeclaration(node); if (isDirectiveOrComponent) { - decoratedDirectives.add(node); - } else { - if (this._hasAngularDecoratedClassMember(node)) { - undecoratedDirectives.add(node); + if (isAbstractDirective) { + abstractDirectives.add(node); } else { - undecoratedClasses.add(node); + nonAbstractDirectives.add(node); } + } else if (usesAngularFeatures) { + abstractDirectives.add(node); + result.add(node); + } else { + undecoratedClasses.add(node); } }; sourceFiles.forEach(sourceFile => sourceFile.forEachChild(visitNode)); - // We collected all class declarations that use Angular features but are not decorated. For - // such undecorated directives, the derived classes also need to be migrated. To achieve this, - // we walk through all undecorated classes and mark those which extend from an undecorated - // directive as undecorated directive too. + // We collected all undecorated class declarations which inherit from abstract directives. + // For such abstract directives, the derived classes also need to be migrated. undecoratedClasses.forEach(node => { for (const {node: baseClass} of findBaseClassDeclarations(node, this.typeChecker)) { - // If the undecorated class inherits from a decorated directive, skip the current class. - // We do this because undecorated classes which inherit from directives/components are - // handled in the `undecorated-classes-with-di` migration which copies inherited metadata. - if (decoratedDirectives.has(baseClass)) { + // If the undecorated class inherits from a non-abstract directive, skip the current + // class. We do this because undecorated classes which inherit metadata from non-abstract + // directives are handle in the `undecorated-classes-with-di` migration that copies + // inherited metadata into an explicit decorator. + if (nonAbstractDirectives.has(baseClass)) { break; - } else if (undecoratedDirectives.has(baseClass)) { - undecoratedDirectives.add(node); - undecoratedClasses.delete(node); + } else if (abstractDirectives.has(baseClass)) { + result.add(node); break; } } }); - return undecoratedDirectives; + return result; + } + + /** + * Analyzes the given class declaration by determining whether the class + * is a directive, is an abstract directive, or uses Angular features. + */ + private _analyzeClassDeclaration(node: ts.ClassDeclaration): AnalyzedClass { + const ngDecorators = node.decorators && getAngularDecorators(this.typeChecker, node.decorators); + const usesAngularFeatures = this._hasAngularDecoratedClassMember(node); + if (ngDecorators === undefined || ngDecorators.length === 0) { + return {isDirectiveOrComponent: false, isAbstractDirective: false, usesAngularFeatures}; + } + const directiveDecorator = ngDecorators.find(({name}) => name === 'Directive'); + const componentDecorator = ngDecorators.find(({name}) => name === 'Component'); + const isAbstractDirective = + directiveDecorator !== undefined && this._isAbstractDirective(directiveDecorator); + return { + isDirectiveOrComponent: !!directiveDecorator || !!componentDecorator, + isAbstractDirective, + usesAngularFeatures, + }; + } + + /** + * Checks whether the given decorator resolves to an abstract directive. An directive is + * considered "abstract" if there is no selector specified. + */ + private _isAbstractDirective({node}: NgDecorator): boolean { + const metadataArgs = node.expression.arguments; + if (metadataArgs.length === 0) { + return true; + } + const metadataExpr = unwrapExpression(metadataArgs[0]); + if (!ts.isObjectLiteralExpression(metadataExpr)) { + return false; + } + const metadata = reflectObjectLiteral(metadataExpr); + if (!metadata.has('selector')) { + return false; + } + const selector = this.partialEvaluator.evaluate(metadata.get('selector') !); + return selector == null; } private _hasAngularDecoratedClassMember(node: ts.ClassDeclaration): boolean { diff --git a/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts b/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts index c141898803aed..27c7ac65f2d12 100644 --- a/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts +++ b/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts @@ -259,6 +259,39 @@ describe('Undecorated classes with decorated fields migration', () => { expect(fileContent).toMatch(/}\s+export class MyCompWrapped/); }); + it('should add @Directive to derived undecorated classes of abstract directives', async() => { + writeFile('/index.ts', ` + import { Input, Directive, NgModule } from '@angular/core'; + + @Directive() + export class Base { + // ... + } + + export class DerivedA extends Base {} + export class DerivedB extends DerivedA {} + export class DerivedC extends DerivedB {} + + @Directive({selector: 'my-comp'}) + export class MyComp extends DerivedC {} + + export class MyCompWrapped extends MyComp {} + + @NgModule({declarations: [MyComp, MyCompWrapped]}) + export class AppModule {} + `); + + await runMigration(); + const fileContent = tree.readContent('/index.ts'); + expect(fileContent).toContain(`import { Input, Directive, NgModule } from '@angular/core';`); + expect(fileContent).toMatch(/core';\s+@Directive\(\)\s+export class Base/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedA/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedB/); + expect(fileContent).toMatch(/@Directive\(\)\s+export class DerivedC/); + expect(fileContent).toMatch(/}\s+@Directive\(\{selector: 'my-comp'}\)\s+export class MyComp/); + expect(fileContent).toMatch(/}\s+export class MyCompWrapped/); + }); + function writeFile(filePath: string, contents: string) { host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); } diff --git a/packages/core/schematics/utils/typescript/functions.ts b/packages/core/schematics/utils/typescript/functions.ts index 3e32af41329f5..b8cd376588795 100644 --- a/packages/core/schematics/utils/typescript/functions.ts +++ b/packages/core/schematics/utils/typescript/functions.ts @@ -17,11 +17,11 @@ export function isFunctionLikeDeclaration(node: ts.Node): node is ts.FunctionLik /** * Unwraps a given expression TypeScript node. Expressions can be wrapped within multiple - * parentheses. e.g. "(((({exp}))))()". The function should return the TypeScript node - * referring to the inner expression. e.g "exp". + * parentheses or as expression. e.g. "(((({exp}))))()". The function should return the + * TypeScript node referring to the inner expression. e.g "exp". */ export function unwrapExpression(node: ts.Expression | ts.ParenthesizedExpression): ts.Expression { - if (ts.isParenthesizedExpression(node)) { + if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node)) { return unwrapExpression(node.expression); } else { return node; From c810ac71530f5c5c27443cef24a9f1ee82a28656 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Wed, 1 Apr 2020 09:16:14 +0200 Subject: [PATCH 093/262] build: sort module resolution warnings in ts-circular-deps tool (#36361) For better overview of modules that cannot be resolved in the `ts-circular-deps` tool, the warnings are now sorted. Additionally, an empty line between fixed and new circular dependencies is now printed. That should slightly help with distinguishing. PR Close #36361 --- dev-infra/ts-circular-dependencies/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dev-infra/ts-circular-dependencies/index.ts b/dev-infra/ts-circular-dependencies/index.ts index 50f8a903b79fd..002fd707a3930 100644 --- a/dev-infra/ts-circular-dependencies/index.ts +++ b/dev-infra/ts-circular-dependencies/index.ts @@ -85,10 +85,12 @@ export function main( // from the View Engine compiler (i.e. factories, summaries) cannot be resolved. if (printWarnings && warningsCount !== 0) { console.info(chalk.yellow('⚠ The following imports could not be resolved:')); - analyzer.unresolvedModules.forEach(specifier => console.info(` • ${specifier}`)); + Array.from(analyzer.unresolvedModules) + .sort() + .forEach(specifier => console.info(` • ${specifier}`)); analyzer.unresolvedFiles.forEach((value, key) => { console.info(` • ${getRelativePath(baseDir, key)}`); - value.forEach(specifier => console.info(` ${specifier}`)); + value.sort().forEach(specifier => console.info(` ${specifier}`)); }); } else { console.info(chalk.yellow(`⚠ ${warningsCount} imports could not be resolved.`)); @@ -108,12 +110,13 @@ export function main( if (newCircularDeps.length !== 0) { console.error(chalk.yellow(` New circular dependencies which are not allowed:`)); newCircularDeps.forEach(c => console.error(` • ${convertReferenceChainToString(c)}`)); + console.error(); } if (fixedCircularDeps.length !== 0) { console.error( chalk.yellow(` Fixed circular dependencies that need to be removed from the golden:`)); fixedCircularDeps.forEach(c => console.error(` • ${convertReferenceChainToString(c)}`)); - console.info(); + console.error(); if (approveCommand) { console.info(chalk.yellow(` Please approve the new golden with: ${approveCommand}`)); } else { From 04f61c0c3ee9b3616b1719b4ae9c3eb097698218 Mon Sep 17 00:00:00 2001 From: Alan Agius <alan.agius4@gmail.com> Date: Thu, 2 Apr 2020 13:51:31 +0200 Subject: [PATCH 094/262] build: enable `strictTemplates` in AIO (#36391) PR Close #36391 --- aio/src/app/custom-elements/api/api-list.component.html | 2 +- aio/tsconfig.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/aio/src/app/custom-elements/api/api-list.component.html b/aio/src/app/custom-elements/api/api-list.component.html index dc8461b20439b..e7f101b2ade0d 100644 --- a/aio/src/app/custom-elements/api/api-list.component.html +++ b/aio/src/app/custom-elements/api/api-list.component.html @@ -15,7 +15,7 @@ </aio-select> <div class="form-search"> - <input #filter placeholder="Filter" (input)="setQuery($event.target.value)" aria-label="Filter Search"> + <input #filter placeholder="Filter" (input)="setQuery($any($event.target).value)" aria-label="Filter Search"> <i class="material-icons">search</i> </div> </div> diff --git a/aio/tsconfig.json b/aio/tsconfig.json index aed6d033325dc..2e5d77de7a625 100644 --- a/aio/tsconfig.json +++ b/aio/tsconfig.json @@ -38,6 +38,7 @@ "angularCompilerOptions": { "disableTypeScriptVersionCheck": true, "fullTemplateTypeCheck": true, - "strictInjectionParameters": true + "strictInjectionParameters": true, + "strictTemplates": true } } From de7a9a3b93d286bcb259aa26147b237faf24b0c6 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Sat, 14 Mar 2020 15:10:15 -0400 Subject: [PATCH 095/262] docs: place download section to the top of the page (#36067) Previously, the download link to the example for the angular element guide was in the middle of the page. To make it easier for the user to find the download link, it has been placed to the top of the page. This commit partially addresses #35459 PR Close #36067 --- aio/content/guide/elements.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aio/content/guide/elements.md b/aio/content/guide/elements.md index 0c409a9085977..f5875823c4293 100644 --- a/aio/content/guide/elements.md +++ b/aio/content/guide/elements.md @@ -2,6 +2,12 @@ _Angular elements_ are Angular components packaged as _custom elements_ (also called Web Components), a web standard for defining new HTML elements in a framework-agnostic way. +<div class="alert is-helpful"> + + For the sample app that this page describes, see the <live-example></live-example>. + +</div> + [Custom elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) are a Web Platform feature currently supported by Chrome, Edge (Chromium-based), Firefox, Opera, and Safari, and available in other browsers through polyfills (see [Browser Support](#browser-support)). A custom element extends HTML by allowing you to define a tag whose content is created and controlled by JavaScript code. The browser maintains a `CustomElementRegistry` of defined custom elements, which maps an instantiable JavaScript class to an HTML tag. @@ -153,12 +159,6 @@ For comparison, the demo shows both methods. One button adds the popup using the </code-pane> </code-tabs> -<!-- - StackBlitz transpiles code to ES5. The live example will not work without a polyfill. - Only offer a `.zip` to download for now. ---> -You can download the full code for the example <live-example downloadOnly>here</live-example>. - ## Typings for custom elements From 76d86d5a070c18db8d4b16d9d368ecc502c0dc8b Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Sun, 15 Mar 2020 13:29:33 -0400 Subject: [PATCH 096/262] docs: place download section in angular pipes to the top (#36073) This commit partially addresses #35459 PR Close #36073 --- aio/content/guide/pipes.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aio/content/guide/pipes.md b/aio/content/guide/pipes.md index 780d6872108f0..25047f9f1e777 100644 --- a/aio/content/guide/pipes.md +++ b/aio/content/guide/pipes.md @@ -3,6 +3,12 @@ Every application starts out with what seems like a simple task: get data, transform them, and show them to users. Getting data could be as simple as creating a local variable or as complex as streaming data over a WebSocket. +<div class="alert is-helpful"> + + For the sample app that this page describes, see the <live-example></live-example>. + +</div> + Once data arrives, you could push their raw `toString` values directly to the view, but that rarely makes for a good user experience. For example, in most use cases, users prefer to see a date in a simple format like @@ -16,8 +22,6 @@ In fact, you might like to apply them in your HTML templates as you do styles. Introducing Angular pipes, a way to write display-value transformations that you can declare in your HTML. -You can run the <live-example></live-example> in Stackblitz and download the code from there. - ## Using pipes From 9a0a90feb3bdf1cf63bb24779f7caa3afb627a3f Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Sun, 15 Mar 2020 15:58:34 -0400 Subject: [PATCH 097/262] docs: place download section in angular forms validation to the top of the page (#36074) This commit partially addresses #35459 PR Close #36074 --- aio/content/guide/form-validation.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/aio/content/guide/form-validation.md b/aio/content/guide/form-validation.md index 03f16e6d17a3f..2b61e533190c6 100644 --- a/aio/content/guide/form-validation.md +++ b/aio/content/guide/form-validation.md @@ -1,14 +1,17 @@ # Form validation - - - Improve overall data quality by validating user input for accuracy and completeness. This page shows how to validate user input in the UI and display useful validation messages using both reactive and template-driven forms. It assumes some basic knowledge of the two forms modules. +<div class="alert is-helpful"> + + For the sample app that this page describes, see the <live-example></live-example>. + +</div> + <div class="alert is-helpful"> If you're new to forms, start by reviewing the [Forms](guide/forms) and @@ -336,5 +339,3 @@ With reactive forms: ```typescript new FormControl('', {updateOn: 'blur'}); ``` - -**You can run the <live-example></live-example> to see the complete reactive and template-driven example code.** From 1927d0c7db0d6e9c289b19d7e99a01891a3c78b7 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Sun, 15 Mar 2020 16:17:27 -0400 Subject: [PATCH 098/262] docs: place download section in angular forms to the top (#36075) This commit partially addresses #35459 PR Close #36075 --- aio/content/guide/forms.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aio/content/guide/forms.md b/aio/content/guide/forms.md index 5eaed4460cf69..e7bd8ea30b28e 100644 --- a/aio/content/guide/forms.md +++ b/aio/content/guide/forms.md @@ -7,6 +7,12 @@ schedule a meeting, and perform countless other data-entry tasks. In developing a form, it's important to create a data-entry experience that guides the user efficiently and effectively through the workflow. +<div class="alert is-helpful"> + + For the sample app that this page describes, see the <live-example></live-example>. + +</div> + ## Introduction to Template-driven forms Developing forms requires design skills (which are out of scope for this page), as well as framework support for @@ -22,8 +28,6 @@ This page shows you how to build a simple form from scratch. Along the way you'l * Display validation errors to users and enable/disable form controls. * Share information across HTML elements using template reference variables. -You can run the <live-example></live-example> in Stackblitz and download the code from there. - {@a template-driven} You can build forms by writing templates in the Angular [template syntax](guide/template-syntax) with From 008e12edda6fe59fff403b2934cd1fe2150adcf1 Mon Sep 17 00:00:00 2001 From: Wagner Maciel <wagnermaciel@google.com> Date: Mon, 23 Mar 2020 12:58:52 -0700 Subject: [PATCH 099/262] fix(benchpress): fix typings in lview_debug.ts (#36236) * Installing & using benchpress was throwing typescript errors because typings were not defined for the getters in lview_debug.ts PR Close #36236 --- .../src/render3/instructions/lview_debug.ts | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index a801bbe5e2aa5..d2b513dc3cf06 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -7,7 +7,8 @@ */ import {AttributeMarker, ComponentTemplate} from '..'; -import {SchemaMetadata} from '../../core'; +import {Injector, SchemaMetadata} from '../../core'; +import {Sanitizer} from '../../sanitization/sanitizer'; import {KeyValueArray} from '../../util/array_utils'; import {assertDefined} from '../../util/assert'; import {createNamedArrayType} from '../../util/named_array_type'; @@ -17,8 +18,8 @@ import {DirectiveDefList, PipeDefList, ViewQueriesFunction} from '../interfaces/ import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, TIcu} from '../interfaces/i18n'; import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node'; import {SelectorFlags} from '../interfaces/projection'; -import {TQueries} from '../interfaces/query'; -import {RComment, RElement, RNode} from '../interfaces/renderer'; +import {LQueries, TQueries} from '../interfaces/query'; +import {RComment, RElement, RNode, Renderer3, RendererFactory3} from '../interfaces/renderer'; import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '../interfaces/styling'; import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, HookData, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TData, TVIEW, TView as ITView, TView, TViewType, T_HOST} from '../interfaces/view'; import {attachDebugObject} from '../util/debug_utils'; @@ -404,18 +405,18 @@ export class LViewDebug { return toDebugNodes(tNode, lView); } - get tView() { return this._raw_lView[TVIEW]; } - get cleanup() { return this._raw_lView[CLEANUP]; } - get injector() { return this._raw_lView[INJECTOR]; } - get rendererFactory() { return this._raw_lView[RENDERER_FACTORY]; } - get renderer() { return this._raw_lView[RENDERER]; } - get sanitizer() { return this._raw_lView[SANITIZER]; } - get childHead() { return toDebug(this._raw_lView[CHILD_HEAD]); } - get next() { return toDebug(this._raw_lView[NEXT]); } - get childTail() { return toDebug(this._raw_lView[CHILD_TAIL]); } - get declarationView() { return toDebug(this._raw_lView[DECLARATION_VIEW]); } - get queries() { return this._raw_lView[QUERIES]; } - get tHost() { return this._raw_lView[T_HOST]; } + get tView(): ITView { return this._raw_lView[TVIEW]; } + get cleanup(): any[]|null { return this._raw_lView[CLEANUP]; } + get injector(): Injector|null { return this._raw_lView[INJECTOR]; } + get rendererFactory(): RendererFactory3 { return this._raw_lView[RENDERER_FACTORY]; } + get renderer(): Renderer3 { return this._raw_lView[RENDERER]; } + get sanitizer(): Sanitizer|null { return this._raw_lView[SANITIZER]; } + get childHead(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[CHILD_HEAD]); } + get next(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[NEXT]); } + get childTail(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[CHILD_TAIL]); } + get declarationView(): LViewDebug|null { return toDebug(this._raw_lView[DECLARATION_VIEW]); } + get queries(): LQueries|null { return this._raw_lView[QUERIES]; } + get tHost(): TViewNode|TElementNode|null { return this._raw_lView[T_HOST]; } /** * Normalized view of child views (and containers) attached at this location. From 0af6e9fcbbfd9986e6ac221e21ca4c2603b8f506 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Fri, 3 Apr 2020 16:37:43 +0300 Subject: [PATCH 100/262] refactor(ngcc): move logic for identifying known declarations to method (#36284) The `NgccReflectionHost`s have logic for detecting certain known declarations (such as `Object.assign()` and TypeScript helpers), which allows the `PartialEvaluator` to evaluate expressions it would not be able to statically evaluate otherwise. This commit moves the logic for identifying these known declarations to dedicated methods. This is in preparation of allowing ngcc's `DelegatingReflectionHost` (introduced in #36089) to also apply the known declaration detection logic when reflecting on TypeScript sources. PR Close #36284 --- .../ngcc/src/host/esm2015_host.ts | 110 +++++++++++------- .../compiler-cli/ngcc/src/host/esm5_host.ts | 58 +++++---- 2 files changed, 103 insertions(+), 65 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts index d7b873752b618..4cb8b5087011b 100644 --- a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts @@ -8,13 +8,13 @@ import * as ts from 'typescript'; -import {ClassDeclaration, ClassMember, ClassMemberKind, ConcreteDeclaration, CtorParameter, Declaration, Decorator, KnownDeclaration, TypeScriptReflectionHost, TypeValueReference, isDecoratorIdentifier, reflectObjectLiteral,} from '../../../src/ngtsc/reflection'; +import {ClassDeclaration, ClassMember, ClassMemberKind, ConcreteDeclaration, CtorParameter, Declaration, Decorator, isDecoratorIdentifier, KnownDeclaration, reflectObjectLiteral, TypeScriptReflectionHost, TypeValueReference,} from '../../../src/ngtsc/reflection'; import {isWithinPackage} from '../analysis/util'; import {Logger} from '../logging/logger'; import {BundleProgram} from '../packages/bundle_program'; import {findAll, getNameText, hasNameIdentifier, isDefined, stripDollarSuffix} from '../utils'; -import {ClassSymbol, ModuleWithProvidersFunction, NgccClassSymbol, NgccReflectionHost, PRE_R3_MARKER, SwitchableVariableDeclaration, isSwitchableVariableDeclaration} from './ngcc_host'; +import {ClassSymbol, isSwitchableVariableDeclaration, ModuleWithProvidersFunction, NgccClassSymbol, NgccReflectionHost, PRE_R3_MARKER, SwitchableVariableDeclaration} from './ngcc_host'; export const DECORATORS = 'decorators' as ts.__String; export const PROP_DECORATORS = 'propDecorators' as ts.__String; @@ -346,24 +346,14 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N // The identifier may have been of an additional class assignment such as `MyClass_1` that was // present as alias for `MyClass`. If so, resolve such aliases to their original declaration. - if (superDeclaration !== null && superDeclaration.node !== null) { + if (superDeclaration !== null && superDeclaration.node !== null && + superDeclaration.known === null) { const aliasedIdentifier = this.resolveAliasedClassIdentifier(superDeclaration.node); if (aliasedIdentifier !== null) { return this.getDeclarationOfIdentifier(aliasedIdentifier); } } - // If the identifier resolves to the global JavaScript `Object`, return a - // declaration that denotes it as the known `JsGlobalObject` declaration. - if (superDeclaration !== null && this.isJavaScriptObjectDeclaration(superDeclaration)) { - return { - known: KnownDeclaration.JsGlobalObject, - expression: id, - viaModule: null, - node: null, - }; - } - return superDeclaration; } @@ -511,8 +501,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N return null; } if (!isNamedDeclaration(declaration)) { - throw new Error( - `Cannot get the dts file for a declaration that has no name: ${declaration.getText()} in ${declaration.getSourceFile().fileName}`); + throw new Error(`Cannot get the dts file for a declaration that has no name: ${ + declaration.getText()} in ${declaration.getSourceFile().fileName}`); } // Try to retrieve the dts declaration from the public map @@ -520,7 +510,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N this.publicDtsDeclarationMap = this.computePublicDtsDeclarationMap(this.src, this.dts); } if (this.publicDtsDeclarationMap.has(declaration)) { - return this.publicDtsDeclarationMap.get(declaration) !; + return this.publicDtsDeclarationMap.get(declaration)!; } // No public export, try the private map @@ -528,7 +518,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N this.privateDtsDeclarationMap = this.computePrivateDtsDeclarationMap(this.src, this.dts); } if (this.privateDtsDeclarationMap.has(declaration)) { - return this.privateDtsDeclarationMap.get(declaration) !; + return this.privateDtsDeclarationMap.get(declaration)!; } // No declaration found at all @@ -602,8 +592,38 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N return last; } + /** + * Check whether a `Declaration` corresponds with a known declaration, such as `Object`, and set + * its `known` property to the appropriate `KnownDeclaration`. + * + * @param decl The `Declaration` to check. + * @return The passed in `Declaration` (potentially enhanced with a `KnownDeclaration`). + */ + detectKnownDeclaration(decl: null): null; + detectKnownDeclaration<T extends Declaration>(decl: T): T; + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null; + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null { + if (decl !== null && decl.known === null && this.isJavaScriptObjectDeclaration(decl)) { + // If the identifier resolves to the global JavaScript `Object`, update the declaration to + // denote it as the known `JsGlobalObject` declaration. + decl.known = KnownDeclaration.JsGlobalObject; + } + + return decl; + } + + ///////////// Protected Helpers ///////////// + /** + * Resolve a `ts.Symbol` to its declaration and detect whether it corresponds with a known + * declaration. + */ + protected getDeclarationOfSymbol(symbol: ts.Symbol, originalId: ts.Identifier|null): Declaration + |null { + return this.detectKnownDeclaration(super.getDeclarationOfSymbol(symbol, originalId)); + } + /** * Finds the identifier of the actual class declaration for a potentially aliased declaration of a * class. @@ -618,7 +638,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N protected resolveAliasedClassIdentifier(declaration: ts.Declaration): ts.Identifier|null { this.ensurePreprocessed(declaration.getSourceFile()); return this.aliasedClassDeclarations.has(declaration) ? - this.aliasedClassDeclarations.get(declaration) ! : + this.aliasedClassDeclarations.get(declaration)! : null; } @@ -674,7 +694,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N this.aliasedClassDeclarations.set(aliasedDeclaration.node, declaration.name); } - /** Get the top level statements for a module. + /** + * Get the top level statements for a module. * * In ES5 and ES2015 this is just the top level statements of the file. * @param sourceFile The module whose statements we want. @@ -728,7 +749,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N protected acquireDecoratorInfo(classSymbol: NgccClassSymbol): DecoratorInfo { const decl = classSymbol.declaration.valueDeclaration; if (this.decoratorCache.has(decl)) { - return this.decoratorCache.get(decl) !; + return this.decoratorCache.get(decl)!; } // Extract decorators from static properties and `__decorate` helper calls, then merge them @@ -757,7 +778,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N * none of the static properties exist. */ protected computeDecoratorInfoFromStaticProperties(classSymbol: NgccClassSymbol): { - classDecorators: Decorator[] | null; memberDecorators: Map<string, Decorator[]>| null; + classDecorators: Decorator[]|null; memberDecorators: Map<string, Decorator[]>| null; constructorParamInfo: ParamInfo[] | null; } { let classDecorators: Decorator[]|null = null; @@ -1026,7 +1047,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N // The helper arg was reflected to represent an actual decorator. if (this.isFromCore(entry.decorator)) { const decorators = - memberDecorators.has(memberName) ? memberDecorators.get(memberName) ! : []; + memberDecorators.has(memberName) ? memberDecorators.get(memberName)! : []; decorators.push(entry.decorator); memberDecorators.set(memberName, decorators); } @@ -1193,7 +1214,6 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N if (ts.isArrayLiteralExpression(decoratorsArray)) { // Add each decorator that is imported from `@angular/core` into the `decorators` array decoratorsArray.elements.forEach(node => { - // If the decorator is not an object literal expression then we are not interested if (ts.isObjectLiteralExpression(node)) { // We are only interested in objects of the form: `{ type: DecoratorType, args: [...] }` @@ -1201,14 +1221,15 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N // Is the value of the `type` property an identifier? if (decorator.has('type')) { - let decoratorType = decorator.get('type') !; + let decoratorType = decorator.get('type')!; if (isDecoratorIdentifier(decoratorType)) { const decoratorIdentifier = ts.isIdentifier(decoratorType) ? decoratorType : decoratorType.name; decorators.push({ name: decoratorIdentifier.text, identifier: decoratorType, - import: this.getImportOfIdentifier(decoratorIdentifier), node, + import: this.getImportOfIdentifier(decoratorIdentifier), + node, args: getDecoratorArgs(node), }); } @@ -1347,7 +1368,13 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N const type: ts.TypeNode = (node as any).type || null; return { node, - implementation: node, kind, type, name, nameNode, value, isStatic, + implementation: node, + kind, + type, + name, + nameNode, + value, + isStatic, decorators: decorators || [] }; } @@ -1362,7 +1389,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N ts.ParameterDeclaration[]|null { const members = classSymbol.implementation.members; if (members && members.has(CONSTRUCTOR)) { - const constructorSymbol = members.get(CONSTRUCTOR) !; + const constructorSymbol = members.get(CONSTRUCTOR)!; // For some reason the constructor does not have a `valueDeclaration` ?!? const constructor = constructorSymbol.declarations && constructorSymbol.declarations[0] as ts.ConstructorDeclaration | undefined; @@ -1424,7 +1451,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N name: getNameText(nameNode), nameNode, typeValueReference, - typeNode: null, decorators + typeNode: null, + decorators }; }); } @@ -1473,9 +1501,9 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N ts.isObjectLiteralExpression(element) ? reflectObjectLiteral(element) : null) .map(paramInfo => { const typeExpression = - paramInfo && paramInfo.has('type') ? paramInfo.get('type') ! : null; + paramInfo && paramInfo.has('type') ? paramInfo.get('type')! : null; const decoratorInfo = - paramInfo && paramInfo.has('decorators') ? paramInfo.get('decorators') ! : null; + paramInfo && paramInfo.has('decorators') ? paramInfo.get('decorators')! : null; const decorators = decoratorInfo && this.reflectDecorators(decoratorInfo) .filter(decorator => this.isFromCore(decorator)); @@ -1619,7 +1647,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N if (fileExports !== null) { for (const [exportName, {node: declaration}] of fileExports) { if (declaration !== null && dtsDeclarationMap.has(exportName)) { - declarationMap.set(declaration, dtsDeclarationMap.get(exportName) !); + declarationMap.set(declaration, dtsDeclarationMap.get(exportName)!); } } } @@ -1670,15 +1698,17 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N const ngModuleDeclaration = this.getDeclarationOfExpression(ngModuleValue); if (!ngModuleDeclaration || ngModuleDeclaration.node === null) { - throw new Error( - `Cannot find a declaration for NgModule ${ngModuleValue.getText()} referenced in "${declaration!.getText()}"`); + throw new Error(`Cannot find a declaration for NgModule ${ + ngModuleValue.getText()} referenced in "${declaration!.getText()}"`); } if (!hasNameIdentifier(ngModuleDeclaration.node)) { return null; } return { name, - ngModule: ngModuleDeclaration as ConcreteDeclaration<ClassDeclaration>, declaration, container + ngModule: ngModuleDeclaration as ConcreteDeclaration<ClassDeclaration>, + declaration, + container }; } @@ -1705,7 +1735,7 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N return null; } - const exportDecl = namespaceExports.get(expression.name.text) !; + const exportDecl = namespaceExports.get(expression.name.text)!; return {...exportDecl, viaModule: namespaceDecl.viaModule}; } @@ -1737,8 +1767,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N ///////////// Exported Helpers ///////////// export type ParamInfo = { - decorators: Decorator[] | null, - typeExpression: ts.Expression | null + decorators: Decorator[]|null, + typeExpression: ts.Expression|null }; /** @@ -1782,7 +1812,7 @@ export interface DecoratorCall { * ], SomeDirective); * ``` */ -export type DecorateHelperEntry = ParameterTypes | ParameterDecorators | DecoratorCall; +export type DecorateHelperEntry = ParameterTypes|ParameterDecorators|DecoratorCall; /** * The recorded decorator information of a single class. This information is cached in the host. @@ -1811,7 +1841,7 @@ interface DecoratorInfo { * A statement node that represents an assignment. */ export type AssignmentStatement = - ts.ExpressionStatement & {expression: {left: ts.Identifier, right: ts.Expression}}; + ts.ExpressionStatement&{expression: {left: ts.Identifier, right: ts.Expression}}; /** * Test whether a statement node is an assignment statement. diff --git a/packages/compiler-cli/ngcc/src/host/esm5_host.ts b/packages/compiler-cli/ngcc/src/host/esm5_host.ts index 4c8bb221260fc..67c7abb291d09 100644 --- a/packages/compiler-cli/ngcc/src/host/esm5_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm5_host.ts @@ -8,10 +8,10 @@ import * as ts from 'typescript'; -import {ClassDeclaration, ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, Parameter, isNamedVariableDeclaration, reflectObjectLiteral} from '../../../src/ngtsc/reflection'; +import {ClassDeclaration, ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, isNamedVariableDeclaration, Parameter, reflectObjectLiteral} from '../../../src/ngtsc/reflection'; import {getNameText, getTsHelperFnFromDeclaration, hasNameIdentifier} from '../utils'; -import {Esm2015ReflectionHost, ParamInfo, getPropertyValueFromSymbol, isAssignment, isAssignmentStatement} from './esm2015_host'; +import {Esm2015ReflectionHost, getPropertyValueFromSymbol, isAssignment, isAssignmentStatement, ParamInfo} from './esm2015_host'; import {NgccClassSymbol} from './ngcc_host'; @@ -81,12 +81,13 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { getInternalNameOfClass(clazz: ClassDeclaration): ts.Identifier { const innerClass = this.getInnerFunctionDeclarationFromClassDeclaration(clazz); if (innerClass === undefined) { - throw new Error( - `getInternalNameOfClass() called on a non-ES5 class: expected ${clazz.name.text} to have an inner class declaration`); + throw new Error(`getInternalNameOfClass() called on a non-ES5 class: expected ${ + clazz.name.text} to have an inner class declaration`); } if (innerClass.name === undefined) { throw new Error( - `getInternalNameOfClass() called on a class with an anonymous inner declaration: expected a name on:\n${innerClass.getText()}`); + `getInternalNameOfClass() called on a class with an anonymous inner declaration: expected a name on:\n${ + innerClass.getText()}`); } return innerClass.name; } @@ -98,14 +99,15 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { getEndOfClass(classSymbol: NgccClassSymbol): ts.Node { const iifeBody = getIifeBody(classSymbol.declaration.valueDeclaration); if (!iifeBody) { - throw new Error( - `Compiled class declaration is not inside an IIFE: ${classSymbol.name} in ${classSymbol.declaration.valueDeclaration.getSourceFile().fileName}`); + throw new Error(`Compiled class declaration is not inside an IIFE: ${classSymbol.name} in ${ + classSymbol.declaration.valueDeclaration.getSourceFile().fileName}`); } const returnStatementIndex = iifeBody.statements.findIndex(ts.isReturnStatement); if (returnStatementIndex === -1) { throw new Error( - `Compiled class wrapper IIFE does not have a return statement: ${classSymbol.name} in ${classSymbol.declaration.valueDeclaration.getSourceFile().fileName}`); + `Compiled class wrapper IIFE does not have a return statement: ${classSymbol.name} in ${ + classSymbol.declaration.valueDeclaration.getSourceFile().fileName}`); } // Return the statement before the IIFE return statement @@ -190,7 +192,8 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null { const superDeclaration = super.getDeclarationOfIdentifier(id); - if (superDeclaration === null || superDeclaration.node === null) { + if (superDeclaration === null || superDeclaration.node === null || + superDeclaration.known !== null) { return superDeclaration; } @@ -200,7 +203,7 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { super.getDeclarationOfIdentifier(outerClassNode.name) : superDeclaration; - if (!declaration || declaration.node === null) { + if (declaration === null || declaration.node === null || declaration.known !== null) { return declaration; } @@ -257,24 +260,29 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { return {node, body: statements || null, parameters}; } - - ///////////// Protected Helpers ///////////// /** - * Resolve a `ts.Symbol` to its declaration and detect whether it corresponds with a known - * TypeScript helper function. + * Check whether a `Declaration` corresponds with a known declaration, such as a TypeScript helper + * function, and set its `known` property to the appropriate `KnownDeclaration`. + * + * @param decl The `Declaration` to check. + * @return The passed in `Declaration` (potentially enhanced with a `KnownDeclaration`). */ - protected getDeclarationOfSymbol(symbol: ts.Symbol, originalId: ts.Identifier|null): Declaration - |null { - const superDeclaration = super.getDeclarationOfSymbol(symbol, originalId); - - if (superDeclaration !== null && superDeclaration.node !== null && - superDeclaration.known === null) { - superDeclaration.known = getTsHelperFnFromDeclaration(superDeclaration.node); + detectKnownDeclaration(decl: null): null; + detectKnownDeclaration<T extends Declaration>(decl: T): T; + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null; + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null { + decl = super.detectKnownDeclaration(decl); + + if (decl !== null && decl.known === null && decl.node !== null) { + decl.known = getTsHelperFnFromDeclaration(decl.node); } - return superDeclaration; + return decl; } + + ///////////// Protected Helpers ///////////// + /** * Get the inner function declaration of an ES5-style class. * @@ -368,9 +376,9 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { if (expression && ts.isArrayLiteralExpression(expression)) { const elements = expression.elements; return elements.map(reflectArrayElement).map(paramInfo => { - const typeExpression = paramInfo && paramInfo.has('type') ? paramInfo.get('type') ! : null; + const typeExpression = paramInfo && paramInfo.has('type') ? paramInfo.get('type')! : null; const decoratorInfo = - paramInfo && paramInfo.has('decorators') ? paramInfo.get('decorators') ! : null; + paramInfo && paramInfo.has('decorators') ? paramInfo.get('decorators')! : null; const decorators = decoratorInfo && this.reflectDecorators(decoratorInfo); return {typeExpression, decorators}; }); @@ -634,7 +642,7 @@ function getReturnIdentifier(body: ts.Block): ts.Identifier|undefined { return undefined; } -function getReturnStatement(declaration: ts.Expression | undefined): ts.ReturnStatement|undefined { +function getReturnStatement(declaration: ts.Expression|undefined): ts.ReturnStatement|undefined { return declaration && ts.isFunctionExpression(declaration) ? declaration.body.statements.find(ts.isReturnStatement) : undefined; From 93f07aee6c02fc862856f3b2f9cb8f5bafd67863 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Fri, 3 Apr 2020 16:37:45 +0300 Subject: [PATCH 101/262] test(ngcc): use `DelegatingReflectionHost` for testing `NgccReflectionHost`s (#36284) In #36089, `DelegatingReflectionHost` was introduced. Under the hood, it delegates another `NgccReflectionHost` in order to reflect over the program's source files, while using a different TypeScript `ReflectionHost` to reflect over `.d.ts` files (which is how external dependencies are represented in the program). Previously, the `NgccReflectionHost`s were used directly in tests. This does not exercise them in the way they are exercised in the actual program, because (when used directly) they will also reflect on `.d.ts` files too (instead of delegating to the TypeScript `ReflectionHost`). This could hide bugs that would happen on the actual program. This commit fixes this by using the `DelegatingReflectionHost` in the various `NgccReflectionHost` tests. NOTE: This change will cause some of the existing tests to start failing. These failures demonstrate pre-existing bugs in ngcc, that were hidden due to the tests' being inconsistent with how the `ReflectionHost`s are used in the actual program. They will be fixed in the next commit. PR Close #36284 --- .../ngcc/test/host/commonjs_host_spec.ts | 565 ++++++++++-------- .../ngcc/test/host/esm2015_host_spec.ts | 509 +++++++++------- .../ngcc/test/host/esm5_host_spec.ts | 540 +++++++++-------- .../ngcc/test/host/umd_host_spec.ts | 511 ++++++++-------- 4 files changed, 1156 insertions(+), 969 deletions(-) diff --git a/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts b/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts index 3ebd4f1fd526c..421bab1b0d2f5 100644 --- a/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts @@ -8,12 +8,15 @@ import * as ts from 'typescript'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {ClassMemberKind, CtorParameter, InlineDeclaration, KnownDeclaration, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; +import {ClassMemberKind, CtorParameter, InlineDeclaration, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration, KnownDeclaration, TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; import {CommonJsReflectionHost} from '../../src/host/commonjs_host'; +import {DelegatingReflectionHost} from '../../src/host/delegating_host'; import {getIifeBody} from '../../src/host/esm5_host'; +import {NgccReflectionHost} from '../../src/host/ngcc_host'; +import {BundleProgram} from '../../src/packages/bundle_program'; import {MockLogger} from '../helpers/mock_logger'; import {getRootFiles, makeTestBundleProgram, makeTestDtsBundleProgram} from '../helpers/utils'; @@ -21,7 +24,6 @@ import {expectTypeValueReferencesForParameters} from './util'; runInEachFileSystem(() => { describe('CommonJsReflectionHost', () => { - let _: typeof absoluteFrom; let SOME_DIRECTIVE_FILE: TestFile; @@ -45,6 +47,12 @@ runInEachFileSystem(() => { let TYPINGS_DTS_FILES: TestFile[]; let MODULE_WITH_PROVIDERS_PROGRAM: TestFile[]; + // Helpers + const createHost = (bundle: BundleProgram, ngccHost: CommonJsReflectionHost) => { + const tsHost = new TypeScriptReflectionHost(bundle.program.getTypeChecker()); + return new DelegatingReflectionHost(tsHost, ngccHost); + }; + beforeEach(() => { _ = absoluteFrom; @@ -916,16 +924,16 @@ exports.ExternalModule = ExternalModule; }); describe('CommonJsReflectionHost', () => { - describe('getDecoratorsOfDeclaration()', () => { it('should find the decorators on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -933,7 +941,7 @@ exports.ExternalModule = ExternalModule; const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -941,11 +949,12 @@ exports.ExternalModule = ExternalModule; it('should find the decorators on a class at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -953,7 +962,7 @@ exports.ExternalModule = ExternalModule; const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -961,7 +970,8 @@ exports.ExternalModule = ExternalModule; it('should return null if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const decorators = host.getDecoratorsOfDeclaration(functionNode); @@ -971,7 +981,8 @@ exports.ExternalModule = ExternalModule; it('should return null if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const decorators = host.getDecoratorsOfDeclaration(classNode); @@ -981,7 +992,8 @@ exports.ExternalModule = ExternalModule; it('should ignore `decorators` if it is not an array literal', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); @@ -992,11 +1004,12 @@ exports.ExternalModule = ExternalModule; it('should ignore decorator elements that are not object literals', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1005,11 +1018,12 @@ exports.ExternalModule = ExternalModule; it('should ignore decorator elements that have no `type` property', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1018,11 +1032,12 @@ exports.ExternalModule = ExternalModule; it('should ignore decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1032,11 +1047,12 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if decorator has no `args` property', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1046,11 +1062,12 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if decorator\'s `args` has no property assignment', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1060,11 +1077,12 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1077,94 +1095,100 @@ exports.ExternalModule = ExternalModule; it('should find decorated members on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find decorated members on a class at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find non decorated properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const instanceProperty = members.find(member => member.name === 'instanceProperty') !; + const instanceProperty = members.find(member => member.name === 'instanceProperty')!; expect(instanceProperty.kind).toEqual(ClassMemberKind.Property); expect(instanceProperty.isStatic).toEqual(false); - expect(ts.isBinaryExpression(instanceProperty.implementation !)).toEqual(true); - expect(instanceProperty.value !.getText()).toEqual(`'instance'`); + expect(ts.isBinaryExpression(instanceProperty.implementation!)).toEqual(true); + expect(instanceProperty.value!.getText()).toEqual(`'instance'`); }); it('should find static methods on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticMethod = members.find(member => member.name === 'staticMethod') !; + const staticMethod = members.find(member => member.name === 'staticMethod')!; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); - expect(ts.isFunctionExpression(staticMethod.implementation !)).toEqual(true); + expect(ts.isFunctionExpression(staticMethod.implementation!)).toEqual(true); }); it('should find static properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(() => { @@ -1175,7 +1199,8 @@ exports.ExternalModule = ExternalModule; it('should return an empty array if there are no prop decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); @@ -1187,7 +1212,8 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); @@ -1199,13 +1225,14 @@ exports.ExternalModule = ExternalModule; it('should ignore prop decorator elements that are not object literals', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1214,13 +1241,14 @@ exports.ExternalModule = ExternalModule; it('should ignore prop decorator elements that have no `type` property', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1229,13 +1257,14 @@ exports.ExternalModule = ExternalModule; it('should ignore prop decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1244,12 +1273,13 @@ exports.ExternalModule = ExternalModule; it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'}); @@ -1259,13 +1289,14 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if prop decorator has no `args` property', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1276,13 +1307,14 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1292,13 +1324,14 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1311,17 +1344,18 @@ exports.ExternalModule = ExternalModule; it('should find the decorated constructor parameters', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -1331,17 +1365,18 @@ exports.ExternalModule = ExternalModule; it('should find the decorated constructor parameters at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -1351,11 +1386,12 @@ exports.ExternalModule = ExternalModule; it('should accept `ctorParameters` as an array', () => { loadTestFiles([CTOR_DECORATORS_ARRAY_FILE]); const bundle = makeTestBundleProgram(CTOR_DECORATORS_ARRAY_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, CTOR_DECORATORS_ARRAY_FILE.name, 'CtorDecoratedAsArray', isNamedVariableDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters).toBeDefined(); expect(parameters.map(parameter => parameter.name)).toEqual(['arg1']); @@ -1365,10 +1401,13 @@ exports.ExternalModule = ExternalModule; it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); - expect(() => { host.getConstructorParameters(functionNode); }) + expect(() => { + host.getConstructorParameters(functionNode); + }) .toThrowError( 'Attempted to get constructor parameters of a non-class: "function foo() {}"'); }); @@ -1379,22 +1418,24 @@ exports.ExternalModule = ExternalModule; it('should return an array even if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toEqual(jasmine.any(Array)); - expect(parameters !.length).toEqual(1); - expect(parameters ![0].name).toEqual('foo'); - expect(parameters ![0].decorators).toBe(null); + expect(parameters!.length).toEqual(1); + expect(parameters![0].name).toEqual('foo'); + expect(parameters![0].decorators).toBe(null); }); it('should return an empty array if there are no constructor parameters', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', isNamedVariableDeclaration); @@ -1409,14 +1450,15 @@ exports.ExternalModule = ExternalModule; it('should ignore `ctorParameters` if it does not return an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(1); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); @@ -1426,18 +1468,19 @@ exports.ExternalModule = ExternalModule; it('should ignore param decorator elements that are not object literals', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(2); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(2); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); - expect(parameters ![1]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters![1]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg2', decorators: jasmine.any(Array) as any })); @@ -1446,12 +1489,13 @@ exports.ExternalModule = ExternalModule; it('should ignore param decorator elements that have no `type` property', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1461,12 +1505,13 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1475,13 +1520,14 @@ exports.ExternalModule = ExternalModule; it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![2].decorators !; + const decorators = parameters![2].decorators!; expect(decorators.length).toEqual(1); expect(decorators[0].name).toBe('Inject'); @@ -1493,13 +1539,14 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if param decorator has no `args` property', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - const decorators = parameters ![0].decorators !; + expect(parameters!.length).toBe(1); + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1510,12 +1557,13 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1525,12 +1573,13 @@ exports.ExternalModule = ExternalModule; it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1544,45 +1593,46 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([FUNCTION_BODY_FILE]); const bundle = makeTestBundleProgram(FUNCTION_BODY_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const fooNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration) !; - const fooDef = host.getDefinitionOfFunction(fooNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration)!; + const fooDef = host.getDefinitionOfFunction(fooNode)!; expect(fooDef.node).toBe(fooNode); - expect(fooDef.body !.length).toEqual(1); - expect(fooDef.body ![0].getText()).toEqual(`return x;`); + expect(fooDef.body!.length).toEqual(1); + expect(fooDef.body![0].getText()).toEqual(`return x;`); expect(fooDef.parameters.length).toEqual(1); expect(fooDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); const barNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration) !; - const barDef = host.getDefinitionOfFunction(barNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration)!; + const barDef = host.getDefinitionOfFunction(barNode)!; expect(barDef.node).toBe(barNode); - expect(barDef.body !.length).toEqual(1); - expect(ts.isReturnStatement(barDef.body ![0])).toBeTruthy(); - expect(barDef.body ![0].getText()).toEqual(`return x + y;`); + expect(barDef.body!.length).toEqual(1); + expect(ts.isReturnStatement(barDef.body![0])).toBeTruthy(); + expect(barDef.body![0].getText()).toEqual(`return x + y;`); expect(barDef.parameters.length).toEqual(2); expect(barDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); expect(barDef.parameters[1].name).toEqual('y'); - expect(barDef.parameters[1].initializer !.getText()).toEqual('42'); + expect(barDef.parameters[1].initializer!.getText()).toEqual('42'); const bazNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration) !; - const bazDef = host.getDefinitionOfFunction(bazNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration)!; + const bazDef = host.getDefinitionOfFunction(bazNode)!; expect(bazDef.node).toBe(bazNode); - expect(bazDef.body !.length).toEqual(3); + expect(bazDef.body!.length).toEqual(3); expect(bazDef.parameters.length).toEqual(1); expect(bazDef.parameters[0].name).toEqual('x'); expect(bazDef.parameters[0].initializer).toBe(null); const quxNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration) !; - const quxDef = host.getDefinitionOfFunction(quxNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration)!; + const quxDef = host.getDefinitionOfFunction(quxNode)!; expect(quxDef.node).toBe(quxNode); - expect(quxDef.body !.length).toEqual(2); + expect(quxDef.body!.length).toEqual(2); expect(quxDef.parameters.length).toEqual(1); expect(quxDef.parameters[0].name).toEqual('x'); expect(quxDef.parameters[0].initializer).toBe(null); @@ -1593,7 +1643,8 @@ exports.ExternalModule = ExternalModule; it('should find the import of an identifier', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/file_b.js'), 'b', isNamedVariableDeclaration); const identifier = (variableNode.initializer && @@ -1603,14 +1654,15 @@ exports.ExternalModule = ExternalModule; null; expect(identifier).not.toBe(null); - const importOfIdent = host.getImportOfIdentifier(identifier !); + const importOfIdent = host.getImportOfIdentifier(identifier!); expect(importOfIdent).toEqual({name: 'a', from: './file_a'}); }); it('should return null if the identifier was not imported', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/file_b.js'), 'd', isNamedVariableDeclaration); const importOfIdent = @@ -1622,7 +1674,8 @@ exports.ExternalModule = ExternalModule; it('should handle factory functions not wrapped in parentheses', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/file_c.js'), 'c', isNamedVariableDeclaration); const identifier = (variableNode.initializer && @@ -1632,7 +1685,7 @@ exports.ExternalModule = ExternalModule; null; expect(identifier).not.toBe(null); - const importOfIdent = host.getImportOfIdentifier(identifier !); + const importOfIdent = host.getImportOfIdentifier(identifier!); expect(importOfIdent).toEqual({name: 'a', from: './file_a'}); }); }); @@ -1640,10 +1693,10 @@ exports.ExternalModule = ExternalModule; describe('getDeclarationOfIdentifier', () => { // Helpers const createTestForTsHelper = - (program: ts.Program, host: CommonJsReflectionHost, srcFile: TestFile, + (program: ts.Program, host: NgccReflectionHost, srcFile: TestFile, getHelperDeclaration: (name: string) => ts.Declaration) => (varName: string, helperName: string, knownAs: KnownDeclaration, - viaModule: string | null = null) => { + viaModule: string|null = null) => { const node = getDeclaration(program, srcFile.name, varName, ts.isVariableDeclaration); const helperIdentifier = getIdentifierFromCallExpression(node); @@ -1651,7 +1704,8 @@ exports.ExternalModule = ExternalModule; expect(helperDeclaration).toEqual({ known: knownAs, - node: getHelperDeclaration(helperName), viaModule, + node: getHelperDeclaration(helperName), + viaModule, }); }; @@ -1667,12 +1721,13 @@ exports.ExternalModule = ExternalModule; it('should return the declaration of a locally defined identifier', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const ctrDecorators = host.getConstructorParameters(classNode) !; - const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference !as{ + const ctrDecorators = host.getConstructorParameters(classNode)!; + const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference! as { local: true, expression: ts.Identifier, defaultImportStatement: null, @@ -1683,8 +1738,8 @@ exports.ExternalModule = ExternalModule; isNamedVariableDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfViewContainerRef); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe(null); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe(null); }); it('should return the correct declaration for an outer alias identifier', () => { @@ -1702,7 +1757,8 @@ exports.ExternalModule = ExternalModule; loadTestFiles([PROGRAM_FILE]); const bundle = makeTestBundleProgram(PROGRAM_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const expectedDeclaration = getDeclaration( bundle.program, PROGRAM_FILE.name, 'AliasedClass', isNamedVariableDeclaration); @@ -1713,29 +1769,31 @@ exports.ExternalModule = ExternalModule; expect(aliasIdentifier.getText()).toBe('AliasedClass_1'); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclaration); + expect(actualDeclaration!.node).toBe(expectedDeclaration); }); it('should return the source-file of an import namespace', () => { loadFakeCore(getFileSystem()); loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const identifierOfDirective = (((classDecorators[0].node as ts.ObjectLiteralExpression) - .properties[0] as ts.PropertyAssignment) - .initializer as ts.PropertyAccessExpression) - .expression as ts.Identifier; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const identifierOfDirective = + (((classDecorators[0].node as ts.ObjectLiteralExpression).properties[0] as + ts.PropertyAssignment) + .initializer as ts.PropertyAccessExpression) + .expression as ts.Identifier; const expectedDeclarationNode = getSourceFileOrError(bundle.program, _('/node_modules/@angular/core/index.d.ts')); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should return viaModule: null for relative imports', () => { @@ -1756,12 +1814,13 @@ exports.ExternalModule = ExternalModule; ]); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/index.js'), 'b', isNamedVariableDeclaration); const identifier = variableNode.name as ts.Identifier; - const importOfIdent = host.getDeclarationOfIdentifier(identifier !) !; + const importOfIdent = host.getDeclarationOfIdentifier(identifier!)!; expect(importOfIdent.node).not.toBeNull(); expect(importOfIdent.viaModule).toBeNull(); }); @@ -1782,13 +1841,14 @@ exports.ExternalModule = ExternalModule; ]); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/index.js'), 'b', isNamedVariableDeclaration); const identifier = - (variableNode.initializer !as ts.PropertyAccessExpression).name as ts.Identifier; + (variableNode.initializer! as ts.PropertyAccessExpression).name as ts.Identifier; - const importOfIdent = host.getDeclarationOfIdentifier(identifier !) !; + const importOfIdent = host.getDeclarationOfIdentifier(identifier!)!; expect(importOfIdent.viaModule).toBe('lib'); }); @@ -1807,7 +1867,8 @@ exports.ExternalModule = ExternalModule; }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -1834,7 +1895,8 @@ exports.ExternalModule = ExternalModule; }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -1861,7 +1923,8 @@ exports.ExternalModule = ExternalModule; }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -1888,7 +1951,8 @@ exports.ExternalModule = ExternalModule; }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -1925,7 +1989,8 @@ exports.ExternalModule = ExternalModule; const [testFile, tslibFile] = files; const bundle = makeTestBundleProgram(testFile.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const tslibSourceFile = getSourceFileOrError(bundle.program, tslibFile.name); const testForHelper = @@ -1942,12 +2007,13 @@ exports.ExternalModule = ExternalModule; loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/b_module.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, '@angular/core'], ['a', `a = 'a'`, null], @@ -1968,13 +2034,14 @@ exports.ExternalModule = ExternalModule; loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports_emitted_helpers.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -1997,13 +2064,14 @@ exports.ExternalModule = ExternalModule; loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports_imported_helpers.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -2025,11 +2093,12 @@ exports.ExternalModule = ExternalModule; it('should handle inline exports', () => { loadTestFiles([INLINE_EXPORT_FILE]); const bundle = makeTestBundleProgram(_('/inline_export.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/inline_export.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBeNull(); - const decl = exportDeclarations !.get('directives') as InlineDeclaration; + const decl = exportDeclarations!.get('directives') as InlineDeclaration; expect(decl).not.toBeUndefined(); expect(decl.node).toBeNull(); expect(decl.expression).toBeDefined(); @@ -2047,9 +2116,10 @@ exports.ExternalModule = ExternalModule; }; loadTestFiles([tslib]); const bundle = makeTestBundleProgram(tslib.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const sf = getSourceFileOrError(bundle.program, tslib.name); - const exportDeclarations = host.getExportsOfModule(sf) !; + const exportDeclarations = host.getExportsOfModule(sf)!; expect([...exportDeclarations].map(([exportName, {known}]) => [exportName, known])) .toEqual([ @@ -2065,56 +2135,59 @@ exports.ExternalModule = ExternalModule; it('should return the class symbol for an ES2015 class', () => { loadTestFiles([SIMPLE_ES2015_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_ES2015_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_ES2015_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const classSymbol = host.getClassSymbol(node); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(node); - expect(classSymbol !.implementation.valueDeclaration).toBe(node); + expect(classSymbol!.declaration.valueDeclaration).toBe(node); + expect(classSymbol!.implementation.valueDeclaration).toBe(node); }); it('should return the class symbol for an ES5 class (outer variable declaration)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for an ES5 class (inner function declaration)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(innerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the same class symbol (of the outer declaration) for outer and inner declarations', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = - getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; - const innerSymbol = host.getClassSymbol(innerNode) !; - const outerSymbol = host.getClassSymbol(outerNode) !; + const innerSymbol = host.getClassSymbol(innerNode)!; + const outerSymbol = host.getClassSymbol(outerNode)!; expect(innerSymbol.declaration).toBe(outerSymbol.declaration); expect(innerSymbol.implementation).toBe(outerSymbol.implementation); }); @@ -2123,40 +2196,41 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoParensClass', isNamedVariableDeclaration); - const innerNode = - getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for an ES5 class whose IIFE is not wrapped with inner parens', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'InnerParensClass', isNamedVariableDeclaration); - const innerNode = - getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return undefined if node is not an ES5 class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const classSymbol = host.getClassSymbol(node); @@ -2172,7 +2246,8 @@ exports.ExternalModule = ExternalModule; }; loadTestFiles([testFile]); const bundle = makeTestBundleProgram(testFile.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, testFile.name, 'MyClass', isNamedVariableDeclaration); const classSymbol = host.getClassSymbol(node); @@ -2185,7 +2260,8 @@ exports.ExternalModule = ExternalModule; it('should return true if a given node is a TS class declaration', () => { loadTestFiles([SIMPLE_ES2015_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_ES2015_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_ES2015_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); expect(host.isClass(node)).toBe(true); @@ -2195,7 +2271,8 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); expect(host.isClass(node)).toBe(true); @@ -2205,18 +2282,19 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); - const innerNode = - getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; expect(host.isClass(innerNode)).toBe(true); }); it('should return false if a given node is a function declaration', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(host.isClass(node)).toBe(false); @@ -2232,7 +2310,8 @@ exports.ExternalModule = ExternalModule; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); return host.hasBaseClass(classNode); @@ -2279,7 +2358,8 @@ exports.ExternalModule = ExternalModule; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); const expression = host.getBaseClassExpression(classNode); @@ -2301,7 +2381,7 @@ exports.ExternalModule = ExternalModule; function TestClass() {} return TestClass; }(BaseClass));`); - expect(identifier !.text).toBe('BaseClass'); + expect(identifier!.text).toBe('BaseClass'); }); it('should find the base class of an IIFE with a unique name generated for the _super parameter', @@ -2316,7 +2396,7 @@ exports.ExternalModule = ExternalModule; function TestClass() {} return TestClass; }(BaseClass));`); - expect(identifier !.text).toBe('BaseClass'); + expect(identifier!.text).toBe('BaseClass'); }); it('should not find a base class for an IIFE without parameter', () => { @@ -2351,10 +2431,11 @@ exports.ExternalModule = ExternalModule; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); - const expression = host.getBaseClassExpression(classNode) !; + const expression = host.getBaseClassExpression(classNode)!; expect(expression.getText()).toBe('foo()'); }); }); @@ -2363,7 +2444,8 @@ exports.ExternalModule = ExternalModule; it('should return an array of all classes in the given source file', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); @@ -2381,7 +2463,8 @@ exports.ExternalModule = ExternalModule; it('should return decorators of class symbol', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); @@ -2389,14 +2472,14 @@ exports.ExternalModule = ExternalModule; const classDecoratorsPrimary = classSymbolsPrimary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsPrimary.length).toEqual(2); - expect(classDecoratorsPrimary[0] !.map(d => d.name)).toEqual(['Directive']); - expect(classDecoratorsPrimary[1] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[0]!.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[1]!.map(d => d.name)).toEqual(['Directive']); const classSymbolsSecondary = host.findClassSymbols(secondaryFile); const classDecoratorsSecondary = classSymbolsSecondary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsSecondary.length).toEqual(1); - expect(classDecoratorsSecondary[0] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsSecondary[0]!.map(d => d.name)).toEqual(['Directive']); }); }); @@ -2409,11 +2492,11 @@ exports.ExternalModule = ExternalModule; const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'Class1', ts.isVariableDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = createHost( + bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName) - .toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find the dts declaration for exported functions', () => { @@ -2423,9 +2506,10 @@ exports.ExternalModule = ExternalModule; const dts = makeTestDtsBundleProgram(_('/ep/typings/func1.d.ts'), _('/')); const mooFn = getDeclaration( bundle.program, _('/ep/src/func1.js'), 'mooFn', ts.isFunctionDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(mooFn); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); }); it('should return null if there is no matching class in the matching dts file', () => { @@ -2435,7 +2519,8 @@ exports.ExternalModule = ExternalModule; const dts = makeTestDtsBundleProgram(_('/ep/typings/index.d.ts'), _('/')); const missingClass = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'MissingClass1', ts.isVariableDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2448,7 +2533,8 @@ exports.ExternalModule = ExternalModule; const missingClass = getDeclaration( bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', ts.isVariableDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2461,11 +2547,11 @@ exports.ExternalModule = ExternalModule; const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'Class1', ts.isVariableDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = createHost( + bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName) - .toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find aliased exports', () => { @@ -2475,7 +2561,8 @@ exports.ExternalModule = ExternalModule; const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const sourceClass = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'SourceClass', ts.isVariableDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(sourceClass); if (dtsDeclaration === null) { @@ -2498,10 +2585,11 @@ exports.ExternalModule = ExternalModule; const internalClass = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'InternalClass', ts.isVariableDeclaration); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = createHost( + bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(internalClass); - expect(dtsDeclaration !.getSourceFile().fileName) + expect(dtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/internal.d.ts')); }); @@ -2511,18 +2599,19 @@ exports.ExternalModule = ExternalModule; loadTestFiles(TYPINGS_DTS_FILES); const bundle = makeTestBundleProgram(getRootFiles(TYPINGS_SRC_FILES)[0]); const dts = makeTestDtsBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0], _('/ep')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle, dts); + const host = createHost( + bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle, dts)); const class2 = getDeclaration( bundle.program, _('/ep/src/class2.js'), 'Class2', isNamedVariableDeclaration); const class2DtsDeclaration = host.getDtsDeclaration(class2); - expect(class2DtsDeclaration !.getSourceFile().fileName) + expect(class2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/class2.d.ts')); const internalClass2 = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'Class2', isNamedVariableDeclaration); const internalClass2DtsDeclaration = host.getDtsDeclaration(internalClass2); - expect(internalClass2DtsDeclaration !.getSourceFile().fileName) + expect(internalClass2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/internal.d.ts')); }); }); @@ -2531,7 +2620,8 @@ exports.ExternalModule = ExternalModule; it('should return the name of the inner class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const emptyClass = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -2555,7 +2645,8 @@ exports.ExternalModule = ExternalModule; it('should return the name of the inner class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const emptyClass = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -2580,10 +2671,11 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/functions.js')); const fns = host.getModuleWithProvidersFunctions(file); - expect(fns.map(fn => [fn.declaration.name !.getText(), fn.ngModule.node.name.text])) + expect(fns.map(fn => [fn.declaration.name!.getText(), fn.ngModule.node.name.text])) .toEqual([ ['ngModuleIdentifier', 'InternalModule'], ['ngModuleWithEmptyProviders', 'InternalModule'], @@ -2596,7 +2688,8 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/methods.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2623,7 +2716,8 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/outer_aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2636,7 +2730,8 @@ exports.ExternalModule = ExternalModule; () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new CommonJsReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/inner_aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ diff --git a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts index 6f086011db370..f0b5956d1b053 100644 --- a/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts @@ -9,11 +9,13 @@ import * as ts from 'typescript'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {ClassMemberKind, CtorParameter, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; +import {ClassMemberKind, CtorParameter, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration, TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; +import {DelegatingReflectionHost} from '../../src/host/delegating_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; +import {BundleProgram} from '../../src/packages/bundle_program'; import {MockLogger} from '../helpers/mock_logger'; import {getRootFiles, makeTestBundleProgram, makeTestDtsBundleProgram} from '../helpers/utils'; @@ -21,7 +23,6 @@ import {expectTypeValueReferencesForParameters} from './util'; runInEachFileSystem(() => { describe('Esm2015ReflectionHost', () => { - let _: typeof absoluteFrom; let SOME_DIRECTIVE_FILE: TestFile; @@ -48,6 +49,12 @@ runInEachFileSystem(() => { let NAMESPACED_IMPORT_FILE: TestFile; let INDEX_SIGNATURE_PROP_FILE: TestFile; + // Helpers + const createHost = (bundle: BundleProgram, ngccHost: Esm2015ReflectionHost) => { + const tsHost = new TypeScriptReflectionHost(bundle.program.getTypeChecker()); + return new DelegatingReflectionHost(tsHost, ngccHost); + }; + beforeEach(() => { _ = absoluteFrom; @@ -720,10 +727,10 @@ runInEachFileSystem(() => { it('should find the decorators on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -731,7 +738,7 @@ runInEachFileSystem(() => { const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -739,10 +746,10 @@ runInEachFileSystem(() => { it('should find the decorators on an aliased class', () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'AliasedClass', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -750,7 +757,7 @@ runInEachFileSystem(() => { const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -758,7 +765,7 @@ runInEachFileSystem(() => { it('should return null if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const decorators = host.getDecoratorsOfDeclaration(functionNode); @@ -768,7 +775,7 @@ runInEachFileSystem(() => { it('should return null if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const decorators = host.getDecoratorsOfDeclaration(classNode); @@ -778,7 +785,7 @@ runInEachFileSystem(() => { it('should ignore `decorators` if it is not an array literal', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedClassDeclaration); @@ -789,11 +796,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements that are not object literals', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -802,11 +809,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements that have no `type` property', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -815,10 +822,10 @@ runInEachFileSystem(() => { it('should ignore decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -827,10 +834,10 @@ runInEachFileSystem(() => { it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'}); @@ -840,11 +847,12 @@ runInEachFileSystem(() => { it('should be an empty array if decorator has no `args` property', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -854,11 +862,12 @@ runInEachFileSystem(() => { it('should be an empty array if decorator\'s `args` has no property assignment', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -868,11 +877,12 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedClassDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -885,43 +895,43 @@ runInEachFileSystem(() => { it('should find decorated properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); - expect(input1.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'}); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators![0].import).toEqual({name: 'Input', from: '@angular/core'}); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input2.decorators !.map(d => d.name)).toEqual(['Input']); - expect(input2.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'}); + expect(input2.decorators!.map(d => d.name)).toEqual(['Input']); + expect(input2.decorators![0].import).toEqual({name: 'Input', from: '@angular/core'}); }); it('should find non decorated properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const instanceProperty = members.find(member => member.name === 'instanceProperty') !; + const instanceProperty = members.find(member => member.name === 'instanceProperty')!; expect(instanceProperty.kind).toEqual(ClassMemberKind.Property); expect(instanceProperty.isStatic).toEqual(false); - expect(ts.isBinaryExpression(instanceProperty.implementation !)).toEqual(true); - expect(instanceProperty.value !.getText()).toEqual(`'instance'`); + expect(ts.isBinaryExpression(instanceProperty.implementation!)).toEqual(true); + expect(instanceProperty.value!.getText()).toEqual(`'instance'`); }); it('should handle equally named getter/setter pairs correctly', () => { loadTestFiles([ACCESSORS_FILE]); const bundle = makeTestBundleProgram(ACCESSORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, ACCESSORS_FILE.name, 'SomeDirective', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); @@ -930,50 +940,50 @@ runInEachFileSystem(() => { members.filter(member => member.name === 'setterAndGetter'); expect(combinedSetter.kind).toEqual(ClassMemberKind.Setter); expect(combinedSetter.isStatic).toEqual(false); - expect(ts.isSetAccessor(combinedSetter.implementation !)).toEqual(true); + expect(ts.isSetAccessor(combinedSetter.implementation!)).toEqual(true); expect(combinedSetter.value).toBeNull(); - expect(combinedSetter.decorators !.map(d => d.name)).toEqual(['Input']); + expect(combinedSetter.decorators!.map(d => d.name)).toEqual(['Input']); expect(combinedGetter.kind).toEqual(ClassMemberKind.Getter); expect(combinedGetter.isStatic).toEqual(false); - expect(ts.isGetAccessor(combinedGetter.implementation !)).toEqual(true); + expect(ts.isGetAccessor(combinedGetter.implementation!)).toEqual(true); expect(combinedGetter.value).toBeNull(); - expect(combinedGetter.decorators !.map(d => d.name)).toEqual([]); + expect(combinedGetter.decorators!.map(d => d.name)).toEqual([]); }); it('should find static methods on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const staticMethod = members.find(member => member.name === 'staticMethod') !; + const staticMethod = members.find(member => member.name === 'staticMethod')!; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); - expect(ts.isMethodDeclaration(staticMethod.implementation !)).toEqual(true); + expect(ts.isMethodDeclaration(staticMethod.implementation!)).toEqual(true); }); it('should find static properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should ignore index signature properties', () => { loadTestFiles([INDEX_SIGNATURE_PROP_FILE]); const logger = new MockLogger(); const bundle = makeTestBundleProgram(INDEX_SIGNATURE_PROP_FILE.name); - const host = new Esm2015ReflectionHost(logger, false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(logger, false, bundle)); const classNode = getDeclaration( bundle.program, INDEX_SIGNATURE_PROP_FILE.name, 'IndexSignatureClass', isNamedClassDeclaration); @@ -986,7 +996,7 @@ runInEachFileSystem(() => { it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(() => { @@ -997,7 +1007,7 @@ runInEachFileSystem(() => { it('should return an empty array if there are no prop decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); @@ -1009,7 +1019,8 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedClassDeclaration); @@ -1021,13 +1032,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements that are not object literals', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'})); @@ -1036,13 +1047,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements that have no `type` property', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'})); @@ -1051,13 +1062,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'})); @@ -1067,13 +1078,14 @@ runInEachFileSystem(() => { it('should be an empty array if prop decorator has no `args` property', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1084,13 +1096,14 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1100,13 +1113,14 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedClassDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1120,10 +1134,10 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters).toBeDefined(); expect(parameters.map(parameter => parameter.name)).toEqual([ @@ -1136,11 +1150,11 @@ runInEachFileSystem(() => { it('should accept `ctorParameters` as an array', () => { loadTestFiles([CTOR_DECORATORS_ARRAY_FILE]); const bundle = makeTestBundleProgram(CTOR_DECORATORS_ARRAY_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, CTOR_DECORATORS_ARRAY_FILE.name, 'CtorDecoratedAsArray', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters).toBeDefined(); expect(parameters.map(parameter => parameter.name)).toEqual(['arg1']); @@ -1150,10 +1164,12 @@ runInEachFileSystem(() => { it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); - expect(() => { host.getConstructorParameters(functionNode); }) + expect(() => { + host.getConstructorParameters(functionNode); + }) .toThrowError( 'Attempted to get constructor parameters of a non-class: "function foo() {}"'); }); @@ -1161,7 +1177,7 @@ runInEachFileSystem(() => { it('should return `null` if there is no constructor', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); @@ -1171,11 +1187,11 @@ runInEachFileSystem(() => { it('should return an array even if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters).toEqual(jasmine.any(Array)); expect(parameters.length).toEqual(1); @@ -1186,7 +1202,7 @@ runInEachFileSystem(() => { it('should return an empty array if there are no constructor parameters', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', isNamedClassDeclaration); @@ -1198,11 +1214,11 @@ runInEachFileSystem(() => { it('should ignore decorators that are not imported from core', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotFromCore', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters.length).toBe(1); expect(parameters[0]).toEqual(jasmine.objectContaining<CtorParameter>({ @@ -1214,11 +1230,11 @@ runInEachFileSystem(() => { it('should ignore `ctorParameters` if it is not an arrow function', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrowFunction', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters.length).toBe(1); expect(parameters[0]).toEqual(jasmine.objectContaining<CtorParameter>({ @@ -1230,11 +1246,11 @@ runInEachFileSystem(() => { it('should ignore `ctorParameters` if it does not return an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters.length).toBe(1); expect(parameters[0]).toEqual(jasmine.objectContaining<CtorParameter>({ @@ -1257,7 +1273,8 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedClassDeclaration); return host.getConstructorParameters(classNode); @@ -1279,7 +1296,7 @@ runInEachFileSystem(() => { super(arguments); }`); - expect(parameters !.length).toBe(0); + expect(parameters!.length).toBe(0); }); it('does not consider constructors with parameters as synthesized', () => { @@ -1288,7 +1305,7 @@ runInEachFileSystem(() => { super(...arguments); }`); - expect(parameters !.length).toBe(1); + expect(parameters!.length).toBe(1); }); it('does not consider manual super calls as synthesized', () => { @@ -1297,7 +1314,7 @@ runInEachFileSystem(() => { super(); }`); - expect(parameters !.length).toBe(0); + expect(parameters!.length).toBe(0); }); it('does not consider empty constructors as synthesized', () => { @@ -1305,7 +1322,7 @@ runInEachFileSystem(() => { constructor() { }`); - expect(parameters !.length).toBe(0); + expect(parameters!.length).toBe(0); }); }); @@ -1313,18 +1330,19 @@ runInEachFileSystem(() => { it('should ignore param decorator elements that are not object literals', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(2); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(2); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); - expect(parameters ![1]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters![1]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg2', decorators: jasmine.any(Array) as any })); @@ -1333,12 +1351,13 @@ runInEachFileSystem(() => { it('should ignore param decorator elements that have no `type` property', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1347,12 +1366,13 @@ runInEachFileSystem(() => { it('should ignore param decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1361,11 +1381,12 @@ runInEachFileSystem(() => { it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); - const parameters = host.getConstructorParameters(classNode) !; - const decorators = parameters[2].decorators !; + const parameters = host.getConstructorParameters(classNode)!; + const decorators = parameters[2].decorators!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'}); @@ -1376,13 +1397,14 @@ runInEachFileSystem(() => { it('should be an empty array if param decorator has no `args` property', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - const decorators = parameters ![0].decorators !; + expect(parameters!.length).toBe(1); + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1393,12 +1415,13 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1408,12 +1431,13 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedClassDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1427,61 +1451,62 @@ runInEachFileSystem(() => { () => { loadTestFiles([FUNCTION_BODY_FILE]); const bundle = makeTestBundleProgram(FUNCTION_BODY_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const fooNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration) !; - const fooDef = host.getDefinitionOfFunction(fooNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration)!; + const fooDef = host.getDefinitionOfFunction(fooNode)!; expect(fooDef.node).toBe(fooNode); - expect(fooDef.body !.length).toEqual(1); - expect(fooDef.body ![0].getText()).toEqual(`return x;`); + expect(fooDef.body!.length).toEqual(1); + expect(fooDef.body![0].getText()).toEqual(`return x;`); expect(fooDef.parameters.length).toEqual(1); expect(fooDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); const barNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration) !; - const barDef = host.getDefinitionOfFunction(barNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration)!; + const barDef = host.getDefinitionOfFunction(barNode)!; expect(barDef.node).toBe(barNode); - expect(barDef.body !.length).toEqual(1); - expect(ts.isReturnStatement(barDef.body ![0])).toBeTruthy(); - expect(barDef.body ![0].getText()).toEqual(`return x + y;`); + expect(barDef.body!.length).toEqual(1); + expect(ts.isReturnStatement(barDef.body![0])).toBeTruthy(); + expect(barDef.body![0].getText()).toEqual(`return x + y;`); expect(barDef.parameters.length).toEqual(2); expect(barDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); expect(barDef.parameters[1].name).toEqual('y'); - expect(barDef.parameters[1].initializer !.getText()).toEqual('42'); + expect(barDef.parameters[1].initializer!.getText()).toEqual('42'); const bazNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration) !; - const bazDef = host.getDefinitionOfFunction(bazNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration)!; + const bazDef = host.getDefinitionOfFunction(bazNode)!; expect(bazDef.node).toBe(bazNode); - expect(bazDef.body !.length).toEqual(3); + expect(bazDef.body!.length).toEqual(3); expect(bazDef.parameters.length).toEqual(1); expect(bazDef.parameters[0].name).toEqual('x'); expect(bazDef.parameters[0].initializer).toBe(null); const quxNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration) !; - const quxDef = host.getDefinitionOfFunction(quxNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration)!; + const quxDef = host.getDefinitionOfFunction(quxNode)!; expect(quxDef.node).toBe(quxNode); - expect(quxDef.body !.length).toEqual(2); + expect(quxDef.body!.length).toEqual(2); expect(quxDef.parameters.length).toEqual(1); expect(quxDef.parameters[0].name).toEqual('x'); expect(quxDef.parameters[0].initializer).toBe(null); const mooNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'moo', isNamedFunctionDeclaration) !; - const mooDef = host.getDefinitionOfFunction(mooNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'moo', isNamedFunctionDeclaration)!; + const mooDef = host.getDefinitionOfFunction(mooNode)!; expect(mooDef.node).toBe(mooNode); - expect(mooDef.body !.length).toEqual(3); + expect(mooDef.body!.length).toEqual(3); expect(mooDef.parameters).toEqual([]); const juuNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'juu', isNamedFunctionDeclaration) !; - const juuDef = host.getDefinitionOfFunction(juuNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'juu', isNamedFunctionDeclaration)!; + const juuDef = host.getDefinitionOfFunction(juuNode)!; expect(juuDef.node).toBe(juuNode); - expect(juuDef.body !.length).toEqual(2); + expect(juuDef.body!.length).toEqual(2); expect(juuDef.parameters).toEqual([]); }); }); @@ -1490,7 +1515,7 @@ runInEachFileSystem(() => { it('should find the import of an identifier', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/b.js'), 'b', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1501,7 +1526,7 @@ runInEachFileSystem(() => { it('should find the name by which the identifier was exported, not imported', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/b.js'), 'c', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1512,7 +1537,7 @@ runInEachFileSystem(() => { it('should return null if the identifier was not imported', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/b.js'), 'd', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1526,61 +1551,63 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(classNode.name); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(classNode); - expect(actualDeclaration !.viaModule).toBe(null); + expect(actualDeclaration!.node).toBe(classNode); + expect(actualDeclaration!.viaModule).toBe(null); }); it('should return the declaration of an externally defined identifier', () => { loadFakeCore(getFileSystem()); loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedClassDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const identifierOfDirective = ((classDecorators[0].node as ts.ObjectLiteralExpression) - .properties[0] as ts.PropertyAssignment) - .initializer as ts.Identifier; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const identifierOfDirective = + ((classDecorators[0].node as ts.ObjectLiteralExpression).properties[0] as + ts.PropertyAssignment) + .initializer as ts.Identifier; const expectedDeclarationNode = getDeclaration( bundle.program, _('/node_modules/@angular/core/index.d.ts'), 'Directive', isNamedVariableDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should return the source-file of an import namespace', () => { loadFakeCore(getFileSystem()); loadTestFiles([NAMESPACED_IMPORT_FILE]); const bundle = makeTestBundleProgram(NAMESPACED_IMPORT_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, NAMESPACED_IMPORT_FILE.name, 'SomeDirective', ts.isClassDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const identifier = (((classDecorators[0].node as ts.ObjectLiteralExpression) - .properties[0] as ts.PropertyAssignment) - .initializer as ts.PropertyAccessExpression) - .expression as ts.Identifier; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const identifier = + (((classDecorators[0].node as ts.ObjectLiteralExpression).properties[0] as + ts.PropertyAssignment) + .initializer as ts.PropertyAccessExpression) + .expression as ts.Identifier; const expectedDeclarationNode = getSourceFileOrError(bundle.program, _('/node_modules/@angular/core/index.d.ts')); const actualDeclaration = host.getDeclarationOfIdentifier(identifier); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should return the original declaration of an aliased class', () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classDeclaration = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'AliasedClass', ts.isVariableDeclaration); const usageOfAliasedClass = getDeclaration( @@ -1588,7 +1615,7 @@ runInEachFileSystem(() => { ts.isVariableDeclaration); const aliasedClassIdentifier = usageOfAliasedClass.initializer as ts.Identifier; expect(aliasedClassIdentifier.text).toBe('AliasedClass_1'); - expect(host.getDeclarationOfIdentifier(aliasedClassIdentifier) !.node) + expect(host.getDeclarationOfIdentifier(aliasedClassIdentifier)!.node) .toBe(classDeclaration); }); }); @@ -1598,11 +1625,11 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/b.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.keys())).toEqual([ + expect(Array.from(exportDeclarations!.keys())).toEqual([ 'Directive', 'a', 'b', @@ -1614,8 +1641,8 @@ runInEachFileSystem(() => { ]); const values = - Array.from(exportDeclarations !.values()) - .map(declaration => [declaration.node !.getText(), declaration.viaModule]); + Array.from(exportDeclarations!.values()) + .map(declaration => [declaration.node!.getText(), declaration.viaModule]); expect(values).toEqual([ [`Directive: FnWithArg<(clazz: any) => any>`, null], [`a = 'a'`, null], @@ -1633,21 +1660,22 @@ runInEachFileSystem(() => { it('should return the class symbol for an ES2015 class', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const classSymbol = host.getClassSymbol(node); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(node); - expect(classSymbol !.implementation.valueDeclaration).toBe(node); + expect(classSymbol!.declaration.valueDeclaration).toBe(node); + expect(classSymbol!.implementation.valueDeclaration).toBe(node); }); it('should return the class symbol for a class expression (outer variable declaration)', () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -1655,36 +1683,37 @@ runInEachFileSystem(() => { const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for a class expression (inner class expression)', () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const innerNode = (outerNode.initializer as ts.ClassExpression); const classSymbol = host.getClassSymbol(innerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the same class symbol (of the outer declaration) for outer and inner declarations', () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const innerNode = (outerNode.initializer as ts.ClassExpression); - const innerSymbol = host.getClassSymbol(innerNode) !; - const outerSymbol = host.getClassSymbol(outerNode) !; + const innerSymbol = host.getClassSymbol(innerNode)!; + const outerSymbol = host.getClassSymbol(outerNode)!; expect(innerSymbol.declaration).toBe(outerSymbol.declaration); expect(innerSymbol.implementation).toBe(outerSymbol.implementation); }); @@ -1692,7 +1721,7 @@ runInEachFileSystem(() => { it('should return undefined if node is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const classSymbol = host.getClassSymbol(node); @@ -1708,7 +1737,8 @@ runInEachFileSystem(() => { }; loadTestFiles([testFile]); const bundle = makeTestBundleProgram(testFile.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration(bundle.program, testFile.name, 'MyClass', isNamedVariableDeclaration); const classSymbol = host.getClassSymbol(node); @@ -1721,7 +1751,7 @@ runInEachFileSystem(() => { it('should return true if a given node is a TS class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); expect(host.isClass(node)).toBe(true); @@ -1731,7 +1761,8 @@ runInEachFileSystem(() => { () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'EmptyClass', ts.isVariableDeclaration); expect(host.isClass(node)).toBe(true); @@ -1741,7 +1772,8 @@ runInEachFileSystem(() => { () => { loadTestFiles([CLASS_EXPRESSION_FILE]); const bundle = makeTestBundleProgram(CLASS_EXPRESSION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, CLASS_EXPRESSION_FILE.name, 'AliasedClass', ts.isVariableDeclaration); @@ -1751,7 +1783,7 @@ runInEachFileSystem(() => { it('should return false if a given node is a TS function declaration', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(host.isClass(node)).toBe(false); @@ -1766,7 +1798,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedClassDeclaration); expect(host.hasBaseClass(classNode)).toBe(false); @@ -1781,7 +1813,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedClassDeclaration); expect(host.hasBaseClass(classNode)).toBe(true); @@ -1797,7 +1829,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); expect(host.hasBaseClass(classNode)).toBe(true); @@ -1812,7 +1844,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedClassDeclaration); expect(host.getBaseClassExpression(classNode)).toBe(null); @@ -1827,10 +1859,10 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedClassDeclaration); - const baseIdentifier = host.getBaseClassExpression(classNode) !; + const baseIdentifier = host.getBaseClassExpression(classNode)!; if (!ts.isIdentifier(baseIdentifier)) { throw new Error(`Expected ${baseIdentifier.getText()} to be an identifier.`); } @@ -1847,10 +1879,10 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); - const baseIdentifier = host.getBaseClassExpression(classNode) !; + const baseIdentifier = host.getBaseClassExpression(classNode)!; if (!ts.isIdentifier(baseIdentifier)) { throw new Error(`Expected ${baseIdentifier.getText()} to be an identifier.`); } @@ -1868,10 +1900,11 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedClassDeclaration); - const baseExpression = host.getBaseClassExpression(classNode) !; + const baseExpression = host.getBaseClassExpression(classNode)!; expect(baseExpression.getText()).toEqual('foo()'); }); }); @@ -1881,7 +1914,8 @@ runInEachFileSystem(() => { loadTestFiles(ARITY_CLASSES); const bundle = makeTestBundleProgram(ARITY_CLASSES[0].name); const dts = makeTestBundleProgram(ARITY_CLASSES[1].name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const noTypeParamClass = getDeclaration( bundle.program, _('/src/class.js'), 'NoTypeParam', isNamedClassDeclaration); expect(host.getGenericArityOfClass(noTypeParamClass)).toBe(0); @@ -1899,10 +1933,11 @@ runInEachFileSystem(() => { () => { loadTestFiles([MARKER_FILE]); const bundle = makeTestBundleProgram(MARKER_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, MARKER_FILE.name); const declarations = host.getSwitchableDeclarations(file); - expect(declarations.map(d => [d.name.getText(), d.initializer !.getText()])).toEqual([ + expect(declarations.map(d => [d.name.getText(), d.initializer!.getText()])).toEqual([ ['compileNgModuleFactory', 'compileNgModuleFactory__PRE_R3__'] ]); }); @@ -1912,7 +1947,7 @@ runInEachFileSystem(() => { it('should return an array of all classes in the given source file', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); @@ -1930,31 +1965,31 @@ runInEachFileSystem(() => { it('should return decorators of class symbol', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); const classSymbolsPrimary = host.findClassSymbols(primaryFile); const classDecoratorsPrimary = classSymbolsPrimary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsPrimary.length).toEqual(3); - expect(classDecoratorsPrimary[0] !.map(d => d.name)).toEqual(['Directive']); - expect(classDecoratorsPrimary[1] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[0]!.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[1]!.map(d => d.name)).toEqual(['Directive']); expect(classDecoratorsPrimary[2]).toBe(null); const classSymbolsSecondary = host.findClassSymbols(secondaryFile); const classDecoratorsSecondary = classSymbolsSecondary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsSecondary.length).toEqual(1); - expect(classDecoratorsSecondary[0] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsSecondary[0]!.map(d => d.name)).toEqual(['Directive']); }); it('should return a cloned array on each invocation', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const classDecl = - getDeclaration(bundle.program, DECORATED_FILES[0].name, 'A', ts.isClassDeclaration) !; - const classSymbol = host.getClassSymbol(classDecl) !; + getDeclaration(bundle.program, DECORATED_FILES[0].name, 'A', ts.isClassDeclaration)!; + const classSymbol = host.getClassSymbol(classDecl)!; const firstResult = host.getDecoratorsOfSymbol(classSymbol); const secondResult = host.getDecoratorsOfSymbol(classSymbol); @@ -1972,10 +2007,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'Class1', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find the dts declaration for exported functions', () => { @@ -1985,10 +2021,11 @@ runInEachFileSystem(() => { const dts = makeTestDtsBundleProgram(_('/ep/typings/func1.d.ts'), _('/')); const mooFn = getDeclaration( bundle.program, _('/ep/src/func1.js'), 'mooFn', isNamedFunctionDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(mooFn); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); }); it('should return null if there is no matching class in the matching dts file', () => { @@ -1999,7 +2036,8 @@ runInEachFileSystem(() => { const missingClass = getDeclaration( bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2012,7 +2050,8 @@ runInEachFileSystem(() => { const missingClass = getDeclaration( bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2026,9 +2065,10 @@ runInEachFileSystem(() => { getRootFiles(TYPINGS_DTS_FILES)[0], false, [_('/ep/typings/shadow-class.d.ts')]); const shadowClass = getDeclaration( bundle.program, _('/ep/src/shadow-class.js'), 'ShadowClass', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); - const dtsDecl = host.getDtsDeclaration(shadowClass) !; + const dtsDecl = host.getDtsDeclaration(shadowClass)!; expect(dtsDecl).not.toBeNull(); expect(dtsDecl.getSourceFile().fileName).toEqual(_('/ep/typings/shadow-class.d.ts')); }); @@ -2054,7 +2094,8 @@ runInEachFileSystem(() => { const missingClass = getDeclaration( bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', isNamedClassDeclaration); - const host = new TestEsm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new TestEsm2015ReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBeNull(); }); @@ -2067,10 +2108,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'Class1', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find aliased exports', () => { @@ -2080,7 +2122,8 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const sourceClass = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'SourceClass', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(sourceClass); if (dtsDeclaration === null) { @@ -2102,11 +2145,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const internalClass = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'InternalClass', isNamedClassDeclaration); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(internalClass); - expect(dtsDeclaration !.getSourceFile().fileName) - .toEqual(_('/ep/typings/internal.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/internal.d.ts')); }); it('should match publicly and internal exported classes correctly, even if they have the same name', @@ -2115,18 +2158,19 @@ runInEachFileSystem(() => { loadTestFiles(TYPINGS_DTS_FILES); const bundle = makeTestBundleProgram(getRootFiles(TYPINGS_SRC_FILES)[0]); const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts)); const class2 = getDeclaration( bundle.program, _('/ep/src/class2.js'), 'Class2', isNamedClassDeclaration); const class2DtsDeclaration = host.getDtsDeclaration(class2); - expect(class2DtsDeclaration !.getSourceFile().fileName) + expect(class2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/class2.d.ts')); const internalClass2 = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'Class2', isNamedClassDeclaration); const internalClass2DtsDeclaration = host.getDtsDeclaration(internalClass2); - expect(internalClass2DtsDeclaration !.getSourceFile().fileName) + expect(internalClass2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/internal.d.ts')); }); }); @@ -2135,7 +2179,7 @@ runInEachFileSystem(() => { it('should return the name of the class (there is no separate inner class in ES2015)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); expect(host.getInternalNameOfClass(node).text).toEqual('EmptyClass'); @@ -2146,7 +2190,7 @@ runInEachFileSystem(() => { it('should return the name of the class (there is no separate inner class in ES2015)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); expect(host.getAdjacentNameOfClass(node).text).toEqual('EmptyClass'); @@ -2158,10 +2202,11 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/functions.js')); const fns = host.getModuleWithProvidersFunctions(file); - expect(fns.map(fn => [fn.declaration.name !.getText(), fn.ngModule.node.name.text])) + expect(fns.map(fn => [fn.declaration.name!.getText(), fn.ngModule.node.name.text])) .toEqual([ ['ngModuleIdentifier', 'InternalModule'], ['ngModuleWithEmptyProviders', 'InternalModule'], @@ -2175,10 +2220,11 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/methods.js')); const fn = host.getModuleWithProvidersFunctions(file); - expect(fn.map(fn => [fn.declaration.name !.getText(), fn.ngModule.node.name.text])) + expect(fn.map(fn => [fn.declaration.name!.getText(), fn.ngModule.node.name.text])) .toEqual([ ['ngModuleIdentifier', 'InternalModule'], ['ngModuleWithEmptyProviders', 'InternalModule'], @@ -2192,13 +2238,12 @@ runInEachFileSystem(() => { it('should resolve aliased module references to their original declaration', () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); - expect(fn.map(fn => [fn.declaration.name !.getText(), fn.ngModule.node.name.text])) - .toEqual([ - ['forRoot', 'AliasedModule'], - ]); + expect(fn.map(fn => [fn.declaration.name!.getText(), fn.ngModule.node.name.text])).toEqual([ + ['forRoot', 'AliasedModule'], + ]); }); }); @@ -2224,8 +2269,8 @@ runInEachFileSystem(() => { }; loadTestFiles([testFile]); const bundle = makeTestBundleProgram(testFile.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); - const classSymbol = host.findClassSymbols(bundle.program.getSourceFile(testFile.name) !)[0]; + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); + const classSymbol = host.findClassSymbols(bundle.program.getSourceFile(testFile.name)!)[0]; const endOfClass = host.getEndOfClass(classSymbol); expect(endOfClass.getText()) .toEqual( @@ -2247,8 +2292,8 @@ runInEachFileSystem(() => { }; loadTestFiles([testFile]); const bundle = makeTestBundleProgram(testFile.name); - const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); - const classSymbol = host.findClassSymbols(bundle.program.getSourceFile(testFile.name) !)[0]; + const host = createHost(bundle, new Esm2015ReflectionHost(new MockLogger(), false, bundle)); + const classSymbol = host.findClassSymbols(bundle.program.getSourceFile(testFile.name)!)[0]; const endOfClass = host.getEndOfClass(classSymbol); expect(endOfClass.getText()) .toEqual( diff --git a/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts index be3b064a677dd..8182a8807de0b 100644 --- a/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts @@ -9,12 +9,15 @@ import * as ts from 'typescript'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {ClassMemberKind, CtorParameter, Decorator, KnownDeclaration, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; +import {ClassMemberKind, CtorParameter, Decorator, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration, KnownDeclaration, TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; +import {DelegatingReflectionHost} from '../../src/host/delegating_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm5ReflectionHost, getIifeBody} from '../../src/host/esm5_host'; +import {NgccReflectionHost} from '../../src/host/ngcc_host'; +import {BundleProgram} from '../../src/packages/bundle_program'; import {MockLogger} from '../helpers/mock_logger'; import {getRootFiles, makeTestBundleProgram, makeTestDtsBundleProgram} from '../helpers/utils'; @@ -22,7 +25,6 @@ import {expectTypeValueReferencesForParameters} from './util'; runInEachFileSystem(() => { describe('Esm5ReflectionHost', () => { - let _: typeof absoluteFrom; let SOME_DIRECTIVE_FILE: TestFile; @@ -48,6 +50,12 @@ runInEachFileSystem(() => { let MODULE_WITH_PROVIDERS_PROGRAM: TestFile[]; let NAMESPACED_IMPORT_FILE: TestFile; + // Helpers + const createHost = (bundle: BundleProgram, ngccHost: Esm5ReflectionHost) => { + const tsHost = new TypeScriptReflectionHost(bundle.program.getTypeChecker()); + return new DelegatingReflectionHost(tsHost, ngccHost); + }; + beforeEach(() => { _ = absoluteFrom; SOME_DIRECTIVE_FILE = { @@ -891,10 +899,10 @@ runInEachFileSystem(() => { it('should find the decorators on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -902,7 +910,7 @@ runInEachFileSystem(() => { const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -910,11 +918,11 @@ runInEachFileSystem(() => { it('should find the decorators on a class at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -922,7 +930,7 @@ runInEachFileSystem(() => { const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -930,7 +938,7 @@ runInEachFileSystem(() => { it('should return null if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const decorators = host.getDecoratorsOfDeclaration(functionNode); @@ -940,7 +948,7 @@ runInEachFileSystem(() => { it('should return null if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const decorators = host.getDecoratorsOfDeclaration(classNode); @@ -950,7 +958,7 @@ runInEachFileSystem(() => { it('should ignore `decorators` if it is not an array literal', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); @@ -961,11 +969,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements that are not object literals', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining<Decorator>({name: 'Directive'})); @@ -974,11 +982,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements that have no `type` property', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -987,11 +995,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1000,10 +1008,10 @@ runInEachFileSystem(() => { it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'}); @@ -1013,11 +1021,11 @@ runInEachFileSystem(() => { it('should be an empty array if decorator has no `args` property', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1027,11 +1035,11 @@ runInEachFileSystem(() => { it('should be an empty array if decorator\'s `args` has no property assignment', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1041,11 +1049,11 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1058,67 +1066,67 @@ runInEachFileSystem(() => { it('should find decorated members on a class at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); - expect(input1.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'}); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators![0].import).toEqual({name: 'Input', from: '@angular/core'}); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input2.decorators !.map(d => d.name)).toEqual(['Input']); - expect(input2.decorators ![0].import).toEqual({name: 'Input', from: '@angular/core'}); + expect(input2.decorators!.map(d => d.name)).toEqual(['Input']); + expect(input2.decorators![0].import).toEqual({name: 'Input', from: '@angular/core'}); }); it('should find decorated members on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input2.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input2.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find Object.defineProperty members on a class', () => { loadTestFiles([ACCESSORS_FILE]); const bundle = makeTestBundleProgram(ACCESSORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, ACCESSORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const setter = members.find(member => member.name === 'setter') !; + const setter = members.find(member => member.name === 'setter')!; expect(setter.kind).toEqual(ClassMemberKind.Setter); expect(setter.isStatic).toEqual(false); expect(setter.value).toBeNull(); - expect(setter.decorators !.map(d => d.name)).toEqual(['Input']); - expect(ts.isFunctionExpression(setter.implementation !)).toEqual(true); + expect(setter.decorators!.map(d => d.name)).toEqual(['Input']); + expect(ts.isFunctionExpression(setter.implementation!)).toEqual(true); expect((setter.implementation as ts.FunctionExpression).body.statements[0].getText()) .toEqual('this.value = value;'); - const getter = members.find(member => member.name === 'getter') !; + const getter = members.find(member => member.name === 'getter')!; expect(getter.kind).toEqual(ClassMemberKind.Getter); expect(getter.isStatic).toEqual(false); expect(getter.value).toBeNull(); - expect(getter.decorators !.map(d => d.name)).toEqual(['Output']); - expect(ts.isFunctionExpression(getter.implementation !)).toEqual(true); + expect(getter.decorators!.map(d => d.name)).toEqual(['Output']); + expect(ts.isFunctionExpression(getter.implementation!)).toEqual(true); expect((getter.implementation as ts.FunctionExpression).body.statements[0].getText()) .toEqual('return null;'); @@ -1126,16 +1134,16 @@ runInEachFileSystem(() => { members.filter(member => member.name === 'setterAndGetter'); expect(combinedSetter.kind).toEqual(ClassMemberKind.Setter); expect(combinedSetter.isStatic).toEqual(false); - expect(combinedSetter.decorators !.map(d => d.name)).toEqual(['Input']); + expect(combinedSetter.decorators!.map(d => d.name)).toEqual(['Input']); expect(combinedGetter.kind).toEqual(ClassMemberKind.Getter); expect(combinedGetter.isStatic).toEqual(false); - expect(combinedGetter.decorators !.map(d => d.name)).toEqual([]); + expect(combinedGetter.decorators!.map(d => d.name)).toEqual([]); - const staticSetter = members.find(member => member.name === 'staticSetter') !; + const staticSetter = members.find(member => member.name === 'staticSetter')!; expect(staticSetter.kind).toEqual(ClassMemberKind.Setter); expect(staticSetter.isStatic).toEqual(true); expect(staticSetter.value).toBeNull(); - expect(staticSetter.decorators !.map(d => d.name)).toEqual([]); + expect(staticSetter.decorators!.map(d => d.name)).toEqual([]); const none = members.find(member => member.name === 'none'); expect(none).toBeUndefined(); @@ -1147,56 +1155,56 @@ runInEachFileSystem(() => { it('should find non decorated properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const instanceProperty = members.find(member => member.name === 'instanceProperty') !; + const instanceProperty = members.find(member => member.name === 'instanceProperty')!; expect(instanceProperty.kind).toEqual(ClassMemberKind.Property); expect(instanceProperty.isStatic).toEqual(false); - expect(ts.isBinaryExpression(instanceProperty.implementation !)).toEqual(true); - expect(instanceProperty.value !.getText()).toEqual(`'instance'`); + expect(ts.isBinaryExpression(instanceProperty.implementation!)).toEqual(true); + expect(instanceProperty.value!.getText()).toEqual(`'instance'`); }); it('should find static methods on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticMethod = members.find(member => member.name === 'staticMethod') !; + const staticMethod = members.find(member => member.name === 'staticMethod')!; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); expect(staticMethod.value).toBeNull(); - expect(ts.isFunctionExpression(staticMethod.implementation !)).toEqual(true); + expect(ts.isFunctionExpression(staticMethod.implementation!)).toEqual(true); }); it('should find static properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should accept `ctorParameters` as an array', () => { loadTestFiles([CTOR_DECORATORS_ARRAY_FILE]); const bundle = makeTestBundleProgram(CTOR_DECORATORS_ARRAY_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, CTOR_DECORATORS_ARRAY_FILE.name, 'CtorDecoratedAsArray', isNamedVariableDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters).toBeDefined(); expect(parameters.map(parameter => parameter.name)).toEqual(['arg1']); @@ -1206,7 +1214,7 @@ runInEachFileSystem(() => { it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(() => { @@ -1217,7 +1225,7 @@ runInEachFileSystem(() => { it('should return an empty array if there are no prop decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); @@ -1229,7 +1237,7 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); @@ -1241,13 +1249,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements that are not object literals', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'})); @@ -1256,13 +1264,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements that have no `type` property', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'})); @@ -1271,13 +1279,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Input'})); @@ -1287,13 +1295,13 @@ runInEachFileSystem(() => { it('should be an empty array if prop decorator has no `args` property', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1304,13 +1312,14 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1320,13 +1329,13 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1338,7 +1347,7 @@ runInEachFileSystem(() => { () => { loadTestFiles([UNWANTED_PROTOTYPE_EXPORT_FILE]); const bundle = makeTestBundleProgram(UNWANTED_PROTOTYPE_EXPORT_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, UNWANTED_PROTOTYPE_EXPORT_FILE.name, 'SomeParam', isNamedClassDeclaration); @@ -1351,16 +1360,16 @@ runInEachFileSystem(() => { it('should find the decorated constructor parameters', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -1370,17 +1379,17 @@ runInEachFileSystem(() => { it('should find the decorated constructor parameters at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -1390,10 +1399,12 @@ runInEachFileSystem(() => { it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); - expect(() => { host.getConstructorParameters(functionNode); }) + expect(() => { + host.getConstructorParameters(functionNode); + }) .toThrowError( 'Attempted to get constructor parameters of a non-class: "function foo() {}"'); }); @@ -1404,22 +1415,22 @@ runInEachFileSystem(() => { it('should return an array even if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toEqual(jasmine.any(Array)); - expect(parameters !.length).toEqual(1); - expect(parameters ![0].name).toEqual('foo'); - expect(parameters ![0].decorators).toBe(null); + expect(parameters!.length).toEqual(1); + expect(parameters![0].name).toEqual('foo'); + expect(parameters![0].decorators).toBe(null); }); it('should return an empty array if there are no constructor parameters', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', isNamedVariableDeclaration); @@ -1434,14 +1445,14 @@ runInEachFileSystem(() => { it('should ignore `ctorParameters` if it does not return an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(1); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); @@ -1451,18 +1462,18 @@ runInEachFileSystem(() => { it('should ignore param decorator elements that are not object literals', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(2); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(2); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); - expect(parameters ![1]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters![1]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg2', decorators: jasmine.any(Array) as any })); @@ -1471,12 +1482,12 @@ runInEachFileSystem(() => { it('should ignore param decorator elements that have no `type` property', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1485,12 +1496,12 @@ runInEachFileSystem(() => { it('should ignore param decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1499,12 +1510,12 @@ runInEachFileSystem(() => { it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![2].decorators !; + const decorators = parameters![2].decorators!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'}); @@ -1526,7 +1537,7 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); return host.getConstructorParameters(classNode); @@ -1570,7 +1581,7 @@ runInEachFileSystem(() => { return _super !== null && _super.apply(this, arguments) || this; }`); - expect(parameters !.length).toBe(1); + expect(parameters!.length).toBe(1); }); it('does not consider manual super calls as synthesized', () => { @@ -1579,7 +1590,7 @@ runInEachFileSystem(() => { return _super.call(this) || this; }`); - expect(parameters !.length).toBe(0); + expect(parameters!.length).toBe(0); }); it('does not consider empty constructors as synthesized', () => { @@ -1587,7 +1598,7 @@ runInEachFileSystem(() => { function TestClass() { }`); - expect(parameters !.length).toBe(0); + expect(parameters!.length).toBe(0); }); }); @@ -1595,13 +1606,13 @@ runInEachFileSystem(() => { it('should be an empty array if param decorator has no `args` property', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - const decorators = parameters ![0].decorators !; + expect(parameters!.length).toBe(1); + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1612,12 +1623,13 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1627,12 +1639,12 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1646,45 +1658,45 @@ runInEachFileSystem(() => { () => { loadTestFiles([FUNCTION_BODY_FILE]); const bundle = makeTestBundleProgram(FUNCTION_BODY_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const fooNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration) !; - const fooDef = host.getDefinitionOfFunction(fooNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration)!; + const fooDef = host.getDefinitionOfFunction(fooNode)!; expect(fooDef.node).toBe(fooNode); - expect(fooDef.body !.length).toEqual(1); - expect(fooDef.body ![0].getText()).toEqual(`return x;`); + expect(fooDef.body!.length).toEqual(1); + expect(fooDef.body![0].getText()).toEqual(`return x;`); expect(fooDef.parameters.length).toEqual(1); expect(fooDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); const barNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration) !; - const barDef = host.getDefinitionOfFunction(barNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration)!; + const barDef = host.getDefinitionOfFunction(barNode)!; expect(barDef.node).toBe(barNode); - expect(barDef.body !.length).toEqual(1); - expect(ts.isReturnStatement(barDef.body ![0])).toBeTruthy(); - expect(barDef.body ![0].getText()).toEqual(`return x + y;`); + expect(barDef.body!.length).toEqual(1); + expect(ts.isReturnStatement(barDef.body![0])).toBeTruthy(); + expect(barDef.body![0].getText()).toEqual(`return x + y;`); expect(barDef.parameters.length).toEqual(2); expect(barDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); expect(barDef.parameters[1].name).toEqual('y'); - expect(barDef.parameters[1].initializer !.getText()).toEqual('42'); + expect(barDef.parameters[1].initializer!.getText()).toEqual('42'); const bazNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration) !; - const bazDef = host.getDefinitionOfFunction(bazNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration)!; + const bazDef = host.getDefinitionOfFunction(bazNode)!; expect(bazDef.node).toBe(bazNode); - expect(bazDef.body !.length).toEqual(3); + expect(bazDef.body!.length).toEqual(3); expect(bazDef.parameters.length).toEqual(1); expect(bazDef.parameters[0].name).toEqual('x'); expect(bazDef.parameters[0].initializer).toBe(null); const quxNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration) !; - const quxDef = host.getDefinitionOfFunction(quxNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration)!; + const quxDef = host.getDefinitionOfFunction(quxNode)!; expect(quxDef.node).toBe(quxNode); - expect(quxDef.body !.length).toEqual(2); + expect(quxDef.body!.length).toEqual(2); expect(quxDef.parameters.length).toEqual(1); expect(quxDef.parameters[0].name).toEqual('x'); expect(quxDef.parameters[0].initializer).toBe(null); @@ -1695,7 +1707,7 @@ runInEachFileSystem(() => { it('should find the import of an identifier', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/b.js'), 'b', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1706,7 +1718,7 @@ runInEachFileSystem(() => { it('should find the name by which the identifier was exported, not imported', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/b.js'), 'c', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1717,7 +1729,7 @@ runInEachFileSystem(() => { it('should return null if the identifier was not imported', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/b.js'), 'd', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1729,10 +1741,10 @@ runInEachFileSystem(() => { describe('getDeclarationOfIdentifier()', () => { // Helpers const createTestForTsHelper = - (program: ts.Program, host: Esm5ReflectionHost, srcFile: TestFile, + (program: ts.Program, host: NgccReflectionHost, srcFile: TestFile, getHelperDeclaration: (name: string) => ts.Declaration) => (varName: string, helperName: string, knownAs: KnownDeclaration, - viaModule: string | null = null) => { + viaModule: string|null = null) => { const node = getDeclaration(program, srcFile.name, varName, ts.isVariableDeclaration); const helperIdentifier = getIdentifierFromCallExpression(node); @@ -1740,7 +1752,8 @@ runInEachFileSystem(() => { expect(helperDeclaration).toEqual({ known: knownAs, - node: getHelperDeclaration(helperName), viaModule, + node: getHelperDeclaration(helperName), + viaModule, }); }; @@ -1756,11 +1769,11 @@ runInEachFileSystem(() => { it('should return the declaration of a locally defined identifier', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const ctrDecorators = host.getConstructorParameters(classNode) !; - const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference !as{ + const ctrDecorators = host.getConstructorParameters(classNode)!; + const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference! as { local: true, expression: ts.Identifier, defaultImportStatement: null, @@ -1771,51 +1784,53 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfViewContainerRef); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe(null); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe(null); }); it('should return the declaration of an externally defined identifier', () => { loadFakeCore(getFileSystem()); loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const identifierOfDirective = ((classDecorators[0].node as ts.ObjectLiteralExpression) - .properties[0] as ts.PropertyAssignment) - .initializer as ts.Identifier; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const identifierOfDirective = + ((classDecorators[0].node as ts.ObjectLiteralExpression).properties[0] as + ts.PropertyAssignment) + .initializer as ts.Identifier; const expectedDeclarationNode = getDeclaration( bundle.program, _('/node_modules/@angular/core/index.d.ts'), 'Directive', isNamedVariableDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should return the source-file of an import namespace', () => { loadFakeCore(getFileSystem()); loadTestFiles([NAMESPACED_IMPORT_FILE]); const bundle = makeTestBundleProgram(NAMESPACED_IMPORT_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, NAMESPACED_IMPORT_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const identifier = (((classDecorators[0].node as ts.ObjectLiteralExpression) - .properties[0] as ts.PropertyAssignment) - .initializer as ts.PropertyAccessExpression) - .expression as ts.Identifier; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const identifier = + (((classDecorators[0].node as ts.ObjectLiteralExpression).properties[0] as + ts.PropertyAssignment) + .initializer as ts.PropertyAccessExpression) + .expression as ts.Identifier; const expectedDeclarationNode = getSourceFileOrError(bundle.program, _('/node_modules/@angular/core/index.d.ts')); const actualDeclaration = host.getDeclarationOfIdentifier(identifier); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should return the correct declaration for an inner function identifier inside an ES5 IIFE', @@ -1825,25 +1840,26 @@ runInEachFileSystem(() => { .and.callThrough(); loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerDeclaration = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerDeclaration = (((outerDeclaration.initializer as ts.ParenthesizedExpression) - .expression as ts.CallExpression) - .expression as ts.FunctionExpression) - .body.statements[0] as ts.FunctionDeclaration; + const innerDeclaration = + (((outerDeclaration.initializer as ts.ParenthesizedExpression).expression as + ts.CallExpression) + .expression as ts.FunctionExpression) + .body.statements[0] as ts.FunctionDeclaration; const outerIdentifier = outerDeclaration.name as ts.Identifier; const innerIdentifier = innerDeclaration.name as ts.Identifier; - expect(host.getDeclarationOfIdentifier(outerIdentifier) !.node).toBe(outerDeclaration); + expect(host.getDeclarationOfIdentifier(outerIdentifier)!.node).toBe(outerDeclaration); expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledWith(outerIdentifier); expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledTimes(1); superGetDeclarationOfIdentifierSpy.calls.reset(); - expect(host.getDeclarationOfIdentifier(innerIdentifier) !.node).toBe(outerDeclaration); + expect(host.getDeclarationOfIdentifier(innerIdentifier)!.node).toBe(outerDeclaration); expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledWith(innerIdentifier); expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledWith(outerIdentifier); expect(superGetDeclarationOfIdentifierSpy).toHaveBeenCalledTimes(2); @@ -1864,17 +1880,17 @@ runInEachFileSystem(() => { loadTestFiles([PROGRAM_FILE]); const bundle = makeTestBundleProgram(PROGRAM_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const expectedDeclaration = getDeclaration( bundle.program, PROGRAM_FILE.name, 'AliasedClass', isNamedVariableDeclaration); // Grab the `AliasedClass_1` identifier (which is an alias for `AliasedClass`). const aliasIdentifier = (expectedDeclaration.initializer as ts.BinaryExpression).left as ts.Identifier; - const actualDeclaration = host.getDeclarationOfIdentifier(aliasIdentifier) !; + const actualDeclaration = host.getDeclarationOfIdentifier(aliasIdentifier)!; expect(aliasIdentifier.getText()).toBe('AliasedClass_1'); - expect(actualDeclaration.node !.getText()).toBe(expectedDeclaration.getText()); + expect(actualDeclaration.node!.getText()).toBe(expectedDeclaration.getText()); }); it('should return the correct outer declaration for an aliased inner class declaration inside an ES5 IIFE', @@ -1907,23 +1923,24 @@ runInEachFileSystem(() => { loadTestFiles([PROGRAM_FILE]); const bundle = makeTestBundleProgram(PROGRAM_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const expectedDeclaration = getDeclaration( bundle.program, PROGRAM_FILE.name, 'FroalaEditorModule', isNamedVariableDeclaration); // Grab the `FroalaEditorModule_1` identifier returned from the `forRoot()` method - const forRootMethod = ((((expectedDeclaration.initializer as ts.ParenthesizedExpression) - .expression as ts.CallExpression) - .expression as ts.FunctionExpression) - .body.statements[2] as ts.ExpressionStatement); + const forRootMethod = + ((((expectedDeclaration.initializer as ts.ParenthesizedExpression).expression as + ts.CallExpression) + .expression as ts.FunctionExpression) + .body.statements[2] as ts.ExpressionStatement); const identifier = (((((forRootMethod.expression as ts.BinaryExpression).right as ts.FunctionExpression) .body.statements[0] as ts.ReturnStatement) .expression as ts.ObjectLiteralExpression) .properties[0] as ts.PropertyAssignment) .initializer as ts.Identifier; - const actualDeclaration = host.getDeclarationOfIdentifier(identifier) !; - expect(actualDeclaration.node !.getText()).toBe(expectedDeclaration.getText()); + const actualDeclaration = host.getDeclarationOfIdentifier(identifier)!; + expect(actualDeclaration.node!.getText()).toBe(expectedDeclaration.getText()); }); it('should recognize TypeScript helpers (as function declarations)', () => { @@ -1941,7 +1958,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -1968,7 +1985,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -1995,7 +2012,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -2022,7 +2039,7 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, file, @@ -2059,7 +2076,7 @@ runInEachFileSystem(() => { const [testFile, tslibFile] = files; const bundle = makeTestBundleProgram(testFile.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, testFile, @@ -2096,7 +2113,7 @@ runInEachFileSystem(() => { const [testFile, tslibFile] = files; const bundle = makeTestBundleProgram(testFile.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const testForHelper = createTestForTsHelper( bundle.program, host, testFile, @@ -2114,11 +2131,11 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/b.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.keys())).toEqual([ + expect(Array.from(exportDeclarations!.keys())).toEqual([ 'Directive', 'a', 'b', @@ -2130,8 +2147,8 @@ runInEachFileSystem(() => { ]); const values = - Array.from(exportDeclarations !.values()) - .map(declaration => [declaration.node !.getText(), declaration.viaModule]); + Array.from(exportDeclarations!.values()) + .map(declaration => [declaration.node!.getText(), declaration.viaModule]); expect(values).toEqual([ [`Directive: FnWithArg<(clazz: any) => any>`, null], [`a = 'a'`, null], @@ -2162,9 +2179,9 @@ runInEachFileSystem(() => { }; loadTestFiles([tslib]); const bundle = makeTestBundleProgram(tslib.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const sf = getSourceFileOrError(bundle.program, tslib.name); - const exportDeclarations = host.getExportsOfModule(sf) !; + const exportDeclarations = host.getExportsOfModule(sf)!; expect([...exportDeclarations].map(([exportName, {known}]) => [exportName, known])) .toEqual([ @@ -2180,55 +2197,55 @@ runInEachFileSystem(() => { it('should return the class symbol for an ES2015 class', () => { loadTestFiles([SIMPLE_ES2015_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_ES2015_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_ES2015_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const classSymbol = host.getClassSymbol(node); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(node); - expect(classSymbol !.implementation.valueDeclaration).toBe(node); + expect(classSymbol!.declaration.valueDeclaration).toBe(node); + expect(classSymbol!.implementation.valueDeclaration).toBe(node); }); it('should return the class symbol for an ES5 class (outer variable declaration)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for an ES5 class (inner function declaration)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(innerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the same class symbol (of the outer declaration) for outer and inner declarations', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; - const innerSymbol = host.getClassSymbol(innerNode) !; - const outerSymbol = host.getClassSymbol(outerNode) !; + const innerSymbol = host.getClassSymbol(innerNode)!; + const outerSymbol = host.getClassSymbol(outerNode)!; expect(innerSymbol.declaration).toBe(outerSymbol.declaration); expect(innerSymbol.implementation).toBe(outerSymbol.implementation); }); @@ -2237,37 +2254,37 @@ runInEachFileSystem(() => { () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoParensClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for an ES5 class whose IIFE is not wrapped with inner parens', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'InnerParensClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return undefined if node is not an ES5 class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const classSymbol = host.getClassSymbol(node); @@ -2282,7 +2299,7 @@ runInEachFileSystem(() => { }; loadTestFiles([testFile]); const bundle = makeTestBundleProgram(testFile.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration(bundle.program, testFile.name, 'MyClass', isNamedVariableDeclaration); const classSymbol = host.getClassSymbol(node); @@ -2295,7 +2312,7 @@ runInEachFileSystem(() => { it('should return true if a given node is a TS class declaration', () => { loadTestFiles([SIMPLE_ES2015_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_ES2015_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_ES2015_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); expect(host.isClass(node)).toBe(true); @@ -2304,7 +2321,7 @@ runInEachFileSystem(() => { it('should return true if a given node is the outer variable declaration of a class', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); expect(host.isClass(node)).toBe(true); @@ -2313,17 +2330,17 @@ runInEachFileSystem(() => { it('should return true if a given node is the inner variable declaration of a class', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; expect(host.isClass(innerNode)).toBe(true); }); it('should return false if a given node is a function declaration', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(host.isClass(node)).toBe(false); @@ -2339,7 +2356,7 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); return host.hasBaseClass(classNode); @@ -2386,7 +2403,7 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); const expression = host.getBaseClassExpression(classNode); @@ -2408,7 +2425,7 @@ runInEachFileSystem(() => { function TestClass() {} return TestClass; }(BaseClass));`); - expect(identifier !.text).toBe('BaseClass'); + expect(identifier!.text).toBe('BaseClass'); }); it('should find the base class of an IIFE with a unique name generated for the _super parameter', @@ -2423,7 +2440,7 @@ runInEachFileSystem(() => { function TestClass() {} return TestClass; }(BaseClass));`); - expect(identifier !.text).toBe('BaseClass'); + expect(identifier!.text).toBe('BaseClass'); }); it('should not find a base class for an IIFE without parameter', () => { @@ -2458,10 +2475,10 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); - const expression = host.getBaseClassExpression(classNode) !; + const expression = host.getBaseClassExpression(classNode)!; expect(expression.getText()).toBe('foo()'); }); }); @@ -2470,7 +2487,7 @@ runInEachFileSystem(() => { it('should return an array of all classes in the given source file', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); @@ -2488,21 +2505,21 @@ runInEachFileSystem(() => { it('should return decorators of class symbol', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(getRootFiles(DECORATED_FILES)[0]); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); const classSymbolsPrimary = host.findClassSymbols(primaryFile); const classDecoratorsPrimary = classSymbolsPrimary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsPrimary.length).toEqual(2); - expect(classDecoratorsPrimary[0] !.map(d => d.name)).toEqual(['Directive']); - expect(classDecoratorsPrimary[1] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[0]!.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[1]!.map(d => d.name)).toEqual(['Directive']); const classSymbolsSecondary = host.findClassSymbols(secondaryFile); const classDecoratorsSecondary = classSymbolsSecondary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsSecondary.length).toEqual(1); - expect(classDecoratorsSecondary[0] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsSecondary[0]!.map(d => d.name)).toEqual(['Directive']); }); }); @@ -2515,10 +2532,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'Class1', ts.isVariableDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find the dts declaration for exported functions', () => { @@ -2528,10 +2546,11 @@ runInEachFileSystem(() => { const dts = makeTestDtsBundleProgram(_('/ep/typings/func1.d.ts'), _('/')); const mooFn = getDeclaration( bundle.program, _('/ep/src/func1.js'), 'mooFn', ts.isFunctionDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(mooFn); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); }); it('should return null if there is no matching class in the matching dts file', () => { @@ -2541,7 +2560,8 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const missingClass = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'MissingClass1', ts.isVariableDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2554,7 +2574,8 @@ runInEachFileSystem(() => { const missingClass = getDeclaration( bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', ts.isVariableDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2567,10 +2588,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'Class1', ts.isVariableDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find aliased exports', () => { @@ -2580,7 +2602,8 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const sourceClass = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'SourceClass', ts.isVariableDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(sourceClass); if (dtsDeclaration === null) { @@ -2602,11 +2625,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const internalClass = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'InternalClass', ts.isVariableDeclaration); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(internalClass); - expect(dtsDeclaration !.getSourceFile().fileName) - .toEqual(_('/ep/typings/internal.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/internal.d.ts')); }); it('should match publicly and internal exported classes correctly, even if they have the same name', @@ -2615,18 +2638,19 @@ runInEachFileSystem(() => { loadTestFiles(TYPINGS_DTS_FILES); const bundle = makeTestBundleProgram(getRootFiles(TYPINGS_SRC_FILES)[0]); const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle, dts)); const class2 = getDeclaration( bundle.program, _('/ep/src/class2.js'), 'Class2', isNamedVariableDeclaration); const class2DtsDeclaration = host.getDtsDeclaration(class2); - expect(class2DtsDeclaration !.getSourceFile().fileName) + expect(class2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/class2.d.ts')); const internalClass2 = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'Class2', isNamedVariableDeclaration); const internalClass2DtsDeclaration = host.getDtsDeclaration(internalClass2); - expect(internalClass2DtsDeclaration !.getSourceFile().fileName) + expect(internalClass2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/internal.d.ts')); }); }); @@ -2635,7 +2659,7 @@ runInEachFileSystem(() => { it('should return the name of the inner class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const emptyClass = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -2659,7 +2683,7 @@ runInEachFileSystem(() => { it('should return the name of the inner class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const emptyClass = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -2684,10 +2708,10 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/functions.js')); const fns = host.getModuleWithProvidersFunctions(file); - expect(fns.map(fn => [fn.declaration.name !.getText(), fn.ngModule.node.name.text])) + expect(fns.map(fn => [fn.declaration.name!.getText(), fn.ngModule.node.name.text])) .toEqual([ ['ngModuleIdentifier', 'InternalModule'], ['ngModuleWithEmptyProviders', 'InternalModule'], @@ -2701,7 +2725,7 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/methods.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2732,7 +2756,7 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/outer_aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2745,7 +2769,7 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(_('/src/index.js')); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/inner_aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2758,9 +2782,9 @@ runInEachFileSystem(() => { it('should return the last static property of the class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); const classSymbol = - host.findClassSymbols(bundle.program.getSourceFile(SOME_DIRECTIVE_FILE.name) !)[0]; + host.findClassSymbols(bundle.program.getSourceFile(SOME_DIRECTIVE_FILE.name)!)[0]; const endOfClass = host.getEndOfClass(classSymbol); expect(endOfClass.getText()).toEqual(`SomeDirective.propDecorators = { "input1": [{ type: Input },], diff --git a/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts b/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts index 6a549b65eba32..89319ab05f7d5 100644 --- a/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts @@ -9,12 +9,15 @@ import * as ts from 'typescript'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {ClassMemberKind, CtorParameter, Import, InlineDeclaration, KnownDeclaration, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; +import {ClassMemberKind, CtorParameter, Import, InlineDeclaration, isNamedClassDeclaration, isNamedFunctionDeclaration, isNamedVariableDeclaration, KnownDeclaration, TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; +import {DelegatingReflectionHost} from '../../src/host/delegating_host'; import {getIifeBody} from '../../src/host/esm5_host'; -import {UmdReflectionHost, parseStatementForUmdModule} from '../../src/host/umd_host'; +import {NgccReflectionHost} from '../../src/host/ngcc_host'; +import {parseStatementForUmdModule, UmdReflectionHost} from '../../src/host/umd_host'; +import {BundleProgram} from '../../src/packages/bundle_program'; import {MockLogger} from '../helpers/mock_logger'; import {getRootFiles, makeTestBundleProgram} from '../helpers/utils'; @@ -45,6 +48,12 @@ runInEachFileSystem(() => { let TYPINGS_DTS_FILES: TestFile[]; let MODULE_WITH_PROVIDERS_PROGRAM: TestFile[]; + // Helpers + const createHost = (bundle: BundleProgram, ngccHost: UmdReflectionHost) => { + const tsHost = new TypeScriptReflectionHost(bundle.program.getTypeChecker()); + return new DelegatingReflectionHost(tsHost, ngccHost); + }; + beforeEach(() => { _ = absoluteFrom; @@ -1084,10 +1093,10 @@ runInEachFileSystem(() => { it('should find the decorators on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -1095,7 +1104,7 @@ runInEachFileSystem(() => { const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -1103,11 +1112,11 @@ runInEachFileSystem(() => { it('should find the decorators on a class at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); @@ -1115,7 +1124,7 @@ runInEachFileSystem(() => { const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -1123,7 +1132,7 @@ runInEachFileSystem(() => { it('should return null if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const decorators = host.getDecoratorsOfDeclaration(functionNode); @@ -1133,7 +1142,7 @@ runInEachFileSystem(() => { it('should return null if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const decorators = host.getDecoratorsOfDeclaration(classNode); @@ -1143,7 +1152,7 @@ runInEachFileSystem(() => { it('should ignore `decorators` if it is not an array literal', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); @@ -1154,11 +1163,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements that are not object literals', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1167,11 +1176,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements that have no `type` property', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1180,11 +1189,11 @@ runInEachFileSystem(() => { it('should ignore decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1193,11 +1202,11 @@ runInEachFileSystem(() => { it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'}); @@ -1206,32 +1215,32 @@ runInEachFileSystem(() => { it('should find decorated members on a class at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); describe('(returned decorators `args`)', () => { it('should be an empty array if decorator has no `args` property', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1241,11 +1250,11 @@ runInEachFileSystem(() => { it('should be an empty array if decorator\'s `args` has no property assignment', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1255,11 +1264,11 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Directive'); @@ -1272,70 +1281,70 @@ runInEachFileSystem(() => { it('should find decorated members on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find non decorated properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const instanceProperty = members.find(member => member.name === 'instanceProperty') !; + const instanceProperty = members.find(member => member.name === 'instanceProperty')!; expect(instanceProperty.kind).toEqual(ClassMemberKind.Property); expect(instanceProperty.isStatic).toEqual(false); - expect(ts.isBinaryExpression(instanceProperty.implementation !)).toEqual(true); - expect(instanceProperty.value !.getText()).toEqual(`'instance'`); + expect(ts.isBinaryExpression(instanceProperty.implementation!)).toEqual(true); + expect(instanceProperty.value!.getText()).toEqual(`'instance'`); }); it('should find static methods on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticMethod = members.find(member => member.name === 'staticMethod') !; + const staticMethod = members.find(member => member.name === 'staticMethod')!; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); - expect(ts.isFunctionExpression(staticMethod.implementation !)).toEqual(true); + expect(ts.isFunctionExpression(staticMethod.implementation!)).toEqual(true); }); it('should find static properties on a class', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(() => { @@ -1346,7 +1355,7 @@ runInEachFileSystem(() => { it('should return an empty array if there are no prop decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); @@ -1358,7 +1367,7 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); @@ -1370,13 +1379,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements that are not object literals', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1385,13 +1394,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements that have no `type` property', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1401,13 +1410,13 @@ runInEachFileSystem(() => { it('should ignore prop decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_PROP_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Directive'})); @@ -1416,11 +1425,11 @@ runInEachFileSystem(() => { it('should have import information on decorators', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Directive', from: '@angular/core'}); @@ -1430,13 +1439,13 @@ runInEachFileSystem(() => { it('should be an empty array if prop decorator has no `args` property', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1446,13 +1455,13 @@ runInEachFileSystem(() => { it('should be an empty array if prop decorator\'s `args` has no property assignment', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1462,13 +1471,13 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_PROP_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_PROP_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const prop = members.find(m => m.name === 'prop') !; - const decorators = prop.decorators !; + const prop = members.find(m => m.name === 'prop')!; + const decorators = prop.decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Input'); @@ -1480,16 +1489,16 @@ runInEachFileSystem(() => { it('should find the decorated constructor parameters', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -1499,17 +1508,17 @@ runInEachFileSystem(() => { it('should find the decorated constructor parameters at the top level', () => { loadTestFiles([TOPLEVEL_DECORATORS_FILE]); const bundle = makeTestBundleProgram(TOPLEVEL_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -1519,11 +1528,11 @@ runInEachFileSystem(() => { it('should accept `ctorParameters` as an array', () => { loadTestFiles([CTOR_DECORATORS_ARRAY_FILE]); const bundle = makeTestBundleProgram(CTOR_DECORATORS_ARRAY_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, CTOR_DECORATORS_ARRAY_FILE.name, 'CtorDecoratedAsArray', isNamedVariableDeclaration); - const parameters = host.getConstructorParameters(classNode) !; + const parameters = host.getConstructorParameters(classNode)!; expect(parameters).toBeDefined(); expect(parameters.map(parameter => parameter.name)).toEqual(['arg1']); @@ -1533,10 +1542,12 @@ runInEachFileSystem(() => { it('should throw if the symbol is not a class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const functionNode = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); - expect(() => { host.getConstructorParameters(functionNode); }) + expect(() => { + host.getConstructorParameters(functionNode); + }) .toThrowError( 'Attempted to get constructor parameters of a non-class: "function foo() {}"'); }); @@ -1547,22 +1558,22 @@ runInEachFileSystem(() => { it('should return an array even if there are no decorators', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); expect(parameters).toEqual(jasmine.any(Array)); - expect(parameters !.length).toEqual(1); - expect(parameters ![0].name).toEqual('foo'); - expect(parameters ![0].decorators).toBe(null); + expect(parameters!.length).toEqual(1); + expect(parameters![0].name).toEqual('foo'); + expect(parameters![0].decorators).toBe(null); }); it('should return an empty array if there are no constructor parameters', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', isNamedVariableDeclaration); @@ -1577,14 +1588,14 @@ runInEachFileSystem(() => { it('should ignore `ctorParameters` if it does not return an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(1); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); @@ -1594,18 +1605,18 @@ runInEachFileSystem(() => { it('should ignore param decorator elements that are not object literals', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(2); - expect(parameters ![0]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters!.length).toBe(2); + expect(parameters![0]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg1', decorators: null, })); - expect(parameters ![1]).toEqual(jasmine.objectContaining<CtorParameter>({ + expect(parameters![1]).toEqual(jasmine.objectContaining<CtorParameter>({ name: 'arg2', decorators: jasmine.any(Array) as any })); @@ -1614,12 +1625,12 @@ runInEachFileSystem(() => { it('should ignore param decorator elements that have no `type` property', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1628,12 +1639,12 @@ runInEachFileSystem(() => { it('should ignore param decorator elements whose `type` value is not an identifier', () => { loadTestFiles([INVALID_CTOR_DECORATORS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATORS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0]).toEqual(jasmine.objectContaining({name: 'Inject'})); @@ -1642,7 +1653,7 @@ runInEachFileSystem(() => { it('should use `getImportOfIdentifier()` to retrieve import info', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); @@ -1651,7 +1662,7 @@ runInEachFileSystem(() => { .and.returnValue(mockImportInfo); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![2].decorators !; + const decorators = parameters![2].decorators!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toBe(mockImportInfo); @@ -1662,13 +1673,13 @@ runInEachFileSystem(() => { it('should be an empty array if param decorator has no `args` property', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - expect(parameters !.length).toBe(1); - const decorators = parameters ![0].decorators !; + expect(parameters!.length).toBe(1); + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1679,12 +1690,13 @@ runInEachFileSystem(() => { () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1694,12 +1706,12 @@ runInEachFileSystem(() => { it('should be an empty array if `args` property value is not an array literal', () => { loadTestFiles([INVALID_CTOR_DECORATOR_ARGS_FILE]); const bundle = makeTestBundleProgram(INVALID_CTOR_DECORATOR_ARGS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![0].decorators !; + const decorators = parameters![0].decorators!; expect(decorators.length).toBe(1); expect(decorators[0].name).toBe('Inject'); @@ -1713,45 +1725,45 @@ runInEachFileSystem(() => { () => { loadTestFiles([FUNCTION_BODY_FILE]); const bundle = makeTestBundleProgram(FUNCTION_BODY_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const fooNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration) !; - const fooDef = host.getDefinitionOfFunction(fooNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'foo', isNamedFunctionDeclaration)!; + const fooDef = host.getDefinitionOfFunction(fooNode)!; expect(fooDef.node).toBe(fooNode); - expect(fooDef.body !.length).toEqual(1); - expect(fooDef.body ![0].getText()).toEqual(`return x;`); + expect(fooDef.body!.length).toEqual(1); + expect(fooDef.body![0].getText()).toEqual(`return x;`); expect(fooDef.parameters.length).toEqual(1); expect(fooDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); const barNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration) !; - const barDef = host.getDefinitionOfFunction(barNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'bar', isNamedFunctionDeclaration)!; + const barDef = host.getDefinitionOfFunction(barNode)!; expect(barDef.node).toBe(barNode); - expect(barDef.body !.length).toEqual(1); - expect(ts.isReturnStatement(barDef.body ![0])).toBeTruthy(); - expect(barDef.body ![0].getText()).toEqual(`return x + y;`); + expect(barDef.body!.length).toEqual(1); + expect(ts.isReturnStatement(barDef.body![0])).toBeTruthy(); + expect(barDef.body![0].getText()).toEqual(`return x + y;`); expect(barDef.parameters.length).toEqual(2); expect(barDef.parameters[0].name).toEqual('x'); expect(fooDef.parameters[0].initializer).toBe(null); expect(barDef.parameters[1].name).toEqual('y'); - expect(barDef.parameters[1].initializer !.getText()).toEqual('42'); + expect(barDef.parameters[1].initializer!.getText()).toEqual('42'); const bazNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration) !; - const bazDef = host.getDefinitionOfFunction(bazNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'baz', isNamedFunctionDeclaration)!; + const bazDef = host.getDefinitionOfFunction(bazNode)!; expect(bazDef.node).toBe(bazNode); - expect(bazDef.body !.length).toEqual(3); + expect(bazDef.body!.length).toEqual(3); expect(bazDef.parameters.length).toEqual(1); expect(bazDef.parameters[0].name).toEqual('x'); expect(bazDef.parameters[0].initializer).toBe(null); const quxNode = getDeclaration( - bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration) !; - const quxDef = host.getDefinitionOfFunction(quxNode) !; + bundle.program, FUNCTION_BODY_FILE.name, 'qux', isNamedFunctionDeclaration)!; + const quxDef = host.getDefinitionOfFunction(quxNode)!; expect(quxDef.node).toBe(quxNode); - expect(quxDef.body !.length).toEqual(2); + expect(quxDef.body!.length).toEqual(2); expect(quxDef.parameters.length).toEqual(1); expect(quxDef.parameters[0].name).toEqual('x'); expect(quxDef.parameters[0].initializer).toBe(null); @@ -1762,7 +1774,7 @@ runInEachFileSystem(() => { it('should find the import of an identifier', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/file_b.js'), 'b', isNamedVariableDeclaration); const identifier = @@ -1772,14 +1784,14 @@ runInEachFileSystem(() => { null; expect(identifier).not.toBe(null); - const importOfIdent = host.getImportOfIdentifier(identifier !); + const importOfIdent = host.getImportOfIdentifier(identifier!); expect(importOfIdent).toEqual({name: 'a', from: './file_a'}); }); it('should return null if the identifier was not imported', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/file_b.js'), 'd', isNamedVariableDeclaration); const importOfIdent = host.getImportOfIdentifier(variableNode.initializer as ts.Identifier); @@ -1790,7 +1802,7 @@ runInEachFileSystem(() => { it('should handle factory functions not wrapped in parentheses', () => { loadTestFiles(IMPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const variableNode = getDeclaration(bundle.program, _('/file_c.js'), 'c', isNamedVariableDeclaration); const identifier = @@ -1800,7 +1812,7 @@ runInEachFileSystem(() => { null; expect(identifier).not.toBe(null); - const importOfIdent = host.getImportOfIdentifier(identifier !); + const importOfIdent = host.getImportOfIdentifier(identifier!); expect(importOfIdent).toEqual({name: 'a', from: './file_a'}); }); }); @@ -1808,24 +1820,25 @@ runInEachFileSystem(() => { describe('getDeclarationOfIdentifier', () => { // Helpers const createTestForTsHelper = - (host: UmdReflectionHost, factoryFn: ts.FunctionExpression, + (host: NgccReflectionHost, factoryFn: ts.FunctionExpression, getHelperDeclaration: (factoryFn: ts.FunctionExpression, name: string) => ts.Declaration) => (varName: string, helperName: string, knownAs: KnownDeclaration, - viaModule: string | null = null) => { + viaModule: string|null = null) => { const node = getVariableDeclaration(factoryFn, varName); const helperIdentifier = getIdentifierFromCallExpression(node); const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); expect(helperDeclaration).toEqual({ known: knownAs, - node: getHelperDeclaration(factoryFn, helperName), viaModule, + node: getHelperDeclaration(factoryFn, helperName), + viaModule, }); }; const getFunctionDeclaration = (factoryFn: ts.FunctionExpression, name: string) => factoryFn.body.statements.filter(ts.isFunctionDeclaration) - .find(decl => (decl.name !== undefined) && (decl.name.text === name)) !; + .find(decl => (decl.name !== undefined) && (decl.name.text === name))!; const getIdentifierFromCallExpression = (decl: ts.VariableDeclaration) => { if (decl.initializer !== undefined && ts.isCallExpression(decl.initializer)) { @@ -1839,16 +1852,16 @@ runInEachFileSystem(() => { const getVariableDeclaration = (factoryFn: ts.FunctionExpression, name: string) => factoryFn.body.statements.filter(ts.isVariableStatement) .map(stmt => stmt.declarationList.declarations[0]) - .find(decl => ts.isIdentifier(decl.name) && (decl.name.text === name)) !; + .find(decl => ts.isIdentifier(decl.name) && (decl.name.text === name))!; it('should return the declaration of a locally defined identifier', () => { loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const ctrDecorators = host.getConstructorParameters(classNode) !; - const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference !as{ + const ctrDecorators = host.getConstructorParameters(classNode)!; + const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference! as { local: true, expression: ts.Identifier, defaultImportStatement: null, @@ -1859,8 +1872,8 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfViewContainerRef); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe(null); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe(null); }); it('should return the correct declaration for an outer alias identifier', () => { @@ -1884,7 +1897,7 @@ runInEachFileSystem(() => { loadTestFiles([PROGRAM_FILE]); const bundle = makeTestBundleProgram(PROGRAM_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const expectedDeclaration = getDeclaration( bundle.program, PROGRAM_FILE.name, 'AliasedClass', isNamedVariableDeclaration); @@ -1895,28 +1908,29 @@ runInEachFileSystem(() => { expect(aliasIdentifier.getText()).toBe('AliasedClass_1'); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclaration); + expect(actualDeclaration!.node).toBe(expectedDeclaration); }); it('should return the source-file of an import namespace', () => { loadFakeCore(getFileSystem()); loadTestFiles([SOME_DIRECTIVE_FILE]); const bundle = makeTestBundleProgram(SOME_DIRECTIVE_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const identifierOfDirective = (((classDecorators[0].node as ts.ObjectLiteralExpression) - .properties[0] as ts.PropertyAssignment) - .initializer as ts.PropertyAccessExpression) - .expression as ts.Identifier; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const identifierOfDirective = + (((classDecorators[0].node as ts.ObjectLiteralExpression).properties[0] as + ts.PropertyAssignment) + .initializer as ts.PropertyAccessExpression) + .expression as ts.Identifier; const expectedDeclarationNode = getSourceFileOrError(bundle.program, _('/node_modules/@angular/core/index.d.ts')); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should recognize TypeScript helpers (as function declarations)', () => { @@ -1940,9 +1954,9 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const {factoryFn} = parseStatementForUmdModule( - getSourceFileOrError(bundle.program, file.name).statements[0]) !; + getSourceFileOrError(bundle.program, file.name).statements[0])!; const testForHelper = createTestForTsHelper(host, factoryFn, getFunctionDeclaration); @@ -1972,9 +1986,9 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const {factoryFn} = parseStatementForUmdModule( - getSourceFileOrError(bundle.program, file.name).statements[0]) !; + getSourceFileOrError(bundle.program, file.name).statements[0])!; const testForHelper = createTestForTsHelper(host, factoryFn, getFunctionDeclaration); @@ -2004,9 +2018,9 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const {factoryFn} = parseStatementForUmdModule( - getSourceFileOrError(bundle.program, file.name).statements[0]) !; + getSourceFileOrError(bundle.program, file.name).statements[0])!; const testForHelper = createTestForTsHelper(host, factoryFn, getVariableDeclaration); @@ -2036,9 +2050,9 @@ runInEachFileSystem(() => { }; loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const {factoryFn} = parseStatementForUmdModule( - getSourceFileOrError(bundle.program, file.name).statements[0]) !; + getSourceFileOrError(bundle.program, file.name).statements[0])!; const testForHelper = createTestForTsHelper(host, factoryFn, getVariableDeclaration); @@ -2076,9 +2090,9 @@ runInEachFileSystem(() => { const [testFile, tslibFile] = files; const bundle = makeTestBundleProgram(testFile.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const {factoryFn} = parseStatementForUmdModule( - getSourceFileOrError(bundle.program, testFile.name).statements[0]) !; + getSourceFileOrError(bundle.program, testFile.name).statements[0])!; const tslibSourceFile = getSourceFileOrError(bundle.program, tslibFile.name); const testForHelper = createTestForTsHelper(host, factoryFn, () => tslibSourceFile); @@ -2094,12 +2108,12 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/b_module.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, '@angular/core'], ['a', `a = 'a'`, '/a_module'], @@ -2122,12 +2136,12 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -2150,13 +2164,13 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports_imported_helpers.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -2179,11 +2193,11 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles([INLINE_EXPORT_FILE]); const bundle = makeTestBundleProgram(INLINE_EXPORT_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, INLINE_EXPORT_FILE.name); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - const decl = exportDeclarations !.get('directives') as InlineDeclaration; + const decl = exportDeclarations!.get('directives') as InlineDeclaration; expect(decl).not.toBeUndefined(); expect(decl.node).toBeNull(); expect(decl.expression).toBeDefined(); @@ -2201,9 +2215,9 @@ runInEachFileSystem(() => { }; loadTestFiles([tslib]); const bundle = makeTestBundleProgram(tslib.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const sf = getSourceFileOrError(bundle.program, tslib.name); - const exportDeclarations = host.getExportsOfModule(sf) !; + const exportDeclarations = host.getExportsOfModule(sf)!; expect([...exportDeclarations].map(([exportName, {known}]) => [exportName, known])) .toEqual([ @@ -2219,26 +2233,26 @@ runInEachFileSystem(() => { it('should return the class symbol for an ES2015 class', () => { loadTestFiles([SIMPLE_ES2015_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_ES2015_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_ES2015_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); const classSymbol = host.getClassSymbol(node); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(node); - expect(classSymbol !.implementation.valueDeclaration).toBe(node); + expect(classSymbol!.declaration.valueDeclaration).toBe(node); + expect(classSymbol!.implementation.valueDeclaration).toBe(node); }); it('should handle wildcard re-exports of other modules (with emitted helpers)', () => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -2261,13 +2275,13 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports_imported_helpers.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -2290,12 +2304,12 @@ runInEachFileSystem(() => { loadFakeCore(getFileSystem()); loadTestFiles(EXPORTS_FILES); const bundle = makeTestBundleProgram(_('/index.js')); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports_with_require.js')); const exportDeclarations = host.getExportsOfModule(file); expect(exportDeclarations).not.toBe(null); - expect(Array.from(exportDeclarations !.entries()) - .map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule])) + expect(Array.from(exportDeclarations!.entries()) + .map(entry => [entry[0], entry[1].node!.getText(), entry[1].viaModule])) .toEqual([ ['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')], ['a', `a = 'a'`, _('/b_module')], @@ -2317,42 +2331,42 @@ runInEachFileSystem(() => { it('should return the class symbol for an ES5 class (outer variable declaration)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for an ES5 class (inner function declaration)', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(innerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the same class symbol (of the outer declaration) for outer and inner declarations', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; - const innerSymbol = host.getClassSymbol(innerNode) !; - const outerSymbol = host.getClassSymbol(outerNode) !; + const innerSymbol = host.getClassSymbol(innerNode)!; + const outerSymbol = host.getClassSymbol(outerNode)!; expect(innerSymbol.declaration).toBe(outerSymbol.declaration); expect(innerSymbol.implementation).toBe(outerSymbol.implementation); }); @@ -2361,37 +2375,37 @@ runInEachFileSystem(() => { () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'NoParensClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return the class symbol for an ES5 class whose IIFE is not wrapped with inner parens', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'InnerParensClass', isNamedVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(outerNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(outerNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(outerNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); it('should return undefined if node is not an ES5 class', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); const classSymbol = host.getClassSymbol(node); @@ -2406,7 +2420,7 @@ runInEachFileSystem(() => { }; loadTestFiles([testFile]); const bundle = makeTestBundleProgram(testFile.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration(bundle.program, testFile.name, 'MyClass', isNamedVariableDeclaration); const classSymbol = host.getClassSymbol(node); @@ -2419,7 +2433,7 @@ runInEachFileSystem(() => { it('should return true if a given node is a TS class declaration', () => { loadTestFiles([SIMPLE_ES2015_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_ES2015_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_ES2015_CLASS_FILE.name, 'EmptyClass', isNamedClassDeclaration); expect(host.isClass(node)).toBe(true); @@ -2428,7 +2442,7 @@ runInEachFileSystem(() => { it('should return true if a given node is the outer variable declaration of a class', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); expect(host.isClass(node)).toBe(true); @@ -2437,17 +2451,17 @@ runInEachFileSystem(() => { it('should return true if a given node is the inner variable declaration of a class', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const outerNode = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); - const innerNode = getIifeBody(outerNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(outerNode)!.statements.find(isNamedFunctionDeclaration)!; expect(host.isClass(innerNode)).toBe(true); }); it('should return false if a given node is a function declaration', () => { loadTestFiles([FOO_FUNCTION_FILE]); const bundle = makeTestBundleProgram(FOO_FUNCTION_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const node = getDeclaration( bundle.program, FOO_FUNCTION_FILE.name, 'foo', isNamedFunctionDeclaration); expect(host.isClass(node)).toBe(false); @@ -2463,7 +2477,7 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); return host.hasBaseClass(classNode); @@ -2510,7 +2524,7 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); const expression = host.getBaseClassExpression(classNode); @@ -2532,7 +2546,7 @@ runInEachFileSystem(() => { function TestClass() {} return TestClass; }(BaseClass));`); - expect(identifier !.text).toBe('BaseClass'); + expect(identifier!.text).toBe('BaseClass'); }); it('should find the base class of an IIFE with a unique name generated for the _super parameter', @@ -2547,7 +2561,7 @@ runInEachFileSystem(() => { function TestClass() {} return TestClass; }(BaseClass));`); - expect(identifier !.text).toBe('BaseClass'); + expect(identifier!.text).toBe('BaseClass'); }); it('should not find a base class for an IIFE without parameter', () => { @@ -2582,10 +2596,10 @@ runInEachFileSystem(() => { loadTestFiles([file]); const bundle = makeTestBundleProgram(file.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const classNode = getDeclaration(bundle.program, file.name, 'TestClass', isNamedVariableDeclaration); - const expression = host.getBaseClassExpression(classNode) !; + const expression = host.getBaseClassExpression(classNode)!; expect(expression.getText()).toBe('foo()'); }); }); @@ -2594,7 +2608,7 @@ runInEachFileSystem(() => { it('should return an array of all classes in the given source file', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(DECORATED_FILES[0].name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); @@ -2612,21 +2626,21 @@ runInEachFileSystem(() => { it('should return decorators of class symbol', () => { loadTestFiles(DECORATED_FILES); const bundle = makeTestBundleProgram(DECORATED_FILES[0].name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const primaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[0].name); const secondaryFile = getSourceFileOrError(bundle.program, DECORATED_FILES[1].name); const classSymbolsPrimary = host.findClassSymbols(primaryFile); const classDecoratorsPrimary = classSymbolsPrimary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsPrimary.length).toEqual(2); - expect(classDecoratorsPrimary[0] !.map(d => d.name)).toEqual(['Directive']); - expect(classDecoratorsPrimary[1] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[0]!.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsPrimary[1]!.map(d => d.name)).toEqual(['Directive']); const classSymbolsSecondary = host.findClassSymbols(secondaryFile); const classDecoratorsSecondary = classSymbolsSecondary.map(s => host.getDecoratorsOfSymbol(s)); expect(classDecoratorsSecondary.length).toEqual(1); - expect(classDecoratorsSecondary[0] !.map(d => d.name)).toEqual(['Directive']); + expect(classDecoratorsSecondary[0]!.map(d => d.name)).toEqual(['Directive']); }); }); @@ -2639,10 +2653,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'Class1', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find the dts declaration for exported functions', () => { @@ -2652,10 +2667,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(_('/ep/typings/func1.d.ts')); const mooFn = getDeclaration( bundle.program, _('/ep/src/func1.js'), 'mooFn', ts.isFunctionDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(mooFn); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/func1.d.ts')); }); it('should return null if there is no matching class in the matching dts file', () => { @@ -2665,7 +2681,8 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const missingClass = getDeclaration( bundle.program, _('/ep/src/class1.js'), 'MissingClass1', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2677,7 +2694,8 @@ runInEachFileSystem(() => { const missingClass = getDeclaration( bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); expect(host.getDtsDeclaration(missingClass)).toBe(null); }); @@ -2690,10 +2708,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'Class1', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find the dts file that contains a matching class declaration, even if the source files do not match', @@ -2704,10 +2723,11 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const class1 = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'Class1', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(class1); - expect(dtsDeclaration !.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); + expect(dtsDeclaration!.getSourceFile().fileName).toEqual(_('/ep/typings/class1.d.ts')); }); it('should find aliased exports', () => { @@ -2717,7 +2737,8 @@ runInEachFileSystem(() => { const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); const sourceClass = getDeclaration( bundle.program, _('/ep/src/flat-file.js'), 'SourceClass', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const dtsDeclaration = host.getDtsDeclaration(sourceClass); if (dtsDeclaration === null) { @@ -2737,18 +2758,19 @@ runInEachFileSystem(() => { loadTestFiles(TYPINGS_DTS_FILES); const bundle = makeTestBundleProgram(getRootFiles(TYPINGS_SRC_FILES)[0]); const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const class2 = getDeclaration( bundle.program, _('/ep/src/class2.js'), 'Class2', isNamedVariableDeclaration); const class2DtsDeclaration = host.getDtsDeclaration(class2); - expect(class2DtsDeclaration !.getSourceFile().fileName) + expect(class2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/class2.d.ts')); const internalClass2 = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'Class2', isNamedVariableDeclaration); const internalClass2DtsDeclaration = host.getDtsDeclaration(internalClass2); - expect(internalClass2DtsDeclaration !.getSourceFile().fileName) + expect(internalClass2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/internal.d.ts')); }); @@ -2762,14 +2784,15 @@ runInEachFileSystem(() => { bundle.program, _('/ep/src/class2.js'), 'Class2', ts.isVariableDeclaration); const internalClass2 = getDeclaration( bundle.program, _('/ep/src/internal.js'), 'Class2', ts.isVariableDeclaration); - const host = new UmdReflectionHost(new MockLogger(), false, bundle, dts); + const host = + createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle, dts)); const class2DtsDeclaration = host.getDtsDeclaration(class2); - expect(class2DtsDeclaration !.getSourceFile().fileName) + expect(class2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/class2.d.ts')); const internalClass2DtsDeclaration = host.getDtsDeclaration(internalClass2); - expect(internalClass2DtsDeclaration !.getSourceFile().fileName) + expect(internalClass2DtsDeclaration!.getSourceFile().fileName) .toEqual(_('/ep/typings/internal.d.ts')); }); }); @@ -2778,7 +2801,7 @@ runInEachFileSystem(() => { it('should return the name of the inner class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const emptyClass = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -2802,7 +2825,7 @@ runInEachFileSystem(() => { it('should return the name of the inner class declaration', () => { loadTestFiles([SIMPLE_CLASS_FILE]); const bundle = makeTestBundleProgram(SIMPLE_CLASS_FILE.name); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const emptyClass = getDeclaration( bundle.program, SIMPLE_CLASS_FILE.name, 'EmptyClass', isNamedVariableDeclaration); @@ -2827,10 +2850,10 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/functions.js')); const fns = host.getModuleWithProvidersFunctions(file); - expect(fns.map(fn => [fn.declaration.name !.getText(), fn.ngModule.node.name.text])) + expect(fns.map(fn => [fn.declaration.name!.getText(), fn.ngModule.node.name.text])) .toEqual([ ['ngModuleIdentifier', 'InternalModule'], ['ngModuleWithEmptyProviders', 'InternalModule'], @@ -2843,7 +2866,7 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/methods.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2870,7 +2893,7 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/outer_aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ @@ -2883,7 +2906,7 @@ runInEachFileSystem(() => { () => { loadTestFiles(MODULE_WITH_PROVIDERS_PROGRAM); const bundle = makeTestBundleProgram(getRootFiles(MODULE_WITH_PROVIDERS_PROGRAM)[0]); - const host = new UmdReflectionHost(new MockLogger(), false, bundle); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); const file = getSourceFileOrError(bundle.program, _('/src/inner_aliased_class.js')); const fn = host.getModuleWithProvidersFunctions(file); expect(fn.map(fn => [fn.declaration.getText(), fn.ngModule.node.name.text])).toEqual([ From ca25c957bfd8faa7a67cd4b1ac32808dd5eca723 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Fri, 3 Apr 2020 16:37:46 +0300 Subject: [PATCH 102/262] fix(ngcc): correctly detect imported TypeScript helpers (#36284) The `NgccReflectionHost`s have logic for detecting certain known declarations (such as `Object.assign()` and TypeScript helpers), which allows the `PartialEvaluator` to evaluate expressions it would not be able to statically evaluate otherwise. In #36089, `DelegatingReflectionHost` was introduced, which delegates to a TypeScript `ReflectionHost` when reflecting on TypeScript files, which for ngcc's case means `.d.ts` files of dependencies. As a result, ngcc lost the ability to detect TypeScript helpers imported from `tslib`, because `DelegatingReflectionHost` was not able to apply the known declaration detection logic while reflecting on `tslib`'s `.d.ts` files. This commit fixes this by ensuring `DelegatingReflectionHost` calls the `NgccReflectionHost`'s `detectKnownDeclaration()` method as necessary, even when using the TypeScript `ReflectionHost`. NOTE: The previous commit exposed a bug in ngcc that was hidden due to the tests' being inconsistent with how the `ReflectionHost`s are used in the actual program. The changes in this commit are verified by ensuring the failing tests are now passing (hence no new tests are added). PR Close #36284 --- .../ngcc/src/host/delegating_host.ts | 17 +++++++++++++++-- .../compiler-cli/ngcc/src/host/ngcc_host.ts | 15 ++++++++++++--- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/host/delegating_host.ts b/packages/compiler-cli/ngcc/src/host/delegating_host.ts index 3bef3e432dec0..d4d36fc96f38f 100644 --- a/packages/compiler-cli/ngcc/src/host/delegating_host.ts +++ b/packages/compiler-cli/ngcc/src/host/delegating_host.ts @@ -32,7 +32,7 @@ export class DelegatingReflectionHost implements NgccReflectionHost { getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null { if (isFromDtsFile(id)) { - return this.tsHost.getDeclarationOfIdentifier(id); + return this.detectKnownDeclaration(this.tsHost.getDeclarationOfIdentifier(id)); } return this.ngccHost.getDeclarationOfIdentifier(id); } @@ -60,7 +60,13 @@ export class DelegatingReflectionHost implements NgccReflectionHost { getExportsOfModule(module: ts.Node): Map<string, Declaration>|null { if (isFromDtsFile(module)) { - return this.tsHost.getExportsOfModule(module); + const exportMap = this.tsHost.getExportsOfModule(module); + + if (exportMap !== null) { + exportMap.forEach(decl => this.detectKnownDeclaration(decl)); + } + + return exportMap; } return this.ngccHost.getExportsOfModule(module); } @@ -154,4 +160,11 @@ export class DelegatingReflectionHost implements NgccReflectionHost { getEndOfClass(classSymbol: NgccClassSymbol): ts.Node { return this.ngccHost.getEndOfClass(classSymbol); } + + detectKnownDeclaration(decl: null): null; + detectKnownDeclaration<T extends Declaration>(decl: T): T; + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null; + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null { + return this.ngccHost.detectKnownDeclaration(decl); + } } diff --git a/packages/compiler-cli/ngcc/src/host/ngcc_host.ts b/packages/compiler-cli/ngcc/src/host/ngcc_host.ts index e1f3c07fded3f..eb16f662ea888 100644 --- a/packages/compiler-cli/ngcc/src/host/ngcc_host.ts +++ b/packages/compiler-cli/ngcc/src/host/ngcc_host.ts @@ -7,12 +7,12 @@ */ import * as ts from 'typescript'; -import {ClassDeclaration, ConcreteDeclaration, Decorator, ReflectionHost} from '../../../src/ngtsc/reflection'; +import {ClassDeclaration, ConcreteDeclaration, Declaration, Decorator, ReflectionHost} from '../../../src/ngtsc/reflection'; export const PRE_R3_MARKER = '__PRE_R3__'; export const POST_R3_MARKER = '__POST_R3__'; -export type SwitchableVariableDeclaration = ts.VariableDeclaration & {initializer: ts.Identifier}; +export type SwitchableVariableDeclaration = ts.VariableDeclaration&{initializer: ts.Identifier}; export function isSwitchableVariableDeclaration(node: ts.Node): node is SwitchableVariableDeclaration { return ts.isVariableDeclaration(node) && !!node.initializer && @@ -47,7 +47,7 @@ export interface ModuleWithProvidersFunction { * The symbol corresponding to a "class" declaration. I.e. a `ts.Symbol` whose `valueDeclaration` is * a `ClassDeclaration`. */ -export type ClassSymbol = ts.Symbol & {valueDeclaration: ClassDeclaration}; +export type ClassSymbol = ts.Symbol&{valueDeclaration: ClassDeclaration}; /** * A representation of a class that accounts for the potential existence of two `ClassSymbol`s for a @@ -128,4 +128,13 @@ export interface NgccReflectionHost extends ReflectionHost { * @param classSymbol The class whose statements we want. */ getEndOfClass(classSymbol: NgccClassSymbol): ts.Node; + + /** + * Check whether a `Declaration` corresponds with a known declaration and set its `known` property + * to the appropriate `KnownDeclaration`. + * + * @param decl The `Declaration` to check or `null` if there is no declaration. + * @return The passed in `Declaration` (potentially enhanced with a `KnownDeclaration`). + */ + detectKnownDeclaration<T extends Declaration>(decl: T|null): T|null; } From 6402a9ae2a7654210fcfeeb1bb458dd4a8290246 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Tue, 24 Mar 2020 10:20:28 -0700 Subject: [PATCH 103/262] build: rebuild yarn lock from scratch (#36377) Rebuild the yarn lock file from scratch to collapse instances where one package is able to satisfy multiple dependencies. Currently we have some situations where we have multiple versions when one would work. Example: ``` "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/cod integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij dependencies: "@babel/highlight" "^7.0.0" "@babel/code-frame@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/cod integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQ dependencies: "@babel/highlight" "^7.0.0" "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/cod integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0j dependencies: "@babel/highlight" "^7.8.3" ``` becomes ``` "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/cod integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0j dependencies: "@babel/highlight" "^7.8.3" ``` PR Close #36377 --- .circleci/config.yml | 12 +- integration/_payload-limits.json | 4 +- package.json | 4 +- .../test/ng_package/example_package.golden | 92 +- .../example_with_ts_library_package.golden | 23 +- yarn.lock | 4252 +++++++---------- 6 files changed, 1821 insertions(+), 2566 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3b564587e1f1d..d628e5dce489f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,18 +22,18 @@ version: 2.1 # **NOTE 1 **: If you change the cache key prefix, also sync the cache_key_fallback to match. # **NOTE 2 **: Keep the static part of the cache key as prefix to enable correct fallbacks. # See https://circleci.com/docs/2.0/caching/#restoring-cache for how prefixes work in CircleCI. -var_3: &cache_key v4-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} +var_3: &cache_key v6-angular-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} # We invalidate the cache if the Bazel version changes because otherwise the `bazelisk` cache # folder will contain all previously used versions and ultimately cause the cache restoring to # be slower due to its growing size. -var_4: &cache_key_fallback v4-angular-node-12-{{ checksum ".bazelversion" }} -var_3_win: &cache_key_win v5-angular-win-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} -var_4_win: &cache_key_win_fallback v5-angular-win-node-12-{{ checksum ".bazelversion" }} +var_4: &cache_key_fallback v6-angular-node-12-{{ checksum ".bazelversion" }} +var_3_win: &cache_key_win v6-angular-win-node-12-{{ checksum ".bazelversion" }}-{{ checksum "yarn.lock" }}-{{ checksum "WORKSPACE" }}-{{ checksum "packages/bazel/package.bzl" }}-{{ checksum "aio/yarn.lock" }} +var_4_win: &cache_key_win_fallback v6-angular-win-node-12-{{ checksum ".bazelversion" }} # Cache key for the `components-repo-unit-tests` job. **Note** when updating the SHA in the # cache keys also update the SHA for the "COMPONENTS_REPO_COMMIT" environment variable. -var_5: &components_repo_unit_tests_cache_key v5-angular-components-598db096e668aa7e9debd56eedfd127b7a55e371 -var_6: &components_repo_unit_tests_cache_key_fallback v5-angular-components- +var_5: &components_repo_unit_tests_cache_key v6-angular-components-598db096e668aa7e9debd56eedfd127b7a55e371 +var_6: &components_repo_unit_tests_cache_key_fallback v6-angular-components- # Workspace initially persisted by the `setup` job, and then enhanced by `build-npm-packages` and # `build-ivy-npm-packages`. diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 54704a01b4002..6d1421d89fcf1 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -39,7 +39,7 @@ "master": { "uncompressed": { "runtime-es2015": 2289, - "main-es2015": 247198, + "main-es2015": 247727, "polyfills-es2015": 36657, "5-es2015": 751 } @@ -49,7 +49,7 @@ "master": { "uncompressed": { "runtime-es2015": 2289, - "main-es2015": 226144, + "main-es2015": 226728, "polyfills-es2015": 36657, "5-es2015": 779 } diff --git a/package.json b/package.json index 820fe626f1b56..0d77e7f75ffe0 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "@bazel/rollup": "1.5.0", "@bazel/terser": "1.5.0", "@bazel/typescript": "1.5.0", - "@microsoft/api-extractor": "^7.3.9", + "@microsoft/api-extractor": "~7.6.0", "@schematics/angular": "9.0.3", "@types/angular": "^1.6.47", "@types/babel__core": "^7.1.6", @@ -115,7 +115,7 @@ "karma-jasmine": "^2.0.1", "karma-requirejs": "^1.1.0", "karma-sourcemap-loader": "^0.3.7", - "magic-string": "^0.25.0", + "magic-string": "0.25.4", "materialize-css": "1.0.0", "minimatch": "^3.0.4", "minimist": "1.2.0", diff --git a/packages/bazel/test/ng_package/example_package.golden b/packages/bazel/test/ng_package/example_package.golden index 68ea796744546..1896ba68be779 100644 --- a/packages/bazel/test/ng_package/example_package.golden +++ b/packages/bazel/test/ng_package/example_package.golden @@ -266,10 +266,11 @@ Hello } function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } @@ -307,14 +308,15 @@ Hello } function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); - return { + if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { @@ -395,6 +397,21 @@ Hello return (mod && mod.__esModule) ? mod : { default: mod }; } + function __classPrivateFieldGet(receiver, privateMap) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return privateMap.get(receiver); + } + + function __classPrivateFieldSet(receiver, privateMap, value) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to set private field on non-instance"); + } + privateMap.set(receiver, value); + return value; + } + /** * @license * Copyright Google Inc. All Rights Reserved. @@ -551,10 +568,11 @@ var o=function n(e,t,o,r){var f,c=arguments.length,l=c<3?t:null===r?r=Object.get } function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } @@ -592,14 +610,15 @@ var o=function n(e,t,o,r){var f,c=arguments.length,l=c<3?t:null===r?r=Object.get } function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); - return { + if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { @@ -680,6 +699,21 @@ var o=function n(e,t,o,r){var f,c=arguments.length,l=c<3?t:null===r?r=Object.get return (mod && mod.__esModule) ? mod : { default: mod }; } + function __classPrivateFieldGet(receiver, privateMap) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return privateMap.get(receiver); + } + + function __classPrivateFieldSet(receiver, privateMap, value) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to set private field on non-instance"); + } + privateMap.set(receiver, value); + return value; + } + var MySecondService = /** @class */ (function () { function MySecondService() { } @@ -836,10 +870,11 @@ e.MyService=c,e.ɵangular_packages_bazel_test_ng_package_example_imports_imports } function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } @@ -877,14 +912,15 @@ e.MyService=c,e.ɵangular_packages_bazel_test_ng_package_example_imports_imports } function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); - return { + if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { @@ -965,6 +1001,21 @@ e.MyService=c,e.ɵangular_packages_bazel_test_ng_package_example_imports_imports return (mod && mod.__esModule) ? mod : { default: mod }; } + function __classPrivateFieldGet(receiver, privateMap) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return privateMap.get(receiver); + } + + function __classPrivateFieldSet(receiver, privateMap, value) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to set private field on non-instance"); + } + privateMap.set(receiver, value); + return value; + } + /** * @license * Copyright Google Inc. All Rights Reserved. @@ -1124,10 +1175,11 @@ e.SecondaryModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); } function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } @@ -1165,14 +1217,15 @@ e.SecondaryModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); } function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); - return { + if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { @@ -1253,6 +1306,21 @@ e.SecondaryModule=o,e.a=1,Object.defineProperty(e,"__esModule",{value:!0})})); return (mod && mod.__esModule) ? mod : { default: mod }; } + function __classPrivateFieldGet(receiver, privateMap) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return privateMap.get(receiver); + } + + function __classPrivateFieldSet(receiver, privateMap, value) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to set private field on non-instance"); + } + privateMap.set(receiver, value); + return value; + } + /** * @license * Copyright Google Inc. All Rights Reserved. diff --git a/packages/bazel/test/ng_package/example_with_ts_library_package.golden b/packages/bazel/test/ng_package/example_with_ts_library_package.golden index 459aeb7f022d4..b48686126803c 100644 --- a/packages/bazel/test/ng_package/example_with_ts_library_package.golden +++ b/packages/bazel/test/ng_package/example_with_ts_library_package.golden @@ -159,10 +159,11 @@ License: MIT } function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } @@ -200,14 +201,15 @@ License: MIT } function __values(o) { - var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); - return { + if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { @@ -288,6 +290,21 @@ License: MIT return (mod && mod.__esModule) ? mod : { default: mod }; } + function __classPrivateFieldGet(receiver, privateMap) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to get private field on non-instance"); + } + return privateMap.get(receiver); + } + + function __classPrivateFieldSet(receiver, privateMap, value) { + if (!privateMap.has(receiver)) { + throw new TypeError("attempted to set private field on non-instance"); + } + privateMap.set(receiver, value); + return value; + } + /** * @license * Copyright Google Inc. All Rights Reserved. diff --git a/yarn.lock b/yarn.lock index 4f7cb92181697..085e917efcae1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -153,21 +153,7 @@ universal-analytics "^0.4.20" uuid "^3.3.2" -"@babel/code-frame@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" - integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/code-frame@^7.5.5": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== @@ -194,43 +180,23 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941" - integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA== +"@babel/core@^7.7.5", "@babel/core@^7.8.6": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" + integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" - "@babel/helpers" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/core@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.6.tgz#27d7df9258a45c2e686b6f18b6c659e563aa4636" - integrity sha512-Sheg7yEJD51YHAvLEV/7Uvw95AeWqYPL3Vk3zGujJKIhJ+8oLw2ALaf3hbucILhKsgSoADOvtKRJuNVdcJkOrg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.6" - "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.6" + "@babel/generator" "^7.9.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.0" + "@babel/parser" "^7.9.0" "@babel/template" "^7.8.6" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.1" - json5 "^2.1.0" + json5 "^2.1.2" lodash "^4.17.13" resolve "^1.3.2" semver "^5.4.1" @@ -246,32 +212,12 @@ lodash "^4.17.13" source-map "^0.5.0" -"@babel/generator@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" - integrity sha512-m5qo2WgdOJeyYngKImbkyQrnUN1mPceaG5BV+G0E3gWsa4l/jCSryWJdM2x8OuGAOyh+3d5pVYfZWCiNFtynxg== +"@babel/generator@^7.7.7", "@babel/generator@^7.8.6", "@babel/generator@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.4.tgz#12441e90c3b3c4159cdecf312075bf1a8ce2dbce" + integrity sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA== dependencies: - "@babel/types" "^7.7.4" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/generator@^7.7.7", "@babel/generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03" - integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug== - dependencies: - "@babel/types" "^7.8.3" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/generator@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.6.tgz#57adf96d370c9a63c241cd719f9111468578537a" - integrity sha512-4bpOR5ZBz+wWcMeVtcf7FbjcFzCp+817z2/gHNncIRcM9MmKzUhtWCYAq27RAfUrAFwb+OCG1s9WEaVxfi6cjg== - dependencies: - "@babel/types" "^7.8.6" + "@babel/types" "^7.9.0" jsesc "^2.5.1" lodash "^4.17.13" source-map "^0.5.0" @@ -291,22 +237,14 @@ "@babel/helper-explode-assignable-expression" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-call-delegate@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692" - integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A== - dependencies: - "@babel/helper-hoist-variables" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-create-regexp-features-plugin@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79" - integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q== +"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-regex" "^7.8.3" - regexpu-core "^4.6.0" + regexpu-core "^4.7.0" "@babel/helper-define-map@^7.8.3": version "7.8.3" @@ -325,15 +263,6 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-function-name@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.4.tgz#ab6e041e7135d436d8f0a3eca15de5b67a341a2e" - integrity sha512-AnkGIdiBhEuiwdoMnKm7jfPfqItZhgRaZfMg1XX3bS25INOnLPjPG1Ppnajh8eqgt5kPJnfqrRHqFqmjKDZLzQ== - dependencies: - "@babel/helper-get-function-arity" "^7.7.4" - "@babel/template" "^7.7.4" - "@babel/types" "^7.7.4" - "@babel/helper-function-name@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" @@ -343,13 +272,6 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-get-function-arity@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" - integrity sha512-QTGKEdCkjgzgfJ3bAyRwF4yyT3pg+vDgan8DSivq1eS0gwi+KGKE5x8kRcbeFTb/673mkO5SN1IZfmCfA5o+EA== - dependencies: - "@babel/types" "^7.7.4" - "@babel/helper-get-function-arity@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" @@ -371,30 +293,24 @@ dependencies: "@babel/types" "^7.8.3" -"@babel/helper-module-imports@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.4.tgz#e5a92529f8888bf319a6376abfbd1cebc491ad91" - integrity sha512-dGcrX6K9l8258WFjyDLJwuVKxR4XZfU0/vTUgOQYWEnRD8mgr+p4d6fCUMq/ys0h4CCt/S5JhbvtyErjWouAUQ== - dependencies: - "@babel/types" "^7.7.4" - -"@babel/helper-module-imports@^7.8.3": +"@babel/helper-module-imports@^7.7.4", "@babel/helper-module-imports@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== dependencies: "@babel/types" "^7.8.3" -"@babel/helper-module-transforms@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590" - integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q== +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== dependencies: "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-simple-access" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" lodash "^4.17.13" "@babel/helper-optimise-call-expression@^7.8.3": @@ -404,12 +320,7 @@ dependencies: "@babel/types" "^7.8.3" -"@babel/helper-plugin-utils@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" - integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA== - -"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== @@ -432,15 +343,15 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-replace-supers@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc" - integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA== +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== dependencies: "@babel/helper-member-expression-to-functions" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" "@babel/helper-simple-access@^7.8.3": version "7.8.3" @@ -450,13 +361,6 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helper-split-export-declaration@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.4.tgz#57292af60443c4a3622cf74040ddc28e68336fd8" - integrity sha512-guAg1SXFcVr04Guk9eq0S4/rWS++sbmyqosJzVs8+1fH5NI+ZcmkaSkc7dmtAFbHFva6yRJnjW3yAcGxjueDug== - dependencies: - "@babel/types" "^7.7.4" - "@babel/helper-split-export-declaration@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" @@ -464,6 +368,11 @@ dependencies: "@babel/types" "^7.8.3" +"@babel/helper-validator-identifier@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" + integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== + "@babel/helper-wrap-function@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" @@ -474,56 +383,28 @@ "@babel/traverse" "^7.8.3" "@babel/types" "^7.8.3" -"@babel/helpers@^7.7.4", "@babel/helpers@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85" - integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ== +"@babel/helpers@^7.7.4", "@babel/helpers@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" + integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== dependencies: "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helpers@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" - integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.4" - "@babel/types" "^7.8.3" - -"@babel/highlight@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" - integrity sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" "@babel/highlight@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" - integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" + integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== dependencies: + "@babel/helper-validator-identifier" "^7.9.0" chalk "^2.0.0" - esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.7.5", "@babel/parser@^7.7.7", "@babel/parser@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081" - integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ== - -"@babel/parser@^7.1.0", "@babel/parser@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.6.tgz#ba5c9910cddb77685a008e3c587af8d27b67962c" - integrity sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g== - -"@babel/parser@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.4.tgz#75ab2d7110c2cf2fa949959afb05fa346d2231bb" - integrity sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g== +"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.7.5", "@babel/parser@^7.7.7", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" + integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== "@babel/plugin-proposal-async-generator-functions@^7.7.4": version "7.8.3" @@ -551,9 +432,9 @@ "@babel/plugin-syntax-json-strings" "^7.8.0" "@babel/plugin-proposal-object-rest-spread@^7.7.7": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb" - integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" + integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== dependencies: "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" @@ -567,77 +448,42 @@ "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" "@babel/plugin-proposal-unicode-property-regex@^7.7.7": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.3.tgz#b646c3adea5f98800c9ab45105ac34d06cd4a47f" - integrity sha512-1/1/rEZv2XGweRwwSkLpY+s60za9OZ1hJs4YDqFHCw0kYWYwL5IFljVY1MYBL+weT1l9pokDO2uhSTLVxzoHkQ== + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-create-regexp-features-plugin" "^7.8.8" "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-async-generators@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.7.4.tgz#331aaf310a10c80c44a66b238b6e49132bd3c889" - integrity sha512-Li4+EjSpBgxcsmeEF8IFcfV/+yJGxHXDirDkEoyFjumuwbmfCVHUt0HuowD/iGM7OhIRyXJH9YXxqiH6N815+g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-async-generators@^7.8.0": +"@babel/plugin-syntax-async-generators@^7.7.4", "@babel/plugin-syntax-async-generators@^7.8.0": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-dynamic-import@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.7.4.tgz#29ca3b4415abfe4a5ec381e903862ad1a54c3aec" - integrity sha512-jHQW0vbRGvwQNgyVxwDh4yuXu4bH1f5/EICJLAhl1SblLs2CDhrsmCk+v5XLdE9wxtAFRyxx+P//Iw+a5L/tTg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": +"@babel/plugin-syntax-dynamic-import@^7.7.4", "@babel/plugin-syntax-dynamic-import@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-json-strings@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" - integrity sha512-QpGupahTQW1mHRXddMG5srgpHWqRLwJnJZKXTigB9RPFCCGbDGCgBeM/iC82ICXp414WeYx/tD54w7M2qRqTMg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-json-strings@^7.8.0": +"@babel/plugin-syntax-json-strings@^7.7.4", "@babel/plugin-syntax-json-strings@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-object-rest-spread@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.7.4.tgz#47cf220d19d6d0d7b154304701f468fc1cc6ff46" - integrity sha512-mObR+r+KZq0XhRVS2BrBKBpr5jqrqzlPvS9C9vuOf5ilSwzloAl7RPWLrgKdWS6IreaVrjHxTjtyqFiOisaCwg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-object-rest-spread@^7.8.0": +"@babel/plugin-syntax-object-rest-spread@^7.7.4", "@babel/plugin-syntax-object-rest-spread@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.7.4.tgz#a3e38f59f4b6233867b4a92dcb0ee05b2c334aa6" - integrity sha512-4ZSuzWgFxqHRE31Glu+fEr/MirNZOMYmD/0BhBWyLyOOQz/gTAl7QmWm2hX1QxEIXsr2vkdlwxIzTyiYRC4xcQ== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.0": +"@babel/plugin-syntax-optional-catch-binding@^7.7.4", "@babel/plugin-syntax-optional-catch-binding@^7.8.0": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== @@ -683,16 +529,16 @@ lodash "^4.17.13" "@babel/plugin-transform-classes@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8" - integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w== + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" + integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== dependencies: "@babel/helper-annotate-as-pure" "^7.8.3" "@babel/helper-define-map" "^7.8.3" "@babel/helper-function-name" "^7.8.3" "@babel/helper-optimise-call-expression" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" @@ -704,9 +550,9 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-destructuring@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b" - integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ== + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" + integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -734,9 +580,9 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-for-of@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz#15f17bce2fc95c7d59a24b299e83e81cedc22e18" - integrity sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" + integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -763,40 +609,40 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-modules-amd@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5" - integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" + integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== dependencies: - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" "@babel/plugin-transform-modules-commonjs@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.8.3.tgz#df251706ec331bd058a34bdd72613915f82928a5" - integrity sha512-JpdMEfA15HZ/1gNuB9XEDlZM1h/gF/YOH7zaZzQu2xCFRfwc01NXBMHHSTT6hRjlXJJs5x/bfODM3LiCk94Sxg== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" + integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== dependencies: - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-simple-access" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" "@babel/plugin-transform-modules-systemjs@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.8.3.tgz#d8bbf222c1dbe3661f440f2f00c16e9bb7d0d420" - integrity sha512-8cESMCJjmArMYqa9AO5YuMEkE4ds28tMpZcGZB/jl3n0ZzlsxOAi3mC+SKypTfT8gjMupCnd3YiXCkMjj2jfOg== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" + integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== dependencies: "@babel/helper-hoist-variables" "^7.8.3" - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" babel-plugin-dynamic-import-node "^2.3.0" "@babel/plugin-transform-modules-umd@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.8.3.tgz#592d578ce06c52f5b98b02f913d653ffe972661a" - integrity sha512-evhTyWhbwbI3/U6dZAnx/ePoV7H6OUG+OjiJFHmhr9FPn0VShjwC2kdxqIuQ/+1P50TMrneGzMeyMTFOjKSnAw== + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" + integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== dependencies: - "@babel/helper-module-transforms" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-named-capturing-groups-regex@^7.7.4": @@ -822,11 +668,10 @@ "@babel/helper-replace-supers" "^7.8.3" "@babel/plugin-transform-parameters@^7.7.7": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz#7890576a13b17325d8b7d44cb37f21dc3bbdda59" - integrity sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q== + version "7.9.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a" + integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg== dependencies: - "@babel/helper-call-delegate" "^7.8.3" "@babel/helper-get-function-arity" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" @@ -838,11 +683,11 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-regenerator@^7.7.5": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8" - integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA== + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== dependencies: - regenerator-transform "^0.14.0" + regenerator-transform "^0.14.2" "@babel/plugin-transform-reserved-words@^7.7.4": version "7.8.3" @@ -882,9 +727,9 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-transform-typeof-symbol@^7.7.4": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz#5cffb216fb25c8c64ba6bf5f76ce49d3ab079f4d" - integrity sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g== + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== dependencies: "@babel/helper-plugin-utils" "^7.8.3" @@ -953,32 +798,14 @@ js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/runtime@^7.6.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.8.3.tgz#0811944f73a6c926bb2ad35e918dcc1bfab279f1" - integrity sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w== - dependencies: - regenerator-runtime "^0.13.2" - -"@babel/template@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" - integrity sha512-qUzihgVPguAzXCK7WXw8pqs6cEwi54s3E+HrejlkuWO6ivMKx9hZl3Y2fSXp9i5HgyWmj7RKP+ulaYnKM4yYxw== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/parser" "^7.7.4" - "@babel/types" "^7.7.4" - -"@babel/template@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" - integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== +"@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/types" "^7.8.3" + regenerator-runtime "^0.13.4" -"@babel/template@^7.8.6": +"@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== @@ -987,57 +814,27 @@ "@babel/parser" "^7.8.6" "@babel/types" "^7.8.6" -"@babel/traverse@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" - integrity sha512-P1L58hQyupn8+ezVA2z5KBm4/Zr4lCC8dwKCMYzsa5jFMDMQAzaBNy9W5VjB+KAmBjb40U7a/H6ao+Xo+9saIw== - dependencies: - "@babel/code-frame" "^7.5.5" - "@babel/generator" "^7.7.4" - "@babel/helper-function-name" "^7.7.4" - "@babel/helper-split-export-declaration" "^7.7.4" - "@babel/parser" "^7.7.4" - "@babel/types" "^7.7.4" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/traverse@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a" - integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.3" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.3" - "@babel/types" "^7.8.3" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" - integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== +"@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" + integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== dependencies: "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.6" + "@babel/generator" "^7.9.0" "@babel/helper-function-name" "^7.8.3" "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" + "@babel/parser" "^7.9.0" + "@babel/types" "^7.9.0" debug "^4.1.0" globals "^11.1.0" lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.7.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.6.tgz#629ecc33c2557fcde7126e58053127afdb3e6d01" - integrity sha512-wqz7pgWMIrht3gquyEFPVXeXCti72Rm8ep9b5tQKz9Yg9LzJA3HxosF1SB3Kc81KD1A3XBkkVYtJvCKS2Z/QrA== +"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.7.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" + integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== dependencies: - esutils "^2.0.2" + "@babel/helper-validator-identifier" "^7.9.0" lodash "^4.17.13" to-fast-properties "^2.0.0" @@ -1141,38 +938,44 @@ integrity sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ== "@google-cloud/pubsub@^1.1.5": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@google-cloud/pubsub/-/pubsub-1.2.0.tgz#00b26c347b6e777b91fce72f771d7b9f8427e1d4" - integrity sha512-dImRlbWrDSngkhZNBCtqFn5fbuCwd315x2dU3x+u3+aKwNGw7QbX1z7v+q1K+giNfYJN3/uI0+DsZUYtiyAMHw== + version "1.7.0" + resolved "https://registry.yarnpkg.com/@google-cloud/pubsub/-/pubsub-1.7.0.tgz#7506a9aeb0fd2f1f530e9750fd548fcca35b906b" + integrity sha512-CJgyfZ+ZFIwD90LRGh42AU65rZO/8tBg6HVapD9DSFSJxP8O6k0eQMEpLD6S5RAkoo8hWiBRyD0K66PqwP5UpA== dependencies: "@google-cloud/paginator" "^2.0.0" "@google-cloud/precise-date" "^1.0.0" "@google-cloud/projectify" "^1.0.0" "@google-cloud/promisify" "^1.0.0" - "@sindresorhus/is" "^1.0.0" "@types/duplexify" "^3.6.0" "@types/long" "^4.0.0" arrify "^2.0.0" async-each "^1.0.1" extend "^3.0.2" google-auth-library "^5.5.0" - google-gax "^1.7.5" + google-gax "^1.14.2" is-stream-ended "^0.1.4" lodash.snakecase "^4.1.1" p-defer "^3.0.0" protobufjs "^6.8.1" "@grpc/grpc-js@^0.6.12": - version "0.6.15" - resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-0.6.15.tgz#534d1051ddced4e5e5849212789dd64014214dd4" - integrity sha512-BFK5YMu8JILedibo0nr3NYM0ZC5hCZuXtzk10wEUp3d3pH11PjdvTfN1yEJ0VsfBY5Gtp3WOQ+t7Byq0NzH/iQ== + version "0.6.18" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-0.6.18.tgz#ba3b3dfef869533161d192a385412a4abd0db127" + integrity sha512-uAzv/tM8qpbf1vpx1xPMfcUMzbfdqJtdCYAqY/LsLeQQlnTb4vApylojr+wlCyr7bZeg3AFfHvtihnNOQQt/nA== + dependencies: + semver "^6.2.0" + +"@grpc/grpc-js@^0.7.4": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-0.7.5.tgz#17bc4565fa753e737b3e172aa93b93b865c69c96" + integrity sha512-hhWT+vHPtG4tn0zZJw4ndfv730pBPb+lhJfvQhc7ANBvqixtlNOaXm9VNI98wYF/em0PnrskXnOr8rHh96zjlg== dependencies: semver "^6.2.0" "@grpc/proto-loader@^0.5.1": - version "0.5.3" - resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.3.tgz#a233070720bf7560c4d70e29e7950c72549a132c" - integrity sha512-8qvUtGg77G2ZT2HqdqYoM/OY97gQd/0crSG34xNmZ4ZOsv3aQT/FQV9QfZPazTGna6MIoyUd+u6AxsoZjJ/VMQ== + version "0.5.4" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.4.tgz#038a3820540f621eeb1b05d81fbedfb045e14de0" + integrity sha512-HTM4QpI9B2XFkPz7pjwMyMgZchJ93TVkL3kWPW8GDMDKYxsMnmf4w2TNMJK7+KNiYHS5cJrCEAFlF+AwtXWVPA== dependencies: lodash.camelcase "^4.3.0" protobufjs "^6.8.6" @@ -1182,58 +985,55 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@microsoft/api-extractor-model@7.3.2": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.3.2.tgz#71229ba80f8aafc56afe4d3ee83f19b1ce72eb24" - integrity sha512-2yNbQsQl5PI36l5WzHQshwjBHPe5IeIcmidWad0E+wjyaAxGMLx5pBp5AgXY2JG9S9VQjFmmGmqJJBXn8tzu+w== +"@microsoft/api-extractor-model@7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.6.0.tgz#0cac9ae4fc94f168166e9383f18b39b6aa0826f8" + integrity sha512-7gtxCxUMLDv3k1NE7MCaUaQeAwH5dEt/vjnq22cOUiCfiYOxdrvolab+WIXSNKV6rhe+AnIovR9tkxtxw5OiYA== dependencies: - "@microsoft/node-core-library" "3.14.0" - "@microsoft/tsdoc" "0.12.12" - "@types/node" "8.5.8" + "@microsoft/node-core-library" "3.18.0" + "@microsoft/tsdoc" "0.12.14" -"@microsoft/api-extractor@^7.3.9": - version "7.3.9" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.3.9.tgz#c035748e9e8745eb9df43351f76ace1f529d17dc" - integrity sha512-8qj+N/3CgJaHFZj/YlXqtyPAK8vQ2e4oFzKrzbQNw5mtlVnyLlayTkNfVIq93Q0xRMwAhPJjlmxmAuu1ZI88oQ== +"@microsoft/api-extractor@~7.6.0": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.6.2.tgz#e633b4d4bccf76ca624e1d2118d48f5a7defb93c" + integrity sha512-4nK2uAWwC1nfzpEbyCwPfe/39aHkoWIhsodj8yrWTxMpH0eI7Ik/SdHtn3bDKVHIK67EnaR5//fnevpj9ACByw== dependencies: - "@microsoft/api-extractor-model" "7.3.2" - "@microsoft/node-core-library" "3.14.0" - "@microsoft/ts-command-line" "4.2.7" - "@microsoft/tsdoc" "0.12.12" + "@microsoft/api-extractor-model" "7.6.0" + "@microsoft/node-core-library" "3.18.0" + "@microsoft/ts-command-line" "4.3.5" + "@microsoft/tsdoc" "0.12.14" colors "~1.2.1" lodash "~4.17.15" resolve "1.8.1" source-map "~0.6.1" - typescript "~3.5.3" + typescript "~3.7.2" -"@microsoft/node-core-library@3.14.0": - version "3.14.0" - resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.14.0.tgz#c7014328c67c4a4110e2ed2a9bd11cfd0ad3318d" - integrity sha512-+gbTXTRfvR40hTH+C3Vno/RJ51sU/RZAyHb2bo9af8GCdOgxCxCs+qp2KCXklbpuolmIPFfbCmdTwv90yH5tJw== +"@microsoft/node-core-library@3.18.0": + version "3.18.0" + resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.18.0.tgz#9a9123354b3e067bb8a975ba791959ffee1322ed" + integrity sha512-VzzSHtcwgHVW1xbHqpngfn+OS1trAZ1Tw3XXBlMsEKe7Wz7FF2gLr0hZa6x9Pemk5pkd4tu4+GTSOJjCKGjrgg== dependencies: - "@types/fs-extra" "5.0.4" - "@types/jju" "~1.4.0" - "@types/node" "8.5.8" - "@types/z-schema" "3.16.31" + "@types/node" "8.10.54" colors "~1.2.1" fs-extra "~7.0.1" jju "~1.4.0" + semver "~5.3.0" + timsort "~0.3.0" z-schema "~3.18.3" -"@microsoft/ts-command-line@4.2.7": - version "4.2.7" - resolved "https://registry.yarnpkg.com/@microsoft/ts-command-line/-/ts-command-line-4.2.7.tgz#01e963c683ae782e57225c5c424aa65702a9732c" - integrity sha512-PwUMIIDl8oWyl64Y5DW5FAuoRk4KWTBZdk4FEh366KEm5xYFBQhCeatHGURIj8nEYm0Xb2coCrXF77dGDlp/Qw== +"@microsoft/ts-command-line@4.3.5": + version "4.3.5" + resolved "https://registry.yarnpkg.com/@microsoft/ts-command-line/-/ts-command-line-4.3.5.tgz#78026d20244f39978d3397849ac8c40c0c2d4079" + integrity sha512-CN3j86apNOmllUmeJ0AyRfTYA2BP2xlnfgmnyp1HWLqcJmR/zLe/fk/+gohGnNt7o5/qHta3681LQhO2Yy3GFw== dependencies: "@types/argparse" "1.0.33" - "@types/node" "8.5.8" argparse "~1.0.9" colors "~1.2.1" -"@microsoft/tsdoc@0.12.12": - version "0.12.12" - resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.12.tgz#6692f1cbca664f68abbc62f9a26459fba8b9ff28" - integrity sha512-5EzH1gHIonvvgA/xWRmVAJmRkTQj/yayUXyr66hFwNZiFE4j7lP8is9YQeXhwxGZEjO1PVMblAmFF0CyjNtPGw== +"@microsoft/tsdoc@0.12.14": + version "0.12.14" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.14.tgz#0e0810a0a174e50e22dfe8edb30599840712f22d" + integrity sha512-518yewjSga1jLdiLrcmpMFlaba5P+50b0TWNFUpC+SL9Yzf0kMi57qw+bMl+rQ08cGqH1vLx4eg9YFUbZXgZ0Q== "@ngtools/webpack@9.0.3": version "9.0.3" @@ -1245,10 +1045,10 @@ rxjs "6.5.3" webpack-sources "1.4.3" -"@octokit/endpoint@^5.5.0": - version "5.5.3" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.5.3.tgz#0397d1baaca687a4c8454ba424a627699d97c978" - integrity sha512-EzKwkwcxeegYYah5ukEeAI/gYRLv2Y9U5PpIsseGSFDk+G3RbipQGBs8GuYS1TLCtQaqoO66+aQGtITPalxsNQ== +"@octokit/endpoint@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.0.tgz#4c7acd79ab72df78732a7d63b09be53ec5a2230b" + integrity sha512-3nx+MEYoZeD0uJ+7F/gvELLvQJzLXhep2Az0bBSXagbApDvDW0LWwpnAIY/hb0Jwe17A0fJdz0O12dPh05cj7A== dependencies: "@octokit/types" "^2.0.0" is-plain-object "^3.0.0" @@ -1263,22 +1063,22 @@ "@octokit/types" "^2.0.0" universal-user-agent "^4.0.0" -"@octokit/request-error@^1.0.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" - integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA== +"@octokit/request-error@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.0.tgz#94ca7293373654400fbb2995f377f9473e00834b" + integrity sha512-rtYicB4Absc60rUv74Rjpzek84UbVHGHJRu4fNVlZ1mCcyUPPuzFfG9Rn6sjHrd95DEsmjSt1Axlc699ZlbDkw== dependencies: "@octokit/types" "^2.0.0" deprecation "^2.0.0" once "^1.4.0" "@octokit/request@^5.3.0": - version "5.3.2" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.2.tgz#1ca8b90a407772a1ee1ab758e7e0aced213b9883" - integrity sha512-7NPJpg19wVQy1cs2xqXjjRq/RmtSomja/VSWnptfYwuBxLdbYh2UjhGi0Wx7B1v5Iw5GKhfFDQL7jM7SSp7K2g== + version "5.3.4" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.4.tgz#fbc950bf785d59da3b0399fc6d042c8cf52e2905" + integrity sha512-qyj8G8BxQyXjt9Xu6NvfvOr1E0l35lsXtwm3SopsYg/JWXjlsnwqLc8rsD2OLguEL/JjLfBvrXr4az7z8Lch2A== dependencies: - "@octokit/endpoint" "^5.5.0" - "@octokit/request-error" "^1.0.1" + "@octokit/endpoint" "^6.0.0" + "@octokit/request-error" "^2.0.0" "@octokit/types" "^2.0.0" deprecation "^2.0.0" is-plain-object "^3.0.0" @@ -1287,9 +1087,9 @@ universal-user-agent "^5.0.0" "@octokit/types@^2.0.0": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.3.1.tgz#40cd61c125a6161cfb3bfabc75805ac7a54213b4" - integrity sha512-rvJP1Y9A/+Cky2C3var1vsw3Lf5Rjn/0sojNl2AjCX+WbpIHYccaJ46abrZoIxMYnOToul6S9tPytUVkFI7CXQ== + version "2.5.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.5.1.tgz#22563b3bb50034bea3176eac1860340c5e812e2a" + integrity sha512-q4Wr7RexkPRrkQpXzUYF5Fj/14Mr65RyOHj6B9d/sQACpqGcStkHZj4qMEtlMY5SnD/69jlL9ItGPbDM0dR/dA== dependencies: "@types/node" ">= 8" @@ -1369,15 +1169,10 @@ semver "6.3.0" semver-intersect "1.4.0" -"@sindresorhus/is@^1.0.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-1.2.0.tgz#63ce3638cb85231f3704164c90a18ef816da3fb7" - integrity sha512-mwhXGkRV5dlvQc4EgPDxDxO6WuMBVymGFd1CA+2Y+z5dG9MNspoQ+AWjl/Ld1MnpCL8AKbosZlDVohqcIwuWsw== - "@types/angular@^1.6.47": - version "1.6.48" - resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.6.48.tgz#e8f77bf41d00d3293421cbaaed2bafb4d5f399f9" - integrity sha512-zF0WlsWOjTkZjWq93ESfvq/4s3E9P8EnbIjOFzlDbhepL2iOBk9SJf98eqnV2fvjstwrPF+uYZvcAggL7Xw1FA== + version "1.7.0" + resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.7.0.tgz#3dd8d3b2d3b7ce2cca51b9fc3691b48b638eb468" + integrity sha512-zneUmi5I6oSkGBqkRP9rxbWX1mi6Yj7gNV+WNffmJLf8x4cnV0MGqXFNSP90NZ1kRRLCOdKBf9RIVD1TMg4aog== "@types/argparse@1.0.33": version "1.0.33" @@ -1385,9 +1180,9 @@ integrity sha512-VQgHxyPMTj3hIlq9SY1mctqx+Jj8kpQfoLvDlVSDNOyuYs8JYfkuY3OW/4+dO657yPmNhHpePRx0/Tje5ImNVQ== "@types/babel__core@^7.1.6": - version "7.1.6" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.6.tgz#16ff42a5ae203c9af1c6e190ed1f30f83207b610" - integrity sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg== + version "7.1.7" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" + integrity sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -1423,14 +1218,14 @@ integrity sha1-WCskdhaabLpGCiFNR2x0REHYc9U= "@types/bluebird@^3.5.27": - version "3.5.27" - resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.27.tgz#61eb4d75dc6bfbce51cf49ee9bbebe941b2cb5d0" - integrity sha512-6BmYWSBea18+tSjjSC3QIyV93ZKAeNWGM7R6aYt1ryTZXrlHF+QLV0G2yV0viEGVyRkyQsWfMoJ0k/YghBX5sQ== + version "3.5.30" + resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.30.tgz#ee034a0eeea8b84ed868b1aa60d690b08a6cfbc5" + integrity sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw== "@types/chai@^4.1.2": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.7.tgz#1b8e33b61a8c09cbe1f85133071baa0dbf9fa71a" - integrity sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA== + version "4.2.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" + integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== "@types/color-name@^1.1.1": version "1.1.1" @@ -1454,15 +1249,20 @@ dependencies: "@types/node" "*" -"@types/estree@*", "@types/estree@0.0.39": +"@types/estree@*": + version "0.0.44" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.44.tgz#980cc5a29a3ef3bea6ff1f7d021047d7ea575e21" + integrity sha512-iaIVzr+w2ZJ5HkidlZ3EJM8VTZb2MJLCjw3V+505yVts0gRC4UMvjw0d1HPtGqI/HQC/KdsYtayfzl+AXY2R8g== + +"@types/estree@0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== "@types/events@*": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" - integrity sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA== + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== "@types/fs-extra@4.0.2": version "4.0.2" @@ -1471,30 +1271,14 @@ dependencies: "@types/node" "*" -"@types/fs-extra@5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.4.tgz#b971134d162cc0497d221adde3dbb67502225599" - integrity sha512-DsknoBvD8s+RFfSGjmERJ7ZOP1HI0UZRA3FSI+Zakhrc/Gy26YQsLI+m5V5DHxroHRJqCDLKJp7Hixn8zyaF7g== - dependencies: - "@types/node" "*" - "@types/fs-extra@^8.0.1": - version "8.0.1" - resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686" - integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw== - dependencies: - "@types/node" "*" - -"@types/glob@*": - version "5.0.35" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.35.tgz#1ae151c802cece940443b5ac246925c85189f32a" - integrity sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg== + version "8.1.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.0.tgz#1114834b53c3914806cd03b3304b37b3bd221a4d" + integrity sha512-UoOfVEzAUpeSPmjm7h1uk5MH6KZma2z2O7a75onTGjnNvAvMVrPzPL/vBbT65iIGHWj6rokwfmYcmxmlSf2uwg== dependencies: - "@types/events" "*" - "@types/minimatch" "*" "@types/node" "*" -"@types/glob@^7.1.1": +"@types/glob@*", "@types/glob@^7.1.1": version "7.1.1" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== @@ -1517,36 +1301,31 @@ "@types/through" "*" "@types/jasmine@*": - version "3.3.5" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.3.5.tgz#3738ffbf34dffae9ecaac4503d7d969744f0e1d7" - integrity sha512-LJtc52O1PNUffMvH6Q3fS0BOhQWYlkh3SVu/Jc4GoPgJkUytk5Y6YPbw+6lZK2mWWvG62BtVyOFw0ih7r8STsw== + version "3.5.10" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.10.tgz#a1a41012012b5da9d4b205ba9eba58f6cce2ab7b" + integrity sha512-3F8qpwBAiVc5+HPJeXJpbrl+XjawGmciN5LgiO7Gv1pl1RHtjoMNqZpqEksaPJW05ViKe8snYInRs6xB25Xdew== "@types/jasmine@^2.8.8": - version "2.8.8" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.8.tgz#bf53a7d193ea8b03867a38bfdb4fbb0e0bf066c9" - integrity sha512-OJSUxLaxXsjjhob2DBzqzgrkLmukM3+JMpRp0r0E4HTdT1nwDCWhaswjYxazPij6uOdzHCJfNbDjmQ1/rnNbCg== + version "2.8.16" + resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.16.tgz#a6cb24b1149d65293bd616923500014838e14e7d" + integrity sha512-056oRlBBp7MDzr+HoU5su099s/s7wjZ3KcHxLfv+Byqb9MwdLUvsfLgw1VS97hsh3ddxSPyQu+olHMnoVTUY6g== "@types/jasminewd2@^2.0.6": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.6.tgz#2f57a8d9875a6c9ef328a14bd070ba14a055ac39" - integrity sha512-2ZOKrxb8bKRmP/po5ObYnRDgFE4i+lQiEB27bAMmtMWLgJSqlIDqlLx6S0IRorpOmOPRQ6O80NujTmQAtBkeNw== + version "2.0.8" + resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.8.tgz#67afe5098d5ef2386073a7b7384b69a840dfe93b" + integrity sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg== dependencies: "@types/jasmine" "*" -"@types/jju@~1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@types/jju/-/jju-1.4.0.tgz#ee074af79540c0e187426f46f12acbe8f6c31232" - integrity sha512-s6l49zLzFiXYHaTXbA+FNcDRo8ufZgC2/T5/jH+Wfr+ZV2tYbrBpEpN9oPkXXfug+y7pTZFkdeyQ0L/88Z34JA== - "@types/json5@^0.0.30": version "0.0.30" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.30.tgz#44cb52f32a809734ca562e685c6473b5754a7818" integrity sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA== "@types/long@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" - integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q== + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" + integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== "@types/mime-types@^2.1.0": version "2.1.0" @@ -1563,35 +1342,30 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= -"@types/node@*": - version "10.5.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.2.tgz#f19f05314d5421fe37e74153254201a7bf00a707" - integrity sha512-m9zXmifkZsMHZBOyxZWilMwmTlpC8x5Ty360JKTiXvlXZfBWYpsg9ZZvP/Ye+iZUh+Q+MxDLjItVTWIsfwz+8Q== - -"@types/node@8.5.8": - version "8.5.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.8.tgz#92509422653f10e9c0ac18d87e0610b39f9821c7" - integrity sha512-8KmlRxwbKZfjUHFIt3q8TF5S2B+/E5BaAoo/3mgc5h6FJzqxXkCK/VMetO+IRDtwtU6HUvovHMBn+XRj7SV9Qg== +"@types/node@*", "@types/node@>= 8": + version "13.11.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b" + integrity sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ== -"@types/node@>= 8": - version "13.7.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.7.tgz#1628e6461ba8cc9b53196dfeaeec7b07fa6eea99" - integrity sha512-Uo4chgKbnPNlxQwoFmYIwctkQVkMMmsAoGGU4JKwLuvBefF0pCq4FybNSnfkfRCpC7ZW7kttcC/TrRtAJsvGtg== +"@types/node@8.10.54": + version "8.10.54" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.54.tgz#1c88eb253ac1210f1a5876953fb70f7cc4928402" + integrity sha512-kaYyLYf6ICn6/isAyD4K1MyWWd5Q3JgH6bnMN089LUx88+s4W8GvK9Q6JMBVu5vsFFp7pMdSxdKmlBXwH/VFRg== "@types/node@^10.1.0": - version "10.14.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.4.tgz#1c586b991457cbb58fef51bc4e0cfcfa347714b5" - integrity sha512-DT25xX/YgyPKiHFOpNuANIQIVvYEwCWXgK2jYYwqgaMrYE6+tq+DtmMwlD3drl6DJbUwtlIDnn0d7tIn/EbXBg== + version "10.17.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.18.tgz#ae364d97382aacdebf583fa4e7132af2dfe56a0c" + integrity sha512-DQ2hl/Jl3g33KuAUOcMrcAOtsbzb+y/ufakzAdeK9z/H/xsvkpbETZZbPNMIiQuk24f5ZRMCcZIViAwyFIiKmg== "@types/node@^11.13.9": - version "11.13.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-11.13.10.tgz#4df59e5966b56f512bac98898bcbee5067411f0f" - integrity sha512-leUNzbFTMX94TWaIKz8N15Chu55F9QSH+INKayQr5xpkasBQBRF3qQXfo3/dOnMU/dEIit+Y/SU8HyOjq++GwA== + version "11.15.9" + resolved "https://registry.yarnpkg.com/@types/node/-/node-11.15.9.tgz#656b2f61ebe6af278769dfc24e6ab00528a373eb" + integrity sha512-NcOiyA/gxMAounNa4IPm/e13kYqU48onEarMnbLzz3ynEdlxFKYFoBbMBSefAHJR77r9MCtD88J0Z2TVtNsBbw== "@types/node@^12.11.1": - version "12.11.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.11.1.tgz#1fd7b821f798b7fa29f667a1be8f3442bb8922a3" - integrity sha512-TJtwsqZ39pqcljJpajeoofYRfeZ7/I/OMUQ5pR4q5wOKf2ocrUvBAZUMhWsOvKx3dVc/aaV5GluBivt0sWqA5A== + version "12.12.34" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.34.tgz#0a5d6ae5d22612f0cf5f10320e1fc5d2a745dcb8" + integrity sha512-BneGN0J9ke24lBRn44hVHNeDlrXRYF+VRp0HbSUNnEZahXGAysHZIqnf/hER6aabdBgzM4YOV4jrR8gj4Zfi0g== "@types/q@^0.0.32": version "0.0.32" @@ -1717,19 +1491,19 @@ integrity sha512-tHdDdGUBKTbiLLwf5mF78EP35F31UZekG+GRNowl8G5rMQoupAT4qWn/7AaGOvmaqvROdqC3Io/hP1ZyO58QkA== "@types/selenium-webdriver@^3.0.0": - version "3.0.16" - resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.16.tgz#50a4755f8e33edacd9c406729e9b930d2451902a" - integrity sha512-lMC2G0ItF2xv4UCiwbJGbnJlIuUixHrioOhNGHSCsYCJ8l4t9hMCUimCytvFv7qy6AfSzRxhRHoGa+UqaqwyeA== + version "3.0.17" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.17.tgz#50bea0c3c2acc31c959c5b1e747798b3b3d06d4b" + integrity sha512-tGomyEuzSC1H28y2zlW6XPCaDaXFaD6soTdb4GNdmte2qfHtrKqhy0ZFs4r/1hpazCfEZqeTSRLvSasmEx89uw== "@types/semver@^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.2.tgz#5e8b09f0e4af53034b1d0fb9977a277847836205" - integrity sha512-G1Ggy7/9Nsa1Jt2yiBR2riEuyK2DFNnqow6R7cromXPMNynackRY1vqFTLz/gwnef1LHokbXThcPhqMRjUbkpQ== + version "6.2.1" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.2.1.tgz#a236185670a7860f1597cf73bea2e16d001461ba" + integrity sha512-+beqKQOh9PYxuHvijhVl+tIHvT6tuwOrE9m14zd+MT2A38KoKZhh7pYJ0SNleLtwDsiIxHDsIk9bv01oOxvSvA== "@types/shelljs@^0.8.6": - version "0.8.6" - resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.6.tgz#45193a51df99e0f00513c39a2152832399783221" - integrity sha512-svx2eQS268awlppL/P8wgDLBrsDXdKznABHJcuqXyWpSKJgE1s2clXlBvAwbO/lehTmG06NtEWJRkAk4tAgenA== + version "0.8.7" + resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.7.tgz#a2a606b185165abadf8b7995fea5e326e637088e" + integrity sha512-Mg2qGjLIJIieeJ1/NjswAOY9qXDShLeh6JwpD1NZsvUvI0hxdUCNDpnBXv9YQeugKi2EHU+BqkbUE4jpY4GKmQ== dependencies: "@types/glob" "*" "@types/node" "*" @@ -1745,16 +1519,16 @@ integrity sha1-6SBMTNvI4nXWRcAOYVDmj8VhWiQ= "@types/through@*": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.29.tgz#72943aac922e179339c651fa34a4428a4d722f93" - integrity sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w== + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895" + integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg== dependencies: "@types/node" "*" "@types/webpack-sources@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" - integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + version "0.1.7" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.7.tgz#0a330a9456113410c74a5d64180af0cbca007141" + integrity sha512-XyaHrJILjK1VHVC4aVlKsdNN5KBTwufMb43cQs+flGxtPAf/1Qwl8+Q0tp5BwEGaI8D6XT1L+9bSWXckgkjTLw== dependencies: "@types/node" "*" "@types/source-list-map" "*" @@ -1770,15 +1544,10 @@ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-11.1.5.tgz#8d71dfe4848ac5d714b75eca3df9cac75a4f8dac" integrity sha512-1jmXgoIyzxQSm33lYgEXvegtkhloHbed2I0QGlTN66U2F9/ExqJWSCSmaWC0IB/g1tW+IYSp+tDhcZBYB1ZGog== -"@types/z-schema@3.16.31": - version "3.16.31" - resolved "https://registry.yarnpkg.com/@types/z-schema/-/z-schema-3.16.31.tgz#2eb1d00a5e4ec3fa58c76afde12e182b66dc5c1c" - integrity sha1-LrHQCl5Ow/pYx2r94S4YK2bcXBw= - "@typescript-eslint/typescript-estree@^2.4.0": - version "2.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.16.0.tgz#b444943a76c716ed32abd08cbe96172d2ca0ab75" - integrity sha512-hyrCYjFHISos68Bk5KjUAXw0pP/455qq9nxqB1KkT67Pxjcfw+r6Yhcmqnp8etFL45UexCHUMrADHH7dI/m2WQ== + version "2.26.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.26.0.tgz#d8132cf1ee8a72234f996519a47d8a9118b57d56" + integrity sha512-3x4SyZCLB4zsKsjuhxDLeVJN6W29VwBnYpCsZ7vIdPel9ZqLfIZJgJXO47MNUkurGpQuIBALdPQKtsSnWpE1Yg== dependencies: debug "^4.1.1" eslint-visitor-keys "^1.1.0" @@ -1935,9 +1704,9 @@ "@xtuc/long" "4.2.2" "@webcomponents/custom-elements@^1.1.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@webcomponents/custom-elements/-/custom-elements-1.4.0.tgz#f21f41804e1f708d1bc924c345413f8a0e9b51a3" - integrity sha512-t9xpI4KVH4IcVp9XqLIAxHOovNcaUDDcfjK3v7ORv7xjnbIL1Dc+735tUTgyJvugTPAaxunILJY+Rh6+5729Hw== + version "1.4.1" + resolved "https://registry.yarnpkg.com/@webcomponents/custom-elements/-/custom-elements-1.4.1.tgz#9803aaa2286a13a4ba200a7a2ea767871598eb60" + integrity sha512-vNCS1+3sxJOpoIsBjUQiXjGLngakEAGOD5Ale+6ikg6OZG5qI5O39frm3raPhud/IwnF4vec5ags05YBsgzcuA== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -1954,15 +1723,7 @@ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -JSONStream@^1.0.4: - version "1.3.3" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.3.tgz#27b4b8fbbfeab4e71bcf551e7f27be8d952239bf" - integrity sha512-3Sp6WZZ/lXl+nTDoGpGWHEpTnnC6X5fnkolYZR6nwIfzbxxvA8utPWe1gCt7i0m9uVGsSz2IS8K8mJ7HmlduMg== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -JSONStream@^1.2.1, JSONStream@^1.3.4: +JSONStream@^1.0.4, JSONStream@^1.2.1, JSONStream@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -1982,15 +1743,7 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" -accepts@~1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" - integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= - dependencies: - mime-types "~2.1.18" - negotiator "0.6.1" - -accepts@~1.3.5, accepts@~1.3.7: +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== @@ -1998,35 +1751,30 @@ accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn@^6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" - integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== - -acorn@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" - integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== +acorn@^6.1.1, acorn@^6.2.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== acorn@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c" - integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ== + version "7.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" + integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -adm-zip@0.4.11, adm-zip@~0.4.3, adm-zip@~0.4.x: +adm-zip@0.4.11: version "0.4.11" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a" integrity sha512-L8vcjDTCOIJk7wFvmlEUN7AsSb8T+2JrdP7KINBjzr24TJ5Mwj590sLu3BC7zNZowvJWa/JtPmD8eJCzdtDWjA== -adm-zip@^0.4.9: - version "0.4.13" - resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a" - integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw== +adm-zip@^0.4.9, adm-zip@~0.4.3, adm-zip@~0.4.x: + version "0.4.14" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.14.tgz#2cf312bcc9f8875df835b0f6040bd89be0a727a9" + integrity sha512-/9aQCnQHF+0IiCl0qhXoK7qs//SwYE7zX8lsr/DNk1BRAHYxeLZPL4pguwK29gUEqasYQjqPtEpDRSWEkdHn9g== after@0.8.2: version "0.8.2" @@ -2041,10 +1789,10 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" -agent-base@4, agent-base@~4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" - integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== +agent-base@4, agent-base@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" + integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== dependencies: es6-promisify "^5.0.0" @@ -2053,10 +1801,17 @@ agent-base@5: resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== -agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== +agent-base@6: + version "6.0.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.0.tgz#5d0101f19bbfaed39980b22ae866de153b93f09a" + integrity sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw== + dependencies: + debug "4" + +agent-base@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: es6-promisify "^5.0.0" @@ -2085,7 +1840,7 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== -ajv@6.10.2, ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5: +ajv@6.10.2: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== @@ -2105,6 +1860,16 @@ ajv@^5.1.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" + integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + alphanum-sort@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -2131,14 +1896,14 @@ alphanum-sort@^1.0.0: integrity sha512-1865/NmqHNogibNoglY1MGBjx882iu2hI46BBhYDWyz0C4TDM5ER8H8SnYwQKUUG4RXMDsJizszEQ2BEoYKV9w== "angular-mocks@npm:angular-mocks@1.7": - version "1.7.2" - resolved "https://registry.yarnpkg.com/angular-mocks/-/angular-mocks-1.7.2.tgz#8a2bc7a7ce355697a48ab00e548b88e78f71fa52" - integrity sha512-yj9eWPG0usXX2eDTWM6YOmAGKraT7qHwuD+NrNyaR+mtrNr2ls77WuWXTjE1hZpmxTaGj4+R1nMY696XZn740Q== + version "1.7.9" + resolved "https://registry.yarnpkg.com/angular-mocks/-/angular-mocks-1.7.9.tgz#0a3b7e28b9a493b4e3010ed2b0f69a68e9b4f79b" + integrity sha512-LQRqqiV3sZ7NTHBnNmLT0bXtE5e81t97+hkJ56oU0k3dqKv1s6F+nBWRlOVzqHWPGFOiPS8ZJVdrS8DFzHyNIA== "angular@npm:angular@1.7": - version "1.7.2" - resolved "https://registry.yarnpkg.com/angular/-/angular-1.7.2.tgz#687b955dbe5c533f8d73460461707af00360251f" - integrity sha512-JcKKJbBdybUsmQ6x1M3xWyTYQ/ioVKJhSByEAjqrhmlOfvMFdhfMqAx5KIo8rLGk4DFolYPcCSgssjgTVjCtRQ== + version "1.7.9" + resolved "https://registry.yarnpkg.com/angular/-/angular-1.7.9.tgz#e52616e8701c17724c3c238cfe4f9446fd570bc4" + integrity sha512-5se7ZpcOtu0MBFlzGv5dsM1quQDoDeUTwZrWjGtTNA7O88cD8TEk5IEKCTDa3uECV9XnvKREVUr7du1ACiWGFQ== ansi-align@^2.0.0: version "2.0.0" @@ -2154,7 +1919,7 @@ ansi-colors@4.1.1: ansi-colors@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== dependencies: ansi-wrap "^0.1.0" @@ -2177,11 +1942,11 @@ ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== ansi-escapes@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.2.1.tgz#4dccdb846c3eee10f6d64dea66273eab90c37228" - integrity sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q== + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== dependencies: - type-fest "^0.5.2" + type-fest "^0.11.0" ansi-gray@^0.1.1: version "0.1.1" @@ -2227,7 +1992,7 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.2.1: +ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -2288,7 +2053,7 @@ app-module-path@^2.2.0: resolved "https://registry.yarnpkg.com/app-module-path/-/app-module-path-2.2.0.tgz#641aa55dfb7d6a6f0a8141c4b9c0aa50b6c24dd5" integrity sha1-ZBqlXft9am8KgUHEucCqULbCTdU= -aproba@^1.0.3, aproba@^1.1.1: +aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== @@ -2368,14 +2133,6 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= -are-we-there-yet@~1.1.2: - version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" - integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -2396,13 +2153,6 @@ arr-diff@^1.0.1: arr-flatten "^1.0.1" array-slice "^0.2.3" -arr-diff@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" - integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= - dependencies: - arr-flatten "^1.0.1" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -2448,10 +2198,10 @@ array-flatten@1.1.1, array-flatten@^1.0.0: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= -array-flatten@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296" - integrity sha1-Qmu52oQJDBg42BLIFQryCoMx4pY= +array-flatten@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-3.0.0.tgz#6428ca2ee52c7b823192ec600fa3ed2f157cd541" + integrity sha512-zPMVc3ZYlGLNk4mpK1NzP2wg0ml9t7fUgDsayR5Y5rSzxQilzR9FGu/EH2jQOcKSAeAfWeylyW8juy3OkWRvNA== array-flatten@^2.1.0: version "2.1.2" @@ -2495,11 +2245,6 @@ array-uniq@^1.0.1, array-uniq@^1.0.2: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= -array-unique@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" - integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -2566,10 +2311,11 @@ assert-plus@^0.2.0: integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= assert@^1.1.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - integrity sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE= + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== dependencies: + object-assign "^4.1.1" util "0.10.3" assertion-error@^1.1.0: @@ -2588,14 +2334,14 @@ ast-module-types@^2.3.1, ast-module-types@^2.3.2, ast-module-types@^2.4.0, ast-m integrity sha512-zXSoVaMrf2R+r+ISid5/9a8SXm1LLdkhHzh6pSRhj9jklzruOOl1hva1YmFT33wAstg/f9ZndJAlq1BSrFLSGA== async-each@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== async-limiter@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== async@1.2.x: version "1.2.1" @@ -2631,7 +2377,7 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -atob@^2.1.1: +atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== @@ -2659,15 +2405,18 @@ aws-sign2@~0.7.0: resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= -aws4@^1.2.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" - integrity sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w== +aws4@^1.2.1, aws4@^1.6.0, aws4@^1.8.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== -aws4@^1.6.0, aws4@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" - integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== +axios@^0.18.0: + version "0.18.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3" + integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" babel-code-frame@^6.22.0: version "6.26.0" @@ -2732,12 +2481,7 @@ base64-js@1.2.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" integrity sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw== -base64-js@^1.0.2, base64-js@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" - integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== - -base64-js@^1.2.3, base64-js@^1.3.0: +base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== @@ -2765,7 +2509,7 @@ basic-auth-connect@^1.0.0: resolved "https://registry.yarnpkg.com/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz#fdb0b43962ca7b40456a7c2bb48fe173da2d2122" integrity sha1-/bC0OWLKe0BFanwrtI/hc9otISI= -basic-auth@~2.0.0: +basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== @@ -2812,9 +2556,9 @@ bignumber.js@^7.0.0: integrity sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ== binary-extensions@^1.0.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.0.tgz#9523e001306a32444b907423f1de2164222f6ab1" - integrity sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw== + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== binary-extensions@^2.0.0: version "2.0.0" @@ -2829,6 +2573,13 @@ binary-extensions@^2.0.0: buffers "~0.1.1" chainsaw "~0.1.0" +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -2837,12 +2588,14 @@ bl@^1.0.0: readable-stream "^2.3.5" safe-buffer "^5.1.1" -bl@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88" - integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A== +bl@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.2.tgz#52b71e9088515d0606d9dd9cc7aa48dc1f98e73a" + integrity sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ== dependencies: - readable-stream "^3.0.1" + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" bl@~1.1.2: version "1.1.2" @@ -2851,10 +2604,10 @@ bl@~1.1.2: dependencies: readable-stream "~2.0.5" -blob@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921" - integrity sha1-vPEwUspURj8w+fx+lbmkdjCpSSE= +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== blocking-proxy@^1.0.0: version "1.0.1" @@ -2863,20 +2616,10 @@ blocking-proxy@^1.0.0: dependencies: minimist "^1.2.0" -bluebird@^3.3.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" - integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== - -bluebird@^3.5.1, bluebird@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" - integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== - -bluebird@^3.5.5: - version "3.5.5" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" - integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== +bluebird@^3.3.0, bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bluebird@~3.4.1: version "3.4.7" @@ -2888,7 +2631,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -body-parser@1.19.0, body-parser@^1.19.0: +body-parser@1.19.0, body-parser@^1.16.1, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== @@ -2904,22 +2647,6 @@ body-parser@1.19.0, body-parser@^1.19.0: raw-body "2.4.0" type-is "~1.6.17" -body-parser@^1.16.1: - version "1.18.3" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" - integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= - dependencies: - bytes "3.0.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "~1.6.3" - iconv-lite "0.4.23" - on-finished "~2.3.0" - qs "6.5.2" - raw-body "2.3.3" - type-is "~1.6.16" - bonjour@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" @@ -2965,15 +2692,6 @@ brace-expansion@^1.0.0, brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^1.8.2: - version "1.8.5" - resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" - integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= - dependencies: - expand-range "^1.8.1" - preserve "^0.2.0" - repeat-element "^1.1.2" - braces@^2.3.1, braces@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" @@ -3068,7 +2786,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.8.3, browserslist@^4.8.3: +browserslist@4.8.3: version "4.8.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.3.tgz#65802fcd77177c878e015f0e3189f2c4f627ba44" integrity sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg== @@ -3077,35 +2795,30 @@ browserslist@4.8.3, browserslist@^4.8.3: electron-to-chromium "^1.3.322" node-releases "^1.1.44" -browserslist@^4.0.0: - version "4.8.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.5.tgz#691af4e327ac877b25e7a3f7ee869c4ef36cdea3" - integrity sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg== - dependencies: - caniuse-lite "^1.0.30001022" - electron-to-chromium "^1.3.338" - node-releases "^1.1.46" - -browserslist@^4.6.0, browserslist@^4.7.2: - version "4.7.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.3.tgz#02341f162b6bcc1e1028e30624815d4924442dc3" - integrity sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ== +browserslist@^4.0.0, browserslist@^4.6.0, browserslist@^4.7.2, browserslist@^4.8.3: + version "4.11.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.1.tgz#92f855ee88d6e050e7e7311d987992014f1a1f1b" + integrity sha512-DCTr3kDrKEYNw6Jb9HFxVLQNaue8z+0ZfRBRjmCunKDEXEBajKDj2Y+Uelg+Pi29OnvaSGwjOsnRyNEkXzHg5g== dependencies: - caniuse-lite "^1.0.30001010" - electron-to-chromium "^1.3.306" - node-releases "^1.1.40" + caniuse-lite "^1.0.30001038" + electron-to-chromium "^1.3.390" + node-releases "^1.1.53" + pkg-up "^2.0.0" -browserstack@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.0.tgz#b565425ad62ed72c1082a1eb979d5313c7d4754f" - integrity sha1-tWVCWtYu1ywQgqHrl51TE8fUdU8= +browserstack-local@^1.3.7: + version "1.4.5" + resolved "https://registry.yarnpkg.com/browserstack-local/-/browserstack-local-1.4.5.tgz#115153ce1d08d58b7575ecf4381d54d10b42d2cf" + integrity sha512-0/VdSv2YVXmcnwBb64XThMvjM1HnZJnPdv7CUgQbC5y/N9Wsr0Fu+j1oknE9fC/VPx9CpoSC6CJ0kza42skMSA== dependencies: - https-proxy-agent "1.0.0" + https-proxy-agent "^4.0.0" + is-running "^2.1.0" + ps-tree "=1.2.0" + temp-fs "^0.9.9" -browserstack@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.1.tgz#e2dfa66ffee940ebad0a07f7e00fd4687c455d66" - integrity sha512-O8VMT64P9NOLhuIoD4YngyxBURefaSdR4QdhG8l6HZ9VxtU7jc3m6jLufFwKA5gaf7fetfB2TnRJnMxyob+heg== +browserstack@^1.5.1, browserstack@~1.5.1: + version "1.5.3" + resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac" + integrity sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg== dependencies: https-proxy-agent "^2.2.1" @@ -3117,14 +2830,6 @@ browserstacktunnel-wrapper@2.0.1: https-proxy-agent "^1.0.0" unzip "~0.1.9" -browserstacktunnel-wrapper@~2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.2.tgz#3d11159c18cd202b2920b09830fbe4bd90f079b5" - integrity sha512-7w7HYA00qjBtuQH0c5rqW7RbWPHyRROqTZofwNp5G0sKc2fYChsTfbHz3ul8Yd+ffkQvR81m+iPjEB004P6kxQ== - dependencies: - https-proxy-agent "^1.0.0" - unzip "~0.1.9" - buffer-alloc-unsafe@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" @@ -3138,7 +2843,7 @@ buffer-alloc@^1.2.0: buffer-alloc-unsafe "^1.1.0" buffer-fill "^1.0.0" -buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= @@ -3182,10 +2887,10 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.1.0: - version "5.4.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" - integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== +buffer@^5.1.0, buffer@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.5.0.tgz#9c3caa3d623c33dd1c7ef584b89b88bf9c9bc1ce" + integrity sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" @@ -3195,7 +2900,7 @@ buffers@~0.1.1: resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= -builtin-modules@^1.0.0, builtin-modules@^1.1.1: +builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= @@ -3250,9 +2955,9 @@ cacache@13.0.1, cacache@^13.0.1: unique-filename "^1.1.1" cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: - version "12.0.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" - integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== dependencies: bluebird "^3.5.5" chownr "^1.1.1" @@ -3356,20 +3061,10 @@ caniuse-lite@1.0.30001020: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001020.tgz#3f04c1737500ffda78be9beb0b5c1e2070e15926" integrity sha512-yWIvwA68wRHKanAVS1GjN8vajAv7MBFshullKCeq/eKpK7pJBVDgFFEqvgWTkcP2+wIDeQGYFRXECjKZnLkUjA== -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001022: - version "1.0.30001022" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz#9eeffe580c3a8f110b7b1742dcf06a395885e4c6" - integrity sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A== - -caniuse-lite@^1.0.30001006, caniuse-lite@^1.0.30001010: - version "1.0.30001012" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz#653ec635e815b9e0fb801890923b0c2079eb34ec" - integrity sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg== - -caniuse-lite@^1.0.30001017: - version "1.0.30001021" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001021.tgz#e75ed1ef6dbadd580ac7e7720bb16f07b083f254" - integrity sha512-wuMhT7/hwkgd8gldgp2jcrUjOU9RXJ4XxGumQeOsUr91l3WwmM68Cpa/ymCnWEDqakwFXhuDQbaKNHXBPgeE9g== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001006, caniuse-lite@^1.0.30001017, caniuse-lite@^1.0.30001038: + version "1.0.30001038" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz#44da3cbca2ab6cb6aa83d1be5d324e17f141caff" + integrity sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ== canonical-path@1.0.0: version "1.0.0" @@ -3480,10 +3175,10 @@ check-side-effects@0.0.21: rollup-plugin-node-resolve "~4.2.3" rollup-plugin-terser "~4.0.4" -"chokidar@>=2.0.0 <4.0.0": - version "3.3.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" - integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== +"chokidar@>=2.0.0 <4.0.0", chokidar@^3.0.0, chokidar@^3.0.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" + integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -3491,11 +3186,11 @@ check-side-effects@0.0.21: is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.2.0" + readdirp "~3.3.0" optionalDependencies: - fsevents "~2.1.1" + fsevents "~2.1.2" -chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.1.8: +chokidar@^2.0.3, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== @@ -3514,25 +3209,10 @@ chokidar@^2.0.2, chokidar@^2.0.3, chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.0.0, chokidar@^3.0.2: - version "3.3.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" - integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.3.0" - optionalDependencies: - fsevents "~2.1.2" - chownr@^1.1.1, chownr@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" - integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chrome-trace-event@^1.0.2: version "1.0.2" @@ -3636,19 +3316,7 @@ cli-boxes@^1.0.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= -cli-color@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-1.2.0.tgz#3a5ae74fd76b6267af666e69e2afbbd01def34d1" - integrity sha1-OlrnT9drYmevZm5p4q+70B3vNNE= - dependencies: - ansi-regex "^2.1.1" - d "1" - es5-ext "^0.10.12" - es6-iterator "2" - memoizee "^0.4.3" - timers-ext "0.1" - -cli-color@^1.2.0: +cli-color@^1.0.0, cli-color@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-1.4.0.tgz#7d10738f48526824f8fe7da51857cb0f572fe01f" integrity sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w== @@ -3700,6 +3368,15 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -3749,9 +3426,9 @@ clone@^2.1.1, clone@^2.1.2: integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= cloneable-readable@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" - integrity sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg== + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== dependencies: inherits "^2.0.1" process-nextick-args "^2.0.0" @@ -3834,12 +3511,7 @@ colors@1.0.3, colors@1.0.x: resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= -colors@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e" - integrity sha512-EDpX3a7wHMWFA7PUHWPHNWqOxIIRSJetuwl0AS5Oi/5FMV8kWm69RTlgm00GKjBO1xFHMtBbL49yRtMMdticBw== - -colors@^1.1.2: +colors@^1.1.0, colors@^1.1.2: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== @@ -3849,14 +3521,7 @@ colors@~1.2.1: resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc" integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== -combined-stream@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" - integrity sha1-cj599ugBrFYTETp+RFqbactjKBg= - dependencies: - delayed-stream "~1.0.0" - -combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: +combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.5, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -3870,30 +3535,15 @@ commander@2.9.0: dependencies: graceful-readlink ">= 1.0.0" -commander@^2.12.1, commander@^2.13.0, commander@^2.16.0, commander@^2.20.0, commander@^2.8.1, commander@~2.20.3: +commander@^2.12.1, commander@^2.13.0, commander@^2.16.0, commander@^2.19.0, commander@^2.20.0, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0, commander@~2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^2.19.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== - -commander@^2.7.1: - version "2.19.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" - integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== - -commander@^2.9.0: - version "2.16.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50" - integrity sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew== - commander@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.0.tgz#545983a0603fe425bc672d66c9e3c89c42121a83" - integrity sha512-NIQrwvv9V39FHgGFm36+U9SMQzbiHvU79k+iADraJTpmrFFfx7Ds0IvDoAdZsDrknlkRk14OYoWXb57uTh7/sw== + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== commondir@^1.0.1: version "1.0.1" @@ -3920,11 +3570,16 @@ component-bind@1.0.0: resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= -component-emitter@1.2.1, component-emitter@^1.2.1: +component-emitter@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" @@ -3951,11 +3606,11 @@ compress-commons@^2.1.1: readable-stream "^2.3.6" compressible@~2.0.16: - version "2.0.17" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" - integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: - mime-db ">= 1.40.0 < 2" + mime-db ">= 1.43.0 < 2" compression@^1.7.0, compression@^1.7.4: version "1.7.4" @@ -3975,7 +3630,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.2, concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@^1.6.0: +concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@^1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -3985,19 +3640,15 @@ concat-stream@1.6.2, concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@^ readable-stream "^2.2.2" typedarray "^0.0.6" -configstore@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/configstore/-/configstore-1.4.0.tgz#c35781d0501d268c25c54b8b17f6240e8a4fb021" - integrity sha1-w1eB0FAdJowlxUuLF/YkDopPsCE= +concat-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" + integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== dependencies: - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - object-assign "^4.0.1" - os-tmpdir "^1.0.0" - osenv "^0.1.0" - uuid "^2.0.1" - write-file-atomic "^1.1.2" - xdg-basedir "^2.0.0" + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.0.2" + typedarray "^0.0.6" configstore@^3.0.0: version "3.1.2" @@ -4011,6 +3662,18 @@ configstore@^3.0.0: write-file-atomic "^2.0.0" xdg-basedir "^3.0.0" +configstore@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" @@ -4023,17 +3686,7 @@ connect-query@^1.0.0: dependencies: qs "~6.4.0" -connect@^3.6.0: - version "3.6.6" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" - integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= - dependencies: - debug "2.6.9" - finalhandler "1.1.0" - parseurl "~1.3.2" - utils-merge "1.0.1" - -connect@^3.6.2: +connect@^3.6.0, connect@^3.6.2: version "3.7.0" resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== @@ -4044,16 +3697,9 @@ connect@^3.6.2: utils-merge "1.0.1" console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= - dependencies: - date-now "^0.1.4" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== constants-browserify@^1.0.0: version "1.0.0" @@ -4080,57 +3726,94 @@ conventional-changelog-angular@^1.6.6: compare-func "^1.3.1" q "^1.5.1" -conventional-changelog-atom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.0.tgz#cd6453469cfb8fc345af3391b92990251c95558b" - integrity sha512-ygwkwyTQYAm4S0tsDt+1yg8tHhRrv7qu9SOWPhNQlVrInFLsfKc0FActCA3de2ChknxpVPY2B53yhKvCAtkBCg== +conventional-changelog-angular@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz#269540c624553aded809c29a3508fdc2b544c059" + integrity sha512-QDEmLa+7qdhVIv8sFZfVxU1VSyVvnXPsxq8Vam49mKUcO1Z8VTLEJk9uI21uiJUsnmm0I4Hrsdc9TgkOQo9WSA== dependencies: + compare-func "^1.3.1" q "^1.5.1" -conventional-changelog-codemirror@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.0.tgz#bfb61ccabacdd3bf8425a5cbe92276c86c5a0c1e" - integrity sha512-pZt/YynJ5m8C9MGV5wkBuhM1eX+8a84fmNrdOylxg/lJV+lgtAiNhnpskNuixtf71iKVWSlEqMQ6z6CH7/Uo5A== +conventional-changelog-atom@^2.0.0, conventional-changelog-atom@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.3.tgz#3bd14280aa09fe3ec49a0e8fe97b5002db02aad4" + integrity sha512-szZe2ut97qNO6vCCMkm1I/tWu6ol4Rr8a9Lx0y/VlpDnpY0PNp+oGpFgU55lplhx+I3Lro9Iv4/gRj0knfgjzg== + dependencies: + q "^1.5.1" + +conventional-changelog-codemirror@^2.0.0, conventional-changelog-codemirror@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.3.tgz#ebc088154684f8f5171446b8d546ba6b460d46f2" + integrity sha512-t2afackdgFV2yBdHhWPqrKbpaQeVnz2hSJKdWqjasPo5EpIB6TBL0er3cOP1mnGQmuzk9JSvimNSuqjWGDtU5Q== + dependencies: + q "^1.5.1" + +conventional-changelog-conventionalcommits@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.2.3.tgz#22855b32d57d0328951c1c2dc01b172a5f24ea37" + integrity sha512-atGa+R4vvEhb8N/8v3IoW59gCBJeeFiX6uIbPu876ENAmkMwsenyn0R21kdDHJFLQdy6zW4J6b4xN8KI3b9oww== + dependencies: + compare-func "^1.3.1" + lodash "^4.17.15" + q "^1.5.1" + +conventional-changelog-core@^3.1.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz#b31410856f431c847086a7dcb4d2ca184a7d88fb" + integrity sha512-LMMX1JlxPIq/Ez5aYAYS5CpuwbOk6QFp8O4HLAcZxe3vxoCtABkhfjetk8IYdRB9CDQGwJFLR3Dr55Za6XKgUQ== dependencies: + conventional-changelog-writer "^4.0.6" + conventional-commits-parser "^3.0.3" + dateformat "^3.0.0" + get-pkg-repo "^1.0.0" + git-raw-commits "2.0.0" + git-remote-origin-url "^2.0.0" + git-semver-tags "^2.0.3" + lodash "^4.2.1" + normalize-package-data "^2.3.5" q "^1.5.1" + read-pkg "^3.0.0" + read-pkg-up "^3.0.0" + through2 "^3.0.0" -conventional-changelog-core@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-3.1.0.tgz#96a81bb3301b4b2a3dc2851cc54c5fb674ac1942" - integrity sha512-bcZkcFXkqVgG2W8m/1wjlp2wn/BKDcrPgw3/mvSEQtzs8Pax8JbAPFpEQReHY92+EKNNXC67wLA8y2xcNx0rDA== +conventional-changelog-core@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.1.4.tgz#39be27fca6ef20a0f998d7a3a1e97cfa8a055cb6" + integrity sha512-LO58ZbEpp1Ul+y/vOI8rJRsWkovsYkCFbOCVgi6UnVfU8WC0F8K8VQQwaBZWWUpb6JvEiN4GBR5baRP2txZ+Vg== dependencies: - conventional-changelog-writer "^4.0.0" - conventional-commits-parser "^3.0.0" + add-stream "^1.0.0" + conventional-changelog-writer "^4.0.11" + conventional-commits-parser "^3.0.8" dateformat "^3.0.0" get-pkg-repo "^1.0.0" - git-raw-commits "^2.0.0" + git-raw-commits "2.0.0" git-remote-origin-url "^2.0.0" - git-semver-tags "^2.0.0" - lodash "^4.2.1" + git-semver-tags "^3.0.1" + lodash "^4.17.15" normalize-package-data "^2.3.5" q "^1.5.1" - read-pkg "^1.1.0" - read-pkg-up "^1.0.1" - through2 "^2.0.0" + read-pkg "^3.0.0" + read-pkg-up "^3.0.0" + through2 "^3.0.0" -conventional-changelog-ember@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.1.tgz#5a5595b9ed50a6daca4bd3508a47ffe4a1a7152f" - integrity sha512-Ym1xLi7YLGooLUpHCJhlXJW5V7u/g+hlYD/+HKt0KqG2qbiBi7e7/HO9aScXTEKUBGMm7m4C443R+eCWQI2ynA== +conventional-changelog-ember@^2.0.1, conventional-changelog-ember@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.4.tgz#c29b78e4af7825cbecb6c3fd6086ca5c09471ac1" + integrity sha512-q1u73sO9uCnxN4TSw8xu6MRU8Y1h9kpwtcdJuNRwu/LSKI1IE/iuNSH5eQ6aLlQ3HTyrIpTfUuVybW4W0F17rA== dependencies: q "^1.5.1" -conventional-changelog-eslint@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.0.tgz#cc5376cb29a622c1ade197e155bf054640c05cd3" - integrity sha512-Acn20v+13c+o1OAWKvc9sCCl73Nj2vOMyn+G82euiMZwgYNE9CcBkTnw/GKdBi9KiZMK9uy+SCQ/QyAEE+8vZA== +conventional-changelog-eslint@^3.0.0, conventional-changelog-eslint@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.4.tgz#8f4736a23e0cd97e890e76fccc287db2f205f2ff" + integrity sha512-CPwTUENzhLGl3auunrJxiIEWncAGaby7gOFCdj2gslIuOFJ0KPJVOUhRz4Da/I53sdo/7UncUJkiLg94jEsjxg== dependencies: q "^1.5.1" -conventional-changelog-express@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.0.tgz#d3d020118fbfce21a75e025ec097101e355a2361" - integrity sha512-2svPjeXCrjwwqnzu/f3qU5LWoLO0jmUIEbtbbSRXAAP9Ag+137b484eJsiRt9DPYXSVzog0Eoek3rvCzfHcphQ== +conventional-changelog-express@^2.0.0, conventional-changelog-express@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.1.tgz#fea2231d99a5381b4e6badb0c1c40a41fcacb755" + integrity sha512-G6uCuCaQhLxdb4eEfAIHpcfcJ2+ao3hJkbLrw/jSK/eROeNfnxCJasaWdDAfFkxsbpzvQT4W01iSynU3OoPLIw== dependencies: q "^1.5.1" @@ -4141,6 +3824,13 @@ conventional-changelog-jquery@^0.1.0: dependencies: q "^1.4.1" +conventional-changelog-jquery@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.6.tgz#460236ad8fb1d29ff932a14fe4e3a45379b63c5e" + integrity sha512-gHAABCXUNA/HjnZEm+vxAfFPJkgtrZvCDIlCKfdPVXtCIo/Q0lN5VKpx8aR5p8KdVRQFF3OuTlvv5kv6iPuRqA== + dependencies: + q "^1.5.1" + conventional-changelog-jscs@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/conventional-changelog-jscs/-/conventional-changelog-jscs-0.1.0.tgz#0479eb443cc7d72c58bf0bcf0ef1d444a92f0e5c" @@ -4148,34 +3838,34 @@ conventional-changelog-jscs@^0.1.0: dependencies: q "^1.4.1" -conventional-changelog-jshint@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.0.tgz#7a038330f485082e489f47f5d07539036949f87d" - integrity sha512-+4fCln755N0ZzRUEdcDWR5Due71Dsqkbov6K/UmVCnljZvhVh0/wpT4YROoSsAnhfZO8shyWDPFKm6EP20pLQg== +conventional-changelog-jshint@^2.0.0, conventional-changelog-jshint@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.3.tgz#ef6e2caf2ee6ffdfda78fcdf7ce87cf6c512d728" + integrity sha512-Pc2PnMPcez634ckzr4EOWviwRSpZcURaK7bjyD9oK6N5fsC/a+3G7LW5m/JpcHPhA9ZxsfIbm7uqZ3ZDGsQ/sw== dependencies: compare-func "^1.3.1" q "^1.5.1" -conventional-changelog-preset-loader@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.0.1.tgz#d134734e0cc1b91b88b30586c5991f31442029f1" - integrity sha512-HiSfhXNzAzG9klIqJaA97MMiNBR4js+53g4Px0k7tgKeCNVXmrDrm+CY+nIqcmG5NVngEPf8rAr7iji1TWW7zg== +conventional-changelog-preset-loader@^2.0.1, conventional-changelog-preset-loader@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.0.tgz#580fa8ab02cef22c24294d25e52d7ccd247a9a6a" + integrity sha512-/rHb32J2EJnEXeK4NpDgMaAVTFZS3o1ExmjKMtYVgIC4MQn0vkNSbYpdGRotkfGGRWiqk3Ri3FBkiZGbAfIfOQ== -conventional-changelog-writer@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.0.tgz#3ed983c8ef6a3aa51fe44e82c9c75e86f1b5aa42" - integrity sha512-hMZPe0AQ6Bi05epeK/7hz80xxk59nPA5z/b63TOHq2wigM0/akreOc8N4Jam5b9nFgKWX1e9PdPv2ewgW6bcfg== +conventional-changelog-writer@^4.0.11, conventional-changelog-writer@^4.0.6: + version "4.0.11" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.11.tgz#9f56d2122d20c96eb48baae0bf1deffaed1edba4" + integrity sha512-g81GQOR392I+57Cw3IyP1f+f42ME6aEkbR+L7v1FBBWolB0xkjKTeCWVguzRrp6UiT1O6gBpJbEy2eq7AnV1rw== dependencies: compare-func "^1.3.1" - conventional-commits-filter "^2.0.0" + conventional-commits-filter "^2.0.2" dateformat "^3.0.0" - handlebars "^4.0.2" + handlebars "^4.4.0" json-stringify-safe "^5.0.1" - lodash "^4.2.1" - meow "^4.0.0" - semver "^5.5.0" + lodash "^4.17.15" + meow "^5.0.0" + semver "^6.0.0" split "^1.0.0" - through2 "^2.0.0" + through2 "^3.0.0" conventional-changelog@^2.0.3: version "2.0.3" @@ -4194,33 +3884,45 @@ conventional-changelog@^2.0.3: conventional-changelog-jshint "^2.0.0" conventional-changelog-preset-loader "^2.0.1" -conventional-commits-filter@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.0.tgz#a0ce1d1ff7a1dd7fab36bee8e8256d348d135651" - integrity sha512-Cfl0j1/NquB/TMVx7Wrmyq7uRM+/rPQbtVVGwzfkhZ6/yH6fcMmP0Q/9044TBZPTNdGzm46vXFXL14wbET0/Mg== +conventional-changelog@^3.1.18: + version "3.1.18" + resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.18.tgz#7da0a5ab34a604b920b8bf71c6cf5d952f0e805e" + integrity sha512-aN6a3rjgV8qwAJj3sC/Lme2kvswWO7fFSGQc32gREcwIOsaiqBaO6f2p0NomFaPDnTqZ+mMZFLL3hlzvEnZ0mQ== + dependencies: + conventional-changelog-angular "^5.0.6" + conventional-changelog-atom "^2.0.3" + conventional-changelog-codemirror "^2.0.3" + conventional-changelog-conventionalcommits "^4.2.3" + conventional-changelog-core "^4.1.4" + conventional-changelog-ember "^2.0.4" + conventional-changelog-eslint "^3.0.4" + conventional-changelog-express "^2.0.1" + conventional-changelog-jquery "^3.0.6" + conventional-changelog-jshint "^2.0.3" + conventional-changelog-preset-loader "^2.3.0" + +conventional-commits-filter@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz#f122f89fbcd5bb81e2af2fcac0254d062d1039c1" + integrity sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ== dependencies: - is-subset "^0.1.1" + lodash.ismatch "^4.4.0" modify-values "^1.0.0" -conventional-commits-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.0.0.tgz#7f604549a50bd8f60443fbe515484b1c2f06a5c4" - integrity sha512-GWh71U26BLWgMykCp+VghZ4s64wVbtseECcKQ/PvcPZR2cUnz+FUc2J9KjxNl7/ZbCxST8R03c9fc+Vi0umS9Q== +conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.0.8.tgz#23310a9bda6c93c874224375e72b09fb275fe710" + integrity sha512-YcBSGkZbYp7d+Cr3NWUeXbPDFUN6g3SaSIzOybi8bjHL5IJ5225OSCxJJ4LgziyEJ7AaJtE9L2/EU6H7Nt/DDQ== dependencies: JSONStream "^1.0.4" - is-text-path "^1.0.0" - lodash "^4.2.1" - meow "^4.0.0" + is-text-path "^1.0.1" + lodash "^4.17.15" + meow "^5.0.0" split2 "^2.0.0" - through2 "^2.0.0" + through2 "^3.0.0" trim-off-newlines "^1.0.0" -convert-source-map@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" - integrity sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU= - -convert-source-map@^1.7.0: +convert-source-map@^1.5.1, convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== @@ -4291,14 +3993,9 @@ core-js@3.6.0: integrity sha512-AHPTNKzyB+YwgDWoSOCaid9PUSEF6781vsfiK8qUz62zRR448/XgK2NtCbpiUGizbep8Lrpt0Du19PpGGZvw3Q== core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: - version "2.5.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" - integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== - -core-js@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" - integrity sha1-+rg/uwstjchfpjbEudNMdUIMbWU= + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -4456,6 +4153,11 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + css-color-names@0.0.4, css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -4499,10 +4201,13 @@ css-tree@1.0.0-alpha.37: mdn-data "2.0.4" source-map "^0.6.1" -css-unit-converter@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" - integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= +css-tree@1.0.0-alpha.39: + version "1.0.0-alpha.39" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" + integrity sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA== + dependencies: + mdn-data "2.0.6" + source-map "^0.6.1" css-what@^3.2.1: version "3.2.1" @@ -4519,10 +4224,10 @@ css@^2.0.0: source-map-resolve "^0.5.2" urix "^0.1.0" -cssesc@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" - integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== cssnano-preset-default@^4.0.7: version "4.0.7" @@ -4593,11 +4298,11 @@ cssnano@4.1.10: postcss "^7.0.0" csso@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" - integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.3.tgz#0d9985dc852c7cc2b2cacfbbe1079014d1a8e903" + integrity sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ== dependencies: - css-tree "1.0.0-alpha.37" + css-tree "1.0.0-alpha.39" csv-streamify@^3.0.4: version "3.0.4" @@ -4623,10 +4328,10 @@ cycle@1.0.x: resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" integrity sha1-IegLK+hYD5i0aPN5QwZisEbDStI= -cyclist@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" - integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= d@1, d@^1.0.1: version "1.0.1" @@ -4655,11 +4360,6 @@ date-format@^2.0.0: resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf" integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA== -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= - dateformat@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" @@ -4670,14 +4370,14 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2, debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: +debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@3.1.0, debug@~3.1.0: +debug@3.1.0, debug@=3.1.0, debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -4857,30 +4557,31 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= - depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + dependency-graph@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.7.2.tgz#91db9de6eb72699209d88aea4c1fd5221cac1c49" integrity sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ== dependency-tree@^7.0.2: - version "7.2.0" - resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-7.2.0.tgz#1dc8ea13c5623f5eab99b28a4fd4f4eca0809168" - integrity sha512-41LepYuMZNfd/wk7ppfhaOp8dzzd37t9hLP8XKg9WDQZ3u2WmNCR3eZOF/6jDatV+3OL4ChOON9a/UIeC75bYw== + version "7.2.1" + resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-7.2.1.tgz#41c8f6feb54a2ae32475c0158e8d2c2696bb7f54" + integrity sha512-nBxnjkqDW4LqAzBazy60V4lE0mAtIQ+oers/GIIvVvGYVdCD9+RNNd4G9jjstyz7ZFVg/j/OiYCvK5MjoVqA2w== dependencies: commander "^2.19.0" debug "^4.1.1" filing-cabinet "^2.5.1" precinct "^6.2.0" + typescript "^3.7.5" deprecated@^0.0.1: version "0.0.1" @@ -4910,11 +4611,6 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= - detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" @@ -5026,9 +4722,9 @@ diff@^3.2.0, diff@^3.5.0: integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== diff@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" - integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== diffie-hellman@^5.0.0: version "5.0.3" @@ -5127,13 +4823,20 @@ dot-prop@^3.0.0: dependencies: is-obj "^1.0.0" -dot-prop@^4.1.0, dot-prop@^4.1.1: +dot-prop@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ== dependencies: is-obj "^1.0.0" +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + dotenv@^6.1.0: version "6.2.0" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" @@ -5158,22 +4861,12 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= -duplexer@~0.1.1: +duplexer@^0.1.1, duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= -duplexify@^3.4.2: - version "3.6.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.6.1.tgz#b1a7a29c4abfd639585efaecce80d666b1e34125" - integrity sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - -duplexify@^3.6.0: +duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== @@ -5191,14 +4884,7 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" -ecdsa-sig-formatter@1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3" - integrity sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM= - dependencies: - safe-buffer "^5.0.1" - -ecdsa-sig-formatter@1.0.11: +ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== @@ -5220,20 +4906,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.306: - version "1.3.314" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.314.tgz#c186a499ed2c9057bce9eb8dca294d6d5450facc" - integrity sha512-IKDR/xCxKFhPts7h+VaSXS02Z1mznP3fli1BbXWXeN89i2gCzKraU8qLpEid8YzKcmZdZD3Mly3cn5/lY9xsBQ== - -electron-to-chromium@^1.3.322: - version "1.3.334" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.334.tgz#0588359f4ac5c4185ebacdf5fc7e1937e2c99872" - integrity sha512-RcjJhpsVaX0X6ntu/WSBlW9HE9pnCgXS9B8mTUObl1aDxaiOa0Lu+NMveIS5IDC+VELzhM32rFJDCC+AApVwcA== - -electron-to-chromium@^1.3.338: - version "1.3.340" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f" - integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww== +electron-to-chromium@^1.3.322, electron-to-chromium@^1.3.390: + version "1.3.394" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.394.tgz#50e927bb9f6a559ed21d284e7683ec5e2c784835" + integrity sha512-AEbSKBF49P+GgEP34w0VdYWn9SiMHgWUJbOkPEE1WZMIpWXtvfT9N0sd4Lv4jjD6DeSFjRuzm6+btn/yCz6h2Q== elliptic@^6.0.0: version "6.5.2" @@ -5248,6 +4924,11 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -5258,7 +4939,12 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= -encodeurl@~1.0.1, encodeurl@~1.0.2: +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= @@ -5309,14 +4995,14 @@ engine.io-client@~3.2.0: yeast "0.1.2" engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196" - integrity sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw== + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== dependencies: after "0.8.2" arraybuffer.slice "~0.0.7" base64-arraybuffer "0.1.5" - blob "0.0.4" + blob "0.0.5" has-binary2 "~1.0.2" engine.io@~3.2.0: @@ -5374,10 +5060,10 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: - version "1.17.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" - integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: + version "1.17.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" + integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== dependencies: es-to-primitive "^1.2.1" function-bind "^1.1.1" @@ -5391,31 +5077,6 @@ es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: string.prototype.trimleft "^2.1.1" string.prototype.trimright "^2.1.1" -es-abstract@^1.5.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.15.0.tgz#8884928ec7e40a79e3c9bc812d37d10c8b24cc57" - integrity sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.0" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-inspect "^1.6.0" - object-keys "^1.1.1" - string.prototype.trimleft "^2.1.0" - string.prototype.trimright "^2.1.0" - -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -5425,15 +5086,6 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es5-ext@^0.10.12, es5-ext@^0.10.30: - version "0.10.45" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.45.tgz#0bfdf7b473da5919d5adf3bd25ceb754fccc3653" - integrity sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ== - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - next-tick "1" - es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: version "0.10.53" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" @@ -5448,7 +5100,7 @@ es6-error@4.0.0: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.0.tgz#f094c7041f662599bb12720da059d6b9c7ff0f40" integrity sha1-8JTHBB9mJZm7EnINoFnWucf/D0A= -es6-iterator@2, es6-iterator@^2.0.3, es6-iterator@~2.0.3: +es6-iterator@^2.0.3, es6-iterator@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= @@ -5469,11 +5121,6 @@ es6-promise@^4.0.3: resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== -es6-promise@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" - integrity sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y= - es6-promisify@5.0.0, es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" @@ -5481,7 +5128,7 @@ es6-promisify@5.0.0, es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -es6-symbol@^3.1.1, es6-symbol@~3.1.1, es6-symbol@~3.1.3: +es6-symbol@^3.1.1, es6-symbol@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== @@ -5510,9 +5157,9 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escodegen@^1.8.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.13.0.tgz#c7adf9bd3f3cc675bb752f202f79a720189cab29" - integrity sha512-eYk2dCkxR07DsHA/X2hRBj0CFAZeri/LyDMc0C8JT1Hqi6JnVpMhJ7XFITbb0+yZS3lVkaPL2oCkZ3AVmeVbMw== + version "1.14.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" + integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== dependencies: esprima "^4.0.1" estraverse "^4.2.0" @@ -5551,11 +5198,6 @@ estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estree-walker@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.5.2.tgz#d3850be7529c9580d815600b53126515e146dd39" - integrity sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig== - estree-walker@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" @@ -5567,9 +5209,9 @@ esutils@^1.1.6: integrity sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U= esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== etag@~1.8.1: version "1.8.1" @@ -5584,9 +5226,9 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" -event-stream@^3.1.5: +event-stream@=3.3.4: version "3.3.4" - resolved "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= dependencies: duplexer "~0.1.1" @@ -5597,25 +5239,33 @@ event-stream@^3.1.5: stream-combiner "~0.0.4" through "~2.3.1" +event-stream@^3.1.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.5.tgz#e5dd8989543630d94c6cf4d657120341fa31636b" + integrity sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g== + dependencies: + duplexer "^0.1.1" + from "^0.1.7" + map-stream "0.0.7" + pause-stream "^0.0.11" + split "^1.0.1" + stream-combiner "^0.2.2" + through "^2.3.8" + event-target-shim@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter3@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" - integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== - eventemitter3@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== events@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== eventsource@^1.0.7: version "1.0.7" @@ -5668,13 +5318,6 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= -expand-brackets@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" - integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= - dependencies: - is-posix-bracket "^0.1.0" - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -5688,13 +5331,6 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" @@ -5767,32 +5403,20 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@3, extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= - -extend@^3.0.0, extend@^3.0.2, extend@~3.0.1, extend@~3.0.2: +extend@3, extend@^3.0.0, extend@^3.0.1, extend@^3.0.2, extend@~3.0.0, extend@~3.0.1, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== external-editor@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" - integrity sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== dependencies: chardet "^0.7.0" iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" - integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= - dependencies: - is-extglob "^1.0.0" - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -5808,14 +5432,14 @@ extglob@^2.0.4: to-regex "^3.0.1" extract-zip@^1.6.6: - version "1.6.7" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9" - integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k= + version "1.7.0" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" + integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== dependencies: - concat-stream "1.6.2" - debug "2.6.9" - mkdirp "0.5.1" - yauzl "2.4.1" + concat-stream "^1.6.2" + debug "^2.6.9" + mkdirp "^0.5.4" + yauzl "^2.10.0" extsprintf@1.3.0: version "1.3.0" @@ -5833,12 +5457,13 @@ eyes@0.1.x: integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= fancy-log@^1.1.0, fancy-log@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" - integrity sha1-9BEl49hPLn2JpD0G2VjI94vha+E= + version "1.3.3" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" + integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== dependencies: ansi-gray "^0.1.1" color-support "^1.1.3" + parse-node-version "^1.0.0" time-stamp "^1.0.0" fast-deep-equal@^1.0.0: @@ -5851,6 +5476,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + fast-json-stable-stringify@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -5867,9 +5497,9 @@ fast-levenshtein@~2.0.6: integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fast-text-encoding@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz#3e5ce8293409cfaa7177a71b9ca84e1b1e6f25ef" - integrity sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ== + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.1.tgz#4a428566f74fc55ebdd447555b1eb4d9cf514455" + integrity sha512-x4FEgaz3zNRtJfLFqJmHWxkMDDvXVtaznj2V9jiP8ACUJrUgist4bP9FmDL2Vew2Y9mEQI/tG4GqabaitYp9CQ== fast-url-parser@^1.1.3: version "1.1.3" @@ -5892,17 +5522,17 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= dependencies: pend "~1.2.0" figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" - integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== figures@^2.0.0: version "2.0.0" @@ -5912,9 +5542,9 @@ figures@^2.0.0: escape-string-regexp "^1.0.5" figures@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9" - integrity sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g== + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== dependencies: escape-string-regexp "^1.0.5" @@ -5931,10 +5561,10 @@ file-loader@4.2.0: loader-utils "^1.2.3" schema-utils "^2.0.0" -filename-regex@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" - integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== filesize@^3.1.3: version "3.6.1" @@ -5960,17 +5590,6 @@ filing-cabinet@^2.5.1: stylus-lookup "^3.0.1" typescript "^3.0.3" -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -5988,19 +5607,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" - integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= - dependencies: - debug "2.6.9" - encodeurl "~1.0.1" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.2" - statuses "~1.3.1" - unpipe "~1.0.0" - finalhandler@1.1.2, finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -6033,12 +5639,12 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: pkg-dir "^3.0.0" find-cache-dir@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874" - integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg== + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== dependencies: commondir "^1.0.1" - make-dir "^3.0.0" + make-dir "^3.0.2" pkg-dir "^4.1.0" find-index@^0.1.1: @@ -6101,9 +5707,9 @@ findup-sync@~0.3.0: glob "~5.0.0" fined@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.0.tgz#b37dc844b76a2f5e7081e884f7c0ae344f153476" - integrity sha1-s33IRLdqL15wgeiE98CuNE8VNHY= + version "1.2.0" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b" + integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng== dependencies: expand-tilde "^2.0.2" is-plain-object "^2.0.3" @@ -6112,9 +5718,9 @@ fined@^1.0.1: parse-filepath "^1.0.1" firebase-tools@^7.11.0: - version "7.11.0" - resolved "https://registry.yarnpkg.com/firebase-tools/-/firebase-tools-7.11.0.tgz#233f4950a50bb866a996cd46e42156d36a0e01fa" - integrity sha512-BCX/1Ut1/KP8eSmj1TarzoXzu0ZVbm/8S/oTms7xumgGMipwgZsG89/psNG7WUhN/nupZ76DDQPMhua8vvsY0Q== + version "7.16.2" + resolved "https://registry.yarnpkg.com/firebase-tools/-/firebase-tools-7.16.2.tgz#6f318de5d35346b48219e9f7da23ce4576eac16e" + integrity sha512-8jxJMdOtsiXeKGZx5nR3+uOdMAY8XqNZq28XOGPzD4r+6U6AAmbvyhj2500Jm6LtsXQhcKHPaWF4XICv+m3sKg== dependencies: "@google-cloud/pubsub" "^1.1.5" JSONStream "^1.2.1" @@ -6125,7 +5731,7 @@ firebase-tools@^7.11.0: cli-color "^1.2.0" cli-table "^0.3.1" commander "^4.0.1" - configstore "^1.2.0" + configstore "^5.0.1" cross-env "^5.1.3" cross-spawn "^4.0.0" csv-streamify "^3.0.4" @@ -6136,8 +5742,10 @@ firebase-tools@^7.11.0: filesize "^3.1.3" fs-extra "^0.23.1" glob "^7.1.2" - google-auto-auth "^0.7.2" + google-auto-auth "^0.10.1" + google-gax "~1.12.0" inquirer "~6.3.1" + js-yaml "^3.13.1" jsonschema "^1.0.2" jsonwebtoken "^8.2.1" lodash "^4.17.14" @@ -6150,13 +5758,14 @@ firebase-tools@^7.11.0: portfinder "^1.0.23" progress "^2.0.3" request "^2.87.0" + rimraf "^3.0.0" semver "^5.7.1" superstatic "^6.0.1" tar "^4.3.0" tcp-port-used "^1.0.1" tmp "0.0.33" universal-analytics "^0.4.16" - unzipper "^0.10.5" + unzipper "^0.10.10" update-notifier "^2.5.0" uuid "^3.0.0" winston "^1.0.1" @@ -6208,9 +5817,9 @@ first-chunk-stream@^2.0.0: readable-stream "^2.0.2" flagged-respawn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.0.tgz#4e79ae9b2eb38bf86b3bb56bf3e0a56aa5fcabd7" - integrity sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c= + version "1.0.1" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" + integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== flat-arguments@^1.0.0: version "1.0.2" @@ -6223,9 +5832,9 @@ flat-arguments@^1.0.0: lodash.isobject "^3.0.0" flatted@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" - integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== flatten@^1.0.2: version "1.0.3" @@ -6233,32 +5842,32 @@ flatten@^1.0.2: integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== flush-write-stream@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" - integrity sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== dependencies: - inherits "^2.0.1" - readable-stream "^2.0.4" + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" follow-redirects@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" - integrity sha512-v9GI1hpaqq1ZZR6pBD1+kI7O24PhDvNGNodjS3MdcEqyrahCp8zbtpv+2B/krUnSmUH80lbAS7MrdeK5IylgKg== + version "1.11.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" + integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA== dependencies: - debug "^3.1.0" + debug "^3.0.0" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -for-own@^0.1.4: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - for-own@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" @@ -6322,7 +5931,7 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -from@~0: +from@^0.1.7, from@~0: version "0.1.7" resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= @@ -6394,9 +6003,9 @@ fs-minipass@^1.2.5: minipass "^2.6.0" fs-minipass@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.0.0.tgz#a6415edab02fae4b9e9230bc87ee2e4472003cd1" - integrity sha512-40Qz+LFXmd9tzYVnnBmZvFfvAADfUA14TXPK1s7IfElJTIZ97rA8w4Kin7Wt5JBrC3ShnnFJO/5vPjPEeJIq9A== + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" @@ -6423,14 +6032,14 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.7.tgz#4851b664a3783e52003b3c66eb0eee1074933aa4" - integrity sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw== + version "1.2.12" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.12.tgz#db7e0d8ec3b0b45724fd4d83d43554a8f1f0de5c" + integrity sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q== dependencies: - nan "^2.9.2" - node-pre-gyp "^0.10.0" + bindings "^1.5.0" + nan "^2.12.1" -fsevents@~2.1.1, fsevents@~2.1.2: +fsevents@~2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805" integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA== @@ -6474,28 +6083,24 @@ fx-runner@1.0.5: which "1.2.4" winreg "0.0.12" -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= +gaxios@^1.0.4: + version "1.8.4" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-1.8.4.tgz#e08c34fe93c0a9b67a52b7b9e7a64e6435f9a339" + integrity sha512-BoENMnu1Gav18HcpV9IleMPZ9exM+AvUjrAOV4Mzs/vfz2Lu/ABv451iEXByKiMPn2M140uul1txXCg83sAENw== dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" + abort-controller "^3.0.0" + extend "^3.0.2" + https-proxy-agent "^2.2.1" + node-fetch "^2.3.0" gaxios@^2.1.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-2.2.2.tgz#f58516ead6868d997fcf267d4fe2dcef652bd1a3" - integrity sha512-fzttYsjvZxCaN+bQK7FtAMgoIlPtHkMwlz7vHD+aNRcU7I7gHgnp6hvGJksoo+dO1TDxaog+dSBycbYhHIStaA== + version "2.3.4" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-2.3.4.tgz#eea99353f341c270c5f3c29fc46b8ead56f0a173" + integrity sha512-US8UMj8C5pRnao3Zykc4AAVr+cffoNKRTg9Rsf2GiuZCW69vgJj38VK2PzlPuQU73FZ/nTk9/Av6/JGcE1N9vA== dependencies: abort-controller "^3.0.0" extend "^3.0.2" - https-proxy-agent "^4.0.0" + https-proxy-agent "^5.0.0" is-stream "^2.0.0" node-fetch "^2.3.0" @@ -6506,26 +6111,29 @@ gaze@^0.5.1: dependencies: globule "~0.1.0" -gcp-metadata@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-0.3.1.tgz#313814456e7c3d0eeb8f8b084b33579e886f829a" - integrity sha512-5kJPX/RXuqoLmHiOOgkSDk/LI0QaXpEvZ3pvQP4ifjGGDKZKVSOjL/GcDjXA5kLxppFCOjmmsu0Uoop9d1upaQ== +gcp-metadata@^0.6.1, gcp-metadata@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-0.6.3.tgz#4550c08859c528b370459bd77a7187ea0bdbc4ab" + integrity sha512-MSmczZctbz91AxCvqp9GHBoZOSbJKAICV7Ow/AIWSJZRrRchUd5NL1b2P4OfP+4m490BEUPhhARfpHdqCxuCvg== dependencies: - extend "^3.0.0" - retry-request "^3.0.0" + axios "^0.18.0" + extend "^3.0.1" + retry-axios "0.3.2" -gcp-metadata@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-3.3.0.tgz#df061f0c0da3fb274b20f4af0d955030bbc21eac" - integrity sha512-uO3P/aByOQmoDu5bOYBODHmD1oDCZw7/R8SYY0MdmMQSZVEmeTSxmiM1vwde+YHYSpkaQnAAMAIZuOqLvgfp/Q== +gcp-metadata@^3.4.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-3.5.0.tgz#6d28343f65a6bbf8449886a0c0e4a71c77577055" + integrity sha512-ZQf+DLZ5aKcRpLzYUyBS3yo3N0JSa82lNDO8rj3nMSlovLcz2riKFBsYgDzeXcv75oo5eqB2lx+B14UvPoCRnA== dependencies: gaxios "^2.1.0" json-bigint "^0.3.0" generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - integrity sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ= + version "2.3.1" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== + dependencies: + is-property "^1.0.2" generate-object-property@^1.1.0: version "1.2.0" @@ -6612,7 +6220,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -git-raw-commits@^2.0.0: +git-raw-commits@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5" integrity sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg== @@ -6631,13 +6239,21 @@ git-remote-origin-url@^2.0.0: gitconfiglocal "^1.0.0" pify "^2.3.0" -git-semver-tags@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-2.0.0.tgz#c218fd895bdf8e8e02f6bde555b2c3893ac73cd7" - integrity sha512-lSgFc3zQTul31nFje2Q8XdNcTOI6B4I3mJRPCgFzHQQLfxfqdWTYzdtCaynkK5Xmb2wQlSJoKolhXJ1VhKROnQ== +git-semver-tags@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-2.0.3.tgz#48988a718acf593800f99622a952a77c405bfa34" + integrity sha512-tj4FD4ww2RX2ae//jSrXZzrocla9db5h0V7ikPl1P/WwoZar9epdUhwR7XHXSgc+ZkNq72BEEerqQuicoEQfzA== dependencies: meow "^4.0.0" - semver "^5.5.0" + semver "^6.0.0" + +git-semver-tags@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-3.0.1.tgz#9cb9e4974437de1f71f32da3bfe74f4d35afb1b9" + integrity sha512-Hzd1MOHXouITfCasrpVJbRDg9uvW7LfABk3GQmXYZByerBDrfrEMP9HXpNT7RxAbieiocP6u+xq20DkvjwxnCA== + dependencies: + meow "^5.0.0" + semver "^6.0.0" gitconfiglocal@^1.0.0: version "1.0.0" @@ -6646,21 +6262,6 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -glob-base@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" - integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= - dependencies: - glob-parent "^2.0.0" - is-glob "^2.0.0" - -glob-parent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" - integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= - dependencies: - is-glob "^2.0.0" - glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -6670,9 +6271,9 @@ glob-parent@^3.1.0: path-dirname "^1.0.0" glob-parent@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2" - integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw== + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== dependencies: is-glob "^4.0.1" @@ -6727,7 +6328,7 @@ glob@5.x.x, glob@~5.0.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.2, glob@^7.0.3, glob@^7.0.6, glob@^7.1.1: +glob@7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== @@ -6761,7 +6362,7 @@ glob@^4.3.1: minimatch "^2.0.1" once "^1.3.0" -glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -6773,18 +6374,6 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@~3.1.21: version "3.1.21" resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" @@ -6871,61 +6460,85 @@ globule@~0.1.0: minimatch "~0.2.11" glogg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810" - integrity sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw== + version "1.0.2" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f" + integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA== dependencies: sparkles "^1.0.0" gonzales-pe@^4.2.3: - version "4.2.4" - resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.4.tgz#356ae36a312c46fe0f1026dd6cb539039f8500d2" - integrity sha512-v0Ts/8IsSbh9n1OJRnSfa7Nlxi4AkXIsWB6vPept8FDbL4bXn3FNuxjYtO/nmBGu7GDkL9MFeGebeSu6l55EPQ== + version "4.3.0" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" + integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== dependencies: - minimist "1.1.x" + minimist "^1.2.5" -google-auth-library@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" - integrity sha1-bhW6vuhf0d0U2NEoopW2g41SE24= +google-auth-library@^1.3.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-1.6.1.tgz#9c73d831ad720c0c3048ab89d0ffdec714d07dd2" + integrity sha512-jYiWC8NA9n9OtQM7ANn0Tk464do9yhKEtaJ72pKcaBiEwn4LwcGYIYOfwtfsSm3aur/ed3tlSxbmg24IAT6gAg== dependencies: - gtoken "^1.2.1" - jws "^3.1.4" - lodash.noop "^3.0.1" - request "^2.74.0" + axios "^0.18.0" + gcp-metadata "^0.6.3" + gtoken "^2.3.0" + jws "^3.1.5" + lodash.isstring "^4.0.1" + lru-cache "^4.1.3" + retry-axios "^0.3.2" google-auth-library@^5.0.0, google-auth-library@^5.5.0: - version "5.8.0" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-5.8.0.tgz#60a29ef0288c4dc106b537a7a717edec09ded406" - integrity sha512-aXVUAUAhyof66F1STizYRQwO8nAqp7DDhF0tvfyXyZof8LxXaYtOk7CJeZ+o7G+o1EfqJZi9AAlK3FhZVzYWuQ== + version "5.10.1" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-5.10.1.tgz#504ec75487ad140e68dd577c21affa363c87ddff" + integrity sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg== dependencies: arrify "^2.0.0" base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" fast-text-encoding "^1.0.0" gaxios "^2.1.0" - gcp-metadata "^3.3.0" + gcp-metadata "^3.4.0" gtoken "^4.1.0" jws "^4.0.0" lru-cache "^5.0.0" -google-auto-auth@^0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/google-auto-auth/-/google-auto-auth-0.7.2.tgz#bf9352d5c4a0897bf31fd9c491028b765fbea71e" - integrity sha512-ux2n2AE2g3+vcLXwL4dP/M12SFMRX5dzCzBfhAEkTeAB7dpyGdOIEj7nmUx0BHKaCcUQrRWg9kT63X/Mmtk1+A== +google-auto-auth@^0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/google-auto-auth/-/google-auto-auth-0.10.1.tgz#68834a6f3da59a6cb27fce56f76e3d99ee49d0a2" + integrity sha512-iIqSbY7Ypd32mnHGbYctp80vZzXoDlvI9gEfvtl3kmyy5HzOcrZCIGCBdSlIzRsg7nHpQiHE3Zl6Ycur6TSodQ== dependencies: async "^2.3.0" - gcp-metadata "^0.3.0" - google-auth-library "^0.10.0" + gcp-metadata "^0.6.1" + google-auth-library "^1.3.1" request "^2.79.0" -google-gax@^1.7.5: - version "1.13.0" - resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-1.13.0.tgz#82ed44155b296b0069178320c31c75d1bd8a6cd3" - integrity sha512-MSDPDz+eK8X6XHkb2C1DGPRX50RZBLeSnXChV5P6ojLkc1zSfII8OWGdxREBw8/izvRJLQ5XnuSk1ylLB1BKfQ== +google-gax@^1.14.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-1.15.2.tgz#a58aff43ec383f4f056f9d796e8d5e4891161eb8" + integrity sha512-yNNiRf9QxWpZNfQQmSPz3rIDTBDDKnLKY/QEsjCaJyDxttespr6v8WRGgU5KrU/6ZM7QRlgBAYXCkxqHhJp0wA== + dependencies: + "@grpc/grpc-js" "^0.7.4" + "@grpc/proto-loader" "^0.5.1" + "@types/fs-extra" "^8.0.1" + "@types/long" "^4.0.0" + abort-controller "^3.0.0" + duplexify "^3.6.0" + google-auth-library "^5.0.0" + is-stream-ended "^0.1.4" + lodash.at "^4.6.0" + lodash.has "^4.5.2" + node-fetch "^2.6.0" + protobufjs "^6.8.9" + retry-request "^4.0.0" + semver "^6.0.0" + walkdir "^0.4.0" + +google-gax@~1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/google-gax/-/google-gax-1.12.0.tgz#f926f7e6abda245db38ecbebbbf58daaf3a8f687" + integrity sha512-BeeoxVO6y9K20gUsexUwptutd0PfrTItrA02JWwwstlBIOAcvgFp86MHWufQsnrkPVhxBjHXq65aIkSejtJjDg== dependencies: "@grpc/grpc-js" "^0.6.12" "@grpc/proto-loader" "^0.5.1" - "@types/fs-extra" "^8.0.1" "@types/long" "^4.0.0" abort-controller "^3.0.0" duplexify "^3.6.0" @@ -6936,15 +6549,16 @@ google-gax@^1.7.5: node-fetch "^2.6.0" protobufjs "^6.8.8" retry-request "^4.0.0" - semver "^7.0.0" + semver "^6.0.0" walkdir "^0.4.0" -google-p12-pem@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" - integrity sha1-M8RqsCGqc0+gMys5YKmj/8svMXc= +google-p12-pem@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-1.0.4.tgz#b77fb833a2eb9f7f3c689e2e54f095276f777605" + integrity sha512-SwLAUJqUfTB2iS+wFfSS/G9p7bt4eWcc2LyfvmUXe7cWp6p3mpxDo6LLI29MXdU6wvPcQ/up298X7GMC5ylAlA== dependencies: - node-forge "^0.7.1" + node-forge "^0.8.0" + pify "^4.0.0" google-p12-pem@^2.0.0: version "2.0.4" @@ -6987,15 +6601,16 @@ graphviz@0.0.9: dependencies: temp "~0.4.0" -gtoken@^1.2.1: - version "1.2.3" - resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" - integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== +gtoken@^2.3.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-2.3.3.tgz#8a7fe155c5ce0c4b71c886cfb282a9060d94a641" + integrity sha512-EaB49bu/TCoNeQjhCYKI/CurooBKkGxIqFHsWABW0b25fobBYVTMe84A8EBVVZhl8emiUdNypil9huMOTmyAnw== dependencies: - google-p12-pem "^0.1.0" - jws "^3.0.0" - mime "^1.4.1" - request "^2.72.0" + gaxios "^1.0.4" + google-p12-pem "^1.0.0" + jws "^3.1.5" + mime "^2.2.0" + pify "^4.0.0" gtoken@^4.1.0: version "4.1.4" @@ -7020,17 +6635,17 @@ gulp-clang-format@^1.0.27: through2 "^2.0.3" gulp-conventional-changelog@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/gulp-conventional-changelog/-/gulp-conventional-changelog-2.0.3.tgz#80d3b558365bb0d662f61b20257d4084bbed6b07" - integrity sha512-DoDjADVYJTxTrBBBEZg+ISV8tNDPPQZeaTQ+cqXEyfNusjWpiCxOddrr/q0EV/aocTFjsCHNtWP/JGJq9lzmbA== + version "2.0.29" + resolved "https://registry.yarnpkg.com/gulp-conventional-changelog/-/gulp-conventional-changelog-2.0.29.tgz#5068ed24a0baa8ae365420707521903690d41108" + integrity sha512-YWqUYtLyljb1bhRUBsT0mYA+WNIvwKJWzomf4/b2k0G5MfAqQUUPtIRaiE5sV35uhgkPPvOCTOjjudrBUhStyw== dependencies: add-stream "^1.0.0" - concat-stream "^1.6.0" - conventional-changelog "^2.0.3" + concat-stream "^2.0.0" + conventional-changelog "^3.1.18" fancy-log "^1.3.2" object-assign "^4.0.1" plugin-error "^1.0.1" - through2 "^2.0.0" + through2 "^3.0.0" gulp-diff@^1.0.0: version "1.0.0" @@ -7053,14 +6668,14 @@ gulp-filter@^5.1.0: streamfilter "^1.0.5" gulp-git@^2.7.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/gulp-git/-/gulp-git-2.8.0.tgz#c2b8e27566a008daccd0f235fec24a584c49abdd" - integrity sha512-45pahZGIcsb6eCJS9EGCdXqYBbxE1dtSbS03iXIF3dHHor1r37KMqwoQQJv1SXJjpLKc6ei+rdvIl7Ar6tB+ow== + version "2.10.1" + resolved "https://registry.yarnpkg.com/gulp-git/-/gulp-git-2.10.1.tgz#218615c94bbf90660c1cb07a37054041d5e4f2eb" + integrity sha512-qiXYYDXchMZU/AWAgtphi4zbJb/0gXgfPw7TlZwu/7qPS3Bdcc3zbVe1B0xY9S8on6RQTmWoi+KaTGACIXQeNg== dependencies: any-shell-escape "^0.1.1" fancy-log "^1.3.2" lodash.template "^4.4.0" - plugin-error "^0.1.2" + plugin-error "^1.0.1" require-dir "^1.0.0" strip-bom-stream "^3.0.0" through2 "^2.0.3" @@ -7131,18 +6746,18 @@ hammerjs@2.0.8: integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE= handle-thing@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" - integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== -handlebars@^4.0.2, handlebars@^4.0.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482" - integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA== +handlebars@^4.0.3, handlebars@^4.4.0: + version "4.7.5" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.5.tgz#3105d3f54038976bd54e5ae0c711c70d4ed040f8" + integrity sha512-PiM2ZRLZ0X+CIRSX66u7tkQi3rzrlSHAuioMBI1XP8DsfDaXEA+sD7Iyyoz4QACFuhX5z+IimN+n3BFWvvgWrQ== dependencies: neo-async "^2.6.0" - optimist "^0.6.1" source-map "^0.6.1" + yargs "^14.2.3" optionalDependencies: uglify-js "^3.1.4" @@ -7169,7 +6784,7 @@ har-validator@~5.0.3: ajv "^5.1.0" har-schema "^2.0.0" -har-validator@~5.1.0: +har-validator@~5.1.3: version "5.1.3" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== @@ -7223,21 +6838,11 @@ has-gulplog@^0.1.0: dependencies: sparkles "^1.0.0" -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -has-symbols@^1.0.1: +has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -7269,7 +6874,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.0, has@^1.0.1, has@^1.0.3: +has@^1.0.0, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -7339,26 +6944,21 @@ home-dir@^1.0.0: integrity sha1-KRfrRL3JByztqUJXlUOEfjAX/k4= homedir-polyfill@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" - integrity sha1-TCu8inWJmP7r9e1oWA921GdotLw= + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: - version "2.7.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" - integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w== - -hosted-git-info@^2.7.1: - version "2.8.5" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" - integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== +hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== hosted-git-info@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.2.tgz#8b7e3bd114b59b51786f8bade0f39ddc80275a97" - integrity sha512-ezZMWtHXm7Eb7Rq4Mwnx2vs79WUx2QmRg3+ZqeGroKzfDO+EprOcgRPYghsOP9JuYBfK18VojmRTGCg8Ma+ktw== + version "3.0.4" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-3.0.4.tgz#be4973eb1fd2737b11c9c7c19380739bb249f60d" + integrity sha512-4oT62d2jwSDBbLLFLZE+1vPuQ1h8p9wjrJ8Mqx5TjsyWmBMV5B13eJqn8pvluqubLf3cJPTfiYCIwNwDNmzScQ== dependencies: lru-cache "^5.1.1" @@ -7402,16 +7002,6 @@ http-deceiver@^1.2.7: resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= -http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - http-errors@1.7.2: version "1.7.2" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" @@ -7423,6 +7013,16 @@ http-errors@1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" @@ -7457,16 +7057,7 @@ http-proxy-middleware@0.19.1: lodash "^4.17.11" micromatch "^3.1.10" -http-proxy@^1.13.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" - integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== - dependencies: - eventemitter3 "^3.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - -http-proxy@^1.17.0, http-proxy@^1.8.1: +http-proxy@^1.13.0, http-proxy@^1.17.0, http-proxy@^1.8.1: version "1.18.0" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== @@ -7512,7 +7103,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -https-proxy-agent@1.0.0, https-proxy-agent@^1.0.0: +https-proxy-agent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" integrity sha1-NffabEjOTdv6JkiRrFk+5f+GceY= @@ -7521,7 +7112,7 @@ https-proxy-agent@1.0.0, https-proxy-agent@^1.0.0: debug "2" extend "3" -https-proxy-agent@^2.2.1: +https-proxy-agent@^2.2.1, https-proxy-agent@^2.2.3: version "2.2.4" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== @@ -7529,6 +7120,14 @@ https-proxy-agent@^2.2.1: agent-base "^4.3.0" debug "^3.1.0" +https-proxy-agent@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81" + integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg== + dependencies: + agent-base "^4.3.0" + debug "^3.1.0" + https-proxy-agent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" @@ -7537,6 +7136,14 @@ https-proxy-agent@^4.0.0: agent-base "5" debug "4" +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -7553,14 +7160,7 @@ husky@^0.14.3: normalize-path "^1.0.0" strip-indent "^2.0.0" -iconv-lite@0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" - integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -7568,9 +7168,9 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: safer-buffer ">= 2.1.2 < 3" ieee754@^1.1.4: - version "1.1.12" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" - integrity sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA== + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== iferr@^0.1.5: version "0.1.5" @@ -7578,9 +7178,9 @@ iferr@^0.1.5: integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== dependencies: minimatch "^3.0.4" @@ -7689,7 +7289,7 @@ inherits@1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" integrity sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js= -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -7699,7 +7299,7 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= -inherits@2.0.3, inherits@~2.0.0: +inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -7756,9 +7356,9 @@ internal-ip@^4.3.0: ipaddr.js "^1.9.0" interpret@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= + version "1.2.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== invariant@^2.2.2: version "2.2.4" @@ -7767,11 +7367,6 @@ invariant@^2.2.2: dependencies: loose-envify "^1.0.0" -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" @@ -7782,17 +7377,12 @@ ip-regex@^2.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip@^1.1.0, ip@^1.1.5: +ip@1.1.5, ip@^1.1.0, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -ipaddr.js@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" - integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== - -ipaddr.js@^1.9.0: +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== @@ -7870,19 +7460,12 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-builtin-module@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" - integrity sha1-VAVy0096wxGfj3bDDLwbHgN6/74= - dependencies: - builtin-modules "^1.0.0" - -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-buffer@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" + integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== -is-callable@^1.1.5: +is-callable@^1.1.4, is-callable@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== @@ -7921,9 +7504,9 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== is-descriptor@^0.1.0: version "0.1.6" @@ -7948,18 +7531,6 @@ is-directory@^0.3.1: resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= -is-dotfile@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" - integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= - -is-equal-shallow@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" - integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= - dependencies: - is-primitive "^2.0.0" - is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -7972,22 +7543,15 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" -is-extglob@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" - integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= - is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= is-finite@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" - integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko= - dependencies: - number-is-nan "^1.0.0" + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== is-fullwidth-code-point@^1.0.0: version "1.0.0" @@ -8006,13 +7570,6 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^2.0.0, is-glob@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" - integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= - dependencies: - is-extglob "^1.0.0" - is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -8020,14 +7577,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" - integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= - dependencies: - is-extglob "^2.1.1" - -is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -8058,9 +7608,9 @@ is-my-ip-valid@^1.0.0: integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ== is-my-json-valid@^2.12.4: - version "2.17.2" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz#6b2103a288e94ef3de5cf15d29dd85fc4b78d65c" - integrity sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg== + version "2.20.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz#1345a6fca3e8daefc10d0fa77067f54cedafd59a" + integrity sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA== dependencies: generate-function "^2.0.0" generate-object-property "^1.1.0" @@ -8073,13 +7623,6 @@ is-npm@^1.0.0: resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -8087,11 +7630,6 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -8102,6 +7640,11 @@ is-obj@^1.0.0, is-obj@^1.0.1: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -8145,7 +7688,7 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -8159,22 +7702,12 @@ is-plain-object@^3.0.0: dependencies: isobject "^4.0.0" -is-posix-bracket@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" - integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= - -is-primitive@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" - integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= - is-promise@^2.1, is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= -is-property@^1.0.0: +is-property@^1.0.0, is-property@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= @@ -8191,14 +7724,7 @@ is-reference@^1.1.2: dependencies: "@types/estree" "0.0.39" -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - -is-regex@^1.0.5: +is-regex@^1.0.4, is-regex@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== @@ -8237,6 +7763,11 @@ is-retry-allowed@^1.0.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== +is-running@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-running/-/is-running-2.1.0.tgz#30a73ff5cc3854e4fc25490809e9f5abf8de09e0" + integrity sha1-MKc/9cw4VOT8JUkICen1q/jeCeA= + is-stream-ended@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda" @@ -8252,11 +7783,6 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-subset@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6" - integrity sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY= - is-svg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" @@ -8265,20 +7791,20 @@ is-svg@^3.0.0: html-comment-regex "^1.1.0" is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== dependencies: - has-symbols "^1.0.0" + has-symbols "^1.0.1" -is-text-path@^1.0.0: +is-text-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= dependencies: text-extensions "^1.0.0" -is-typedarray@~1.0.0: +is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= @@ -8340,9 +7866,11 @@ isarray@2.0.1: integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= isbinaryfile@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.2.tgz#4a3e974ec0cba9004d3fc6cde7209ea69368a621" - integrity sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE= + version "3.0.3" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== + dependencies: + buffer-alloc "^1.2.0" isemail@1.x.x: version "1.2.0" @@ -8392,9 +7920,9 @@ istanbul-lib-coverage@^3.0.0: integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== istanbul-lib-instrument@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.0.tgz#53321a7970f076262fd3292c8f9b2e4ac544aae1" - integrity sha512-Nm4wVHdo7ZXSG30KjZ2Wl5SU/Bw7bDx1PdaiIFzEStdjs0H12mOTncn1GVYuqQSaZxpg87VGBRsVRPGD2cD1AQ== + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" + integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== dependencies: "@babel/core" "^7.7.5" "@babel/parser" "^7.7.5" @@ -8421,12 +7949,7 @@ istanbul-reports@^1.3.0: dependencies: handlebars "^4.0.3" -jasmine-core@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.1.0.tgz#a4785e135d5df65024dfc9224953df585bd2766c" - integrity sha1-pHheE11d9lAk38kiSVPfWFvSdmw= - -jasmine-core@^3.3, jasmine-core@~3.5.0: +jasmine-core@^3.1.0, jasmine-core@^3.3, jasmine-core@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.5.0.tgz#132c23e645af96d85c8bca13c8758b18429fc1e4" integrity sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA== @@ -8436,11 +7959,6 @@ jasmine-core@~2.8.0: resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e" integrity sha1-vMl5rh+f0FcB5F5S5l06XWPxok4= -jasmine-core@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.3.0.tgz#dea1cdc634bc93c7e0d4ad27185df30fa971b10e" - integrity sha512-3/xSmG/d35hf80BEN66Y6g9Ca5l/Isdeg/j6zvbTYlTzeKinzmaTM4p9am5kYqOmE05D7s1t8FGjzdSnbUbceA== - jasmine-reporters@~2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/jasmine-reporters/-/jasmine-reporters-2.3.2.tgz#898818ffc234eb8b3f635d693de4586f95548d43" @@ -8458,15 +7976,7 @@ jasmine@2.8.0: glob "^7.0.6" jasmine-core "~2.8.0" -jasmine@^3.1.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.3.1.tgz#d61bb1dd8888859bd11ea83074a78ee13d949905" - integrity sha512-/vU3/H7U56XsxIXHwgEuWpCgQ0bRi2iiZeUpx7Nqo8n1TpoDHfZhkPIc7CO8I4pnMzYsi3XaSZEiy8cnTfujng== - dependencies: - glob "^7.0.6" - jasmine-core "~3.3.0" - -jasmine@~3.5.0: +jasmine@^3.1.0, jasmine@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.5.0.tgz#7101eabfd043a1fc82ac24e0ab6ec56081357f9e" integrity sha512-DYypSryORqzsGoMazemIHUfMkXM7I7easFaxAvNM3Mr6Xz3Fy36TupTrAOxZWN8MVKEU5xECv22J4tUQf3uBzQ== @@ -8479,7 +7989,7 @@ jasminewd2@^2.1.0: resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.2.0.tgz#e37cf0b17f199cce23bea71b2039395246b4ec4e" integrity sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4= -jest-worker@24.9.0: +jest-worker@24.9.0, jest-worker@^24.0.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== @@ -8487,18 +7997,10 @@ jest-worker@24.9.0: merge-stream "^2.0.0" supports-color "^6.1.0" -jest-worker@^24.0.0: - version "24.6.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" - integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ== - dependencies: - merge-stream "^1.0.1" - supports-color "^6.1.0" - jest-worker@^25.1.0: - version "25.1.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.1.0.tgz#75d038bad6fdf58eba0d2ec1835856c497e3907a" - integrity sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg== + version "25.2.6" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-25.2.6.tgz#d1292625326794ce187c38f51109faced3846c58" + integrity sha512-FJn9XDUSxcOR4cwDzRfL1z56rUofNTFs539FGASpd50RHdb6EVkhxQqktodW2mI49l+W3H+tFJDotCHUQF6dmA== dependencies: merge-stream "^2.0.0" supports-color "^7.0.0" @@ -8677,14 +8179,7 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" - integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== - dependencies: - minimist "^1.2.0" - -json5@^2.1.2: +json5@^2.1.0, json5@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== @@ -8721,9 +8216,9 @@ jsonpointer@^4.0.0: integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk= jsonschema@^1.0.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.5.tgz#bab69d97fa28946aec0a56a9cc266d23fe80ae61" - integrity sha512-kVTF+08x25PQ0CjuVc0gRM9EUPb0Fe9Ln/utFOgcdxEIOHuU7ooBk/UPTd7t1M91pP35m0MU1T8M5P7vP1bRRw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.6.tgz#52b0a8e9dc06bbae7295249d03e4b9faee8a0c0b" + integrity sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA== jsontoxml@0.0.11: version "0.0.11" @@ -8781,25 +8276,15 @@ jszip@^2.4.0: dependencies: pako "~1.0.2" -jszip@^3.1.3: - version "3.1.5" - resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" - integrity sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ== +jszip@^3.1.3, jszip@^3.2.2: + version "3.3.0" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.3.0.tgz#29d72c21a54990fa885b11fc843db320640d5271" + integrity sha512-EJ9k766htB1ZWnsV5ZMDkKLgA+201r/ouFF8R2OigVjVdcm2rurcBrrdXaeqBJbqnUVMko512PYmlncBKE1Huw== dependencies: - core-js "~2.3.0" - es6-promise "~3.0.2" - lie "~3.1.0" + lie "~3.3.0" pako "~1.0.2" - readable-stream "~2.0.6" - -jwa@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.6.tgz#87240e76c9808dbde18783cf2264ef4929ee50e6" - integrity sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.10" - safe-buffer "^5.0.1" + readable-stream "~2.3.6" + set-immediate-shim "~1.0.1" jwa@^1.4.1: version "1.4.1" @@ -8819,7 +8304,7 @@ jwa@^2.0.0: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: +jws@^3.1.3, jws@^3.1.5, jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -8827,14 +8312,6 @@ jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" -jws@^3.1.3: - version "3.1.5" - resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.5.tgz#80d12d05b293d1e841e7cb8b4e69e561adcf834f" - integrity sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ== - dependencies: - jwa "^1.1.5" - safe-buffer "^5.0.1" - jws@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" @@ -8844,12 +8321,12 @@ jws@^4.0.0: safe-buffer "^5.0.1" karma-browserstack-launcher@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/karma-browserstack-launcher/-/karma-browserstack-launcher-1.3.0.tgz#61fe3d36b1cf10681e40f9d874bf37271fb1c674" - integrity sha512-LrPf5sU/GISkEElWyoy06J8x0c8BcOjjOwf61Wqu6M0aWQu0Eoqm9yh3xON64/ByST/CEr0GsWiREQ/EIEMd4Q== + version "1.5.1" + resolved "https://registry.yarnpkg.com/karma-browserstack-launcher/-/karma-browserstack-launcher-1.5.1.tgz#4caf4cd476a76d3c88205818d8994fc170a68fb4" + integrity sha512-zt9Ukow5A9WZHZXCFVO/h5kRsAdaZYeMNJK9Uan8v42amQXt3B/DZVxl24NCcAIxufKjW13UWd9iJ9knG9OCYw== dependencies: - browserstack "1.5.0" - browserstacktunnel-wrapper "~2.0.1" + browserstack "~1.5.1" + browserstack-local "^1.3.7" q "~1.5.0" karma-chrome-launcher@^2.2.0: @@ -8861,9 +8338,9 @@ karma-chrome-launcher@^2.2.0: which "^1.2.1" karma-firefox-launcher@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-1.2.0.tgz#64fe03dd10300f9754d48f9ebfbf31f6c94a200c" - integrity sha512-j9Zp8M8+VLq1nI/5xZGfzeaEPtGQ/vk3G+Y8vpmFWLvKLNZ2TDjD6cu2dUu7lDbu1HXNgatsAX4jgCZTkR9qhQ== + version "1.3.0" + resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-1.3.0.tgz#ebcbb1d1ddfada6be900eb8fae25bcf2dcdc8171" + integrity sha512-Fi7xPhwrRgr+94BnHX0F5dCl1miIW4RHnzjIGxF8GaIEp7rNqX7LSi7ok63VXs3PS/5MQaQMhGxw+bvD+pibBQ== dependencies: is-wsl "^2.1.0" @@ -8965,9 +8442,9 @@ kind-of@^5.0.0: integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== klaw@^1.0.0: version "1.3.1" @@ -8990,13 +8467,6 @@ lazystream@^1.0.0, lazystream@~1.0.0: dependencies: readable-stream "^2.0.5" -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - lcid@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" @@ -9045,10 +8515,10 @@ license-webpack-plugin@2.1.3: "@types/webpack-sources" "^0.1.5" webpack-sources "^1.2.0" -lie@~3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" - integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4= +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== dependencies: immediate "~3.0.5" @@ -9097,7 +8567,7 @@ loader-runner@^2.4.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== @@ -9106,6 +8576,15 @@ loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2. emojis-list "^2.0.0" json5 "^1.0.1" +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -9174,7 +8653,7 @@ lodash._reevaluate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= -lodash._reinterpolate@^3.0.0, lodash._reinterpolate@~3.0.0: +lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= @@ -9273,6 +8752,11 @@ lodash.isinteger@^4.0.4: resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= +lodash.ismatch@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" + integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= + lodash.isnumber@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" @@ -9323,11 +8807,6 @@ lodash.memoize@^4.1.2: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.noop@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" - integrity sha1-OBiPTWUKOkdCWEObluxFsyYXEzw= - lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -9359,11 +8838,11 @@ lodash.template@^3.0.0: lodash.templatesettings "^3.0.0" lodash.template@^4.0.2, lodash.template@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0" - integrity sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A= + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== dependencies: - lodash._reinterpolate "~3.0.0" + lodash._reinterpolate "^3.0.0" lodash.templatesettings "^4.0.0" lodash.templatesettings@^3.0.0: @@ -9375,11 +8854,11 @@ lodash.templatesettings@^3.0.0: lodash.escape "^3.0.0" lodash.templatesettings@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz#2b4d4e95ba440d915ff08bc899e4553666713316" - integrity sha1-K01OlbpEDZFf8IvImeRVNmZxMxY= + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== dependencies: - lodash._reinterpolate "~3.0.0" + lodash._reinterpolate "^3.0.0" lodash.toarray@^4.4.0: version "4.4.0" @@ -9413,12 +8892,7 @@ lodash@4.11.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.11.1.tgz#a32106eb8e2ec8e82c241611414773c9df15f8bc" integrity sha1-oyEG644uyOgsJBYRQUdzyd8V+Lw= -lodash@^4.0.0, lodash@^4.16.6, lodash@^4.2.1, lodash@~4.17.2: - version "4.17.10" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" - integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== - -lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.8.0, lodash@~4.17.15: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.8.0, lodash@~4.17.15, lodash@~4.17.2: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -9459,9 +8933,9 @@ log4js@^4.0.0: streamroller "^1.0.6" loglevel@^1.6.4: - version "1.6.6" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.6.tgz#0ee6300cc058db6b3551fa1c4bf73b83bb771312" - integrity sha512-Sgr5lbboAUBo3eXCSPL4/KoVz3ROKquOjcctxmHIt+vol2DrqTQe3SwkKKuYhEiWB5kYa13YyopJ69deJ1irzQ== + version "1.6.7" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.7.tgz#b3e034233188c68b889f5b862415306f565e2c56" + integrity sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A== long@^4.0.0: version "4.0.0" @@ -9498,15 +8972,7 @@ lru-cache@2.5.0: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.5.0.tgz#d82388ae9c960becbea0c73bb9eb79b6c6ce9aeb" integrity sha1-2COIrpyWC+y+oMc7uet5tsbOmus= -lru-cache@4.1.x: - version "4.1.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" - integrity sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^4.0.1: +lru-cache@4.1.x, lru-cache@^4.0.1, lru-cache@^4.1.3: version "4.1.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== @@ -9534,9 +9000,9 @@ macos-release@^2.2.0: integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== madge@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/madge/-/madge-3.6.0.tgz#f69e7c3e15a18a195e6bcd7942cc36efabcd9b9a" - integrity sha512-r4pCwKmihtzemQq8Y7edfkAKVKFqWU/AXTnDckwf1D4HOnX/uLAyWHQ+NgEo+FqBappi8wBzWJV5sFyQO2m6FQ== + version "3.8.0" + resolved "https://registry.yarnpkg.com/madge/-/madge-3.8.0.tgz#c76538c1a8accda297009a25ceb8b29b20c99b86" + integrity sha512-bcX2QxiTwWvZrNM+XkmZY1SPl18C2HGaQGhroj3YzqSRxQ1ns7WXCYDyGCfZwp/uLibnNd6IOWrRLOkCS+lpAg== dependencies: chalk "^3.0.0" commander "^4.0.1" @@ -9560,19 +9026,19 @@ madge@^3.6.0: rc "^1.2.7" walkdir "^0.4.1" -magic-string@0.25.4, magic-string@^0.25.2: +magic-string@0.25.4: version "0.25.4" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.4.tgz#325b8a0a79fc423db109b77fd5a19183b7ba5143" integrity sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw== dependencies: sourcemap-codec "^1.4.4" -magic-string@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.0.tgz#1f3696f9931ff0a1ed4c132250529e19cad6759b" - integrity sha512-Msbwa9oNYNPjwVh9ury5X2BHbTFWoirTlzuf4X+pIoSOQVKNRJHXTx1WmKYuXzRM4QZFv8dGXyZvhDMmWhGLPw== +magic-string@^0.25.2: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== dependencies: - sourcemap-codec "^1.4.1" + sourcemap-codec "^1.4.4" make-dir@^1.0.0: version "1.3.0" @@ -9589,10 +9055,10 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.0.tgz#1b5f39f6b9270ed33f9f054c5c0f84304989f801" - integrity sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw== +make-dir@^3.0.0, make-dir@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.2.tgz#04a1acbf22221e1d6ef43559f43e05a90dbb4392" + integrity sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w== dependencies: semver "^6.0.0" @@ -9602,15 +9068,15 @@ make-error@^1.1.1: integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.0.tgz#a8e3fe41d3415dd656fe7b8e8172e1fb4458b38d" - integrity sha512-nFr/vpL1Jc60etMVKeaLOqfGjMMb3tAHFVJWxHOFCFS04Zmd7kGlMxo0l1tzfhoQje0/UPnd0X8OeGUiXXnfPA== + version "5.0.2" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd" + integrity sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag== dependencies: agentkeepalive "^3.4.1" cacache "^12.0.0" http-cache-semantics "^3.8.1" http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.1" + https-proxy-agent "^2.2.3" lru-cache "^5.1.1" mississippi "^3.0.0" node-fetch-npm "^2.0.2" @@ -9652,7 +9118,7 @@ map-obj@^2.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= -map-stream@~0.0.7: +map-stream@0.0.7, map-stream@~0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= @@ -9699,11 +9165,6 @@ materialize-css@1.0.0: resolved "https://registry.yarnpkg.com/materialize-css/-/materialize-css-1.0.0.tgz#8d5db1c4a81c6d65f3b2e2ca83a8e08daa24d1be" integrity sha512-4/oecXl8y/1i8RDZvyvwAICyqwNoKU4or5uf8uoAd74k76KzZ0Llym4zhJ5lLNUskcqjO0AuMcvNyDkpz8Z6zw== -math-random@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.1.tgz#8b3aac588b8a66e4975e3cdea67f7bb329601fac" - integrity sha1-izqsWIuKZuSXXjzepn97sylgH6w= - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -9718,18 +9179,16 @@ mdn-data@2.0.4: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== +mdn-data@2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" + integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - mem@^4.0.0: version "4.3.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" @@ -9761,20 +9220,6 @@ memoizee@^0.4.14: next-tick "1" timers-ext "^0.1.5" -memoizee@^0.4.3: - version "0.4.12" - resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.12.tgz#780e99a219c50c549be6d0fc61765080975c58fb" - integrity sha512-sprBu6nwxBWBvBOh5v2jcsGqiGLlL2xr2dLub3vR8dnE8YB17omwtm/0NSHl8jjNbcsJd5GMWJAnTSVe/O0Wfg== - dependencies: - d "1" - es5-ext "^0.10.30" - es6-weak-map "^2.0.2" - event-emitter "^0.3.5" - is-promise "^2.1" - lru-queue "0.1" - next-tick "1" - timers-ext "^0.1.2" - memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -9822,6 +9267,21 @@ meow@^4.0.0: redent "^2.0.0" trim-newlines "^2.0.0" +meow@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" + integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== + dependencies: + camelcase-keys "^4.0.0" + decamelize-keys "^1.0.0" + loud-rejection "^1.0.0" + minimist-options "^3.0.1" + normalize-package-data "^2.3.4" + read-pkg-up "^3.0.0" + redent "^2.0.0" + trim-newlines "^2.0.0" + yargs-parser "^10.0.0" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -9834,13 +9294,6 @@ merge-source-map@^1.1.0: dependencies: source-map "^0.6.1" -merge-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= - dependencies: - readable-stream "^2.0.1" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -9851,25 +9304,6 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^2.3.11: - version "2.3.11" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" - integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= - dependencies: - arr-diff "^2.0.0" - array-unique "^0.2.1" - braces "^1.8.2" - expand-brackets "^0.1.4" - extglob "^0.3.1" - filename-regex "^2.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.1" - kind-of "^3.0.2" - normalize-path "^2.0.1" - object.omit "^2.0.0" - parse-glob "^3.0.4" - regex-cache "^0.4.2" - micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -9897,57 +9331,28 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.42.0, "mime-db@>= 1.40.0 < 2": - version "1.42.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" - integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== - -mime-db@1.43.0: +mime-db@1.43.0, "mime-db@>= 1.43.0 < 2": version "1.43.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - -mime-types@^2.1.11, mime-types@~2.1.7: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -mime-types@^2.1.12, mime-types@^2.1.16, mime-types@^2.1.25, mime-types@~2.1.17, mime-types@~2.1.18, mime-types@~2.1.19: +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@^2.1.16, mime-types@^2.1.25, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.7: version "2.1.26" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== dependencies: mime-db "1.43.0" -mime-types@~2.1.24: - version "2.1.25" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" - integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== - dependencies: - mime-db "1.42.0" - mime@1.6.0, mime@^1.4.1, mime@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.0.3, mime@^2.2.0, mime@^2.4.4: +mime@^2.0.3, mime@^2.2.0, mime@^2.3.1, mime@^2.4.4: version "2.4.4" resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== -mime@^2.3.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6" - integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w== - mimic-fn@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" @@ -10020,17 +9425,12 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@1.1.x: - version "1.1.3" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" - integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= - -minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0: +minimist@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -minimist@^1.2.5: +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== @@ -10061,7 +9461,7 @@ minipass-pipeline@^1.2.2: dependencies: minipass "^3.0.0" -minipass@^2.3.4, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: +minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== @@ -10069,14 +9469,6 @@ minipass@^2.3.4, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: safe-buffer "^5.1.2" yallist "^3.0.0" -minipass@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" - integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - minipass@^3.0.0, minipass@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.1.tgz#7607ce778472a185ad6d89082aa2070f79cedcd5" @@ -10084,7 +9476,7 @@ minipass@^3.0.0, minipass@^3.1.1: dependencies: yallist "^4.0.0" -minizlib@^1.1.1, minizlib@^1.2.1: +minizlib@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== @@ -10108,19 +9500,19 @@ mississippi@^3.0.0: through2 "^2.0.0" mixin-deep@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" - integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5, mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1, mkdirp@~0.5.x: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +mkdirp@0.5, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@~0.5.1, mkdirp@~0.5.x: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" + integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== dependencies: - minimist "0.0.8" + minimist "^1.2.5" mkdirp@0.5.0: version "0.5.0" @@ -10160,20 +9552,20 @@ module-lookup-amd@^6.1.0: requirejs-config-file "^3.1.1" moment@2.x.x: - version "2.22.2" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" - integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= + version "2.24.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== morgan@^1.8.2: - version "1.9.1" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" - integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA== + version "1.10.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== dependencies: - basic-auth "~2.0.0" + basic-auth "~2.0.1" debug "2.6.9" - depd "~1.1.2" + depd "~2.0.0" on-finished "~2.3.0" - on-headers "~1.0.1" + on-headers "~1.0.2" move-concurrently@^1.0.1: version "1.0.1" @@ -10202,7 +9594,7 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.1, ms@^2.0.0: +ms@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== @@ -10212,7 +9604,7 @@ ms@^0.7.1: resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" integrity sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8= -ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -10271,10 +9663,10 @@ mz@2.4.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nan@^2.9.2: - version "2.12.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" - integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== nanomatch@^1.2.9: version "1.2.13" @@ -10303,20 +9695,6 @@ nash@^3.0.0: lodash "^4.17.5" minimist "^1.1.0" -needle@^2.2.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.4.tgz#51931bff82533b1928b7d1d69e01f1b00ffd2a4e" - integrity sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA== - dependencies: - debug "^2.1.2" - iconv-lite "^0.4.4" - sax "^1.2.4" - -negotiator@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" - integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -10327,7 +9705,12 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== -next-tick@1, next-tick@~1.0.0: +next-tick@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +next-tick@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= @@ -10345,9 +9728,9 @@ node-emoji@^1.4.1: lodash.toarray "^4.4.0" node-fetch-npm@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz#7258c9046182dca345b4208eda918daf33697ff7" - integrity sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw== + version "2.0.4" + resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz#6507d0e17a9ec0be3bec516958a497cec54bf5a4" + integrity sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg== dependencies: encoding "^0.1.11" json-parse-better-errors "^1.0.0" @@ -10363,10 +9746,10 @@ node-forge@0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== -node-forge@^0.7.1: - version "0.7.6" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" - integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== +node-forge@^0.8.0: + version "0.8.5" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.8.5.tgz#57906f07614dc72762c84cef442f427c0e1b86ee" + integrity sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q== node-forge@^0.9.0: version "0.9.1" @@ -10402,42 +9785,10 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz#3070040716afdc778747b61b6887bf78880b80fc" - integrity sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A== - dependencies: - detect-libc "^1.0.2" - mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" - -node-releases@^1.1.40: - version "1.1.41" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.41.tgz#57674a82a37f812d18e3b26118aefaf53a00afed" - integrity sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg== - dependencies: - semver "^6.3.0" - -node-releases@^1.1.44: - version "1.1.45" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.45.tgz#4cf7e9175d71b1317f15ffd68ce63bce1d53e9f2" - integrity sha512-cXvGSfhITKI8qsV116u2FTzH5EWZJfgG7d4cpqwF8I8+1tWpD6AsvvGRKq2onR0DNj1jfqsjkXZsm14JMS7Cyg== - dependencies: - semver "^6.3.0" - -node-releases@^1.1.46: - version "1.1.47" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4" - integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA== - dependencies: - semver "^6.3.0" +node-releases@^1.1.44, node-releases@^1.1.53: + version "1.1.53" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" + integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ== node-source-walk@^4.0.0, node-source-walk@^4.2.0: version "4.2.0" @@ -10468,14 +9819,6 @@ nopt@3.0.x, nopt@^3.0.1: dependencies: abbrev "1" -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= - dependencies: - abbrev "1" - osenv "^0.1.4" - nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -10483,7 +9826,7 @@ nopt@~1.0.10: dependencies: abbrev "1" -normalize-package-data@^2.0.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -10493,22 +9836,12 @@ normalize-package-data@^2.0.0: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" - integrity sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw== - dependencies: - hosted-git-info "^2.1.4" - is-builtin-module "^1.0.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - normalize-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= -normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: +normalize-path@^2.0.0, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= @@ -10541,11 +9874,18 @@ normalize-url@^3.0.0: integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@6.1.1: +npm-package-arg@6.1.1, npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: version "6.1.1" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== @@ -10555,16 +9895,6 @@ npm-package-arg@6.1.1: semver "^5.6.0" validate-npm-package-name "^3.0.0" -npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.0.tgz#15ae1e2758a5027efb4c250554b85a737db7fcc1" - integrity sha512-zYbhP2k9DbJhA0Z3HKUePUgdB1x7MfIfKssC+WLPFMKTBZKpZh5m13PgexJjCq6KW7j17r0jHWcCpxEqnnncSA== - dependencies: - hosted-git-info "^2.6.0" - osenv "^0.1.5" - semver "^5.5.0" - validate-npm-package-name "^3.0.0" - npm-package-arg@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-7.0.0.tgz#52cdf08b491c0c59df687c4c925a89102ef794a5" @@ -10576,20 +9906,13 @@ npm-package-arg@^7.0.0: validate-npm-package-name "^3.0.0" npm-packlist@^1.1.12: - version "1.2.0" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.2.0.tgz#55a60e793e272f00862c7089274439a4cc31fc7f" - integrity sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ== - dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" - -npm-packlist@^1.1.6: - version "1.4.0" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.0.tgz#b2c0867af2a396e0734343d2b6b3f7934db935f2" - integrity sha512-zCAmKshsFx2MhOsXdYmZd1DO2d8ts80kVASSWX6lv8654i0edCnNCoEqwVsMygl1BSroCPW6Zh5Dcw+ann775g== + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== dependencies: ignore-walk "^3.0.1" npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" npm-pick-manifest@3.0.2, npm-pick-manifest@^3.0.0: version "3.0.2" @@ -10601,9 +9924,9 @@ npm-pick-manifest@3.0.2, npm-pick-manifest@^3.0.0: semver "^5.4.1" npm-registry-fetch@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.2.tgz#2b1434f93ccbe6b6385f8e45f45db93e16921d7a" - integrity sha512-Z0IFtPEozNdeZRPh3aHHxdG+ZRpzcbQaJLthsm3VhNf6DScicTFRHZzK82u8RsJUsUHkX+QH/zcB/5pmd20H4A== + version "4.0.3" + resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz#3c2179e39e04f9348b1c2979545951d36bee8766" + integrity sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw== dependencies: JSONStream "^1.3.4" bluebird "^3.5.1" @@ -10620,16 +9943,6 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - nth-check@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -10672,7 +9985,7 @@ object-assign@^3.0.0: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= -object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -10691,20 +10004,15 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== - object-inspect@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== object-is@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" - integrity sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY= + version "1.0.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.2.tgz#6b80eb84fe451498f65007982f035a5b445edec4" + integrity sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ== object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" @@ -10738,15 +10046,7 @@ object.defaults@^1.1.0: for-own "^1.0.0" isobject "^3.0.0" -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" - -object.getownpropertydescriptors@^2.1.0: +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== @@ -10762,14 +10062,6 @@ object.map@^1.0.0: for-own "^1.0.0" make-iterator "^1.0.0" -object.omit@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" - integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= - dependencies: - for-own "^0.1.4" - is-extendable "^0.1.1" - object.pick@^1.2.0, object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -10799,7 +10091,7 @@ on-finished@^2.2.0, on-finished@~2.3.0: dependencies: ee-first "1.1.1" -on-headers@^1.0.0, on-headers@~1.0.1, on-headers@~1.0.2: +on-headers@^1.0.0, on-headers@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== @@ -10953,16 +10245,7 @@ os-homedir@^1.0.0, os-homedir@^1.0.1: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-locale@^3.0.0: +os-locale@^3.0.0, os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== @@ -10989,7 +10272,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.0, osenv@^0.1.4, osenv@^0.1.5: +osenv@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -11018,9 +10301,9 @@ p-finally@^1.0.0: integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= p-is-promise@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.0.0.tgz#7554e3d572109a87e1f3f53f6a7d85d1b194f4c5" - integrity sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg== + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== p-limit@^1.1.0: version "1.3.0" @@ -11029,21 +10312,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" - integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== - dependencies: - p-try "^2.0.0" - -p-limit@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== - dependencies: - p-try "^2.0.0" - -p-limit@^2.2.1, p-limit@^2.2.2: +p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1, p-limit@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== @@ -11150,22 +10419,17 @@ pako@~0.2.5: resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU= -pako@~1.0.2: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" - integrity sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg== - -pako@~1.0.5: - version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" - integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== +pako@~1.0.2, pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parallel-transform@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" - integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== dependencies: - cyclist "~0.2.2" + cyclist "^1.0.1" inherits "^2.0.3" readable-stream "^2.1.5" @@ -11195,16 +10459,6 @@ parse-github-repo-url@^1.3.0: resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A= -parse-glob@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" - integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= - dependencies: - glob-base "^0.3.0" - is-dotfile "^1.0.0" - is-extglob "^1.0.0" - is-glob "^2.0.0" - parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -11225,6 +10479,11 @@ parse-ms@^2.1.0: resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== +parse-node-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -11306,12 +10565,7 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME= - -path-parse@^1.0.6: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== @@ -11361,7 +10615,7 @@ pathval@^1.1.0: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= -pause-stream@0.0.11: +pause-stream@0.0.11, pause-stream@^0.0.11: version "0.0.11" resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= @@ -11394,15 +10648,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4: - version "2.1.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.1.1.tgz#ecdfbea7704adb5fe6fb47f9866c4c0e15e905c5" - integrity sha512-OYMyqkKzK7blWO/+XZYP6w8hH0LDvkBvdvKukti+7kqYFCiEAk+gI3DWnryapc0Dau05ugGTy0foQ6mqn4AHYA== - -picomatch@^2.0.7: - version "2.2.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" - integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== +picomatch@^2.0.4, picomatch@^2.0.7: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== pify@^2.0.0, pify@^2.3.0: version "2.3.0" @@ -11445,6 +10694,13 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + pkginfo@0.3.x: version "0.3.1" resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" @@ -11500,14 +10756,13 @@ posix-character-classes@^0.1.0: integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= postcss-calc@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.1.tgz#36d77bab023b0ecbb9789d84dcb23c4941145436" - integrity sha512-oXqx0m6tb4N3JGdmeMSc/i91KppbYsFZKdH0xMOqK8V1rJlzrKlTdokz8ozUXLVejydRN6u2IddxpcijRj2FqQ== + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.2.tgz#504efcd008ca0273120568b0792b16cdcde8aac1" + integrity sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ== dependencies: - css-unit-converter "^1.1.1" - postcss "^7.0.5" - postcss-selector-parser "^5.0.0-rc.4" - postcss-value-parser "^3.3.1" + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" postcss-colormin@^4.0.3: version "4.0.3" @@ -11757,20 +11012,20 @@ postcss-reduce-transforms@^4.0.2: postcss-value-parser "^3.0.0" postcss-selector-parser@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz#4f875f4afb0c96573d5cf4d74011aee250a7e865" - integrity sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU= + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== dependencies: - dot-prop "^4.1.1" + dot-prop "^5.2.0" indexes-of "^1.0.1" uniq "^1.0.1" -postcss-selector-parser@^5.0.0-rc.4: - version "5.0.0" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" - integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== +postcss-selector-parser@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== dependencies: - cssesc "^2.0.0" + cssesc "^3.0.0" indexes-of "^1.0.1" uniq "^1.0.1" @@ -11793,15 +11048,15 @@ postcss-unique-selectors@^4.0.1: postcss "^7.0.0" uniqs "^2.0.0" -postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.1: +postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3: version "3.3.1" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== postcss-value-parser@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9" - integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ== + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz#651ff4593aa9eda8d5d0d66593a2417aeaeb325d" + integrity sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg== postcss-values-parser@^1.5.0: version "1.5.0" @@ -11821,19 +11076,10 @@ postcss@7.0.21: source-map "^0.6.1" supports-color "^6.1.0" -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.21: - version "7.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.23.tgz#9f9759fad661b15964f3cfc3140f66f1e05eadc1" - integrity sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^7.0.2, postcss@^7.0.5: - version "7.0.26" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" - integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.27: + version "7.0.27" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9" + integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -11868,11 +11114,6 @@ prepend-http@^1.0.0, prepend-http@^1.0.1: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= -preserve@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" - integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= - pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -11885,26 +11126,21 @@ pretty-ms@^5.0.0: dependencies: parse-ms "^2.1.0" -private@^0.1.6: +private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== -process-nextick-args@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" @@ -11947,7 +11183,7 @@ promzard@0.3.0: dependencies: read "1" -protobufjs@6.8.8, protobufjs@^6.8.1, protobufjs@^6.8.6, protobufjs@^6.8.8: +protobufjs@6.8.8: version "6.8.8" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw== @@ -11966,6 +11202,25 @@ protobufjs@6.8.8, protobufjs@^6.8.1, protobufjs@^6.8.6, protobufjs@^6.8.8: "@types/node" "^10.1.0" long "^4.0.0" +protobufjs@^6.8.1, protobufjs@^6.8.6, protobufjs@^6.8.8, protobufjs@^6.8.9: + version "6.8.9" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.9.tgz#0b1adbcdaa983d369c3d9108a97c814edc030754" + integrity sha512-j2JlRdUeL/f4Z6x4aU4gj9I2LECglC+5qR2TrWb193Tla1qfdaNQTZ8I27Pt7K0Ajmvjjpft7O3KWTGciz4gpw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + protoduck@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" @@ -11995,32 +11250,39 @@ protractor@^5.4.2: webdriver-manager "^12.0.6" proxy-addr@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" - integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== dependencies: forwarded "~0.1.2" - ipaddr.js "1.9.0" + ipaddr.js "1.9.1" proxy-from-env@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" - integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= +ps-tree@=1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd" + integrity sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA== + dependencies: + event-stream "=3.3.4" + pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= -psl@^1.1.24: - version "1.7.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" - integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== public-encrypt@^4.0.0: version "4.0.3" @@ -12079,7 +11341,7 @@ punycode@^1.2.4, punycode@^1.3.2, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -12120,11 +11382,6 @@ qjobs@^1.1.4: resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== -qs@6.5.2, qs@~6.5.1, qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" @@ -12145,6 +11402,11 @@ qs@~6.4.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM= +qs@~6.5.1, qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" @@ -12173,15 +11435,6 @@ quick-lru@^1.0.0: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= -randomatic@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.0.0.tgz#d35490030eb4f7578de292ce6dfb04a91a128923" - integrity sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -12197,26 +11450,11 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" - integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= - -range-parser@^1.2.1, range-parser@~1.2.1: +range-parser@^1.2.0, range-parser@^1.2.1, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -raw-body@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" - integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== - dependencies: - bytes "3.0.0" - http-errors "1.6.3" - iconv-lite "0.4.23" - unpipe "1.0.0" - raw-body@2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" @@ -12253,14 +11491,14 @@ read-cache@^1.0.0: pify "^2.3.0" read-package-json@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.0.tgz#e3d42e6c35ea5ae820d9a03ab0c7291217fc51d5" - integrity sha512-KLhu8M1ZZNkMcrq1+0UJbR8Dii8KZUqB0Sha4mOx/bknfKI/fyrQVrG/YIt2UOtG667sD8+ee4EXMM91W9dC+A== + version "2.1.1" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.1.tgz#16aa66c59e7d4dad6288f179dd9295fd59bb98f1" + integrity sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A== dependencies: glob "^7.1.1" json-parse-better-errors "^1.0.1" normalize-package-data "^2.0.0" - slash "^1.0.0" + npm-normalize-package-bin "^1.0.0" optionalDependencies: graceful-fs "^4.1.2" @@ -12297,7 +11535,7 @@ read-pkg-up@^4.0.0: find-up "^3.0.0" read-pkg "^3.0.0" -read-pkg@^1.0.0, read-pkg@^1.1.0: +read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= @@ -12322,10 +11560,10 @@ read@1, read@1.0.7: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.3.3, readable-stream@^2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -12335,10 +11573,10 @@ read@1, read@1.0.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -"readable-stream@2 || 3", readable-stream@^3.0.1, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" - integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== +"readable-stream@2 || 3", readable-stream@^3.0.2, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" @@ -12364,20 +11602,7 @@ readable-stream@^1.1.8, readable-stream@~1.1.9: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@~2.0.0, readable-stream@~2.0.5, readable-stream@~2.0.6: +readable-stream@~2.0.0, readable-stream@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" integrity sha1-j5A0HmilPMySh4jaz80Rs265t44= @@ -12408,13 +11633,6 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@~3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" - integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== - dependencies: - picomatch "^2.0.4" - readdirp@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" @@ -12453,14 +11671,14 @@ redeyed@~2.1.0: esprima "~4.0.0" reflect-metadata@^0.1.3: - version "0.1.12" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2" - integrity sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A== + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== -regenerate-unicode-properties@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" - integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== dependencies: regenerate "^1.4.0" @@ -12469,7 +11687,7 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== -regenerator-runtime@0.13.3, regenerator-runtime@^0.13.2: +regenerator-runtime@0.13.3: version "0.13.3" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== @@ -12479,24 +11697,23 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + regenerator-runtime@^0.9.5: version "0.9.6" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" integrity sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck= -regenerator-transform@^0.14.0: - version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" - integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ== +regenerator-transform@^0.14.2: + version "0.14.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" + integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== dependencies: - private "^0.1.6" - -regex-cache@^0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" - integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== - dependencies: - is-equal-shallow "^0.1.3" + "@babel/runtime" "^7.8.4" + private "^0.1.8" regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" @@ -12507,23 +11724,24 @@ regex-not@^1.0.0, regex-not@^1.0.2: safe-regex "^1.1.0" regexp.prototype.flags@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" - integrity sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" + integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== dependencies: - define-properties "^1.1.2" + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" -regexpu-core@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" - integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== dependencies: regenerate "^1.4.0" - regenerate-unicode-properties "^8.1.0" - regjsgen "^0.5.0" - regjsparser "^0.6.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.1.0" + unicode-match-property-value-ecmascript "^1.2.0" registry-auth-token@^3.0.1: version "3.4.0" @@ -12540,15 +11758,15 @@ registry-url@^3.0.3: dependencies: rc "^1.0.1" -regjsgen@^0.5.0: +regjsgen@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== -regjsparser@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c" - integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ== +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== dependencies: jsesc "~0.5.0" @@ -12562,7 +11780,7 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.5.2, repeat-string@^1.6.1: +repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -12618,62 +11836,62 @@ request@2.75.0: tough-cookie "~2.3.0" tunnel-agent "~0.4.1" -request@2.x, request@~2.87.0: - version "2.87.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" - integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== +request@2.x, request@^2.79.0, request@^2.83.0, request@^2.87.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== dependencies: aws-sign2 "~0.7.0" - aws4 "^1.6.0" + aws4 "^1.8.0" caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.1" + combined-stream "~1.0.6" + extend "~3.0.2" forever-agent "~0.6.1" - form-data "~2.3.1" - har-validator "~5.0.3" + form-data "~2.3.2" + har-validator "~5.1.3" http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" - mime-types "~2.1.17" - oauth-sign "~0.8.2" + mime-types "~2.1.19" + oauth-sign "~0.9.0" performance-now "^2.1.0" - qs "~6.5.1" - safe-buffer "^5.1.1" - tough-cookie "~2.3.3" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" tunnel-agent "^0.6.0" - uuid "^3.1.0" + uuid "^3.3.2" -request@^2.72.0, request@^2.74.0, request@^2.79.0, request@^2.81.0, request@^2.83.0, request@^2.87.0, request@^2.88.0: - version "2.88.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" - integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== +request@~2.87.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + integrity sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw== dependencies: aws-sign2 "~0.7.0" - aws4 "^1.8.0" + aws4 "^1.6.0" caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" + combined-stream "~1.0.5" + extend "~3.0.1" forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.0" + form-data "~2.3.1" + har-validator "~5.0.3" http-signature "~1.2.0" is-typedarray "~1.0.0" isstream "~0.1.2" json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" + mime-types "~2.1.17" + oauth-sign "~0.8.2" performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.4.3" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" tunnel-agent "^0.6.0" - uuid "^3.3.2" + uuid "^3.1.0" require-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/require-dir/-/require-dir-1.0.0.tgz#c2639de72960ea1ee280279f2da35e03c6536b2d" - integrity sha512-PUJcQVTP4n6F8Un1GEEWhqnmBMfukVsL5gqwBxt7RF+nP+9hSOLJ/vSs5iUoXw1UWDgzqg9B/IIb15kfQKWsAQ== + version "1.2.0" + resolved "https://registry.yarnpkg.com/require-dir/-/require-dir-1.2.0.tgz#0d443b75e96012d3ca749cf19f529a789ae74817" + integrity sha512-LY85DTSu+heYgDqq/mK+7zFHWkttVNRXC9NKcKGyuGLdlsfbjEPrIEYdCVrx6hqnJb+xSu3Lzaoo8VnmOhhjNA== require-directory@^2.1.1: version "2.1.1" @@ -12739,7 +11957,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.8.1, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: +resolve@1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" integrity sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA== @@ -12751,17 +11969,10 @@ resolve@^0.7.1: resolved "https://registry.yarnpkg.com/resolve/-/resolve-0.7.4.tgz#395a9ef9e873fbfe12bd14408bd91bb936003d69" integrity sha1-OVqe+ehz+/4SvRRAi9kbuTYAPWk= -resolve@^1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" - integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== - dependencies: - path-parse "^1.0.6" - -resolve@^1.11.0, resolve@^1.11.1: - version "1.12.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" - integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.3.2: + version "1.15.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" + integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== dependencies: path-parse "^1.0.6" @@ -12786,13 +11997,10 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry-request@^3.0.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/retry-request/-/retry-request-3.3.2.tgz#fd8e0079e7b0dfc7056e500b6f089437db0da4df" - integrity sha512-WIiGp37XXDC6e7ku3LFoi7LCL/Gs9luGeeqvbPRb+Zl6OQMw4RCRfSaW+aLfE6lhz1R941UavE6Svl3Dm5xGIQ== - dependencies: - request "^2.81.0" - through2 "^2.0.0" +retry-axios@0.3.2, retry-axios@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/retry-axios/-/retry-axios-0.3.2.tgz#5757c80f585b4cc4c4986aa2ffd47a60c6d35e13" + integrity sha512-jp4YlI0qyDFfXiXGhkCOliBN1G7fRH03Nqy8YdShzGqbY5/9S2x/IR6C88ls2DFkbWuL3ASkP7QD3pVrNpPgwQ== retry-request@^4.0.0: version "4.1.1" @@ -12832,12 +12040,12 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2, rimraf@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" - integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: - glob "^7.0.5" + glob "^7.1.3" rimraf@3.0.0: version "3.0.0" @@ -12846,19 +12054,19 @@ rimraf@3.0.0: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.6.3, rimraf@^2.7.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" -rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== +rimraf@~2.5.2: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + integrity sha1-loAAk8vxoMhr2VtGJUZ1NcKd+gQ= dependencies: - glob "^7.1.3" + glob "^7.0.5" ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" @@ -12918,15 +12126,7 @@ rollup-plugin-terser@~4.0.4: serialize-javascript "^1.6.1" terser "^3.14.1" -rollup-pluginutils@^2.0.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.3.0.tgz#478ace04bd7f6da2e724356ca798214884738fc4" - integrity sha512-xB6hsRsjdJdIYWEyYUJy/3ki5g69wrf0luHPGNK3ZSocV6HLNfio59l3dZ3TL4xUwEKgROhFi9jOCt6c5gfUWw== - dependencies: - estree-walker "^0.5.2" - micromatch "^2.3.11" - -rollup-pluginutils@^2.8.1: +rollup-pluginutils@^2.0.1, rollup-pluginutils@^2.8.1: version "2.8.2" resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== @@ -12952,16 +12152,16 @@ rollup@~1.11.3: acorn "^6.1.1" router@^1.3.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/router/-/router-1.3.3.tgz#c142f6b5ea4d6b3359022ca95b6580bd217f89cf" - integrity sha1-wUL2tepNazNZAiypW2WAvSF/ic8= + version "1.3.5" + resolved "https://registry.yarnpkg.com/router/-/router-1.3.5.tgz#cb2f47f74fd99a77fb3bc01cc947f46b79b1790f" + integrity sha512-kozCJZUhuSJ5VcLhSb3F8fsmGXy+8HaDbKCAerR1G6tq3mnMZFMuSohbFvGv1c5oMFipijDjRZuuN/Sq5nMf3g== dependencies: - array-flatten "2.1.1" + array-flatten "3.0.0" debug "2.6.9" methods "~1.1.2" - parseurl "~1.3.2" + parseurl "~1.3.3" path-to-regexp "0.1.7" - setprototypeof "1.1.0" + setprototypeof "1.2.0" utils-merge "1.0.1" rsvp@^3.6.2: @@ -12970,9 +12170,9 @@ rsvp@^3.6.2: integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + version "2.4.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8" + integrity sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg== dependencies: is-promise "^2.1.0" @@ -12983,17 +12183,17 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@6.5.3, rxjs@^6.5.3: +rxjs@6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a" integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA== dependencies: tslib "^1.9.0" -rxjs@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" - integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== +rxjs@^6.4.0, rxjs@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c" + integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q== dependencies: tslib "^1.9.0" @@ -13045,13 +12245,13 @@ sass@1.23.3: chokidar ">=2.0.0 <4.0.0" sauce-connect-launcher@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.2.4.tgz#8d38f85242a9fbede1b2303b559f7e20c5609a1c" - integrity sha512-X2vfwulR6brUGiicXKxPm1GJ7dBEeP1II450Uv4bHGrcGOapZNgzJvn9aioea5IC5BPp/7qjKdE3xbbTBIVXMA== + version "1.3.1" + resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.1.tgz#31137f57b0f7176e1c0525b7fb09c6da746647cf" + integrity sha512-vIf9qDol3q2FlYzrKt0dr3kvec6LSjX2WS+/mVnAJIhqh1evSkPKCR2AzcJrnSmx9Xt9PtV0tLY7jYh0wsQi8A== dependencies: adm-zip "~0.4.3" async "^2.1.2" - https-proxy-agent "^2.2.1" + https-proxy-agent "^3.0.0" lodash "^4.16.6" rimraf "^2.5.4" @@ -13066,7 +12266,7 @@ saucelabs@^1.5.0: dependencies: https-proxy-agent "^2.2.1" -sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: +sax@>=0.6.0, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -13080,20 +12280,12 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f" - integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ== - dependencies: - ajv "^6.10.2" - ajv-keywords "^3.4.1" - -schema-utils@^2.6.1, schema-utils@^2.6.4: - version "2.6.4" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" - integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== +schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.1.0, schema-utils@^2.6.1, schema-utils@^2.6.4: + version "2.6.5" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a" + integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ== dependencies: - ajv "^6.10.2" + ajv "^6.12.0" ajv-keywords "^3.4.1" select-hose@^2.0.0: @@ -13122,14 +12314,13 @@ selenium-webdriver@3.6.0, selenium-webdriver@^3.0.1: xml2js "^0.4.17" selenium-webdriver@^4.0.0-alpha.1: - version "4.0.0-alpha.1" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.1.tgz#cc93415e21d2dc1dfd85dfc5f6b55f3ac53933b1" - integrity sha512-z88rdjHAv3jmTZ7KSGUkTvo4rGzcDGMq0oXWHNIDK96Gs31JKVdu9+FMtT4KBrVoibg8dUicJDok6GnqqttO5Q== + version "4.0.0-alpha.7" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz#e3879d8457fd7ad8e4424094b7dc0540d99e6797" + integrity sha512-D4qnTsyTr91jT8f7MfN+OwY0IlU5+5FmlO5xlgRUV6hDEV8JyYx2NerdTEqDDkNq7RZDYc4VoPALk8l578RBHw== dependencies: - jszip "^3.1.3" - rimraf "^2.5.4" + jszip "^3.2.2" + rimraf "^2.7.1" tmp "0.0.30" - xml2js "^0.4.17" selfsigned@^1.10.7: version "1.10.7" @@ -13152,16 +12343,21 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" -"semver@2 || 3 || 4 || 5", semver@5.6.0, semver@^5.0.0, semver@^5.3.0, semver@^5.4.1, semver@^5.6.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" - integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +"semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== semver@5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.1.0.tgz#85f2cf8550465c4df000cf7d86f6b054106ab9e5" integrity sha1-hfLPhVBGXE3wAM99hvawVBBqueU= +semver@5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + semver@6.3.0, semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" @@ -13177,21 +12373,16 @@ semver@^4.1.0: resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= -semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.5.0, semver@^5.7.1: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.1.1.tgz#29104598a197d6cbe4733eeecbe968f7b43a9667" - integrity sha512-WfuG+fl6eh3eZ2qAf6goB7nhiCd7NPXhmyFxigB/TOkQyeLP8w8GsVehvtGNtnNmyboz4TgeK40B1Kbql/8c5A== - semver@~5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" integrity sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no= +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -13225,11 +12416,6 @@ sequencify@~0.0.7: integrity sha1-kM/xnQLgcCf9dn9erT57ldHnOAw= serialize-javascript@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" - integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== - -serialize-javascript@^1.7.0: version "1.9.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.1.tgz#cfc200aef77b600c47da9bb8149c943e798c2fdb" integrity sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A== @@ -13262,25 +12448,20 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-value@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" - integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE= - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.1" - to-object-path "^0.3.0" +set-immediate-shim@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= -set-value@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" - integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg== +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" is-extendable "^0.1.1" @@ -13302,6 +12483,11 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" @@ -13370,9 +12556,9 @@ sign-addon@0.2.0: when "3.7.7" signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== simple-swizzle@^0.2.2: version "0.2.2" @@ -13393,15 +12579,10 @@ slash@^1.0.0: dependencies: readable-stream "~1.0.31" -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - -smart-buffer@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" - integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== +smart-buffer@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" + integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== snapdragon-node@^2.0.1: version "2.1.1" @@ -13441,9 +12622,9 @@ sntp@1.x.x: hoek "2.x.x" socket.io-adapter@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b" - integrity sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs= + version "1.1.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" + integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== socket.io-client@2.1.1: version "2.1.1" @@ -13507,20 +12688,20 @@ sockjs@0.3.19: uuid "^3.0.1" socks-proxy-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" - integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== + version "4.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" + integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== dependencies: - agent-base "~4.2.0" - socks "~2.2.0" + agent-base "~4.2.1" + socks "~2.3.2" -socks@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.2.tgz#f061219fc2d4d332afb4af93e865c84d3fa26e2b" - integrity sha512-g6wjBnnMOZpE0ym6e0uHSddz9p3a+WsBaaYQaBaSCJYvrC4IXykQR9MNGjLQf38e9iIIhp3b1/Zk8YZI3KGJ0Q== +socks@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.3.tgz#01129f0a5d534d2b897712ed8aceab7ee65d78e3" + integrity sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA== dependencies: - ip "^1.1.5" - smart-buffer "^4.0.1" + ip "1.1.5" + smart-buffer "^4.1.0" sort-keys@^1.0.0: version "1.1.2" @@ -13543,11 +12724,11 @@ source-map-loader@0.2.4: loader-utils "^1.1.0" source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: - atob "^2.1.1" + atob "^2.1.2" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" @@ -13560,7 +12741,7 @@ source-map-support@0.4.3: dependencies: source-map "^0.5.3" -source-map-support@0.5.16, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.12: +source-map-support@0.5.16, source-map-support@^0.5.5, source-map-support@^0.5.6, source-map-support@~0.5.10, source-map-support@~0.5.12: version "0.5.16" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== @@ -13583,14 +12764,6 @@ source-map-support@~0.4.0: dependencies: source-map "^0.5.6" -source-map-support@~0.5.10: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -13616,17 +12789,7 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sourcemap-codec@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.1.tgz#c8fd92d91889e902a07aee392bdd2c5863958ba2" - integrity sha512-hX1eNBNuilj8yfFnECh0DzLgwKpBLMIvmhgEhixXNui8lMLBInTI8Kyxt++RwJnMNu7cAUo635L2+N1TxMJCzA== - -sourcemap-codec@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.4.tgz#c63ea927c029dd6bd9a2b7fa03b3fec02ad56e9f" - integrity sha512-CYAPYdBu34781kLHkaW3m6b/uUSyMOC2R61gcYMWooeuaGtjof86ZA/8T+qVPPt7np1085CR9hmMGrySwEc8Xg== - -sourcemap-codec@^1.4.8: +sourcemap-codec@^1.4.4, sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== @@ -13645,9 +12808,9 @@ spawn-sync@1.0.15: os-shim "^0.1.2" spawn-wrap@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.2.tgz#cff58e73a8224617b6561abdc32586ea0c82248c" - integrity sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg== + version "1.4.3" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.4.3.tgz#81b7670e170cca247d80bf5faf0cfb713bdcf848" + integrity sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw== dependencies: foreground-child "^1.5.6" mkdirp "^0.5.0" @@ -13678,9 +12841,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz#81c0ce8f21474756148bbb5f3bfc0f36bf15d76e" - integrity sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g== + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== spdy-transport@^3.0.0: version "3.0.0" @@ -13733,7 +12896,7 @@ split@0.3: dependencies: through "2" -split@^1.0.0: +split@^1.0.0, split@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== @@ -13798,11 +12961,6 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= -statuses@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" - integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= - stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -13819,6 +12977,14 @@ stream-combiner2@^1.1.1: duplexer2 "~0.1.0" readable-stream "^2.0.2" +stream-combiner@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + stream-combiner@~0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" @@ -13910,7 +13076,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -13918,16 +13084,16 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" - integrity sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ== +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^5.2.0" + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" -string-width@^4.2.0: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== @@ -13936,37 +13102,39 @@ string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== +string.prototype.trimend@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.0.tgz#ee497fd29768646d84be2c9b819e292439614373" + integrity sha512-EEJnGqa/xNfIg05SxiPSqRS7S9qwDhYts1TSLR1BQfYUfPe1stofgGKvwERK9+9yf+PpfBMlpBaCHucXGPQfUA== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" + es-abstract "^1.17.5" string.prototype.trimleft@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" - integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" + integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" + es-abstract "^1.17.5" + string.prototype.trimstart "^1.0.0" -string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== +string.prototype.trimright@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" + integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" + es-abstract "^1.17.5" + string.prototype.trimend "^1.0.0" -string.prototype.trimright@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" - integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== +string.prototype.trimstart@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.0.tgz#afe596a7ce9de905496919406c9734845f01a2f2" + integrity sha512-iCP8g01NFYiiBOnwG1Xc3WZLyoo+RuBymwIlWncShXDDJYWN6DbnM3odslBJdgCdRlq94B5s63NWAZlcn2CS4w== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" + es-abstract "^1.17.5" string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" @@ -14015,7 +13183,7 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -14262,29 +13430,16 @@ tar-stream@^1.5.0: xtend "^4.0.0" tar-stream@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3" - integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw== + version "2.1.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.2.tgz#6d5ef1a7e5783a95ff70b69b97455a5968dc1325" + integrity sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q== dependencies: - bl "^3.0.0" + bl "^4.0.1" end-of-stream "^1.4.1" fs-constants "^1.0.0" inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4: - version "4.4.8" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" - integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== - dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.3.4" - minizlib "^1.1.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.2" - tar@^4.3.0, tar@^4.4.10: version "4.4.13" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" @@ -14306,6 +13461,13 @@ tcp-port-used@^1.0.1: debug "4.1.0" is2 "2.0.1" +temp-fs@^0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/temp-fs/-/temp-fs-0.9.9.tgz#8071730437870720e9431532fe2814364f8803d7" + integrity sha1-gHFzBDeHByDpQxUy/igUNk+IA9c= + dependencies: + rimraf "~2.5.2" + temp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/temp/-/temp-0.4.0.tgz#671ad63d57be0fe9d7294664b3fc400636678a60" @@ -14334,15 +13496,15 @@ terser-webpack-plugin@2.3.3: webpack-sources "^1.4.3" terser-webpack-plugin@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" - integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== dependencies: cacache "^12.0.2" find-cache-dir "^2.1.0" is-wsl "^1.1.0" schema-utils "^1.0.0" - serialize-javascript "^1.7.0" + serialize-javascript "^2.1.2" source-map "^0.6.1" terser "^4.1.2" webpack-sources "^1.4.0" @@ -14366,19 +13528,10 @@ terser@^3.14.1: source-map "~0.6.1" source-map-support "~0.5.10" -terser@^4.1.2, terser@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.4.0.tgz#22c46b4817cf4c9565434bfe6ad47336af259ac3" - integrity sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -terser@^4.4.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" - integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== +terser@^4.1.2, terser@^4.4.0, terser@^4.4.3: + version "4.6.10" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.10.tgz#90f5bd069ff456ddbc9503b18e52f9c493d3b7c2" + integrity sha512-qbF/3UOo11Hggsbsqm2hPa6+L4w7bkr+09FNseEe8xrcVD3APGLFqE+Oz1ZKAxjYnFsj80rLOfgAtJ0LNJjtTA== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -14395,9 +13548,9 @@ test-exclude@^5.2.2: require-main-filename "^2.0.0" text-extensions@^1.0.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.7.0.tgz#faaaba2625ed746d568a23e4d0aacd9bf08a8b39" - integrity sha512-AKXZeDq230UaSzaO5s3qQUZOaC7iKbzq0jOFL614R7d9R593HLqAOL0cYoqLdkNrjBSOdmoQI06yigq1TSBXAg== + version "1.9.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" + integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== thenify-all@^1.0.0: version "1.6.0" @@ -14434,7 +13587,7 @@ through2@^0.6.1: readable-stream ">=1.0.33-1 <1.1.0-0" xtend ">=4.0.0 <4.1.0-0" -through2@^2.0.0, through2@^2.0.3: +through2@^2.0.0, through2@^2.0.2, through2@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -14442,22 +13595,14 @@ through2@^2.0.0, through2@^2.0.3: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" - -through2@^3.0.1: +through2@^3.0.0, through2@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== dependencies: readable-stream "2 || 3" -through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3, through@~2.3.1, through@~2.3.8: +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= @@ -14491,14 +13636,6 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -timers-ext@0.1, timers-ext@^0.1.2: - version "0.1.5" - resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.5.tgz#77147dd4e76b660c2abb8785db96574cbbd12922" - integrity sha512-tsEStd7kmACHENhsUPaxb8Jf8/+GZZxyNFQbZD07HQOyooOa6At1rQqjffgvg7n+dxscQa9cjjMdWhJtsP2sxg== - dependencies: - es5-ext "~0.10.14" - next-tick "1" - timers-ext@^0.1.5: version "0.1.7" resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" @@ -14507,7 +13644,7 @@ timers-ext@^0.1.5: es5-ext "~0.10.46" next-tick "1" -timsort@^0.3.0: +timsort@^0.3.0, timsort@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= @@ -14618,13 +13755,13 @@ tough-cookie@~2.3.0, tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -tough-cookie@~2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" - integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== dependencies: - psl "^1.1.24" - punycode "^1.4.1" + psl "^1.1.28" + punycode "^2.1.1" toxic@^1.0.0: version "1.0.1" @@ -14674,9 +13811,9 @@ try-require@^1.0.0: integrity sha1-NEiaLKwMCcHMEO2RugEVlNQzO+I= ts-node@^8.6.2: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35" - integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg== + version "8.8.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.8.1.tgz#7c4d3e9ed33aa703b64b28d7f9d194768be5064d" + integrity sha512-10DE9ONho06QORKAaCBpPiFCdW+tZJuY/84tyypGtl6r+/C7Asq0dhqbRZURuUlLQtZxxDvT8eoj8cGW0ha6Bg== dependencies: arg "^4.1.0" diff "^4.0.1" @@ -14689,7 +13826,7 @@ tsickle@0.38.1: resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.38.1.tgz#30762db759d40c435943093b6972c7f2efb384ef" integrity sha512-4xZfvC6+etRu6ivKCNqMOd1FqcY/m6JY3Y+yr5+Xw+i751ciwrWINi6x/3l1ekcODH9GZhlf0ny2LpzWxnjWYA== -tslib@1.10.0, tslib@^1.10.0, tslib@^1.9.0: +tslib@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== @@ -14699,10 +13836,10 @@ tslib@1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ== -tslib@^1.8.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" - integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== +tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" + integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== tslint-eslint-rules@5.4.0: version "5.4.0" @@ -14812,12 +13949,12 @@ type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2" - integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw== +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== -type-is@~1.6.16, type-is@~1.6.17, type-is@~1.6.18: +type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -14840,6 +13977,13 @@ typed-graphqlify@^2.3.0: resolved "https://registry.yarnpkg.com/typed-graphqlify/-/typed-graphqlify-2.3.0.tgz#c85f09b65b56e6da2c993899a34e551e2616bf91" integrity sha512-iRjAneX/0gHBOrJnZGF5Nwl6OjHDiYBYxQzqenRJExVod0A0QHto9npX4d68i+2OuSHAzatNgSVtJoRgnBHeYQ== +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -14855,30 +13999,25 @@ typescript@3.6.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== -typescript@^3.0.3, typescript@^3.6.4: - version "3.7.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" - integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== - -typescript@~3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" - integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== - -typescript@~3.8.3: +typescript@^3.0.3, typescript@^3.6.4, typescript@^3.7.5, typescript@~3.8.3: version "3.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@~3.7.2: + version "3.7.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" + integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== + uglify-js@^1.3.3: version "1.3.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-1.3.5.tgz#4b5bfff9186effbaa888e4c9e94bd9fc4c94929d" integrity sha1-S1v/+Rhu/7qoiOTJ6UvZ/EyUkp0= uglify-js@^3.1.4: - version "3.7.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a" - integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg== + version "3.8.1" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.8.1.tgz#43bb15ce6f545eaa0a64c49fd29375ea09fa0f93" + integrity sha512-W7KxyzeaQmZvUFbGj4+YFshhVrMBGSg2IbcYAjGWGvx8DHvJMclbTDMpffdxFUGPBHjIytk7KJUR/KUXstUGDw== dependencies: commander "~2.20.3" source-map "~0.6.1" @@ -14894,9 +14033,9 @@ unc-path-regex@^0.1.2: integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= underscore@1.x: - version "1.9.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" - integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== + version "1.10.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.10.2.tgz#73d6aa3668f3188e4adb0f1943bd12cfd7efaaaf" + integrity sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -14911,15 +14050,15 @@ unicode-match-property-ecmascript@^1.0.4: unicode-canonical-property-names-ecmascript "^1.0.4" unicode-property-aliases-ecmascript "^1.0.4" -unicode-match-property-value-ecmascript@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277" - integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g== +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== unicode-property-aliases-ecmascript@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57" - integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw== + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== unicoderegexp@^0.4.1: version "0.4.1" @@ -14927,14 +14066,14 @@ unicoderegexp@^0.4.1: integrity sha1-r7EOTvHu3ccRQXu7ZSvIhdqdQXE= union-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" - integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ= + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== dependencies: arr-union "^3.1.0" get-value "^2.0.6" is-extendable "^0.1.1" - set-value "^0.4.3" + set-value "^2.0.1" union@~0.4.3: version "0.4.6" @@ -14961,9 +14100,9 @@ unique-filename@^1.1.1: unique-slug "^2.0.0" unique-slug@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.1.tgz#5e9edc6d1ce8fb264db18a507ef9bd8544451ca6" - integrity sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== dependencies: imurmurhash "^0.1.4" @@ -14979,6 +14118,13 @@ unique-string@^1.0.0: dependencies: crypto-random-string "^1.0.0" +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + universal-analytics@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/universal-analytics/-/universal-analytics-0.4.15.tgz#4abc61b159ffe765be144e07b7b739e0ee7b88ab" @@ -15052,10 +14198,10 @@ unzip@~0.1.9: readable-stream "~1.0.31" setimmediate ">= 1.0.1 < 2" -unzipper@^0.10.5: - version "0.10.5" - resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.5.tgz#4d189ae6f8af634b26efe1a1817c399e0dd4a1a0" - integrity sha512-i5ufkXNjWZYxU/0nKKf6LkvW8kn9YzRvfwuPWjXP+JTFce/8bqeR0gEfbiN2IDdJa6ZU6/2IzFRLK0z1v0uptw== +unzipper@^0.10.10: + version "0.10.10" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.10.tgz#d82d41fbdfa1f0731123eb11c2cfc028b45d3d42" + integrity sha512-wEgtqtrnJ/9zIBsQb8UIxOhAH1eTHfi7D/xvmrUoMEePeI6u24nq1wigazbIFtHt6ANYXdEVTvc8XYNlTurs7A== dependencies: big-integer "^1.6.17" binary "~0.3.0" @@ -15193,15 +14339,10 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho= - uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0, uuid@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== v8-coverage@1.0.9: version "1.0.9" @@ -15354,11 +14495,11 @@ walkdir@^0.4.0, walkdir@^0.4.1: integrity sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ== watchpack@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" - integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== + version "1.6.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2" + integrity sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA== dependencies: - chokidar "^2.0.2" + chokidar "^2.1.8" graceful-fs "^4.1.2" neo-async "^2.5.0" @@ -15572,13 +14713,6 @@ which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: dependencies: isexe "^2.0.0" -wide-align@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" - integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== - dependencies: - string-width "^1.0.2 || 2" - widest-line@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" @@ -15643,6 +14777,15 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -15657,15 +14800,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^1.1.2: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write-file-atomic@^2.0.0: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -15675,6 +14809,16 @@ write-file-atomic@^2.0.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + ws@^6.1.0, ws@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" @@ -15691,18 +14835,16 @@ ws@~3.3.1: safe-buffer "~5.1.0" ultron "~1.1.0" -xdg-basedir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2" - integrity sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I= - dependencies: - os-homedir "^1.0.0" - xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + xhr2@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.2.0.tgz#eddeff782f3b7551061b8d75645085269396e521" @@ -15717,12 +14859,12 @@ xml2js@0.4.16: xmlbuilder "^4.1.0" xml2js@^0.4.17, xml2js@~0.4.4: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== dependencies: sax ">=0.6.0" - xmlbuilder "~9.0.1" + xmlbuilder "~11.0.0" xmlbuilder@^4.1.0: version "4.2.1" @@ -15731,21 +14873,21 @@ xmlbuilder@^4.1.0: dependencies: lodash "^4.0.0" -xmlbuilder@^9.0.7, xmlbuilder@~9.0.1: +xmlbuilder@^9.0.7: version "9.0.7" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= -xmldom@0.1.x, xmldom@^0.1.22: +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +xmldom@0.1.x, xmldom@^0.1.22, xmldom@^0.1.27: version "0.1.31" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== -xmldom@^0.1.27: - version "0.1.27" - resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9" - integrity sha1-1QH5ezvbQDr4757MIFcxh6rawOk= - xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" @@ -15756,12 +14898,7 @@ xpath@^0.0.27: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92" integrity sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ== -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= - -xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1: +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== @@ -15792,11 +14929,18 @@ yallist@^4.0.0: integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.7.2.tgz#f26aabf738590ab61efaca502358e48dc9f348b2" - integrity sha512-qXROVp90sb83XtAoqE8bP9RwAkTTZbugRUTm5YeFCBfNRPEp2YzTeqWiz7m5OORHzEvrA/qcGS8hp/E+MMROYw== + version "1.8.3" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.8.3.tgz#2f420fca58b68ce3a332d0ca64be1d191dd3f87a" + integrity sha512-X/v7VDnK+sxbQ2Imq4Jt2PRUsRsP7UcpSl3Llg6+NRRqWLIvxkMFYtH1FmvwNGYRKKPa+EPA4qDBlI9WVG1UKw== + dependencies: + "@babel/runtime" "^7.8.7" + +yargs-parser@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== dependencies: - "@babel/runtime" "^7.6.3" + camelcase "^4.1.0" yargs-parser@^11.1.1: version "11.1.1" @@ -15806,10 +14950,18 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^15.0.1: + version "15.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.1.tgz#54786af40b820dcb2fb8025b11b4d659d76323b3" + integrity sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^18.1.0: - version "18.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.0.tgz#1b0ab1118ebd41f68bb30e729f4c83df36ae84c3" - integrity sha512-o/Jr6JBOv6Yx3pL+5naWSoIA2jJ+ZkMYQG/ie9qFbukBe4uzmBatlXFOiu/tNKRWEtyf+n5w7jc/O16ufqOTdQ== + version "18.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.2.tgz#2f482bea2136dbde0861683abea7756d30b504f1" + integrity sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" @@ -15857,15 +15009,15 @@ yargs@15.3.0: yargs-parser "^18.1.0" yargs@^11.0.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" - integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766" + integrity sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw== dependencies: cliui "^4.0.0" decamelize "^1.1.1" find-up "^2.1.0" get-caller-file "^1.0.1" - os-locale "^2.0.0" + os-locale "^3.1.0" require-directory "^2.1.1" require-main-filename "^1.0.1" set-blocking "^2.0.0" @@ -15874,12 +15026,30 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU= +yargs@^14.2.3: + version "14.2.3" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" + integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== + dependencies: + cliui "^5.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^15.0.1" + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= dependencies: - fd-slicer "~1.0.1" + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" yeast@0.1.2: version "0.1.2" @@ -15921,9 +15091,9 @@ zip-stream@^1.0.0, zip-stream@^1.1.0: readable-stream "^2.0.0" zip-stream@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.2.tgz#841efd23214b602ff49c497cba1a85d8b5fbc39c" - integrity sha512-ykebHGa2+uzth/R4HZLkZh3XFJzivhVsjJt8bN3GvBzLaqqrUdRacu+c4QtnUgjkkQfsOuNE1JgLKMCPNmkKgg== + version "2.1.3" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b" + integrity sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q== dependencies: archiver-utils "^2.1.0" compress-commons "^2.1.1" From 36535e9abd1c27950a3b7a2c988d61e7d17daded Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Wed, 1 Apr 2020 15:08:25 -0700 Subject: [PATCH 104/262] fix(dev-infra): correct pullapprove global approval regex (#36384) PR Close #36384 --- dev-infra/pullapprove/group.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dev-infra/pullapprove/group.ts b/dev-infra/pullapprove/group.ts index 4dc34d012ce0f..d901284497389 100644 --- a/dev-infra/pullapprove/group.ts +++ b/dev-infra/pullapprove/group.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {IMinimatch, Minimatch, match} from 'minimatch'; +import {IMinimatch, Minimatch} from 'minimatch'; import {PullApproveGroupConfig} from './parse-yaml'; @@ -34,7 +34,7 @@ const CONDITION_TYPES = { INCLUDE_GLOBS: /^contains_any_globs/, EXCLUDE_GLOBS: /^not contains_any_globs/, ATTR_LENGTH: /^len\(.*\)/, - GLOBAL_APPROVAL: /^global-(docs-)?approvers not in groups.approved$/, + GLOBAL_APPROVAL: /^"global-(docs-)?approvers" not in groups.approved$/, }; /** A PullApprove group to be able to test files against. */ @@ -82,10 +82,7 @@ export class PullApproveGroup { ` - ${condition}` + `\n\n` + `Known condition regexs:\n` + - `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - $ { - v - } - `).join('\n')}` + + `${Object.entries(CONDITION_TYPES).map(([k, v]) => ` ${k} - ${v}`).join('\n')}` + `\n\n`; console.error(errMessage); process.exit(1); @@ -95,7 +92,9 @@ export class PullApproveGroup { } /** Retrieve all of the lines which were not able to be parsed. */ - getBadLines(): string[] { return this.misconfiguredLines; } + getBadLines(): string[] { + return this.misconfiguredLines; + } /** Retrieve the results for the Group, all matched and unmatched conditions. */ getResults(): PullApproveGroupResult { From a555fdba325b599456f628f2f685c7a000b6e4aa Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 30 Mar 2020 08:25:39 -0700 Subject: [PATCH 105/262] build: update pullapprove config to better handle global approvals (#36384) Beginning with this change, global approvals will now require the approver to include `Reviewed-for: global-approvers`, and a docs global approval requires `Reviewed-for: global-docs-approvers`. Historically, providing a review by any member of the global reviewer groups would automatically be considered a global review. This change enforces that global approval should be an intentional, explicit action. The global-approvers and global-docs-approvers group will not be requested as reviews by pullapprove. PR Close #36384 --- .pullapprove.yml | 199 ++++++++++++++++++++++++----------------------- 1 file changed, 103 insertions(+), 96 deletions(-) diff --git a/.pullapprove.yml b/.pullapprove.yml index ef53b80c4c729..2d181f59c6093 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -97,6 +97,12 @@ version: 3 +# Meta field that goes unused by PullApprove to allow for defining aliases to be +# used throughout the config. +meta: + 1: &can-be-global-approved "\"global-approvers\" not in groups.approved" + 2: &can-be-global-docs-approved "\"global-docs-approvers\" not in groups.approved" + # turn on 'draft' support # https://docs.pullapprove.com/config/github-api-version/ # https://developer.github.com/v3/previews/#draft-pull-requests @@ -115,11 +121,49 @@ pullapprove_conditions: groups: + # ========================================================= + # Global Approvers + # + # All reviews performed for global approvals require using + # the `Reviewed-for:` specifier to set the approval + # specificity as documented at: + # https://docs.pullapprove.com/reviewed-for/ + # ========================================================= + global-approvers: + type: optional + reviewers: + teams: + - framework-global-approvers + reviews: + request: 0 + required: 1 + reviewed_for: required + + # ========================================================= + # Global Approvers For Docs + # + # All reviews performed for global docs approvals require + # using the `Reviewed-for:` specifier to set the approval + # specificity as documented at: + # https://docs.pullapprove.com/reviewed-for/ + # ========================================================= + global-docs-approvers: + type: optional + reviewers: + teams: + - framework-global-approvers-for-docs-only-changes + reviews: + request: 0 + required: 1 + reviewed_for: required + # ========================================================= # Framework: Animations # ========================================================= fw-animations: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/animations/**', @@ -135,9 +179,6 @@ groups: reviewers: users: - matsko - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -145,6 +186,8 @@ groups: # ========================================================= fw-compiler: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/compiler/**', @@ -161,9 +204,6 @@ groups: - AndrewKushnir - JoostK - kara - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -171,6 +211,8 @@ groups: # ========================================================= fw-ngcc: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/compiler-cli/ngcc/**' @@ -181,9 +223,6 @@ groups: - gkalpak - JoostK - petebacondarwin - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -191,6 +230,8 @@ groups: # ========================================================= fw-core: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/core/**', @@ -300,9 +341,6 @@ groups: - kara - mhevery - pkozlowski-opensource - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -310,6 +348,8 @@ groups: # ========================================================= fw-http: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/common/http/**', @@ -323,9 +363,6 @@ groups: users: - alxhub - IgorMinar - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -333,6 +370,8 @@ groups: # ========================================================= fw-elements: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/elements/**', @@ -344,9 +383,6 @@ groups: users: - andrewseguin - gkalpak - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -354,6 +390,8 @@ groups: # ========================================================= fw-forms: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/forms/**', @@ -377,9 +415,6 @@ groups: reviewers: users: - AndrewKushnir - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -387,6 +422,8 @@ groups: # ========================================================= fw-i18n: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/core/src/i18n/**', @@ -411,9 +448,6 @@ groups: - AndrewKushnir - mhevery - petebacondarwin - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -421,6 +455,8 @@ groups: # ========================================================= fw-platform-server: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/platform-server/**', @@ -431,9 +467,6 @@ groups: users: - alxhub - kyliau - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -441,6 +474,8 @@ groups: # ========================================================= fw-router: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/router/**', @@ -452,9 +487,6 @@ groups: reviewers: users: - atscott - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -462,6 +494,8 @@ groups: # ========================================================= fw-server-worker: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/service-worker/**', @@ -480,9 +514,6 @@ groups: - alxhub - gkalpak - IgorMinar - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -490,6 +521,8 @@ groups: # ========================================================= fw-upgrade: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/upgrade/**', @@ -511,9 +544,6 @@ groups: users: - gkalpak - petebacondarwin - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -521,6 +551,8 @@ groups: # ========================================================= fw-testing: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ '**/testing/**', @@ -533,9 +565,6 @@ groups: - IgorMinar - kara - pkozlowski-opensource - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -543,6 +572,7 @@ groups: # ========================================================= fw-benchmarks: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ 'modules/benchmarks/**' @@ -552,8 +582,6 @@ groups: - IgorMinar - kara - pkozlowski-opensource - teams: - - ~framework-global-approvers # ========================================================= @@ -561,6 +589,7 @@ groups: # ========================================================= fw-playground: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ 'modules/playground/**' @@ -569,8 +598,6 @@ groups: users: - IgorMinar - kara - teams: - - ~framework-global-approvers # ========================================================= @@ -578,6 +605,8 @@ groups: # ========================================================= fw-security: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/core/src/sanitization/**', @@ -592,15 +621,14 @@ groups: users: - IgorMinar - mhevery - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= # Bazel # ========================================================= bazel: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/bazel/**', @@ -611,9 +639,6 @@ groups: - IgorMinar - josephperrott - kyliau - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -621,6 +646,8 @@ groups: # ========================================================= language-service: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/language-service/**', @@ -631,9 +658,6 @@ groups: users: - ayazhafiz - kyliau - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -641,6 +665,8 @@ groups: # ========================================================= zone-js: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/zone.js/**', @@ -650,9 +676,6 @@ groups: users: - JiaLiPassion - mhevery - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -660,6 +683,8 @@ groups: # ========================================================= benchpress: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'packages/benchpress/**' @@ -667,9 +692,6 @@ groups: reviewers: users: - alxhub - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -677,6 +699,7 @@ groups: # ========================================================= integration-tests: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ 'integration/**' @@ -687,8 +710,6 @@ groups: - josephperrott - kara - mhevery - teams: - - ~framework-global-approvers # ========================================================= @@ -696,6 +717,8 @@ groups: # ========================================================= docs-getting-started-and-tutorial: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/content/guide/setup-local.md', @@ -719,9 +742,6 @@ groups: - aikidave - IgorMinar - StephenFluin - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -729,6 +749,8 @@ groups: # ========================================================= docs-marketing: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/content/marketing/**', @@ -742,9 +764,6 @@ groups: users: - IgorMinar - StephenFluin - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -752,6 +771,8 @@ groups: # ========================================================= docs-observables: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/content/guide/observables.md', @@ -768,9 +789,6 @@ groups: reviewers: users: - alxhub - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -778,6 +796,8 @@ groups: # ========================================================= docs-packaging-and-releasing: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'docs/PUBLIC_API.md', @@ -802,9 +822,6 @@ groups: users: - IgorMinar - kara - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -812,6 +829,8 @@ groups: # ========================================================= docs-cli: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/content/cli/**', @@ -833,9 +852,6 @@ groups: - clydin - IgorMinar - mgechev - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -843,6 +859,8 @@ groups: # ========================================================= docs-libraries: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/content/guide/creating-libraries.md', @@ -854,9 +872,6 @@ groups: - alan-agius4 - IgorMinar - mgechev - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -864,6 +879,8 @@ groups: # ========================================================= docs-schematics: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/content/guide/schematics.md', @@ -877,9 +894,6 @@ groups: - alan-agius4 - IgorMinar - mgechev - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -887,6 +901,8 @@ groups: # ========================================================= docs-infra: conditions: + - *can-be-global-approved + - *can-be-global-docs-approved - > contains_any_globs(files, [ 'aio/*', @@ -907,9 +923,6 @@ groups: - gkalpak - IgorMinar - petebacondarwin - teams: - - ~framework-global-approvers - - ~framework-global-approvers-for-docs-only-changes # ========================================================= @@ -917,6 +930,7 @@ groups: # ========================================================= dev-infra: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ '*', @@ -980,8 +994,6 @@ groups: - gkalpak - IgorMinar - josephperrott - teams: - - ~framework-global-approvers # ========================================================= @@ -989,6 +1001,7 @@ groups: # ========================================================= public-api: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ 'goldens/public-api/**', @@ -1001,8 +1014,6 @@ groups: reviewers: users: - IgorMinar - teams: - - ~framework-global-approvers # ================================================ @@ -1010,6 +1021,7 @@ groups: # ================================================ size-tracking: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ 'aio/scripts/_payload-limits.json', @@ -1019,8 +1031,6 @@ groups: users: - IgorMinar - kara - teams: - - ~framework-global-approvers # ================================================ @@ -1028,6 +1038,7 @@ groups: # ================================================ circular-dependencies: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ 'goldens/packages-circular-deps.json' @@ -1037,8 +1048,6 @@ groups: - IgorMinar - josephperrott - kara - teams: - - ~framework-global-approvers #################################################################################### @@ -1050,6 +1059,7 @@ groups: # ========================================================= code-ownership: conditions: + - *can-be-global-approved - > contains_any_globs(files, [ '.pullapprove.yml' @@ -1057,8 +1067,6 @@ groups: reviewers: users: - IgorMinar - teams: - - ~framework-global-approvers # ==================================================== @@ -1066,6 +1074,7 @@ groups: # ==================================================== fallback: conditions: + - *can-be-global-approved # Groups which are found to have matching conditions are `active` # according to PullApprove. If no groups are matched and considered # active, we still want to have a review occur. @@ -1073,5 +1082,3 @@ groups: reviewers: users: - IgorMinar - teams: - - ~framework-global-approvers From 568e9df1d6ea4c22f915830d424a208c7146169d Mon Sep 17 00:00:00 2001 From: Mikel Ward <mbw@google.com> Date: Thu, 13 Feb 2020 13:34:02 -0800 Subject: [PATCH 106/262] fix(router): allow UrlMatcher to return null (#36402) The matcher is allowed to return null per https://angular.io/api/router/UrlMatcher#usage-notes And run `yarn gulp format` to pick up recent clang format changes. Closes #29824 BREAKING CHANGE: UrlMatcher's type now reflects that it could always return null. If you implemented your own Router or Recognizer class, please update it to handle matcher returning null. PR Close #36402 --- goldens/public-api/router/router.d.ts | 2 +- packages/router/src/config.ts | 53 ++++++++++++++------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/goldens/public-api/router/router.d.ts b/goldens/public-api/router/router.d.ts index 58fda6ec4781e..a09f01f799582 100644 --- a/goldens/public-api/router/router.d.ts +++ b/goldens/public-api/router/router.d.ts @@ -500,7 +500,7 @@ export declare abstract class UrlHandlingStrategy { abstract shouldProcessUrl(url: UrlTree): boolean; } -export declare type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) => UrlMatchResult; +export declare type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) => UrlMatchResult | null; export declare type UrlMatchResult = { consumed: UrlSegment[]; diff --git a/packages/router/src/config.ts b/packages/router/src/config.ts index 9ba6564de97d0..2ce2a3cbb94ec 100644 --- a/packages/router/src/config.ts +++ b/packages/router/src/config.ts @@ -36,7 +36,8 @@ export type Routes = Route[]; * @publicApi */ export type UrlMatchResult = { - consumed: UrlSegment[]; posParams?: {[name: string]: UrlSegment}; + consumed: UrlSegment[]; + posParams?: {[name: string]: UrlSegment}; }; /** @@ -64,7 +65,7 @@ export type UrlMatchResult = { * @publicApi */ export type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) => - UrlMatchResult; + UrlMatchResult|null; /** * @@ -109,7 +110,7 @@ export type ResolveData = { * @see `Route#loadChildren`. * @publicApi */ -export type LoadChildrenCallback = () => Type<any>| NgModuleFactory<any>| Observable<Type<any>>| +export type LoadChildrenCallback = () => Type<any>|NgModuleFactory<any>|Observable<Type<any>>| Promise<NgModuleFactory<any>|Type<any>|any>; /** @@ -123,7 +124,7 @@ export type LoadChildrenCallback = () => Type<any>| NgModuleFactory<any>| Observ * @see `Route#loadChildren`. * @publicApi */ -export type LoadChildren = LoadChildrenCallback | DeprecatedLoadChildren; +export type LoadChildren = LoadChildrenCallback|DeprecatedLoadChildren; /** * A string of the form `path/to/file#exportName` that acts as a URL for a set of routes to load. @@ -147,7 +148,7 @@ export type DeprecatedLoadChildren = string; * @see `RouterLink` * @publicApi */ -export type QueryParamsHandling = 'merge' | 'preserve' | ''; +export type QueryParamsHandling = 'merge'|'preserve'|''; /** * @@ -156,9 +157,9 @@ export type QueryParamsHandling = 'merge' | 'preserve' | ''; * @see `Route#runGuardsAndResolvers` * @publicApi */ -export type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | - 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | - ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean); +export type RunGuardsAndResolvers = + 'pathParamsChange'|'pathParamsOrQueryParamsChange'|'paramsChange'|'paramsOrQueryParamsChange'| + 'always'|((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean); /** * A configuration object that defines a single route. @@ -519,36 +520,36 @@ function validateNode(route: Route, fullPath: string): void { } if (!route.component && !route.children && !route.loadChildren && (route.outlet && route.outlet !== PRIMARY_OUTLET)) { - throw new Error( - `Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`); + throw new Error(`Invalid configuration of route '${ + fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`); } if (route.redirectTo && route.children) { - throw new Error( - `Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`); + throw new Error(`Invalid configuration of route '${ + fullPath}': redirectTo and children cannot be used together`); } if (route.redirectTo && route.loadChildren) { - throw new Error( - `Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`); + throw new Error(`Invalid configuration of route '${ + fullPath}': redirectTo and loadChildren cannot be used together`); } if (route.children && route.loadChildren) { - throw new Error( - `Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`); + throw new Error(`Invalid configuration of route '${ + fullPath}': children and loadChildren cannot be used together`); } if (route.redirectTo && route.component) { - throw new Error( - `Invalid configuration of route '${fullPath}': redirectTo and component cannot be used together`); + throw new Error(`Invalid configuration of route '${ + fullPath}': redirectTo and component cannot be used together`); } if (route.path && route.matcher) { throw new Error( `Invalid configuration of route '${fullPath}': path and matcher cannot be used together`); } if (route.redirectTo === void 0 && !route.component && !route.children && !route.loadChildren) { - throw new Error( - `Invalid configuration of route '${fullPath}'. One of the following must be provided: component, redirectTo, children or loadChildren`); + throw new Error(`Invalid configuration of route '${ + fullPath}'. One of the following must be provided: component, redirectTo, children or loadChildren`); } if (route.path === void 0 && route.matcher === void 0) { - throw new Error( - `Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`); + throw new Error(`Invalid configuration of route '${ + fullPath}': routes must have either a path or a matcher specified`); } if (typeof route.path === 'string' && route.path.charAt(0) === '/') { throw new Error(`Invalid configuration of route '${fullPath}': path cannot start with a slash`); @@ -556,12 +557,12 @@ function validateNode(route: Route, fullPath: string): void { if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) { const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`; - throw new Error( - `Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`); + throw new Error(`Invalid configuration of route '{path: "${fullPath}", redirectTo: "${ + route.redirectTo}"}': please provide 'pathMatch'. ${exp}`); } if (route.pathMatch !== void 0 && route.pathMatch !== 'full' && route.pathMatch !== 'prefix') { - throw new Error( - `Invalid configuration of route '${fullPath}': pathMatch can only be set to 'prefix' or 'full'`); + throw new Error(`Invalid configuration of route '${ + fullPath}': pathMatch can only be set to 'prefix' or 'full'`); } if (route.children) { validateConfig(route.children, fullPath); From c8bef1259c185fab24ef483ed626bc27ba61d775 Mon Sep 17 00:00:00 2001 From: Doguhan Uluca <duluca@gmail.com> Date: Wed, 15 Jan 2020 13:03:24 -0500 Subject: [PATCH 107/262] docs: adding Doguhan Uluca as GDE resource (#34789) PR Close #34789 --- aio/content/images/bios/doguhan.jpg | Bin 0 -> 29889 bytes aio/content/marketing/contributors.json | 8 ++++++++ 2 files changed, 8 insertions(+) create mode 100644 aio/content/images/bios/doguhan.jpg diff --git a/aio/content/images/bios/doguhan.jpg b/aio/content/images/bios/doguhan.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9585e677aaa8f72b96e7e547cb0453c04b1f3308 GIT binary patch literal 29889 zcmcG#1z4Ot7C-vJ0D~1uaUEKqv{=#NP@s5=ySBKyyR?PkQlNOT;tcNYP#lW87Izq6 zfIIzm_xpDD+1>yD-sia)k~#0m$w_`E=S?z6xSzgX1|G^tNJ{`nNB|&(_yG4Sz$<Y# za}xk~`xamT001383Ni;!5EMcLAVWj|K>mjO4-Qh)H_%`7@67vE@GogGF?|Ikc?sz^ z;(w?HPrtXbvqGi@0Baj32PH{SY7I>-YVZtz43Gj?2(4J}4IS-76cpb4*6>^Q_xHbs zi^)G)0E{#L=lp+_{<kMABV$KH1O#*h-`2>{&>BIz0RU=>p`C*h0DuV)d>&UPyWjNh zHV`-<8i=6Z{iaR-MkDe70)xNN!GFl8D2X9tQV=wbq1k&Q1YLxnnGF7kZ~9O4-`aqX zK<JS)wlQ`vH>Cb;3k3&T6LTx$KQjK7{2#LaN%DV@)>h64%zp$3BE@#JRF*}2KSN;u zVD$d=Z<+-`7a6`6S4PmZ2zu7VTutup^qrlPs1kyHis<ks&X%eo2pZuL$WkT_5~>Iq zp$FN)%vtImbdraeiaLT%gy6T^7|6;0z3jB1qZq=Lz!L=j&dgZ)w|%Jq07Px>B&~v= z5qdyE4z^0a<q>TFnHU+r7Dv!b2s*^lR`z!r5IRBCjxNf-`M=vU?O`VNyPd!J0~YUP z6c9ARH$kh$R+7Kv5p{v!c1{X^ZvzUIjg{Q*dJ%P@yf$|H11~}k3YC+YiWGv6s29b` z$wB4sWl^F`%q67%E?;iuAoZL7yX>r;)gL~JXd5cBgR|0a?1;KhS>8K{OCo55PE-YB z8`a<T{7t(6YDn(^W55<LK%|C%4R8xk14@7-Ad2|50~`=JCV)9$h2R(?a*YujW5m-x zWSIXb=LlFL_~wAiA9;?5RN)WFzm@!lEHz+?;MxGc{*W~U#HexrXM`p*U=P7H`%@=1 zAclByM(|Aki=Mx=W&7`XY*C0&SW!3-kssv^iXaLP3NJv7B8>71MF{0Jg3F7-|EF#R zM45je`rV#wL@j^QV~?oO_zyWX1ok!rMknAsB3(g9*aD7!YWNqcM3Ff^`zt5FLEqeP zIP&P9Y-NrpY5AuF^S@YB{{Lii)OFNfs6P?u4C?%!I;c_SQ0Eb!8H8>A!eaYZ{@<<q zyQj<%J!<<ea{t~J|Bw<vAhr6Vq&30{<_OHj|Ad+OpLO(jHIn>Q+fS5QopJ0QFB6+6 zvcI^$tzaA^cOeG^F#W}4onqZ*{mGian$5ZkiUn1Hnm~1+de8ts4Qd6ofm%S_ASkHe zPx=4lLx1)?@Vn)|{pxqSe|y(I5dO2R5gv;pibIY=gYy~(f<uS%=1(bV9AX?c94Q=n zL=O3%{q~oCQ~xt^gk3Zdwf)0B|GBQ;?~3`Knh<?}^Z?-j=6}`rFFv4(Xt6oqiqPqR zu=j6&vjN-@vj6<%{T&es6$%@Q^uKvG&u^dqhi)`+wAW}N05uu|8ZR0fn#^zdAMY|6 zJtB`6k&6Fw+YtWor^LS?HFh#~`#qlkVzzef4(6t2PSotItlZQhh^fz*TH3~tg^BvT zl@;|LS&q~W#*W4gF2+VI!0&nUcR2t!Rr+H-L?Rmgi|6zf00a*ZW8cVMJS}GcC~^b< zV$Q#K&k$oJVLAZRzBF`paQT})#6&#^0FEXc?0-BXVT&Thuf_ZOQ^Yt1jsbw%===Md z%=`P>EQJ1f0BE(kZw2tsk)n{IKuAvjWIQAg9@2d$fS78KP?7!!e^(43A%jp*(ZJ{! zm{<sbs)qnF5(tEh0zySaK|x4+Bk}<hJk&>z*+kIr72kuO*b}h(M`xhZh?cbxDvch| zau_%SU|<pvlaP|pJ*9v4oPm?;B{vT*pV(`02}vnw8D$k!HFX3$LnC7oQ!{f5M<-_& zS2uT$zz-ik1qFW&iHZFZ7oYGoF)1@EJLh|DUVcG&MP*fWO>JF$dq-zicTaC$|JeA% z&&jFjnc0=qwe^k7tzX+a$0w&}=NFf-tLxvmkO0u%U?I}KA^SI6cnDm`C@3Hl@NZm5 z$gaPE<DsBFW<z@<q6mI(kN<?-ADuunI-{%&gN8%th|s`c6qAUSbA|5sH?%*H{oer# z`2U3LPhfxHnnO$m$bSS7GBOAi1OlO=p&|krI@<4mj*0$9!2El_{v+W04!D1YdxR1s zgboxG6folNAr=PK!~fUeegUzJB)y*nut7)&X9D2?!oV#&GvpcY|8oT0kNjWOlaaQH zWj1S>Nc3!k$i#v06{R%2AF5l`<v#O`;P$wzwfiwm$MGPRmC@Z;jR`hSHz-EF^c$0> zH{n(O@$Ma_`H|s@X2^J}qZaH^kws0`Q#LdB+e-|N;6*}`K2qzR$OJIgiEay=NL~NN zG4YOYj-1*@A*sW?$@^{fI83E3bAnvh^%t~f;vNWS_hRs-SP%~23U;Rc5b8+RAZoPN z>}K~$c<}^wx9`RRy$4YJkN4^~@<!lX*>l^po6A2?yE=o>Z}P+k$otb*A9MVA?wH}g zad{E~Cl)@^7{)W7O`q93QjMs}t<%wYbvpefQ26D$=n{eyr`scN9c7)a`W+VjF^|P1 zhnsDihv9ZOHEYhPOf1R)N!MfYNCOPe$oQ7nh1K1MJZPIB<PPikYGs{fqsUQvx3*|2 zq}-w;ChvfamI-4wz>Z&iH0=QbMLirexpBiC>hxB>{iKY>D>`SP{y6GQ{N8ZiS}^Rq z3)75(^tw&lOFqYE0fNFcXXv}qLiDSCEGB5LY=NtIw(#W`<~&2mJs?i!>cX|qvhR5$ z_O_l#kL{<80E7b)wd<lhBgU|Wx?1aWLMxJ{spG#ya3Iepl$u$fp+CJ7uVA5NJm4Ci z@T^>%lZ7_o_4_y@XIl2?Uh3ta^#+*FGX4HfQTTrJ|KK}WNoK{Xo}ob+nc=b=Wk{+j zMltdL(!|tC!hSxYk3=UM1&bHpthcFpD6D9*gKp7G{wE?4v+S7P`5QKx2<7Qsa+dfk zT3jD|{-#xR(UhmXUEPaeZeuK^fYe8q;_tuM!Y}l~w@t~{6gP-{ahr-D{;-Fysrp=X zTv0szYgYIai)h@ilK)*Ce8jC`6&%(~y~|B@4@7WzwmjTXXRga`Ox@%a^8dQ*0kG*b z%<BxaQ)jZeQ9l$G8DgLqB*44oJ|4cqBwU3?Jlx?Es>#ebNTmrhG-jT-m~`2#G?2Eo zrq!=}Lr(YRRGKWzK;VG+$fqoSSF3SpmT&!JaX@m(h2<3`uOPTaW-B9Vt`Hr~Siq(m zAat0VQ*M5+o+VAT=IA}$wjX1!xlkdejfbL%KX8f+{VsXBt&r`|+bWuUxZ(~#GS2d{ zRjM5~**TuK2{SqfFOYEQ9<E2(GL!pOs)IqdnJwSV!R%ZtRtI~!_zDr?k^=9dg6`0O z0%hGV-pl-AQFY<2Vd<0APEh<dbMVa582(@r@bkwcs_=@l-fMN<d|B&6!|=|RV=oo( zYfQX(x*3XOqbutBvgQv&dQ?%IcB4F0d2K3-Yy$LIx5A4sg!R(<>&U%D54w_G#u*25 zgQt!O3lb9iSh6oh-y*}aNk)SqI%INm-z`HMlp==61Z&$+UivNzTGR^^Kb^EMyCM$) zQ~FbE&1OX4RuaWOgo3hOPP9e?lrB#1@3sdet?_D8opv{sSUxcyJcJiXzFG|0?L8C? zPKij6nQD|>zWF%`XUo^!CYH&@*njGl8eRKN6P-@p&JCLBg?FP1*FH*3EwbOKNlFbb z&vu+!;M1864(cs_(2x<q&F|+`XiIGx(AF%V-H^(DzQ={MS!5k4htx(hat~aGJG~_P zki>kWGfQ;RlSm#=Fz`O{jScI(sU?L61zrGB!F2ra<UR1gw+0$~N40CYmX5NmfQvrN zcDHy`m14qg93})&Ed5OTRkIiLA{o+$AKM;-6}h++xJ1&3dOX}l<Rb)g&MV2v(G7EW z`2*X}>-bHo(rW?2>xWX*Q^)aB7eq(1yB-8F+n2Leia9@Q7^avGW@1=*bR<+YrTI&> zDWZg0Z$pJGnN2TjU^P@3?!30BZfUBaniXNFpNYhR53=68r<zZRsvYo5xXI=cTKmFM zDO}{iP!%`Ww2?v_AIm&|-(4=r@bJeI*8WnO01^lE)uPE<9z}5i;D1D<`?3H2rbFpr zeaAH`J*~E29k-=bwLH!nbkz`v5aZffXVMvL*;9U};iD3VP8`cot|m*Fqs?ef=x&1I z^!BWiykO@ktJG=;TiwFfBLMWYB^okYbCG)NyH9-lLT}QvISS@{kjS~KWBt0^f5y6- zFTCS2tZq|+NfN8-rHblsj<6*J_WZCD5~1}n>*#VN)&I!!!;3&MN1EDL<tD##^=Ka{ zydafGN2*V6jMO(Qaue&4#2$iqyJaCgVUvNHSN+N;=fiL8-<a>8olr)-*+E0P`F4YI z4=5`n+V)DlON=6S>+fEWEkiBa{~0tMa^SS|z`a`ZV3`3!_-Dow!Nv9EWuNb5dnG0T z6FT#8#LD4oJ}<k7gmePCwac%acNo%gi!hF93mv_tZw_4ODOnq_eIPQmUCwlUXD?YQ zQ&m`>q8o|dVYvdhFg&nuoMOZ+Q}W)F`zN*Dwl_y^G>%8$5%s5DA{HS6FuISYZ4o-y z-e`<+SogrbMyJHqzJ1CjuN{RqF2$YX$oPgX%KA_Q4=4G?3^_^2JwV`xLO-<*f`lvl z<V<`g?m734SzgFW(#fYuWJtb6tMz2FJpE<4yYKV12Lb5UN8WAwyShZltD*aRG=zh7 z8p)3@!bhE#OW2XqMaFWvoY1E?SeRa0*ict%J`!tS>U_j+wEoT~?OZVBsDb>g=*)hm zSIPSA31~->7B{0fwCfWunQ`oo@-GKVVOLi7K-#+D6clQ)dCtKpzmazm5ZR0)C9LOw zYo$W$vnf%WEt}g{&%`MPn^;#H{^VR?ED*|YRmOgI{Ho3PFw%a4EXy)aip|pfbCv+% zh8*wrwruH(<!am3$K~_Z3hoPc?gb}?_B#=UT9px<U7jY`@uwSWj3b4(Uk&F?xqi$^ zF&_womNieFy<<;V>5)*L@$dF&j{9Y8Z|J;Y&a_XrXhrv)YGYa^<q_MkL?2pX1ngr2 zGu{(+vAjKwA@Im3;fRu!&K_JOx9??I{fB#ibFi*)$iLsvwPgU^_8!nR+Qt<;OuGj> z`y)MZZX}Ry8AUCxOpoC4+3`dt>?Pjh_du~fOpPUhGhWYvNp4kjwg(KHL4pK-Rr{@* z$$HWig<7p`m|)|e+3|q3wRf35TNCK)8LRaeyy6k|6E0Tx>2zw3?aF}p;P4?$*&AO` zhSg6*GXkiy;FT_;(E`(R;(Gw44Yn)X)iSe#i)qP$;hY|H!V>qGHX&x%%u<?Mc+W%_ zhUPi7P3S9-ek3s{t6T+(JSOU&B;BfN7-y121@}o4nZIm|aMS-%N-5pf%ENQ_>7mfl zqM`k6L|i4+C;WMD0!5Wq|8tNS|8IlD+8wpq@Ee%xa=2p;S*uCqDD%^LX9Zc|FWDay z_~Lm$^CRHZDL7%_MU?c?+uLL~O`eb;qwgx}2Y4<uxwbj_`uV9QpLe@=%Oh*2mv!i; z((B#Y{%|FTt*x@|R=9vz9$W(UxyUW;ZqI@{Y2&tYOqXH#%}M{z0XxWg3zIzR8xC7Y zPjjesTiD$){>C>4f_(~{=9as9xd-J}F_JWSy?R@Fd>+Iqt(c(`k>4F7`?IUZtlup; z3bB-oW0!Fc)$L_?drJ>ff<0KyN$4MBZ|5)%x%}XncMv4NnRgbHf8UxHzUT4!O}$6V z7C^M|HEjzjEMxD_qW*M_Ifm;Xi$uafGf62^!f>J>1|70R7|9*ZBv$S&^7)PlnP)p` z>o9BLMK1d;H%iT=(9POBHY)tBQo7uDAgX_$w-I>@wfwKQ#8~9S^^>9e){Wy)jFByP zL-Ki~B=Ftz+OkTo;q1XE-dXtp;plrn(1PYY!Fo<UFQlWETi%8tvAUt^3o9zAJT^}@ zhYO|lP-K4tcv$bMjps03tC02(<I!xda#&QhUq>BDH*Q`rmZf-0FkPo`qfJC3BsT-H z#q|PCGiCMtVNUQ6|3k@pK)cG6AvC|zyrzJ02KMn2^+c4sjffHfFel&Q+g<X*;%RBj z<j>B0(gh5fgwHL0H&EODn7Q_Zn}9wnis%Tw%}U{lL(b|O%1*0~nq|?w^i`q-^<*-! z3t5rjWb1qOL1Bj9+4(4LrbJ%M(v;q)Har|<FT7=o6BhNjMRoF>u^&S1&pp&wPI2ZE zDax)nee&*&1JR=7r4&ieNZ8oL#}o66mvQc!W)-q8AE`%K_ia=k+0O^ou6wFKcC^q9 zHtLfgxd)u4eA38T;z?p?Uu=Ze>bdXOpWQjnn75$ARlP}4tx}>V2x&-qYMS1w6Qdst zg=mmfz!cY9SfvSw6?*F)!CO7{dEq>RhVI;ox>h)I?6}HdF3|6shk<D{wNZh_PYNi? z-UqPqN6HLN3O%xPQBM;SE2pzAu#=@&BL(rmEz@{&1na^#VkhsEKaEW2nX8Y=aF@PY zPHPQMAIQH}g*hd@W}9wwOL{|@8z4xWmROQG-o`hSKoNsZT8hJpLEaGYl@@6{eK@z` zZrFo3fJ;8?j&!V<rI-1Pd^dxzvpgO>hHsVT@q9LYVkKK2U`l<eB}qtXHIN&aB1G$h zSm(4o7s6bC^TWi8-EPzwUI>`l<BOB%aH>^j#IY~PT^Mv!vr2;L&-LnBury>1GiTcz zHxh|>rY_C$k`+bsRaF&`K-7j|%kS)UNdRmdR1ZZp$!KmDX2bv?^*;xQiT^x6K>PJ! zjNmSED25m1SR;l(*j5+*06pXLumUl>nJ8ZS+W5KgXB<7?bBmVrLl~23h}zaF#IKPY z6nMe>(zEUh&Ziw)W_Hi0vKmVN%kO^hl%tXxa?^>m0bkQlD{(jLtu);6{L2y=)%x<! zjdO{!mfsB<Za(i}Y&6#rPFT2Z69pQYerJ>#w{bPzO@AenOSpDjo$B;-@W+ZD>5$00 zH^<u_uOtq_jh!7TmY$?SUwrv+ghgd1jH7V@QPd)v-)w9CkxO|=C$~-D{qtNI&f5bn zVMquP-<o|;$lYg7{sCpplIKTyez%~9TGjB3Xr(!1mOeUy7{WsApK{_x(sP!5F_O1) z&SU#@UAyuFW7p2iN#6ziA>{kp*QGybke`I6ALLUqI-CwHzY!Z)+pWY2jQD!X;7LwO zr^bZQMrt@t|BdQAtUzOyfMqX))m*}K>4|j$1(k$vss~Q;%5x~$Gd<Nl5*}X;vtE#$ zf)vHg<YdB1a{i;y*ZR#3PEv}JgModvKkBZhW_+>ku%(^z=fqsuuk50RYiKLVXxE!1 z^<ab>s};{W)P`M=VulJURfm%Wc#je^;`gmx_S}Yn{En~)WeA5Mbqca@?$RCRZ9*eU zy%k?j@V7?`Z~W@`<A^EZ*O4E1Q?5XQ;yoPDR|5FImXoTf(1}2DsTzFAE}Hly{0S+Z zp?WZs5CXsKe1+vLuDncapBKKq(P^R1m0X*+qFTD}I101(?eSAtXyPNLSjUf^xORc^ zADiygtT0QQ@Fz2RNo801#UP<jAX}b2(d9~sTfY+=o@#PT;PdRBbNRG&1jTf3k`kQR zzXyy)k}5)k*}0%I0jneji<3(a!w6^k^uM(pMkH>-)Z-VtP$tgG3-e~(Ywc>cEFZbq zfGKMQ1t0h{-3I@7(%I)Hx4Bk+3g20SIkaEAGOiIzp_0_i4V#QwWr&{N$nW4J9~WC` z`H&8x9p59;l^J{z9rO6~8B-^A3q8*cnCkot=}5d0$xv3|L-eIOO{9I7H@@|^HUhI~ zYE=;Vt5(QIM)O{r3DTZ7Qy;?zOqJx`T%N$W`0x}$1aRhBT{`*S+Hg>lEIW}F%qFxq zG29^$O#X=A!DO2tyMDxv+*QsNsd#HH^rPzHeCwpkPPvQ!z=Pess>rMCMXNQY^d%PC z=R|jqeeWeN%`Y^@&Soy3fiev@6ZwZQ>ul{pwS|w}%V-X)-|YC-)wflv3T!t36c5)z zV!pS<>k_kOKYzmBNvaAKZnKhXi|0CSap+Jo6b#X4-*rN$^w(V5<}|8mhCeqlSIAHJ z^Rn;j&kteHrgMR5?*S5vo2M;k&8V>U(+lI<q7u$<k*=1H0&iKz57g-%vDvw54+r-2 z-UH7Czoc!pxQn0|sqfTc%M`xlIJWwMxvgrC*pg_F`(Jxvp!=WyWsKPhy~Df*R(5ZM z!+ahc(_~@k%1fCUczHD&H|BcWzH$~0_Z6$U@<(h-NW<t>g+p4<orLjVGQEpSZW7nh zTjE3aK-n<fBf>qq-VY&Yk(*=J?$nj#)#G;xd4}{2)sClB9kX@hbJDKxjhwH`HiAfp zky>ZCPY-_5m(_nLy0|GXfAEo#$4-QFm=cFg=e$tNo-?|k`fU9f#0{se_x71m^O|{P zTCByzxXys|0t>{|2WjoRp!(#kyTGUjAMHkUeeJA_3qwyB{)D}5Txy`zD}}?Tly^pX zHfX-7#&1_VgV!S!W4Q7BT>XFg?Vs7|%_k+wbxCmZ_U@Zn#u3X_;kEpPk_Vq3NL~?c zQ&AmtZC1GW8#)J5q!x}(W4n+RdPsh7)|FKZxR#QeoSmLs2P9NpKq(pbZG&2{yv#PZ z7~e7{Ei#8U+gGvjT+Z@GA5Im!!QfgUqv_&t@2=J(g^zsw4wxIY35eOO>ORs$KiM%f zU3{YNgP%4(wJqFXi<ZpzY-R-yuZIC=^FW%?^5YS4o34bQeWS?g^T7FqH^xs`?Xt`P zqm<(_XsOd%b}TcRkRf3<b=XqfIpE<04eM5QrmMSt3BoBo9(Q5>6j9nv@tlV$#h`MM z=y~wOyW^hol90)vXD7zCY>|2v<X=^c#KLo%eT&_>>Y^7gP6g%EoNB}N!{cA*oF;YD zRz^oBZemTuAgo++Wt}yxTROxMtx?faTa%15)BVseM$ostvFNo&TKMzavW__o9f^I` zD9Uw1hm>XC^vQZlsf}Ky0#=?UiR|6bI0@{fgwsL=ws5<)Pl6umDF@lkL()6??_Ctw z{UoOdhMx~pAoESI>oSz1z9Vp6h`#a|6LTAXPA;{+Msck6bAW5%iP@TW5qNM4IgPnL z#SaP6pIs%<*S{}lv6H`%j24q?xAi!HGW-*zM^XhfZ4io~z!=h#l&(`eKX3Fyr5{nX zI`(?0ghuviuBM&$K-E^q`NZDYJwQGkkU#_rQPXRAK45(gj>tNO{`8$GT&0IIA$A~} zNsnKTeTE7RR8Lv4-2)J!d!WIwr-TDGHIPO>Vt6e4$=1m|iaVLKd!_rhcX+ZEIxXMj zsz-PX{oMS}B5YL5rNy>9M2#*ktG&0dp-j(?qd#pL+Okq)+~WGw$FWP(CvEcCtwd%B z<Gy_0|JqFyzMuThZ*9S)3u05Gd`3^ALWJ*&(>qd4jduaKXhn*zAVaorg2UyWPj?h> zouhjoxRKeC0%MKb^7Fwr@mZmt_zY4vpM`fpff0V|m(U?Wj@ILz{5<n99(rmFoV{m0 zjmx0O5?lkz3&h^^#y6&G+YZ}@<<BE{&#|}-+y@G=zMZwr{=8ydajjgi{=P8VK^uwx zoTKh-(L4>nGjE@U#B(@S7CZ4Pq@M1`H}HLZQ%#}~K2v$K2V;4O%CZrj|B&=A9QW0x zh^3XOi_k_Ynd-gASa{(yQr%#B@<<9Q2Vu-TIL(S8;b3#Bug$K2B9nn;tPz6<%ggh1 zPz=VM>JFQEP3hZp&T?{BiIXx2ZZ{UvM1aTIwvO|TcK$+8#>6J4FzPf{0dt--Jxk7v zx<zm-=^3eE>weg^{rRE)*?L)dwDrU%l1S>XihF=)CCvUFn1u3=7KzQxO?RWURV4;r z1tN{s(N?1`UkXiA4QH5tHhEkc`9#xy-t`EBKf-&s%4?CWYscFJStnkQ(&-bccKyCG z70I)^$McX9OPB7M%w9c$iAlS|a7FuWG`895cp$&Ww!1Ni;9PRFJ8L=<P3VoW_jZDY zMlzOPW5hZ4p_*=4iDZ7>A}K9|dMU7XUr+C`nX7UVoA?jvCu}KeypYLn@jI`O_eq5i zKbI|<;(i!a8sYRzmf5^BHhER+<#YyR$uy@*eVUlSqMzu%+oLtW_kjrdnU1j+!cFOc zITGKmDUT93w^-2RuM@+~orN7BIazB;>>Vk}tTiwqO;f8UKjLlCiJ3n%>c7O5lA&{V zB0#m*2)a`3s#5r_;+3~QnWEg>?VwBQy`d2twUtXhmh<svvI7q8u7ZHvs8?tjxP?&Q zL50m);K*im#C4*!sD?fZa(MR7RWZ=+_N$L&EoPhFSy@{tZ+^B_8fwx?qDjq?qg-E4 z4W;pXyo12yj)psLh2$&3`4y^9voY=0`xkXWRy^{-F&-w((Hcp_N?W8ngxzqlqj{lc zM^zWmFBX$tVtTw=UTvCh!23Zvy1Yq{rG!KOt5PX@ly)?#j~YAMi8?G$Nj=^RZ}PBF z>?pm1EG?fp{%j^&xjaDF6V1RXaEWm^f8Aa$SHEaHol_-2`M99eJ~s3hfugwP*Z;Cw zN4lT-&+jARGzxU;dxz=2(pGpkJnK^OEs@jPW>Td4m1b59yZoxS4~rM?sF$!q`A+>t z=W73Gsv4F#a-Y3G_{n$jiOXRS4~3s_M*5tkXpsKxS1)^8_D?UXM|D|V@mRXA`K-Hu z;kYt)&drd}xl{>3I_rrx+HUOt3>G|XpRT^v1^*~kIXkJ|5{rW#Rd7yZQDw5V$?8b| z#j!gZY8a|OOf8bCzky>7_Fxpo`xp`M+*v4B+R5UbLdt6zcb|(#!i{CuXoi6`%@Xds zC&QRCx)Ot^!|_qmOmZW%{&C9o<mF)6EqlSB5%q?SoY{HSI($f3cR?R6X)EMeYd1g% z_BtJFtUt1*`c7r;%;IJ%C#9-oa(gm(0&k3`wOL*^<pqr)7P1xQ&L}7Di5zJkupwJv z_dtpob5+X2t6YA8#%H}9HimUyorU)hdyM0wUeB`{UMGmlNDar+mvjwp#LhORh?6r` zEVND9NOM?pPp+6;eNFLj8FWz;C8GnSI9(R>2Z!wtf9m0SBKP=8dW~>X29qBm_Pl&u z%g#hdV@=>#OW#=PBtz)S56#3Gg9i~ovt`bZN3(Nf!BR*IHBhcfI|iBUhh;<~RqQ+u zQh*2V<lj@oBsif4cfVSn$W`}?8k1@uG3C7~<w%L>*nJzQD2>^NhaEYeF0)ab;AD1g zX5cj6RySrG9{P;u`i!t$V+Vf+Vku=1hgvj<PpVR~+B7Aoa>2FhsGAj29C=(6`uY7# zY8LIgFjpupUVvhJP?b#8Xe)Vm_y>}nMao^#iS995U^&V+N3*s{5~UO*c*~($9qOvP z#NCot!Y%UM+0o3YppaOkjY63&f;T80XMDF?oK_u!lh*XxuBzm$vI5V{1$!W5X%Uxq zKTIuMt!|ijem>F#JRUM$gA@!#x%M!r+qQiYF0~NAXHt3~AWxMXJ|F?kl{tI%E<ri; z(VV)ZX+E`5R)$zo9uTLhW9q74Ie6Giz1_$8boEUS&AW2=^mRnlw0O~UoMeQtvmH9k zVtpFf@Pa_~5_4qn9sYL9j1aiI0?gR#s()z|_Z3HwBjn8Es;8}mxDjjR1<u?wY)PkT zG);P4ifjX383joW5@vB1l!Cg9dWn5=iyz;=qns$Nl2x+boE?bmNxzJW*3UK`SIR(Z zfW&NmnP<b7Z+Q7EGh~kkIpo>5{}gfm#}O`Q$mhkjc`^L?aYW3qd;6|b^Q)jbRv|uQ zj~n$<NyM}%S#2#t?yO0h7@BCLo3&1nZQdskQS_=uFi3bpK6qd0reikeOX8fprGP1= z-7k@zE&V~_j%^xEmdB_nwQe(gbZR^)g)Dpzrd4UL?`SZ87#3oC?y0%NYo&fr!;u+C z`~q(<1~Zmv#QG7s4}o)e2zSYJ#^eh$#cYWa2pGP$Ewcgd*1~W+&U-f-O{GJKnm-ZD z*|k%vX00=PVqj%!TN8``e}k%x9a5RiuX+C*r&6)*Ztbewj_E`irsQ+fsiOHF<VBg2 zaWJcbo5$ov_5Kv8bv;T_=i1lr5^6B&ls(QG($&5AYCCP_oQJR-&J!$cRKu31BF^@S z_s7E?|FoImZN2Oq#gOPhuLE{#e#qN|@k{rwo1%uU)TU!~$=lg)8`zNqQq;u-k~7+? z(b!;9X>LC{Sz)d+p1WU8O?ovlN$KWFArsdowfSxRYLex<v{lS*L0v>1IMI%I`Z`!n zA6@y&y3vGG^)Ehe>!;k&!;15BmM-RPpVc+HoV=f>lA0>09+8}gu@fA$fxkI^*^s|o zo*hG8EGk`25WbTPBRAAPNHG*R9s+Zn&Ql>BtHO&f>fTGZ@c&ru_wGgV+XK2h?LR!J zGL7c@`NFJt*rxRMTX;$0g|*%ZPs#K{Kd%!G90wS6gm*1r=y#v#8pVP4wNhEH>0EtI z&1isw?oE_6xEnMHE_=kN-|}_HmM(<a{q!X&iU%Q>=5|z1ywFRa{;1O52D(q!dKD`7 z@vE;>1Us(IGTG$WW>F$Uw^MoB@Vuj4xbhwdIxh_M^t?jRb0t;0<mlFpjoXh7b46}y zpXwnqK4l24wE9GyF(isOXzTKM2vfRL|FnCHsoEHirY0K8SP#vh2;B2cv)sYOf=jlH z`m`p6*@7ga>ng~i=8=XeOv51KgzJW->grOL<&7uoUKJy^a*>_!9e6PgFi=Rq=AjQ} zvj!F8#tTfie8AlS8$Y1%?!jWCk+;0eCF28K+b8D1JUd7{y_CCK7NedJTTz8C?y-W% zlsb~+k~HsJ3#O=^S5=9QOW`T!3*FU1agNi&D))&-n!1*2OtDq)15eK3g&V#EcOzx{ zj#&Fan`&RU1$pPD(tI%+xrmvW>{gEnws)U;pXS4MWvV{OCbEoMoCdVXfu|4)<}Tk^ zoS7|a{*DJ1bD3;qLWY57eLY@hm(U<D^JC;oec@TM!GY>ot03#9`j<~@x3bM+{de}G ze_;#>aO)k98hN7kR@U4D=^93lG0u~84&s_~K{bSD(@d#Nnn&*G_*!S%={k#W+r$^A zg*&C)NZ`GZpxRUo4|n=^ynBOz+esI?;0ym`g-;~KdtQ>xq+p946tkAYM_tX0K3rGO zl_rlJ@*nQjTM?)c;s#M`Q8;#QeIj8rt64kswDGQtY~dr%NOhdnBjD;;0!^M$T@ts$ zsqSek*3Yc3sD_V)SL6LxUm&h?tqr3hhBVpF@y1Qn@fg`31LAO|Ujc2reWd4y`gkx4 zYwnK47gQWD$Z>uneO|(1VV;O%F5;($iDb>qn@6B|9!$@WTZ(3w<|=M@I?h=n$n8aU zER0dDC5h(2PGu%HLy^Gecp}jsPwj_Z@hne$giYOH#NLR_nGs)-C5}4p%d}%W4OAGX zGc&1uhDCDlE}90n7Mn3|5r?DJNZkdD`&QW@v_jt4-ju*pE>ljuzB%_-`rhb`!6GbB zh78<8sV#E%vkDVmb=(=trMgl6u#&$sTKMu)Yi_~XLF7oWu;Tc+<uhkyhE4t-vLA6N zMrvcYl@~OnQM?(iK)0#z7b~f*tEtuD$2gCYM9L>o$9hACu}d{{*rOtPziX^3^kM-z zNJ)30_rP+xR?o+(7c+%Y<8YGeFZFVv?w-cjNd>PHUfc}xq?X3Ns!PBGJz@*6Ea#Z| za@8l9e=$g)s1=1+wE_PgegDTj3?x$3FNN5FZQxqymg6e7pV1M0w=F)5q`S><VrkDJ zn444m!6tS0qK^c*Tld~O3dftA)fXWiHsSnp8Z&))ji%U&ari==Tf%WZUU1)^MFJwn z^siu9S-&n>clhK+T`4lK-)W<{rLY@+Ewj#k$O`n-pjzoZy>hP-3c`&tB;-~dcd0r5 zzSTV?@A*wHoLl{qHJ7XDBN6tf0&RffS&vSHd!Y|GEXacT<?+BH6T4P!#imjRd9ReU z*#bBUZ0i_*l_j-64|e#*xjJIKv)r%!wPAoO4d4<meQ^ernOqq=yzGtYa7d&sRkiWP zB?V7U$x($dFiJ=!e1@uhXo8uqdkY=~c3#j(dOGsevB;O82}AXZJ$820zQ3u65INLO zDwVkwD7sdG8ptbRm4jfQ$g#>IFY7h5`Uost8O@F8fG6yQ#3nqLJSgi^IP^gUHExwd za0tOjm<l~n<R~v!veF8mhqDsqd=4dm1r^Ov=24#-(fgUawsKtwZe1IR)uX;X>`LW- zk!N<vmWeo*jd%REc3ZUCEC)M0-s()pefL)40z^Ai-l*{53k6?TYQKUZR8GFhUb){= z`6slCYJevQOIgmgEnUMBae3u~z;k2^vW4)p1ahOR7{7sOiVsMxR81{pu<=#yed!hE zm(qwI{^(2}Q&Ka9Q$Gt0XwpF5+!0>g9xJcD=oEBRS6szvf4j$~^G(9!c7C@`J>^~4 zvL7q1%z*&j%5ykl?(~Ar92OMclGZzwZi6|CCdg`Qvu8m5{h_u>TQ_5p#}%p40KJya zP)PaCP@(2=Zshsi!p?Qnh_%Uv7>D3^;IFJr;cq4EvJl)?Z@VT_y$j2Bna975M&>Dq z!23#|>XXGz*fVZw=;zi3?v07gp6!L;G!Y>k{$9oL0Qs$?;{}Pe?uvy)@uG!jx&Y?R zi<5yTCXz;T8~N`WOYK^z=}m_(MYx&-1f>~^@rFNlzF%R{HM*%-@&ePh>56DAb=ALl zIgWNEVyYA7Vim26R=k4yF-EV_hpeG~d^Orfli4Pbb#d8P!)ZC>*q6{tI9-0ca?nyL zO*T|ejw_l-0hCWoSx4#1(6nL=QHbAUB-Q!GgA{3aU{R`pHQ`LLkRbcZG9ZhzZ?Kr( ziQiggcQv6cMnF1e$+!LO%EsJg!rRza*+)9q%Pxy`RJBF=WOq|~ypxr`m>Rh}UnZj~ zHX*=(N3%%`BgI<<cXyUhwx?c(BuUhfEr<)41|h{rO}~$>XhX3R_u^R72h8-4U}IkN zdErT%r?eLvH*@l*5=Fi<ykd9zx?Wt2btif~5-*+2PTIpIGMJgYo4q4kWsie8)A4la z_7b>>rAn|~c05~~va`D58rvb8tjLson&U=>73SVx6lsv!81T@qws((BAL@e#<IU7{ zL!Q|$%FxIT`k(@;vGP=3Kin6@H@l;;#nlb^wA%OjF|J+7K=F3?2hWrn^>Dv|H7#g` zqSVe%t&f`(Ka?T7(p@5}co%=VC76qMc1v*riDB>_U|Jbs7vwgqd9UM=OqK5F&E%0C zBL&6UGkQ;=8DflOqt;*Oy$mq%;Y~JiD2}9%+p_(TC>8ZH49`GyUL-+W<>|976a5gz z$c`)mHPQU=ypRf;-F-r*M>7*f-0r&cV9)kNF=}(2Jr=sqU|ix?HoS_kOG@eev1Wf5 z<Y=u&OD*%-rbw!)PSx!Pi(`sW04`**vKbF9H2(3nX<;|HPQ@?#Ob2J7A$_bx6fT%G zO(UwrMJ{w$<vwvLaWyZW+q!-n@b<vjhbmyVW0obw;EJxwDVl^zECU4(7ILdHdQMW6 z`eaxo^j3GBtsh*G$8&3WN|>s9*IQVJPk3qD#%y_`-dd`~JCI~qRkuZNb`>k^-?O3` zr|PvYlq*cQB0RIAG$-7a?tcwwZNY&x++jYqKMK+hBBNX^w9lKL3;P()=#-=$yhief zlgHM;@>*n^vx!@LeE%$!YK)Pb@ikrt3VK-=*$eU43W%%Em~iJKqR+R#uh*GOy|7NW z)S?P^wSRmM*eKHK4_VxPg*r?0w7so9N9@NXB8d|y{Cfodx4S+i_^WCS&MQl37JT8K zyM_j%V`oy<g#G$T4jPl!_%H;BpS*NQR7M<cMzZCth&pIz59>e9Agi6_+$>2+*!23j zEOD#{WlL6RyisEN_3JAfUBOptw^4E>nP+^UAzVhfO%S;LnU0ED<&Wp_knOBwSgS^R z`fX+3CZn^y)|H2w<ldt%CBsu3*xC_{@qCiKS3P%xU7zBdu2a+sCQpyq*FLrNT6qKx zdi5O3wvBoTO+208lyWpIu!$EOa4B^Bf^xZT2wyv6_pO-L6f?9t&W^P?$ut15f9soV zl2V)^JUQHd;Yc9_`ZW8jv%-BPQ>1N(E&Wo`%ds~nz#&UhTo4z;uLuRx*9#mj=YE3I z9fRLQ-Was8V5kiw8d=W>PK2E6+FlqPz5ZoX>RBiu053lT-Q9q%rb6$A@1BIrbrQuZ za`*AY+1X+CWAsPQ`{4>L#$8ixU|4rRsi$(aiM5zd2D92S5=K*q1@NyRc(O-<UCqQw zi=@Xc8CJsekx!h?Pv&t4)Q8e5g93a6+~(TIToN)YTxR2Qa&<`urZ9lStY<$yrfJNa zaN}SZF8S-{X?_11`&2uHVzpLKTP!@&x>x9(9k8u4K6w0Gv;QuioCVU(?W67S()Wc& z#AoO(gyc*Z1RLwu_O@AEU2NYl=1=X7sy-2+Ugt)YLvJIzG=Uyz>ozyXdpet~*NPFH zqmX3UwjdV%ZqR<Vab5v+*&B73(r`yh6><9u!s2q#giA(ieg;3%%s9+=n*7ctd9KSb z^CwJK!Pz+Me5+9Q&OT3Ws)9{TCi9NjZrS3<LBtW1T>p=iT`$4-o*NuX3R&AckyGKX z>>{yr@&a4t!}ep%9OFL3x>~zJE;R*Rv`VH!C%S3o5A9TlC@8QU$663SRF`iAW#;#5 z9x<Bo>bYIQcQ=ZCTiM%aW6dv+qzoKh?e6w)1rF1b<W-DEh)LL{F*<HGSzO-(o%$x# z+O~W9+;VTDB+^;%$t4BlBt5!DE4NoCvdlUP4p353&M%?gT2_!_NSjCVdre{~o{=b? z5jK5?u@EHer)i)#9R@It{jkp;vn?LFc2^E5=RC{%UQrctp`X%*Upq{)My=ikA#s|! z_3T>08O`CYk0`TdU5YTKS8tT+y`Z+=_t$rUT`C|ZdC%6%%h1zdHmS#Y`?O)m{^wks zZu~3dZm}2RN9umn?$!6e15Qu$!w4ZoR}_gI1)l``eWB&49J!o)8LK156q+~-4Yz}Z z;VEBKm;?kHrY$>Cl8G`q+ZncQ#DVk)lImlPxCS78514+ff@1i#ZypVZ*m6=9=Dp53 zoaMKE1PE^><E39npFt;YU|;=X{lJ9nZpj_jt|5)W1u$Q=U}@9**|(N_cu}MMIV8AV zTwV|O7CRp1Pz5a+*vaAreWCve31|i#8Tqgr$%U`V+Esu*8h$b4acfqC<aly_^r8G! z$dL2%8<;u;+jOz9=fZX}7iN15>eNT}(!r)<*&=!>2a?75VoZ7m(}}bXx$&-)HT(WZ zwB@;AP_b>YN*rHg#ZM0^H8D{xGuo*pN=N~h7y0r&jl5a&AQd|GR?;>3o0^Z9$K&4_ zyU%`ns)_bwaHdIPoN~$yIbd0)Af$m`7O`vgXB!jFUlyzosLt}$uDtH>5Ae3!_MN#0 zRJGCJBDM}o^$|P=zK5x;ksJD4Upq3<$jh$PAFQQ^JHnaA5r>HnkK#ICtQ|u7aAGsG z`{xWJ+}F`ra&271kRJC@AG{;}ZhuaKUZtpUB}e<kCztERi-Em+z+fN8miTVmmr96B zr{q^=W2i`tV+>Ze*AKt!d%!swOjULLSr7My3yxQMo9^@Q*Ak9(NlT?|2Cj3y-f8ln z==x!rjeDC7vA{l7n&l$nFZq6L#8~c+N}%}a-y`Jyzg)>G@$BNG@Od&~bN0P^Tlty1 zsh;|I$)}KzFB7Y4%!$=hjrnq1)O+LgR}fk=?fnCZME1Sf8tanglu7l@md}Q5in15h z-;LxzXMLAYt>c4F^{&CiULrQNvN1$&d_4tyi@mUJqy$ghQj1xZtP3Bir=fElU6nlj zPL&*_vhT|hbVwm68etxs%j?CiZaG{aklf+n8!q$|E-nw*)ruRaFpn6t>g}Y(8rh=+ z1aYArXX&B%7Rs7k1r|WEr&4K!19G1ol&o~vdZ5wsM!nkWL0MVQtF$2k31YL1$XBe6 z%3j7t)#)W(Y{zJkkFH`R#M|&<Al_MpQMJ7D3V1yN$7w;a44G>reGN;FxnXQ7J2EPU zSPs96r{On8PZ7%lSaUt$j1hO}R=dtAHBTRTLu8}p>94mwRWOTNC}(YsNw4wpbqJj0 zSTe+50xoOlYH;FRJ?ZS0`o)h-uz#o%+rP&0p`>GU%G54yTO_$iiJMKIgwktOiN0PY z@KN-HZ>+wE)&tG-l=o~Hxi~$e?Cp^qxZQQPvU2)NHA<G>!o&J&Id_wdV+2Z9Yj?)q zYV3!d3qSQ;&Y*hKTy_*6e#|XXO$_cJF4Y;B?h9tL0^d%m^PbHzZbMLalYGM)2{T|F zvi5Y%P|FAH`@E#iS3wgmMXuFH7X^;c!q-}`Ez)qNR*1=L%B-0ye@W8O>gIyWC`I<f zeH7tn$9g$83|_A%e2vp19^EEOC#lsQO_sg*VaxQW=105$s?9xcI`m3pd0p6GM@d1u z=Y)5|LiM%~X512c4?OiQcEyOGKP3)3<Jzp>j}fpEMHMVu<SOPhd}W}|$#+2OAdIW1 z#|Dk6>*3x1h3ZC_#lx?04acEk|4GI5GL&3;b1hn~uJY5+V0r}KJs>bSKWE_TVu$7+ zSQs@~h2>n8tU3Xu9^(`gux*^MNjAcRemgku{YcEz<HtDKXCa#$ea>GdH1tL1`(E_0 z<;!Nuan3VX?pi#!Jq<a^;<SDG9*~>BlhM$4>T{fAf*NF`Mvq+L(?&%$ad-e%KCb8n z4@|;!J(<R&I>46^Mh<nquwDXZ$jt`F++i%jW-SE2nkmQjpN`#;{d!cfT^;)%)`Hvi zr0RAog55)+@q_#qX9Hig=0|QOQyoIYWn)(O4%!9K_i4OOn{<XD{c-3GmqNCTZS_C5 zB9h8yg;MWKN1uu?mz=nX-1$_6v^~9&TgB+5X)@O;eVIciQj5*vc@KP4F()*P);KDh zOS&3pf564DTN<NNLcd|VuY5$d)G5SJH^r25_oJoGxT&;R<Wo&k7(;oT-Wvy0CC@^y zj#?qlW&MZ~^KjxoAGTLc)(+J8`#ghHtrQp_9KdGX*xTg{I*Rz82)&2R$Halt+lsbL zexLCie?X6)UD8CSt+wz$1u%$%Gp)ImH4ZYFT*VwxvLet)H>9?s12vf(HZD}N-0m1h z*7IZgbEFMe$2QW2E6(-v&xJzswDsF4_dkR>TdX~&eJxddK<dCaW_@U5ZLPNaEdT`~ zPyu1#Qk;mlLW(T*dc4vy6VG#yqzloTID2X%QeMyS?H*|Dpz^6Y<P+Y@Sb3nkY74Qv zJ`4eR4xm+}0x2&2-4D|<xOR+fam7zX8ie8zC))O_@kVhek9S?KG^UPC_u0N<9WVQS zP?KM~2T0{la!OJYtuyFho3)T9-wp#L3twm*4U@t-j;Gq8q%g>8P3NHgjcNDn#(1AS z_A7F2^mlGjHGb)@_DKD@?a(ANTiys@EJvcju%yT!0hQWsA58;V{2KA>oxTKNLZ*Tz zo#`I1sf*(zPtTT5>-^7>R_{nD-N-2)W9LM^iMR(6xVDvg^a?(3>VG~-Y)13xSB5hF z$ov&KFCSD7PkVm!GH_KoO5!>$g(D73?H+=wwP)EYgw!~A<l7#~)~AgwdL)8TvjG-t zT~1q9hfe(zUwG<c%Vjd6C{FnL<9{6e|I2;5-=}z~$7=Ch-Z-1n*u7aEzKxA{O^mD1 z&uQRsADV4T@&<8FG=jJ@!pkPFg*AEHADI?0^K<ahx>JISXC8rP+j>N<{^1(B#eC@* zM^sk7CY&aU>56<+ymE8g)VuBh%*yV%8v_fXGVIK_$E}AkxB}|JIdJXqM#JKHn1w$3 z?4@deMgq-aqi`(75(gfnAo*lJ%bmGFS^1{1#>6$8*aumHyZu~|pt;sa-^}2mgU2X` z7&EoT!-`RMQqVXJ_pv0E9JdSM*Ig!dP#If%xpS&v+g7+8EF(h?Cah6EzGtlMoO)ys zo2Y2K(3sb^{9cSo$R>;HoPKZc_*oY%(IcJ{ybtaMNT}?>PedT`jQ#h3mARD-mmqCx zz}V)`r%FiJ+CFWcNN52uRMO$n!&7JnF5v@6=jhxZUxztf*lBC~`NEEmf%_S>AdFH5 zQ&+x^p~W!tiw9(+I;fa=uu+K$B_(9f`n!p=ngrO<D~qH(itlE#nF}U+j0VB`<uaZq z<Zjr`BFzgT?P<}^@m9>;p)&sBP~p}8jbhosw`Z)@yvfS5K;}+TmIk>&9mNTX0UJN! zZiP^KA+}4=w>lpP=wv_GoYCpJX(;54q%vZ6CS7w#DMUI2bqhugJ%;rT>ldq-rU+4r zfP{;k9L@zXS(S9kB{$7rt~Y8v!*8qvXyca%;50-iYEagS=8s@;#m78Cy}I(3k}}Ix zhmni)YDPbWFx`gQy;ib9W>_8%dCDLgd3aS_=jUa+V!ltn92~FXIS`6#--#y*D{f+K zJrQp7R3~(&ZTj`y<$Wo$@Pdl{i59dIo;~5^dt9OKXuE>@A=W%VPrN7iApY6Zd>hr2 z?RWXH+6B|)rLab6PLHkbR5w_FB~w$?2doQk7Q{W(aUKGo=k_~D@Kir{_8`^V`BWxk zj<@HHdY>=x`FbU;InhJB07)+j_0Pcr#soh(v$k6nhckb`Jict^>ef}khsA%zMYq8p zz*L;QZEPP76fx~5TN#po?|~w4j!%f2M7yjD(JzeGSIH3pwemAd(q%0$`&<k5Xma_c z>6;+N$g!qoZ}r!sKVF-@`Y{y+Uek56qHiGW`!!Ugvvw%TsGM09_Iv|F`DYVjT1!K9 zO&x1RbnLMGu)fF1py`@i@`K^&JsZ442OjD*0n?CEX4zFMS7m`1Hf%xpt1c#QDb6ph zyhl9dx^)mqu_ANVk+<K6a<o%}DBjr*dUYKKt~lXs*Z6RZDA08U<JuAX)4n=cI;7qb z>={u{-4&+dw8fMwx0uR&`ZX$;eZc!7kN&vJS@@{#{ZBY|9+TQ>Z;eaLYwT!FneNxE zt#%j`n~m26EL2wupAwkW_ZDulB9Ck;wj|@P`qTCGzCLX_6>pLh|BB2pmrwQcBt0Oi z{Wbd|wg|>w3k*Ati6mt6NY}2NN|@+OJV<&a9p@^&MMy_dme(DJH}o-m+g`C~jd~&F zAF%aUyL!oD+x3^0L*4{%=xcA+fA-4{cK3^;jvuDKT7zoAvhFaE^2E76!U<`uGA1wf z-h}p-nvJm0AnvDF{$eHj`T45lk+dhTude)T%S@qmqz(+Rt!_aYKHyqP>S|~s&|_F* zd-Oq=h2Nm*x`ju0IqCYgyXi>lVBvsrr7{U6*hTco$&#&MUFN*oO=n6B;v8dYVGO2t z#cX`Yni;|{5bz()QE~s<wL!#C2^0xG{8eU|WL0eg#G-WfRQUQIYJXAsqO4|8X(^L3 zvAj2WEE!yxDzgxtT4^HuxKup@`+<q25KU+YA9jMe!?#!v(vXCQ`Xm+e5l-CdV1+bO zwYqFiDh7~#>5l^0(zE}5H*|;pR*_5pk?y?ZCVo8+%gf?sNg9V|S7pDXsWO`#N>ml4 zZ}=@?kncUAM^)zHi0fxgi0Mu+vg00@&61x2f98B^+U3$>a5q{-7FWN|q_rrG`C3zo zr0;DH&38dJIJ~hjY4W&aoY%cn$IioO?R0IiMZaY^myB*GdaVi6S<yd?1~s!@9e%?3 zxs28fopIEkYCpxKh1}WL-$tkH8UL4nZ(Cp*(#xK;UA<;}+&<K|XF|lBJ$yfPjdQMD zPK4HB4~|vLJ;Ix^Ya|{TBayrI27(7r9A{ke+qS5xZk{iPyG&`0J+U-VkSRo^eTcMn z?R&j@_4UX%*w*UBH%n6~V;q?u&#&+WY-n2Kz<C$YY22B$)s5os2}IF(GIZuhG3ErP z4Q7vdmMNToi}mZP=|-*`C)bVX8Ls}}(QOm6kP-)t6JSWNsem9EtL{_l4DYZbY>Ip3 z9(ZWJ__$Oy*+7f}4g8H3H1*w1a!bp#o40szE<>?0IuN#&<LIeUDU^k)wa?lVEumYg zafGo3+ST(eSP)=wc`A#YcAiyeA>s;pI{3}O1J}l53g10%4!ytdqec(?T$MY?>_TKt z+goNiN1fW&0m_UvLJN#5k-^v27Zs~0@=TS+wSXO~<?f)3X&i>AOW@&<pk$Lf*MM4e zjhI^V3SRr^oF~#)vqjDpBhBtnl_5H>RC>EsZU~%t<@HGAyMp|>EKO+zEC&&x#H}1R z$Y*9BhFz`f|EI6BifXIx_H|mUv`BH+P@rgm;*vsNthhTAFHqby6beNXq-c>AcZvju z;O<&nf@^RK^yJ&)>@oH^``h~>7b_R*V#!=<{(sMW)?5~7Zgc9w3g_C;{SZe|SV0t| z49zz={R`;J#8Itod}AzA{&L=#CL@x{ZFmI27vs5x6i76~_PIwuS~nWELiXRY_(Mk; zgWHcuGw?hxeo9<c7Po)2SLAVwKlOzZO%|kw@66oAj)kEFSkoV=+dfrXr+6p4XG=TV zJi$|y?%PY>JbvW1(}TJTj@DDBRx7)p4>j$YRj3*DzA0xz!our-PN%0>EZ!2qlD{dx zm}<CtyVZAWS$J0=L=Q~6`5WqsPdyvb3r?ll=h|3Jhy0y=3y$oVX{z@!5fWhHIzr{p z4#Y}pb_cjND9xQ_FN;;7e3JuD^XUlgq2;SDAG=o1f$6CG+Swh(MVaoLGqRdEg@KNX zLM7kViOH|olq=1Kb#w=R2@Xy`C?Zcutw*qf8b8tVAh*lKOzcu3Cd9%=xB4Zg&!@dn z2TK<Re}<n!ydhn5eavto32p?Pb61M0d4qKfzrq`I>9m4~GOpc0TJ)CSFM>b@_7rjY z4hgBRJkJJ^<~9tT?FW}Ykqg0d%ENH&?6-pQi`MAi>>poFJK%+1=Yf<~@gGFNGmL{V z9J1T0d)u4Z11Y9Sj|LM~SPh9wi8r>}6JUj$yz<?>-h^0Rx25&xf=<t5z1tkV2A4I@ z1u<H0t;N<L2b9XG#NBn|R&%2G`^HaqjsXZpk~md?sN(@U#p&%pLYzp>zWKABWAHl= z^1}@x<tiW<$#_no-5S$y9QHk|uTJcGBq(EUdkjVVxY4_K<y|}ed0T+e<b;8}|GkL{ zF9xF%rF1_F*lg1N-rk?#ht3Te4<oZN|F>(z{{yf2uX6c+fB(UW@gai{8*Ck2<@!LW z+;#tg=E&X|OU(H72{l^mXR2zIrr&Pcn;@b|PJ_n@Z)MhyiUXReI8=R&*OiAx8)ILX zZerI=Y&%l~Qi-o7t#qlFtT@m3FcL`5`=pXk;G4<$w~~Hmox5MW(f<gEDo4^3sJh<Z zxvpe*^Ln_GyT5nbylv-lW{OqZe+Njs&4OL11*2?zZN1_<k4P1QENPs9jhX~*eZ@zi zi5UQ?PwB^;-UH%GPVG)I71+-Nmwl)a!sCjrls@@EO2R`K=Luq0=#ErZKY}%L1PL>? zf-X3Rm=P7g>!NzThT*MPg+(s>3bJrpN-~wQgt*QLUUauH8ATZSd}xtw$Il?AlY1iy zxZH;Gp!g6C9u7vay137ca#Bs%k@+FNU(oYokK-)UX1I6kOu%@f=VtHJmF$Q~d;r>7 z4Kgt=Xi3I@ZjFkqd6S*#0N>7E>-!<MmhSz|HQIdg?F>bqhxieiX5RVDJqh$FTT@|v zo4~hN55eZgF-_fW;q8J`)hc*s$G;*`IE}N!qeNvSvq?g!*r*1s%Z$ci#H^68*4%`F z^S9qV^^XDnxVXk-5w`m3<O&^59Io?eK(+nZB4E+nYzhtVhB(Jyaz;y*%f3CcR0fJi zsr`hqCfzjAA&IPy^6QGd6Y(KJ=TirJCg>SejMKUWN21zt@?G+{$4BkYNWL(Pr4ZbU z%2EIOKPSXW;jY`N-C2cOe*p)2rQf$+2VLbztT1g*yt?$`ovz|31(zt>G$!TSIL<qz znMv>UXumNT11cam8ZadP0tPBdJN>v<VEl_+mg1#r_@$6Wz?s87KFQi+vu8o+`&^(v zlewvmtq23(M{G&|)0NirhClEB@wp+O>$dQe??>8E&phnhVU-T<W4GttK*6JJUy!SZ z+k&lPoUNL>^Gjj)tXpd&F^D$6gTrpDz<OP4&geMnH&S1f?$Rpr#6EFVRd>{Z)*}&^ z&bV{-bcC)+L4iuomL-cXwzZ*SOmM@}-A<C}*PW2cdaFW({qJq~Qb1Ty0D0S#Cu^ue zgHnIUR@$TK1E{mn;RI`bF9Bnl>x>uqdTGhUXS;0&b|YS5|0C<zcQYB(_LEdj65T0O zYSr9;e(s6At9B6CYVvG%<Cm7Y!J)k_`?L)+SWdn1m5UMGoP?{4^#yuuedhIgmRG+- zNWj;CF_)e^WYhrW*4p9>DIX7=W1K^G{I$*@M`+-q7xM*AdZBxad&^&dvfiMfqK>Px zFlU@(M`doOo{n8HL#&OD-nX)~v<s~IZkqdOvZ@9qo?lRlq4vN*|9ZDTu;F>8yk@e0 z8f%uC;MV8FRl#Aw>1fs`{S4lca^l+Sd5K)@=OJoUpd@ECLdt!}^VEV1+Y59sh?z}d z{5X12WNdu9x;NE9Yv}}3(7)^(Nie=_M=w061m)?iQ=mwkyOE!=33)%G&`_}TDNkmg zE!PB(HFXl~Fs7U)m**u%>=29Nmyl6Dvu4;L9aPHccwLrM=jHzoN&IUY{J&tW|53Io z%z90QkSSfOgiAN2y?3y-=)C!uA$L#4SPDtN*ej?t72EHM9C+r*4ZC+Y^rg=bg0*Tr zR&H-m4mlk%IXTU+%=sBx@%aVMumblSfFPtUS9bJj*H*Ixva`?Ah>qk)9v~N`qSj^+ zb#n<N8M2NJo^QWBVr)IRjW-*eJEF@0+dIrLkV}Z#53HY%nJ$?uZ0UR`@2ZWW!k}yZ ztw4*2&xp|*ZsSHG7MI$J&0U5Pub&|xe%oz}e7leA57{2*)^Inyymh;@;LpM`m(m*^ z>puZE;R5HcEp+^LepM*zsM)d?&Sa+Q`zs7CLnBxchjrP)C5Wc|f|BMw)mL}9($Aw3 z2vntx5q%ir43mw`r4ITSonK>wvBLQa3;ZrGN_6Y17l&H1q$TJPbOI(MdU9{PY$tSA zSQ@J8GN*5=RrjhIpXaxo6XT94^Y~4R!DA|zS|O8)dCpah=TG{X)L1rYpLUJ!KxQ_O zt2C*zxOqT342G`ueSg<QdRWr7@&RMq5xX3z2g@bfB3XwPK~|v$p9&{%FH^X8lDnhv zJUGNULGbxcUss0IHF|;R1htKK9p9u+@#^0Q7%wL}Q#T8pDOvCf<*db=&Sl#p7ikdg ztONP4UOJkO^INib^(yu~%`9@L>3eRlAe@3{oytxNKp~`pFDeYowZ@Ob`HgBQda@X^ z4QEc+zJHI>6@PhU+J!Nhz0NI#ucZl-iyn@p#4n6p*=|@&HmInsOv`gpln9vFr6*{E zDo!)UN2s(|H-G#Kh;@im(Xyjjv&z>IWhjF`Z=qT{xshKJo^|DdWCZ8BjJ*Tr`)@<n z>9Bq&9kHpa#BVy<;QWd4+-M_4!lBzOQ(R?l54v93Y8sRAe-^>~y*KK+*N-vVa?%YZ zhQ*4)$1Ar(9r$Qy!z9)Sd)w4rP%S;M8o;ZfHvc@xv?li{Maeb#*zk_^%Tw-rStQ#L zmSUU0EGI2%mY;$JY24IrR7RoR<%lnTkYgzcrd+cPk;*(6IKGVj;k$`1J``z&<J-Yj z+3GjMn<VQs_$`9}XW1`sHVWg4P5-85osJAVDJbqk_XQvkh5Hu}d?~nfcYX9?edvWR zyo%xIn#u2B1~X=74w@fiZPYwQV_fwl9%|OYkF()-Zp0Zd<Rp{WfJYlRwf9JxpS&n{ z>|)t)LKGSMU0ZMEFQ77h9wmD!+1q>-$&)c6-c0vELpY!*4pp8T7J#Slv3v~gxTutw z7F4S(OcGLJT-#xz&kn92*rzb(kP_Yzd4%n+zuAA@e<KmZszWz#v0&5qj}z7RxRo^z zP?9G#t?FFFL6{bNyWQ=F+(u6zPBCQ#NR=B;wJ6ADx&Lu*AC&1w*tIMb=+H~83&ksV z5-8y!k)@YiCrZi5zzG~)dl*J7bG8BpLH_WyWQJ#EDw8M^#E2|wyr*?_)cmj<ds2*? z>PSj)X!Myki8g@QBRkq+RXlCoujasgHMOI-WD_8zV00_VGEjf!rQ#>3WJg?Gd9R zt!2~|#{^IaU8bJ?yGa?){{s2`N9n5E+PUg$p#agg1hP1{g6o{-fQ5rw;C!&E*m0HJ z`Voox91MHjp<r>yozstn-2}SHc`I-eT0XXMaHQ2EY%5^zoroTBJNd9Rw(l@Klyk)D zd$VVh#2{>c$QGF!)IIl{Tt&>>)qYzTM?57oeoVt8yqtAD4M%y7({+I5I^R(E?XST8 zT%%0sn8~4Jizhrjqdru7T9VBp%*9lUw)71L(7{p}9UhIU7TaxO1Q0ISPzvR88Q5k> zQ~1naIoXimpGlycAi)0PfjxxEjPg*M_6bB>hqcL<1wZCDCF%yn(b$;IU7>H=Xx@PI z!<$jC(E_TCvsD%yX}xm)XQX)B!E7}FV4)3gzjlz?-cZyD;aNstWc{>4s+iZNPzZc< zEAhP^*t?s)Ju8gOy=`-D3X}wK3?)&F9$AVsFAg3boLehO{TT&Q?|a-A+yZ+~1Zbe9 z1&!bIcN$ZMSeQI9yhWrBE{egmDy`#o^2z!nVY>o<w6()#Vqa_9?T%Fj&=j{fY4=bu zDtR*Uos5&+S?Oi%Ywp)SPZ(4n5%`Yh_i`oUJjTso!~;$=Mry&hDc9%PvG(QY#6){x zK^57Q`27W(lD?1X<V(yP<hOBbZ6MCv^hTmTuHe_G!eMBEcKpNf&E-DM&$~J9z|Zsg zi<qJCO7|GOpD%u})_3DaJbrea^L{Sx4pB3Ggbl6+PtpP?fM<+|TRmA(@jqLoq_f+k zdhYM6h<R6gPd?ig&b1n=NYBjV^p0%+E~Rb}h53SUj(8%^u)PCav;8`}@qsd`QyEXi zsP|#lBDYJXVRfzHilbXE*d@<LIcR=(#oZRaGzkvrs5z?|+jZBT!ND7Lr`lP~%8pgS zA2-k+xHcxhJ(;YHp?;HTbS%U!!sI%QxSN{-S7V3LH{VO&sHtTMx||Qx_*k?#f8XZ& zs>kKVPhmGei^OFRWK}03A)(x~+KhTY)50Ov0hII-H!x>JpsceBG;Ay6kVgAsmV0w= z^YS}!x!Gk{_!G>Xctc=j&7JL(<MGiizNMk<FR{TzSb7ZJK&rk9EIV!Ty{&Fi(Ks(I zH-&3KNe!ld)7Jb8g~9n>V9I~pXc*gLi#Xbi==UcZaD;GOjHXsWsx+OeL?lU2jKgil z%(@Ug=~t!T<DLkK>~wgc^FnUt9W(}PJ4U;kuCuRiOed!Fg(Zrbzb;R;f7yjrP7jC< z3D2Kw9O(#(KU?72LSnF88@$8Rt4|R;%wO3_g2KfP1O5U^c~4B`Bs{MxWHzk%DQBuV zt7oN|+R3(sH}qL}a#^T%x)lqHC%)B0mJMaevld2#<CVDyT}WbcriB`qEWSdl)H9}2 z(9C@4-<3Q_-^;`&+a3ax_^<?-9Pq!MRm9auy~kLoW5v_LJ?FH3cao_8JFm()76EFK zd^mW`yfKucFk@&Cbjs*QpSn>~UNI?a%#hAMk~n=$dN5-Ew4+V3-uyVro-X)p5cmA0 zG|1Q@N7+k=Tz@PBsMShI>yLgQX8SqJ^Arq7@Vu`l$nyX~q*`=UN<~uq1fD+OhDsYX z86>mgwXae1(>=m~Z^?;B`QpRc$1Y2QeA7sKePgibs>Np<n){D`o&~9QBfOV)Xm?;* zFrxM>O}b%hzsq9RMvY8JiHU*5@A_{dRxAwGIM7N%>(-rxXdF;84i)OuxOOf&Mc(8V z|H~4V1jAs?RK?SOx_lXV!CLKmyX@++{)#j;`#f<+wpgUJgfeP3vyuaLmP*ZTE~+kK z#n?s0gIKkp&1*reU|OvlcUnivS1zqMlJI=mBB1beL;dsNwK@eSFg04c;~p`~qyJ^9 zShDmDpOM%1m-=mLXjEX<0X+zHy!Cal*p2oh!R;>KlC>zQRJ=0$k!ZTbc>`ad>#F~d zmsMfgnql9PE5h2sr!$3Ns1<Aos;X}{!B`{gVwd2x$nn3euuk9hSW+4Uc_`8AVQJ`p zyk2|q#S9<ZAqKYElfbZO1D%FvR4Z-_0ckary7C;D8y_YHC_QxL+C@b{UC@Q14G85d zr8YC;6CF7K#!r9;DJ~R!S-<=rC&B&~^HbS_p6=9JZlN9h*@~R1s+#vKQ^V`PSc*~s zS^#I%P4+38cELgM2}etK7I7!#`4auSEyz-x=*~2NZi*$~2;RKEmwTM0=es%bd{y>! zPm21>kl|i`cMM_kt1iOJ1fsuyCuZwZ1Csimfkh|dJCzaYrna{CZfJ1jy{8ITt@Xwi z8S>tIz4&_3bf19F6-<L)5zmR&hf76ue+X(40VPsUC$1REyW205+KxkIB%8g<#-b=X zAKkIRGeWYicS1#uWf=l^mKbdLo^mB$8!fB87B}{&9Di2yB^x5OtW#aPM(fdv3~=y! z_yKd)$GGkB)xj4SbNhZX*^+VJGl<3M{{kNTIHat!^*G1RTjhFkUQK%(M2&=RICw47 zST3|azr%`u@p_5S)tGF#Sr!=3K(;etkZHF}hgDFN2%udrRk<3X3AnKV1d+9eXonCy zEB9B?$n8|=zbq&W?CiNO6_)u$IMNpoB8Fk`^i>3cD&S#uSJqR*_@6bRkXG=A(X8cH zn+a5YM0+394{<Y4uR^nVUD#rtH}FtT^1h}N1!li<pR8CkA|r@DXC*-Fi)93vjaL1M zuu34`;+LmiJ`gA6O8Dh#D8yup1m%kuCt;~4jMQhP_L-}HPU<(!Bftsp%<WG_Jp1(2 z<V-~jqHRk__sy@t68u)4#?pmlZC&PSRQzt%g;>t_*4taMM?Yr8L^$asOBD+uCLKH8 zF-B(DabQ4IZE7Lsoa|aWuDJv7WLzt6^29>jN(K~tkafB0171&wLTTB)nvE|QlX&@( zZbp$o881ss8P7JV*E5&QYh-V|knL0M*hwN$Pkq8|Kb<rtbXspE`*&R^QceFffA?l+ z<CzCV_=@0^@|mw9%LxauG>5eHi`ruA^)o{3Hr<;fWWCvqgJsUD!|5$y1y{8+(S0ZT z^NQ_5VUqTX4oQa;<W<9jS>hW!Xb0s!p@!avGONbiDzc(M!sHLbj|(jn8)IR`g@${6 zJn)|_apd##*`7|MR#}lW86+9MchWDvd&FbL|F(AeN*j7JcS_8oJ2PEUtck%15Tm}z z{$^Io&;t$^b~U{r?D2!dSu)<b8jFTi&Hr+n_<hCU;7NKV+LPnZMGBE$oC=(mA( zI|b)1xJkN^KWQEnKUdJuDSTSa9eb!DyQ=I2-EcA--Xo$@J)jYF-f+T8s%IwGA5HX+ zK^LblmvWa8>f-6q6z-QCQ3K<!Bf{=GmAcmTR+&}pDd(4p_#<VdZ~0&E>Wn7=cO4Al zI{$4H@^6_ThbFmLmKZW^Vnq=EL0&q*GoT!O^UgeC+&n30%{Xp?N3kj|?p28lZU$5v zzxfN$&06(s#&eUhc_;=sk8pM>d9Hy&ruvHPm-<{w@g!RtcZUFbK<LRs$D-@rP2vWa z+`j3t(6jV_!p+olxiP^m-<<_=G+jflSSb@ua-_Uf8nK5l+s1{mJ%#szNk%rHH1;aq zeEs1}XC2N&qC}mUWMHl71mDWnDOz8cU5ss)=CVy4@SYIWfj+cn-5C&tHr_VP<v)+) zCX{lS-jZ<kc6N1{loMaGEWW4|OdN^D<7$3#kT@#IcVgl=6<Dg?zGaEGvoFFhTf8hy zcPL-uRmogtlxSP5cwhW-VJTb#`T^c*B2zDVkiJFu!<H=>WdSR%AnSW8lmCswo6fCf zfiE3Tk&2RIS<WA7?EmNqb&DU)JL)**EFhp#kO<YU7uqIYdBP6nlT|R&ekD|EOT)sh zU*ghLRZ><~h;O2NrLK1VWmK%va42~cFNws_`KlMB71cGLp7T|hUnWSaFW>3aq%uDN zzI9!u2+j9WsJeZF0W+Hm5Lxg;+TBAj29nl+lGRPukHLQ#L(ZMK{FtO;gF_|BVO|4$ zuPU}LJ5P7s{b(G|$CK+|y9kjioeH9PpYL!tQxIRw|9+=FsbP&?o^s6Z+>+EPPLxbS z9gAb%D@hd7HAIq=OO7Uso6W{!z3MrMO6e_wC*ge1?6Frv_*N1r#&%Qq9|HF<NqOar z1hHU0EpD`J<zQLRDnZhTHAF47IHnd2c2wVDppyajsVKAH)moI;bLn+ZWb<}azk=u6 zAtiu>h3Eb*s730dxUloMWud`7dAz-!cGZf(GNX@8SZMF=^7Hr(oCUbVu&X|btI_7- zWFkA)I+Y7fM(^ifT5^}Wy^0?|gsdg6w3LkTwpb^nS|%GJxW#h&HXkU$+Ln3azE;lA zMI>uixJbzyQ>-KN!4=|~7!!w!fdLHWNP?C0$`>K1+AIGV-}ys9Nr#>VD-g<?+D;lP z=vuRTzZRv!ki3diU;N=C1@y7(y88I4Ei=zahmLea;_F`k#|_Uswzu3OCEiXEDv<M# zVR7`r1m*SVOFwMN5jfVkvID=@IW3d&_&A&f@IErj+Z=jG&i-{P707!vm{nN%$vb|@ z=mGNhE_*5HCj(OOmzc`Oj>Yeily3OG%b9%~3Gt16PM0%%UXH(bX`G>yK8wF7_azTz zBrFRIV!N3?5dx=Rwo3z8r)NC<5GS<Iq_?Krsi!5|u2y{Axuvk^3WU(BJeoWvge|&A zimgpq{kbE&a(pOl<9Qs+;(*+Dri}Ui9AW-(M7=&x)1-W+?Y^Z1ZDz(pQ@(FD;HB^o zI3<eWbZ5Oc{#3Z#TPo;B3EK#b<w#woPcp7HNu9!Ch&WPC8XF$9=)b$A_S>Gp`^Km# z8(CQkw?L<rC*A0iuh;!FWyPs@&BS%uKKYrOJhFVIK>|0IPF~*Z``QsB)r0+naeYXD z<GNYI3i(uv!&><VZX?;59E0)-bH~AbfBN+=>)+RkF<(BbDEMzhjPUP&!(MJJuVNoc zT8NN1Dh_BG&Y4v8NBPBOz-RnP#Xq(deuOQ{;i43(KN4#-1k$6LC7U-Wy0fuRT*%GG z*QcX}<Z0&5M0niJ>a8MihK~aQcc*6G;4qw{p^cO1XwP*J=4}=|GMX3?^{2VT%wSn< z@Y|zrao=^c*R4B(q4$I~z~Yo83wT;kFqc5rNg1yD!h?;8S$SRWQc{t%h4~B(z_Veu zis^geo9<vKzfasUB3j+&=lclzBHj|=P5-IUz%^SHmhME!`FbtASaoBwu8_~$ZO=vB zHLBr0sB;PqAlM<3LGdfI0?1C%cVK~<h#_($yOiC+lS@fZZ{zKPU;3HJu2OzyJ%z9y zqczTP$DJEkOJB3uV7b=zc)MAJU$C}Df#mnj(lsd4?QXe>m<q>F2Vs?#PsLfQ*Hj;M z#YInOY5ZG2UujFFPl9?L*2w+=X50)5c_gNFhY;qwOM1#JzU&ecs}PH-rBrx>3N>!> zoh4vSi4&uq4_^Z@&dBA?M-A-jG}I-`NB0cU!*sQy)?E;u9-;==VxjtTUQnWQrcH0s zyz(l=jH901MZSdPD9iEb*F~x=A236g+;7o<nuB9he;$2Xc;kIhIynHsDSpLXixt~( ztM<LG3X#2qD!J2VeTS3p?&-90<?r-z3*6+(@U3uNMVk!r?a*f<kNgmZU(iUnoaS|( zCBI{IYHXkuE+b0EPbjD-vnBT~tfR67WSb4S8|&hnMjqEQH6URZ!Adj<Dy4kepPJ&t zn;?|#b7be**W~K>hwYYgC{FAXt=3ctp${@eLvJ>Z&{b@w$9!FvAXC<3G=r7H!=^;b z>(j%=H}xq&8jse=W6P%cRBS~iSLQh1QQi8B#nl?#;XfGXl{>4_r)H4>yk5L5;>AmL zQ>EC;nC0{emw>fLW;ohy{1*@<#c}fud4|wDrH!~wPQm}os<U9FBkMSfL(}G@fFXFh zV%K%n)wl54B#3RFikIX)3CL>QE^zmz@~U<QyXthzC`*Woh&zW0O&`Bv7;O>drYpz% zh-%k!KFwCAF6>e9+Z4J~?EZLnYfp+UVB1G@UTzLYXS-+Pg$%E58M17qwtIB4eL=(h zwXi1LhiiaGMY=eZbM0;VeCVwstbJc(#A?~zbzwBRR<wUf63fFdaH|bk>O0m0$pcu3 zv4rLZf_hsqeIb3XojpAZm5ELD3ajqs91G1jD$^+Vgb5n=viGzO{N8%oTL(X3755PA zTr?gjSi*F|fnWYAB~F{!zjImO`M6~iXHUng5oPr_+6LkY(ppyetgo8#CNtN=aV8Mo zZDAxM+3og}@cS7)p>%e@W8Ysu9WNTZvsNR02#Y?T$DPjCo%X16!uAm+&qF3YnY%G| zSqhfF#6iM0QogkD-H7$|feB$Emy)cvZd5)AY<(l7#WO6XF@?7u=T7B+?Q<3_zEEuR zWMCQteYjh^GJPm$V+tCj=cld=bCS5HNyxcYNsFj!jRc2PU0Z2nCOk=!aLWtzYUKX& z*u-8*aYJ^x)6P)K5c2Uf`-{`Hhf=fXGYTPh1goev7*QsrOB*^zKVk6wzeX3}{})WT z3BBrmD0X~&{t2fuh&0XWG`y6EqYIDA+(}}V;d}zVl?pnc2jCdKwH9^jj!GicnNPYm z4Ep2e+;MLN#q=RoI0-Q0Pf9kW=N5T0x=lxI>_+l)fB6fF77a4PoQd}94cqFyxi2p_ zW6`bL)@J--f_|3D`?3S?1=!~GT+Q2S3W7;RV3n=y=VS{tmc#_b17nZL8gh(Q|BIsD z3}1~+)zTj=A$ITS{`8md<S%aRa>xf@j5%HE<eQIgSEXBbdNKLj?U1EOB|{92!|v!g z(2j}F$>L>`w=SZq^^j$UEQj~@0mJK;2hskYB3SrL`T5<{-T^k#5#|uNA4lGR3Vxum z2Trln&P91~oQeI17=ED1&chxdL&9HxSko0Ue$M&8*jcMIeSvhX@m+)ExVA8{tZNde zT*&_|4!iVNA(>*X2OHz5-qG6{EET6TsK3pGjY1#&jNvRY6b2=0-r4!Kr+<9~sLXbp zyGcQDX6}`|jc#;O$Z3J%$K1`5^a+;zP#E+oG+M5vEAO+P;if%+-HwPCXqeJKKQusC zC<PN)h>hxp2CoFUG}k=ysXRW8FE%sNjKsKc3QpL{KtR3qlgbeP8O~^v?*0sF%?R4q zp3?R}`Er>malE36a*NeqM7-9ks3+}YeD6jrXn;&zbOo7$nLQN-iX8qB*yO-xz^&gj z&@D#r(?-Y+vmzT?`SamIw+x~^6WTi~cN7v8yZ2`nb9?|JbyM?M*%l36Oh!ifee{*h zX=Yn2a<NBO^Ue9^V`3}QO*Q(}?Ih%u*CX~RX*$`_G~WG3_}5-U-PUc~BYJQt?T2}$ zA#upk<(Y)VugI8{#lUT|$m5Zd2-u5iH=DH7?7sBm4%K0F=(JsxM!kLZ{!bOC+_TQ* zYos16^--?sgvKERPsP-3;M(TZW9nARCCI<rGdbD8Gp9^5U|mX6DwAVaw^Xp1m0$h? z>}Rc=z`RQ5@H5OSr<s|mQ9C>LG)5xPp??574M+M}jFaTr4yk=?<!C{JCmv{dl(3-! zqD|wPogm$DiJjjq|HF==+HeUoXt|mC(373HvF<#VDz<MJ)HKs)KMS>WW6=m>ZEEFk z=l<eUBI5k3NbM)BWJa~!UGQ^oG;=G<C~cod20bA?Y$pg<cP}v{=CKwc9<}$jw32_G z-(N>g7duc5$%)v3JYxGy&h-UhwhEocyqalFa6HZ#HGCcCsrBblYcS5?F8m?$FW{3i zR?tKiW^~UA8JPK)u4<p0pnb$vlxksF82ItK%bTw85S-H!TRz?SY0!CPA$l<pzCh9g zu37DN;HB{iTrl$N7QT|LqT9+PY7;{5&QtD@9B|PuG&8~Z{%$L$K`k6iEWvi_+(E6^ zO^9U@J;I5e$f4Rjt(S+$K2pdHR$l=po140S|0j#_U;J7agF%7;x)W`9D2Zv5d+CN; zof*&UQy1ID#0Uia{1((2^Qv<D+Xe&V5>9{fL-SNG;@I#+ecHy(+6^3WMHh^L?%)Af zfpB!13AkBW5xz+Xz{y*3nrLA$B!BK!ZJK>Kc2X13S3olh7d+nKQdM<x*mDtawtdk$ zzhO}-Iyz*fm;Q0d7JgtbDWWSP5%_wH^;tWjRXrVHpCA@hyhNf)w0V#|n!c|0Yfoo8 zZMn_x7pwfrk#UW4vCFZ-wNXuC)WGzy)tfh)fgFlLrPdIR%+2`Ja3jdAV3>-=gi7tT z=%RVru~}mxLr5^kJ%dKP!4=OJ21$dZN1NKGF8Xf}St@SEdo`bnIjjN-$x_gIvoUo} zjWdEk4&t>34x_hQjlpLfOdaBexz7ANL1*_mLqn81n1zEgW3Zl)uRmC~9E1a-ew!?C z_u70l|EA6<M76@K(dytQ1X+LI>9VYFq;u>jv6R_t^??6=oP?YvEMDk$zaVY$wm>6+ z`eRb+i>{7+PPy4bTL(9MP46Wvymw?4qQ19H+ObZ2+j9KkQAPWD>7}8vr=O<c%#EuK zIYg%GO{W*_PS3KEoQD?P^KyVcd{UF)Wv7iQySgox75(-7%|@zmCm;VsUcxgcQm%b| zG5QVI0$1pwphk{li6PY&?|ee8>PPIxS>0Hq4|6O2GwIrx;)C?Q=|f<=l6;tC<f9I8 z#4sl=P6k<1RmC3q`z~U7*@oFXd%~`vBYq!(eNDfmyBcD6bK6bYpe>iv-ocB;Ttgi= zFkQ%dvUW+)@<3G(Kj^J{ixqW21*g4I3G>Qg{yu?;o9n~+Y?+<bj~_yHY}avTaMg_> zJ1tyC7FdveK-b-j&nthLb!Mc13U0yydFRHT0f=r*fLM2=qfu@#z(4AcXI)R81ABmi zxuKbMVPDd9<h`yX`PJglY_%cDdBKOkKoE7$q?Jz&5gf~>BH>O5)(A2jY>L#>@T7Rb zwCN`d9{ry4Y_+CgIc!Wa)}yLF$bg~}?E`FYcr#c=h}|5GJL{uJdzw918%k2Ib>VRJ z?4g3^@u|-dif!XZa$<+!Mf6oIOT69dTiHp1pxwU!eVi3jzoN>$sL``2_1f^qPOHYc zM%jedmLGR_5gdbEA<slHJ;_k-3VvQ0#t3t`!onS{P9AX)_m)CmiuYClZOkUe6PHw& zVsx9|KsF6=TaL!rx3;fEp!XGC7v?Zk;b|om!lgm>oGLD~@(1vrxI!f}+7!Ub@D+}W zl0_t2Q;-X7IqEbCP8SY+^+z4zUSYR-!C!&b3gE=)lqdmY)2Q)N8trCvA4!W~22=!? zW4}XVrzq#@P51O>sO_d%gr`yFhdYO%6uSy1y1WEAQ5!E&8@B1hL}SO{=1BVNopPg= zY<H&-t2za?pOr<$EIxdYbg~sK2+B|QpGo?>%P~Q>4Rf5qLT+R7;tg?Ez7T+ujaf?- zGIxI&%Vjn}ZaQZr9F?N+t78-KvyAh>g2uIO!<>dbO4Rb^`ObEr?mf01`2e($z%8iE zH$S9vh2&aPa!l)Hj<zrml8;5#sq%T~F=u)6!d6^<%RmpbFsJnRTQ)?M)T6v0OsCEC zBDiQ@q%2(w$YL&2U&U_rR)A3BK<lC40q2BC597WNWsmw@JYWh_8uk!3Y+U#>%k6<R z1MD3L{U?wTY?>sJAPV4+pVqOX0dA{zmip>$9z*$r1L5mh?CGyrO|64U+&I3Uc6idr zzd_w=^<{**(Y0%<@QXVpc`?`zJ`CD2_&R#$_p?TGQ|uWgQ+Eq<5StRVdJshPYeia` z?-@%~=1QjB>l7%<CqhcmEC0p6C#Fpd`dqTCjI%CBK0q-xJxH5$Yfpbixz7bV{A#X; zYzw%Oi&6n6zc~d*k?Sp!W^r05X#R6<Nj0XiXRO^(ZoMQ*HffiF3RVz3*puzmi&s{Q znyP8geVFnPe0B8O<D4WnC@GRAH5)tKi)ivzR&`1y0k?lo(@>-_hBe51GQ*N7;*rTP zEMl3Tp94GQc`de>yTaZottMF%KB4Pui4qZGXg@H0j*%#;;xt4GMzEH)<Bk4U!+^*& zcJqUjwBUDs0{u#m;g08`CKJh%@$;M6lrR<&gAv^OiI?)@6FB3J=~{p;U{Sfg6$Lqs zn*P|XgOruHccn=2+dWcoHd{(&$WPhAkt_d8t{_d9prl{LofvevaXxptlAX7D5?+E6 z#uokx$2bL3H|neJc=jeA3i<}wcqu?(?!rW*&8u_i@B(GW<B+VcYY+HF(~e2DgMm{c zgeJj)FPx<W<J>-k-s!!jL5(=_KDpVcI&>I+iQyDF6}91c&sv`{Cf%_U)kvK7&9C4s zyN|U<c_se7w6*>c(ns){t4I@!KlB`JHkSI~GkYD16E2uMoI4@tMI?n|^T1hMJ;TFP z1=*gp3Ey~GEw}43z+%fWC@+&|MPy9S%q~=A3=SX&>~Szu1=ncN1{4%4X&O604>7Lf zZV(Rl(kLvn?+=4tu_P6%pd`u{^0>J916YT`rFcjtyMTc?&5&wi3##{P6lf_Ro$66y zr_`$kC2n0-=Vdt-af_zDcjHx5pd~Iz&bvHaJdD@<5+UN#1NwPr&$gz(-}(OoBzxsG literal 0 HcmV?d00001 diff --git a/aio/content/marketing/contributors.json b/aio/content/marketing/contributors.json index 82daf6651d352..27538d4cdf9ea 100644 --- a/aio/content/marketing/contributors.json +++ b/aio/content/marketing/contributors.json @@ -806,6 +806,14 @@ "bio": "Kwinten is a GDE for Angular with a passion for reactive coding. He works as a software engineer for Stackblitz. He shares his passion for Angular and coding through blogposts and training sessions with the company he co-founded called Strongbrew.", "groups": ["GDE"] }, + "doguhan": { + "name": "Doguhan Uluca", + "picture": "doguhan.jpg", + "twitter": "duluca", + "website": "https://angularforenterprise.com", + "bio": "Doguhan is a GDE in Angular and Web Technologies. He is the author of Angular for Enterprise-Ready Web Applications, a speaker, organizer for AngularDC, and OSS contributor. When away from a screen, he enjoys playing Go, building legos, and claims to be an avid mixologist.", + "groups": ["GDE"] + }, "juleskremer": { "name": "Jules Kremer", "picture": "juleskremer.jpg", From 8be8466a00aa64661c0a45d8f74746433367bc3e Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Mon, 6 Apr 2020 08:30:08 +0100 Subject: [PATCH 108/262] style(ngcc): reformat of ngcc after clang update (#36447) PR Close #36447 --- packages/compiler-cli/ngcc/index.ts | 5 +- packages/compiler-cli/ngcc/main-ngcc.ts | 7 +- .../ngcc/src/analysis/decoration_analyzer.ts | 28 ++- .../module_with_providers_analyzer.ts | 21 +- .../src/analysis/ngcc_references_registry.ts | 4 +- .../ngcc/src/analysis/ngcc_trait_compiler.ts | 8 +- .../analysis/private_declarations_analyzer.ts | 7 +- .../compiler-cli/ngcc/src/analysis/util.ts | 2 +- .../dependencies/commonjs_dependency_host.ts | 8 +- .../src/dependencies/dependency_resolver.ts | 9 +- .../ngcc/src/dependencies/module_resolver.ts | 6 +- .../src/dependencies/umd_dependency_host.ts | 4 +- .../directory_walker_entry_point_finder.ts | 3 +- .../targeted_entry_point_finder.ts | 9 +- .../ngcc/src/entry_point_finder/utils.ts | 9 +- .../ngcc/src/execution/cluster/api.ts | 2 +- .../ngcc/src/execution/cluster/executor.ts | 4 +- .../ngcc/src/execution/cluster/master.ts | 2 +- .../execution/cluster/package_json_updater.ts | 2 +- .../ngcc/src/execution/cluster/utils.ts | 4 +- .../src/execution/single_process_executor.ts | 4 +- .../ngcc/src/execution/tasks/api.ts | 2 +- .../ngcc/src/execution/tasks/completion.ts | 21 +- .../execution/tasks/queues/base_task_queue.ts | 10 +- .../tasks/queues/parallel_task_queue.ts | 4 +- .../ngcc/src/execution/tasks/utils.ts | 18 +- .../ngcc/src/host/commonjs_host.ts | 3 +- .../ngcc/src/host/commonjs_umd_utils.ts | 11 +- .../compiler-cli/ngcc/src/host/umd_host.ts | 6 +- .../ngcc/src/locking/async_locker.ts | 9 +- .../lock_file_with_child_process/index.ts | 4 +- .../lock_file_with_child_process/unlocker.ts | 8 +- .../ngcc/src/locking/sync_locker.ts | 3 +- .../ngcc/src/logging/console_logger.ts | 2 +- packages/compiler-cli/ngcc/src/main.ts | 40 ++-- .../missing_injectable_migration.ts | 6 +- .../compiler-cli/ngcc/src/migrations/utils.ts | 9 +- .../ngcc/src/packages/bundle_program.ts | 20 +- .../ngcc/src/packages/configuration.ts | 14 +- .../ngcc/src/packages/entry_point.ts | 18 +- .../ngcc/src/packages/entry_point_bundle.ts | 13 +- .../ngcc/src/packages/entry_point_manifest.ts | 15 +- .../packages/patch_ts_expando_initializer.ts | 59 ++++-- .../ngcc/src/packages/transformer.ts | 21 +- .../rendering/commonjs_rendering_formatter.ts | 4 +- .../ngcc/src/rendering/dts_renderer.ts | 22 ++- .../src/rendering/esm5_rendering_formatter.ts | 8 +- .../src/rendering/esm_rendering_formatter.ts | 17 +- .../ngcc/src/rendering/renderer.ts | 17 +- .../ngcc/src/rendering/rendering_formatter.ts | 3 +- .../ngcc/src/rendering/source_maps.ts | 16 +- .../src/rendering/umd_rendering_formatter.ts | 14 +- .../compiler-cli/ngcc/src/rendering/utils.ts | 4 +- .../ngcc/src/sourcemaps/segment_marker.ts | 10 +- .../ngcc/src/sourcemaps/source_file.ts | 19 +- .../ngcc/src/sourcemaps/source_file_loader.ts | 12 +- packages/compiler-cli/ngcc/src/utils.ts | 13 +- .../writing/cleaning/cleaning_strategies.ts | 11 +- .../ngcc/src/writing/in_place_file_writer.ts | 7 +- .../writing/new_entry_point_file_writer.ts | 6 +- .../ngcc/src/writing/package_json_updater.ts | 4 +- .../test/analysis/decoration_analyzer_spec.ts | 59 +++--- .../ngcc/test/analysis/migration_host_spec.ts | 18 +- .../module_with_providers_analyzer_spec.ts | 37 ++-- .../test/analysis/ngcc_trait_compiler_spec.ts | 30 ++- .../private_declarations_analyzer_spec.ts | 6 +- .../test/analysis/references_registry_spec.ts | 10 +- .../analysis/switch_marker_analyzer_spec.ts | 11 +- .../commonjs_dependency_host_spec.ts | 26 ++- .../dependencies/dependency_resolver_spec.ts | 16 +- .../dependencies/dts_dependency_host_spec.ts | 1 - .../dependencies/esm_dependency_host_spec.ts | 1 - .../dependencies/umd_dependency_host_spec.ts | 6 +- ...irectory_walker_entry_point_finder_spec.ts | 4 +- .../targeted_entry_point_finder_spec.ts | 5 +- .../test/entry_point_finder/utils_spec.ts | 7 +- .../test/execution/cluster/executor_spec.ts | 18 +- .../cluster/package_json_updater_spec.ts | 5 +- .../test/execution/cluster/worker_spec.ts | 12 +- .../ngcc/test/execution/helpers.ts | 6 +- .../single_processor_executor_spec.ts | 18 +- .../tasks/queues/parallel_task_queue_spec.ts | 20 +- .../tasks/queues/serial_task_queue_spec.ts | 22 +-- .../ngcc/test/helpers/mock_lock_file.ts | 8 +- .../ngcc/test/helpers/mock_logger.ts | 18 +- .../compiler-cli/ngcc/test/helpers/utils.ts | 9 +- .../host/commonjs_host_import_helper_spec.ts | 14 +- .../host/esm2015_host_import_helper_spec.ts | 102 +++++----- .../test/host/esm5_host_import_helper_spec.ts | 121 ++++++------ .../test/host/umd_host_import_helper_spec.ts | 26 +-- packages/compiler-cli/ngcc/test/host/util.ts | 7 +- .../ngcc/test/integration/ngcc_spec.ts | 75 ++++--- .../ngcc/test/integration/util.ts | 20 +- .../ngcc/test/locking/async_locker_spec.ts | 25 +-- .../lockfile_with_child_process/index_spec.ts | 8 +- .../lockfile_with_child_process/util_spec.ts | 7 +- .../ngcc/test/locking/sync_locker_spec.ts | 7 +- .../missing_injectable_migration_spec.ts | 66 ++++--- .../undecorated_parent_migration_spec.ts | 55 +++--- .../ngcc/test/packages/build_marker_spec.ts | 7 +- .../ngcc/test/packages/configuration_spec.ts | 33 ++-- .../test/packages/entry_point_bundle_spec.ts | 9 +- .../packages/entry_point_manifest_spec.ts | 18 +- .../ngcc/test/packages/entry_point_spec.ts | 108 +++++----- .../commonjs_rendering_formatter_spec.ts | 66 +++---- .../ngcc/test/rendering/dts_renderer_spec.ts | 77 +++++--- .../esm5_rendering_formatter_spec.ts | 84 ++++---- .../rendering/esm_rendering_formatter_spec.ts | 84 ++++---- .../ngcc/test/rendering/renderer_spec.ts | 186 +++++++++++++----- .../rendering/umd_rendering_formatter_spec.ts | 73 +++---- .../sourcemaps/source_file_loader_spec.ts | 56 +++--- .../ngcc/test/sourcemaps/source_file_spec.ts | 32 +-- packages/compiler-cli/ngcc/test/utils_spec.ts | 2 +- .../cleaning/cleaning_strategies_spec.ts | 12 +- .../writing/cleaning/package_cleaner_spec.ts | 2 +- .../test/writing/in_place_file_writer_spec.ts | 9 +- .../new_entry_point_file_writer_spec.ts | 13 +- .../test/writing/package_json_updater_spec.ts | 2 +- 118 files changed, 1385 insertions(+), 1045 deletions(-) diff --git a/packages/compiler-cli/ngcc/index.ts b/packages/compiler-cli/ngcc/index.ts index 0c1a5810b0bbc..db94fc695ab89 100644 --- a/packages/compiler-cli/ngcc/index.ts +++ b/packages/compiler-cli/ngcc/index.ts @@ -7,9 +7,10 @@ */ import {CachedFileSystem, NodeJSFileSystem, setFileSystem} from '../src/ngtsc/file_system'; -import {AsyncNgccOptions, NgccOptions, SyncNgccOptions, mainNgcc} from './src/main'; +import {AsyncNgccOptions, mainNgcc, NgccOptions, SyncNgccOptions} from './src/main'; + export {ConsoleLogger} from './src/logging/console_logger'; -export {LogLevel, Logger} from './src/logging/logger'; +export {Logger, LogLevel} from './src/logging/logger'; export {AsyncNgccOptions, NgccOptions, SyncNgccOptions} from './src/main'; export {PathMappings} from './src/utils'; diff --git a/packages/compiler-cli/ngcc/main-ngcc.ts b/packages/compiler-cli/ngcc/main-ngcc.ts index cd88da9518eef..05279057c13a2 100644 --- a/packages/compiler-cli/ngcc/main-ngcc.ts +++ b/packages/compiler-cli/ngcc/main-ngcc.ts @@ -125,7 +125,7 @@ if (require.main === module) { // And we have to convert the option to a string to handle `no-tsconfig`, which will be `false`. const tsConfigPath = `${options['tsconfig']}` === 'false' ? null : options['tsconfig']; - (async() => { + (async () => { try { const logger = logLevel && new ConsoleLogger(LogLevel[logLevel]); @@ -137,7 +137,10 @@ if (require.main === module) { createNewEntryPointFormats, logger, enableI18nLegacyMessageIdFormat, - async: options['async'], invalidateEntryPointManifest, errorOnFailedEntryPoint, tsConfigPath + async: options['async'], + invalidateEntryPointManifest, + errorOnFailedEntryPoint, + tsConfigPath }); if (logger) { diff --git a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts index a8e02ccc3f141..2b66c5662dd1a 100644 --- a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts @@ -12,7 +12,7 @@ import {ParsedConfiguration} from '../../..'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations'; import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles'; import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics'; -import {FileSystem, LogicalFileSystem, absoluteFrom, dirname, resolve} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, dirname, FileSystem, LogicalFileSystem, resolve} from '../../../src/ngtsc/file_system'; import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, PrivateExportAliasingHost, Reexport, ReferenceEmitter} from '../../../src/ngtsc/imports'; import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../../src/ngtsc/metadata'; import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator'; @@ -28,7 +28,7 @@ import {EntryPointBundle} from '../packages/entry_point_bundle'; import {DefaultMigrationHost} from './migration_host'; import {NgccTraitCompiler} from './ngcc_trait_compiler'; import {CompiledClass, CompiledFile, DecorationAnalyses} from './types'; -import {NOOP_DEPENDENCY_TRACKER, isWithinPackage} from './util'; +import {isWithinPackage, NOOP_DEPENDENCY_TRACKER} from './util'; @@ -38,8 +38,12 @@ import {NOOP_DEPENDENCY_TRACKER, isWithinPackage} from './util'; class NgccResourceLoader implements ResourceLoader { constructor(private fs: FileSystem) {} canPreload = false; - preload(): undefined|Promise<void> { throw new Error('Not implemented.'); } - load(url: string): string { return this.fs.readFile(resolve(url)); } + preload(): undefined|Promise<void> { + throw new Error('Not implemented.'); + } + load(url: string): string { + return this.fs.readFile(resolve(url)); + } resolve(url: string, containingFile: string): string { return resolve(dirname(absoluteFrom(containingFile)), url); } @@ -56,7 +60,7 @@ export class DecorationAnalyzer { private rootDirs = this.bundle.rootDirs; private packagePath = this.bundle.entryPoint.package; private isCore = this.bundle.isCore; - private compilerOptions = this.tsConfig !== null? this.tsConfig.options: {}; + private compilerOptions = this.tsConfig !== null ? this.tsConfig.options : {}; moduleResolver = new ModuleResolver(this.program, this.options, this.host, /* moduleResolutionCache */ null); @@ -73,8 +77,9 @@ export class DecorationAnalyzer { // based on whether a bestGuessOwningModule is present in the Reference. new LogicalProjectStrategy(this.reflectionHost, new LogicalFileSystem(this.rootDirs)), ]); - aliasingHost = this.bundle.entryPoint.generateDeepReexports? - new PrivateExportAliasingHost(this.reflectionHost): null; + aliasingHost = this.bundle.entryPoint.generateDeepReexports ? + new PrivateExportAliasingHost(this.reflectionHost) : + null; dtsModuleScopeResolver = new MetadataDtsModuleScopeResolver(this.dtsMetaReader, this.aliasingHost); scopeRegistry = new LocalModuleScopeRegistry( @@ -191,7 +196,9 @@ export class DecorationAnalyzer { }); } - protected reportDiagnostics() { this.compiler.diagnostics.forEach(this.diagnosticHandler); } + protected reportDiagnostics() { + this.compiler.diagnostics.forEach(this.diagnosticHandler); + } protected compileFile(sourceFile: ts.SourceFile): CompiledFile { const constantPool = new ConstantPool(); @@ -211,7 +218,8 @@ export class DecorationAnalyzer { compiledClasses.push({ name: record.node.name.text, decorators: this.compiler.getAllDecorators(record.node), - declaration: record.node, compilation + declaration: record.node, + compilation }); } @@ -224,7 +232,7 @@ export class DecorationAnalyzer { if (!exportStatements.has(sf.fileName)) { return []; } - const exports = exportStatements.get(sf.fileName) !; + const exports = exportStatements.get(sf.fileName)!; const reexports: Reexport[] = []; exports.forEach(([fromModule, symbolName], asAlias) => { diff --git a/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts index 8c6ad1ee8343b..eb7a0b4a8cdf8 100644 --- a/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/module_with_providers_analyzer.ts @@ -75,10 +75,9 @@ export class ModuleWithProvidersAnalyzer { const dtsClass = this.host.getDtsDeclaration(containerClass.declaration.valueDeclaration); // Get the declaration of the matching static method dtsFn = dtsClass && ts.isClassDeclaration(dtsClass) ? - dtsClass.members - .find( - member => ts.isMethodDeclaration(member) && ts.isIdentifier(member.name) && - member.name.text === fn.name) as ts.Declaration : + dtsClass.members.find( + member => ts.isMethodDeclaration(member) && ts.isIdentifier(member.name) && + member.name.text === fn.name) as ts.Declaration : null; } else { dtsFn = this.host.getDtsDeclaration(fn.declaration); @@ -87,8 +86,8 @@ export class ModuleWithProvidersAnalyzer { throw new Error(`Matching type declaration for ${fn.declaration.getText()} is missing`); } if (!isFunctionOrMethod(dtsFn)) { - throw new Error( - `Matching type declaration for ${fn.declaration.getText()} is not a function: ${dtsFn.getText()}`); + throw new Error(`Matching type declaration for ${ + fn.declaration.getText()} is not a function: ${dtsFn.getText()}`); } return dtsFn; } @@ -106,12 +105,14 @@ export class ModuleWithProvidersAnalyzer { // to its type declaration. const dtsNgModule = this.host.getDtsDeclaration(ngModule.node); if (!dtsNgModule) { - throw new Error( - `No typings declaration can be found for the referenced NgModule class in ${fn.declaration.getText()}.`); + throw new Error(`No typings declaration can be found for the referenced NgModule class in ${ + fn.declaration.getText()}.`); } if (!ts.isClassDeclaration(dtsNgModule) || !hasNameIdentifier(dtsNgModule)) { - throw new Error( - `The referenced NgModule in ${fn.declaration.getText()} is not a named class declaration in the typings program; instead we get ${dtsNgModule.getText()}`); + throw new Error(`The referenced NgModule in ${ + fn.declaration + .getText()} is not a named class declaration in the typings program; instead we get ${ + dtsNgModule.getText()}`); } return {node: dtsNgModule, known: null, viaModule: null}; diff --git a/packages/compiler-cli/ngcc/src/analysis/ngcc_references_registry.ts b/packages/compiler-cli/ngcc/src/analysis/ngcc_references_registry.ts index ba8e0dbb2d6b1..f557cd9d6cf76 100644 --- a/packages/compiler-cli/ngcc/src/analysis/ngcc_references_registry.ts +++ b/packages/compiler-cli/ngcc/src/analysis/ngcc_references_registry.ts @@ -45,5 +45,7 @@ export class NgccReferencesRegistry implements ReferencesRegistry { * Create and return a mapping for the registered resolved references. * @returns A map of reference identifiers to reference declarations. */ - getDeclarationMap(): Map<ts.Identifier, ConcreteDeclaration> { return this.map; } + getDeclarationMap(): Map<ts.Identifier, ConcreteDeclaration> { + return this.map; + } } diff --git a/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts b/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts index f4d7f80fba59d..1c526bc78a02e 100644 --- a/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts +++ b/packages/compiler-cli/ngcc/src/analysis/ngcc_trait_compiler.ts @@ -29,7 +29,9 @@ export class NgccTraitCompiler extends TraitCompiler { /* compileNonExportedClasses */ true, new DtsTransformRegistry()); } - get analyzedFiles(): ts.SourceFile[] { return Array.from(this.fileToClasses.keys()); } + get analyzedFiles(): ts.SourceFile[] { + return Array.from(this.fileToClasses.keys()); + } /** * Analyzes the source file in search for classes to process. For any class that is found in the @@ -81,5 +83,7 @@ export class NgccTraitCompiler extends TraitCompiler { } class NoIncrementalBuild implements IncrementalBuild<any> { - priorWorkFor(sf: ts.SourceFile): any[]|null { return null; } + priorWorkFor(sf: ts.SourceFile): any[]|null { + return null; + } } diff --git a/packages/compiler-cli/ngcc/src/analysis/private_declarations_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/private_declarations_analyzer.ts index d005345201245..afc99f25613db 100644 --- a/packages/compiler-cli/ngcc/src/analysis/private_declarations_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/private_declarations_analyzer.ts @@ -7,10 +7,11 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFromSourceFile} from '../../../src/ngtsc/file_system'; +import {absoluteFromSourceFile, AbsoluteFsPath} from '../../../src/ngtsc/file_system'; import {ConcreteDeclaration} from '../../../src/ngtsc/reflection'; import {NgccReflectionHost} from '../host/ngcc_host'; import {hasNameIdentifier, isDefined} from '../utils'; + import {NgccReferencesRegistry} from './ngcc_references_registry'; export interface ExportInfo { @@ -48,7 +49,7 @@ export class PrivateDeclarationsAnalyzer { exports.forEach((declaration, exportedName) => { if (declaration.node !== null && hasNameIdentifier(declaration.node)) { if (privateDeclarations.has(declaration.node.name)) { - const privateDeclaration = privateDeclarations.get(declaration.node.name) !; + const privateDeclaration = privateDeclarations.get(declaration.node.name)!; if (privateDeclaration.node !== declaration.node) { throw new Error(`${declaration.node.name.text} is declared multiple times.`); } @@ -62,7 +63,7 @@ export class PrivateDeclarationsAnalyzer { return Array.from(privateDeclarations.keys()).map(id => { const from = absoluteFromSourceFile(id.getSourceFile()); - const declaration = privateDeclarations.get(id) !; + const declaration = privateDeclarations.get(id)!; const dtsDeclaration = this.host.getDtsDeclaration(declaration.node); const dtsFrom = dtsDeclaration && absoluteFromSourceFile(dtsDeclaration.getSourceFile()); diff --git a/packages/compiler-cli/ngcc/src/analysis/util.ts b/packages/compiler-cli/ngcc/src/analysis/util.ts index a953d4608cacd..ef4a3931da5f7 100644 --- a/packages/compiler-cli/ngcc/src/analysis/util.ts +++ b/packages/compiler-cli/ngcc/src/analysis/util.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFromSourceFile, relative} from '../../../src/ngtsc/file_system'; +import {absoluteFromSourceFile, AbsoluteFsPath, relative} from '../../../src/ngtsc/file_system'; import {DependencyTracker} from '../../../src/ngtsc/incremental/api'; export function isWithinPackage(packagePath: AbsoluteFsPath, sourceFile: ts.SourceFile): boolean { diff --git a/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts b/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts index 3d4ab17b8e701..ef783179ca4b9 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/commonjs_dependency_host.ts @@ -6,8 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; + import {AbsoluteFsPath} from '../../../src/ngtsc/file_system'; -import {RequireCall, isReexportStatement, isRequireCall} from '../host/commonjs_umd_utils'; +import {isReexportStatement, isRequireCall, RequireCall} from '../host/commonjs_umd_utils'; + import {DependencyHostBase} from './dependency_host'; import {ResolvedDeepImport, ResolvedRelativeModule} from './module_resolver'; @@ -120,5 +122,7 @@ export class CommonJsDependencyHost extends DependencyHostBase { * @returns false if there are definitely no require calls * in this file, true otherwise. */ - private hasRequireCalls(source: string): boolean { return /require\(['"]/.test(source); } + private hasRequireCalls(source: string): boolean { + return /require\(['"]/.test(source); + } } diff --git a/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts b/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts index ef9d2c4e550fa..9570ddcf4ab9e 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts @@ -7,12 +7,14 @@ */ import {DepGraph} from 'dependency-graph'; + import {AbsoluteFsPath, FileSystem, resolve} from '../../../src/ngtsc/file_system'; import {Logger} from '../logging/logger'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, EntryPointFormat, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from '../packages/entry_point'; +import {EntryPoint, EntryPointFormat, getEntryPointFormat, SUPPORTED_FORMAT_PROPERTIES} from '../packages/entry_point'; import {PartiallyOrderedList} from '../utils'; -import {DependencyHost, DependencyInfo, createDependencyInfo} from './dependency_host'; + +import {createDependencyInfo, DependencyHost, DependencyInfo} from './dependency_host'; const builtinNodeJsModules = new Set<string>(require('module').builtinModules); @@ -123,7 +125,8 @@ export class DependencyResolver { const host = this.hosts[formatInfo.format]; if (!host) { throw new Error( - `Could not find a suitable format for computing dependencies of entry-point: '${entryPoint.path}'.`); + `Could not find a suitable format for computing dependencies of entry-point: '${ + entryPoint.path}'.`); } const depInfo = createDependencyInfo(); host.collectDependencies(formatInfo.path, depInfo); diff --git a/packages/compiler-cli/ngcc/src/dependencies/module_resolver.ts b/packages/compiler-cli/ngcc/src/dependencies/module_resolver.ts index 1179dcd53fa5d..82fc8e5f3c67c 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/module_resolver.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/module_resolver.ts @@ -5,8 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFrom, dirname, isRoot, join, resolve} from '../../../src/ngtsc/file_system'; -import {PathMappings, isRelativePath, resolveFileWithPostfixes} from '../utils'; +import {absoluteFrom, AbsoluteFsPath, dirname, FileSystem, isRoot, join, resolve} from '../../../src/ngtsc/file_system'; +import {isRelativePath, PathMappings, resolveFileWithPostfixes} from '../utils'; /** * This is a very cut-down implementation of the TypeScript module resolution strategy. @@ -222,7 +222,7 @@ export class ModuleResolver { } /** The result of resolving an import to a module. */ -export type ResolvedModule = ResolvedExternalModule | ResolvedRelativeModule | ResolvedDeepImport; +export type ResolvedModule = ResolvedExternalModule|ResolvedRelativeModule|ResolvedDeepImport; /** * A module that is external to the package doing the importing. diff --git a/packages/compiler-cli/ngcc/src/dependencies/umd_dependency_host.ts b/packages/compiler-cli/ngcc/src/dependencies/umd_dependency_host.ts index ab2eb677e5bbf..7cc1b1c17220d 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/umd_dependency_host.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/umd_dependency_host.ts @@ -84,5 +84,7 @@ export class UmdDependencyHost extends DependencyHostBase { * @returns false if there are definitely no require calls * in this file, true otherwise. */ - private hasRequireCalls(source: string): boolean { return /require\(['"]/.test(source); } + private hasRequireCalls(source: string): boolean { + return /require\(['"]/.test(source); + } } diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index bf9e6cca9c4f8..4e238a576e285 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -9,10 +9,11 @@ import {AbsoluteFsPath, FileSystem, PathSegment} from '../../../src/ngtsc/file_s import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point'; +import {EntryPoint, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from '../packages/entry_point'; import {EntryPointManifest} from '../packages/entry_point_manifest'; import {PathMappings} from '../utils'; import {NGCC_DIRECTORY} from '../writing/new_entry_point_file_writer'; + import {EntryPointFinder} from './interface'; import {getBasePaths, trackDuration} from './utils'; diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index f21d4cd64cbf7..3258561805a3c 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -5,13 +5,14 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, PathSegment, join, relative, relativeFrom} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, FileSystem, join, PathSegment, relative, relativeFrom} from '../../../src/ngtsc/file_system'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; import {hasBeenProcessed} from '../packages/build_marker'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, EntryPointJsonProperty, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../packages/entry_point'; +import {EntryPoint, EntryPointJsonProperty, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from '../packages/entry_point'; import {PathMappings} from '../utils'; + import {EntryPointFinder} from './interface'; import {getBasePaths} from './utils'; @@ -76,7 +77,7 @@ export class TargetedEntryPointFinder implements EntryPointFinder { } private processNextPath(): void { - const path = this.unprocessedPaths.shift() !; + const path = this.unprocessedPaths.shift()!; const entryPoint = this.getEntryPoint(path); if (entryPoint === null || !entryPoint.compiledByAngular) { return; @@ -130,7 +131,7 @@ export class TargetedEntryPointFinder implements EntryPointFinder { // Start the search at the deepest nested `node_modules` folder that is below the `basePath` // but above the `entryPointPath`, if there are any. while (nodeModulesIndex >= 0) { - packagePath = join(packagePath, segments.shift() !); + packagePath = join(packagePath, segments.shift()!); nodeModulesIndex--; } diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts index f2ea90da10241..67f2a2f332217 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts @@ -30,7 +30,7 @@ import {PathMappings} from '../utils'; */ export function getBasePaths( logger: Logger, sourceDirectory: AbsoluteFsPath, - pathMappings: PathMappings | undefined): AbsoluteFsPath[] { + pathMappings: PathMappings|undefined): AbsoluteFsPath[] { const fs = getFileSystem(); const basePaths = [sourceDirectory]; if (pathMappings) { @@ -51,7 +51,8 @@ export function getBasePaths( basePaths.push(basePath); } else { logger.warn( - `The basePath "${basePath}" computed from baseUrl "${baseUrl}" and path mapping "${path}" does not exist in the file-system.\n` + + `The basePath "${basePath}" computed from baseUrl "${baseUrl}" and path mapping "${ + path}" does not exist in the file-system.\n` + `It will not be scanned for entry-points.`); } })); @@ -109,8 +110,8 @@ function removeContainedPaths(value: AbsoluteFsPath, index: number, array: Absol * @param log The function to call with the duration of the task * @returns The result of calling `task`. */ -export function trackDuration<T = void>( - task: () => T extends Promise<unknown>? never : T, log: (duration: number) => void): T { +export function trackDuration<T = void>(task: () => T extends Promise<unknown>? never : T, + log: (duration: number) => void): T { const startTime = Date.now(); const result = task(); const duration = Math.round((Date.now() - startTime) / 100) / 10; diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/api.ts b/packages/compiler-cli/ngcc/src/execution/cluster/api.ts index 970e3fd5be166..2325d52670cdb 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/api.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/api.ts @@ -44,7 +44,7 @@ export interface UpdatePackageJsonMessage extends JsonObject { } /** The type of messages sent from cluster workers to the cluster master. */ -export type MessageFromWorker = ErrorMessage | TaskCompletedMessage | UpdatePackageJsonMessage; +export type MessageFromWorker = ErrorMessage|TaskCompletedMessage|UpdatePackageJsonMessage; /** The type of messages sent from the cluster master to cluster workers. */ export type MessageToWorker = ProcessTaskMessage; diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts b/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts index dd381bb81c9b5..333a8e4e72a4d 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/executor.ts @@ -35,8 +35,8 @@ export class ClusterExecutor implements Executor { if (cluster.isMaster) { // This process is the cluster master. return this.lockFile.lock(() => { - this.logger.debug( - `Running ngcc on ${this.constructor.name} (using ${this.workerCount} worker processes).`); + this.logger.debug(`Running ngcc on ${this.constructor.name} (using ${ + this.workerCount} worker processes).`); const master = new ClusterMaster( this.workerCount, this.logger, this.pkgJsonUpdater, analyzeEntryPoints, this.createTaskCompletedCallback); diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts index 9976b4b3270ba..e40e42009ad83 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/master.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/master.ts @@ -262,7 +262,7 @@ export class ClusterMaster { */ private wrapEventHandler<Args extends unknown[]>(fn: (...args: Args) => void|Promise<void>): (...args: Args) => Promise<void> { - return async(...args: Args) => { + return async (...args: Args) => { try { await fn(...args); } catch (err) { diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts b/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts index 6014045507581..7196cce6b49a9 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/package_json_updater.ts @@ -12,7 +12,7 @@ import * as cluster from 'cluster'; import {AbsoluteFsPath} from '../../../../src/ngtsc/file_system'; import {JsonObject} from '../../packages/entry_point'; -import {PackageJsonChange, PackageJsonUpdate, PackageJsonUpdater, applyChange} from '../../writing/package_json_updater'; +import {applyChange, PackageJsonChange, PackageJsonUpdate, PackageJsonUpdater} from '../../writing/package_json_updater'; import {sendMessageToMaster} from './utils'; diff --git a/packages/compiler-cli/ngcc/src/execution/cluster/utils.ts b/packages/compiler-cli/ngcc/src/execution/cluster/utils.ts index 351cf58e73063..b9ca051299dcb 100644 --- a/packages/compiler-cli/ngcc/src/execution/cluster/utils.ts +++ b/packages/compiler-cli/ngcc/src/execution/cluster/utils.ts @@ -23,14 +23,14 @@ export class Deferred<T> { * * @param value The value to resolve the promise with. */ - resolve !: (value: T) => void; + resolve!: (value: T) => void; /** * Rejects the associated promise with the specified reason. * * @param reason The rejection reason. */ - reject !: (reason: any) => void; + reject!: (reason: any) => void; /** The `Promise` instance associated with this deferred. */ promise = new Promise<T>((resolve, reject) => { diff --git a/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts b/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts index 6d6dbf0553609..20f494af1998c 100644 --- a/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts +++ b/packages/compiler-cli/ngcc/src/execution/single_process_executor.ts @@ -30,7 +30,7 @@ export abstract class SingleProcessorExecutorBase { const startTime = Date.now(); while (!taskQueue.allTasksCompleted) { - const task = taskQueue.getNextTask() !; + const task = taskQueue.getNextTask()!; compile(task); taskQueue.markTaskCompleted(task); } @@ -65,6 +65,6 @@ export class SingleProcessExecutorAsync extends SingleProcessorExecutorBase impl } async execute(analyzeEntryPoints: AnalyzeEntryPointsFn, createCompileFn: CreateCompileFn): Promise<void> { - await this.lockFile.lock(async() => this.doExecute(analyzeEntryPoints, createCompileFn)); + await this.lockFile.lock(async () => this.doExecute(analyzeEntryPoints, createCompileFn)); } } diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/api.ts b/packages/compiler-cli/ngcc/src/execution/tasks/api.ts index ed2fd2165b6d9..0516b66db8271 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/api.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/api.ts @@ -66,7 +66,7 @@ export type CreateTaskCompletedCallback = (taskQueue: TaskQueue) => TaskComplete * A function to be called once a task has been processed. */ export type TaskCompletedCallback = - (task: Task, outcome: TaskProcessingOutcome, message: string | null) => void; + (task: Task, outcome: TaskProcessingOutcome, message: string|null) => void; /** * Represents the outcome of processing a `Task`. diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts b/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts index 5a8111fa9a642..88f2879aabda2 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/completion.ts @@ -8,8 +8,9 @@ import {FileSystem, resolve} from '../../../../src/ngtsc/file_system'; import {Logger} from '../../logging/logger'; import {markAsProcessed} from '../../packages/build_marker'; -import {PackageJsonFormatProperties, getEntryPointFormat} from '../../packages/entry_point'; +import {getEntryPointFormat, PackageJsonFormatProperties} from '../../packages/entry_point'; import {PackageJsonUpdater} from '../../writing/package_json_updater'; + import {Task, TaskCompletedCallback, TaskProcessingOutcome, TaskQueue} from './api'; /** @@ -18,7 +19,7 @@ import {Task, TaskCompletedCallback, TaskProcessingOutcome, TaskQueue} from './a * These functions can be composed using the `composeTaskCompletedCallbacks()` * to create a `TaskCompletedCallback` function that can be passed to an `Executor`. */ -export type TaskCompletedHandler = (task: Task, message: string | null) => void; +export type TaskCompletedHandler = (task: Task, message: string|null) => void; /** * Compose a group of TaskCompletedHandlers into a single TaskCompletedCallback. @@ -30,11 +31,11 @@ export type TaskCompletedHandler = (task: Task, message: string | null) => void; */ export function composeTaskCompletedCallbacks( callbacks: Record<TaskProcessingOutcome, TaskCompletedHandler>): TaskCompletedCallback { - return (task: Task, outcome: TaskProcessingOutcome, message: string | null): void => { + return (task: Task, outcome: TaskProcessingOutcome, message: string|null): void => { const callback = callbacks[outcome]; if (callback === undefined) { - throw new Error( - `Unknown task outcome: "${outcome}" - supported outcomes: ${JSON.stringify(Object.keys(callbacks))}`); + throw new Error(`Unknown task outcome: "${outcome}" - supported outcomes: ${ + JSON.stringify(Object.keys(callbacks))}`); } callback(task, message); }; @@ -64,10 +65,11 @@ export function createMarkAsProcessedHandler(pkgJsonUpdater: PackageJsonUpdater) * Create a handler that will throw an error. */ export function createThrowErrorHandler(fs: FileSystem): TaskCompletedHandler { - return (task: Task, message: string | null): void => { + return (task: Task, message: string|null): void => { const format = getEntryPointFormat(fs, task.entryPoint, task.formatProperty); throw new Error( - `Failed to compile entry-point ${task.entryPoint.name} (${task.formatProperty} as ${format})` + + `Failed to compile entry-point ${task.entryPoint.name} (${task.formatProperty} as ${ + format})` + (message !== null ? ` due to ${message}` : '')); }; } @@ -77,11 +79,12 @@ export function createThrowErrorHandler(fs: FileSystem): TaskCompletedHandler { */ export function createLogErrorHandler( logger: Logger, fs: FileSystem, taskQueue: TaskQueue): TaskCompletedHandler { - return (task: Task, message: string | null): void => { + return (task: Task, message: string|null): void => { taskQueue.markAsFailed(task); const format = getEntryPointFormat(fs, task.entryPoint, task.formatProperty); logger.error( - `Failed to compile entry-point ${task.entryPoint.name} (${task.formatProperty} as ${format})` + + `Failed to compile entry-point ${task.entryPoint.name} (${task.formatProperty} as ${ + format})` + (message !== null ? ` due to ${message}` : '')); }; } diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/queues/base_task_queue.ts b/packages/compiler-cli/ngcc/src/execution/tasks/queues/base_task_queue.ts index de1497fb66d42..cd709f1a1cd72 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/queues/base_task_queue.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/queues/base_task_queue.ts @@ -38,9 +38,9 @@ export abstract class BaseTaskQueue implements TaskQueue { } // We are skipping this task so mark it as complete this.markTaskCompleted(nextTask); - const failedTask = this.tasksToSkip.get(nextTask) !; - this.logger.warn( - `Skipping processing of ${nextTask.entryPoint.name} because its dependency ${failedTask.entryPoint.name} failed to compile.`); + const failedTask = this.tasksToSkip.get(nextTask)!; + this.logger.warn(`Skipping processing of ${nextTask.entryPoint.name} because its dependency ${ + failedTask.entryPoint.name} failed to compile.`); nextTask = this.computeNextTask(); } return nextTask; @@ -48,7 +48,7 @@ export abstract class BaseTaskQueue implements TaskQueue { markAsFailed(task: Task) { if (this.dependencies.has(task)) { - for (const dependentTask of this.dependencies.get(task) !) { + for (const dependentTask of this.dependencies.get(task)!) { this.skipDependentTasks(dependentTask, task); } } @@ -81,7 +81,7 @@ export abstract class BaseTaskQueue implements TaskQueue { protected skipDependentTasks(task: Task, failedTask: Task) { this.tasksToSkip.set(task, failedTask); if (this.dependencies.has(task)) { - for (const dependentTask of this.dependencies.get(task) !) { + for (const dependentTask of this.dependencies.get(task)!) { this.skipDependentTasks(dependentTask, failedTask); } } diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/queues/parallel_task_queue.ts b/packages/compiler-cli/ngcc/src/execution/tasks/queues/parallel_task_queue.ts index b7f7ef9fc241a..2718a0ee05133 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/queues/parallel_task_queue.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/queues/parallel_task_queue.ts @@ -49,9 +49,9 @@ export class ParallelTaskQueue extends BaseTaskQueue { } // Unblock the tasks that are dependent upon `task` - for (const dependentTask of this.dependencies.get(task) !) { + for (const dependentTask of this.dependencies.get(task)!) { if (this.blockedTasks.has(dependentTask)) { - const blockingTasks = this.blockedTasks.get(dependentTask) !; + const blockingTasks = this.blockedTasks.get(dependentTask)!; // Remove the completed task from the lists of tasks blocking other tasks. blockingTasks.delete(task); if (blockingTasks.size === 0) { diff --git a/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts b/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts index 26682a82acbcf..22846a361e688 100644 --- a/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts +++ b/packages/compiler-cli/ngcc/src/execution/tasks/utils.ts @@ -10,8 +10,8 @@ import {EntryPoint} from '../../packages/entry_point'; import {PartiallyOrderedTasks, Task, TaskDependencies} from './api'; /** Stringify a task for debugging purposes. */ -export const stringifyTask = (task: Task): string => - `{entryPoint: ${task.entryPoint.name}, formatProperty: ${task.formatProperty}, processDts: ${task.processDts}}`; +export const stringifyTask = (task: Task): string => `{entryPoint: ${ + task.entryPoint.name}, formatProperty: ${task.formatProperty}, processDts: ${task.processDts}}`; /** * Compute a mapping of tasks to the tasks that are dependent on them (if any). @@ -45,7 +45,7 @@ export function computeTaskDependencies( // Find the earlier tasks (`candidateDependencies`) that this task depends upon. const deps = graph.dependenciesOf(entryPointPath); const taskDependencies = deps.filter(dep => candidateDependencies.has(dep)) - .map(dep => candidateDependencies.get(dep) !); + .map(dep => candidateDependencies.get(dep)!); // If this task has dependencies, add it to the dependencies and dependents maps. if (taskDependencies.length > 0) { @@ -61,7 +61,7 @@ export function computeTaskDependencies( // dependency of other tasks), so the following should theoretically never happen, but check // just in case. if (candidateDependencies.has(entryPointPath)) { - const otherTask = candidateDependencies.get(entryPointPath) !; + const otherTask = candidateDependencies.get(entryPointPath)!; throw new Error( 'Invariant violated: Multiple tasks are assigned generating typings for ' + `'${entryPointPath}':\n - ${stringifyTask(otherTask)}\n - ${stringifyTask(task)}`); @@ -73,7 +73,7 @@ export function computeTaskDependencies( // This task is not generating typings so we need to add it to the dependents of the task that // does generate typings, if that exists if (candidateDependencies.has(entryPointPath)) { - const typingsTask = candidateDependencies.get(entryPointPath) !; + const typingsTask = candidateDependencies.get(entryPointPath)!; const typingsTaskDependents = getDependentsSet(dependencies, typingsTask); typingsTaskDependents.add(task); } @@ -87,7 +87,7 @@ export function getDependentsSet(map: TaskDependencies, task: Task): Set<Task> { if (!map.has(task)) { map.set(task, new Set()); } - return map.get(task) !; + return map.get(task)!; } /** @@ -125,13 +125,13 @@ export function sortTasksByPriority( tasks: PartiallyOrderedTasks, dependencies: TaskDependencies): PartiallyOrderedTasks { const priorityPerTask = new Map<Task, [number, number]>(); const computePriority = (task: Task, idx: number): - [number, number] => [dependencies.has(task) ? dependencies.get(task) !.size : 0, idx]; + [number, number] => [dependencies.has(task) ? dependencies.get(task)!.size : 0, idx]; tasks.forEach((task, i) => priorityPerTask.set(task, computePriority(task, i))); return tasks.slice().sort((task1, task2) => { - const [p1, idx1] = priorityPerTask.get(task1) !; - const [p2, idx2] = priorityPerTask.get(task2) !; + const [p1, idx1] = priorityPerTask.get(task1)!; + const [p2, idx2] = priorityPerTask.get(task2)!; return (p2 - p1) || (idx1 - idx2); }); diff --git a/packages/compiler-cli/ngcc/src/host/commonjs_host.ts b/packages/compiler-cli/ngcc/src/host/commonjs_host.ts index 00b4bf4f5bccc..a2ba25cfbf059 100644 --- a/packages/compiler-cli/ngcc/src/host/commonjs_host.ts +++ b/packages/compiler-cli/ngcc/src/host/commonjs_host.ts @@ -7,13 +7,14 @@ */ import * as ts from 'typescript'; + import {absoluteFrom} from '../../../src/ngtsc/file_system'; import {Declaration, Import} from '../../../src/ngtsc/reflection'; import {Logger} from '../logging/logger'; import {BundleProgram} from '../packages/bundle_program'; import {FactoryMap, getTsHelperFnFromIdentifier, isDefined, stripExtension} from '../utils'; -import {ExportDeclaration, ExportStatement, ReexportStatement, RequireCall, findNamespaceOfIdentifier, findRequireCallReference, isExportStatement, isReexportStatement, isRequireCall} from './commonjs_umd_utils'; +import {ExportDeclaration, ExportStatement, findNamespaceOfIdentifier, findRequireCallReference, isExportStatement, isReexportStatement, isRequireCall, ReexportStatement, RequireCall} from './commonjs_umd_utils'; import {Esm5ReflectionHost} from './esm5_host'; import {NgccClassSymbol} from './ngcc_host'; diff --git a/packages/compiler-cli/ngcc/src/host/commonjs_umd_utils.ts b/packages/compiler-cli/ngcc/src/host/commonjs_umd_utils.ts index 86ddc9550354e..e871034f99aed 100644 --- a/packages/compiler-cli/ngcc/src/host/commonjs_umd_utils.ts +++ b/packages/compiler-cli/ngcc/src/host/commonjs_umd_utils.ts @@ -16,7 +16,12 @@ export interface ExportDeclaration { } export interface ExportStatement extends ts.ExpressionStatement { - expression: ts.BinaryExpression&{left: ts.PropertyAccessExpression & {expression: ts.Identifier}}; + expression: ts.BinaryExpression&{ + left: ts.PropertyAccessExpression & + { + expression: ts.Identifier + } + }; } /** @@ -34,7 +39,9 @@ export interface ExportStatement extends ts.ExpressionStatement { * expression and can be either a `require('...')` call or an identifier (initialized via a * `require('...')` call). */ -export interface ReexportStatement extends ts.ExpressionStatement { expression: ts.CallExpression; } +export interface ReexportStatement extends ts.ExpressionStatement { + expression: ts.CallExpression; +} export interface RequireCall extends ts.CallExpression { arguments: ts.CallExpression['arguments']&[ts.StringLiteral]; diff --git a/packages/compiler-cli/ngcc/src/host/umd_host.ts b/packages/compiler-cli/ngcc/src/host/umd_host.ts index b053820c77621..a9ef6bb56547e 100644 --- a/packages/compiler-cli/ngcc/src/host/umd_host.ts +++ b/packages/compiler-cli/ngcc/src/host/umd_host.ts @@ -13,7 +13,8 @@ import {Declaration, Import} from '../../../src/ngtsc/reflection'; import {Logger} from '../logging/logger'; import {BundleProgram} from '../packages/bundle_program'; import {FactoryMap, getTsHelperFnFromIdentifier, stripExtension} from '../utils'; -import {ExportDeclaration, ExportStatement, ReexportStatement, findNamespaceOfIdentifier, findRequireCallReference, isExportStatement, isReexportStatement, isRequireCall} from './commonjs_umd_utils'; + +import {ExportDeclaration, ExportStatement, findNamespaceOfIdentifier, findRequireCallReference, isExportStatement, isReexportStatement, isRequireCall, ReexportStatement} from './commonjs_umd_utils'; import {Esm5ReflectionHost, stripParentheses} from './esm5_host'; export class UmdReflectionHost extends Esm5ReflectionHost { @@ -61,7 +62,8 @@ export class UmdReflectionHost extends Esm5ReflectionHost { return this.umdImportPaths.get(importParameter); } - /** Get the top level statements for a module. + /** + * Get the top level statements for a module. * * In UMD modules these are the body of the UMD factory function. * diff --git a/packages/compiler-cli/ngcc/src/locking/async_locker.ts b/packages/compiler-cli/ngcc/src/locking/async_locker.ts index 56bc531357dcd..f0ee1b7393d46 100644 --- a/packages/compiler-cli/ngcc/src/locking/async_locker.ts +++ b/packages/compiler-cli/ngcc/src/locking/async_locker.ts @@ -52,7 +52,7 @@ export class AsyncLocker { if (attempts === 0) { this.logger.info( `Another process, with id ${pid}, is currently running ngcc.\n` + - `Waiting up to ${this.retryDelay*this.retryAttempts/1000}s for it to finish.`); + `Waiting up to ${this.retryDelay * this.retryAttempts / 1000}s for it to finish.`); } // The file is still locked by another process so wait for a bit and retry await new Promise(resolve => setTimeout(resolve, this.retryDelay)); @@ -60,7 +60,10 @@ export class AsyncLocker { } // If we fall out of the loop then we ran out of rety attempts throw new Error( - `Timed out waiting ${this.retryAttempts * this.retryDelay/1000}s for another ngcc process, with id ${pid}, to complete.\n` + - `(If you are sure no ngcc process is running then you should delete the lock-file at ${this.lockFile.path}.)`); + `Timed out waiting ${ + this.retryAttempts * this.retryDelay / + 1000}s for another ngcc process, with id ${pid}, to complete.\n` + + `(If you are sure no ngcc process is running then you should delete the lock-file at ${ + this.lockFile.path}.)`); } } diff --git a/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/index.ts b/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/index.ts index 8cde3e462b547..cbabff7719db4 100644 --- a/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/index.ts +++ b/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/index.ts @@ -8,8 +8,8 @@ import {ChildProcess, fork} from 'child_process'; import {AbsoluteFsPath, CachedFileSystem, FileSystem} from '../../../../src/ngtsc/file_system'; -import {LogLevel, Logger} from '../../logging/logger'; -import {LockFile, getLockFilePath} from '../lock_file'; +import {Logger, LogLevel} from '../../logging/logger'; +import {getLockFilePath, LockFile} from '../lock_file'; import {removeLockFile} from './util'; diff --git a/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/unlocker.ts b/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/unlocker.ts index 798613541a725..b31f21f966625 100644 --- a/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/unlocker.ts +++ b/packages/compiler-cli/ngcc/src/locking/lock_file_with_child_process/unlocker.ts @@ -20,14 +20,14 @@ const fs = new NodeJSFileSystem(); // We create a logger that has the same logging level as the parent process, since it should have // been passed through as one of the args -const logLevel = parseInt(process.argv.pop() !, 10); +const logLevel = parseInt(process.argv.pop()!, 10); const logger = new ConsoleLogger(logLevel); // We must store the parent PID now as it changes if the parent process is killed early const ppid = process.ppid.toString(); // The path to the lock-file to remove should have been passed as one of the args -const lockFilePath = fs.resolve(process.argv.pop() !); +const lockFilePath = fs.resolve(process.argv.pop()!); logger.debug(`Starting unlocker at process ${process.pid} on behalf of process ${ppid}`); logger.debug(`The lock-file path is ${lockFilePath}`); @@ -36,4 +36,6 @@ logger.debug(`The lock-file path is ${lockFilePath}`); * When the parent process exits (for whatever reason) remove the loc-file if it exists and as long * as it was one that was created by the parent process. */ -process.on('disconnect', () => { removeLockFile(fs, logger, lockFilePath, ppid); }); +process.on('disconnect', () => { + removeLockFile(fs, logger, lockFilePath, ppid); +}); diff --git a/packages/compiler-cli/ngcc/src/locking/sync_locker.ts b/packages/compiler-cli/ngcc/src/locking/sync_locker.ts index 391ca822e3663..6c58cbe41da98 100644 --- a/packages/compiler-cli/ngcc/src/locking/sync_locker.ts +++ b/packages/compiler-cli/ngcc/src/locking/sync_locker.ts @@ -57,6 +57,7 @@ export class SyncLocker { `ngcc is already running at process with id ${pid}.\n` + `If you are running multiple builds in parallel then you should pre-process your node_modules via the command line ngcc tool before starting the builds;\n` + `See https://v9.angular.io/guide/ivy#speeding-up-ngcc-compilation.\n` + - `(If you are sure no ngcc process is running then you should delete the lock-file at ${this.lockFile.path}.)`); + `(If you are sure no ngcc process is running then you should delete the lock-file at ${ + this.lockFile.path}.)`); } } diff --git a/packages/compiler-cli/ngcc/src/logging/console_logger.ts b/packages/compiler-cli/ngcc/src/logging/console_logger.ts index 040bce95134af..66acf79b8a9a6 100644 --- a/packages/compiler-cli/ngcc/src/logging/console_logger.ts +++ b/packages/compiler-cli/ngcc/src/logging/console_logger.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {LogLevel, Logger} from './logger'; +import {Logger, LogLevel} from './logger'; const RESET = '\x1b[0m'; const RED = '\x1b[31m'; diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index a069b8b03b63d..e0565b4c5b865 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -14,7 +14,7 @@ import * as ts from 'typescript'; import {readConfiguration} from '../..'; import {replaceTsWithNgInErrors} from '../../src/ngtsc/diagnostics'; -import {AbsoluteFsPath, FileSystem, absoluteFrom, dirname, getFileSystem, resolve} from '../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, dirname, FileSystem, getFileSystem, resolve} from '../../src/ngtsc/file_system'; import {CommonJsDependencyHost} from './dependencies/commonjs_dependency_host'; import {DependencyResolver, InvalidEntryPoint} from './dependencies/dependency_resolver'; @@ -38,10 +38,10 @@ import {AsyncLocker} from './locking/async_locker'; import {LockFileWithChildProcess} from './locking/lock_file_with_child_process'; import {SyncLocker} from './locking/sync_locker'; import {ConsoleLogger} from './logging/console_logger'; -import {LogLevel, Logger} from './logging/logger'; +import {Logger, LogLevel} from './logging/logger'; import {hasBeenProcessed} from './packages/build_marker'; import {NgccConfiguration} from './packages/configuration'; -import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat} from './packages/entry_point'; +import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, getEntryPointFormat, SUPPORTED_FORMAT_PROPERTIES} from './packages/entry_point'; import {makeEntryPointBundle} from './packages/entry_point_bundle'; import {EntryPointManifest, InvalidatingEntryPointManifest} from './packages/entry_point_manifest'; import {Transformer} from './packages/transformer'; @@ -164,12 +164,12 @@ export interface SyncNgccOptions { /** * The options to configure the ngcc compiler for asynchronous execution. */ -export type AsyncNgccOptions = Omit<SyncNgccOptions, 'async'>& {async: true}; +export type AsyncNgccOptions = Omit<SyncNgccOptions, 'async'>&{async: true}; /** * The options to configure the ngcc compiler. */ -export type NgccOptions = AsyncNgccOptions | SyncNgccOptions; +export type NgccOptions = AsyncNgccOptions|SyncNgccOptions; /** * This is the main entry-point into ngcc (aNGular Compatibility Compiler). @@ -181,12 +181,20 @@ export type NgccOptions = AsyncNgccOptions | SyncNgccOptions; */ export function mainNgcc(options: AsyncNgccOptions): Promise<void>; export function mainNgcc(options: SyncNgccOptions): void; -export function mainNgcc( - {basePath, targetEntryPointPath, propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, - compileAllFormats = true, createNewEntryPointFormats = false, - logger = new ConsoleLogger(LogLevel.info), pathMappings, async = false, - errorOnFailedEntryPoint = false, enableI18nLegacyMessageIdFormat = true, - invalidateEntryPointManifest = false, tsConfigPath}: NgccOptions): void|Promise<void> { +export function mainNgcc({ + basePath, + targetEntryPointPath, + propertiesToConsider = SUPPORTED_FORMAT_PROPERTIES, + compileAllFormats = true, + createNewEntryPointFormats = false, + logger = new ConsoleLogger(LogLevel.info), + pathMappings, + async = false, + errorOnFailedEntryPoint = false, + enableI18nLegacyMessageIdFormat = true, + invalidateEntryPointManifest = false, + tsConfigPath +}: NgccOptions): void|Promise<void> { if (!!targetEntryPointPath) { // targetEntryPointPath forces us to error if an entry-point fails. errorOnFailedEntryPoint = true; @@ -279,7 +287,7 @@ export function mainNgcc( continue; } - const formatPropertiesToMarkAsProcessed = equivalentPropertiesMap.get(formatProperty) !; + const formatPropertiesToMarkAsProcessed = equivalentPropertiesMap.get(formatProperty)!; tasks.push({entryPoint, formatProperty, formatPropertiesToMarkAsProcessed, processDts}); // Only process typings for the first property (if not already processed). @@ -442,7 +450,7 @@ function getExecutor( function getDependencyResolver( fileSystem: FileSystem, logger: Logger, config: NgccConfiguration, - pathMappings: PathMappings | undefined): DependencyResolver { + pathMappings: PathMappings|undefined): DependencyResolver { const moduleResolver = new ModuleResolver(fileSystem, pathMappings); const esmDependencyHost = new EsmDependencyHost(fileSystem, moduleResolver); const umdDependencyHost = new UmdDependencyHost(fileSystem, moduleResolver); @@ -461,8 +469,8 @@ function getDependencyResolver( function getEntryPointFinder( fs: FileSystem, logger: Logger, resolver: DependencyResolver, config: NgccConfiguration, entryPointManifest: EntryPointManifest, basePath: AbsoluteFsPath, - absoluteTargetEntryPointPath: AbsoluteFsPath | null, - pathMappings: PathMappings | undefined): EntryPointFinder { + absoluteTargetEntryPointPath: AbsoluteFsPath|null, + pathMappings: PathMappings|undefined): EntryPointFinder { if (absoluteTargetEntryPointPath !== null) { return new TargetedEntryPointFinder( fs, config, logger, resolver, basePath, absoluteTargetEntryPointPath, pathMappings); @@ -533,7 +541,7 @@ function getPropertiesToProcess( const equivalentPropertiesMap = new Map<EntryPointJsonProperty, EntryPointJsonProperty[]>(); for (const prop of propertiesToConsider) { - const formatPath = packageJson[prop] !; + const formatPath = packageJson[prop]!; const equivalentProperties = formatPathToProperties[formatPath]; equivalentPropertiesMap.set(prop, equivalentProperties); } diff --git a/packages/compiler-cli/ngcc/src/migrations/missing_injectable_migration.ts b/packages/compiler-cli/ngcc/src/migrations/missing_injectable_migration.ts index 8c590a08878d1..1affab1b795c8 100644 --- a/packages/compiler-cli/ngcc/src/migrations/missing_injectable_migration.ts +++ b/packages/compiler-cli/ngcc/src/migrations/missing_injectable_migration.ts @@ -102,7 +102,7 @@ function migrateProviders(metadata: ResolvedValueMap, field: string, host: Migra if (!metadata.has(field)) { return; } - const providers = metadata.get(field) !; + const providers = metadata.get(field)!; if (!Array.isArray(providers)) { return; } @@ -127,10 +127,10 @@ function migrateProvider(provider: ResolvedValue, host: MigrationHost): void { // as the provider itself configures 'deps'. Only if 'deps' is missing will this require a // factory to exist on SomeClass. if (!provider.has('deps')) { - migrateProviderClass(provider.get('useClass') !, host); + migrateProviderClass(provider.get('useClass')!, host); } } else { - migrateProviderClass(provider.get('provide') !, host); + migrateProviderClass(provider.get('provide')!, host); } } else if (Array.isArray(provider)) { for (const v of provider) { diff --git a/packages/compiler-cli/ngcc/src/migrations/utils.ts b/packages/compiler-cli/ngcc/src/migrations/utils.ts index c51b95014b617..1437f46b35801 100644 --- a/packages/compiler-cli/ngcc/src/migrations/utils.ts +++ b/packages/compiler-cli/ngcc/src/migrations/utils.ts @@ -43,7 +43,7 @@ export function hasConstructor(host: MigrationHost, clazz: ClassDeclaration): bo */ export function createDirectiveDecorator( clazz: ClassDeclaration, - metadata?: {selector: string | null, exportAs: string[] | null}): Decorator { + metadata?: {selector: string|null, exportAs: string[]|null}): Decorator { const args: ts.Expression[] = []; if (metadata !== undefined) { const metaArgs: ts.PropertyAssignment[] = []; @@ -60,7 +60,8 @@ export function createDirectiveDecorator( identifier: null, import: {name: 'Directive', from: '@angular/core'}, node: null, - synthesizedFor: clazz.name, args, + synthesizedFor: clazz.name, + args, }; } @@ -69,7 +70,7 @@ export function createDirectiveDecorator( */ export function createComponentDecorator( clazz: ClassDeclaration, - metadata: {selector: string | null, exportAs: string[] | null}): Decorator { + metadata: {selector: string|null, exportAs: string[]|null}): Decorator { const metaArgs: ts.PropertyAssignment[] = [ property('template', ''), ]; @@ -127,5 +128,5 @@ function reifySourceFile(expr: ts.Expression): ts.Expression { if (!ts.isVariableStatement(stmt)) { throw new Error(`Expected VariableStatement, got ${ts.SyntaxKind[stmt.kind]}`); } - return stmt.declarationList.declarations[0].initializer !; + return stmt.declarationList.declarations[0].initializer!; } diff --git a/packages/compiler-cli/ngcc/src/packages/bundle_program.ts b/packages/compiler-cli/ngcc/src/packages/bundle_program.ts index cbea96d34bad0..a094a03c07082 100644 --- a/packages/compiler-cli/ngcc/src/packages/bundle_program.ts +++ b/packages/compiler-cli/ngcc/src/packages/bundle_program.ts @@ -6,17 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {AbsoluteFsPath, FileSystem, dirname, resolve} from '../../../src/ngtsc/file_system'; + +import {AbsoluteFsPath, dirname, FileSystem, resolve} from '../../../src/ngtsc/file_system'; + import {patchTsGetExpandoInitializer, restoreGetExpandoInitializer} from './patch_ts_expando_initializer'; /** -* An entry point bundle contains one or two programs, e.g. `src` and `dts`, -* that are compiled via TypeScript. -* -* To aid with processing the program, this interface exposes the program itself, -* as well as path and TS file of the entry-point to the program and the r3Symbols -* file, if appropriate. -*/ + * An entry point bundle contains one or two programs, e.g. `src` and `dts`, + * that are compiled via TypeScript. + * + * To aid with processing the program, this interface exposes the program itself, + * as well as path and TS file of the entry-point to the program and the r3Symbols + * file, if appropriate. + */ export interface BundleProgram { program: ts.Program; options: ts.CompilerOptions; @@ -46,7 +48,7 @@ export function makeBundleProgram( program.getTypeChecker(); restoreGetExpandoInitializer(originalGetExpandoInitializer); - const file = program.getSourceFile(path) !; + const file = program.getSourceFile(path)!; const r3SymbolsFile = r3SymbolsPath && program.getSourceFile(r3SymbolsPath) || null; return {program, options, host, package: pkg, path, file, r3SymbolsPath, r3SymbolsFile}; diff --git a/packages/compiler-cli/ngcc/src/packages/configuration.ts b/packages/compiler-cli/ngcc/src/packages/configuration.ts index ea1660e917ea7..10b45e9b31217 100644 --- a/packages/compiler-cli/ngcc/src/packages/configuration.ts +++ b/packages/compiler-cli/ngcc/src/packages/configuration.ts @@ -8,7 +8,9 @@ import {createHash} from 'crypto'; import {satisfies} from 'semver'; import * as vm from 'vm'; -import {AbsoluteFsPath, FileSystem, dirname, join, resolve} from '../../../src/ngtsc/file_system'; + +import {AbsoluteFsPath, dirname, FileSystem, join, resolve} from '../../../src/ngtsc/file_system'; + import {PackageJsonFormatPropertiesMap} from './entry_point'; /** @@ -178,7 +180,7 @@ export class NgccConfiguration { getConfig(packagePath: AbsoluteFsPath, version: string|null): VersionedPackageConfig { const cacheKey = packagePath + (version !== null ? `@${version}` : ''); if (this.cache.has(cacheKey)) { - return this.cache.get(cacheKey) !; + return this.cache.get(cacheKey)!; } const projectLevelConfig = @@ -256,7 +258,8 @@ export class NgccConfiguration { const theExports = {}; const sandbox = { module: {exports: theExports}, - exports: theExports, require, + exports: theExports, + require, __dirname: dirname(srcPath), __filename: srcPath }; @@ -292,9 +295,8 @@ export class NgccConfiguration { } } -function findSatisfactoryVersion( - configs: VersionedPackageConfig[] | undefined, version: string | null): VersionedPackageConfig| - null { +function findSatisfactoryVersion(configs: VersionedPackageConfig[]|undefined, version: string|null): + VersionedPackageConfig|null { if (configs === undefined) { return null; } diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point.ts b/packages/compiler-cli/ngcc/src/packages/entry_point.ts index 08bcf8e4f1887..cc74e8e82a269 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point.ts @@ -17,7 +17,7 @@ import {NgccConfiguration, NgccEntryPointConfig} from './configuration'; /** * The possible values for the format of an entry-point. */ -export type EntryPointFormat = 'esm5' | 'esm2015' | 'umd' | 'commonjs'; +export type EntryPointFormat = 'esm5'|'esm2015'|'umd'|'commonjs'; /** * An object containing information about an entry-point, including paths @@ -42,10 +42,12 @@ export interface EntryPoint extends JsonObject { generateDeepReexports: boolean; } -export type JsonPrimitive = string | number | boolean | null; -export type JsonValue = JsonPrimitive | JsonArray | JsonObject | undefined; +export type JsonPrimitive = string|number|boolean|null; +export type JsonValue = JsonPrimitive|JsonArray|JsonObject|undefined; export interface JsonArray extends Array<JsonValue> {} -export interface JsonObject { [key: string]: JsonValue; } +export interface JsonObject { + [key: string]: JsonValue; +} export interface PackageJsonFormatPropertiesMap { fesm2015?: string; @@ -97,8 +99,7 @@ export const INCOMPATIBLE_ENTRY_POINT = 'incompatible-entry-point'; * * INCOMPATIBLE_ENTRY_POINT - the path was a non-processable entry-point that should be searched * for sub-entry-points */ -export type GetEntryPointResult = - EntryPoint | typeof INCOMPATIBLE_ENTRY_POINT | typeof NO_ENTRY_POINT; +export type GetEntryPointResult = EntryPoint|typeof INCOMPATIBLE_ENTRY_POINT|typeof NO_ENTRY_POINT; /** @@ -161,7 +162,8 @@ export function getEntryPointInfo( packageJson: entryPointPackageJson, package: packagePath, path: entryPointPath, - typings: resolve(entryPointPath, typings), compiledByAngular, + typings: resolve(entryPointPath, typings), + compiledByAngular, ignoreMissingDependencies: entryPointConfig !== undefined ? !!entryPointConfig.ignoreMissingDependencies : false, generateDeepReexports: @@ -236,7 +238,7 @@ function isUmdModule(fs: FileSystem, sourceFilePath: AbsoluteFsPath): boolean { } function mergeConfigAndPackageJson( - entryPointPackageJson: EntryPointPackageJson | null, entryPointConfig: NgccEntryPointConfig, + entryPointPackageJson: EntryPointPackageJson|null, entryPointConfig: NgccEntryPointConfig, packagePath: AbsoluteFsPath, entryPointPath: AbsoluteFsPath): EntryPointPackageJson { if (entryPointPackageJson !== null) { return {...entryPointPackageJson, ...entryPointConfig.override}; diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts index 89d28e2398c0f..74b4173006c0e 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_bundle.ts @@ -48,10 +48,8 @@ export function makeEntryPointBundle( enableI18nLegacyMessageIdFormat: boolean = true): EntryPointBundle { // Create the TS program and necessary helpers. const rootDir = entryPoint.package; - const options: ts.CompilerOptions = { - allowJs: true, - maxNodeModuleJsDepth: Infinity, rootDir, ...pathMappings - }; + const options: ts + .CompilerOptions = {allowJs: true, maxNodeModuleJsDepth: Infinity, rootDir, ...pathMappings}; const srcHost = new NgccSourcesCompilerHost(fs, options, entryPoint.path); const dtsHost = new NgtscCompilerHost(fs, options); @@ -72,7 +70,12 @@ export function makeEntryPointBundle( return { entryPoint, format, - rootDirs: [rootDir], isCore, isFlatCore, src, dts, enableI18nLegacyMessageIdFormat + rootDirs: [rootDir], + isCore, + isFlatCore, + src, + dts, + enableI18nLegacyMessageIdFormat }; } diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts index ab9c3cc6697b3..60d78df97e670 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts @@ -12,7 +12,7 @@ import {Logger} from '../logging/logger'; import {NGCC_VERSION} from './build_marker'; import {NgccConfiguration} from './configuration'; -import {EntryPoint, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from './entry_point'; +import {EntryPoint, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from './entry_point'; /** * Manages reading and writing a manifest file that contains a list of all the entry-points that @@ -63,8 +63,8 @@ export class EntryPointManifest { return null; } - this.logger.debug( - `Entry-point manifest found for ${basePath} so loading entry-point information directly.`); + this.logger.debug(`Entry-point manifest found for ${ + basePath} so loading entry-point information directly.`); const startTime = Date.now(); const entryPoints: EntryPoint[] = []; @@ -72,8 +72,9 @@ export class EntryPointManifest { const result = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, entryPointPath); if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { - throw new Error( - `The entry-point manifest at ${manifestPath} contained an invalid pair of package paths: [${packagePath}, ${entryPointPath}]`); + throw new Error(`The entry-point manifest at ${ + manifestPath} contained an invalid pair of package paths: [${packagePath}, ${ + entryPointPath}]`); } else { entryPoints.push(result); } @@ -142,7 +143,9 @@ export class EntryPointManifest { * called. */ export class InvalidatingEntryPointManifest extends EntryPointManifest { - readEntryPointsUsingManifest(basePath: AbsoluteFsPath): EntryPoint[]|null { return null; } + readEntryPointsUsingManifest(basePath: AbsoluteFsPath): EntryPoint[]|null { + return null; + } } /** diff --git a/packages/compiler-cli/ngcc/src/packages/patch_ts_expando_initializer.ts b/packages/compiler-cli/ngcc/src/packages/patch_ts_expando_initializer.ts index 0d6a20b0395c1..b2d5428d2f49f 100644 --- a/packages/compiler-cli/ngcc/src/packages/patch_ts_expando_initializer.ts +++ b/packages/compiler-cli/ngcc/src/packages/patch_ts_expando_initializer.ts @@ -58,17 +58,16 @@ export function patchTsGetExpandoInitializer(): unknown { } // Override the function to add support for recognizing the IIFE structure used in ES5 bundles. - (ts as any).getExpandoInitializer = - (initializer: ts.Node, isPrototypeAssignment: boolean): ts.Expression | undefined => { - // If the initializer is a call expression within parenthesis, unwrap the parenthesis - // upfront such that unsupported IIFE syntax `(function(){}())` becomes `function(){}()`, - // which is supported. - if (ts.isParenthesizedExpression(initializer) && - ts.isCallExpression(initializer.expression)) { - initializer = initializer.expression; - } - return originalGetExpandoInitializer(initializer, isPrototypeAssignment); - }; + (ts as any).getExpandoInitializer = (initializer: ts.Node, + isPrototypeAssignment: boolean): ts.Expression|undefined => { + // If the initializer is a call expression within parenthesis, unwrap the parenthesis + // upfront such that unsupported IIFE syntax `(function(){}())` becomes `function(){}()`, + // which is supported. + if (ts.isParenthesizedExpression(initializer) && ts.isCallExpression(initializer.expression)) { + initializer = initializer.expression; + } + return originalGetExpandoInitializer(initializer, isPrototypeAssignment); + }; return originalGetExpandoInitializer; } @@ -125,16 +124,36 @@ function checkIfExpandoPropertyIsPresent(): boolean { const sourceFile = ts.createSourceFile('test.js', sourceText, ts.ScriptTarget.ES5, true, ts.ScriptKind.JS); const host: ts.CompilerHost = { - getSourceFile(): ts.SourceFile | undefined{return sourceFile;}, - fileExists(): boolean{return true;}, - readFile(): string | undefined{return '';}, + getSourceFile(): ts.SourceFile | + undefined { + return sourceFile; + }, + fileExists(): boolean { + return true; + }, + readFile(): string | + undefined { + return ''; + }, writeFile() {}, - getDefaultLibFileName(): string{return '';}, - getCurrentDirectory(): string{return '';}, - getDirectories(): string[]{return [];}, - getCanonicalFileName(fileName: string): string{return fileName;}, - useCaseSensitiveFileNames(): boolean{return true;}, - getNewLine(): string{return '\n';}, + getDefaultLibFileName(): string { + return ''; + }, + getCurrentDirectory(): string { + return ''; + }, + getDirectories(): string[] { + return []; + }, + getCanonicalFileName(fileName: string): string { + return fileName; + }, + useCaseSensitiveFileNames(): boolean { + return true; + }, + getNewLine(): string { + return '\n'; + }, }; const options = {noResolve: true, noLib: true, noEmit: true, allowJs: true}; const program = ts.createProgram(['test.js'], options, host); diff --git a/packages/compiler-cli/ngcc/src/packages/transformer.ts b/packages/compiler-cli/ngcc/src/packages/transformer.ts index f7a30944f7851..005482f3f7002 100644 --- a/packages/compiler-cli/ngcc/src/packages/transformer.ts +++ b/packages/compiler-cli/ngcc/src/packages/transformer.ts @@ -36,8 +36,7 @@ import {EntryPointBundle} from './entry_point_bundle'; export type TransformResult = { success: true; diagnostics: ts.Diagnostic[]; transformedFiles: FileToWrite[]; -} | -{ +}|{ success: false; diagnostics: ts.Diagnostic[]; }; @@ -79,8 +78,13 @@ export class Transformer { const reflectionHost = new DelegatingReflectionHost(tsReflectionHost, ngccReflectionHost); // Parse and analyze the files. - const {decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - moduleWithProvidersAnalyses, diagnostics} = this.analyzeProgram(reflectionHost, bundle); + const { + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + moduleWithProvidersAnalyses, + diagnostics + } = this.analyzeProgram(reflectionHost, bundle); // Bail if the analysis produced any errors. if (hasErrors(diagnostics)) { @@ -162,8 +166,13 @@ export class Transformer { const privateDeclarationsAnalyses = privateDeclarationsAnalyzer.analyzeProgram(bundle.src.program); - return {decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - moduleWithProvidersAnalyses, diagnostics}; + return { + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + moduleWithProvidersAnalyses, + diagnostics + }; } } diff --git a/packages/compiler-cli/ngcc/src/rendering/commonjs_rendering_formatter.ts b/packages/compiler-cli/ngcc/src/rendering/commonjs_rendering_formatter.ts index bdac597093ee2..1ddfeb64fe564 100644 --- a/packages/compiler-cli/ngcc/src/rendering/commonjs_rendering_formatter.ts +++ b/packages/compiler-cli/ngcc/src/rendering/commonjs_rendering_formatter.ts @@ -6,13 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ import {dirname, relative} from 'canonical-path'; -import * as ts from 'typescript'; import MagicString from 'magic-string'; +import * as ts from 'typescript'; + import {Reexport} from '../../../src/ngtsc/imports'; import {Import, ImportManager} from '../../../src/ngtsc/translator'; import {ExportInfo} from '../analysis/private_declarations_analyzer'; import {isRequireCall} from '../host/commonjs_umd_utils'; import {NgccReflectionHost} from '../host/ngcc_host'; + import {Esm5RenderingFormatter} from './esm5_rendering_formatter'; import {stripExtension} from './utils'; diff --git a/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts b/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts index 25cc214d529d0..91ab5ea398971 100644 --- a/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts +++ b/packages/compiler-cli/ngcc/src/rendering/dts_renderer.ts @@ -7,20 +7,22 @@ */ import MagicString from 'magic-string'; import * as ts from 'typescript'; + import {FileSystem} from '../../../src/ngtsc/file_system'; import {Reexport} from '../../../src/ngtsc/imports'; import {CompileResult} from '../../../src/ngtsc/transform'; -import {translateType, ImportManager} from '../../../src/ngtsc/translator'; +import {ImportManager, translateType} from '../../../src/ngtsc/translator'; +import {ModuleWithProvidersAnalyses, ModuleWithProvidersInfo} from '../analysis/module_with_providers_analyzer'; +import {ExportInfo, PrivateDeclarationsAnalyses} from '../analysis/private_declarations_analyzer'; import {DecorationAnalyses} from '../analysis/types'; -import {ModuleWithProvidersInfo, ModuleWithProvidersAnalyses} from '../analysis/module_with_providers_analyzer'; -import {PrivateDeclarationsAnalyses, ExportInfo} from '../analysis/private_declarations_analyzer'; import {IMPORT_PREFIX} from '../constants'; import {NgccReflectionHost} from '../host/ngcc_host'; -import {EntryPointBundle} from '../packages/entry_point_bundle'; import {Logger} from '../logging/logger'; -import {FileToWrite, getImportRewriter} from './utils'; +import {EntryPointBundle} from '../packages/entry_point_bundle'; + import {RenderingFormatter} from './rendering_formatter'; import {renderSourceAndMap} from './source_maps'; +import {FileToWrite, getImportRewriter} from './utils'; /** * A structure that captures information about what needs to be rendered @@ -84,7 +86,7 @@ export class DtsRenderer { const outputText = new MagicString(dtsFile.text); const printer = ts.createPrinter(); const importManager = new ImportManager( - getImportRewriter(this.bundle.dts !.r3SymbolsFile, this.bundle.isCore, false), + getImportRewriter(this.bundle.dts!.r3SymbolsFile, this.bundle.isCore, false), IMPORT_PREFIX); renderInfo.classInfo.forEach(dtsClass => { @@ -129,7 +131,7 @@ export class DtsRenderer { const dtsDeclaration = this.host.getDtsDeclaration(compiledClass.declaration); if (dtsDeclaration) { const dtsFile = dtsDeclaration.getSourceFile(); - const renderInfo = dtsMap.has(dtsFile) ? dtsMap.get(dtsFile) ! : new DtsRenderInfo(); + const renderInfo = dtsMap.has(dtsFile) ? dtsMap.get(dtsFile)! : new DtsRenderInfo(); renderInfo.classInfo.push({dtsDeclaration, compilation: compiledClass.compilation}); // Only add re-exports if the .d.ts tree is overlayed with the .js tree, as re-exports in // ngcc are only used to support deep imports into e.g. commonjs code. For a deep import @@ -150,7 +152,7 @@ export class DtsRenderer { // Capture the ModuleWithProviders functions/methods that need updating if (moduleWithProvidersAnalyses !== null) { moduleWithProvidersAnalyses.forEach((moduleWithProvidersToFix, dtsFile) => { - const renderInfo = dtsMap.has(dtsFile) ? dtsMap.get(dtsFile) ! : new DtsRenderInfo(); + const renderInfo = dtsMap.has(dtsFile) ? dtsMap.get(dtsFile)! : new DtsRenderInfo(); renderInfo.moduleWithProviders = moduleWithProvidersToFix; dtsMap.set(dtsFile, renderInfo); }); @@ -167,9 +169,9 @@ export class DtsRenderer { `The simplest fix for this is to ensure that this class is exported from the package's entry-point.`); } }); - const dtsEntryPoint = this.bundle.dts !.file; + const dtsEntryPoint = this.bundle.dts!.file; const renderInfo = - dtsMap.has(dtsEntryPoint) ? dtsMap.get(dtsEntryPoint) ! : new DtsRenderInfo(); + dtsMap.has(dtsEntryPoint) ? dtsMap.get(dtsEntryPoint)! : new DtsRenderInfo(); renderInfo.privateExports = privateDeclarationsAnalyses; dtsMap.set(dtsEntryPoint, renderInfo); } diff --git a/packages/compiler-cli/ngcc/src/rendering/esm5_rendering_formatter.ts b/packages/compiler-cli/ngcc/src/rendering/esm5_rendering_formatter.ts index 0feb106de085a..40a347457858d 100644 --- a/packages/compiler-cli/ngcc/src/rendering/esm5_rendering_formatter.ts +++ b/packages/compiler-cli/ngcc/src/rendering/esm5_rendering_formatter.ts @@ -25,14 +25,14 @@ export class Esm5RenderingFormatter extends EsmRenderingFormatter { addDefinitions(output: MagicString, compiledClass: CompiledClass, definitions: string): void { const iifeBody = getIifeBody(compiledClass.declaration); if (!iifeBody) { - throw new Error( - `Compiled class declaration is not inside an IIFE: ${compiledClass.name} in ${compiledClass.declaration.getSourceFile().fileName}`); + throw new Error(`Compiled class declaration is not inside an IIFE: ${compiledClass.name} in ${ + compiledClass.declaration.getSourceFile().fileName}`); } const returnStatement = iifeBody.statements.find(ts.isReturnStatement); if (!returnStatement) { - throw new Error( - `Compiled class wrapper IIFE does not have a return statement: ${compiledClass.name} in ${compiledClass.declaration.getSourceFile().fileName}`); + throw new Error(`Compiled class wrapper IIFE does not have a return statement: ${ + compiledClass.name} in ${compiledClass.declaration.getSourceFile().fileName}`); } const insertionPoint = returnStatement.getFullStart(); diff --git a/packages/compiler-cli/ngcc/src/rendering/esm_rendering_formatter.ts b/packages/compiler-cli/ngcc/src/rendering/esm_rendering_formatter.ts index d2b42d552274d..d2b1cae500f56 100644 --- a/packages/compiler-cli/ngcc/src/rendering/esm_rendering_formatter.ts +++ b/packages/compiler-cli/ngcc/src/rendering/esm_rendering_formatter.ts @@ -8,17 +8,19 @@ import {Statement} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; -import {relative, dirname, AbsoluteFsPath, absoluteFromSourceFile} from '../../../src/ngtsc/file_system'; + +import {absoluteFromSourceFile, AbsoluteFsPath, dirname, relative} from '../../../src/ngtsc/file_system'; import {NOOP_DEFAULT_IMPORT_RECORDER, Reexport} from '../../../src/ngtsc/imports'; import {Import, ImportManager, translateStatement} from '../../../src/ngtsc/translator'; import {isDtsPath} from '../../../src/ngtsc/util/src/typescript'; -import {CompiledClass} from '../analysis/types'; -import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host'; import {ModuleWithProvidersInfo} from '../analysis/module_with_providers_analyzer'; import {ExportInfo} from '../analysis/private_declarations_analyzer'; -import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter'; -import {stripExtension} from './utils'; +import {CompiledClass} from '../analysis/types'; import {isAssignment} from '../host/esm2015_host'; +import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host'; + +import {RedundantDecoratorMap, RenderingFormatter} from './rendering_formatter'; +import {stripExtension} from './utils'; /** * A RenderingFormatter that works with ECMAScript Module import and export statements. @@ -226,7 +228,8 @@ export class EsmRenderingFormatter implements RenderingFormatter { info.declaration.getEnd(); outputText.appendLeft( insertPoint, - `: ${generateImportString(importManager, '@angular/core', 'ModuleWithProviders')}<${ngModule}>`); + `: ${generateImportString(importManager, '@angular/core', 'ModuleWithProviders')}<${ + ngModule}>`); } }); } @@ -296,7 +299,7 @@ function findStatement(node: ts.Node): ts.Statement|undefined { } function generateImportString( - importManager: ImportManager, importPath: string | null, importName: string) { + importManager: ImportManager, importPath: string|null, importName: string) { const importAs = importPath ? importManager.generateNamedImport(importPath, importName) : null; return importAs ? `${importAs.moduleImport}.${importAs.symbol}` : `${importName}`; } diff --git a/packages/compiler-cli/ngcc/src/rendering/renderer.ts b/packages/compiler-cli/ngcc/src/rendering/renderer.ts index 54480b7df7a4c..033d05530ca71 100644 --- a/packages/compiler-cli/ngcc/src/rendering/renderer.ts +++ b/packages/compiler-cli/ngcc/src/rendering/renderer.ts @@ -8,16 +8,18 @@ import {ConstantPool, Expression, Statement, WrappedNodeExpr, WritePropExpr} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; + +import {FileSystem} from '../../../src/ngtsc/file_system'; import {ImportManager} from '../../../src/ngtsc/translator'; -import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/types'; import {PrivateDeclarationsAnalyses} from '../analysis/private_declarations_analyzer'; import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer'; +import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/types'; import {IMPORT_PREFIX} from '../constants'; -import {FileSystem} from '../../../src/ngtsc/file_system'; import {NgccReflectionHost} from '../host/ngcc_host'; import {Logger} from '../logging/logger'; import {EntryPointBundle} from '../packages/entry_point_bundle'; -import {RenderingFormatter, RedundantDecoratorMap} from './rendering_formatter'; + +import {RedundantDecoratorMap, RenderingFormatter} from './rendering_formatter'; import {renderSourceAndMap} from './source_maps'; import {FileToWrite, getImportRewriter, stripExtension} from './utils'; @@ -138,11 +140,11 @@ export class Renderer { if (dec.node === null) { return; } - const decoratorArray = dec.node.parent !; + const decoratorArray = dec.node.parent!; if (!decoratorsToRemove.has(decoratorArray)) { decoratorsToRemove.set(decoratorArray, [dec.node]); } else { - decoratorsToRemove.get(decoratorArray) !.push(dec.node); + decoratorsToRemove.get(decoratorArray)!.push(dec.node); } }); }); @@ -160,8 +162,9 @@ export class Renderer { private renderDefinitions( sourceFile: ts.SourceFile, compiledClass: CompiledClass, imports: ImportManager): string { const name = this.host.getInternalNameOfClass(compiledClass.declaration); - const statements: Statement[] = compiledClass.compilation.map( - c => { return createAssignmentStatement(name, c.name, c.initializer); }); + const statements: Statement[] = compiledClass.compilation.map(c => { + return createAssignmentStatement(name, c.name, c.initializer); + }); return this.renderStatements(sourceFile, statements, imports); } diff --git a/packages/compiler-cli/ngcc/src/rendering/rendering_formatter.ts b/packages/compiler-cli/ngcc/src/rendering/rendering_formatter.ts index e97b1065682a4..4cfeadeb05931 100644 --- a/packages/compiler-cli/ngcc/src/rendering/rendering_formatter.ts +++ b/packages/compiler-cli/ngcc/src/rendering/rendering_formatter.ts @@ -8,12 +8,13 @@ import {Statement} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; + import {Reexport} from '../../../src/ngtsc/imports'; import {Import, ImportManager} from '../../../src/ngtsc/translator'; +import {ModuleWithProvidersInfo} from '../analysis/module_with_providers_analyzer'; import {ExportInfo} from '../analysis/private_declarations_analyzer'; import {CompiledClass} from '../analysis/types'; import {SwitchableVariableDeclaration} from '../host/ngcc_host'; -import {ModuleWithProvidersInfo} from '../analysis/module_with_providers_analyzer'; /** * The collected decorators that have become redundant after the compilation diff --git a/packages/compiler-cli/ngcc/src/rendering/source_maps.ts b/packages/compiler-cli/ngcc/src/rendering/source_maps.ts index ff836bdc600d7..07d040db86f9d 100644 --- a/packages/compiler-cli/ngcc/src/rendering/source_maps.ts +++ b/packages/compiler-cli/ngcc/src/rendering/source_maps.ts @@ -5,14 +5,16 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {SourceMapConverter, fromObject, generateMapFileComment} from 'convert-source-map'; +import {fromObject, generateMapFileComment, SourceMapConverter} from 'convert-source-map'; import MagicString from 'magic-string'; import * as ts from 'typescript'; -import {FileSystem, absoluteFromSourceFile, basename, absoluteFrom} from '../../../src/ngtsc/file_system'; -import {FileToWrite} from './utils'; -import {SourceFileLoader} from '../sourcemaps/source_file_loader'; -import {RawSourceMap} from '../sourcemaps/raw_source_map'; + +import {absoluteFrom, absoluteFromSourceFile, basename, FileSystem} from '../../../src/ngtsc/file_system'; import {Logger} from '../logging/logger'; +import {RawSourceMap} from '../sourcemaps/raw_source_map'; +import {SourceFileLoader} from '../sourcemaps/source_file_loader'; + +import {FileToWrite} from './utils'; export interface SourceMapInfo { source: string; @@ -53,8 +55,8 @@ export function renderSourceAndMap( ]; } } catch (e) { - logger.error( - `Error when flattening the source-map "${generatedMapPath}" for "${generatedPath}": ${e.toString()}`); + logger.error(`Error when flattening the source-map "${generatedMapPath}" for "${ + generatedPath}": ${e.toString()}`); return [ {path: generatedPath, contents: generatedContent}, {path: generatedMapPath, contents: fromObject(generatedMap).toJSON()}, diff --git a/packages/compiler-cli/ngcc/src/rendering/umd_rendering_formatter.ts b/packages/compiler-cli/ngcc/src/rendering/umd_rendering_formatter.ts index 4860cda6b86e5..8051f79c15ba0 100644 --- a/packages/compiler-cli/ngcc/src/rendering/umd_rendering_formatter.ts +++ b/packages/compiler-cli/ngcc/src/rendering/umd_rendering_formatter.ts @@ -6,17 +6,19 @@ * found in the LICENSE file at https://angular.io/license */ import {dirname, relative} from 'canonical-path'; -import * as ts from 'typescript'; import MagicString from 'magic-string'; +import * as ts from 'typescript'; + +import {Reexport} from '../../../src/ngtsc/imports'; import {Import, ImportManager} from '../../../src/ngtsc/translator'; import {ExportInfo} from '../analysis/private_declarations_analyzer'; import {UmdReflectionHost} from '../host/umd_host'; + import {Esm5RenderingFormatter} from './esm5_rendering_formatter'; import {stripExtension} from './utils'; -import {Reexport} from '../../../src/ngtsc/imports'; -type CommonJsConditional = ts.ConditionalExpression & {whenTrue: ts.CallExpression}; -type AmdConditional = ts.ConditionalExpression & {whenTrue: ts.CallExpression}; +type CommonJsConditional = ts.ConditionalExpression&{whenTrue: ts.CallExpression}; +type AmdConditional = ts.ConditionalExpression&{whenTrue: ts.CallExpression}; /** * A RenderingFormatter that works with UMD files, instead of `import` and `export` statements @@ -24,7 +26,9 @@ type AmdConditional = ts.ConditionalExpression & {whenTrue: ts.CallExpression}; * wrapper function for AMD, CommonJS and global module formats. */ export class UmdRenderingFormatter extends Esm5RenderingFormatter { - constructor(protected umdHost: UmdReflectionHost, isCore: boolean) { super(umdHost, isCore); } + constructor(protected umdHost: UmdReflectionHost, isCore: boolean) { + super(umdHost, isCore); + } /** * Add the imports to the UMD module IIFE. diff --git a/packages/compiler-cli/ngcc/src/rendering/utils.ts b/packages/compiler-cli/ngcc/src/rendering/utils.ts index 29cafaa78599b..9b9d25303ec42 100644 --- a/packages/compiler-cli/ngcc/src/rendering/utils.ts +++ b/packages/compiler-cli/ngcc/src/rendering/utils.ts @@ -24,11 +24,11 @@ export interface FileToWrite { * Create an appropriate ImportRewriter given the parameters. */ export function getImportRewriter( - r3SymbolsFile: ts.SourceFile | null, isCore: boolean, isFlat: boolean): ImportRewriter { + r3SymbolsFile: ts.SourceFile|null, isCore: boolean, isFlat: boolean): ImportRewriter { if (isCore && isFlat) { return new NgccFlatImportRewriter(); } else if (isCore) { - return new R3SymbolsImportRewriter(r3SymbolsFile !.fileName); + return new R3SymbolsImportRewriter(r3SymbolsFile!.fileName); } else { return new NoopImportRewriter(); } diff --git a/packages/compiler-cli/ngcc/src/sourcemaps/segment_marker.ts b/packages/compiler-cli/ngcc/src/sourcemaps/segment_marker.ts index 78d71f1053a0c..2fa738ace33de 100644 --- a/packages/compiler-cli/ngcc/src/sourcemaps/segment_marker.ts +++ b/packages/compiler-cli/ngcc/src/sourcemaps/segment_marker.ts @@ -8,11 +8,11 @@ /** -* A marker that indicates the start of a segment in a mapping. -* -* The end of a segment is indicated by the the first segment-marker of another mapping whose start -* is greater or equal to this one. -*/ + * A marker that indicates the start of a segment in a mapping. + * + * The end of a segment is indicated by the the first segment-marker of another mapping whose start + * is greater or equal to this one. + */ export interface SegmentMarker { readonly line: number; readonly column: number; diff --git a/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts b/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts index 839eec56f02fb..f860d162fc726 100644 --- a/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts +++ b/packages/compiler-cli/ngcc/src/sourcemaps/source_file.ts @@ -6,10 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ import {removeComments, removeMapFileComments} from 'convert-source-map'; -import {SourceMapMappings, SourceMapSegment, decode, encode} from 'sourcemap-codec'; +import {decode, encode, SourceMapMappings, SourceMapSegment} from 'sourcemap-codec'; + import {AbsoluteFsPath, dirname, relative} from '../../../src/ngtsc/file_system'; + import {RawSourceMap} from './raw_source_map'; -import {SegmentMarker, compareSegments, offsetSegment} from './segment_marker'; +import {compareSegments, offsetSegment, SegmentMarker} from './segment_marker'; export function removeSourceMapComments(contents: string): string { return removeMapFileComments(removeComments(contents)).replace(/\n\n$/, '\n'); @@ -77,7 +79,8 @@ export class SourceFile { const sourceMap: RawSourceMap = { version: 3, file: relative(sourcePathDir, this.sourcePath), - sources: sources.map(sf => relative(sourcePathDir, sf.sourcePath)), names, + sources: sources.map(sf => relative(sourcePathDir, sf.sourcePath)), + names, mappings: encode(mappings), sourcesContent: sources.map(sf => sf.contents), }; @@ -302,7 +305,7 @@ export function mergeMappings(generatedSource: SourceFile, ab: Mapping, bc: Mapp * in the `sources` parameter. */ export function parseMappings( - rawMap: RawSourceMap | null, sources: (SourceFile | null)[], + rawMap: RawSourceMap|null, sources: (SourceFile|null)[], generatedSourceStartOfLinePositions: number[]): Mapping[] { if (rawMap === null) { return []; @@ -318,15 +321,15 @@ export function parseMappings( const generatedLineMappings = rawMappings[generatedLine]; for (const rawMapping of generatedLineMappings) { if (rawMapping.length >= 4) { - const originalSource = sources[rawMapping[1] !]; + const originalSource = sources[rawMapping[1]!]; if (originalSource === null || originalSource === undefined) { // the original source is missing so ignore this mapping continue; } const generatedColumn = rawMapping[0]; const name = rawMapping.length === 5 ? rawMap.names[rawMapping[4]] : undefined; - const line = rawMapping[2] !; - const column = rawMapping[3] !; + const line = rawMapping[2]!; + const column = rawMapping[3]!; const generatedSegment: SegmentMarker = { line: generatedLine, column: generatedColumn, @@ -361,7 +364,7 @@ export function extractOriginalSegments(mappings: Mapping[]): Map<SourceFile, Se if (!originalSegments.has(originalSource)) { originalSegments.set(originalSource, []); } - const segments = originalSegments.get(originalSource) !; + const segments = originalSegments.get(originalSource)!; segments.push(mapping.originalSegment); } originalSegments.forEach(segmentMarkers => segmentMarkers.sort(compareSegments)); diff --git a/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts b/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts index 76b7966c49f8f..50626436c3e55 100644 --- a/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts +++ b/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts @@ -6,7 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ import {commentRegex, fromComment, mapFileCommentRegex} from 'convert-source-map'; -import {AbsoluteFsPath, FileSystem, absoluteFrom} from '../../../src/ngtsc/file_system'; + +import {absoluteFrom, AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system'; + import {RawSourceMap} from './raw_source_map'; import {SourceFile} from './source_file'; @@ -51,8 +53,8 @@ export class SourceFileLoader { // Track source file paths if we have loaded them from disk so that we don't get into an // infinite recursion if (previousPaths.includes(sourcePath)) { - throw new Error( - `Circular source file mapping dependency: ${previousPaths.join(' -> ')} -> ${sourcePath}`); + throw new Error(`Circular source file mapping dependency: ${ + previousPaths.join(' -> ')} -> ${sourcePath}`); } previousPaths = previousPaths.concat([sourcePath]); @@ -66,7 +68,7 @@ export class SourceFileLoader { let map: RawSourceMap|null = null; let inline = true; - let sources: (SourceFile | null)[] = []; + let sources: (SourceFile|null)[] = []; if (mapAndPath !== null) { const basePath = mapAndPath.mapPath || sourcePath; sources = this.processSources(basePath, mapAndPath.map, previousPaths); @@ -87,7 +89,7 @@ export class SourceFileLoader { private loadSourceMap(sourcePath: AbsoluteFsPath, contents: string): MapAndPath|null { const inline = commentRegex.exec(contents); if (inline !== null) { - return {map: fromComment(inline.pop() !).sourcemap, mapPath: null}; + return {map: fromComment(inline.pop()!).sourcemap, mapPath: null}; } const external = mapFileCommentRegex.exec(contents); diff --git a/packages/compiler-cli/ngcc/src/utils.ts b/packages/compiler-cli/ngcc/src/utils.ts index fc633164f8924..f729abe386bcb 100644 --- a/packages/compiler-cli/ngcc/src/utils.ts +++ b/packages/compiler-cli/ngcc/src/utils.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {AbsoluteFsPath, FileSystem, absoluteFrom} from '../../src/ngtsc/file_system'; + +import {absoluteFrom, AbsoluteFsPath, FileSystem} from '../../src/ngtsc/file_system'; import {KnownDeclaration} from '../../src/ngtsc/reflection'; /** @@ -37,11 +38,11 @@ export function getOriginalSymbol(checker: ts.TypeChecker): (symbol: ts.Symbol) }; } -export function isDefined<T>(value: T | undefined | null): value is T { +export function isDefined<T>(value: T|undefined|null): value is T { return (value !== undefined) && (value !== null); } -export function getNameText(name: ts.PropertyName | ts.BindingName): string { +export function getNameText(name: ts.PropertyName|ts.BindingName): string { return ts.isIdentifier(name) || ts.isLiteralExpression(name) ? name.text : name.getText(); } @@ -111,10 +112,12 @@ export class FactoryMap<K, V> { this.internalMap.set(key, this.factory(key)); } - return this.internalMap.get(key) !; + return this.internalMap.get(key)!; } - set(key: K, value: V): void { this.internalMap.set(key, value); } + set(key: K, value: V): void { + this.internalMap.set(key, value); + } } /** diff --git a/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts b/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts index 3bf1861955ea3..12c1ccfcea0d5 100644 --- a/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts +++ b/packages/compiler-cli/ngcc/src/writing/cleaning/cleaning_strategies.ts @@ -5,15 +5,16 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, PathSegment, absoluteFrom} from '../../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, PathSegment} from '../../../../src/ngtsc/file_system'; import {cleanPackageJson} from '../../packages/build_marker'; import {NGCC_BACKUP_EXTENSION} from '../in_place_file_writer'; import {NGCC_DIRECTORY} from '../new_entry_point_file_writer'; + import {isLocalDirectory} from './utils'; /** -* Implement this interface to extend the cleaning strategies of the `PackageCleaner`. -*/ + * Implement this interface to extend the cleaning strategies of the `PackageCleaner`. + */ export interface CleaningStrategy { canClean(path: AbsoluteFsPath, basename: PathSegment): boolean; clean(path: AbsoluteFsPath, basename: PathSegment): void; @@ -44,7 +45,9 @@ export class NgccDirectoryCleaner implements CleaningStrategy { canClean(path: AbsoluteFsPath, basename: PathSegment): boolean { return basename === NGCC_DIRECTORY && isLocalDirectory(this.fs, path); } - clean(path: AbsoluteFsPath, _basename: PathSegment): void { this.fs.removeDeep(path); } + clean(path: AbsoluteFsPath, _basename: PathSegment): void { + this.fs.removeDeep(path); + } } /** diff --git a/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts b/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts index ab390f2c6feda..52c6022053ddc 100644 --- a/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts +++ b/packages/compiler-cli/ngcc/src/writing/in_place_file_writer.ts @@ -5,11 +5,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {FileSystem, absoluteFrom, dirname} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, dirname, FileSystem} from '../../../src/ngtsc/file_system'; import {Logger} from '../logging/logger'; import {EntryPointJsonProperty} from '../packages/entry_point'; import {EntryPointBundle} from '../packages/entry_point_bundle'; import {FileToWrite} from '../rendering/utils'; + import {FileWriter} from './file_writer'; export const NGCC_BACKUP_EXTENSION = '.__ivy_ngcc_bak'; @@ -37,7 +38,9 @@ export class InPlaceFileWriter implements FileWriter { `Tried to overwrite ${backPath} with an ngcc back up file, which is disallowed.`); } else { this.logger.error( - `Tried to write ${backPath} with an ngcc back up file but it already exists so not writing, nor backing up, ${file.path}.\n` + + `Tried to write ${ + backPath} with an ngcc back up file but it already exists so not writing, nor backing up, ${ + file.path}.\n` + `This error may be because two or more entry-points overlap and ngcc has been asked to process some files more than once.\n` + `You should check other entry-points in this package and set up a config to ignore any that you are not using.`); } diff --git a/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts b/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts index 0d78265f3a0e0..40c8fa2c7335f 100644 --- a/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts +++ b/packages/compiler-cli/ngcc/src/writing/new_entry_point_file_writer.ts @@ -6,7 +6,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFromSourceFile, dirname, join, relative} from '../../../src/ngtsc/file_system'; +import {absoluteFromSourceFile, AbsoluteFsPath, dirname, FileSystem, join, relative} from '../../../src/ngtsc/file_system'; import {isDtsPath} from '../../../src/ngtsc/util/src/typescript'; import {Logger} from '../logging/logger'; import {EntryPoint, EntryPointJsonProperty} from '../packages/entry_point'; @@ -83,8 +83,8 @@ export class NewEntryPointFileWriter extends InPlaceFileWriter { const packageJsonPath = join(entryPoint.path, 'package.json'); // All format properties point to the same format-path. - const oldFormatProp = formatProperties[0] !; - const oldFormatPath = packageJson[oldFormatProp] !; + const oldFormatProp = formatProperties[0]!; + const oldFormatPath = packageJson[oldFormatProp]!; const oldAbsFormatPath = join(entryPoint.path, oldFormatPath); const newAbsFormatPath = join(ngccFolder, relative(entryPoint.package, oldAbsFormatPath)); const newFormatPath = relative(entryPoint.path, newAbsFormatPath); diff --git a/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts b/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts index bfd5295ad439e..bf36458300f6a 100644 --- a/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts +++ b/packages/compiler-cli/ngcc/src/writing/package_json_updater.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, dirname} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, dirname, FileSystem} from '../../../src/ngtsc/file_system'; import {JsonObject, JsonValue} from '../packages/entry_point'; export type PackageJsonChange = [string[], JsonValue, PackageJsonPropertyPositioning]; -export type PackageJsonPropertyPositioning = 'unimportant' | 'alphabetic' | {before: string}; +export type PackageJsonPropertyPositioning = 'unimportant'|'alphabetic'|{before: string}; export type WritePackageJsonChangesFn = (changes: PackageJsonChange[], packageJsonPath: AbsoluteFsPath, parsedJson?: JsonObject) => void; diff --git a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts index 12b4b62b21807..42e932da7dc67 100644 --- a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {FatalDiagnosticError, makeDiagnostic} from '../../../src/ngtsc/diagnostics'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {ClassDeclaration, Decorator} from '../../../src/ngtsc/reflection'; import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../../src/ngtsc/transform'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; @@ -21,7 +21,7 @@ import {Migration, MigrationHost} from '../../src/migrations/migration'; import {MockLogger} from '../helpers/mock_logger'; import {getRootFiles, makeTestEntryPointBundle} from '../helpers/utils'; -type DecoratorHandlerWithResolve = DecoratorHandler<unknown, unknown, unknown>& { +type DecoratorHandlerWithResolve = DecoratorHandler<unknown, unknown, unknown>&{ resolve: NonNullable<DecoratorHandler<unknown, unknown, unknown>['resolve']>; }; @@ -29,7 +29,9 @@ runInEachFileSystem(() => { describe('DecorationAnalyzer', () => { let _: typeof absoluteFrom; - beforeEach(() => { _ = absoluteFrom; }); + beforeEach(() => { + _ = absoluteFrom; + }); describe('analyzeProgram()', () => { let logs: string[]; @@ -50,8 +52,8 @@ runInEachFileSystem(() => { ]); // Only detect the Component and Directive decorators handler.detect.and.callFake( - (node: ts.Declaration, decorators: Decorator[] | null): DetectResult<unknown>| - undefined => { + (node: ts.Declaration, decorators: Decorator[]|null): DetectResult<unknown>| + undefined => { const className = (node as any).name.text; if (decorators === null) { logs.push(`detect: ${className} (no decorators)`); @@ -94,17 +96,17 @@ runInEachFileSystem(() => { // The "test" compilation result is just the name of the decorator being compiled // (suffixed with `(compiled)`) handler.compile.and.callFake((decl: ts.Declaration, analysis: any) => { - logs.push( - `compile: ${(decl as any).name.text}@${analysis.decoratorName} (resolved: ${analysis.resolved})`); + logs.push(`compile: ${(decl as any).name.text}@${analysis.decoratorName} (resolved: ${ + analysis.resolved})`); return `@${analysis.decoratorName} (compiled)`; }); return handler; }; - function setUpAnalyzer( - testFiles: TestFile[], - options: {analyzeError: boolean, - resolveError: boolean} = {analyzeError: false, resolveError: false}) { + function setUpAnalyzer(testFiles: TestFile[], options: { + analyzeError: boolean, + resolveError: boolean + } = {analyzeError: false, resolveError: false}) { logs = []; loadTestFiles(testFiles); loadFakeCore(getFileSystem()); @@ -173,9 +175,9 @@ runInEachFileSystem(() => { it('should return an object containing a reference to the original source file', () => { const testFile = getSourceFileOrError(program, _('/node_modules/test-package/test.js')); - expect(result.get(testFile) !.sourceFile).toBe(testFile); + expect(result.get(testFile)!.sourceFile).toBe(testFile); const otherFile = getSourceFileOrError(program, _('/node_modules/test-package/other.js')); - expect(result.get(otherFile) !.sourceFile).toBe(otherFile); + expect(result.get(otherFile)!.sourceFile).toBe(otherFile); }); it('should call detect on the decorator handlers with each class from the parsed file', @@ -192,20 +194,23 @@ runInEachFileSystem(() => { it('should return an object containing the classes that were analyzed', () => { const file1 = getSourceFileOrError(program, _('/node_modules/test-package/test.js')); - const compiledFile1 = result.get(file1) !; + const compiledFile1 = result.get(file1)!; expect(compiledFile1.compiledClasses.length).toEqual(2); expect(compiledFile1.compiledClasses[0]).toEqual(jasmine.objectContaining({ - name: 'MyComponent', compilation: ['@Component (compiled)'], + name: 'MyComponent', + compilation: ['@Component (compiled)'], } as unknown as CompiledClass)); expect(compiledFile1.compiledClasses[1]).toEqual(jasmine.objectContaining({ - name: 'MyDirective', compilation: ['@Directive (compiled)'], + name: 'MyDirective', + compilation: ['@Directive (compiled)'], } as unknown as CompiledClass)); const file2 = getSourceFileOrError(program, _('/node_modules/test-package/other.js')); - const compiledFile2 = result.get(file2) !; + const compiledFile2 = result.get(file2)!; expect(compiledFile2.compiledClasses.length).toEqual(1); expect(compiledFile2.compiledClasses[0]).toEqual(jasmine.objectContaining({ - name: 'MyOtherComponent', compilation: ['@Component (compiled)'], + name: 'MyOtherComponent', + compilation: ['@Component (compiled)'], } as unknown as CompiledClass)); }); @@ -284,18 +289,18 @@ runInEachFileSystem(() => { () => { const file = getSourceFileOrError(program, _('/node_modules/test-package/component.js')); - const analysis = result.get(file) !; + const analysis = result.get(file)!; expect(analysis).toBeDefined(); const ImportedComponent = - analysis.compiledClasses.find(f => f.name === 'ImportedComponent') !; + analysis.compiledClasses.find(f => f.name === 'ImportedComponent')!; expect(ImportedComponent).toBeDefined(); }); it('should analyze an internally defined component, which is not exported at all', () => { const file = getSourceFileOrError(program, _('/node_modules/test-package/entrypoint.js')); - const analysis = result.get(file) !; + const analysis = result.get(file)!; expect(analysis).toBeDefined(); - const LocalComponent = analysis.compiledClasses.find(f => f.name === 'LocalComponent') !; + const LocalComponent = analysis.compiledClasses.find(f => f.name === 'LocalComponent')!; expect(LocalComponent).toBeDefined(); }); }); @@ -341,7 +346,7 @@ runInEachFileSystem(() => { }); it('should ignore classes from an externally imported file', () => { - const file = program.getSourceFile(_('/node_modules/other/component.js')) !; + const file = program.getSourceFile(_('/node_modules/other/component.js'))!; expect(result.has(file)).toBe(false); }); }); @@ -427,11 +432,15 @@ runInEachFileSystem(() => { name = 'FakeDecoratorHandler'; precedence = HandlerPrecedence.PRIMARY; - detect(): undefined { throw new Error('detect should not have been called'); } + detect(): undefined { + throw new Error('detect should not have been called'); + } analyze(): AnalysisOutput<unknown> { throw new Error('analyze should not have been called'); } - compile(): CompileResult { throw new Error('compile should not have been called'); } + compile(): CompileResult { + throw new Error('compile should not have been called'); + } } const analyzer = setUpAnalyzer([{ diff --git a/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts b/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts index bceeadc9f30df..57c3da663f80f 100644 --- a/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts @@ -62,7 +62,7 @@ runInEachFileSystem(() => { const {host, compiler} = createMigrationHost({entryPoint, handlers: [handler]}); host.injectSyntheticDecorator(mockClazz, injectedDecorator); - const record = compiler.recordFor(mockClazz) !; + const record = compiler.recordFor(mockClazz)!; expect(record).toBeDefined(); expect(record.traits.length).toBe(1); expect(record.traits[0].detected.decorator).toBe(injectedDecorator); @@ -77,7 +77,7 @@ runInEachFileSystem(() => { const decorator = createComponentDecorator(mockClazz, {selector: 'comp', exportAs: null}); host.injectSyntheticDecorator(mockClazz, decorator); - const record = compiler.recordFor(mockClazz) !; + const record = compiler.recordFor(mockClazz)!; const migratedTrait = record.traits[0]; if (migratedTrait.state !== TraitState.ERRORED) { return fail('Expected migrated class trait to be in an error state'); @@ -120,7 +120,7 @@ runInEachFileSystem(() => { host.injectSyntheticDecorator(myClass, injectedDecorator); - const decorators = host.getAllDecorators(myClass) !; + const decorators = host.getAllDecorators(myClass)!; expect(decorators.length).toBe(2); expect(decorators[0].name).toBe('Directive'); expect(decorators[1].name).toBe('InjectedDecorator'); @@ -183,9 +183,13 @@ class DetectDecoratorHandler implements DecoratorHandler<unknown, unknown, unkno return {trigger: node, decorator, metadata: {}}; } - analyze(node: ClassDeclaration): AnalysisOutput<unknown> { return {}; } + analyze(node: ClassDeclaration): AnalysisOutput<unknown> { + return {}; + } - compile(node: ClassDeclaration): CompileResult|CompileResult[] { return []; } + compile(node: ClassDeclaration): CompileResult|CompileResult[] { + return []; + } } class DiagnosticProducingHandler implements DecoratorHandler<unknown, unknown, unknown> { @@ -201,5 +205,7 @@ class DiagnosticProducingHandler implements DecoratorHandler<unknown, unknown, u return {diagnostics: [makeDiagnostic(9999, node, 'test diagnostic')]}; } - compile(node: ClassDeclaration): CompileResult|CompileResult[] { return []; } + compile(node: ClassDeclaration): CompileResult|CompileResult[] { + return []; + } } diff --git a/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts index 87e07e9bc8335..a775dd4cc736b 100644 --- a/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/module_with_providers_analyzer_spec.ts @@ -7,8 +7,8 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {absoluteFrom, AbsoluteFsPath, getSourceFileOrError} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadTestFiles} from '../../../test/helpers'; import {ModuleWithProvidersAnalyses, ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer'; @@ -333,7 +333,7 @@ runInEachFileSystem(() => { 'test-package', 'esm2015', false, getRootFiles(TEST_PROGRAM), getRootFiles(TEST_DTS_PROGRAM)); program = bundle.src.program; - dtsProgram = bundle.dts !; + dtsProgram = bundle.dts!; const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle.src, dtsProgram); referencesRegistry = new NgccReferencesRegistry(host); @@ -367,8 +367,8 @@ runInEachFileSystem(() => { const libraryModuleDeclaration = getDeclaration( program, absoluteFrom('/node_modules/some-library/index.d.ts'), 'LibraryModule', ts.isClassDeclaration); - expect(declarations.has(externalModuleDeclaration.name !)).toBe(true); - expect(declarations.has(libraryModuleDeclaration.name !)).toBe(false); + expect(declarations.has(externalModuleDeclaration.name!)).toBe(true); + expect(declarations.has(libraryModuleDeclaration.name!)).toBe(false); }); it('should find declarations that have implicit return types', () => { @@ -414,13 +414,12 @@ runInEachFileSystem(() => { analyses: ModuleWithProvidersAnalyses, fileName: AbsoluteFsPath) { const file = getSourceFileOrError(dtsProgram.program, fileName); const analysis = analyses.get(file); - return analysis ? - analysis.map( - info => - [info.declaration.name !.getText(), - (info.ngModule.node as ts.ClassDeclaration).name !.getText(), - info.ngModule.viaModule]) : - []; + return analysis ? analysis.map( + info => + [info.declaration.name!.getText(), + (info.ngModule.node as ts.ClassDeclaration).name!.getText(), + info.ngModule.viaModule]) : + []; } }); }); @@ -536,7 +535,7 @@ runInEachFileSystem(() => { 'test-package', 'esm2015', false, getRootFiles(TEST_PROGRAM), getRootFiles(TEST_DTS_PROGRAM)); const program = bundle.src.program; - const dtsProgram = bundle.dts !; + const dtsProgram = bundle.dts!; const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle.src, dtsProgram); const referencesRegistry = new NgccReferencesRegistry(host); @@ -558,9 +557,9 @@ runInEachFileSystem(() => { const libraryModuleDeclaration = getDeclaration( program, absoluteFrom('/node_modules/some-library/index.d.ts'), 'LibraryModule', ts.isClassDeclaration); - expect(declarations.has(explicitInternalModuleDeclaration.name !)).toBe(true); - expect(declarations.has(externalModuleDeclaration.name !)).toBe(true); - expect(declarations.has(libraryModuleDeclaration.name !)).toBe(false); + expect(declarations.has(explicitInternalModuleDeclaration.name!)).toBe(true); + expect(declarations.has(externalModuleDeclaration.name!)).toBe(true); + expect(declarations.has(libraryModuleDeclaration.name!)).toBe(false); }); it('should track references even when typings have already been processed', () => { @@ -586,9 +585,9 @@ runInEachFileSystem(() => { const libraryModuleDeclaration = getDeclaration( program, absoluteFrom('/node_modules/some-library/index.d.ts'), 'LibraryModule', ts.isClassDeclaration); - expect(declarations.has(explicitInternalModuleDeclaration.name !)).toBe(true); - expect(declarations.has(externalModuleDeclaration.name !)).toBe(true); - expect(declarations.has(libraryModuleDeclaration.name !)).toBe(false); + expect(declarations.has(explicitInternalModuleDeclaration.name!)).toBe(true); + expect(declarations.has(externalModuleDeclaration.name!)).toBe(true); + expect(declarations.has(libraryModuleDeclaration.name!)).toBe(false); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts b/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts index c164a76a5ea74..776be92f05afe 100644 --- a/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/ngcc_trait_compiler_spec.ts @@ -91,7 +91,7 @@ runInEachFileSystem(() => { const record = compiler.recordFor(mockClazz); expect(record).toBeDefined(); - expect(record !.traits.length).toBe(1); + expect(record!.traits.length).toBe(1); }); it('should add a new trait to an existing class record', () => { @@ -118,11 +118,11 @@ runInEachFileSystem(() => { compiler.analyzeFile(entryPoint.src.file); compiler.injectSyntheticDecorator(myClass, injectedDecorator); - const record = compiler.recordFor(myClass) !; + const record = compiler.recordFor(myClass)!; expect(record).toBeDefined(); expect(record.traits.length).toBe(2); - expect(record.traits[0].detected.decorator !.name).toBe('Directive'); - expect(record.traits[1].detected.decorator !.name).toBe('InjectedDecorator'); + expect(record.traits[0].detected.decorator!.name).toBe('Directive'); + expect(record.traits[1].detected.decorator!.name).toBe('InjectedDecorator'); }); it('should not add a weak handler when a primary handler already exists', () => { @@ -150,10 +150,10 @@ runInEachFileSystem(() => { compiler.injectSyntheticDecorator(myClass, injectedDecorator); - const record = compiler.recordFor(myClass) !; + const record = compiler.recordFor(myClass)!; expect(record).toBeDefined(); expect(record.traits.length).toBe(1); - expect(record.traits[0].detected.decorator !.name).toBe('Directive'); + expect(record.traits[0].detected.decorator!.name).toBe('Directive'); }); it('should replace an existing weak handler when injecting a primary handler', () => { @@ -181,10 +181,10 @@ runInEachFileSystem(() => { compiler.injectSyntheticDecorator(myClass, injectedDecorator); - const record = compiler.recordFor(myClass) !; + const record = compiler.recordFor(myClass)!; expect(record).toBeDefined(); expect(record.traits.length).toBe(1); - expect(record.traits[0].detected.decorator !.name).toBe('InjectedDecorator'); + expect(record.traits[0].detected.decorator!.name).toBe('InjectedDecorator'); }); it('should produce an error when a primary handler is added when a primary handler is already present', @@ -214,12 +214,11 @@ runInEachFileSystem(() => { compiler.injectSyntheticDecorator(myClass, injectedDecorator); - const record = compiler.recordFor(myClass) !; + const record = compiler.recordFor(myClass)!; expect(record).toBeDefined(); expect(record.metaDiagnostics).toBeDefined(); - expect(record.metaDiagnostics !.length).toBe(1); - expect(record.metaDiagnostics ![0].code) - .toBe(ngErrorCode(ErrorCode.DECORATOR_COLLISION)); + expect(record.metaDiagnostics!.length).toBe(1); + expect(record.metaDiagnostics![0].code).toBe(ngErrorCode(ErrorCode.DECORATOR_COLLISION)); expect(record.traits.length).toBe(0); }); @@ -233,7 +232,7 @@ runInEachFileSystem(() => { const decorator = createComponentDecorator(mockClazz, {selector: 'comp', exportAs: null}); compiler.injectSyntheticDecorator(mockClazz, decorator); - const record = compiler.recordFor(mockClazz) !; + const record = compiler.recordFor(mockClazz)!; const migratedTrait = record.traits[0]; if (migratedTrait.state !== TraitState.ERRORED) { return fail('Expected migrated class trait to be in an error state'); @@ -286,13 +285,12 @@ runInEachFileSystem(() => { compiler.injectSyntheticDecorator(myClass, injectedDecorator); - const decorators = compiler.getAllDecorators(myClass) !; + const decorators = compiler.getAllDecorators(myClass)!; expect(decorators.length).toBe(2); expect(decorators[0].name).toBe('Directive'); expect(decorators[1].name).toBe('InjectedDecorator'); }); }); - }); }); @@ -302,7 +300,7 @@ class TestHandler implements DecoratorHandler<unknown, unknown, unknown> { precedence = HandlerPrecedence.PRIMARY; detect(node: ClassDeclaration, decorators: Decorator[]|null): DetectResult<unknown>|undefined { - this.log.push(`${this.name}:detect:${node.name.text}:${decorators !.map(d => d.name)}`); + this.log.push(`${this.name}:detect:${node.name.text}:${decorators!.map(d => d.name)}`); return undefined; } diff --git a/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts index f31e9c003c472..ec9ed520bc68f 100644 --- a/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/private_declarations_analyzer_spec.ts @@ -7,8 +7,8 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {absoluteFrom, AbsoluteFsPath} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {Reference} from '../../../src/ngtsc/imports'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadTestFiles} from '../../../test/helpers/src/mock_file_loading'; @@ -192,6 +192,6 @@ runInEachFileSystem(() => { program: ts.Program, registry: NgccReferencesRegistry, fileName: AbsoluteFsPath, componentName: string) { const declaration = getDeclaration(program, fileName, componentName, ts.isClassDeclaration); - registry.add(null !, new Reference(declaration)); + registry.add(null!, new Reference(declaration)); } }); diff --git a/packages/compiler-cli/ngcc/test/analysis/references_registry_spec.ts b/packages/compiler-cli/ngcc/test/analysis/references_registry_spec.ts index 73e2d542b1bf3..83d56e5a9a8e6 100644 --- a/packages/compiler-cli/ngcc/test/analysis/references_registry_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/references_registry_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; import {absoluteFrom} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {Reference} from '../../../src/ngtsc/imports'; import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator'; import {TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; @@ -44,19 +44,19 @@ runInEachFileSystem(() => { getDeclaration(program, indexPath, 'someFunction', ts.isFunctionDeclaration); const someVariableDecl = getDeclaration(program, indexPath, 'someVariable', ts.isVariableDeclaration); - const testArrayExpression = testArrayDeclaration.initializer !; + const testArrayExpression = testArrayDeclaration.initializer!; const reflectionHost = new TypeScriptReflectionHost(checker); const evaluator = new PartialEvaluator(reflectionHost, checker, /* dependencyTracker */ null); const registry = new NgccReferencesRegistry(reflectionHost); const references = (evaluator.evaluate(testArrayExpression) as any[]).filter(isReference); - registry.add(null !, ...references); + registry.add(null!, ...references); const map = registry.getDeclarationMap(); expect(map.size).toEqual(2); - expect(map.get(someClassDecl.name !) !.node).toBe(someClassDecl); - expect(map.get(someFunctionDecl.name !) !.node).toBe(someFunctionDecl); + expect(map.get(someClassDecl.name!)!.node).toBe(someClassDecl); + expect(map.get(someFunctionDecl.name!)!.node).toBe(someFunctionDecl); expect(map.has(someVariableDecl.name as ts.Identifier)).toBe(false); }); }); diff --git a/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts index b67ab259b8479..53f91a7d46734 100644 --- a/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {absoluteFrom, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; @@ -15,7 +15,6 @@ import {makeTestEntryPointBundle} from '../helpers/utils'; runInEachFileSystem(() => { describe('SwitchMarkerAnalyzer', () => { - let _: typeof absoluteFrom; let TEST_PROGRAM: TestFile[]; @@ -87,14 +86,14 @@ runInEachFileSystem(() => { expect(analysis.has(entrypoint)).toBe(false); expect(analysis.has(a)).toBe(false); expect(analysis.has(b)).toBe(true); - expect(analysis.get(b) !.sourceFile).toBe(b); - expect(analysis.get(b) !.declarations.map(decl => decl.getText())).toEqual([ + expect(analysis.get(b)!.sourceFile).toBe(b); + expect(analysis.get(b)!.declarations.map(decl => decl.getText())).toEqual([ 'factoryB = factory__PRE_R3__' ]); expect(analysis.has(c)).toBe(true); - expect(analysis.get(c) !.sourceFile).toBe(c); - expect(analysis.get(c) !.declarations.map(decl => decl.getText())).toEqual([ + expect(analysis.get(c)!.sourceFile).toBe(c); + expect(analysis.get(c)!.declarations.map(decl => decl.getText())).toEqual([ 'factoryC = factory__PRE_R3__', 'factoryD = factory__PRE_R3__', ]); diff --git a/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts index e0966c775e459..9244efe96da1b 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/commonjs_dependency_host_spec.ts @@ -387,7 +387,7 @@ runInEachFileSystem(() => { reExportsWithoutRequire?: string[]; } - function commonJs(importsPerType: ImportsPerType | string[], exportNames: string[] = []): string { + function commonJs(importsPerType: ImportsPerType|string[], exportNames: string[] = []): string { if (Array.isArray(importsPerType)) { importsPerType = {varDeclaration: importsPerType}; } @@ -414,8 +414,9 @@ runInEachFileSystem(() => { } = importsPerType; // var foo = require('...'); - importsOfTypeVarDeclaration.forEach( - p => { importStatements.push(`var ${pathToVarName(p)} = require('${p}');`); }); + importsOfTypeVarDeclaration.forEach(p => { + importStatements.push(`var ${pathToVarName(p)} = require('${p}');`); + }); // var foo = require('...'), bar = require('...'); importsOfTypeVarDeclarations.forEach(pp => { @@ -424,8 +425,9 @@ runInEachFileSystem(() => { }); // exports.foo = require('...'); - importsOfTypePropAssignment.forEach( - p => { importStatements.push(`exports.${pathToVarName(p)} = require('${p}');`); }); + importsOfTypePropAssignment.forEach(p => { + importStatements.push(`exports.${pathToVarName(p)} = require('${p}');`); + }); // module.exports = {foo: require('...')}; const propAssignments = @@ -434,15 +436,19 @@ runInEachFileSystem(() => { importStatements.push(`module.exports = {${propAssignments}\n};`); // require('...'); - importsOfTypeForSideEffects.forEach(p => { importStatements.push(`require('${p}');`); }); + importsOfTypeForSideEffects.forEach(p => { + importStatements.push(`require('${p}');`); + }); // __export(require('...')); - importsOfTypeReExportsWithEmittedHelper.forEach( - p => { importStatements.push(`__export(require('${p}'));`); }); + importsOfTypeReExportsWithEmittedHelper.forEach(p => { + importStatements.push(`__export(require('${p}'));`); + }); // tslib_1.__exportStar(require('...'), exports); - importsOfTypeReExportsWithImportedHelper.forEach( - p => { importStatements.push(`tslib_1.__exportStar(require('${p}'), exports);`); }); + importsOfTypeReExportsWithImportedHelper.forEach(p => { + importStatements.push(`tslib_1.__exportStar(require('${p}'), exports);`); + }); // var foo = require('...'); // __export(foo); diff --git a/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts index 65ac921e24ade..0fffdbcf9071f 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts @@ -8,7 +8,7 @@ import {DepGraph} from 'dependency-graph'; -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, relativeFrom} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, relativeFrom} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {DependencyInfo} from '../../src/dependencies/dependency_host'; import {DependencyResolver, SortedEntryPointsInfo} from '../../src/dependencies/dependency_resolver'; @@ -254,7 +254,8 @@ runInEachFileSystem(() => { const result = resolver.sortEntryPointsByDependency([first]); expect(result.entryPoints).toEqual([first]); expect(logger.logs.warn).toEqual([[ - `Entry point 'first' contains deep imports into '${_('/deep/one')}'. This is probably not a problem, but may cause the compilation of entry points to be out of order.` + `Entry point 'first' contains deep imports into '${ + _('/deep/one')}'. This is probably not a problem, but may cause the compilation of entry points to be out of order.` ]]); }); @@ -292,14 +293,14 @@ runInEachFileSystem(() => { const result = resolver.sortEntryPointsByDependency([testEntryPoint]); expect(result.entryPoints).toEqual([testEntryPoint]); expect(logger.logs.warn).toEqual([[ - `Entry point 'test-package' contains deep imports into '${_('/project/node_modules/deeper/one')}'. This is probably not a problem, but may cause the compilation of entry points to be out of order.` + `Entry point 'test-package' contains deep imports into '${ + _('/project/node_modules/deeper/one')}'. This is probably not a problem, but may cause the compilation of entry points to be out of order.` ]]); - }); it('should error if the entry point does not have a suitable format', () => { expect(() => resolver.sortEntryPointsByDependency([ - { path: '/first', packageJson: {}, compiledByAngular: true } as EntryPoint + {path: '/first', packageJson: {}, compiledByAngular: true} as EntryPoint ])).toThrowError(`There is no appropriate source code format in '/first' entry-point.`); }); @@ -307,7 +308,8 @@ runInEachFileSystem(() => { resolver = new DependencyResolver(fs, new MockLogger(), config, {esm2015: host}, host); expect(() => resolver.sortEntryPointsByDependency([first])) .toThrowError( - `Could not find a suitable format for computing dependencies of entry-point: '${first.path}'.`); + `Could not find a suitable format for computing dependencies of entry-point: '${ + first.path}'.`); }); it('should capture any dependencies that were ignored', () => { @@ -462,7 +464,7 @@ runInEachFileSystem(() => { deps[entryPointPath].missing.forEach( dep => missing.add(fs.isRooted(dep) ? absoluteFrom(dep) : relativeFrom(dep))); if (deps[entryPointPath].deepImports) { - deps[entryPointPath].deepImports !.forEach(dep => deepImports.add(dep)); + deps[entryPointPath].deepImports!.forEach(dep => deepImports.add(dep)); } return {dependencies, missing, deepImports}; }; diff --git a/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts index eb7986c8f868b..48a96239345fb 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/dts_dependency_host_spec.ts @@ -14,7 +14,6 @@ import {createDependencyInfo} from '../../src/dependencies/dependency_host'; import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; runInEachFileSystem(() => { - describe('DtsDependencyHost', () => { let _: typeof absoluteFrom; let host: DtsDependencyHost; diff --git a/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts index 259e8d5cacb0b..b0c79838d8474 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/esm_dependency_host_spec.ts @@ -16,7 +16,6 @@ import {EsmDependencyHost, hasImportOrReexportStatements, isStringImportOrReexpo import {ModuleResolver} from '../../src/dependencies/module_resolver'; runInEachFileSystem(() => { - describe('EsmDependencyHost', () => { let _: typeof absoluteFrom; let host: EsmDependencyHost; diff --git a/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts index f778abfca3558..b736790fddc48 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/umd_dependency_host_spec.ts @@ -251,8 +251,10 @@ runInEachFileSystem(() => { exportNames.map(e => ` exports.${e.replace(/.+\./, '')} = ${e};`).join('\n'); return ` (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports${commonJsRequires}) : - typeof define === 'function' && define.amd ? define('${moduleName}', ['exports'${amdDeps}], factory) : + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports${ + commonJsRequires}) : + typeof define === 'function' && define.amd ? define('${moduleName}', ['exports'${ + amdDeps}], factory) : (factory(global.${moduleName}${globalParams})); }(this, (function (exports${params}) { 'use strict'; ${exportStatements} diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts index 9d9c873faba53..a8990eb5d1097 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/directory_walker_entry_point_finder_spec.ts @@ -5,8 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, relative} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, relative} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {DependencyResolver} from '../../src/dependencies/dependency_resolver'; import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts index 0bbd51fbfbe71..e8555324b86f8 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/targeted_entry_point_finder_spec.ts @@ -5,8 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, relative} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, relative} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {DependencyResolver} from '../../src/dependencies/dependency_resolver'; import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; @@ -365,7 +365,6 @@ runInEachFileSystem(() => { basePath: AbsoluteFsPath, entryPoints: EntryPoint[]): [string, string][] { return entryPoints.map(x => [relative(basePath, x.package), relative(basePath, x.path)]); } - }); describe('targetNeedsProcessingOrCleaning()', () => { diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts index 996370b9da2a1..840a3e1b45eb8 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts @@ -132,9 +132,12 @@ runInEachFileSystem(() => { fs.resolve(projectDirectory, 'dist-1'), ]); expect(logger.logs.warn).toEqual([ - [`The basePath "${fs.resolve(projectDirectory, 'sub-folder/dist-2')}" computed from baseUrl "${projectDirectory}" and path mapping "sub-folder/dist-2" does not exist in the file-system.\n` + + [`The basePath "${ + fs.resolve(projectDirectory, 'sub-folder/dist-2')}" computed from baseUrl "${ + projectDirectory}" and path mapping "sub-folder/dist-2" does not exist in the file-system.\n` + `It will not be scanned for entry-points.`], - [`The basePath "${fs.resolve(projectDirectory, 'libs')}" computed from baseUrl "${projectDirectory}" and path mapping "libs/*" does not exist in the file-system.\n` + + [`The basePath "${fs.resolve(projectDirectory, 'libs')}" computed from baseUrl "${ + projectDirectory}" and path mapping "libs/*" does not exist in the file-system.\n` + `It will not be scanned for entry-points.`], ]); }); diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts index 1fc5696786aef..87d264ab5a545 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts @@ -51,7 +51,7 @@ describe('ClusterExecutor', () => { describe('(on cluster master)', () => { beforeEach(() => runAsClusterMaster(true)); - it('should log debug info about the executor', async() => { + it('should log debug info about the executor', async () => { const anyFn: () => any = () => undefined; await executor.execute(anyFn, anyFn); @@ -60,7 +60,7 @@ describe('ClusterExecutor', () => { ]); }); - it('should delegate to `ClusterMaster#run()`', async() => { + it('should delegate to `ClusterMaster#run()`', async () => { const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints'); const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); @@ -75,13 +75,13 @@ describe('ClusterExecutor', () => { }); it('should call LockFile.write() and LockFile.remove() if master runner completes successfully', - async() => { + async () => { const anyFn: () => any = () => undefined; await executor.execute(anyFn, anyFn); expect(lockFileLog).toEqual(['write()', 'remove()']); }); - it('should call LockFile.write() and LockFile.remove() if master runner fails', async() => { + it('should call LockFile.write() and LockFile.remove() if master runner fails', async () => { const anyFn: () => any = () => undefined; masterRunSpy.and.returnValue(Promise.reject(new Error('master runner error'))); let error = ''; @@ -94,7 +94,7 @@ describe('ClusterExecutor', () => { expect(lockFileLog).toEqual(['write()', 'remove()']); }); - it('should not call master runner if LockFile.write() fails', async() => { + it('should not call master runner if LockFile.write() fails', async () => { const anyFn: () => any = () => undefined; spyOn(mockLockFile, 'write').and.callFake(() => { lockFileLog.push('write()'); @@ -114,7 +114,7 @@ describe('ClusterExecutor', () => { expect(masterRunSpy).not.toHaveBeenCalled(); }); - it('should fail if LockFile.remove() fails', async() => { + it('should fail if LockFile.remove() fails', async () => { const anyFn: () => any = () => undefined; spyOn(mockLockFile, 'remove').and.callFake(() => { lockFileLog.push('remove()'); @@ -139,14 +139,14 @@ describe('ClusterExecutor', () => { describe('(on cluster worker)', () => { beforeEach(() => runAsClusterMaster(false)); - it('should not log debug info about the executor', async() => { + it('should not log debug info about the executor', async () => { const anyFn: () => any = () => undefined; await executor.execute(anyFn, anyFn); expect(mockLogger.logs.debug).toEqual([]); }); - it('should delegate to `ClusterWorker#run()`', async() => { + it('should delegate to `ClusterWorker#run()`', async () => { const analyzeEntryPointsSpy = jasmine.createSpy('analyzeEntryPoints'); const createCompilerFnSpy = jasmine.createSpy('createCompilerFn'); @@ -160,7 +160,7 @@ describe('ClusterExecutor', () => { expect(createCompilerFnSpy).toHaveBeenCalledWith(jasmine.any(Function)); }); - it('should not call LockFile.write() or LockFile.remove()', async() => { + it('should not call LockFile.write() or LockFile.remove()', async () => { const anyFn: () => any = () => undefined; await executor.execute(anyFn, anyFn); expect(lockFileLog).toEqual([]); diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts index d2cea43299719..9a556f8f42641 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/package_json_updater_spec.ts @@ -39,8 +39,9 @@ runInEachFileSystem(() => { isMaster => describe(`(on cluster ${isMaster ? 'master' : 'worker'})`, () => { beforeEach(() => runAsClusterMaster(isMaster)); - it('should return a `PackageJsonUpdate` instance', - () => { expect(updater.createUpdate()).toEqual(jasmine.any(PackageJsonUpdate)); }); + it('should return a `PackageJsonUpdate` instance', () => { + expect(updater.createUpdate()).toEqual(jasmine.any(PackageJsonUpdate)); + }); it('should wire up the `PackageJsonUpdate` with its `writeChanges()` method', () => { const writeChangesSpy = spyOn(updater, 'writeChanges'); diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts index 89463a3b92a08..b9d92e47d922a 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/worker_spec.ts @@ -60,11 +60,9 @@ describe('ClusterWorker', () => { onTaskCompleted(null as any, TaskProcessingOutcome.Processed, null); expect(processSendSpy).toHaveBeenCalledTimes(1); - expect(processSendSpy).toHaveBeenCalledWith({ - type: 'task-completed', - outcome: TaskProcessingOutcome.Processed, - message: null - }); + expect(processSendSpy) + .toHaveBeenCalledWith( + {type: 'task-completed', outcome: TaskProcessingOutcome.Processed, message: null}); processSendSpy.calls.reset(); @@ -137,7 +135,9 @@ describe('ClusterWorker', () => { } as unknown as Task; let err: string|Error; - compileFnSpy.and.callFake(() => { throw err; }); + compileFnSpy.and.callFake(() => { + throw err; + }); worker.run(); diff --git a/packages/compiler-cli/ngcc/test/execution/helpers.ts b/packages/compiler-cli/ngcc/test/execution/helpers.ts index 0cd3fbd13977a..a72ad23452c90 100644 --- a/packages/compiler-cli/ngcc/test/execution/helpers.ts +++ b/packages/compiler-cli/ngcc/test/execution/helpers.ts @@ -14,8 +14,8 @@ import {EntryPoint} from '../../src/packages/entry_point'; * * NOTE 1: The first task for each entry-point generates typings (which is similar to what happens * in the actual code). - * NOTE 2: The `computeTaskDependencies()` implementation relies on the fact that tasks are sorted in such - * a way that a task can only depend upon earlier tasks (i.e. dependencies always come + * NOTE 2: The `computeTaskDependencies()` implementation relies on the fact that tasks are sorted + * in such a way that a task can only depend upon earlier tasks (i.e. dependencies always come * before dependents in the list of tasks). * To preserve this attribute, you need to ensure that entry-points will only depend on * entry-points with a lower index. Take this into account when defining `entryPointDeps`. @@ -52,7 +52,7 @@ export function createTasksAndGraph( graph.addNode(entryPoint.path); for (let tIdx = 0; tIdx < tasksPerEntryPointCount; tIdx++) { - tasks.push({ entryPoint, formatProperty: `prop-${tIdx}`, processDts: tIdx === 0 } as Task); + tasks.push({entryPoint, formatProperty: `prop-${tIdx}`, processDts: tIdx === 0} as Task); } } diff --git a/packages/compiler-cli/ngcc/test/execution/single_processor_executor_spec.ts b/packages/compiler-cli/ngcc/test/execution/single_processor_executor_spec.ts index b6e7c09db8e9e..a1fdb16e79449 100644 --- a/packages/compiler-cli/ngcc/test/execution/single_processor_executor_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/single_processor_executor_spec.ts @@ -33,11 +33,13 @@ describe('SingleProcessExecutor', () => { executor = new SingleProcessExecutorSync(mockLogger, locker, createTaskCompletedCallback); }); - const noTasks = () => ({ allTasksCompleted: true, getNextTask: () => null } as TaskQueue); + const noTasks = () => ({allTasksCompleted: true, getNextTask: () => null} as TaskQueue); const oneTask = () => { let tasksCount = 1; return <TaskQueue>{ - get allTasksCompleted() { return tasksCount === 0; }, + get allTasksCompleted() { + return tasksCount === 0; + }, getNextTask() { tasksCount--; return {}; @@ -55,7 +57,9 @@ describe('SingleProcessExecutor', () => { }); it('should call LockFile.write() and LockFile.remove() if `analyzeEntryPoints` fails', () => { - const errorFn: () => never = () => { throw new Error('analyze error'); }; + const errorFn: () => never = () => { + throw new Error('analyze error'); + }; const createCompileFn: () => any = () => undefined; let error: string = ''; try { @@ -68,7 +72,9 @@ describe('SingleProcessExecutor', () => { }); it('should call LockFile.write() and LockFile.remove() if `createCompileFn` fails', () => { - const createErrorCompileFn: () => any = () => { throw new Error('compile error'); }; + const createErrorCompileFn: () => any = () => { + throw new Error('compile error'); + }; let error: string = ''; try { executor.execute(oneTask, createErrorCompileFn); @@ -85,7 +91,9 @@ describe('SingleProcessExecutor', () => { throw new Error('LockFile.write() error'); }); - const analyzeFn: () => any = () => { lockFileLog.push('analyzeFn'); }; + const analyzeFn: () => any = () => { + lockFileLog.push('analyzeFn'); + }; const anyFn: () => any = () => undefined; executor = new SingleProcessExecutorSync(mockLogger, locker, createTaskCompletedCallback); let error = ''; diff --git a/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts b/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts index 03d196fe374d5..cb524d970e29d 100644 --- a/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/tasks/queues/parallel_task_queue_spec.ts @@ -77,9 +77,9 @@ describe('ParallelTaskQueue', () => { it('should be `true`, when there are no unprocess or in-progress tasks', () => { const {queue} = createQueue(3); - const task1 = queue.getNextTask() !; - const task2 = queue.getNextTask() !; - const task3 = queue.getNextTask() !; + const task1 = queue.getNextTask()!; + const task2 = queue.getNextTask()!; + const task3 = queue.getNextTask()!; expect(queue.allTasksCompleted).toBe(false); queue.markTaskCompleted(task1); @@ -266,8 +266,8 @@ describe('ParallelTaskQueue', () => { it('should mark a task as completed', () => { const {queue} = createQueue(2); - const task1 = queue.getNextTask() !; - const task2 = queue.getNextTask() !; + const task1 = queue.getNextTask()!; + const task2 = queue.getNextTask()!; expect(queue.allTasksCompleted).toBe(false); queue.markTaskCompleted(task1); @@ -327,7 +327,7 @@ describe('ParallelTaskQueue', () => { processNextTask(queue2); processNextTask(queue2); - const task = queue2.getNextTask() !; + const task = queue2.getNextTask()!; expect(queue2.toString()).toContain(' All tasks completed: false\n'); @@ -344,7 +344,7 @@ describe('ParallelTaskQueue', () => { ' - {entryPoint: entry-point-1, formatProperty: prop-0, processDts: true}\n' + ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n'); - const task1 = queue.getNextTask() !; + const task1 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (2): \n' + @@ -352,7 +352,7 @@ describe('ParallelTaskQueue', () => { ' - {entryPoint: entry-point-2, formatProperty: prop-0, processDts: true}\n'); queue.markTaskCompleted(task1); - const task2 = queue.getNextTask() !; + const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (1): \n' + @@ -367,14 +367,14 @@ describe('ParallelTaskQueue', () => { const {queue} = createQueue(3); expect(queue.toString()).toContain(' In-progress tasks (0): \n'); - const task1 = queue.getNextTask() !; + const task1 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}\n'); queue.markTaskCompleted(task1); - const task2 = queue.getNextTask() !; + const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + diff --git a/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts b/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts index ea53af115e01c..c5cd05c5f4fce 100644 --- a/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/tasks/queues/serial_task_queue_spec.ts @@ -30,12 +30,10 @@ describe('SerialTaskQueue', () => { const tasks: PartiallyOrderedTasks = [] as any; const graph = new DepGraph<EntryPoint>(); for (let i = 0; i < taskCount; i++) { - const entryPoint = { - name: `entry-point-${i}`, - path: `/path/to/entry/point/${i}` - } as EntryPoint; + const entryPoint = {name: `entry-point-${i}`, path: `/path/to/entry/point/${i}`} as + EntryPoint; tasks.push( - { entryPoint: entryPoint, formatProperty: `prop-${i}`, processDts: i % 2 === 0 } as Task); + {entryPoint: entryPoint, formatProperty: `prop-${i}`, processDts: i % 2 === 0} as Task); graph.addNode(entryPoint.path); } const dependencies = computeTaskDependencies(tasks, graph); @@ -140,7 +138,7 @@ describe('SerialTaskQueue', () => { describe('markTaskCompleted()', () => { it('should mark a task as completed, so that the next task can be picked', () => { const {queue} = createQueue(3); - const task = queue.getNextTask() !; + const task = queue.getNextTask()!; expect(() => queue.getNextTask()).toThrow(); @@ -174,7 +172,7 @@ describe('SerialTaskQueue', () => { processNextTask(queue2); processNextTask(queue2); - const task = queue2.getNextTask() !; + const task = queue2.getNextTask()!; expect(queue2.toString()).toContain(' All tasks completed: false\n'); @@ -191,7 +189,7 @@ describe('SerialTaskQueue', () => { ' - {entryPoint: entry-point-1, formatProperty: prop-1, processDts: false}\n' + ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n'); - const task1 = queue.getNextTask() !; + const task1 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (2): \n' + @@ -199,7 +197,7 @@ describe('SerialTaskQueue', () => { ' - {entryPoint: entry-point-2, formatProperty: prop-2, processDts: true}\n'); queue.markTaskCompleted(task1); - const task2 = queue.getNextTask() !; + const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' Unprocessed tasks (1): \n' + @@ -214,14 +212,14 @@ describe('SerialTaskQueue', () => { const {queue} = createQueue(3); expect(queue.toString()).toContain(' In-progress tasks (0): '); - const task1 = queue.getNextTask() !; + const task1 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + ' - {entryPoint: entry-point-0, formatProperty: prop-0, processDts: true}'); queue.markTaskCompleted(task1); - const task2 = queue.getNextTask() !; + const task2 = queue.getNextTask()!; expect(queue.toString()) .toContain( ' In-progress tasks (1): \n' + @@ -253,7 +251,7 @@ describe('SerialTaskQueue', () => { ' In-progress tasks (0): '); processNextTask(queue2); - const task = queue2.getNextTask() !; + const task = queue2.getNextTask()!; expect(queue2.toString()) .toBe( 'SerialTaskQueue\n' + diff --git a/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.ts b/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.ts index c4271216b8eb8..5917df00a5f56 100644 --- a/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.ts +++ b/packages/compiler-cli/ngcc/test/helpers/mock_lock_file.ts @@ -15,10 +15,14 @@ export class MockLockFile implements LockFile { constructor( fs: FileSystem, private log: string[] = [], public path = fs.resolve('/lockfile'), private pid = '1234') {} - write() { this.log.push('write()'); } + write() { + this.log.push('write()'); + } read(): string { this.log.push('read()'); return this.pid; } - remove() { this.log.push('remove()'); } + remove() { + this.log.push('remove()'); + } } diff --git a/packages/compiler-cli/ngcc/test/helpers/mock_logger.ts b/packages/compiler-cli/ngcc/test/helpers/mock_logger.ts index bc686a994f6c7..83e5afe09d23d 100644 --- a/packages/compiler-cli/ngcc/test/helpers/mock_logger.ts +++ b/packages/compiler-cli/ngcc/test/helpers/mock_logger.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {LogLevel, Logger} from '../../src/logging/logger'; +import {Logger, LogLevel} from '../../src/logging/logger'; export class MockLogger implements Logger { constructor(public level = LogLevel.info) {} @@ -17,8 +17,16 @@ export class MockLogger implements Logger { warn: [], error: [], }; - debug(...args: string[]) { this.logs.debug.push(args); } - info(...args: string[]) { this.logs.info.push(args); } - warn(...args: string[]) { this.logs.warn.push(args); } - error(...args: string[]) { this.logs.error.push(args); } + debug(...args: string[]) { + this.logs.debug.push(args); + } + info(...args: string[]) { + this.logs.info.push(args); + } + warn(...args: string[]) { + this.logs.warn.push(args); + } + error(...args: string[]) { + this.logs.error.push(args); + } } \ No newline at end of file diff --git a/packages/compiler-cli/ngcc/test/helpers/utils.ts b/packages/compiler-cli/ngcc/test/helpers/utils.ts index 781be94e3d573..cfd4315b1aada 100644 --- a/packages/compiler-cli/ngcc/test/helpers/utils.ts +++ b/packages/compiler-cli/ngcc/test/helpers/utils.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, NgtscCompilerHost, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, getFileSystem, NgtscCompilerHost} from '../../../src/ngtsc/file_system'; import {TestFile} from '../../../src/ngtsc/file_system/testing'; import {BundleProgram, makeBundleProgram} from '../../src/packages/bundle_program'; import {NgccEntryPointConfig} from '../../src/packages/configuration'; @@ -49,7 +49,12 @@ export function makeTestEntryPointBundle( return { entryPoint, format, - rootDirs: [absoluteFrom('/')], src, dts, isCore, isFlatCore, enableI18nLegacyMessageIdFormat + rootDirs: [absoluteFrom('/')], + src, + dts, + isCore, + isFlatCore, + enableI18nLegacyMessageIdFormat }; } diff --git a/packages/compiler-cli/ngcc/test/host/commonjs_host_import_helper_spec.ts b/packages/compiler-cli/ngcc/test/host/commonjs_host_import_helper_spec.ts index 0d9554a810473..cb3e012f4e2bf 100644 --- a/packages/compiler-cli/ngcc/test/host/commonjs_host_import_helper_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/commonjs_host_import_helper_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; @@ -90,15 +90,15 @@ exports.AliasedDirective$1 = AliasedDirective$1; const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('core.Directive'); + expect(decorator.identifier!.getText()).toEqual('core.Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -111,15 +111,15 @@ exports.AliasedDirective$1 = AliasedDirective$1; const classNode = getDeclaration( bundle.program, TOPLEVEL_DECORATORS_FILE.name, 'AliasedDirective$1', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('core.Directive'); + expect(decorator.identifier!.getText()).toEqual('core.Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); diff --git a/packages/compiler-cli/ngcc/test/host/esm2015_host_import_helper_spec.ts b/packages/compiler-cli/ngcc/test/host/esm2015_host_import_helper_spec.ts index e9baddd052215..554862120e9cf 100644 --- a/packages/compiler-cli/ngcc/test/host/esm2015_host_import_helper_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm2015_host_import_helper_spec.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {ClassMemberKind, Import, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles, loadTsLib} from '../../../test/helpers'; @@ -168,16 +168,16 @@ runInEachFileSystem(() => { const classNode = getDeclaration( bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -189,16 +189,16 @@ runInEachFileSystem(() => { const classNode = getDeclaration( bundle.program, _('/some_directive_ctor_parameters.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -210,16 +210,16 @@ runInEachFileSystem(() => { const classNode = getDeclaration( bundle.program, _('/node_modules/@angular/core/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: './directives'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -234,15 +234,15 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find decorated members on a class when mixing `ctorParameters` and `__decorate`', @@ -254,10 +254,10 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find non decorated properties on a class', () => { @@ -268,11 +268,11 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const instanceProperty = members.find(member => member.name === 'instanceProperty') !; + const instanceProperty = members.find(member => member.name === 'instanceProperty')!; expect(instanceProperty.kind).toEqual(ClassMemberKind.Property); expect(instanceProperty.isStatic).toEqual(false); - expect(ts.isBinaryExpression(instanceProperty.implementation !)).toEqual(true); - expect(instanceProperty.value !.getText()).toEqual(`'instance'`); + expect(ts.isBinaryExpression(instanceProperty.implementation!)).toEqual(true); + expect(instanceProperty.value!.getText()).toEqual(`'instance'`); }); it('should find static methods on a class', () => { @@ -283,10 +283,10 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticMethod = members.find(member => member.name === 'staticMethod') !; + const staticMethod = members.find(member => member.name === 'staticMethod')!; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); - expect(ts.isMethodDeclaration(staticMethod.implementation !)).toEqual(true); + expect(ts.isMethodDeclaration(staticMethod.implementation!)).toEqual(true); }); it('should find static properties on a class', () => { @@ -297,11 +297,11 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should find static properties on a class that has an intermediate variable assignment', @@ -313,11 +313,11 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should support decorators being used inside @angular/core', () => { @@ -329,10 +329,10 @@ runInEachFileSystem(() => { isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); }); @@ -346,10 +346,10 @@ runInEachFileSystem(() => { const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', 'String', @@ -366,20 +366,20 @@ runInEachFileSystem(() => { const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, ]); - const decorators = parameters ![2].decorators !; + const decorators = parameters![2].decorators!; expect(decorators.length).toEqual(1); expect(decorators[0].name).toBe('Inject'); - expect(decorators[0].import !.from).toBe('@angular/core'); - expect(decorators[0].import !.name).toBe('Inject'); + expect(decorators[0].import!.from).toBe('@angular/core'); + expect(decorators[0].import!.name).toBe('Inject'); }); }); @@ -390,8 +390,8 @@ runInEachFileSystem(() => { const classNode = getDeclaration( bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const ctrDecorators = host.getConstructorParameters(classNode) !; - const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference !as{ + const ctrDecorators = host.getConstructorParameters(classNode)!; + const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference! as { local: true, expression: ts.Identifier, defaultImportStatement: null, @@ -401,8 +401,8 @@ runInEachFileSystem(() => { bundle.program, _('/some_directive.js'), 'ViewContainerRef', ts.isClassDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfViewContainerRef); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe(null); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe(null); }); it('should return the declaration of an externally defined identifier', () => { @@ -411,8 +411,8 @@ runInEachFileSystem(() => { const classNode = getDeclaration( bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const decoratorNode = classDecorators[0].node !; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const decoratorNode = classDecorators[0].node!; const identifierOfDirective = ts.isCallExpression(decoratorNode) && ts.isIdentifier(decoratorNode.expression) ? decoratorNode.expression : @@ -421,10 +421,10 @@ runInEachFileSystem(() => { const expectedDeclarationNode = getDeclaration( bundle.program, _('/node_modules/@angular/core/index.d.ts'), 'Directive', isNamedVariableDeclaration); - const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective !); + const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective!); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); }); @@ -435,13 +435,13 @@ runInEachFileSystem(() => { const ngModuleRef = findVariableDeclaration( getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'HttpClientXsrfModule_1'); - const value = host.getVariableValue(ngModuleRef !); + const value = host.getVariableValue(ngModuleRef!); expect(value).not.toBe(null); if (!value || !ts.isClassExpression(value)) { throw new Error( `Expected value to be a class expression: ${value && value.getText()}.`); } - expect(value.name !.text).toBe('HttpClientXsrfModule'); + expect(value.name!.text).toBe('HttpClientXsrfModule'); }); it('should return null if the variable has no assignment', () => { @@ -449,7 +449,7 @@ runInEachFileSystem(() => { const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); const missingValue = findVariableDeclaration( getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'missingValue'); - const value = host.getVariableValue(missingValue !); + const value = host.getVariableValue(missingValue!); expect(value).toBe(null); }); @@ -458,7 +458,7 @@ runInEachFileSystem(() => { const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); const nonDecoratedVar = findVariableDeclaration( getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'nonDecoratedVar'); - const value = host.getVariableValue(nonDecoratedVar !); + const value = host.getVariableValue(nonDecoratedVar!); expect(value).toBe(null); }); }); @@ -468,7 +468,7 @@ runInEachFileSystem(() => { const bundle = makeTestBundleProgram(_('/ngmodule.js')); const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle); const classSymbol = - host.findClassSymbols(bundle.program.getSourceFile(_('/ngmodule.js')) !)[0]; + host.findClassSymbols(bundle.program.getSourceFile(_('/ngmodule.js'))!)[0]; const endOfClass = host.getEndOfClass(classSymbol); expect(endOfClass.getText()) .toMatch( @@ -479,7 +479,7 @@ runInEachFileSystem(() => { }); function findVariableDeclaration( - node: ts.Node | undefined, variableName: string): ts.VariableDeclaration|undefined { + node: ts.Node|undefined, variableName: string): ts.VariableDeclaration|undefined { if (!node) { return; } diff --git a/packages/compiler-cli/ngcc/test/host/esm5_host_import_helper_spec.ts b/packages/compiler-cli/ngcc/test/host/esm5_host_import_helper_spec.ts index 16c6deb129b54..6ad45d394aaf8 100644 --- a/packages/compiler-cli/ngcc/test/host/esm5_host_import_helper_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm5_host_import_helper_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {ClassMemberKind, isNamedFunctionDeclaration, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadFakeCore, loadTestFiles, loadTsLib} from '../../../test/helpers'; @@ -227,19 +227,18 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); - }); it('should find the decorators on a minified class', () => { @@ -248,19 +247,18 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_minified_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); - }); it('should find the decorators on an aliased class', () => { @@ -269,16 +267,16 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_aliased_directive.js'), 'AliasedDirective$1', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -290,16 +288,16 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_directive_ctor_parameters.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -311,16 +309,16 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/node_modules/@angular/core/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('Directive'); + expect(decorator.identifier!.getText()).toEqual('Directive'); expect(decorator.import).toEqual({name: 'Directive', from: './directives'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -333,13 +331,12 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_minified_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const innerNode = - getIifeBody(classNode) !.statements.find(isNamedFunctionDeclaration) !; + const innerNode = getIifeBody(classNode)!.statements.find(isNamedFunctionDeclaration)!; const classSymbol = host.getClassSymbol(classNode); expect(classSymbol).toBeDefined(); - expect(classSymbol !.declaration.valueDeclaration).toBe(classNode); - expect(classSymbol !.implementation.valueDeclaration).toBe(innerNode); + expect(classSymbol!.declaration.valueDeclaration).toBe(classNode); + expect(classSymbol!.implementation.valueDeclaration).toBe(innerNode); }); }); @@ -352,15 +349,15 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find decorated members on a class when mixing `ctorParameters` and `__decorate`', @@ -372,10 +369,10 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); it('should find non decorated properties on a class', () => { @@ -386,11 +383,11 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const instanceProperty = members.find(member => member.name === 'instanceProperty') !; + const instanceProperty = members.find(member => member.name === 'instanceProperty')!; expect(instanceProperty.kind).toEqual(ClassMemberKind.Property); expect(instanceProperty.isStatic).toEqual(false); - expect(ts.isBinaryExpression(instanceProperty.implementation !)).toEqual(true); - expect(instanceProperty.value !.getText()).toEqual(`'instance'`); + expect(ts.isBinaryExpression(instanceProperty.implementation!)).toEqual(true); + expect(instanceProperty.value!.getText()).toEqual(`'instance'`); }); it('should find static methods on a class', () => { @@ -401,10 +398,10 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticMethod = members.find(member => member.name === 'staticMethod') !; + const staticMethod = members.find(member => member.name === 'staticMethod')!; expect(staticMethod.kind).toEqual(ClassMemberKind.Method); expect(staticMethod.isStatic).toEqual(true); - expect(ts.isFunctionExpression(staticMethod.implementation !)).toEqual(true); + expect(ts.isFunctionExpression(staticMethod.implementation!)).toEqual(true); }); it('should find static properties on a class', () => { @@ -415,11 +412,11 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const staticProperty = members.find(member => member.name === 'staticProperty') !; + const staticProperty = members.find(member => member.name === 'staticProperty')!; expect(staticProperty.kind).toEqual(ClassMemberKind.Property); expect(staticProperty.isStatic).toEqual(true); - expect(ts.isPropertyAccessExpression(staticProperty.implementation !)).toEqual(true); - expect(staticProperty.value !.getText()).toEqual(`'static'`); + expect(ts.isPropertyAccessExpression(staticProperty.implementation!)).toEqual(true); + expect(staticProperty.value!.getText()).toEqual(`'static'`); }); it('should support decorators being used inside @angular/core', () => { @@ -431,10 +428,10 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); }); describe('getConstructorParameters', () => { @@ -447,10 +444,10 @@ export { AliasedDirective$1 }; const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', 'String', @@ -467,10 +464,10 @@ export { AliasedDirective$1 }; const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, @@ -485,7 +482,7 @@ export { AliasedDirective$1 }; bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); const parameters = host.getConstructorParameters(classNode); - const decorators = parameters ![2].decorators !; + const decorators = parameters![2].decorators!; expect(decorators.length).toEqual(1); expect(decorators[0].import).toEqual({name: 'Inject', from: '@angular/core'}); @@ -522,7 +519,7 @@ export { AliasedDirective$1 }; const ngModuleDecorators = ngModuleClasses.map(s => host.getDecoratorsOfSymbol(s)); expect(ngModuleClasses.length).toEqual(1); - expect(ngModuleDecorators[0] !.map(d => d.name)).toEqual(['NgModule']); + expect(ngModuleDecorators[0]!.map(d => d.name)).toEqual(['NgModule']); const someDirectiveFile = getSourceFileOrError(bundle.program, _('/some_directive.js')); const someDirectiveClasses = host.findClassSymbols(someDirectiveFile); @@ -532,7 +529,7 @@ export { AliasedDirective$1 }; expect(someDirectiveDecorators.length).toEqual(3); expect(someDirectiveDecorators[0]).toBe(null); expect(someDirectiveDecorators[1]).toBe(null); - expect(someDirectiveDecorators[2] !.map(d => d.name)).toEqual(['Directive']); + expect(someDirectiveDecorators[2]!.map(d => d.name)).toEqual(['Directive']); }); }); @@ -543,8 +540,8 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const ctrDecorators = host.getConstructorParameters(classNode) !; - const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference !as{ + const ctrDecorators = host.getConstructorParameters(classNode)!; + const identifierOfViewContainerRef = (ctrDecorators[0].typeValueReference! as { local: true, expression: ts.Identifier, defaultImportStatement: null, @@ -555,8 +552,8 @@ export { AliasedDirective$1 }; isNamedVariableDeclaration); const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfViewContainerRef); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe(null); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe(null); }); it('should return the declaration of an externally defined identifier', () => { @@ -565,8 +562,8 @@ export { AliasedDirective$1 }; const classNode = getDeclaration( bundle.program, _('/some_directive.js'), 'SomeDirective', isNamedVariableDeclaration); - const classDecorators = host.getDecoratorsOfDeclaration(classNode) !; - const decoratorNode = classDecorators[0].node !; + const classDecorators = host.getDecoratorsOfDeclaration(classNode)!; + const decoratorNode = classDecorators[0].node!; const identifierOfDirective = ts.isCallExpression(decoratorNode) && ts.isIdentifier(decoratorNode.expression) ? @@ -576,10 +573,10 @@ export { AliasedDirective$1 }; const expectedDeclarationNode = getDeclaration( bundle.program, _('/node_modules/@angular/core/index.d.ts'), 'Directive', isNamedVariableDeclaration); - const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective !); + const actualDeclaration = host.getDeclarationOfIdentifier(identifierOfDirective!); expect(actualDeclaration).not.toBe(null); - expect(actualDeclaration !.node).toBe(expectedDeclarationNode); - expect(actualDeclaration !.viaModule).toBe('@angular/core'); + expect(actualDeclaration!.node).toBe(expectedDeclarationNode); + expect(actualDeclaration!.viaModule).toBe('@angular/core'); }); it('should find the "actual" declaration of an aliased variable identifier', () => { @@ -589,9 +586,9 @@ export { AliasedDirective$1 }; getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'HttpClientXsrfModule_1', isNgModulePropertyAssignment); - const declaration = host.getDeclarationOfIdentifier(ngModuleRef !); + const declaration = host.getDeclarationOfIdentifier(ngModuleRef!); expect(declaration).not.toBe(null); - expect(declaration !.node !.getText()).toContain('function HttpClientXsrfModule()'); + expect(declaration!.node!.getText()).toContain('function HttpClientXsrfModule()'); }); }); describe('getVariableValue', () => { @@ -601,7 +598,7 @@ export { AliasedDirective$1 }; const ngModuleRef = findVariableDeclaration( getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'HttpClientXsrfModule_1'); - const value = host.getVariableValue(ngModuleRef !); + const value = host.getVariableValue(ngModuleRef!); expect(value).not.toBe(null); if (!value || !ts.isFunctionDeclaration(value.parent)) { throw new Error( @@ -615,7 +612,7 @@ export { AliasedDirective$1 }; const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); const missingValue = findVariableDeclaration( getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'missingValue'); - const value = host.getVariableValue(missingValue !); + const value = host.getVariableValue(missingValue!); expect(value).toBe(null); }); @@ -624,7 +621,7 @@ export { AliasedDirective$1 }; const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); const nonDecoratedVar = findVariableDeclaration( getSourceFileOrError(bundle.program, _('/ngmodule.js')), 'nonDecoratedVar'); - const value = host.getVariableValue(nonDecoratedVar !); + const value = host.getVariableValue(nonDecoratedVar!); expect(value).toBe(null); }); }); @@ -634,7 +631,7 @@ export { AliasedDirective$1 }; const bundle = makeTestBundleProgram(_('/ngmodule.js')); const host = new Esm5ReflectionHost(new MockLogger(), false, bundle); const classSymbol = - host.findClassSymbols(bundle.program.getSourceFile(_('/ngmodule.js')) !)[0]; + host.findClassSymbols(bundle.program.getSourceFile(_('/ngmodule.js'))!)[0]; const endOfClass = host.getEndOfClass(classSymbol); expect(endOfClass.getText()) .toMatch( @@ -644,7 +641,7 @@ export { AliasedDirective$1 }; }); function findVariableDeclaration( - node: ts.Node | undefined, variableName: string): ts.VariableDeclaration|undefined { + node: ts.Node|undefined, variableName: string): ts.VariableDeclaration|undefined { if (!node) { return; } @@ -656,7 +653,7 @@ export { AliasedDirective$1 }; }); function findIdentifier( - node: ts.Node | undefined, identifierName: string, + node: ts.Node|undefined, identifierName: string, requireFn: (node: ts.Identifier) => boolean): ts.Identifier|undefined { if (!node) { return undefined; diff --git a/packages/compiler-cli/ngcc/test/host/umd_host_import_helper_spec.ts b/packages/compiler-cli/ngcc/test/host/umd_host_import_helper_spec.ts index 35929b4f7106e..9be9a1f3a2129 100644 --- a/packages/compiler-cli/ngcc/test/host/umd_host_import_helper_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/umd_host_import_helper_spec.ts @@ -7,7 +7,7 @@ */ import {absoluteFrom} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {ClassMemberKind, isNamedVariableDeclaration} from '../../../src/ngtsc/reflection'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {loadTestFiles} from '../../../test/helpers'; @@ -81,16 +81,16 @@ runInEachFileSystem(() => { const host = new UmdReflectionHost(new MockLogger(), false, bundle); const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('core.Directive'); + expect(decorator.identifier!.getText()).toEqual('core.Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -102,16 +102,16 @@ runInEachFileSystem(() => { const classNode = getDeclaration( bundle.program, SOME_DIRECTIVE_FILE.name, 'AliasedDirective$1', isNamedVariableDeclaration); - const decorators = host.getDecoratorsOfDeclaration(classNode) !; + const decorators = host.getDecoratorsOfDeclaration(classNode)!; expect(decorators).toBeDefined(); expect(decorators.length).toEqual(1); const decorator = decorators[0]; expect(decorator.name).toEqual('Directive'); - expect(decorator.identifier !.getText()).toEqual('core.Directive'); + expect(decorator.identifier!.getText()).toEqual('core.Directive'); expect(decorator.import).toEqual({name: 'Directive', from: '@angular/core'}); - expect(decorator.args !.map(arg => arg.getText())).toEqual([ + expect(decorator.args!.map(arg => arg.getText())).toEqual([ '{ selector: \'[someDirective]\' }', ]); }); @@ -126,15 +126,15 @@ runInEachFileSystem(() => { bundle.program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', isNamedVariableDeclaration); const members = host.getMembersOfClass(classNode); - const input1 = members.find(member => member.name === 'input1') !; + const input1 = members.find(member => member.name === 'input1')!; expect(input1.kind).toEqual(ClassMemberKind.Property); expect(input1.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); - const input2 = members.find(member => member.name === 'input2') !; + const input2 = members.find(member => member.name === 'input2')!; expect(input2.kind).toEqual(ClassMemberKind.Property); expect(input2.isStatic).toEqual(false); - expect(input1.decorators !.map(d => d.name)).toEqual(['Input']); + expect(input1.decorators!.map(d => d.name)).toEqual(['Input']); }); describe('getConstructorParameters', () => { @@ -148,10 +148,10 @@ runInEachFileSystem(() => { const parameters = host.getConstructorParameters(classNode); expect(parameters).toBeDefined(); - expect(parameters !.map(parameter => parameter.name)).toEqual([ + expect(parameters!.map(parameter => parameter.name)).toEqual([ '_viewContainer', '_template', 'injected' ]); - expectTypeValueReferencesForParameters(parameters !, [ + expectTypeValueReferencesForParameters(parameters!, [ 'ViewContainerRef', 'TemplateRef', null, diff --git a/packages/compiler-cli/ngcc/test/host/util.ts b/packages/compiler-cli/ngcc/test/host/util.ts index 7e6a9de5ee1c0..1214e90cf4246 100644 --- a/packages/compiler-cli/ngcc/test/host/util.ts +++ b/packages/compiler-cli/ngcc/test/host/util.ts @@ -14,9 +14,8 @@ import {CtorParameter} from '../../../src/ngtsc/reflection'; * names. */ export function expectTypeValueReferencesForParameters( - parameters: CtorParameter[], expectedParams: (string | null)[], - fromModule: string | null = null) { - parameters !.forEach((param, idx) => { + parameters: CtorParameter[], expectedParams: (string|null)[], fromModule: string|null = null) { + parameters!.forEach((param, idx) => { const expected = expectedParams[idx]; if (expected !== null) { if (param.typeValueReference === null) { @@ -32,7 +31,7 @@ export function expectTypeValueReferencesForParameters( expect(param.typeValueReference.expression.text).toEqual(expected); } } else if (param.typeValueReference !== null) { - expect(param.typeValueReference.moduleName).toBe(fromModule !); + expect(param.typeValueReference.moduleName).toBe(fromModule!); expect(param.typeValueReference.name).toBe(expected); } } diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 4cc67792d5820..8092d757b73b3 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -8,8 +8,9 @@ /// <reference types="node" /> import * as os from 'os'; -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem, join} from '../../../src/ngtsc/file_system'; -import {Folder, MockFileSystem, TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; + +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, join} from '../../../src/ngtsc/file_system'; +import {Folder, MockFileSystem, runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {loadStandardTestFiles, loadTestFiles} from '../../../test/helpers'; import {getLockFilePath} from '../../src/locking/lock_file'; import {mainNgcc} from '../../src/main'; @@ -19,6 +20,7 @@ import {EntryPointManifestFile} from '../../src/packages/entry_point_manifest'; import {Transformer} from '../../src/packages/transformer'; import {DirectPackageJsonUpdater, PackageJsonUpdater} from '../../src/writing/package_json_updater'; import {MockLogger} from '../helpers/mock_logger'; + import {compileIntoApf, compileIntoFlatEs5Package} from './util'; const testFiles = loadStandardTestFiles({fakeCore: false, rxjs: true}); @@ -145,7 +147,8 @@ runInEachFileSystem(() => { }); ['esm5', 'esm2015'].forEach(target => { - it(`should be able to process spread operator inside objects for ${target} format (imported helpers)`, + it(`should be able to process spread operator inside objects for ${ + target} format (imported helpers)`, () => { compileIntoApf( 'test-package', { @@ -184,7 +187,8 @@ runInEachFileSystem(() => { expect(jsContents).toContain('ngcc0.ɵɵclassProp("a", true)("b", true)("c", false)'); }); - it(`should be able to process emitted spread operator inside objects for ${target} format (emitted helpers)`, + it(`should be able to process emitted spread operator inside objects for ${ + target} format (emitted helpers)`, () => { compileIntoApf( 'test-package', { @@ -326,7 +330,7 @@ runInEachFileSystem(() => { }); const before = fs.readFile(_(`/node_modules/test-package/index.js`)); - const originalProp = /ɵprov[^;]+/.exec(before) ![0]; + const originalProp = /ɵprov[^;]+/.exec(before)![0]; mainNgcc({ basePath: '/node_modules', targetEntryPointPath: 'test-package', @@ -496,7 +500,7 @@ runInEachFileSystem(() => { }); describe('in async mode', () => { - it('should run ngcc without errors for fesm2015', async() => { + it('should run ngcc without errors for fesm2015', async () => { const promise = mainNgcc({ basePath: '/node_modules', propertiesToConsider: ['fesm2015'], @@ -507,7 +511,7 @@ runInEachFileSystem(() => { await promise; }); - it('should reject, if some of the entry-points are unprocessable', async() => { + it('should reject, if some of the entry-points are unprocessable', async () => { const createEntryPoint = (name: string, prop: EntryPointJsonProperty): TestFile[] => { return [ { @@ -541,7 +545,7 @@ runInEachFileSystem(() => { ` - ${_('/dist/unprocessable-3')}`))); }); - it('should reject, if an error happens during processing', async() => { + it('should reject, if an error happens during processing', async () => { spyOn(Transformer.prototype, 'transform').and.throwError('Test error.'); const promise = mainNgcc({ @@ -651,7 +655,8 @@ runInEachFileSystem(() => { markPropertiesAsProcessed('@angular/common/http/testing', SUPPORTED_FORMAT_PROPERTIES); mainNgcc({ basePath: '/node_modules', - targetEntryPointPath: '@angular/common/http/testing', logger, + targetEntryPointPath: '@angular/common/http/testing', + logger, }); expect(logger.logs.debug).toContain([ 'The target entry-point has already been processed' @@ -665,7 +670,8 @@ runInEachFileSystem(() => { mainNgcc({ basePath: '/node_modules', targetEntryPointPath: '@angular/common/http/testing', - propertiesToConsider: ['fesm2015', 'esm5', 'esm2015'], logger, + propertiesToConsider: ['fesm2015', 'esm5', 'esm2015'], + logger, }); expect(logger.logs.debug).not.toContain([ 'The target entry-point has already been processed' @@ -682,7 +688,8 @@ runInEachFileSystem(() => { basePath: '/node_modules', targetEntryPointPath: '@angular/common/http/testing', propertiesToConsider: ['esm5', 'esm2015'], - compileAllFormats: false, logger, + compileAllFormats: false, + logger, }); expect(logger.logs.debug).not.toContain([ @@ -699,7 +706,8 @@ runInEachFileSystem(() => { targetEntryPointPath: '@angular/common/http/testing', // Simulate a property that does not exist on the package.json and will be ignored. propertiesToConsider: ['missing', 'esm2015', 'esm5'], - compileAllFormats: false, logger, + compileAllFormats: false, + logger, }); expect(logger.logs.debug).toContain([ @@ -717,7 +725,8 @@ runInEachFileSystem(() => { targetEntryPointPath: '@angular/common/http/testing', // Simulate a property that does not exist on the package.json and will be ignored. propertiesToConsider: ['missing', 'esm2015', 'esm5'], - compileAllFormats: false, logger, + compileAllFormats: false, + logger, }); expect(logger.logs.debug).toContain([ @@ -752,7 +761,7 @@ runInEachFileSystem(() => { // Now hack the files to look like it was processed by an outdated version of ngcc const packageJson = loadPackage('test-package', _('/node_modules')); - packageJson.__processed_by_ivy_ngcc__ !.typings = '8.0.0'; + packageJson.__processed_by_ivy_ngcc__!.typings = '8.0.0'; packageJson.main_ivy_ngcc = '__ivy_ngcc__/main.js'; fs.writeFile(_('/node_modules/test-package/package.json'), JSON.stringify(packageJson)); fs.writeFile(_('/node_modules/test-package/x.js'), 'processed content'); @@ -838,7 +847,8 @@ runInEachFileSystem(() => { // `fesm2015` and `es2015` map to the same file: `./fesm2015/common.js` mainNgcc({ basePath: '/node_modules/@angular/common', - propertiesToConsider: ['fesm2015'], logger, + propertiesToConsider: ['fesm2015'], + logger, }); expect(logs).not.toContain(['Skipping @angular/common : es2015 (already compiled).']); @@ -851,7 +861,8 @@ runInEachFileSystem(() => { // Now, compiling `es2015` should be a no-op. mainNgcc({ basePath: '/node_modules/@angular/common', - propertiesToConsider: ['es2015'], logger, + propertiesToConsider: ['es2015'], + logger, }); expect(logs).toContain(['Skipping @angular/common : es2015 (already compiled).']); @@ -997,21 +1008,21 @@ runInEachFileSystem(() => { expectNotToHaveProp(pkg, 'esm5_ivy_ngcc'); expectToHaveProp(pkg, 'fesm2015_ivy_ngcc'); expectNotToHaveProp(pkg, 'fesm5_ivy_ngcc'); - expectToHaveProp(pkg.__processed_by_ivy_ngcc__ !, 'fesm2015'); + expectToHaveProp(pkg.__processed_by_ivy_ngcc__!, 'fesm2015'); // Process `fesm5` and update `package.json`. pkg = processFormatAndUpdatePackageJson('fesm5'); expectNotToHaveProp(pkg, 'esm5_ivy_ngcc'); expectToHaveProp(pkg, 'fesm2015_ivy_ngcc'); expectToHaveProp(pkg, 'fesm5_ivy_ngcc'); - expectToHaveProp(pkg.__processed_by_ivy_ngcc__ !, 'fesm5'); + expectToHaveProp(pkg.__processed_by_ivy_ngcc__!, 'fesm5'); // Process `esm5` and update `package.json`. pkg = processFormatAndUpdatePackageJson('esm5'); expectToHaveProp(pkg, 'esm5_ivy_ngcc'); expectToHaveProp(pkg, 'fesm2015_ivy_ngcc'); expectToHaveProp(pkg, 'fesm5_ivy_ngcc'); - expectToHaveProp(pkg.__processed_by_ivy_ngcc__ !, 'esm5'); + expectToHaveProp(pkg.__processed_by_ivy_ngcc__!, 'esm5'); // Ensure the properties are in deterministic order (regardless of processing order). const pkgKeys = stringifyKeys(pkg); @@ -1026,7 +1037,7 @@ runInEachFileSystem(() => { // For example: // - `fesm2015` <=> `es2015` // - `fesm5` <=> `module` - expect(stringifyKeys(pkg.__processed_by_ivy_ngcc__ !)) + expect(stringifyKeys(pkg.__processed_by_ivy_ngcc__!)) .toBe('|es2015|esm5|fesm2015|fesm5|module|typings|'); // Helpers @@ -1034,7 +1045,8 @@ runInEachFileSystem(() => { expect(obj.hasOwnProperty(prop)) .toBe( false, - `Expected object not to have property '${prop}': ${JSON.stringify(obj, null, 2)}`); + `Expected object not to have property '${prop}': ${ + JSON.stringify(obj, null, 2)}`); } function expectToHaveProp(obj: object, prop: string) { @@ -1053,7 +1065,9 @@ runInEachFileSystem(() => { return loadPackage('@angular/core'); } - function stringifyKeys(obj: object) { return `|${Object.keys(obj).join('|')}|`; } + function stringifyKeys(obj: object) { + return `|${Object.keys(obj).join('|')}|`; + } }); }); @@ -1206,7 +1220,8 @@ runInEachFileSystem(() => { mainNgcc({ basePath: '/node_modules', propertiesToConsider: ['es2015'], - errorOnFailedEntryPoint: false, logger, + errorOnFailedEntryPoint: false, + logger, }); expect(logger.logs.error.length).toEqual(1); const message = logger.logs.error[0][0]; @@ -1236,7 +1251,8 @@ runInEachFileSystem(() => { const logger = new MockLogger(); mainNgcc({ basePath: '/node_modules', - propertiesToConsider: ['esm2015'], logger, + propertiesToConsider: ['esm2015'], + logger, }); expect(logger.logs.info).toContain(['Compiling @angular/common/http : esm2015 as esm2015']); }); @@ -1281,7 +1297,8 @@ runInEachFileSystem(() => { mainNgcc({ basePath: '/dist', propertiesToConsider: ['es2015'], - tsConfigPath: _('/tsconfig.app.json'), logger + tsConfigPath: _('/tsconfig.app.json'), + logger }); expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', @@ -1316,7 +1333,8 @@ runInEachFileSystem(() => { mainNgcc({ basePath: '/node_modules', propertiesToConsider: ['es2015'], - pathMappings: {paths: {'*': ['dist/*']}, baseUrl: '/'}, logger + pathMappings: {paths: {'*': ['dist/*']}, baseUrl: '/'}, + logger }); expect(loadPackage('@angular/core').__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', @@ -1356,7 +1374,8 @@ runInEachFileSystem(() => { mainNgcc({ basePath: '/dist', propertiesToConsider: ['es2015'], - tsConfigPath: null, logger, + tsConfigPath: null, + logger, }); expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ es2015: '0.0.0-PLACEHOLDER', @@ -1821,7 +1840,7 @@ runInEachFileSystem(() => { expect(jsContents).toContain('exports.ɵngExportɵFooModuleɵFoo = ɵngcc1.Foo;'); expect(dtsContents) .toContain(`export {Foo as ɵngExportɵFooModuleɵFoo} from './directive';`); - expect(dtsContents.match(/ɵngExportɵFooModuleɵFoo/g) !.length).toBe(1); + expect(dtsContents.match(/ɵngExportɵFooModuleɵFoo/g)!.length).toBe(1); expect(dtsContents).not.toContain(`ɵngExportɵFooModuleɵLocalDir`); }); }); diff --git a/packages/compiler-cli/ngcc/test/integration/util.ts b/packages/compiler-cli/ngcc/test/integration/util.ts index e0880074831f5..735b33d13bc12 100644 --- a/packages/compiler-cli/ngcc/test/integration/util.ts +++ b/packages/compiler-cli/ngcc/test/integration/util.ts @@ -234,11 +234,21 @@ class MockCompilerHost implements ts.CompilerHost { this.fs.writeFile(this.fs.resolve(fileName), data); } - getCurrentDirectory(): string { return this.fs.pwd(); } - getCanonicalFileName(fileName: string): string { return fileName; } - useCaseSensitiveFileNames(): boolean { return true; } - getNewLine(): string { return '\n'; } - fileExists(fileName: string): boolean { return this.fs.exists(this.fs.resolve(fileName)); } + getCurrentDirectory(): string { + return this.fs.pwd(); + } + getCanonicalFileName(fileName: string): string { + return fileName; + } + useCaseSensitiveFileNames(): boolean { + return true; + } + getNewLine(): string { + return '\n'; + } + fileExists(fileName: string): boolean { + return this.fs.exists(this.fs.resolve(fileName)); + } readFile(fileName: string): string|undefined { const abs = this.fs.resolve(fileName); return this.fs.exists(abs) ? this.fs.readFile(abs) : undefined; diff --git a/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts b/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts index 0922c92f358ff..d9a045758a206 100644 --- a/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts @@ -14,13 +14,13 @@ import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { describe('AsyncLocker', () => { describe('lock()', () => { - it('should guard the `fn()` with calls to `write()` and `remove()`', async() => { + it('should guard the `fn()` with calls to `write()` and `remove()`', async () => { const fs = getFileSystem(); const log: string[] = []; const lockFile = new MockLockFile(fs, log); const locker = new AsyncLocker(lockFile, new MockLogger(), 100, 10); - await locker.lock(async() => { + await locker.lock(async () => { log.push('fn() - before'); // This promise forces node to do a tick in this function, ensuring that we are truly // testing an async scenario. @@ -31,7 +31,7 @@ runInEachFileSystem(() => { }); it('should guard the `fn()` with calls to `write()` and `remove()`, even if it throws', - async() => { + async () => { let error: string = ''; const fs = getFileSystem(); const log: string[] = []; @@ -39,7 +39,7 @@ runInEachFileSystem(() => { const locker = new AsyncLocker(lockFile, new MockLogger(), 100, 10); try { - await locker.lock(async() => { + await locker.lock(async () => { log.push('fn()'); throw new Error('ERROR'); }); @@ -50,7 +50,7 @@ runInEachFileSystem(() => { expect(log).toEqual(['write()', 'fn()', 'remove()']); }); - it('should retry if another process is locking', async() => { + it('should retry if another process is locking', async () => { const fs = getFileSystem(); const log: string[] = []; const lockFile = new MockLockFile(fs, log); @@ -69,7 +69,7 @@ runInEachFileSystem(() => { return lockFileContents; }); - const promise = locker.lock(async() => log.push('fn()')); + const promise = locker.lock(async () => log.push('fn()')); // The lock is now waiting on the lock-file becoming free, so no `fn()` in the log. expect(log).toEqual(['write()', 'read() => 188']); expect(logger.logs.info).toEqual([[ @@ -83,7 +83,7 @@ runInEachFileSystem(() => { expect(log).toEqual(['write()', 'read() => 188', 'write()', 'fn()', 'remove()']); }); - it('should extend the retry timeout if the other process locking the file changes', async() => { + it('should extend the retry timeout if the other process locking the file changes', async () => { const fs = getFileSystem(); const log: string[] = []; const lockFile = new MockLockFile(fs, log); @@ -102,7 +102,7 @@ runInEachFileSystem(() => { return lockFileContents; }); - const promise = locker.lock(async() => log.push('fn()')); + const promise = locker.lock(async () => log.push('fn()')); // The lock is now waiting on the lock-file becoming free, so no `fn()` in the log. expect(log).toEqual(['write()', 'read() => 188']); expect(logger.logs.info).toEqual([[ @@ -132,7 +132,7 @@ runInEachFileSystem(() => { }); it('should error if another process does not release the lock-file before this times out', - async() => { + async () => { const fs = getFileSystem(); const log: string[] = []; const lockFile = new MockLockFile(fs, log); @@ -151,7 +151,7 @@ runInEachFileSystem(() => { return lockFileContents; }); - const promise = locker.lock(async() => log.push('fn()')); + const promise = locker.lock(async () => log.push('fn()')); // The lock is now waiting on the lock-file becoming free, so no `fn()` in the log. expect(log).toEqual(['write()', 'read() => 188']); @@ -159,10 +159,11 @@ runInEachFileSystem(() => { let error: Error; await promise.catch(e => error = e); expect(log).toEqual(['write()', 'read() => 188', 'write()', 'read() => 188']); - expect(error !.message) + expect(error!.message) .toEqual( `Timed out waiting 0.2s for another ngcc process, with id 188, to complete.\n` + - `(If you are sure no ngcc process is running then you should delete the lock-file at ${lockFile.path}.)`); + `(If you are sure no ngcc process is running then you should delete the lock-file at ${ + lockFile.path}.)`); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/index_spec.ts b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/index_spec.ts index ae7287b917ba2..049660ba94a89 100644 --- a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/index_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/index_spec.ts @@ -23,7 +23,7 @@ runInEachFileSystem(() => { class LockFileUnderTest extends LockFileWithChildProcess { // Note that log is initialized in the `createUnlocker()` function that is called from // super(), so we can't initialize it here. - log !: string[]; + log!: string[]; constructor(fs: FileSystem) { super(fs, new MockLogger()); fs.ensureDir(fs.dirname(this.path)); @@ -47,7 +47,11 @@ runInEachFileSystem(() => { const log = this.log; // Normally this would fork a child process and return it. // But we don't want to do that in these tests. - return <any>{disconnect() { log.push('unlocker.disconnect()'); }}; + return <any>{ + disconnect() { + log.push('unlocker.disconnect()'); + } + }; } } diff --git a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/util_spec.ts b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/util_spec.ts index b0ffe4c672330..171d4625a445c 100644 --- a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/util_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/util_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '../../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; import {removeLockFile} from '../../../src/locking/lock_file_with_child_process/util'; import {MockLogger} from '../../helpers/mock_logger'; @@ -24,8 +24,9 @@ runInEachFileSystem(() => { }); describe('removeLockFile()', () => { - it('should do nothing if there is no file to remove', - () => { removeLockFile(fs, logger, absoluteFrom('/lockfile/path'), '1234'); }); + it('should do nothing if there is no file to remove', () => { + removeLockFile(fs, logger, absoluteFrom('/lockfile/path'), '1234'); + }); it('should do nothing if the pid does not match', () => { fs.writeFile(lockFilePath, '888'); diff --git a/packages/compiler-cli/ngcc/test/locking/sync_locker_spec.ts b/packages/compiler-cli/ngcc/test/locking/sync_locker_spec.ts index 8cd9687d07121..05e18987d78ee 100644 --- a/packages/compiler-cli/ngcc/test/locking/sync_locker_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/sync_locker_spec.ts @@ -50,7 +50,9 @@ runInEachFileSystem(() => { const lockFile = new MockLockFile(fs, log); const locker = new SyncLocker(lockFile); - spyOn(lockFile, 'write').and.callFake(() => { throw {code: 'EEXIST'}; }); + spyOn(lockFile, 'write').and.callFake(() => { + throw {code: 'EEXIST'}; + }); spyOn(lockFile, 'read').and.returnValue('188'); expect(() => locker.lock(() => {})) @@ -58,7 +60,8 @@ runInEachFileSystem(() => { `ngcc is already running at process with id 188.\n` + `If you are running multiple builds in parallel then you should pre-process your node_modules via the command line ngcc tool before starting the builds;\n` + `See https://v9.angular.io/guide/ivy#speeding-up-ngcc-compilation.\n` + - `(If you are sure no ngcc process is running then you should delete the lock-file at ${lockFile.path}.)`); + `(If you are sure no ngcc process is running then you should delete the lock-file at ${ + lockFile.path}.)`); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/migrations/missing_injectable_migration_spec.ts b/packages/compiler-cli/ngcc/test/migrations/missing_injectable_migration_spec.ts index 8ae41906d41b0..f8553bda29e92 100644 --- a/packages/compiler-cli/ngcc/test/migrations/missing_injectable_migration_spec.ts +++ b/packages/compiler-cli/ngcc/test/migrations/missing_injectable_migration_spec.ts @@ -7,14 +7,14 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {absoluteFrom, AbsoluteFsPath, getFileSystem} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {DecorationAnalyses} from '../../src/analysis/types'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; -import {MissingInjectableMigration, getAngularCoreDecoratorName} from '../../src/migrations/missing_injectable_migration'; +import {getAngularCoreDecoratorName, MissingInjectableMigration} from '../../src/migrations/missing_injectable_migration'; import {MockLogger} from '../helpers/mock_logger'; import {getRootFiles, makeTestEntryPointBundle} from '../helpers/utils'; @@ -58,7 +58,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'ServiceA')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceB')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceC')).toBe(false); @@ -66,7 +66,7 @@ runInEachFileSystem(() => { }); function runTests( - type: 'NgModule' | 'Directive' | 'Component', propName: 'providers' | 'viewProviders') { + type: 'NgModule'|'Directive'|'Component', propName: 'providers'|'viewProviders') { const args = type === 'Component' ? 'template: "", ' : ''; it(`should migrate type provider in ${type}`, () => { @@ -85,7 +85,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'OtherService')).toBe(false); }); @@ -106,12 +106,12 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'OtherService')).toBe(false); }); - it(`should migrate object literal provider with forwardRef in ${type}`, async() => { + it(`should migrate object literal provider with forwardRef in ${type}`, async () => { const {program, analysis} = setUpAndAnalyzeProgram([{ name: INDEX_FILENAME, contents: ` @@ -121,12 +121,13 @@ runInEachFileSystem(() => { export class TestClass {} TestClass.decorators = [ - { type: ${type}, args: [{${args}${propName}: [{provide: forwardRef(() => MyService) }]}] } + { type: ${type}, args: [{${args}${ + propName}: [{provide: forwardRef(() => MyService) }]}] } ]; `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); }); @@ -140,12 +141,13 @@ runInEachFileSystem(() => { export class TestClass {} TestClass.decorators = [ - { type: ${type}, args: [{${args}${propName}: [{provide: MyService, useValue: null }]}] } + { type: ${type}, args: [{${args}${ + propName}: [{provide: MyService, useValue: null }]}] } ]; `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); @@ -159,12 +161,13 @@ runInEachFileSystem(() => { export class TestClass {} TestClass.decorators = [ - { type: ${type}, args: [{${args}${propName}: [{provide: MyService, useFactory: () => null }]}] } + { type: ${type}, args: [{${args}${ + propName}: [{provide: MyService, useFactory: () => null }]}] } ]; `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); @@ -189,7 +192,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'MyToken')).toBe(false); expect(hasInjectableDecorator(index, analysis, 'MyTokenAlias')).toBe(false); @@ -206,12 +209,13 @@ runInEachFileSystem(() => { export class TestClass {} TestClass.decorators = [ - { type: ${type}, args: [{${args}${propName}: [{provide: MyToken, useClass: MyService}]}] } + { type: ${type}, args: [{${args}${ + propName}: [{provide: MyToken, useClass: MyService}]}] } ]; `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'MyToken')).toBe(false); }); @@ -234,7 +238,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(getInjectableDecorators(index, analysis, 'MyService').length).toBe(1); }); @@ -256,7 +260,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); @@ -278,7 +282,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); @@ -300,7 +304,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); @@ -320,7 +324,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'ServiceA')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceB')).toBe(true); }); @@ -348,7 +352,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'ServiceA')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceB')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceC')).toBe(true); @@ -381,7 +385,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'ServiceA')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceB')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceC')).toBe(true); @@ -407,7 +411,7 @@ runInEachFileSystem(() => { ` }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'ServiceA')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceB')).toBe(true); expect(hasInjectableDecorator(index, analysis, 'ServiceC')).toBe(false); @@ -434,7 +438,7 @@ runInEachFileSystem(() => { ` }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(getInjectableDecorators(index, analysis, 'ServiceA').length).toBe(1); expect(getInjectableDecorators(index, analysis, 'ServiceB').length).toBe(1); }); @@ -454,7 +458,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'ServiceA')).toBe(false); }); @@ -481,7 +485,7 @@ runInEachFileSystem(() => { } ]); - const index = program.getSourceFile(SERVICE_FILENAME) !; + const index = program.getSourceFile(SERVICE_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); }); @@ -508,7 +512,7 @@ runInEachFileSystem(() => { } ]); - const index = program.getSourceFile(SERVICE_FILENAME) !; + const index = program.getSourceFile(SERVICE_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); @@ -527,7 +531,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(true); }); @@ -546,7 +550,7 @@ runInEachFileSystem(() => { `, }]); - const index = program.getSourceFile(INDEX_FILENAME) !; + const index = program.getSourceFile(INDEX_FILENAME)!; expect(hasInjectableDecorator(index, analysis, 'MyService')).toBe(false); }); } diff --git a/packages/compiler-cli/ngcc/test/migrations/undecorated_parent_migration_spec.ts b/packages/compiler-cli/ngcc/test/migrations/undecorated_parent_migration_spec.ts index 91ca55a152a9f..064aa26b96ff2 100644 --- a/packages/compiler-cli/ngcc/test/migrations/undecorated_parent_migration_spec.ts +++ b/packages/compiler-cli/ngcc/test/migrations/undecorated_parent_migration_spec.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; + +import {absoluteFrom, AbsoluteFsPath, getFileSystem} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; @@ -34,7 +35,7 @@ runInEachFileSystem(() => { ` }]); expect(errors).toEqual([]); - const file = analysis.get(program.getSourceFile(INDEX_FILENAME) !); + const file = analysis.get(program.getSourceFile(INDEX_FILENAME)!); expect(file).toBeUndefined(); }); @@ -56,7 +57,7 @@ runInEachFileSystem(() => { ` }]); expect(errors).toEqual([]); - const file = analysis.get(program.getSourceFile(INDEX_FILENAME) !) !; + const file = analysis.get(program.getSourceFile(INDEX_FILENAME)!)!; expect(file.compiledClasses.find(c => c.name === 'DerivedClass')).toBeDefined(); expect(file.compiledClasses.find(c => c.name === 'BaseClass')).toBeUndefined(); }); @@ -81,15 +82,15 @@ runInEachFileSystem(() => { ` }]); expect(errors).toEqual([]); - const file = analysis.get(program.getSourceFile(INDEX_FILENAME) !) !; + const file = analysis.get(program.getSourceFile(INDEX_FILENAME)!)!; expect(file.compiledClasses.find(c => c.name === 'DerivedClass')).toBeDefined(); - const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass') !; - expect(baseClass.decorators !.length).toEqual(1); - const decorator = baseClass.decorators ![0]; + const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass')!; + expect(baseClass.decorators!.length).toEqual(1); + const decorator = baseClass.decorators![0]; expect(decorator.name).toEqual('Directive'); expect(decorator.identifier).toBeNull('The decorator must be synthesized'); expect(decorator.import).toEqual({from: '@angular/core', name: 'Directive'}); - expect(decorator.args !.length).toEqual(0); + expect(decorator.args!.length).toEqual(0); }); it('should not add a decorator to a base class that is already decorated', () => { @@ -114,11 +115,11 @@ runInEachFileSystem(() => { ` }]); expect(errors).toEqual([]); - const file = analysis.get(program.getSourceFile(INDEX_FILENAME) !) !; + const file = analysis.get(program.getSourceFile(INDEX_FILENAME)!)!; expect(file.compiledClasses.find(c => c.name === 'DerivedClass')).toBeDefined(); - const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass') !; - expect(baseClass.decorators !.length).toEqual(1); - const decorator = baseClass.decorators ![0]; + const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass')!; + expect(baseClass.decorators!.length).toEqual(1); + const decorator = baseClass.decorators![0]; expect(decorator.name).toEqual('Directive'); expect(decorator.identifier).not.toBeNull('The decorator must not be synthesized'); }); @@ -145,25 +146,25 @@ runInEachFileSystem(() => { ` }]); expect(errors).toEqual([]); - const file = analysis.get(program.getSourceFile(INDEX_FILENAME) !) !; + const file = analysis.get(program.getSourceFile(INDEX_FILENAME)!)!; expect(file.compiledClasses.find(c => c.name === 'DerivedClass')).toBeDefined(); expect(file.compiledClasses.find(c => c.name === 'RealBaseClass')).toBeUndefined(); - const intermediateClass = file.compiledClasses.find(c => c.name === 'IntermediateClass') !; - expect(intermediateClass.decorators !.length).toEqual(1); - const intermediateDecorator = intermediateClass.decorators ![0]; + const intermediateClass = file.compiledClasses.find(c => c.name === 'IntermediateClass')!; + expect(intermediateClass.decorators!.length).toEqual(1); + const intermediateDecorator = intermediateClass.decorators![0]; expect(intermediateDecorator.name).toEqual('Directive'); expect(intermediateDecorator.identifier).toBeNull('The decorator must be synthesized'); expect(intermediateDecorator.import).toEqual({from: '@angular/core', name: 'Directive'}); - expect(intermediateDecorator.args !.length).toEqual(0); + expect(intermediateDecorator.args!.length).toEqual(0); - const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass') !; - expect(baseClass.decorators !.length).toEqual(1); - const baseDecorator = baseClass.decorators ![0]; + const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass')!; + expect(baseClass.decorators!.length).toEqual(1); + const baseDecorator = baseClass.decorators![0]; expect(baseDecorator.name).toEqual('Directive'); expect(baseDecorator.identifier).toBeNull('The decorator must be synthesized'); expect(baseDecorator.import).toEqual({from: '@angular/core', name: 'Directive'}); - expect(baseDecorator.args !.length).toEqual(0); + expect(baseDecorator.args!.length).toEqual(0); }); it('should handle the base class being in a different file (same package) as the derived class', @@ -195,14 +196,14 @@ runInEachFileSystem(() => { } ]); expect(errors).toEqual([]); - const file = analysis.get(program.getSourceFile(BASE_FILENAME) !) !; - const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass') !; - expect(baseClass.decorators !.length).toEqual(1); - const decorator = baseClass.decorators ![0]; + const file = analysis.get(program.getSourceFile(BASE_FILENAME)!)!; + const baseClass = file.compiledClasses.find(c => c.name === 'BaseClass')!; + expect(baseClass.decorators!.length).toEqual(1); + const decorator = baseClass.decorators![0]; expect(decorator.name).toEqual('Directive'); expect(decorator.identifier).toBeNull('The decorator must be synthesized'); expect(decorator.import).toEqual({from: '@angular/core', name: 'Directive'}); - expect(decorator.args !.length).toEqual(0); + expect(decorator.args!.length).toEqual(0); }); it('should skip the base class if it is in a different package from the derived class', () => { diff --git a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts index e6637cf99d1e4..ff9f414c7ac6a 100644 --- a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts @@ -8,7 +8,7 @@ import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; -import {NGCC_VERSION, cleanPackageJson, hasBeenProcessed, markAsProcessed, needsCleaning} from '../../src/packages/build_marker'; +import {cleanPackageJson, hasBeenProcessed, markAsProcessed, needsCleaning, NGCC_VERSION} from '../../src/packages/build_marker'; import {EntryPointPackageJson} from '../../src/packages/entry_point'; import {DirectPackageJsonUpdater} from '../../src/writing/package_json_updater'; @@ -192,8 +192,9 @@ runInEachFileSystem(() => { .toBe(false); }); - it('should return false if no markers exist', - () => { expect(hasBeenProcessed({name: 'test'}, 'module')).toBe(false); }); + it('should return false if no markers exist', () => { + expect(hasBeenProcessed({name: 'test'}, 'module')).toBe(false); + }); }); describe('needsCleaning()', () => { diff --git a/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts b/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts index f91abd6c7de4c..b9c06673973c0 100644 --- a/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts @@ -7,7 +7,7 @@ */ import {createHash} from 'crypto'; -import {FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {DEFAULT_NGCC_CONFIG, NgccConfiguration} from '../../src/packages/configuration'; @@ -27,8 +27,8 @@ runInEachFileSystem(() => { it('should error if a project level config file is badly formatted', () => { loadTestFiles([{name: _Abs('/project-1/ngcc.config.js'), contents: `bad js code`}]); expect(() => new NgccConfiguration(fs, _Abs('/project-1'))) - .toThrowError( - `Invalid project configuration file at "${_Abs('/project-1/ngcc.config.js')}": Unexpected identifier`); + .toThrowError(`Invalid project configuration file at "${ + _Abs('/project-1/ngcc.config.js')}": Unexpected identifier`); }); }); @@ -50,8 +50,8 @@ runInEachFileSystem(() => { };` }]); const project1Conf = new NgccConfiguration(fs, project1); - const expectedProject1Config = - `{"packages":{"${project1Package1}":[{"entryPoints":{"${project1Package1EntryPoint1}":{}},"versionRange":"*"}]}}`; + const expectedProject1Config = `{"packages":{"${project1Package1}":[{"entryPoints":{"${ + project1Package1EntryPoint1}":{}},"versionRange":"*"}]}}`; expect(project1Conf.hash) .toEqual(createHash('md5').update(expectedProject1Config).digest('hex')); @@ -71,8 +71,8 @@ runInEachFileSystem(() => { };` }]); const project2Conf = new NgccConfiguration(fs, project2); - const expectedProject2Config = - `{"packages":{"${project2Package1}":[{"entryPoints":{"${project2Package1EntryPoint1}":{"ignore":true}},"versionRange":"*"}]}}`; + const expectedProject2Config = `{"packages":{"${project2Package1}":[{"entryPoints":{"${ + project2Package1EntryPoint1}":{"ignore":true}},"versionRange":"*"}]}}`; expect(project2Conf.hash) .toEqual(createHash('md5').update(expectedProject2Config).digest('hex')); }); @@ -136,8 +136,9 @@ runInEachFileSystem(() => { }]); const configuration = new NgccConfiguration(fs, _Abs('/project-1')); expect(() => configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0')) - .toThrowError( - `Invalid package configuration file at "${_Abs('/project-1/node_modules/package-1/ngcc.config.js')}": Unexpected identifier`); + .toThrowError(`Invalid package configuration file at "${ + _Abs( + '/project-1/node_modules/package-1/ngcc.config.js')}": Unexpected identifier`); }); }); @@ -243,7 +244,7 @@ runInEachFileSystem(() => { ]); const configuration = new NgccConfiguration(fs, _Abs('/project-1')); - const getConfig = (packageName: string, version: string | null) => + const getConfig = (packageName: string, version: string|null) => configuration.getConfig(_Abs(`/project-1/node_modules/${packageName}`), version); // Default version range: * @@ -343,7 +344,6 @@ runInEachFileSystem(() => { versionRange: '*', entryPoints: {[_Abs('/project-1/node_modules/@angular/common')]: {}} }); - }); it('should override package level config with project level config per package', () => { @@ -412,8 +412,7 @@ runInEachFileSystem(() => { configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0'); expect(config).toEqual({ versionRange: '*', - entryPoints: - {[_Abs('/project-1/node_modules/package-1/default-level-entry-point')]: {}} + entryPoints: {[_Abs('/project-1/node_modules/package-1/default-level-entry-point')]: {}} }); }); @@ -427,8 +426,7 @@ runInEachFileSystem(() => { // merge entry-points. expect(config).toEqual({ versionRange: '1.0.0', - entryPoints: - {[_Abs('/project-1/node_modules/package-1/package-level-entry-point')]: {}} + entryPoints: {[_Abs('/project-1/node_modules/package-1/package-level-entry-point')]: {}} }); }); @@ -465,8 +463,7 @@ runInEachFileSystem(() => { // merge entry-points. expect(config).toEqual({ versionRange: '*', - entryPoints: - {[_Abs('/project-1/node_modules/package-1/project-level-entry-point')]: {}} + entryPoints: {[_Abs('/project-1/node_modules/package-1/project-level-entry-point')]: {}} }); }); @@ -490,7 +487,7 @@ runInEachFileSystem(() => { }); const configuration = new NgccConfiguration(fs, _Abs('/project-1')); - const getConfig = (packageName: string, version: string | null) => + const getConfig = (packageName: string, version: string|null) => configuration.getConfig(_Abs(`/project-1/node_modules/${packageName}`), version); // Default version range: * diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts index 9bec20881bde8..8f9b1df83d23c 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_bundle_spec.ts @@ -13,7 +13,6 @@ import {makeEntryPointBundle} from '../../src/packages/entry_point_bundle'; runInEachFileSystem(() => { describe('entry point bundle', () => { - function setupMockFileSystem(): void { const _ = absoluteFrom; loadTestFiles([ @@ -196,7 +195,7 @@ runInEachFileSystem(() => { '/node_modules/other/index.d.ts', ].map(p => absoluteFrom(p).toString()))); - expect(esm5bundle.dts !.program.getSourceFiles().map(sf => sf.fileName)) + expect(esm5bundle.dts!.program.getSourceFiles().map(sf => sf.fileName)) .toEqual(jasmine.arrayWithExactContents([ // All modules in the dts program should be declaration files '/node_modules/test/index.d.ts', @@ -231,7 +230,7 @@ runInEachFileSystem(() => { /* pathMappings */ undefined, /* mirrorDtsFromSrc */ true); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/test/internal.js')); - expect(esm5bundle.dts !.program.getSourceFiles().map(sf => sf.fileName)) + expect(esm5bundle.dts!.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/test/internal.d.ts')); }); @@ -253,7 +252,7 @@ runInEachFileSystem(() => { /* pathMappings */ undefined, /* mirrorDtsFromSrc */ true); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/internal/esm2015/src/internal.js')); - expect(esm5bundle.dts !.program.getSourceFiles().map(sf => sf.fileName)) + expect(esm5bundle.dts!.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/internal/src/internal.d.ts')); }); @@ -275,7 +274,7 @@ runInEachFileSystem(() => { /* pathMappings */ undefined, /* mirrorDtsFromSrc */ false); expect(esm5bundle.src.program.getSourceFiles().map(sf => sf.fileName)) .toContain(absoluteFrom('/node_modules/test/internal.js')); - expect(esm5bundle.dts !.program.getSourceFiles().map(sf => sf.fileName)) + expect(esm5bundle.dts!.program.getSourceFiles().map(sf => sf.fileName)) .not.toContain(absoluteFrom('/node_modules/test/internal.d.ts')); }); }); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts index b67eaa73c929f..12debe0965011 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts @@ -7,7 +7,7 @@ */ import {createHash} from 'crypto'; -import {FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NGCC_VERSION} from '../../src/packages/build_marker'; @@ -135,13 +135,15 @@ runInEachFileSystem(() => { _Abs('/project/node_modules/__ngcc_entry_points__.json'), JSON.stringify(manifestFile)); const entryPoints = manifest.readEntryPointsUsingManifest(_Abs('/project/node_modules')); expect(entryPoints).toEqual([{ - name: 'some_package/valid_entry_point', packageJson: jasmine.any(Object), - package: _Abs('/project/node_modules/some_package'), - path: _Abs('/project/node_modules/some_package/valid_entry_point'), - typings: _Abs( - '/project/node_modules/some_package/valid_entry_point/valid_entry_point.d.ts'), - compiledByAngular: true, ignoreMissingDependencies: false, - generateDeepReexports: false, + name: 'some_package/valid_entry_point', + packageJson: jasmine.any(Object), + package: _Abs('/project/node_modules/some_package'), + path: _Abs('/project/node_modules/some_package/valid_entry_point'), + typings: + _Abs('/project/node_modules/some_package/valid_entry_point/valid_entry_point.d.ts'), + compiledByAngular: true, + ignoreMissingDependencies: false, + generateDeepReexports: false, } as any]); }); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index 9a0e7957b7b98..3ac8b1f32c869 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -6,11 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES, getEntryPointFormat, getEntryPointInfo} from '../../src/packages/entry_point'; +import {EntryPoint, getEntryPointFormat, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point'; import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { @@ -69,8 +69,7 @@ runInEachFileSystem(() => { ]); const config = new NgccConfiguration(fs, _('/project')); spyOn(config, 'getConfig').and.returnValue({ - entryPoints: - {[_('/project/node_modules/some_package/valid_entry_point')]: {ignore: true}} + entryPoints: {[_('/project/node_modules/some_package/valid_entry_point')]: {ignore: true}} }); const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, @@ -102,8 +101,9 @@ runInEachFileSystem(() => { fs, config, new MockLogger(), SOME_PACKAGE, _('/project/node_modules/some_package/valid_entry_point')); const overriddenPackageJson = { - ...loadPackageJson(fs, '/project/node_modules/some_package/valid_entry_point'), - ...override}; + ...loadPackageJson(fs, '/project/node_modules/some_package/valid_entry_point'), + ...override + }; expect(entryPoint).toEqual({ name: 'some_package/valid_entry_point', package: SOME_PACKAGE, @@ -145,8 +145,7 @@ runInEachFileSystem(() => { const override = JSON.parse(createPackageJson('missing_package_json', {excludes: ['name']})); spyOn(config, 'getConfig').and.returnValue({ - entryPoints: - {[_('/project/node_modules/some_package/missing_package_json')]: {override}} + entryPoints: {[_('/project/node_modules/some_package/missing_package_json')]: {override}} }); const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, @@ -211,37 +210,38 @@ runInEachFileSystem(() => { // Let's give 'module' a specific path, otherwise compute it based on the property. const typingsPath = prop === 'module' ? 'index' : `${prop}/missing_typings`; - it(`should return an object if it can guess the typings path from the "${prop}" field`, () => { - loadTestFiles([ - { - name: _('/project/node_modules/some_package/missing_typings/package.json'), - contents: createPackageJson('missing_typings', {excludes: ['typings']}), - }, - { - name: _( - `/project/node_modules/some_package/missing_typings/${typingsPath}.metadata.json`), - contents: 'some meta data', - }, - { - name: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`), - contents: '// some typings file', - }, - ]); - const config = new NgccConfiguration(fs, _('/project')); - const entryPoint = getEntryPointInfo( - fs, config, new MockLogger(), SOME_PACKAGE, - _('/project/node_modules/some_package/missing_typings')); - expect(entryPoint).toEqual({ - name: 'some_package/missing_typings', - package: SOME_PACKAGE, - path: _('/project/node_modules/some_package/missing_typings'), - typings: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`), - packageJson: loadPackageJson(fs, '/project/node_modules/some_package/missing_typings'), - compiledByAngular: true, - ignoreMissingDependencies: false, - generateDeepReexports: false, - }); - }); + it(`should return an object if it can guess the typings path from the "${prop}" field`, + () => { + loadTestFiles([ + { + name: _('/project/node_modules/some_package/missing_typings/package.json'), + contents: createPackageJson('missing_typings', {excludes: ['typings']}), + }, + { + name: _(`/project/node_modules/some_package/missing_typings/${ + typingsPath}.metadata.json`), + contents: 'some meta data', + }, + { + name: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`), + contents: '// some typings file', + }, + ]); + const config = new NgccConfiguration(fs, _('/project')); + const entryPoint = getEntryPointInfo( + fs, config, new MockLogger(), SOME_PACKAGE, + _('/project/node_modules/some_package/missing_typings')); + expect(entryPoint).toEqual({ + name: 'some_package/missing_typings', + package: SOME_PACKAGE, + path: _('/project/node_modules/some_package/missing_typings'), + typings: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`), + packageJson: loadPackageJson(fs, '/project/node_modules/some_package/missing_typings'), + compiledByAngular: true, + ignoreMissingDependencies: false, + generateDeepReexports: false, + }); + }); } it('should return an object with `compiledByAngular` set to false if there is no metadata.json file next to the typing file', @@ -401,23 +401,29 @@ runInEachFileSystem(() => { entryPoint = result; }); - it('should return `esm2015` format for `fesm2015` property', - () => { expect(getEntryPointFormat(fs, entryPoint, 'fesm2015')).toBe('esm2015'); }); + it('should return `esm2015` format for `fesm2015` property', () => { + expect(getEntryPointFormat(fs, entryPoint, 'fesm2015')).toBe('esm2015'); + }); - it('should return `esm5` format for `fesm5` property', - () => { expect(getEntryPointFormat(fs, entryPoint, 'fesm5')).toBe('esm5'); }); + it('should return `esm5` format for `fesm5` property', () => { + expect(getEntryPointFormat(fs, entryPoint, 'fesm5')).toBe('esm5'); + }); - it('should return `esm2015` format for `es2015` property', - () => { expect(getEntryPointFormat(fs, entryPoint, 'es2015')).toBe('esm2015'); }); + it('should return `esm2015` format for `es2015` property', () => { + expect(getEntryPointFormat(fs, entryPoint, 'es2015')).toBe('esm2015'); + }); - it('should return `esm2015` format for `esm2015` property', - () => { expect(getEntryPointFormat(fs, entryPoint, 'esm2015')).toBe('esm2015'); }); + it('should return `esm2015` format for `esm2015` property', () => { + expect(getEntryPointFormat(fs, entryPoint, 'esm2015')).toBe('esm2015'); + }); - it('should return `esm5` format for `esm5` property', - () => { expect(getEntryPointFormat(fs, entryPoint, 'esm5')).toBe('esm5'); }); + it('should return `esm5` format for `esm5` property', () => { + expect(getEntryPointFormat(fs, entryPoint, 'esm5')).toBe('esm5'); + }); - it('should return `esm5` format for `module` property', - () => { expect(getEntryPointFormat(fs, entryPoint, 'module')).toBe('esm5'); }); + it('should return `esm5` format for `module` property', () => { + expect(getEntryPointFormat(fs, entryPoint, 'module')).toBe('esm5'); + }); it('should return `umd` for `main` if the file contains a UMD wrapper function', () => { loadTestFiles([{ diff --git a/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts index 2071a8555e324..914208bedcd39 100644 --- a/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/commonjs_rendering_formatter_spec.ts @@ -8,19 +8,20 @@ import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; + +import {absoluteFrom, absoluteFromSourceFile, AbsoluteFsPath, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {NoopImportRewriter} from '../../../src/ngtsc/imports'; -import {AbsoluteFsPath, getFileSystem, getSourceFileOrError, absoluteFrom, absoluteFromSourceFile} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {loadTestFiles} from '../../../test/helpers'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {ImportManager} from '../../../src/ngtsc/translator'; +import {loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {CommonJsReflectionHost} from '../../src/host/commonjs_host'; import {CommonJsRenderingFormatter} from '../../src/rendering/commonjs_rendering_formatter'; -import {makeTestEntryPointBundle} from '../helpers/utils'; import {MockLogger} from '../helpers/mock_logger'; +import {makeTestEntryPointBundle} from '../helpers/utils'; runInEachFileSystem(() => { describe('CommonJsRenderingFormatter', () => { @@ -273,7 +274,7 @@ var A = (function() {`); const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( - output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); + output, file, switchMarkerAnalyses.get(sourceFile)!.declarations); expect(output.toString()) .not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`); expect(output.toString()) @@ -295,7 +296,7 @@ var A = (function() {`); const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(` A.prototype.ngDoCheck = function() { @@ -314,15 +315,16 @@ SOME DEFINITION TEXT program, absoluteFromSourceFile(sourceFile), 'NoIife', ts.isFunctionDeclaration); const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) - .toThrowError( - `Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`); + .toThrowError(`Compiled class declaration is not inside an IIFE: NoIife in ${ + _('/node_modules/test-package/some/file.js')}`); const badIifeDeclaration = getDeclaration( program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration); const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`); + `Compiled class wrapper IIFE does not have a return statement: BadIife in ${ + _('/node_modules/test-package/some/file.js')}`); }); }); @@ -347,8 +349,8 @@ SOME DEFINITION TEXT const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup(program); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( @@ -364,8 +366,8 @@ SOME DEFINITION TEXT const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup(program); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITIONS'); renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); const definitionsPosition = output.toString().indexOf('SOME DEFINITIONS'); @@ -377,16 +379,15 @@ SOME DEFINITION TEXT }); describe('removeDecorators', () => { - it('should delete the decorator (and following comma) that was matched in the analysis', () => { const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .not.toContain(`{ type: core.Directive, args: [{ selector: '[a]' }] },`); @@ -404,10 +405,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .toContain(`{ type: core.Directive, args: [{ selector: '[a]' }] },`); @@ -425,10 +426,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()) @@ -441,7 +442,6 @@ SOME DEFINITION TEXT .toContain(`function C() {}\nSOME DEFINITION TEXT\n return C;`); expect(output.toString()).not.toContain(`C.decorators`); }); - }); describe('[__decorate declarations]', () => { @@ -450,10 +450,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).not.toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -467,10 +467,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -485,10 +485,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); diff --git a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts index cb78fa5f42766..101427f31cdb9 100644 --- a/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/dts_renderer_spec.ts @@ -7,21 +7,22 @@ */ import MagicString from 'magic-string'; import * as ts from 'typescript'; + import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {Reexport} from '../../../src/ngtsc/imports'; -import {loadTestFiles} from '../../../test/helpers'; import {Import, ImportManager} from '../../../src/ngtsc/translator'; +import {loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; -import {CompiledClass} from '../../src/analysis/types'; -import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {ModuleWithProvidersAnalyzer, ModuleWithProvidersInfo} from '../../src/analysis/module_with_providers_analyzer'; -import {PrivateDeclarationsAnalyzer, ExportInfo} from '../../src/analysis/private_declarations_analyzer'; +import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; +import {ExportInfo, PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer'; +import {CompiledClass} from '../../src/analysis/types'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; -import {RenderingFormatter, RedundantDecoratorMap} from '../../src/rendering/rendering_formatter'; import {DtsRenderer} from '../../src/rendering/dts_renderer'; +import {RedundantDecoratorMap, RenderingFormatter} from '../../src/rendering/rendering_formatter'; import {MockLogger} from '../helpers/mock_logger'; -import {makeTestEntryPointBundle, getRootFiles} from '../helpers/utils'; +import {getRootFiles, makeTestEntryPointBundle} from '../helpers/utils'; class TestRenderingFormatter implements RenderingFormatter { addImports(output: MagicString, imports: Import[], sf: ts.SourceFile) { @@ -53,7 +54,9 @@ class TestRenderingFormatter implements RenderingFormatter { importManager: ImportManager): void { output.prepend('\n// ADD MODUlE WITH PROVIDERS PARAMS\n'); } - printStatement(): string { return 'IGNORED'; } + printStatement(): string { + return 'IGNORED'; + } } function createTestRenderer( @@ -92,12 +95,14 @@ function createTestRenderer( const renderer = new DtsRenderer(testFormatter, fs, logger, host, bundle); - return {renderer, - testFormatter, - decorationAnalyses, - moduleWithProvidersAnalyses, - privateDeclarationsAnalyses, - bundle}; + return { + renderer, + testFormatter, + decorationAnalyses, + moduleWithProvidersAnalyses, + privateDeclarationsAnalyses, + bundle + }; } runInEachFileSystem(() => { @@ -120,35 +125,44 @@ runInEachFileSystem(() => { }); it('should render extract types into typings files', () => { - const {renderer, decorationAnalyses, privateDeclarationsAnalyses, - moduleWithProvidersAnalyses} = - createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); + const { + renderer, + decorationAnalyses, + privateDeclarationsAnalyses, + moduleWithProvidersAnalyses + } = createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); const result = renderer.renderProgram( decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses); const typingsFile = - result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !; + result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts'))!; expect(typingsFile.contents) .toContain( 'foo(x: number): number;\n static ɵfac: ɵngcc0.ɵɵFactoryDef<A, never>;\n static ɵdir: ɵngcc0.ɵɵDirectiveDefWithMeta'); }); it('should render imports into typings files', () => { - const {renderer, decorationAnalyses, privateDeclarationsAnalyses, - moduleWithProvidersAnalyses} = - createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); + const { + renderer, + decorationAnalyses, + privateDeclarationsAnalyses, + moduleWithProvidersAnalyses + } = createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); const result = renderer.renderProgram( decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses); const typingsFile = - result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !; + result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts'))!; expect(typingsFile.contents).toContain(`\n// ADD IMPORTS\n`); }); it('should render exports into typings files', () => { - const {renderer, decorationAnalyses, privateDeclarationsAnalyses, - moduleWithProvidersAnalyses} = - createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); + const { + renderer, + decorationAnalyses, + privateDeclarationsAnalyses, + moduleWithProvidersAnalyses + } = createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); // Add a mock export to trigger export rendering privateDeclarationsAnalyses.push({ @@ -161,20 +175,23 @@ runInEachFileSystem(() => { decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses); const typingsFile = - result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !; + result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts'))!; expect(typingsFile.contents).toContain(`\n// ADD EXPORTS\n`); }); it('should render ModuleWithProviders type params', () => { - const {renderer, decorationAnalyses, privateDeclarationsAnalyses, - moduleWithProvidersAnalyses} = - createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); + const { + renderer, + decorationAnalyses, + privateDeclarationsAnalyses, + moduleWithProvidersAnalyses + } = createTestRenderer('test-package', [INPUT_PROGRAM], [INPUT_DTS_PROGRAM]); const result = renderer.renderProgram( decorationAnalyses, privateDeclarationsAnalyses, moduleWithProvidersAnalyses); const typingsFile = - result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts')) !; + result.find(f => f.path === _('/node_modules/test-package/typings/file.d.ts'))!; expect(typingsFile.contents).toContain(`\n// ADD MODUlE WITH PROVIDERS PARAMS\n`); }); }); diff --git a/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts index 8a4c4e0bc5888..72edb0a8408fb 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm5_rendering_formatter_spec.ts @@ -8,20 +8,21 @@ import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; + +import {absoluteFrom, absoluteFromSourceFile, AbsoluteFsPath, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {NoopImportRewriter} from '../../../src/ngtsc/imports'; -import {AbsoluteFsPath, absoluteFrom, absoluteFromSourceFile, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {getDeclaration} from '../../../src/ngtsc/testing'; import {ImportManager} from '../../../src/ngtsc/translator'; -import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {loadTestFiles} from '../../../test/helpers'; +import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {IMPORT_PREFIX} from '../../src/constants'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Esm5RenderingFormatter} from '../../src/rendering/esm5_rendering_formatter'; -import {makeTestEntryPointBundle} from '../helpers/utils'; import {MockLogger} from '../helpers/mock_logger'; +import {makeTestEntryPointBundle} from '../helpers/utils'; function setup(file: {name: AbsoluteFsPath, contents: string}) { loadTestFiles([file]); @@ -39,13 +40,16 @@ function setup(file: {name: AbsoluteFsPath, contents: string}) { return { host, program: bundle.src.program, - sourceFile: bundle.src.file, renderer, decorationAnalyses, switchMarkerAnalyses, importManager + sourceFile: bundle.src.file, + renderer, + decorationAnalyses, + switchMarkerAnalyses, + importManager }; } runInEachFileSystem(() => { describe('Esm5RenderingFormatter', () => { - let _: typeof absoluteFrom; let PROGRAM: TestFile; let PROGRAM_DECORATE_HELPER: TestFile; @@ -276,7 +280,7 @@ var A = (function() {`); const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( - output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); + output, file, switchMarkerAnalyses.get(sourceFile)!.declarations); expect(output.toString()) .not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`); expect(output.toString()) @@ -298,7 +302,7 @@ var A = (function() {`); const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(` A.prototype.ngDoCheck = function() { @@ -317,15 +321,16 @@ SOME DEFINITION TEXT program, absoluteFromSourceFile(sourceFile), 'NoIife', ts.isFunctionDeclaration); const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) - .toThrowError( - `Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`); + .toThrowError(`Compiled class declaration is not inside an IIFE: NoIife in ${ + _('/node_modules/test-package/some/file.js')}`); const badIifeDeclaration = getDeclaration( program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration); const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`); + `Compiled class wrapper IIFE does not have a return statement: BadIife in ${ + _('/node_modules/test-package/some/file.js')}`); }); }); @@ -350,8 +355,8 @@ SOME DEFINITION TEXT const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup(program); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( @@ -367,8 +372,8 @@ SOME DEFINITION TEXT const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup(program); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITIONS'); renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); const definitionsPosition = output.toString().indexOf('SOME DEFINITIONS'); @@ -381,16 +386,15 @@ SOME DEFINITION TEXT describe('removeDecorators', () => { - it('should delete the decorator (and following comma) that was matched in the analysis', () => { const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .not.toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); @@ -406,10 +410,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); expect(output.toString()).toContain(`{ type: OtherA }`); @@ -425,10 +429,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); @@ -447,10 +451,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).not.toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -464,10 +468,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -481,10 +485,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -500,10 +504,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'E') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'E')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).not.toContain(`Directive({ selector: '[e]' })`); expect(output.toString()).not.toContain(`E = tslib_1.__decorate([`); @@ -515,10 +519,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'F') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'F')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).not.toContain(`Directive({ selector: '[f]' })`); expect(output.toString()).not.toContain(`F = tslib_1.__decorate([`); diff --git a/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts index 275c42e5c7c44..43f39e3080c53 100644 --- a/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/esm_rendering_formatter_spec.ts @@ -8,20 +8,21 @@ import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; -import {NoopImportRewriter} from '../../../src/ngtsc/imports'; + import {absoluteFrom, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {loadTestFiles, loadFakeCore} from '../../../test/helpers'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; +import {NoopImportRewriter} from '../../../src/ngtsc/imports'; import {ImportManager} from '../../../src/ngtsc/translator'; +import {loadFakeCore, loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; +import {ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {IMPORT_PREFIX} from '../../src/constants'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {EsmRenderingFormatter} from '../../src/rendering/esm_rendering_formatter'; -import {makeTestEntryPointBundle, getRootFiles} from '../helpers/utils'; import {MockLogger} from '../helpers/mock_logger'; -import {ModuleWithProvidersAnalyzer} from '../../src/analysis/module_with_providers_analyzer'; +import {getRootFiles, makeTestEntryPointBundle} from '../helpers/utils'; function setup(files: TestFile[], dtsFiles?: TestFile[]) { const fs = getFileSystem(); @@ -32,7 +33,7 @@ function setup(files: TestFile[], dtsFiles?: TestFile[]) { } const logger = new MockLogger(); const bundle = makeTestEntryPointBundle( - 'test-package', 'esm2015', false, getRootFiles(files), dtsFiles && getRootFiles(dtsFiles)) !; + 'test-package', 'esm2015', false, getRootFiles(files), dtsFiles && getRootFiles(dtsFiles))!; const host = new Esm2015ReflectionHost(logger, false, bundle.src, bundle.dts); const referencesRegistry = new NgccReferencesRegistry(host); const decorationAnalyses = @@ -45,13 +46,16 @@ function setup(files: TestFile[], dtsFiles?: TestFile[]) { host, bundle, program: bundle.src.program, - sourceFile: bundle.src.file, renderer, decorationAnalyses, switchMarkerAnalyses, importManager, + sourceFile: bundle.src.file, + renderer, + decorationAnalyses, + switchMarkerAnalyses, + importManager, }; } runInEachFileSystem(() => { describe('EsmRenderingFormatter', () => { - let _: typeof absoluteFrom; let PROGRAM: TestFile; @@ -195,7 +199,7 @@ export class A {`); const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( - output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); + output, file, switchMarkerAnalyses.get(sourceFile)!.declarations); expect(output.toString()) .not.toContain(`let compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`); expect(output.toString()) @@ -216,7 +220,7 @@ export class A {`); const {renderer, decorationAnalyses, sourceFile} = setup([PROGRAM]); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(` export class A {} @@ -230,7 +234,7 @@ A.decorators = [ const {renderer, decorationAnalyses, sourceFile} = setup([PROGRAM]); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(` let C = C_1 = class C {}; @@ -259,8 +263,8 @@ C.decorators = [ const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup([program]); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( @@ -275,8 +279,8 @@ C.decorators = [ const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup([program]); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITIONS'); renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); const definitionsPosition = output.toString().indexOf('SOME DEFINITIONS'); @@ -294,10 +298,10 @@ C.decorators = [ const {decorationAnalyses, sourceFile, renderer} = setup([PROGRAM]); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .not.toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); @@ -315,10 +319,10 @@ C.decorators = [ const {decorationAnalyses, sourceFile, renderer} = setup([PROGRAM]); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); @@ -343,10 +347,10 @@ A.decorators = [ const {decorationAnalyses, sourceFile, renderer} = setup([file]); const output = new MagicString(text); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); // The decorator should have been removed correctly. expect(output.toString()).toContain('A.decorators = [ { type: OtherA }'); @@ -358,10 +362,10 @@ A.decorators = [ const {decorationAnalyses, sourceFile, renderer} = setup([PROGRAM]); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .toContain(`{ type: Directive, args: [{ selector: '[a]' }] },`); @@ -424,10 +428,10 @@ export { D }; const {renderer, decorationAnalyses, sourceFile} = setup([PROGRAM_DECORATE_HELPER]); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).not.toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -441,10 +445,10 @@ export { D }; const {renderer, decorationAnalyses, sourceFile} = setup([PROGRAM_DECORATE_HELPER]); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -459,10 +463,10 @@ export { D }; const {renderer, decorationAnalyses, sourceFile} = setup([PROGRAM_DECORATE_HELPER]); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -573,8 +577,8 @@ export { D }; new ModuleWithProvidersAnalyzer(host, referencesRegistry, true) .analyzeProgram(bundle.src.program); const typingsFile = getSourceFileOrError( - bundle.dts !.program, _('/node_modules/test-package/typings/index.d.ts')); - const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile) !; + bundle.dts!.program, _('/node_modules/test-package/typings/index.d.ts')); + const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile)!; const output = new MagicString(MODULE_WITH_PROVIDERS_DTS_PROGRAM[0].contents); const importManager = new ImportManager(new NoopImportRewriter(), 'i'); @@ -610,8 +614,8 @@ export { D }; new ModuleWithProvidersAnalyzer(host, referencesRegistry, true) .analyzeProgram(bundle.src.program); const typingsFile = getSourceFileOrError( - bundle.dts !.program, _('/node_modules/test-package/typings/module.d.ts')); - const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile) !; + bundle.dts!.program, _('/node_modules/test-package/typings/module.d.ts')); + const moduleWithProvidersInfo = moduleWithProvidersAnalyses.get(typingsFile)!; const output = new MagicString(MODULE_WITH_PROVIDERS_DTS_PROGRAM[1].contents); const importManager = new ImportManager(new NoopImportRewriter(), 'i'); diff --git a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts index dc3d144d181e5..ff450182c4f93 100644 --- a/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts @@ -6,27 +6,28 @@ * found in the LICENSE file at https://angular.io/license */ import {Statement} from '@angular/compiler'; -import {SourceMapMappings, encode} from 'sourcemap-codec'; +import {fromObject, generateMapFileComment, SourceMapConverter} from 'convert-source-map'; import MagicString from 'magic-string'; +import {encode, SourceMapMappings} from 'sourcemap-codec'; import * as ts from 'typescript'; -import {fromObject, generateMapFileComment, SourceMapConverter} from 'convert-source-map'; + import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; import {NOOP_DEFAULT_IMPORT_RECORDER, Reexport} from '../../../src/ngtsc/imports'; -import {loadTestFiles} from '../../../test/helpers'; import {Import, ImportManager, translateStatement} from '../../../src/ngtsc/translator'; +import {loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; -import {CompiledClass} from '../../src/analysis/types'; -import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {ModuleWithProvidersInfo} from '../../src/analysis/module_with_providers_analyzer'; -import {PrivateDeclarationsAnalyzer, ExportInfo} from '../../src/analysis/private_declarations_analyzer'; +import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; +import {ExportInfo, PrivateDeclarationsAnalyzer} from '../../src/analysis/private_declarations_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; +import {CompiledClass} from '../../src/analysis/types'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Renderer} from '../../src/rendering/renderer'; +import {RedundantDecoratorMap, RenderingFormatter} from '../../src/rendering/rendering_formatter'; import {MockLogger} from '../helpers/mock_logger'; -import {RenderingFormatter, RedundantDecoratorMap} from '../../src/rendering/rendering_formatter'; -import {makeTestEntryPointBundle, getRootFiles} from '../helpers/utils'; +import {getRootFiles, makeTestEntryPointBundle} from '../helpers/utils'; class TestRenderingFormatter implements RenderingFormatter { private printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed}); @@ -106,12 +107,14 @@ function createTestRenderer( const renderer = new Renderer(host, testFormatter, fs, logger, bundle); - return {renderer, - testFormatter, - decorationAnalyses, - switchMarkerAnalyses, - privateDeclarationsAnalyses, - bundle}; + return { + renderer, + testFormatter, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + bundle + }; } runInEachFileSystem(() => { @@ -227,8 +230,13 @@ runInEachFileSystem(() => { it('should render as JavaScript', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [COMPONENT_PROGRAM]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [COMPONENT_PROGRAM]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy; @@ -253,8 +261,13 @@ A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, v describe('calling RenderingFormatter methods', () => { it('should call addImports with the source code and info about the core Angular library.', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [JS_CONTENT]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [JS_CONTENT]); const result = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addImportsSpy = testFormatter.addImports as jasmine.Spy; @@ -266,8 +279,13 @@ A.ɵcmp = ɵngcc0.ɵɵdefineComponent({ type: A, selectors: [["a"]], decls: 1, v it('should call addDefinitions with the source code, the analyzed class and the rendered definitions.', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [JS_CONTENT]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [JS_CONTENT]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy; @@ -284,8 +302,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` it('should call addAdjacentStatements with the source code, the analyzed class and the rendered statements', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [JS_CONTENT]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [JS_CONTENT]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy; @@ -303,8 +326,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` it('should call removeDecorators with the source code, a map of class decorators that have been analyzed', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [JS_CONTENT]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [JS_CONTENT]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const removeDecoratorsSpy = testFormatter.removeDecorators as jasmine.Spy; @@ -326,8 +354,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render definitions as static fields', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [NGMODULE_PROGRAM]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [NGMODULE_PROGRAM]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy; @@ -337,8 +370,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render adjacent statements', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [NGMODULE_PROGRAM]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [NGMODULE_PROGRAM]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy; @@ -347,8 +385,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render directives using the inner class name if different from outer', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer( 'test-package', [{ name: _('/node_modules/test-package/src/file.js'), @@ -379,8 +422,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render injectables using the inner class name if different from outer', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer( 'test-package', [{ name: _('/node_modules/test-package/src/file.js'), @@ -411,8 +459,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render ng-modules using the inner class name if different from outer', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer( 'test-package', [{ name: _('/node_modules/test-package/src/file.js'), @@ -448,8 +501,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render pipes using the inner class name if different from outer', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer( 'test-package', [{ name: _('/node_modules/test-package/src/file.js'), @@ -479,9 +537,13 @@ A.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["", "a", ""]] });` }); it('should render classes without decorators if class fields are decorated', () => { - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = - createTestRenderer('test-package', [{ + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [{ name: _('/node_modules/test-package/src/file.js'), contents: ` import { Directive, ViewChild } from '@angular/core'; @@ -514,8 +576,13 @@ UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, vie it('should call renderImports after other abstract methods', () => { // This allows the other methods to add additional imports if necessary - const {renderer, decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('test-package', [JS_CONTENT]); + const { + renderer, + decorationAnalyses, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('test-package', [JS_CONTENT]); const addExportsSpy = testFormatter.addExports as jasmine.Spy; const addDefinitionsSpy = testFormatter.addDefinitions as jasmine.Spy; const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy; @@ -537,8 +604,12 @@ UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, vie name: JS_CONTENT.name, contents: JS_CONTENT.contents + '\n' + JS_CONTENT_MAP.toComment() }]; - const {decorationAnalyses, renderer, switchMarkerAnalyses, - privateDeclarationsAnalyses} = createTestRenderer('test-package', sourceFiles); + const { + decorationAnalyses, + renderer, + switchMarkerAnalyses, + privateDeclarationsAnalyses + } = createTestRenderer('test-package', sourceFiles); const [sourceFile, mapFile] = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); expect(sourceFile.path).toEqual(_('/node_modules/test-package/src/file.js')); @@ -555,9 +626,12 @@ UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, vie }]; const mappingFiles: TestFile[] = [{name: _(JS_CONTENT.name + '.map'), contents: JS_CONTENT_MAP.toJSON()}]; - const {decorationAnalyses, renderer, switchMarkerAnalyses, - privateDeclarationsAnalyses} = - createTestRenderer('test-package', sourceFiles, undefined, mappingFiles); + const { + decorationAnalyses, + renderer, + switchMarkerAnalyses, + privateDeclarationsAnalyses + } = createTestRenderer('test-package', sourceFiles, undefined, mappingFiles); const [sourceFile, mapFile] = renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); expect(sourceFile.path).toEqual(_('/node_modules/test-package/src/file.js')); @@ -582,8 +656,13 @@ UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, vie contents: `export const NgModule = () => null;` }; // The package name of `@angular/core` indicates that we are compiling the core library. - const {decorationAnalyses, renderer, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('@angular/core', [CORE_FILE, R3_SYMBOLS_FILE]); + const { + decorationAnalyses, + renderer, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('@angular/core', [CORE_FILE, R3_SYMBOLS_FILE]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy; @@ -602,8 +681,13 @@ UndecoratedBase.ɵdir = ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, vie export class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n` }; - const {decorationAnalyses, renderer, switchMarkerAnalyses, privateDeclarationsAnalyses, - testFormatter} = createTestRenderer('@angular/core', [CORE_FILE]); + const { + decorationAnalyses, + renderer, + switchMarkerAnalyses, + privateDeclarationsAnalyses, + testFormatter + } = createTestRenderer('@angular/core', [CORE_FILE]); renderer.renderProgram( decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses); const addAdjacentStatementsSpy = testFormatter.addAdjacentStatements as jasmine.Spy; diff --git a/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts b/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts index e56f77751115d..b260b54b993f6 100644 --- a/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts +++ b/packages/compiler-cli/ngcc/test/rendering/umd_rendering_formatter_spec.ts @@ -8,16 +8,17 @@ import {DeclareVarStmt, LiteralExpr, StmtModifier} from '@angular/compiler'; import MagicString from 'magic-string'; import * as ts from 'typescript'; -import {NoopImportRewriter} from '../../../src/ngtsc/imports'; + import {absoluteFrom, absoluteFromSourceFile, getFileSystem, getSourceFileOrError} from '../../../src/ngtsc/file_system'; -import {TestFile, runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {loadTestFiles} from '../../../test/helpers'; +import {runInEachFileSystem, TestFile} from '../../../src/ngtsc/file_system/testing'; +import {NoopImportRewriter} from '../../../src/ngtsc/imports'; import {getDeclaration} from '../../../src/ngtsc/testing'; +import {ImportManager} from '../../../src/ngtsc/translator'; +import {loadTestFiles} from '../../../test/helpers'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {UmdReflectionHost} from '../../src/host/umd_host'; -import {ImportManager} from '../../../src/ngtsc/translator'; import {UmdRenderingFormatter} from '../../src/rendering/umd_rendering_formatter'; import {MockLogger} from '../helpers/mock_logger'; import {makeTestEntryPointBundle} from '../helpers/utils'; @@ -40,14 +41,15 @@ function setup(file: TestFile) { decorationAnalyses, host, importManager, - program: src.program, renderer, - sourceFile: src.file, switchMarkerAnalyses + program: src.program, + renderer, + sourceFile: src.file, + switchMarkerAnalyses }; } runInEachFileSystem(() => { describe('UmdRenderingFormatter', () => { - let _: typeof absoluteFrom; let PROGRAM: TestFile; let PROGRAM_DECORATE_HELPER: TestFile; @@ -438,7 +440,7 @@ var A = (function() {`); const file = getSourceFileOrError(program, _('/node_modules/test-package/some/file.js')); const output = new MagicString(PROGRAM.contents); renderer.rewriteSwitchableDeclarations( - output, file, switchMarkerAnalyses.get(sourceFile) !.declarations); + output, file, switchMarkerAnalyses.get(sourceFile)!.declarations); expect(output.toString()) .not.toContain(`var compileNgModuleFactory = compileNgModuleFactory__PRE_R3__;`); expect(output.toString()) @@ -460,7 +462,7 @@ var A = (function() {`); const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()).toContain(` A.prototype.ngDoCheck = function() { @@ -479,15 +481,16 @@ SOME DEFINITION TEXT program, absoluteFromSourceFile(sourceFile), 'NoIife', ts.isFunctionDeclaration); const mockNoIifeClass: any = {declaration: noIifeDeclaration, name: 'NoIife'}; expect(() => renderer.addDefinitions(output, mockNoIifeClass, 'SOME DEFINITION TEXT')) - .toThrowError( - `Compiled class declaration is not inside an IIFE: NoIife in ${_('/node_modules/test-package/some/file.js')}`); + .toThrowError(`Compiled class declaration is not inside an IIFE: NoIife in ${ + _('/node_modules/test-package/some/file.js')}`); const badIifeDeclaration = getDeclaration( program, absoluteFromSourceFile(sourceFile), 'BadIife', ts.isVariableDeclaration); const mockBadIifeClass: any = {declaration: badIifeDeclaration, name: 'BadIife'}; expect(() => renderer.addDefinitions(output, mockBadIifeClass, 'SOME DEFINITION TEXT')) .toThrowError( - `Compiled class wrapper IIFE does not have a return statement: BadIife in ${_('/node_modules/test-package/some/file.js')}`); + `Compiled class wrapper IIFE does not have a return statement: BadIife in ${ + _('/node_modules/test-package/some/file.js')}`); }); }); @@ -518,8 +521,8 @@ SOME DEFINITION TEXT const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup(program); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); expect(output.toString()) .toContain( @@ -535,8 +538,8 @@ SOME DEFINITION TEXT const program = {name: _('/node_modules/test-package/some/file.js'), contents}; const {renderer, decorationAnalyses, sourceFile} = setup(program); const output = new MagicString(contents); - const compiledClass = decorationAnalyses.get(sourceFile) !.compiledClasses.find( - c => c.name === 'SomeDirective') !; + const compiledClass = decorationAnalyses.get(sourceFile)!.compiledClasses.find( + c => c.name === 'SomeDirective')!; renderer.addDefinitions(output, compiledClass, 'SOME DEFINITIONS'); renderer.addAdjacentStatements(output, compiledClass, 'SOME STATEMENTS'); const definitionsPosition = output.toString().indexOf('SOME DEFINITIONS'); @@ -548,16 +551,15 @@ SOME DEFINITION TEXT }); describe('removeDecorators', () => { - it('should delete the decorator (and following comma) that was matched in the analysis', () => { const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .not.toContain(`{ type: core.Directive, args: [{ selector: '[a]' }] },`); @@ -575,10 +577,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()) .toContain(`{ type: core.Directive, args: [{ selector: '[a]' }] },`); @@ -596,10 +598,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM); const output = new MagicString(PROGRAM.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators ![0]; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators![0]; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); renderer.addDefinitions(output, compiledClass, 'SOME DEFINITION TEXT'); expect(output.toString()) @@ -610,7 +612,6 @@ SOME DEFINITION TEXT expect(output.toString()).toContain(`{ type: OtherB }`); expect(output.toString()).not.toContain(`C.decorators`); }); - }); describe('[__decorate declarations]', () => { @@ -619,10 +620,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'A') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'A')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).not.toContain(`core.Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -636,10 +637,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'B') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'B')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`core.Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); @@ -654,10 +655,10 @@ SOME DEFINITION TEXT const {renderer, decorationAnalyses, sourceFile} = setup(PROGRAM_DECORATE_HELPER); const output = new MagicString(PROGRAM_DECORATE_HELPER.contents); const compiledClass = - decorationAnalyses.get(sourceFile) !.compiledClasses.find(c => c.name === 'C') !; - const decorator = compiledClass.decorators !.find(d => d.name === 'Directive') !; + decorationAnalyses.get(sourceFile)!.compiledClasses.find(c => c.name === 'C')!; + const decorator = compiledClass.decorators!.find(d => d.name === 'Directive')!; const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); - decoratorsToRemove.set(decorator.node !.parent !, [decorator.node !]); + decoratorsToRemove.set(decorator.node!.parent!, [decorator.node!]); renderer.removeDecorators(output, decoratorsToRemove); expect(output.toString()).toContain(`core.Directive({ selector: '[a]' }),`); expect(output.toString()).toContain(`OtherA()`); diff --git a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts index 51d656601f4f2..c0d644b288ffe 100644 --- a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts +++ b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {FileSystem, absoluteFrom, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; +import {absoluteFrom, FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; import {fromObject} from 'convert-source-map'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; @@ -75,7 +75,8 @@ runInEachFileSystem(() => { const encodedSourceMap = Buffer.from(JSON.stringify(sourceMap)).toString('base64'); const sourceFile = registry.loadSourceFile( _('/foo/src/index.js'), - `some inline content\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${encodedSourceMap}`); + `some inline content\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${ + encodedSourceMap}`); if (sourceFile === null) { return fail('Expected source file to be defined'); } @@ -139,26 +140,26 @@ runInEachFileSystem(() => { expect(sourceFile.sources.length).toEqual(3); - expect(sourceFile.sources[0] !.contents).toEqual('x content'); - expect(sourceFile.sources[0] !.sourcePath).toEqual(_('/foo/src/x.js')); - expect(sourceFile.sources[0] !.rawMap).toEqual(null); - expect(sourceFile.sources[0] !.sources).toEqual([]); + expect(sourceFile.sources[0]!.contents).toEqual('x content'); + expect(sourceFile.sources[0]!.sourcePath).toEqual(_('/foo/src/x.js')); + expect(sourceFile.sources[0]!.rawMap).toEqual(null); + expect(sourceFile.sources[0]!.sources).toEqual([]); - expect(sourceFile.sources[1] !.contents).toEqual('y content'); - expect(sourceFile.sources[1] !.sourcePath).toEqual(_('/foo/src/y.js')); - expect(sourceFile.sources[1] !.rawMap).toEqual(ySourceMap); + expect(sourceFile.sources[1]!.contents).toEqual('y content'); + expect(sourceFile.sources[1]!.sourcePath).toEqual(_('/foo/src/y.js')); + expect(sourceFile.sources[1]!.rawMap).toEqual(ySourceMap); - expect(sourceFile.sources[1] !.sources.length).toEqual(1); - expect(sourceFile.sources[1] !.sources[0] !.contents).toEqual('a content'); - expect(sourceFile.sources[1] !.sources[0] !.sourcePath).toEqual(_('/foo/src/a.js')); - expect(sourceFile.sources[1] !.sources[0] !.rawMap).toEqual(null); - expect(sourceFile.sources[1] !.sources[0] !.sources).toEqual([]); + expect(sourceFile.sources[1]!.sources.length).toEqual(1); + expect(sourceFile.sources[1]!.sources[0]!.contents).toEqual('a content'); + expect(sourceFile.sources[1]!.sources[0]!.sourcePath).toEqual(_('/foo/src/a.js')); + expect(sourceFile.sources[1]!.sources[0]!.rawMap).toEqual(null); + expect(sourceFile.sources[1]!.sources[0]!.sources).toEqual([]); - expect(sourceFile.sources[2] !.contents).toEqual('z content'); - expect(sourceFile.sources[2] !.sourcePath).toEqual(_('/foo/src/z.js')); - expect(sourceFile.sources[2] !.rawMap).toEqual(null); - expect(sourceFile.sources[2] !.sources).toEqual([]); + expect(sourceFile.sources[2]!.contents).toEqual('z content'); + expect(sourceFile.sources[2]!.sourcePath).toEqual(_('/foo/src/z.js')); + expect(sourceFile.sources[2]!.rawMap).toEqual(null); + expect(sourceFile.sources[2]!.sources).toEqual([]); }); it('should handle a missing source file referenced from a source-map', () => { @@ -186,22 +187,25 @@ runInEachFileSystem(() => { const aPath = _('/foo/src/a.js'); fs.writeFile( - aPath, 'a content\n' + + aPath, + 'a content\n' + fromObject(createRawSourceMap({file: 'a.js', sources: ['b.js']})).toComment()); const bPath = _('/foo/src/b.js'); fs.writeFile( - bPath, 'b content\n' + + bPath, + 'b content\n' + fromObject(createRawSourceMap({file: 'b.js', sources: ['c.js']})).toComment()); const cPath = _('/foo/src/c.js'); fs.writeFile( - cPath, 'c content\n' + + cPath, + 'c content\n' + fromObject(createRawSourceMap({file: 'c.js', sources: ['a.js']})).toComment()); expect(() => registry.loadSourceFile(aPath)) - .toThrowError( - `Circular source file mapping dependency: ${aPath} -> ${bPath} -> ${cPath} -> ${aPath}`); + .toThrowError(`Circular source file mapping dependency: ${aPath} -> ${bPath} -> ${ + cPath} -> ${aPath}`); }); it('should not fail if there is a cyclic dependency in filenames of inline sources', () => { @@ -209,7 +213,8 @@ runInEachFileSystem(() => { const aPath = _('/foo/src/a.js'); fs.writeFile( - aPath, 'a content\n' + + aPath, + 'a content\n' + fromObject(createRawSourceMap({file: 'a.js', sources: ['b.js']})).toComment()); const bPath = _('/foo/src/b.js'); @@ -238,6 +243,7 @@ function createRawSourceMap(custom: Partial<RawSourceMap>): RawSourceMap { 'sources': [], 'sourcesContent': [], 'names': [], - 'mappings': '', ...custom + 'mappings': '', + ...custom }; } \ No newline at end of file diff --git a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts index 5c0456bc39f99..7b7f44c5292e3 100644 --- a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts +++ b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_spec.ts @@ -11,13 +11,15 @@ import {absoluteFrom} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {RawSourceMap} from '../../src/sourcemaps/raw_source_map'; import {SegmentMarker} from '../../src/sourcemaps/segment_marker'; -import {Mapping, SourceFile, computeStartOfLinePositions, ensureOriginalSegmentLinks, extractOriginalSegments, findLastMappingIndexBefore, parseMappings} from '../../src/sourcemaps/source_file'; +import {computeStartOfLinePositions, ensureOriginalSegmentLinks, extractOriginalSegments, findLastMappingIndexBefore, Mapping, parseMappings, SourceFile} from '../../src/sourcemaps/source_file'; runInEachFileSystem(() => { describe('SourceFile and utilities', () => { let _: typeof absoluteFrom; - beforeEach(() => { _ = absoluteFrom; }); + beforeEach(() => { + _ = absoluteFrom; + }); describe('parseMappings()', () => { it('should be an empty array for source files with no source map', () => { @@ -118,7 +120,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined}; const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0); @@ -133,7 +135,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined}; const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 0); @@ -147,7 +149,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 60, position: 60, next: undefined}; @@ -162,7 +164,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 5, position: 5, next: undefined}; @@ -180,7 +182,7 @@ runInEachFileSystem(() => { const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0); expect(index).toEqual(2); }); @@ -194,7 +196,7 @@ runInEachFileSystem(() => { const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0); expect(index).toEqual(3); }); @@ -209,7 +211,7 @@ runInEachFileSystem(() => { const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ true, 0); expect(index).toEqual(1); }); @@ -223,7 +225,7 @@ runInEachFileSystem(() => { const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const index = findLastMappingIndexBefore(mappings, marker3, /* exclusive */ false, 0); expect(index).toEqual(3); }); @@ -238,7 +240,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 35, position: 35, next: undefined}; const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 1); @@ -253,7 +255,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined}; const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 2); @@ -268,7 +270,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined}; const index = findLastMappingIndexBefore(mappings, marker, /* exclusive */ false, 3); @@ -282,7 +284,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 25, position: 25, next: undefined}; @@ -298,7 +300,7 @@ runInEachFileSystem(() => { const marker2: SegmentMarker = {line: 0, column: 20, position: 20, next: marker3}; const marker1: SegmentMarker = {line: 0, column: 10, position: 10, next: marker2}; const mappings: Mapping[] = [marker1, marker2, marker3, marker4, marker5].map( - marker => ({ generatedSegment: marker } as Mapping)); + marker => ({generatedSegment: marker} as Mapping)); const marker: SegmentMarker = {line: 0, column: 30, position: 30, next: undefined}; diff --git a/packages/compiler-cli/ngcc/test/utils_spec.ts b/packages/compiler-cli/ngcc/test/utils_spec.ts index e6c292df724ce..f373e5313a013 100644 --- a/packages/compiler-cli/ngcc/test/utils_spec.ts +++ b/packages/compiler-cli/ngcc/test/utils_spec.ts @@ -126,7 +126,7 @@ describe('getTsHelperFnFromDeclaration()', () => { const classDecl = ts.createClassDeclaration(undefined, undefined, '__assign', undefined, undefined, []); - expect(classDecl.name !.text).toBe('__assign'); + expect(classDecl.name!.text).toBe('__assign'); expect(getTsHelperFnFromDeclaration(classDecl)).toBe(null); }); }); diff --git a/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts b/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts index e8b2b5ec71ea9..5678d41a64421 100644 --- a/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/cleaning/cleaning_strategies_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, PathSegment, absoluteFrom, getFileSystem} from '../../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, PathSegment} from '../../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; import {EntryPointPackageJson} from '../../../src/packages/entry_point'; import {BackupFileCleaner, NgccDirectoryCleaner, PackageJsonCleaner} from '../../../src/writing/cleaning/cleaning_strategies'; @@ -21,9 +21,10 @@ runInEachFileSystem(() => { }); describe('PackageJsonCleaner', () => { - let packageJsonPath: AbsoluteFsPath; - beforeEach(() => { packageJsonPath = _abs('/node_modules/pkg/package.json'); }); + beforeEach(() => { + packageJsonPath = _abs('/node_modules/pkg/package.json'); + }); describe('canClean()', () => { it('should return true if the basename is package.json', () => { @@ -150,7 +151,6 @@ runInEachFileSystem(() => { }); describe('canClean()', () => { - it('should return true if the file name ends in .__ivy_ngcc_bak and the processed file exists', () => { const strategy = new BackupFileCleaner(fs); @@ -192,7 +192,9 @@ runInEachFileSystem(() => { describe('NgccDirectoryCleaner', () => { let ivyDirectory: AbsoluteFsPath; - beforeEach(() => { ivyDirectory = _abs('/node_modules/pkg/__ivy_ngcc__'); }); + beforeEach(() => { + ivyDirectory = _abs('/node_modules/pkg/__ivy_ngcc__'); + }); describe('canClean()', () => { it('should return true if the path is a directory and is called __ivy_ngcc__', () => { diff --git a/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.ts b/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.ts index 762d024461378..7260845cfe0c1 100644 --- a/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/cleaning/package_cleaner_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, PathSegment, absoluteFrom, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, PathSegment} from '@angular/compiler-cli/src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../../src/ngtsc/file_system/testing'; import {CleaningStrategy} from '../../../src/writing/cleaning/cleaning_strategies'; diff --git a/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts b/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts index 95eeae821f0e3..0b3d249bd35df 100644 --- a/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/in_place_file_writer_spec.ts @@ -14,7 +14,6 @@ import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { describe('InPlaceFileWriter', () => { - let _: typeof absoluteFrom; beforeEach(() => { @@ -79,8 +78,8 @@ runInEachFileSystem(() => { () => fileWriter.writeBundle( {} as EntryPointBundle, [{path: absoluteBackupPath, contents: 'MODIFIED BACKED UP'}])) - .toThrowError( - `Tried to overwrite ${absoluteBackupPath}.__ivy_ngcc_bak with an ngcc back up file, which is disallowed.`); + .toThrowError(`Tried to overwrite ${ + absoluteBackupPath}.__ivy_ngcc_bak with an ngcc back up file, which is disallowed.`); }); it('should log an error, and skip writing the file, if the backup file already exists and errorOnFailedEntryPoint is false', @@ -95,7 +94,9 @@ runInEachFileSystem(() => { expect(fs.readFile(absoluteBackupPath)).toEqual('ORIGINAL ALREADY BACKED UP'); expect(fs.readFile(_(absoluteBackupPath + '.__ivy_ngcc_bak'))).toEqual('BACKED UP'); expect(logger.logs.error).toEqual([[ - `Tried to write ${absoluteBackupPath}.__ivy_ngcc_bak with an ngcc back up file but it already exists so not writing, nor backing up, ${absoluteBackupPath}.\n` + + `Tried to write ${ + absoluteBackupPath}.__ivy_ngcc_bak with an ngcc back up file but it already exists so not writing, nor backing up, ${ + absoluteBackupPath}.\n` + `This error may be because two or more entry-points overlap and ngcc has been asked to process some files more than once.\n` + `You should check other entry-points in this package and set up a config to ignore any that you are not using.` ]]); diff --git a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts index a0a01c0911b37..5f361cbb4ebf1 100644 --- a/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/new_entry_point_file_writer_spec.ts @@ -5,11 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, getEntryPointInfo} from '../../src/packages/entry_point'; +import {EntryPoint, EntryPointFormat, EntryPointJsonProperty, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from '../../src/packages/entry_point'; import {EntryPointBundle, makeEntryPointBundle} from '../../src/packages/entry_point_bundle'; import {FileWriter} from '../../src/writing/file_writer'; import {NewEntryPointFileWriter} from '../../src/writing/new_entry_point_file_writer'; @@ -19,7 +19,6 @@ import {loadPackageJson} from '../packages/entry_point_spec'; runInEachFileSystem(() => { describe('NewEntryPointFileWriter', () => { - let _: typeof absoluteFrom; let fs: FileSystem; let fileWriter: FileWriter; @@ -107,7 +106,7 @@ runInEachFileSystem(() => { fs, logger, /* errorOnFailedEntryPoint */ true, new DirectPackageJsonUpdater(fs)); const config = new NgccConfiguration(fs, _('/')); const result = getEntryPointInfo( - fs, config, logger, _('/node_modules/test'), _('/node_modules/test')) !; + fs, config, logger, _('/node_modules/test'), _('/node_modules/test'))!; if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } @@ -247,7 +246,7 @@ runInEachFileSystem(() => { fs, logger, /* errorOnFailedEntryPoint */ true, new DirectPackageJsonUpdater(fs)); const config = new NgccConfiguration(fs, _('/')); const result = getEntryPointInfo( - fs, config, logger, _('/node_modules/test'), _('/node_modules/test/a')) !; + fs, config, logger, _('/node_modules/test'), _('/node_modules/test/a'))!; if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } @@ -376,7 +375,7 @@ runInEachFileSystem(() => { fs, logger, /* errorOnFailedEntryPoint */ true, new DirectPackageJsonUpdater(fs)); const config = new NgccConfiguration(fs, _('/')); const result = getEntryPointInfo( - fs, config, new MockLogger(), _('/node_modules/test'), _('/node_modules/test/b')) !; + fs, config, new MockLogger(), _('/node_modules/test'), _('/node_modules/test/b'))!; if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } @@ -501,6 +500,6 @@ runInEachFileSystem(() => { fs: FileSystem, entryPoint: EntryPoint, formatProperty: EntryPointJsonProperty, format: EntryPointFormat): EntryPointBundle { return makeEntryPointBundle( - fs, entryPoint, entryPoint.packageJson[formatProperty] !, false, format, true); + fs, entryPoint, entryPoint.packageJson[formatProperty]!, false, format, true); } }); diff --git a/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts b/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts index 56f6a9a64328e..8efe32c3baf49 100644 --- a/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts +++ b/packages/compiler-cli/ngcc/test/writing/package_json_updater_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {JsonObject} from '../../src/packages/entry_point'; From e893c5a3301fa54ef1d21a16dd30461d994ccc17 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz <ayaz.hafiz.1@gmail.com> Date: Tue, 23 Jul 2019 12:32:14 -0700 Subject: [PATCH 109/262] fix(compiler-cli): pass real source spans where they are empty (#31805) Some consumers of functions that take `ParseSourceSpan`s currently pass empty and incorrect source spans. This fixes those cases. PR Close #31805 --- .../src/ngtsc/annotations/src/directive.ts | 87 +++++++------- .../src/ngtsc/annotations/src/util.ts | 16 ++- .../ngtsc/annotations/test/directive_spec.ts | 107 +++++++++++------- .../compiler-cli/test/ngtsc/ngtsc_spec.ts | 25 ++++ packages/compiler/src/parse_util.ts | 4 - 5 files changed, 151 insertions(+), 88 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index a0caee7461317..9a2007386502f 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, EMPTY_SOURCE_SPAN, Expression, Identifiers, ParseError, ParsedHostBindings, R3DependencyMetadata, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings, verifyHostBindings} from '@angular/compiler'; +import {ConstantPool, Expression, Identifiers, ParseError, ParsedHostBindings, R3DependencyMetadata, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings, verifyHostBindings} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -21,7 +21,7 @@ import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFl import {getDirectiveDiagnostics, getProviderDiagnostics} from './diagnostics'; import {compileNgFactoryDefField} from './factory'; import {generateSetClassMetadataCall} from './metadata'; -import {findAngularDecorator, getConstructorDependencies, isAngularDecorator, readBaseClass, resolveProvidersRequiringFactory, unwrapConstructorDependencies, unwrapExpression, unwrapForwardRef, validateConstructorDependencies, wrapFunctionExpressionsInParens, wrapTypeReference} from './util'; +import {createSourceSpan, findAngularDecorator, getConstructorDependencies, isAngularDecorator, readBaseClass, resolveProvidersRequiringFactory, unwrapConstructorDependencies, unwrapExpression, unwrapForwardRef, validateConstructorDependencies, wrapFunctionExpressionsInParens, wrapTypeReference} from './util'; const EMPTY_OBJECT: {[key: string]: string} = {}; const FIELD_DECORATORS = [ @@ -320,7 +320,7 @@ export function extractDirectiveMetadata( outputs: {...outputsFromMeta, ...outputsFromFields}, queries, viewQueries, selector, fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), type, internalType, typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0, - typeSourceSpan: EMPTY_SOURCE_SPAN, usesInheritance, exportAs, providers + typeSourceSpan: createSourceSpan(clazz.name), usesInheritance, exportAs, providers }; return {decorator: directive, metadata}; } @@ -580,54 +580,61 @@ type StringMap<T> = { [key: string]: T; }; -export function extractHostBindings( - members: ClassMember[], evaluator: PartialEvaluator, coreModule: string | undefined, - metadata?: Map<string, ts.Expression>): ParsedHostBindings { - let hostMetadata: StringMap<string|Expression> = {}; - if (metadata && metadata.has('host')) { - const expr = metadata.get('host') !; - const hostMetaMap = evaluator.evaluate(expr); - if (!(hostMetaMap instanceof Map)) { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `Decorator host metadata must be an object`); +function evaluateHostExpressionBindings( + hostExpr: ts.Expression, evaluator: PartialEvaluator): ParsedHostBindings { + const hostMetaMap = evaluator.evaluate(hostExpr); + if (!(hostMetaMap instanceof Map)) { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, hostExpr, `Decorator host metadata must be an object`); + } + const hostMetadata: StringMap<string|Expression> = {}; + hostMetaMap.forEach((value, key) => { + // Resolve Enum references to their declared value. + if (value instanceof EnumValue) { + value = value.resolved; } - hostMetaMap.forEach((value, key) => { - // Resolve Enum references to their declared value. - if (value instanceof EnumValue) { - value = value.resolved; - } - if (typeof key !== 'string') { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, expr, - `Decorator host metadata must be a string -> string object, but found unparseable key`); - } + if (typeof key !== 'string') { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, hostExpr, + `Decorator host metadata must be a string -> string object, but found unparseable key`); + } - if (typeof value == 'string') { - hostMetadata[key] = value; - } else if (value instanceof DynamicValue) { - hostMetadata[key] = new WrappedNodeExpr(value.node as ts.Expression); - } else { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, expr, - `Decorator host metadata must be a string -> string object, but found unparseable value`); - } - }); - } + if (typeof value == 'string') { + hostMetadata[key] = value; + } else if (value instanceof DynamicValue) { + hostMetadata[key] = new WrappedNodeExpr(value.node as ts.Expression); + } else { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, hostExpr, + `Decorator host metadata must be a string -> string object, but found unparseable value`); + } + }); const bindings = parseHostBindings(hostMetadata); - // TODO: create and provide proper sourceSpan to make error message more descriptive (FW-995) - // For now, pass an incorrect (empty) but valid sourceSpan. - const errors = verifyHostBindings(bindings, EMPTY_SOURCE_SPAN); + const errors = verifyHostBindings(bindings, createSourceSpan(hostExpr)); if (errors.length > 0) { throw new FatalDiagnosticError( - // TODO: provide more granular diagnostic and output specific host expression that triggered - // an error instead of the whole host object - ErrorCode.HOST_BINDING_PARSE_ERROR, metadata !.get('host') !, + // TODO: provide more granular diagnostic and output specific host expression that + // triggered an error instead of the whole host object. + ErrorCode.HOST_BINDING_PARSE_ERROR, hostExpr, errors.map((error: ParseError) => error.msg).join('\n')); } + return bindings; +} + +export function extractHostBindings( + members: ClassMember[], evaluator: PartialEvaluator, coreModule: string | undefined, + metadata?: Map<string, ts.Expression>): ParsedHostBindings { + let bindings: ParsedHostBindings; + if (metadata && metadata.has('host')) { + bindings = evaluateHostExpressionBindings(metadata.get('host') !, evaluator); + } else { + bindings = parseHostBindings({}); + } + filterToMembersWithDecorator(members, 'HostBinding', coreModule).forEach(({member, decorators}) => { decorators.forEach(decorator => { let hostPropertyName: string = member.name; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts index 7cddaae9f8d75..c4a88684fc048 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, ExternalExpr, LiteralExpr, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; +import {Expression, ExternalExpr, LiteralExpr, ParseLocation, ParseSourceFile, ParseSourceSpan, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics'; @@ -475,3 +475,17 @@ export function wrapTypeReference(reflector: ReflectionHost, clazz: ClassDeclara value; return {value, type}; } + +/** Creates a ParseSourceSpan for a TypeScript node. */ +export function createSourceSpan(node: ts.Node): ParseSourceSpan { + const sf = node.getSourceFile(); + const [startOffset, endOffset] = [node.getStart(), node.getEnd()]; + const {line: startLine, character: startCol} = sf.getLineAndCharacterOfPosition(startOffset); + const {line: endLine, character: endCol} = sf.getLineAndCharacterOfPosition(endOffset); + const parseSf = new ParseSourceFile(sf.getFullText(), sf.fileName); + + // +1 because values are zero-indexed. + return new ParseSourceSpan( + new ParseLocation(parseSf, startOffset, startLine + 1, startCol + 1), + new ParseLocation(parseSf, endOffset, endLine + 1, endCol + 1)); +} diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts index b15e85ca63048..62ecab624ef88 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts @@ -5,6 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import * as ts from 'typescript'; import {absoluteFrom} from '../../file_system'; import {runInEachFileSystem} from '../../file_system/testing'; import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports'; @@ -16,10 +17,10 @@ import {getDeclaration, makeProgram} from '../../testing'; import {DirectiveDecoratorHandler} from '../src/directive'; runInEachFileSystem(() => { - describe('DirectiveDecoratorHandler', () => { - let _: typeof absoluteFrom; - beforeEach(() => _ = absoluteFrom); + let _: typeof absoluteFrom; + beforeEach(() => _ = absoluteFrom); + describe('DirectiveDecoratorHandler', () => { it('should use the `ReflectionHost` to detect class inheritance', () => { const {program} = makeProgram([ { @@ -40,53 +41,73 @@ runInEachFileSystem(() => { }, ]); - const checker = program.getTypeChecker(); - const reflectionHost = new TestReflectionHost(checker); - const evaluator = new PartialEvaluator(reflectionHost, checker, /* dependencyTracker */ null); - const metaReader = new LocalMetadataRegistry(); - const dtsReader = new DtsMetadataReader(checker, reflectionHost); - const scopeRegistry = new LocalModuleScopeRegistry( - metaReader, new MetadataDtsModuleScopeResolver(dtsReader, null), new ReferenceEmitter([]), - null); - const injectableRegistry = new InjectableClassRegistry(reflectionHost); - const handler = new DirectiveDecoratorHandler( - reflectionHost, evaluator, scopeRegistry, scopeRegistry, metaReader, - NOOP_DEFAULT_IMPORT_RECORDER, injectableRegistry, - /* isCore */ false, /* annotateForClosureCompiler */ false); - - const analyzeDirective = (dirName: string) => { - const DirNode = getDeclaration(program, _('/entry.ts'), dirName, isNamedClassDeclaration); - - const detected = - handler.detect(DirNode, reflectionHost.getDecoratorsOfDeclaration(DirNode)); - if (detected === undefined) { - throw new Error(`Failed to recognize @Directive (${dirName}).`); - } - - const {analysis} = handler.analyze(DirNode, detected.metadata); - if (analysis === undefined) { - throw new Error(`Failed to analyze @Directive (${dirName}).`); - } - - return analysis; - }; - - // By default, `TestReflectionHost#hasBaseClass()` returns `false`. - const analysis1 = analyzeDirective('TestDir1'); + const analysis1 = analyzeDirective(program, 'TestDir1', /*hasBaseClass*/ false); expect(analysis1.meta.usesInheritance).toBe(false); - // Tweak `TestReflectionHost#hasBaseClass()` to return true. - reflectionHost.hasBaseClassReturnValue = true; - - const analysis2 = analyzeDirective('TestDir2'); + const analysis2 = analyzeDirective(program, 'TestDir2', /*hasBaseClass*/ true); expect(analysis2.meta.usesInheritance).toBe(true); }); + + it('should record the source span of a Directive class type', () => { + const src = ` + import {Directive} from '@angular/core'; + + @Directive({selector: 'test-dir'}) + export class TestDir {} + `; + const {program} = makeProgram([ + { + name: _('/node_modules/@angular/core/index.d.ts'), + contents: 'export const Directive: any;', + }, + { + name: _('/entry.ts'), + contents: src, + }, + ]); + + const analysis = analyzeDirective(program, 'TestDir'); + const span = analysis.meta.typeSourceSpan; + expect(span.toString()).toBe('TestDir'); + expect(span.start.toString()).toContain('/entry.ts@5:22'); + expect(span.end.toString()).toContain('/entry.ts@5:29'); + }); }); // Helpers - class TestReflectionHost extends TypeScriptReflectionHost { - hasBaseClassReturnValue = false; + function analyzeDirective(program: ts.Program, dirName: string, hasBaseClass: boolean = false) { + class TestReflectionHost extends TypeScriptReflectionHost { + constructor(checker: ts.TypeChecker) { super(checker); } + + hasBaseClass(_class: ClassDeclaration): boolean { return hasBaseClass; } + } + + const checker = program.getTypeChecker(); + const reflectionHost = new TestReflectionHost(checker); + const evaluator = new PartialEvaluator(reflectionHost, checker, /*dependencyTracker*/ null); + const metaReader = new LocalMetadataRegistry(); + const dtsReader = new DtsMetadataReader(checker, reflectionHost); + const scopeRegistry = new LocalModuleScopeRegistry( + metaReader, new MetadataDtsModuleScopeResolver(dtsReader, null), new ReferenceEmitter([]), + null); + const injectableRegistry = new InjectableClassRegistry(reflectionHost); + const handler = new DirectiveDecoratorHandler( + reflectionHost, evaluator, scopeRegistry, scopeRegistry, metaReader, + NOOP_DEFAULT_IMPORT_RECORDER, injectableRegistry, /*isCore*/ false, + /*annotateForClosureCompiler*/ false); + + const DirNode = getDeclaration(program, _('/entry.ts'), dirName, isNamedClassDeclaration); + + const detected = handler.detect(DirNode, reflectionHost.getDecoratorsOfDeclaration(DirNode)); + if (detected === undefined) { + throw new Error(`Failed to recognize @Directive (${dirName}).`); + } + + const {analysis} = handler.analyze(DirNode, detected.metadata); + if (analysis === undefined) { + throw new Error(`Failed to analyze @Directive (${dirName}).`); + } - hasBaseClass(clazz: ClassDeclaration): boolean { return this.hasBaseClassReturnValue; } + return analysis; } }); diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index db54ed8e055ac..6131de87df807 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -37,6 +37,10 @@ const setClassMetadataRegExp = (expectedType: string): RegExp => const testFiles = loadStandardTestFiles(); +function getDiagnosticSourceCode(diag: ts.Diagnostic): string { + return diag.file !.text.substr(diag.start !, diag.length !); +} + runInEachFileSystem(os => { describe('ngtsc behavioral tests', () => { let env !: NgtscTestEnvironment; @@ -2897,6 +2901,27 @@ runInEachFileSystem(os => { `Unexpected global target 'UnknownTarget' defined for 'click' event. Supported list of global targets: window,document,body.`); }); + it('should provide error location for invalid host properties', () => { + env.write('test.ts', ` + import {Component} from '@angular/core'; + + @Component({ + selector: 'test', + template: '...', + host: { + '(click)': 'act() | pipe', + } + }) + class FooCmp {} + `); + + const errors = env.driveDiagnostics(); + expect(getDiagnosticSourceCode(errors[0])).toBe(`{ + '(click)': 'act() | pipe', + }`); + expect(errors[0].messageText).toContain('/test.ts@7:17'); + }); + it('should throw in case pipes are used in host listeners', () => { env.write(`test.ts`, ` import {Component} from '@angular/core'; diff --git a/packages/compiler/src/parse_util.ts b/packages/compiler/src/parse_util.ts index 8935dfc26aaed..e6e7c30758ca2 100644 --- a/packages/compiler/src/parse_util.ts +++ b/packages/compiler/src/parse_util.ts @@ -7,7 +7,6 @@ */ import * as chars from './chars'; import {CompileIdentifierMetadata, identifierModuleUrl, identifierName} from './compile_metadata'; -import {error} from './util'; export class ParseLocation { constructor( @@ -109,9 +108,6 @@ export class ParseSourceSpan { } } -export const EMPTY_PARSE_LOCATION = new ParseLocation(new ParseSourceFile('', ''), 0, 0, 0); -export const EMPTY_SOURCE_SPAN = new ParseSourceSpan(EMPTY_PARSE_LOCATION, EMPTY_PARSE_LOCATION); - export enum ParseErrorLevel { WARNING, ERROR, From f40d51733ab7f598aa419006322051106534f407 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Fri, 20 Mar 2020 12:24:12 -0700 Subject: [PATCH 110/262] fix(dev-infra): use commit message validation from @angular/dev-infra-private (#36172) Prior to this change we manage a local version of commit message validation in addition to the commit message validation tool contained in the ng-dev tooling. By adding the ability to validate a range of commit messages together, the remaining piece of commit message validation that is in the local version is replicated. We use both commands provided by the `ng-dev commit-message` tooling: - pre-commit-validate: Set to automatically run on an git hook to validate commits as they are created locally. - validate-range: Run by CI for every PR, testing that all of the commits added by the PR are valid when considered together. Ensuring that all fixups are matched to another commit in the change. PR Close #36172 --- .circleci/config.yml | 5 +- .pullapprove.yml | 1 - dev-infra/commit-message/BUILD.bazel | 3 + dev-infra/commit-message/cli.ts | 33 ++- dev-infra/commit-message/config.ts | 2 +- dev-infra/commit-message/validate-file.ts | 3 + dev-infra/commit-message/validate-range.ts | 45 ++++ dev-infra/commit-message/validate.spec.ts | 54 ++-- dev-infra/commit-message/validate.ts | 27 +- gulpfile.js | 3 +- package.json | 2 +- scripts/git/commit-msg.js | 34 --- tools/gulp-tasks/validate-commit-message.js | 92 ------- tools/validate-commit-message/BUILD.bazel | 9 - .../commit-message.json | 44 ---- tools/validate-commit-message/index.js | 9 - .../validate-commit-message.js | 100 -------- .../validate-commit-message.spec.js | 234 ------------------ 18 files changed, 130 insertions(+), 570 deletions(-) create mode 100644 dev-infra/commit-message/validate-range.ts delete mode 100755 scripts/git/commit-msg.js delete mode 100644 tools/gulp-tasks/validate-commit-message.js delete mode 100644 tools/validate-commit-message/BUILD.bazel delete mode 100644 tools/validate-commit-message/commit-message.json delete mode 100644 tools/validate-commit-message/index.js delete mode 100644 tools/validate-commit-message/validate-commit-message.js delete mode 100644 tools/validate-commit-message/validate-commit-message.spec.js diff --git a/.circleci/config.yml b/.circleci/config.yml index d628e5dce489f..3c45a7265481a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -278,9 +278,10 @@ jobs: - run: 'yarn bazel:lint || (echo -e "\n.bzl files have lint errors. Please run ''yarn bazel:lint-fix''"; exit 1)' - - run: yarn lint --branch $CI_GIT_BASE_REVISION - - run: yarn ts-circular-deps:check + - run: yarn -s lint --branch $CI_GIT_BASE_REVISION + - run: yarn -s ts-circular-deps:check - run: yarn -s ng-dev pullapprove verify + - run: yarn -s ng-dev commit-message validate-range --range $CI_COMMIT_RANGE test: executor: diff --git a/.pullapprove.yml b/.pullapprove.yml index 2d181f59c6093..6d79b06082e3e 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -981,7 +981,6 @@ groups: 'tools/ts-api-guardian/**', 'tools/tslint/**', 'tools/utils/**', - 'tools/validate-commit-message/**', 'tools/yarn/**', 'tools/*', '**/*.bzl', diff --git a/dev-infra/commit-message/BUILD.bazel b/dev-infra/commit-message/BUILD.bazel index fe11b49270bfb..1197df1dcc9dd 100644 --- a/dev-infra/commit-message/BUILD.bazel +++ b/dev-infra/commit-message/BUILD.bazel @@ -8,13 +8,16 @@ ts_library( "config.ts", "validate.ts", "validate-file.ts", + "validate-range.ts", ], module_name = "@angular/dev-infra-private/commit-message", visibility = ["//dev-infra:__subpackages__"], deps = [ "//dev-infra/utils:config", "@npm//@types/node", + "@npm//@types/shelljs", "@npm//@types/yargs", + "@npm//shelljs", "@npm//tslib", "@npm//yargs", ], diff --git a/dev-infra/commit-message/cli.ts b/dev-infra/commit-message/cli.ts index 83bd1b8a664b8..aada6a317818e 100644 --- a/dev-infra/commit-message/cli.ts +++ b/dev-infra/commit-message/cli.ts @@ -7,13 +7,38 @@ */ import * as yargs from 'yargs'; import {validateFile} from './validate-file'; +import {validateCommitRange} from './validate-range'; /** Build the parser for the commit-message commands. */ export function buildCommitMessageParser(localYargs: yargs.Argv) { - return localYargs.help().strict().command( - 'pre-commit-validate', 'Validate the most recent commit message', {}, () => { - validateFile('.git/COMMIT_EDITMSG'); - }); + return localYargs.help() + .strict() + .command( + 'pre-commit-validate', 'Validate the most recent commit message', {}, + () => { + validateFile('.git/COMMIT_EDITMSG'); + }) + .command( + 'validate-range', 'Validate a range of commit messages', { + 'range': { + description: 'The range of commits to check, e.g. --range abc123..xyz456', + demandOption: ' A range must be provided, e.g. --range abc123..xyz456', + type: 'string', + requiresArg: true, + }, + }, + argv => { + // If on CI, and not pull request number is provided, assume the branch + // being run on is an upstream branch. + if (process.env['CI'] && process.env['CI_PULL_REQUEST'] === 'false') { + console.info( + `Since valid commit messages are enforced by PR linting on CI, we do not\n` + + `need to validate commit messages on CI runs on upstream branches.\n\n` + + `Skipping check of provided commit range`); + return; + } + validateCommitRange(argv.range); + }); } if (require.main == module) { diff --git a/dev-infra/commit-message/config.ts b/dev-infra/commit-message/config.ts index 8b01bf3053a0f..4085e809b170d 100644 --- a/dev-infra/commit-message/config.ts +++ b/dev-infra/commit-message/config.ts @@ -10,4 +10,4 @@ export interface CommitMessageConfig { minBodyLength: number; types: string[]; scopes: string[]; -} \ No newline at end of file +} diff --git a/dev-infra/commit-message/validate-file.ts b/dev-infra/commit-message/validate-file.ts index 1bac796df1dfb..b5c02555a971d 100644 --- a/dev-infra/commit-message/validate-file.ts +++ b/dev-infra/commit-message/validate-file.ts @@ -17,5 +17,8 @@ export function validateFile(filePath: string) { const commitMessage = readFileSync(join(getRepoBaseDir(), filePath), 'utf8'); if (validateCommitMessage(commitMessage)) { console.info('√ Valid commit message'); + return; } + // If the validation did not return true, exit as a failure. + process.exit(1); } diff --git a/dev-infra/commit-message/validate-range.ts b/dev-infra/commit-message/validate-range.ts new file mode 100644 index 0000000000000..4da1f681e214b --- /dev/null +++ b/dev-infra/commit-message/validate-range.ts @@ -0,0 +1,45 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +import {exec} from 'shelljs'; +import {parseCommitMessage, validateCommitMessage, ValidateCommitMessageOptions} from './validate'; + +// Whether the provided commit is a fixup commit. +const isNonFixup = (m: string) => !parseCommitMessage(m).isFixup; + +/** Validate all commits in a provided git commit range. */ +export function validateCommitRange(range: string) { + // A random value is used as a string to allow for a definite split point in the git log result. + const randomValueSeparator = `${Math.random()}`; + // Custom git log format that provides the commit header and body, separated as expected with + // the custom separator as the trailing value. + const gitLogFormat = `%s%n%n%b${randomValueSeparator}`; + + // Retrieve the commits in the provided range. + const result = exec(`git log --reverse --format=${gitLogFormat} ${range}`, {silent: true}); + if (result.code) { + throw new Error(`Failed to get all commits in the range: \n ${result.stderr}`); + } + + // Separate the commits from a single string into individual commits + const commits = result.split(randomValueSeparator).map(l => l.trim()).filter(line => !!line); + + console.info(`Examining ${commits.length} commit(s) in the provided range: ${range}`); + + // Check each commit in the commit range. Commits are allowed to be fixup commits for other + // commits in the provided commit range. + const allCommitsInRangeValid = commits.every((m, i) => { + const options: ValidateCommitMessageOptions = { + disallowSquash: true, + nonFixupCommitHeaders: isNonFixup(m) ? undefined : commits.slice(0, i).filter(isNonFixup) + }; + return validateCommitMessage(m, options); + }); + if (allCommitsInRangeValid) { + console.info('√ All commit messages in range valid.'); + } +} diff --git a/dev-infra/commit-message/validate.spec.ts b/dev-infra/commit-message/validate.spec.ts index f9f3166f06778..3029613e11cf8 100644 --- a/dev-infra/commit-message/validate.spec.ts +++ b/dev-infra/commit-message/validate.spec.ts @@ -50,7 +50,6 @@ describe('validate-commit-message.js', () => { }); describe('validateMessage()', () => { - it('should be valid', () => { expect(validateCommitMessage('feat(packaging): something')).toBe(VALID); expect(lastError).toBe(''); @@ -66,7 +65,6 @@ describe('validate-commit-message.js', () => { expect(validateCommitMessage('Revert: "release(packaging): something"')).toBe(VALID); expect(lastError).toBe(''); - }); it('should validate max length', () => { @@ -74,8 +72,8 @@ describe('validate-commit-message.js', () => { 'fix(compiler): something super mega extra giga tera long, maybe even longer and longer and longer and longer and longer and longer...'; expect(validateCommitMessage(msg)).toBe(INVALID); - expect(lastError).toContain( - `The commit message header is longer than ${config.commitMessage.maxLineLength} characters`); + expect(lastError).toContain(`The commit message header is longer than ${ + config.commitMessage.maxLineLength} characters`); }); it('should validate "<type>(<scope>): <subject>" format', () => { @@ -130,7 +128,6 @@ describe('validate-commit-message.js', () => { }); describe('(revert)', () => { - it('should allow valid "revert: ..." syntaxes', () => { expect(validateCommitMessage('revert: anything')).toBe(VALID); expect(lastError).toBe(''); @@ -143,7 +140,6 @@ describe('validate-commit-message.js', () => { expect(validateCommitMessage('rEvErT anything')).toBe(VALID); expect(lastError).toBe(''); - }); it('should not allow "revert(scope): ..." syntax', () => { @@ -164,31 +160,29 @@ describe('validate-commit-message.js', () => { }); describe('(squash)', () => { - it('should strip the `squash! ` prefix and validate the rest', () => { const errorMessage = `The commit message header does not match the expected format.`; // Valid messages. expect(validateCommitMessage('squash! feat(core): add feature')).toBe(VALID); - expect(validateCommitMessage('squash! fix: a bug', false)).toBe(VALID); + expect(validateCommitMessage('squash! fix: a bug', {disallowSquash: false})).toBe(VALID); // Invalid messages. - expect(validateCommitMessage('squash! fix a typo', false)).toBe(INVALID); + expect(validateCommitMessage('squash! fix a typo', {disallowSquash: false})).toBe(INVALID); expect(lastError).toContain('squash! fix a typo'); expect(lastError).toContain(errorMessage); expect(validateCommitMessage('squash! squash! fix: a bug')).toBe(INVALID); expect(lastError).toContain('squash! squash! fix: a bug'); expect(lastError).toContain(errorMessage); - - }); describe('with `disallowSquash`', () => { - it('should fail', () => { - expect(validateCommitMessage('fix(core): something', true)).toBe(VALID); - expect(validateCommitMessage('squash! fix(core): something', true)).toBe(INVALID); + expect(validateCommitMessage('fix(core): something', {disallowSquash: true})).toBe(VALID); + expect(validateCommitMessage('squash! fix(core): something', { + disallowSquash: true + })).toBe(INVALID); expect(lastError).toContain( 'The commit must be manually squashed into the target commit'); }); @@ -196,9 +190,7 @@ describe('validate-commit-message.js', () => { }); describe('(fixup)', () => { - describe('without `nonFixupCommitHeaders`', () => { - it('should strip the `fixup! ` prefix and validate the rest', () => { const errorMessage = `The commit message header does not match the expected format.`; @@ -214,21 +206,26 @@ describe('validate-commit-message.js', () => { expect(validateCommitMessage('fixup! fixup! fix: a bug')).toBe(INVALID); expect(lastError).toContain('fixup! fixup! fix: a bug'); expect(lastError).toContain(errorMessage); - - }); }); describe('with `nonFixupCommitHeaders`', () => { - it('should check that the fixup commit matches a non-fixup one', () => { const msg = 'fixup! foo'; - expect(validateCommitMessage(msg, false, ['foo', 'bar', 'baz'])).toBe(VALID); - expect(validateCommitMessage(msg, false, ['bar', 'baz', 'foo'])).toBe(VALID); - expect(validateCommitMessage(msg, false, ['baz', 'foo', 'bar'])).toBe(VALID); - - expect(validateCommitMessage(msg, false, ['qux', 'quux', 'quuux'])).toBe(INVALID); + expect(validateCommitMessage( + msg, {disallowSquash: false, nonFixupCommitHeaders: ['foo', 'bar', 'baz']})) + .toBe(VALID); + expect(validateCommitMessage( + msg, {disallowSquash: false, nonFixupCommitHeaders: ['bar', 'baz', 'foo']})) + .toBe(VALID); + expect(validateCommitMessage( + msg, {disallowSquash: false, nonFixupCommitHeaders: ['baz', 'foo', 'bar']})) + .toBe(VALID); + + expect(validateCommitMessage( + msg, {disallowSquash: false, nonFixupCommitHeaders: ['qux', 'quux', 'quuux']})) + .toBe(INVALID); expect(lastError).toContain( 'Unable to find match for fixup commit among prior commits: \n' + ' qux\n' + @@ -237,8 +234,13 @@ describe('validate-commit-message.js', () => { }); it('should fail if `nonFixupCommitHeaders` is empty', () => { - expect(validateCommitMessage('refactor(core): make reactive', false, [])).toBe(VALID); - expect(validateCommitMessage('fixup! foo', false, [])).toBe(INVALID); + expect(validateCommitMessage('refactor(core): make reactive', { + disallowSquash: false, + nonFixupCommitHeaders: [] + })).toBe(VALID); + expect(validateCommitMessage( + 'fixup! foo', {disallowSquash: false, nonFixupCommitHeaders: []})) + .toBe(INVALID); expect(lastError).toContain( `Unable to find match for fixup commit among prior commits: -`); }); diff --git a/dev-infra/commit-message/validate.ts b/dev-infra/commit-message/validate.ts index 1213cd416c43a..7088b9081cbc0 100644 --- a/dev-infra/commit-message/validate.ts +++ b/dev-infra/commit-message/validate.ts @@ -8,6 +8,12 @@ import {getAngularDevConfig} from '../utils/config'; import {CommitMessageConfig} from './config'; +/** Options for commit message validation. */ +export interface ValidateCommitMessageOptions { + disallowSquash?: boolean; + nonFixupCommitHeaders?: string[]; +} + const FIXUP_PREFIX_RE = /^fixup! /i; const GITHUB_LINKING_RE = /((closed?s?)|(fix(es)?(ed)?)|(resolved?s?))\s\#(\d+)/ig; const SQUASH_PREFIX_RE = /^squash! /i; @@ -26,17 +32,17 @@ export function parseCommitMessage(commitMsg: string) { let subject = ''; if (COMMIT_HEADER_RE.test(commitMsg)) { - header = COMMIT_HEADER_RE.exec(commitMsg) ![1] + header = COMMIT_HEADER_RE.exec(commitMsg)![1] .replace(FIXUP_PREFIX_RE, '') .replace(SQUASH_PREFIX_RE, ''); } if (COMMIT_BODY_RE.test(commitMsg)) { - body = COMMIT_BODY_RE.exec(commitMsg) ![1]; + body = COMMIT_BODY_RE.exec(commitMsg)![1]; bodyWithoutLinking = body.replace(GITHUB_LINKING_RE, ''); } if (TYPE_SCOPE_RE.test(header)) { - const parsedCommitHeader = TYPE_SCOPE_RE.exec(header) !; + const parsedCommitHeader = TYPE_SCOPE_RE.exec(header)!; type = parsedCommitHeader[1]; scope = parsedCommitHeader[2]; subject = parsedCommitHeader[3]; @@ -54,10 +60,9 @@ export function parseCommitMessage(commitMsg: string) { }; } - /** Validate a commit message against using the local repo's config. */ export function validateCommitMessage( - commitMsg: string, disallowSquash: boolean = false, nonFixupCommitHeaders?: string[]) { + commitMsg: string, options: ValidateCommitMessageOptions = {}) { function error(errorMessage: string) { console.error( `INVALID COMMIT MSG: \n` + @@ -78,7 +83,7 @@ export function validateCommitMessage( return true; } - if (commit.isSquash && disallowSquash) { + if (commit.isSquash && options.disallowSquash) { error('The commit must be manually squashed into the target commit'); return false; } @@ -86,11 +91,11 @@ export function validateCommitMessage( // If it is a fixup commit and `nonFixupCommitHeaders` is not empty, we only care to check whether // there is a corresponding non-fixup commit (i.e. a commit whose header is identical to this // commit's header after stripping the `fixup! ` prefix). - if (commit.isFixup && nonFixupCommitHeaders) { - if (!nonFixupCommitHeaders.includes(commit.header)) { + if (commit.isFixup && options.nonFixupCommitHeaders) { + if (!options.nonFixupCommitHeaders.includes(commit.header)) { error( 'Unable to find match for fixup commit among prior commits: ' + - (nonFixupCommitHeaders.map(x => `\n ${x}`).join('') || '-')); + (options.nonFixupCommitHeaders.map(x => `\n ${x}`).join('') || '-')); return false; } @@ -118,8 +123,8 @@ export function validateCommitMessage( } if (commit.bodyWithoutLinking.trim().length < config.minBodyLength) { - error( - `The commit message body does not meet the minimum length of ${config.minBodyLength} characters`); + error(`The commit message body does not meet the minimum length of ${ + config.minBodyLength} characters`); return false; } diff --git a/gulpfile.js b/gulpfile.js index 35852b3103169..eed70c10b73f0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -49,8 +49,7 @@ gulp.task('format:changed:enforce', ['format:untracked:enforce', 'format:diff:en // Alias for `format:changed` that formerly formatted all files. gulp.task('format', ['format:changed']); -gulp.task('lint', ['format:changed:enforce', 'validate-commit-messages']); -gulp.task('validate-commit-messages', loadTask('validate-commit-message')); +gulp.task('lint', ['format:changed:enforce']); gulp.task('source-map-test', loadTask('source-map-test')); gulp.task('changelog', loadTask('changelog')); gulp.task('changelog:zonejs', loadTask('changelog-zonejs')); diff --git a/package.json b/package.json index 0d77e7f75ffe0..5b6197158ce0b 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "preinstall": "node tools/yarn/check-yarn.js", "postinstall": "node scripts/webdriver-manager-update.js && node --preserve-symlinks --preserve-symlinks-main ./tools/postinstall-patches.js", "check-env": "gulp check-env", - "commitmsg": "node ./scripts/git/commit-msg.js", + "commitmsg": "yarn -s ng-dev commit-message pre-commit-validate", "test-ivy-aot": "bazelisk test --config=ivy --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot", "test-non-ivy": "bazelisk test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only", "test-fixme-ivy-aot": "bazelisk test --config=ivy --build_tag_filters=-no-ivy-aot --test_tag_filters=-no-ivy-aot", diff --git a/scripts/git/commit-msg.js b/scripts/git/commit-msg.js deleted file mode 100755 index 7b80d058f92cf..0000000000000 --- a/scripts/git/commit-msg.js +++ /dev/null @@ -1,34 +0,0 @@ -#! /usr/bin/env node -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// git commit-msg hook to check the commit message against Angular conventions -// see `/CONTRIBUTING.md` for mode details. - -'use strict'; - -const fs = require('fs'); -const checkMsg = require('../../tools/validate-commit-message'); -const msgFile = process.env['GIT_PARAMS']; - -let isValid = true; - -if (msgFile) { - const commitMsg = fs.readFileSync(msgFile, {encoding: 'utf-8'}); - const firstLine = commitMsg.split('\n')[0]; - isValid = checkMsg(firstLine); - - if (!isValid) { - console.error( - '\nCheck CONTRIBUTING.md at the root of the repo for more information.' + - '\n' + - '\n(In case you need the invalid commit message, it should be stored in \'.git/COMMIT_EDITMSG\'.)'); - } -} - -process.exit(isValid ? 0 : 1); diff --git a/tools/gulp-tasks/validate-commit-message.js b/tools/gulp-tasks/validate-commit-message.js deleted file mode 100644 index 5761856c0c4e6..0000000000000 --- a/tools/gulp-tasks/validate-commit-message.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - - -// tslint:disable:no-console -module.exports = (gulp) => async() => { - try { - const validateCommitMessage = require('../validate-commit-message'); - const shelljs = require('shelljs'); - const getRefsAndShasForTarget = require('../utils/get-refs-and-shas-for-target'); - - // Break on error. - shelljs.set('-e'); - - - let target = {}; - if (process.env['CI'] === 'true') { - // Validation of commit messages on CI - if (process.env['CI_PULL_REQUEST'] === 'false') { - // Skip commit message validation on CI for non-PR branches as we are not testing new - // unreviewed commits. By enforcing correctness on the incoming changes in the PR - // branches, we are able to render this check unnecessary on non-PR branches. - console.info( - `Since valid commit messages are enforced by PR linting on CI,\n` + - `we do not need to validate commit messages on CI runs on upstream branches.\n\n` + - `Skipping validate-commit-message check`); - process.exit(); - } - target = await getRefsAndShasForTarget(process.env['CI_PULL_REQUEST']); - } else { - // Validation of commit messages locally - const baseRef = 'master'; - const headRef = shelljs.exec('git symbolic-ref --short HEAD', {silent: true}).trim(); - const baseSha = shelljs.exec(`git rev-parse origin/master`, {silent: true}).trim(); - const headSha = shelljs.exec(`git rev-parse HEAD`, {silent: true}).trim(); - const commonAncestorSha = - shelljs.exec(`git merge-base origin/master ${headSha}`, {silent: true}).trim(); - target = { - base: { - ref: baseRef, - sha: baseSha, - }, - head: { - ref: headRef, - sha: headSha, - }, - commonAncestorSha: commonAncestorSha, - latestShaOfTargetBranch: baseSha, - latestShaOfPrBranch: headSha, - }; - } - - const result = shelljs.exec( - `git log --reverse --format=%s ${target.commonAncestorSha}..${target.latestShaOfPrBranch}`, - {silent: true}); - - if (result.code) { - throw new Error(`Failed to fetch commits: ${result.stderr}`); - } - - const commitsByLine = result.trim().split(/\n/).filter(line => line != ''); - - console.log(`Examining ${commitsByLine.length} commit(s) between ${target.base.ref} and HEAD`); - - if (commitsByLine.length == 0) { - console.log(`There are zero new commits between ${target.base.ref} and HEAD`); - } - - const disallowSquashCommits = true; - const isNonFixup = m => !validateCommitMessage.FIXUP_PREFIX_RE.test(m); - const someCommitsInvalid = !commitsByLine.every((m, i) => { - // `priorNonFixupCommits` is only needed if the current commit is a fixup commit. - const priorNonFixupCommits = - isNonFixup(m) ? undefined : commitsByLine.slice(0, i).filter(isNonFixup); - return validateCommitMessage(m, disallowSquashCommits, priorNonFixupCommits); - }); - - if (someCommitsInvalid) { - throw new Error( - 'Please fix the failing commit messages before continuing...\n' + - 'Commit message guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines'); - } - } catch (err) { - console.error(err); - process.exit(1); - } -}; diff --git a/tools/validate-commit-message/BUILD.bazel b/tools/validate-commit-message/BUILD.bazel deleted file mode 100644 index 29c0c64cc055a..0000000000000 --- a/tools/validate-commit-message/BUILD.bazel +++ /dev/null @@ -1,9 +0,0 @@ -load("//tools:defaults.bzl", "jasmine_node_test") - -jasmine_node_test( - name = "validate-commit-message", - srcs = glob(["*.js"]), - data = [ - "commit-message.json", - ], -) diff --git a/tools/validate-commit-message/commit-message.json b/tools/validate-commit-message/commit-message.json deleted file mode 100644 index 09d8e70e0e6b0..0000000000000 --- a/tools/validate-commit-message/commit-message.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "maxLength": 120, - "types": [ - "build", - "ci", - "docs", - "feat", - "fix", - "perf", - "refactor", - "release", - "style", - "test" - ], - "scopes": [ - "animations", - "bazel", - "benchpress", - "changelog", - "common", - "compiler", - "compiler-cli", - "core", - "dev-infra", - "docs-infra", - "elements", - "forms", - "http", - "language-service", - "localize", - "ngcc", - "packaging", - "platform-browser", - "platform-browser-dynamic", - "platform-server", - "platform-webworker", - "platform-webworker-dynamic", - "router", - "service-worker", - "upgrade", - "ve", - "zone.js" - ] -} diff --git a/tools/validate-commit-message/index.js b/tools/validate-commit-message/index.js deleted file mode 100644 index 6e45729380a00..0000000000000 --- a/tools/validate-commit-message/index.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -module.exports = require('./validate-commit-message'); \ No newline at end of file diff --git a/tools/validate-commit-message/validate-commit-message.js b/tools/validate-commit-message/validate-commit-message.js deleted file mode 100644 index e264f0f513cd6..0000000000000 --- a/tools/validate-commit-message/validate-commit-message.js +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env node - -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * GIT commit message format enforcement - * - * Note: this script was originally written by Vojta for AngularJS :-) - */ - -'use strict'; - -const config = require('./commit-message.json'); -const FIXUP_PREFIX_RE = /^fixup! /i; -const SQUASH_PREFIX_RE = /^squash! /i; -const REVERT_PREFIX_RE = /^revert:? /i; - -module.exports = (commitHeader, disallowSquash, nonFixupCommitHeaders) => { - if (REVERT_PREFIX_RE.test(commitHeader)) { - return true; - } - - const {header, type, scope, isFixup, isSquash} = parseCommitHeader(commitHeader); - - if (isSquash && disallowSquash) { - error('The commit must be manually squashed into the target commit', commitHeader); - return false; - } - - // If it is a fixup commit and `nonFixupCommitHeaders` is not empty, we only care to check whether - // there is a corresponding non-fixup commit (i.e. a commit whose header is identical to this - // commit's header after stripping the `fixup! ` prefix). - if (isFixup && nonFixupCommitHeaders) { - if (!nonFixupCommitHeaders.includes(header)) { - error( - 'Unable to find match for fixup commit among prior commits: ' + - (nonFixupCommitHeaders.map(x => `\n ${x}`).join('') || '-'), - commitHeader); - return false; - } - - return true; - } - - if (header.length > config.maxLength) { - error(`The commit message header is longer than ${config.maxLength} characters`, commitHeader); - return false; - } - - if (!type) { - const format = '<type>(<scope>): <subject>'; - error( - `The commit message header does not match the format of '${format}' or 'Revert: "${format}"'`, - commitHeader); - return false; - } - - if (!config.types.includes(type)) { - error(`'${type}' is not an allowed type.\n => TYPES: ${config.types.join(', ')}`, commitHeader); - return false; - } - - if (scope && !config.scopes.includes(scope)) { - error( - `'${scope}' is not an allowed scope.\n => SCOPES: ${config.scopes.join(', ')}`, - commitHeader); - return false; - } - - return true; -}; - -module.exports.FIXUP_PREFIX_RE = FIXUP_PREFIX_RE; -module.exports.config = config; - -// Helpers -function error(errorMessage, commitHeader) { - console.error(`INVALID COMMIT MSG: ${commitHeader}\n => ERROR: ${errorMessage}`); -} - -function parseCommitHeader(header) { - const isFixup = FIXUP_PREFIX_RE.test(header); - const isSquash = SQUASH_PREFIX_RE.test(header); - header = header.replace(FIXUP_PREFIX_RE, '').replace(SQUASH_PREFIX_RE, ''); - - const match = /^(\w+)(?:\(([^)]+)\))?\: (.+)$/.exec(header) || []; - - return { - header, - type: match[1], - scope: match[2], - subject: match[3], isFixup, isSquash, - }; -} diff --git a/tools/validate-commit-message/validate-commit-message.spec.js b/tools/validate-commit-message/validate-commit-message.spec.js deleted file mode 100644 index 181eaa7782bdf..0000000000000 --- a/tools/validate-commit-message/validate-commit-message.spec.js +++ /dev/null @@ -1,234 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Imports -const validateMessage = require('./validate-commit-message'); - -// Constants -const TYPES = validateMessage.config.types.join(', '); -const SCOPES = validateMessage.config.scopes.join(', '); - -const INVALID = false; -const VALID = true; - - -describe('validate-commit-message.js', () => { - let errors = []; - let logs = []; - - // Helpers - const stripColor = msg => msg.replace(/\x1B\[\d+m/g, ''); - - beforeEach(() => { - errors = []; - logs = []; - - spyOn(console, 'error').and.callFake(msg => errors.push(stripColor(msg))); - spyOn(console, 'log').and.callFake(msg => logs.push(stripColor(msg))); - }); - - describe('validateMessage()', () => { - - it('should be valid', () => { - expect(validateMessage('fix(core): something')).toBe(VALID); - expect(validateMessage('feat(common): something')).toBe(VALID); - expect(validateMessage('docs(compiler): something')).toBe(VALID); - expect(validateMessage('style(http): something')).toBe(VALID); - expect(validateMessage('refactor(platform-webworker): something')).toBe(VALID); - expect(validateMessage('test(language-service): something')).toBe(VALID); - expect(validateMessage('test(packaging): something')).toBe(VALID); - expect(validateMessage('release: something')).toBe(VALID); - expect(validateMessage('release(packaging): something')).toBe(VALID); - expect(validateMessage('release(packaging): something')).toBe(VALID); - expect(validateMessage('fixup! release(packaging): something')).toBe(VALID); - expect(validateMessage('squash! release(packaging): something')).toBe(VALID); - expect(validateMessage('Revert: "release(packaging): something"')).toBe(VALID); - expect(validateMessage('Revert "release(packaging): something"')).toBe(VALID); - expect(errors).toEqual([]); - }); - - it('should validate max length', () => { - var msg = - 'fix(compiler): something super mega extra giga tera long, maybe even longer and longer and longer and longer and longer and longer...'; - - expect(validateMessage(msg)).toBe(INVALID); - expect(errors).toEqual([ - `INVALID COMMIT MSG: ${msg}\n => ERROR: The commit message header is longer than 120 characters` - ]); - }); - - it('should validate "<type>(<scope>): <subject>" format', () => { - const msg = 'not correct format'; - - expect(validateMessage(msg)).toBe(INVALID); - expect(errors).toEqual([ - `INVALID COMMIT MSG: ${msg}\n => ERROR: The commit message header does not match the format of '<type>(<scope>): <subject>' or 'Revert: "<type>(<scope>): <subject>"'`, - ]); - }); - - it('should fail when type is invalid', () => { - const msg = 'weird(common): something'; - - expect(validateMessage(msg)).toBe(INVALID); - expect(errors).toEqual([ - `INVALID COMMIT MSG: ${msg}\n => ERROR: 'weird' is not an allowed type.\n => TYPES: ${TYPES}`, - ]); - }); - - it('should fail when scope is invalid', () => { - const errorMessageFor = (scope, header) => - `INVALID COMMIT MSG: ${header}\n => ERROR: '${scope}' is not an allowed scope.\n => SCOPES: ${SCOPES}`; - - expect(validateMessage('fix(Compiler): something')).toBe(INVALID); - expect(validateMessage('feat(bah): something')).toBe(INVALID); - expect(validateMessage('style(webworker): something')).toBe(INVALID); - expect(validateMessage('refactor(security): something')).toBe(INVALID); - expect(validateMessage('refactor(docs): something')).toBe(INVALID); - expect(validateMessage('release(angular): something')).toBe(INVALID); - expect(errors).toEqual([ - errorMessageFor('Compiler', 'fix(Compiler): something'), - errorMessageFor('bah', 'feat(bah): something'), - errorMessageFor('webworker', 'style(webworker): something'), - errorMessageFor('security', 'refactor(security): something'), - errorMessageFor('docs', 'refactor(docs): something'), - errorMessageFor('angular', 'release(angular): something'), - ]); - }); - - it('should allow empty scope', () => { - expect(validateMessage('fix: blablabla')).toBe(VALID); - expect(errors).toEqual([]); - }); - - // We do not want to allow WIP. It is OK to fail the PR build in this case to show that there is - // work still to be done (i.e. fixing the commit message). - it('should not allow "WIP: ..." syntax', () => { - const msg = 'WIP: fix: something'; - - expect(validateMessage(msg)).toBe(INVALID); - expect(errors).toEqual([ - `INVALID COMMIT MSG: ${msg}\n => ERROR: 'WIP' is not an allowed type.\n => TYPES: ${TYPES}`, - ]); - }); - - describe('(revert)', () => { - - it('should allow valid "revert: ..." syntaxes', () => { - expect(validateMessage('revert: anything')).toBe(VALID); - expect(validateMessage('Revert: "anything"')).toBe(VALID); - expect(validateMessage('revert anything')).toBe(VALID); - expect(validateMessage('rEvErT anything')).toBe(VALID); - expect(errors).toEqual([]); - }); - - it('should not allow "revert(scope): ..." syntax', () => { - const msg = 'revert(compiler): reduce generated code payload size by 65%'; - - expect(validateMessage(msg)).toBe(INVALID); - expect(errors).toEqual([ - `INVALID COMMIT MSG: ${msg}\n => ERROR: 'revert' is not an allowed type.\n => TYPES: ${TYPES}`, - ]); - }); - - // https://github.com/angular/angular/issues/23479 - it('should allow typical Angular messages generated by git', () => { - const msg = - 'Revert "fix(compiler): Pretty print object instead of [Object object] (#22689)" (#23442)'; - - expect(validateMessage(msg)).toBe(VALID); - expect(errors).toEqual([]); - }); - }); - - describe('(squash)', () => { - - it('should strip the `squash! ` prefix and validate the rest', () => { - const errorMessageFor = header => - `INVALID COMMIT MSG: ${header}\n => ERROR: The commit message header does not match the format of ` + - '\'<type>(<scope>): <subject>\' or \'Revert: "<type>(<scope>): <subject>"\''; - - // Valid messages. - expect(validateMessage('squash! feat(core): add feature')).toBe(VALID); - expect(validateMessage('squash! fix: a bug', false)).toBe(VALID); - - // Invalid messages. - expect(validateMessage('squash! fix a typo', false)).toBe(INVALID); - expect(validateMessage('squash! squash! fix: a bug')).toBe(INVALID); - expect(errors).toEqual([ - errorMessageFor('squash! fix a typo'), - errorMessageFor('squash! squash! fix: a bug'), - ]); - }); - - describe('with `disallowSquash`', () => { - - it('should fail', () => { - expect(validateMessage('fix: something', true)).toBe(VALID); - expect(validateMessage('squash! fix: something', true)).toBe(INVALID); - expect(errors).toEqual([ - 'INVALID COMMIT MSG: squash! fix: something\n' + - ' => ERROR: The commit must be manually squashed into the target commit', - ]); - }); - }); - }); - - describe('(fixup)', () => { - - describe('without `nonFixupCommitHeaders`', () => { - - it('should strip the `fixup! ` prefix and validate the rest', () => { - const errorMessageFor = header => - `INVALID COMMIT MSG: ${header}\n => ERROR: The commit message header does not match the format of ` + - '\'<type>(<scope>): <subject>\' or \'Revert: "<type>(<scope>): <subject>"\''; - - // Valid messages. - expect(validateMessage('fixup! feat(core): add feature')).toBe(VALID); - expect(validateMessage('fixup! fix: a bug')).toBe(VALID); - - // Invalid messages. - expect(validateMessage('fixup! fix a typo')).toBe(INVALID); - expect(validateMessage('fixup! fixup! fix: a bug')).toBe(INVALID); - expect(errors).toEqual([ - errorMessageFor('fixup! fix a typo'), - errorMessageFor('fixup! fixup! fix: a bug'), - ]); - }); - }); - - describe('with `nonFixupCommitHeaders`', () => { - - it('should check that the fixup commit matches a non-fixup one', () => { - const msg = 'fixup! foo'; - - expect(validateMessage(msg, false, ['foo', 'bar', 'baz'])).toBe(VALID); - expect(validateMessage(msg, false, ['bar', 'baz', 'foo'])).toBe(VALID); - expect(validateMessage(msg, false, ['baz', 'foo', 'bar'])).toBe(VALID); - - expect(validateMessage(msg, false, ['qux', 'quux', 'quuux'])).toBe(INVALID); - expect(errors).toEqual([ - `INVALID COMMIT MSG: ${msg}\n` + - ' => ERROR: Unable to find match for fixup commit among prior commits: \n' + - ' qux\n' + - ' quux\n' + - ' quuux', - ]); - }); - - it('should fail if `nonFixupCommitHeaders` is empty', () => { - expect(validateMessage('refactor(router): make reactive', false, [])).toBe(VALID); - expect(validateMessage('fixup! foo', false, [])).toBe(INVALID); - expect(errors).toEqual([ - 'INVALID COMMIT MSG: fixup! foo\n' + - ' => ERROR: Unable to find match for fixup commit among prior commits: -', - ]); - }); - }); - }); - }); -}); From 1b4df6484e7681095d136e99235e2bbcd87fbe49 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Thu, 2 Apr 2020 19:47:02 +0300 Subject: [PATCH 111/262] docs: add missing command in `WebWorker` guide (#36397) The command was accidentally removed in #36383 PR Close #36397 --- aio/content/guide/web-worker.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aio/content/guide/web-worker.md b/aio/content/guide/web-worker.md index 2b62794139dbd..cdf2dd8a8e3a6 100644 --- a/aio/content/guide/web-worker.md +++ b/aio/content/guide/web-worker.md @@ -19,6 +19,8 @@ To add a web worker to an existing project, use the Angular CLI `ng generate` co You can add a web worker anywhere in your application. For example, to add a web worker to the root component, `src/app/app.component.ts`, run the following command. +`ng generate web-worker app` + The command performs the following actions. - Configures your project to use web workers, if it isn't already. From 1140bbc25c0b6a7153a931bd58630de266a6fdd0 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@umich.edu> Date: Fri, 3 Apr 2020 20:57:39 -0700 Subject: [PATCH 112/262] refactor(language-service): reformat using clang-format (#36426) clang-format was recently updated and any PRs that touch files in the language service will have to reformat all the files. Instead of changing the formatting in those PRs, this PR formats all files in language-service package once and for all. PR Close #36426 --- packages/language-service/src/completions.ts | 21 +- packages/language-service/src/definitions.ts | 2 +- .../src/diagnostic_messages.ts | 21 +- packages/language-service/src/diagnostics.ts | 4 +- .../src/expression_diagnostics.ts | 27 ++- .../language-service/src/expression_type.ts | 37 ++- packages/language-service/src/expressions.ts | 11 +- packages/language-service/src/hover.ts | 9 +- packages/language-service/src/html_info.ts | 12 +- .../language-service/src/locate_symbol.ts | 77 +++++-- .../language-service/src/reflector_host.ts | 14 +- packages/language-service/src/symbols.ts | 8 +- packages/language-service/src/template.ts | 4 +- packages/language-service/src/ts_plugin.ts | 10 +- packages/language-service/src/types.ts | 9 +- .../language-service/src/typescript_host.ts | 52 +++-- .../src/typescript_symbols.ts | 212 +++++++++++++----- packages/language-service/src/utils.ts | 19 +- .../language-service/test/completions_spec.ts | 58 ++--- .../language-service/test/definitions_spec.ts | 114 +++++----- .../test/diagnostic_messages_spec.ts | 3 +- .../language-service/test/diagnostics_spec.ts | 74 +++--- .../test/expression_diagnostics_spec.ts | 31 +-- .../test/global_symbols_spec.ts | 4 +- packages/language-service/test/hover_spec.ts | 60 ++--- .../language-service/test/html_info_spec.ts | 1 - .../test/language_service_spec.ts | 19 +- packages/language-service/test/mocks.ts | 85 +++++-- .../test/reflector_host_spec.ts | 8 +- .../language-service/test/template_spec.ts | 13 +- packages/language-service/test/test_utils.ts | 35 ++- .../language-service/test/ts_plugin_spec.ts | 8 +- .../test/typescript_host_spec.ts | 12 +- .../test/typescript_symbols_spec.ts | 22 +- packages/language-service/test/utils_spec.ts | 2 +- 35 files changed, 686 insertions(+), 412 deletions(-) diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index 0a01ebf5dd241..dc0895c26e6fb 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AbsoluteSourceSpan, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, EmptyExpr, ExpressionBinding, HtmlAstPath, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ParseSpan, ReferenceAst, TagContentType, TemplateBinding, Text, VariableBinding, getHtmlTagDefinition} from '@angular/compiler'; +import {AbsoluteSourceSpan, AST, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, EmptyExpr, ExpressionBinding, getHtmlTagDefinition, HtmlAstPath, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ParseSpan, ReferenceAst, TagContentType, TemplateBinding, Text, VariableBinding} from '@angular/compiler'; import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; import {AstResult} from './common'; @@ -216,7 +216,8 @@ export function getTemplateCompletions( const replacementSpan = getBoundedWordSpan(templateInfo, position); return result.map(entry => { return { - ...entry, replacementSpan, + ...entry, + replacementSpan, }; }); } @@ -331,7 +332,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C elemAst = parent; } } else if (templatePath.tail instanceof ElementAst) { - refAst = new ReferenceAst(htmlAttr.name, null !, htmlAttr.value, htmlAttr.valueSpan !); + refAst = new ReferenceAst(htmlAttr.name, null!, htmlAttr.value, htmlAttr.valueSpan!); elemAst = templatePath.tail; } if (refAst && elemAst) { @@ -340,7 +341,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C } else { // HtmlAst contains the `Attribute` node, however the corresponding `AttrAst` // node is missing from the TemplateAst. - const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan !); + const attrAst = new AttrAst(htmlAttr.name, htmlAttr.value, htmlAttr.valueSpan!); attrAst.visit(visitor, null); } return visitor.results; @@ -434,7 +435,9 @@ class ExpressionVisitor extends NullTemplateVisitor { super(); } - get results(): ng.CompletionEntry[] { return Array.from(this.completions.values()); } + get results(): ng.CompletionEntry[] { + return Array.from(this.completions.values()); + } visitDirectiveProperty(ast: BoundDirectivePropertyAst): void { this.processExpressionCompletions(ast.value); @@ -444,7 +447,9 @@ class ExpressionVisitor extends NullTemplateVisitor { this.processExpressionCompletions(ast.value); } - visitEvent(ast: BoundEventAst): void { this.processExpressionCompletions(ast.handler); } + visitEvent(ast: BoundEventAst): void { + this.processExpressionCompletions(ast.handler); + } visitElement(): void { // no-op for now @@ -577,7 +582,7 @@ class ExpressionVisitor extends NullTemplateVisitor { } } else if (binding instanceof ExpressionBinding) { if (inSpan(this.position, binding.value?.ast.sourceSpan)) { - this.processExpressionCompletions(binding.value !.ast); + this.processExpressionCompletions(binding.value!.ast); return; } else if (!binding.value && this.position > binding.key.span.end) { // No expression is defined for the value of the key expression binding, but the cursor is @@ -637,7 +642,7 @@ function angularAttributes(info: AstResult, elementName: string): AngularAttribu if (selector.element && selector.element !== elementName) { continue; } - const summary = selectorMap.get(selector) !; + const summary = selectorMap.get(selector)!; const hasTemplateRef = isStructuralDirective(summary.type); // attributes are listed in (attribute, value) pairs for (let i = 0; i < selector.attrs.length; i += 2) { diff --git a/packages/language-service/src/definitions.ts b/packages/language-service/src/definitions.ts index 17c14744d5c6c..417df1f1e1e1d 100644 --- a/packages/language-service/src/definitions.ts +++ b/packages/language-service/src/definitions.ts @@ -7,7 +7,7 @@ */ import * as path from 'path'; -import * as ts from 'typescript'; // used as value and is provided at runtime +import * as ts from 'typescript'; // used as value and is provided at runtime import {AstResult} from './common'; import {locateSymbols} from './locate_symbol'; import {getPropertyAssignmentFromValue, isClassDecoratorProperty} from './template'; diff --git a/packages/language-service/src/diagnostic_messages.ts b/packages/language-service/src/diagnostic_messages.ts index 885d781bd2992..749dceb8fd203 100644 --- a/packages/language-service/src/diagnostic_messages.ts +++ b/packages/language-service/src/diagnostic_messages.ts @@ -14,15 +14,15 @@ export interface DiagnosticMessage { kind: keyof typeof ts.DiagnosticCategory; } -type DiagnosticName = 'directive_not_in_module' | 'missing_template_and_templateurl' | - 'both_template_and_templateurl' | 'invalid_templateurl' | 'template_context_missing_member' | - 'callable_expression_expected_method_call' | 'call_target_not_callable' | - 'expression_might_be_null' | 'expected_a_number_type' | 'expected_a_string_or_number_type' | - 'expected_operands_of_similar_type_or_any' | 'unrecognized_operator' | - 'unrecognized_primitive' | 'no_pipe_found' | 'unable_to_resolve_compatible_call_signature' | - 'unable_to_resolve_signature' | 'could_not_resolve_type' | 'identifier_not_callable' | - 'identifier_possibly_undefined' | 'identifier_not_defined_in_app_context' | - 'identifier_not_defined_on_receiver' | 'identifier_is_private'; +type DiagnosticName = 'directive_not_in_module'|'missing_template_and_templateurl'| + 'both_template_and_templateurl'|'invalid_templateurl'|'template_context_missing_member'| + 'callable_expression_expected_method_call'|'call_target_not_callable'| + 'expression_might_be_null'|'expected_a_number_type'|'expected_a_string_or_number_type'| + 'expected_operands_of_similar_type_or_any'|'unrecognized_operator'|'unrecognized_primitive'| + 'no_pipe_found'|'unable_to_resolve_compatible_call_signature'|'unable_to_resolve_signature'| + 'could_not_resolve_type'|'identifier_not_callable'|'identifier_possibly_undefined'| + 'identifier_not_defined_in_app_context'|'identifier_not_defined_on_receiver'| + 'identifier_is_private'; export const Diagnostic: Record<DiagnosticName, DiagnosticMessage> = { directive_not_in_module: { @@ -156,6 +156,7 @@ export function createDiagnostic( dm.message.replace(/%(\d+)/g, (_, index: string) => formatArgs[+index - 1]); return { kind: ts.DiagnosticCategory[dm.kind], - message: formattedMessage, span, + message: formattedMessage, + span, }; } diff --git a/packages/language-service/src/diagnostics.ts b/packages/language-service/src/diagnostics.ts index d437a918ea224..646086c5ef0ce 100644 --- a/packages/language-service/src/diagnostics.ts +++ b/packages/language-service/src/diagnostics.ts @@ -11,7 +11,7 @@ import * as path from 'path'; import * as ts from 'typescript'; import {AstResult} from './common'; -import {Diagnostic, createDiagnostic} from './diagnostic_messages'; +import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {getTemplateExpressionDiagnostics} from './expression_diagnostics'; import * as ng from './types'; import {TypeScriptServiceHost} from './typescript_host'; @@ -193,7 +193,7 @@ function chainDiagnostics(chain: ng.DiagnosticMessageChain): ts.DiagnosticMessag * @param file */ export function ngDiagnosticToTsDiagnostic( - d: ng.Diagnostic, file: ts.SourceFile | undefined): ts.Diagnostic { + d: ng.Diagnostic, file: ts.SourceFile|undefined): ts.Diagnostic { return { file, start: d.span.start, diff --git a/packages/language-service/src/expression_diagnostics.ts b/packages/language-service/src/expression_diagnostics.ts index 0af26418be9c6..61e62ec6180be 100644 --- a/packages/language-service/src/expression_diagnostics.ts +++ b/packages/language-service/src/expression_diagnostics.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, VariableAst, identifierName, templateVisitAll, tokenReference} from '@angular/compiler'; +import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, identifierName, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableAst} from '@angular/compiler'; -import {Diagnostic, createDiagnostic} from './diagnostic_messages'; +import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {AstType} from './expression_type'; import {BuiltinType, Definition, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; @@ -44,7 +44,9 @@ function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { name: reference.name, kind: 'reference', type: type || info.query.getBuiltinType(BuiltinType.Any), - get definition() { return getDefinitionOf(info, reference); } + get definition() { + return getDefinitionOf(info, reference); + } }); } } @@ -109,7 +111,10 @@ function getVarDeclarations( results.push({ name: variable.name, kind: 'variable', - type: symbol, get definition() { return getDefinitionOf(info, variable); }, + type: symbol, + get definition() { + return getDefinitionOf(info, variable); + }, }); } } @@ -296,7 +301,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { visitVariable(ast: VariableAst): void { const directive = this.directiveSummary; if (directive && ast.value) { - const context = this.info.query.getTemplateContext(directive.type.reference) !; + const context = this.info.query.getTemplateContext(directive.type.reference)!; if (context && !context.has(ast.value)) { const missingMember = ast.value === '$implicit' ? 'an implicit value' : `a member called '${ast.value}'`; @@ -322,7 +327,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { // Find directive that references this template this.directiveSummary = - ast.directives.map(d => d.directive).find(d => hasTemplateReference(d.type)) !; + ast.directives.map(d => d.directive).find(d => hasTemplateReference(d.type))!; // Process children super.visitEmbeddedTemplate(ast, context); @@ -350,9 +355,13 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { } } - private push(ast: TemplateAst) { this.path.push(ast); } + private push(ast: TemplateAst) { + this.path.push(ast); + } - private pop() { this.path.pop(); } + private pop() { + this.path.pop(); + } private absSpan(span: Span, additionalOffset: number = 0): Span { return { @@ -366,7 +375,7 @@ function hasTemplateReference(type: CompileTypeMetadata): boolean { if (type.diDeps) { for (let diDep of type.diDeps) { if (diDep.token && diDep.token.identifier && - identifierName(diDep.token !.identifier !) == 'TemplateRef') + identifierName(diDep.token!.identifier!) == 'TemplateRef') return true; } } diff --git a/packages/language-service/src/expression_type.ts b/packages/language-service/src/expression_type.ts index 5277ca3c55273..8b2b5caeb2a6e 100644 --- a/packages/language-service/src/expression_type.ts +++ b/packages/language-service/src/expression_type.ts @@ -8,11 +8,13 @@ import {AST, AstVisitor, Binary, BindingPipe, Chain, Conditional, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '@angular/compiler'; -import {Diagnostic, createDiagnostic} from './diagnostic_messages'; +import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {BuiltinType, Signature, Symbol, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; -export interface ExpressionDiagnosticsContext { inEvent?: boolean; } +export interface ExpressionDiagnosticsContext { + inEvent?: boolean; +} // AstType calculatetype of the ast given AST element. export class AstType implements AstVisitor { @@ -22,7 +24,9 @@ export class AstType implements AstVisitor { private scope: SymbolTable, private query: SymbolQuery, private context: ExpressionDiagnosticsContext, private source: string) {} - getType(ast: AST): Symbol { return ast.visit(this); } + getType(ast: AST): Symbol { + return ast.visit(this); + } getDiagnostics(ast: AST): ng.Diagnostic[] { const type: Symbol = ast.visit(this); @@ -204,10 +208,10 @@ export class AstType implements AstVisitor { // support contextual typing of arguments so this is simpler than TypeScript's // version. const args = ast.args.map(arg => this.getType(arg)); - const target = this.getType(ast.target !); + const target = this.getType(ast.target!); if (!target || !target.callable) { this.diagnostics.push(createDiagnostic( - ast.span, Diagnostic.call_target_not_callable, this.sourceOf(ast.target !), target.name)); + ast.span, Diagnostic.call_target_not_callable, this.sourceOf(ast.target!), target.name)); return this.anyType; } const signature = target.selectSignature(args); @@ -237,11 +241,24 @@ export class AstType implements AstVisitor { public: true, definition: undefined, documentation: [], - members(): SymbolTable{return _this.scope;}, - signatures(): Signature[]{return [];}, - selectSignature(types): Signature | undefined{return undefined;}, - indexed(argument): Symbol | undefined{return undefined;}, - typeArguments(): Symbol[] | undefined{return undefined;}, + members(): SymbolTable { + return _this.scope; + }, + signatures(): Signature[] { + return []; + }, + selectSignature(types): Signature | + undefined { + return undefined; + }, + indexed(argument): Symbol | + undefined { + return undefined; + }, + typeArguments(): Symbol[] | + undefined { + return undefined; + }, }; } diff --git a/packages/language-service/src/expressions.ts b/packages/language-service/src/expressions.ts index 594a3c565b17b..bc33a1650a3ec 100644 --- a/packages/language-service/src/expressions.ts +++ b/packages/language-service/src/expressions.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, ASTWithSource, AstPath as AstPathBase, RecursiveAstVisitor} from '@angular/compiler'; +import {AST, AstPath as AstPathBase, ASTWithSource, RecursiveAstVisitor} from '@angular/compiler'; + import {AstType} from './expression_type'; import {BuiltinType, Span, Symbol, SymbolTable, TemplateSource} from './types'; import {inSpan} from './utils'; @@ -41,7 +42,7 @@ export function getExpressionCompletions( undefined { const path = findAstAt(ast, position); if (path.empty) return undefined; - const tail = path.tail !; + const tail = path.tail!; let result: SymbolTable|undefined = scope; function getType(ast: AST): Symbol { @@ -57,7 +58,9 @@ export function getExpressionCompletions( visitConditional(ast) {}, visitFunctionCall(ast) {}, visitImplicitReceiver(ast) {}, - visitInterpolation(ast) { result = undefined; }, + visitInterpolation(ast) { + result = undefined; + }, visitKeyedRead(ast) {}, visitKeyedWrite(ast) {}, visitLiteralArray(ast) {}, @@ -111,7 +114,7 @@ export function getExpressionSymbol( templateInfo: TemplateSource): {symbol: Symbol, span: Span}|undefined { const path = findAstAt(ast, position, /* excludeEmpty */ true); if (path.empty) return undefined; - const tail = path.tail !; + const tail = path.tail!; function getType(ast: AST): Symbol { return new AstType(scope, templateInfo.query, {}, templateInfo.source).getType(ast); diff --git a/packages/language-service/src/hover.ts b/packages/language-service/src/hover.ts index 145fdfbc6b4c5..9d60e13554947 100644 --- a/packages/language-service/src/hover.ts +++ b/packages/language-service/src/hover.ts @@ -37,14 +37,15 @@ export function getTemplateHover( // The container is either the symbol's container (for example, 'AppComponent' // is the container of the symbol 'title' in its template) or the NgModule // that the directive belongs to (the container of AppComponent is AppModule). - let containerName: string|undefined = symbol.container ?.name; + let containerName: string|undefined = symbol.container?.name; if (!containerName && staticSymbol) { // If there is a static symbol then the target is a directive. const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol); - containerName = ngModule ?.type.reference.name; + containerName = ngModule?.type.reference.name; } - return createQuickInfo(symbol.name, symbol.kind, span, containerName, symbol.type?.name, symbol.documentation); + return createQuickInfo( + symbol.name, symbol.kind, span, containerName, symbol.type?.name, symbol.documentation); } /** @@ -63,7 +64,7 @@ export function getTsHover( const kind = metadata.isComponent ? 'component' : 'directive'; const textSpan = ts.createTextSpanFromBounds(declarationSpan.start, declarationSpan.end); const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(staticSymbol); - const moduleName = ngModule ?.type.reference.name; + const moduleName = ngModule?.type.reference.name; return createQuickInfo( directiveName, kind, textSpan, moduleName, ts.ScriptElementKind.classElement); } diff --git a/packages/language-service/src/html_info.ts b/packages/language-service/src/html_info.ts index b54243ba2fc32..dc5315c0c3aca 100644 --- a/packages/language-service/src/html_info.ts +++ b/packages/language-service/src/html_info.ts @@ -10,7 +10,7 @@ // This section defines the HTML elements and attribute surface of HTML 4 // which is derived from https://www.w3.org/TR/html4/strict.dtd -type attrType = string | string[]; +type attrType = string|string[]; type hash<T> = { [name: string]: T }; @@ -104,7 +104,9 @@ const groups: hash<number>[] = [ {class: 1, style: 1}, {hreflang: 2, rel: 1, rev: 1}, {ismap: 7}, - { defer: 25, event: 1, for : 1 } + { + defer: 25, event: 1, for: 1 + } ]; const elements: {[name: string]: number[]} = { @@ -193,7 +195,7 @@ export function elementNames(): string[] { return Object.keys(elements).sort().map(v => v.toLowerCase()); } -function compose(indexes: number[] | undefined): hash<attrType> { +function compose(indexes: number[]|undefined): hash<attrType> { const result: hash<attrType> = {}; if (indexes) { for (let index of indexes) { @@ -415,7 +417,9 @@ export class SchemaInformation { }); } - allKnownElements(): string[] { return Object.keys(this.schema); } + allKnownElements(): string[] { + return Object.keys(this.schema); + } eventsOf(elementName: string): string[] { const elementType = this.schema[elementName.toLowerCase()] || {}; diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index 1f1cbc286fd16..fba5d1a812ec0 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, VariableBinding, templateVisitAll, tokenReference} from '@angular/compiler'; +import {AST, Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableBinding} from '@angular/compiler'; import * as tss from 'typescript/lib/tsserverlibrary'; import {AstResult} from './common'; @@ -77,7 +77,7 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): } if (result) { symbol = result.symbol; - span = offsetSpan(result.span, attribute.valueSpan !.start.offset); + span = offsetSpan(result.span, attribute.valueSpan!.start.offset); } return true; } @@ -121,7 +121,9 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): span = spanOf(ast); } }, - visitElementProperty(ast) { attributeValueSymbol(ast.value); }, + visitElementProperty(ast) { + attributeValueSymbol(ast.value); + }, visitAttr(ast) { const element = path.first(ElementAst); if (!element) return; @@ -188,7 +190,8 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): const {start, end} = offsetSpan(span, info.template.span.start); return { symbol, - span: tss.createTextSpanFromBounds(start, end), staticSymbol, + span: tss.createTextSpanFromBounds(start, end), + staticSymbol, }; } } @@ -216,7 +219,7 @@ function getSymbolInMicrosyntax(info: AstResult, path: TemplateAstPath, attribut if (inSpan(path.position, tb.value?.ast.sourceSpan)) { const dinfo = diagnosticInfoFromTemplateInfo(info); const scope = getExpressionScope(dinfo, path); - result = getExpressionSymbol(scope, tb.value !, path.position, info.template); + result = getExpressionSymbol(scope, tb.value!, path.position, info.template); } else if (inSpan(path.position, tb.sourceSpan)) { const template = path.first(EmbeddedTemplateAst); if (template) { @@ -277,7 +280,9 @@ function findParentOfBinding( } visitDirective(ast: DirectiveAst) { - const result = this.visitChildren(ast, visit => { visit(ast.inputs); }); + const result = this.visitChildren(ast, visit => { + visit(ast.inputs); + }); return result; } @@ -309,33 +314,63 @@ function findInputBinding(info: AstResult, name: string, directiveAst: Directive */ class OverrideKindSymbol implements Symbol { public readonly kind: DirectiveKind; - constructor(private sym: Symbol, kindOverride: DirectiveKind) { this.kind = kindOverride; } + constructor(private sym: Symbol, kindOverride: DirectiveKind) { + this.kind = kindOverride; + } - get name(): string { return this.sym.name; } + get name(): string { + return this.sym.name; + } - get language(): string { return this.sym.language; } + get language(): string { + return this.sym.language; + } - get type(): Symbol|undefined { return this.sym.type; } + get type(): Symbol|undefined { + return this.sym.type; + } - get container(): Symbol|undefined { return this.sym.container; } + get container(): Symbol|undefined { + return this.sym.container; + } - get public(): boolean { return this.sym.public; } + get public(): boolean { + return this.sym.public; + } - get callable(): boolean { return this.sym.callable; } + get callable(): boolean { + return this.sym.callable; + } - get nullable(): boolean { return this.sym.nullable; } + get nullable(): boolean { + return this.sym.nullable; + } - get definition(): Definition { return this.sym.definition; } + get definition(): Definition { + return this.sym.definition; + } - get documentation(): ts.SymbolDisplayPart[] { return this.sym.documentation; } + get documentation(): ts.SymbolDisplayPart[] { + return this.sym.documentation; + } - members() { return this.sym.members(); } + members() { + return this.sym.members(); + } - signatures() { return this.sym.signatures(); } + signatures() { + return this.sym.signatures(); + } - selectSignature(types: Symbol[]) { return this.sym.selectSignature(types); } + selectSignature(types: Symbol[]) { + return this.sym.selectSignature(types); + } - indexed(argument: Symbol) { return this.sym.indexed(argument); } + indexed(argument: Symbol) { + return this.sym.indexed(argument); + } - typeArguments(): Symbol[]|undefined { return this.sym.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.sym.typeArguments(); + } } diff --git a/packages/language-service/src/reflector_host.ts b/packages/language-service/src/reflector_host.ts index 13ba23a885449..6a1b83793236c 100644 --- a/packages/language-service/src/reflector_host.ts +++ b/packages/language-service/src/reflector_host.ts @@ -7,7 +7,7 @@ */ import {StaticSymbolResolverHost} from '@angular/compiler'; -import {MetadataCollector, MetadataReaderHost, createMetadataReaderCache, readMetadata} from '@angular/compiler-cli/src/language_services'; +import {createMetadataReaderCache, MetadataCollector, MetadataReaderHost, readMetadata} from '@angular/compiler-cli/src/language_services'; import * as path from 'path'; import * as ts from 'typescript'; @@ -26,10 +26,10 @@ class ReflectorModuleModuleResolutionHost implements ts.ModuleResolutionHost, Me private readonly tsLSHost: ts.LanguageServiceHost, private readonly getProgram: () => ts.Program) { if (tsLSHost.directoryExists) { - this.directoryExists = directoryName => tsLSHost.directoryExists !(directoryName); + this.directoryExists = directoryName => tsLSHost.directoryExists!(directoryName); } if (tsLSHost.realpath) { - this.realpath = path => tsLSHost.realpath !(path); + this.realpath = path => tsLSHost.realpath!(path); } } @@ -53,14 +53,14 @@ class ReflectorModuleModuleResolutionHost implements ts.ModuleResolutionHost, Me // resolution, and it's used by Angular to read metadata.json during // metadata resolution. if (this.tsLSHost.readFile) { - return this.tsLSHost.readFile(fileName) !; + return this.tsLSHost.readFile(fileName)!; } // As a fallback, read the JSON files from the editor snapshot. const snapshot = this.tsLSHost.getScriptSnapshot(fileName); if (!snapshot) { // MetadataReaderHost readFile() declaration should be // `readFile(fileName: string): string | undefined` - return undefined !; + return undefined!; } return snapshot.getText(0, snapshot.getLength()); } @@ -120,5 +120,7 @@ export class ReflectorHost implements StaticSymbolResolverHost { return resolved ? resolved.resolvedFileName : null; } - getOutputName(filePath: string) { return filePath; } + getOutputName(filePath: string) { + return filePath; + } } diff --git a/packages/language-service/src/symbols.ts b/packages/language-service/src/symbols.ts index da3f851e24dc2..f4eb5142828b6 100644 --- a/packages/language-service/src/symbols.ts +++ b/packages/language-service/src/symbols.ts @@ -40,7 +40,7 @@ export interface Location { /** * A defnition location(s). */ -export type Definition = Location[] | undefined; +export type Definition = Location[]|undefined; /** * A symbol describing a language element that can be referenced by expressions @@ -235,8 +235,8 @@ export enum BuiltinType { * * @publicApi */ -export type DeclarationKind = 'attribute' | 'html attribute' | 'component' | 'element' | 'entity' | - 'key' | 'method' | 'pipe' | 'property' | 'type' | 'reference' | 'variable'; +export type DeclarationKind = 'attribute'|'html attribute'|'component'|'element'|'entity'|'key'| + 'method'|'pipe'|'property'|'type'|'reference'|'variable'; /** * Describes a symbol to type binding used to build a symbol table. @@ -287,7 +287,7 @@ export interface PipeInfo { * * @publicApi */ -export type Pipes = PipeInfo[] | undefined; +export type Pipes = PipeInfo[]|undefined; /** * Describes the language context in which an Angular expression is evaluated. diff --git a/packages/language-service/src/template.ts b/packages/language-service/src/template.ts index e882b1ca81017..c5f3924bead0b 100644 --- a/packages/language-service/src/template.ts +++ b/packages/language-service/src/template.ts @@ -39,7 +39,9 @@ abstract class BaseTemplate implements ng.TemplateSource { /** * Return the Angular StaticSymbol for the class that contains this template. */ - get type() { return this.classSymbol; } + get type() { + return this.classSymbol; + } /** * Return a Map-like data structure that allows users to retrieve some or all diff --git a/packages/language-service/src/ts_plugin.ts b/packages/language-service/src/ts_plugin.ts index e2d4594cc9c10..d7774bf222c8c 100644 --- a/packages/language-service/src/ts_plugin.ts +++ b/packages/language-service/src/ts_plugin.ts @@ -27,8 +27,7 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { const ngLS = createLanguageService(ngLSHost); function getCompletionsAtPosition( - fileName: string, position: number, - options: tss.GetCompletionsAtPositionOptions | undefined) { + fileName: string, position: number, options: tss.GetCompletionsAtPositionOptions|undefined) { if (!angularOnly) { const results = tsLS.getCompletionsAtPosition(fileName, position, options); if (results && results.entries.length) { @@ -93,8 +92,11 @@ export function create(info: tss.server.PluginCreateInfo): tss.LanguageService { {}, tsLS, // Then override the methods supported by Angular language service { - getCompletionsAtPosition, getQuickInfoAtPosition, getSemanticDiagnostics, - getDefinitionAtPosition, getDefinitionAndBoundSpan, + getCompletionsAtPosition, + getQuickInfoAtPosition, + getSemanticDiagnostics, + getDefinitionAtPosition, + getDefinitionAndBoundSpan, }); return proxy; } diff --git a/packages/language-service/src/types.ts b/packages/language-service/src/types.ts index cb349eea4d3bb..804a3fbc08d85 100644 --- a/packages/language-service/src/types.ts +++ b/packages/language-service/src/types.ts @@ -74,7 +74,7 @@ export interface TemplateSource { * * @publicApi */ -export type TemplateSources = TemplateSource[] | undefined; +export type TemplateSources = TemplateSource[]|undefined; /** * Error information found getting declaration information @@ -264,7 +264,7 @@ export enum CompletionKind { VARIABLE = 'variable', } -export type CompletionEntry = Omit<ts.CompletionEntry, 'kind'>& { +export type CompletionEntry = Omit<ts.CompletionEntry, 'kind'>&{ kind: CompletionKind, }; @@ -361,5 +361,6 @@ export interface Hover { * @publicApi */ export type LanguageService = Pick< - ts.LanguageService, 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'| - 'getQuickInfoAtPosition'|'getSemanticDiagnostics'>; + ts.LanguageService, + 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'|'getQuickInfoAtPosition'| + 'getSemanticDiagnostics'>; diff --git a/packages/language-service/src/typescript_host.ts b/packages/language-service/src/typescript_host.ts index e7a6e8d9ef82a..20602d028cef9 100644 --- a/packages/language-service/src/typescript_host.ts +++ b/packages/language-service/src/typescript_host.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotSummaryResolver, CompileDirectiveSummary, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver, isFormattedError} from '@angular/compiler'; +import {analyzeNgModules, AotSummaryResolver, CompileDirectiveSummary, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, I18NHtmlParser, isFormattedError, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser} from '@angular/compiler'; import {SchemaMetadata, ViewEncapsulation, ɵConsole as Console} from '@angular/core'; import * as tss from 'typescript/lib/tsserverlibrary'; import {AstResult} from './common'; import {createLanguageService} from './language_service'; import {ReflectorHost} from './reflector_host'; -import {ExternalTemplate, InlineTemplate, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue} from './template'; +import {ExternalTemplate, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue, InlineTemplate} from './template'; import {Declaration, DeclarationError, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types'; import {findTightestNode, getDirectiveClassLike} from './utils'; @@ -35,14 +35,18 @@ export function createLanguageServiceFromTypescript( * syntactically incorrect templates. */ export class DummyHtmlParser extends HtmlParser { - parse(): ParseTreeResult { return new ParseTreeResult([], []); } + parse(): ParseTreeResult { + return new ParseTreeResult([], []); + } } /** * Avoid loading resources in the language servcie by using a dummy loader. */ export class DummyResourceLoader extends ResourceLoader { - get(url: string): Promise<string> { return Promise.resolve(''); } + get(url: string): Promise<string> { + return Promise.resolve(''); + } } /** @@ -74,10 +78,18 @@ export class TypeScriptServiceHost implements LanguageServiceHost { readonly tsLsHost: tss.LanguageServiceHost, private readonly tsLS: tss.LanguageService) { this.summaryResolver = new AotSummaryResolver( { - loadSummary(filePath: string) { return null; }, - isSourceFile(sourceFilePath: string) { return true; }, - toSummaryFileName(sourceFilePath: string) { return sourceFilePath; }, - fromSummaryFileName(filePath: string): string{return filePath;}, + loadSummary(filePath: string) { + return null; + }, + isSourceFile(sourceFilePath: string) { + return true; + }, + toSummaryFileName(sourceFilePath: string) { + return sourceFilePath; + }, + fromSummaryFileName(filePath: string): string { + return filePath; + }, }, this.staticSymbolCache); this.reflectorHost = new ReflectorHost(() => this.program, tsLsHost); @@ -159,7 +171,11 @@ export class TypeScriptServiceHost implements LanguageServiceHost { this.collectedErrors.clear(); this.resolver.clearCache(); - const analyzeHost = {isSourceFile(filePath: string) { return true; }}; + const analyzeHost = { + isSourceFile(filePath: string) { + return true; + } + }; const programFiles = this.program.getSourceFiles().map(sf => sf.fileName); this.analyzedModules = analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver); @@ -168,7 +184,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost { const urlResolver = createOfflineCompileUrlResolver(); for (const ngModule of this.analyzedModules.ngModules) { for (const directive of ngModule.declaredDirectives) { - const {metadata} = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference) !; + const {metadata} = this.resolver.getNonNormalizedDirectiveMetadata(directive.reference)!; if (metadata.isComponent && metadata.template && metadata.template.templateUrl) { const templateName = urlResolver.resolve( this.reflector.componentModuleUrl(directive.reference), @@ -494,9 +510,9 @@ export class TypeScriptServiceHost implements LanguageServiceHost { const parser = new TemplateParser( new CompilerConfig(), this.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, - null !, // console - [] // tranforms - ); + null!, // console + [] // tranforms + ); const htmlResult = htmlParser.parse(template.source, fileName, { tokenizeExpansionForms: true, preserveLineEndings: true, // do not convert CRLF to LF @@ -509,8 +525,12 @@ export class TypeScriptServiceHost implements LanguageServiceHost { return { htmlAst: htmlResult.rootNodes, templateAst: parseResult.templateAst, - directive: data.metadata, directives, pipes, - parseErrors: parseResult.errors, expressionParser, template, + directive: data.metadata, + directives, + pipes, + parseErrors: parseResult.errors, + expressionParser, + template, }; } @@ -574,7 +594,7 @@ function spanOf(node: tss.Node): Span { function spanAt(sourceFile: tss.SourceFile, line: number, column: number): Span|undefined { if (line != null && column != null) { const position = tss.getPositionOfLineAndCharacter(sourceFile, line, column); - const findChild = function findChild(node: tss.Node): tss.Node | undefined { + const findChild = function findChild(node: tss.Node): tss.Node|undefined { if (node.kind > tss.SyntaxKind.LastToken && node.pos <= position && node.end > position) { const betterNode = tss.forEachChild(node, findChild); return betterNode || node; diff --git a/packages/language-service/src/typescript_symbols.ts b/packages/language-service/src/typescript_symbols.ts index f018a092c6b3b..19e5464c444bf 100644 --- a/packages/language-service/src/typescript_symbols.ts +++ b/packages/language-service/src/typescript_symbols.ts @@ -68,7 +68,7 @@ export function getClassFromStaticSymbol( return classDeclaration; } } - }) as(ts.ClassDeclaration | undefined); + }) as (ts.ClassDeclaration | undefined); } return undefined; @@ -123,7 +123,9 @@ class TypeScriptSymbolQuery implements SymbolQuery { return result || this.getBuiltinType(BuiltinType.Any); } - getArrayType(type: Symbol): Symbol { return this.getBuiltinType(BuiltinType.Any); } + getArrayType(type: Symbol): Symbol { + return this.getBuiltinType(BuiltinType.Any); + } getElementType(type: Symbol): Symbol|undefined { if (type instanceof TypeWrapper) { @@ -193,13 +195,13 @@ class TypeScriptSymbolQuery implements SymbolQuery { private getTemplateRefContextType(typeSymbol: ts.Symbol, context: TypeContext): Symbol|undefined { const type = this.checker.getTypeOfSymbolAtLocation(typeSymbol, this.source); const constructor = type.symbol && type.symbol.members && - getFromSymbolTable(type.symbol.members !, '__constructor'); + getFromSymbolTable(type.symbol.members!, '__constructor'); if (constructor) { - const constructorDeclaration = constructor.declarations ![0] as ts.ConstructorTypeNode; + const constructorDeclaration = constructor.declarations![0] as ts.ConstructorTypeNode; for (const parameter of constructorDeclaration.parameters) { - const type = this.checker.getTypeAtLocation(parameter.type !); - if (type.symbol !.name == 'TemplateRef' && isReferenceType(type)) { + const type = this.checker.getTypeAtLocation(parameter.type!); + if (type.symbol!.name == 'TemplateRef' && isReferenceType(type)) { const typeWrapper = new TypeWrapper(type, context); const typeArguments = typeWrapper.typeArguments(); if (typeArguments && typeArguments.length === 1) { @@ -237,7 +239,9 @@ class TypeWrapper implements Symbol { } } - get name(): string { return this.context.checker.typeToString(this.tsType); } + get name(): string { + return this.context.checker.typeToString(this.tsType); + } public readonly kind: DeclarationKind = 'type'; @@ -249,7 +253,9 @@ class TypeWrapper implements Symbol { public readonly public: boolean = true; - get callable(): boolean { return typeCallable(this.tsType); } + get callable(): boolean { + return typeCallable(this.tsType); + } get nullable(): boolean { return this.context.checker.getNonNullableType(this.tsType) != this.tsType; @@ -276,7 +282,9 @@ class TypeWrapper implements Symbol { return new SymbolTableWrapper(this.tsType.getApparentProperties(), this.context, this.tsType); } - signatures(): Signature[] { return signaturesOf(this.tsType, this.context); } + signatures(): Signature[] { + return signaturesOf(this.tsType, this.context); + } selectSignature(types: Symbol[]): Signature|undefined { return selectSignature(this.tsType, this.context, types); @@ -332,30 +340,44 @@ class SymbolWrapper implements Symbol { symbol: ts.Symbol, /** TypeScript type context of the symbol. */ private context: TypeContext, - /** Type of the TypeScript symbol, if known. If not provided, the type of the symbol - * will be determined dynamically; see `SymbolWrapper#tsType`. */ + /** + * Type of the TypeScript symbol, if known. If not provided, the type of the symbol + * will be determined dynamically; see `SymbolWrapper#tsType`. + */ private _tsType?: ts.Type) { this.symbol = symbol && context && (symbol.flags & ts.SymbolFlags.Alias) ? context.checker.getAliasedSymbol(symbol) : symbol; } - get name(): string { return this.symbol.name; } + get name(): string { + return this.symbol.name; + } - get kind(): DeclarationKind { return this.callable ? 'method' : 'property'; } + get kind(): DeclarationKind { + return this.callable ? 'method' : 'property'; + } - get type(): TypeWrapper { return new TypeWrapper(this.tsType, this.context); } + get type(): TypeWrapper { + return new TypeWrapper(this.tsType, this.context); + } - get container(): Symbol|undefined { return getContainerOf(this.symbol, this.context); } + get container(): Symbol|undefined { + return getContainerOf(this.symbol, this.context); + } get public(): boolean { // Symbols that are not explicitly made private are public. return !isSymbolPrivate(this.symbol); } - get callable(): boolean { return typeCallable(this.tsType); } + get callable(): boolean { + return typeCallable(this.tsType); + } - get definition(): Definition { return definitionFromTsSymbol(this.symbol); } + get definition(): Definition { + return definitionFromTsSymbol(this.symbol); + } get documentation(): ts.SymbolDisplayPart[] { return this.symbol.getDocumentationComment(this.context.checker); @@ -368,21 +390,27 @@ class SymbolWrapper implements Symbol { const typeWrapper = new TypeWrapper(declaredType, this.context); this._members = typeWrapper.members(); } else { - this._members = new SymbolTableWrapper(this.symbol.members !, this.context, this.tsType); + this._members = new SymbolTableWrapper(this.symbol.members!, this.context, this.tsType); } } return this._members; } - signatures(): Signature[] { return signaturesOf(this.tsType, this.context); } + signatures(): Signature[] { + return signaturesOf(this.tsType, this.context); + } selectSignature(types: Symbol[]): Signature|undefined { return selectSignature(this.tsType, this.context, types); } - indexed(argument: Symbol): Symbol|undefined { return undefined; } + indexed(argument: Symbol): Symbol|undefined { + return undefined; + } - typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.type.typeArguments(); + } private get tsType(): ts.Type { let type = this._tsType; @@ -403,29 +431,53 @@ class DeclaredSymbol implements Symbol { constructor(private declaration: SymbolDeclaration) {} - get name() { return this.declaration.name; } + get name() { + return this.declaration.name; + } - get kind() { return this.declaration.kind; } + get kind() { + return this.declaration.kind; + } - get container(): Symbol|undefined { return undefined; } + get container(): Symbol|undefined { + return undefined; + } - get type(): Symbol { return this.declaration.type; } + get type(): Symbol { + return this.declaration.type; + } - get callable(): boolean { return this.type.callable; } + get callable(): boolean { + return this.type.callable; + } - get definition(): Definition { return this.declaration.definition; } + get definition(): Definition { + return this.declaration.definition; + } - get documentation(): ts.SymbolDisplayPart[] { return this.declaration.type.documentation; } + get documentation(): ts.SymbolDisplayPart[] { + return this.declaration.type.documentation; + } - members(): SymbolTable { return this.type.members(); } + members(): SymbolTable { + return this.type.members(); + } - signatures(): Signature[] { return this.type.signatures(); } + signatures(): Signature[] { + return this.type.signatures(); + } - selectSignature(types: Symbol[]): Signature|undefined { return this.type.selectSignature(types); } + selectSignature(types: Symbol[]): Signature|undefined { + return this.type.selectSignature(types); + } - typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.type.typeArguments(); + } - indexed(argument: Symbol): Symbol|undefined { return undefined; } + indexed(argument: Symbol): Symbol|undefined { + return undefined; + } } class SignatureWrapper implements Signature { @@ -435,15 +487,21 @@ class SignatureWrapper implements Signature { return new SymbolTableWrapper(this.signature.getParameters(), this.context); } - get result(): Symbol { return new TypeWrapper(this.signature.getReturnType(), this.context); } + get result(): Symbol { + return new TypeWrapper(this.signature.getReturnType(), this.context); + } } class SignatureResultOverride implements Signature { constructor(private signature: Signature, private resultType: Symbol) {} - get arguments(): SymbolTable { return this.signature.arguments; } + get arguments(): SymbolTable { + return this.signature.arguments; + } - get result(): Symbol { return this.resultType; } + get result(): Symbol { + return this.resultType; + } } export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { @@ -456,7 +514,7 @@ export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { return result as ts.SymbolTable; } -function toSymbols(symbolTable: ts.SymbolTable | undefined): ts.Symbol[] { +function toSymbols(symbolTable: ts.SymbolTable|undefined): ts.Symbol[] { if (!symbolTable) return []; const table = symbolTable as any; @@ -507,7 +565,9 @@ class SymbolTableWrapper implements SymbolTable { } } - get size(): number { return this.symbols.length; } + get size(): number { + return this.symbols.length; + } get(key: string): Symbol|undefined { const symbol = getFromSymbolTable(this.symbolTable, key); @@ -535,20 +595,26 @@ class SymbolTableWrapper implements SymbolTable { this.stringIndexType !== undefined; } - values(): Symbol[] { return this.symbols.map(s => new SymbolWrapper(s, this.context)); } + values(): Symbol[] { + return this.symbols.map(s => new SymbolWrapper(s, this.context)); + } } class MapSymbolTable implements SymbolTable { private map = new Map<string, Symbol>(); private _values: Symbol[] = []; - get size(): number { return this.map.size; } + get size(): number { + return this.map.size; + } - get(key: string): Symbol|undefined { return this.map.get(key); } + get(key: string): Symbol|undefined { + return this.map.get(key); + } add(symbol: Symbol) { if (this.map.has(symbol.name)) { - const previous = this.map.get(symbol.name) !; + const previous = this.map.get(symbol.name)!; this._values[this._values.indexOf(previous)] = symbol; } this.map.set(symbol.name, symbol); @@ -561,7 +627,9 @@ class MapSymbolTable implements SymbolTable { } } - has(key: string): boolean { return this.map.has(key); } + has(key: string): boolean { + return this.map.has(key); + } values(): Symbol[] { // Switch to this.map.values once iterables are supported by the target language. @@ -572,7 +640,9 @@ class MapSymbolTable implements SymbolTable { class PipesTable implements SymbolTable { constructor(private pipes: CompilePipeSummary[], private context: TypeContext) {} - get size() { return this.pipes.length; } + get size() { + return this.pipes.length; + } get(key: string): Symbol|undefined { const pipe = this.pipes.find(pipe => pipe.name == key); @@ -581,9 +651,13 @@ class PipesTable implements SymbolTable { } } - has(key: string): boolean { return this.pipes.find(pipe => pipe.name == key) != null; } + has(key: string): boolean { + return this.pipes.find(pipe => pipe.name == key) != null; + } - values(): Symbol[] { return this.pipes.map(pipe => new PipeSymbol(pipe, this.context)); } + values(): Symbol[] { + return this.pipes.map(pipe => new PipeSymbol(pipe, this.context)); + } } // This matches .d.ts files that look like ".../<package-name>/<package-name>.d.ts", @@ -600,9 +674,13 @@ class PipeSymbol implements Symbol { constructor(private pipe: CompilePipeSummary, private context: TypeContext) {} - get name(): string { return this.pipe.name; } + get name(): string { + return this.pipe.name; + } - get type(): TypeWrapper { return new TypeWrapper(this.tsType, this.context); } + get type(): TypeWrapper { + return new TypeWrapper(this.tsType, this.context); + } get definition(): Definition|undefined { const symbol = this.tsType.getSymbol(); @@ -617,12 +695,16 @@ class PipeSymbol implements Symbol { return symbol.getDocumentationComment(this.context.checker); } - members(): SymbolTable { return EmptyTable.instance; } + members(): SymbolTable { + return EmptyTable.instance; + } - signatures(): Signature[] { return signaturesOf(this.tsType, this.context); } + signatures(): Signature[] { + return signaturesOf(this.tsType, this.context); + } selectSignature(types: Symbol[]): Signature|undefined { - let signature = selectSignature(this.tsType, this.context, types) !; + let signature = selectSignature(this.tsType, this.context, types)!; if (types.length > 0) { const parameterType = types[0]; let resultType: Symbol|undefined = undefined; @@ -645,16 +727,20 @@ class PipeSymbol implements Symbol { return signature; } - indexed(argument: Symbol): Symbol|undefined { return undefined; } + indexed(argument: Symbol): Symbol|undefined { + return undefined; + } - typeArguments(): Symbol[]|undefined { return this.type.typeArguments(); } + typeArguments(): Symbol[]|undefined { + return this.type.typeArguments(); + } private get tsType(): ts.Type { let type = this._tsType; if (!type) { const classSymbol = this.findClassSymbol(this.pipe.type.reference); if (classSymbol) { - type = this._tsType = this.findTransformMethodType(classSymbol) !; + type = this._tsType = this.findTransformMethodType(classSymbol)!; } if (!type) { type = this._tsType = getTsTypeFromBuiltinType(BuiltinType.Any, this.context); @@ -700,9 +786,15 @@ function findClassSymbolInContext(type: StaticSymbol, context: TypeContext): ts. class EmptyTable implements SymbolTable { public readonly size: number = 0; - get(key: string): Symbol|undefined { return undefined; } - has(key: string): boolean { return false; } - values(): Symbol[] { return []; } + get(key: string): Symbol|undefined { + return undefined; + } + has(key: string): boolean { + return false; + } + values(): Symbol[] { + return []; + } static instance = new EmptyTable(); } @@ -743,7 +835,7 @@ function getTsTypeFromBuiltinType(builtinType: BuiltinType, ctx: TypeContext): t function spanAt(sourceFile: ts.SourceFile, line: number, column: number): Span|undefined { if (line != null && column != null) { const position = ts.getPositionOfLineAndCharacter(sourceFile, line, column); - const findChild = function findChild(node: ts.Node): ts.Node | undefined { + const findChild = function findChild(node: ts.Node): ts.Node|undefined { if (node.kind > ts.SyntaxKind.LastToken && node.pos <= position && node.end > position) { const betterNode = ts.forEachChild(node, findChild); return betterNode || node; @@ -779,7 +871,7 @@ function parentDeclarationOf(node: ts.Node): ts.Node|undefined { case ts.SyntaxKind.SourceFile: return undefined; } - node = node.parent !; + node = node.parent!; } } @@ -797,7 +889,7 @@ function getContainerOf(symbol: ts.Symbol, context: TypeContext): Symbol|undefin } } -function typeKindOf(type: ts.Type | undefined): BuiltinType { +function typeKindOf(type: ts.Type|undefined): BuiltinType { if (type) { if (type.flags & ts.TypeFlags.Any) { return BuiltinType.Any; diff --git a/packages/language-service/src/utils.ts b/packages/language-service/src/utils.ts index 6d00eace56774..e2f9de8bab97d 100644 --- a/packages/language-service/src/utils.ts +++ b/packages/language-service/src/utils.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, identifierName, templateVisitAll, visitAll} from '@angular/compiler'; +import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, identifierName, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, templateVisitAll, visitAll} from '@angular/compiler'; import * as ts from 'typescript'; import {AstResult, SelectorInfo} from './common'; @@ -25,8 +25,8 @@ export function isParseSourceSpan(value: any): value is ParseSourceSpan { export function spanOf(span: SpanHolder): Span; export function spanOf(span: ParseSourceSpan): Span; -export function spanOf(span: SpanHolder | ParseSourceSpan | undefined): Span|undefined; -export function spanOf(span?: SpanHolder | ParseSourceSpan): Span|undefined { +export function spanOf(span: SpanHolder|ParseSourceSpan|undefined): Span|undefined; +export function spanOf(span?: SpanHolder|ParseSourceSpan): Span|undefined { if (!span) return undefined; if (isParseSourceSpan(span)) { return {start: span.start.offset, end: span.end.offset}; @@ -36,7 +36,7 @@ export function spanOf(span?: SpanHolder | ParseSourceSpan): Span|undefined { } else if (span.children && span.children.length) { return { start: span.sourceSpan.start.offset, - end: spanOf(span.children[span.children.length - 1]) !.end + end: spanOf(span.children[span.children.length - 1])!.end }; } return {start: span.sourceSpan.start.offset, end: span.sourceSpan.end.offset}; @@ -44,8 +44,9 @@ export function spanOf(span?: SpanHolder | ParseSourceSpan): Span|undefined { } export function inSpan(position: number, span?: Span, exclusive?: boolean): boolean { - return span != null && (exclusive ? position >= span.start && position < span.end : - position >= span.start && position <= span.end); + return span != null && + (exclusive ? position >= span.start && position < span.end : + position >= span.start && position <= span.end); } export function offsetSpan(span: Span, amount: number): Span { @@ -71,7 +72,7 @@ export function getSelectors(info: AstResult): SelectorInfo { const map = new Map<CssSelector, CompileDirectiveSummary>(); const results: CssSelector[] = []; for (const directive of info.directives) { - const selectors: CssSelector[] = CssSelector.parse(directive.selector !); + const selectors: CssSelector[] = CssSelector.parse(directive.selector!); for (const selector of selectors) { results.push(selector); map.set(selector, directive); @@ -141,7 +142,9 @@ export function findTemplateAstAt(ast: TemplateAst[], position: number): Templat visitDirective(ast: DirectiveAst, context: any): any { // Ignore the host properties of a directive - const result = this.visitChildren(context, visit => { visit(ast.inputs); }); + const result = this.visitChildren(context, visit => { + visit(ast.inputs); + }); // We never care about the diretive itself, just its inputs. if (path[path.length - 1] === ast) { path.pop(); diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index ed8f3e081f5ae..9e12a5db67938 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -25,7 +25,9 @@ describe('completions', () => { const ngHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should be able to get entity completions', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'entity-amp'); @@ -102,7 +104,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(APP_COMPONENT, 'h2-hero'); const completions = ngLS.getCompletionsAtPosition(APP_COMPONENT, marker.start); expect(completions).toBeDefined(); - const internal = completions !.entries.find(e => e.name === 'internal'); + const internal = completions!.entries.find(e => e.name === 'internal'); expect(internal).toBeUndefined(); }); @@ -202,7 +204,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - expect(completions !.entries).toContain(jasmine.objectContaining({ + expect(completions!.entries).toContain(jasmine.objectContaining({ name: 'myClick', kind: CompletionKind.METHOD as any, insertText: 'myClick()', @@ -214,7 +216,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'pipe-method'); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - expect(completions !.entries).toContain(jasmine.objectContaining({ + expect(completions!.entries).toContain(jasmine.objectContaining({ name: 'lowercase', kind: CompletionKind.PIPE as any, insertText: 'lowercase', @@ -234,7 +236,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, location); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - const {entries} = completions !; + const {entries} = completions!; expect(entries).not.toContain(jasmine.objectContaining({name: 'div'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'h1'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'h2'})); @@ -257,7 +259,7 @@ describe('completions', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'h1-after-space'); const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expect(completions).toBeDefined(); - const {entries} = completions !; + const {entries} = completions!; expect(entries).not.toContain(jasmine.objectContaining({name: 'class'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'id'})); expect(entries).not.toContain(jasmine.objectContaining({name: 'onclick'})); @@ -536,9 +538,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'key') !; + const completion = completions.entries.find(entry => entry.name === 'key')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('property'); expect(completion.replacementSpan).toBeUndefined(); @@ -553,9 +555,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'start'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'acronym') !; + const completion = completions.entries.find(entry => entry.name === 'acronym')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('html element'); expect(completion.replacementSpan).toEqual({start: location.start, length: 3}); @@ -570,9 +572,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'end'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'acronym') !; + const completion = completions.entries.find(entry => entry.name === 'acronym')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('html element'); expect(completion.replacementSpan).toEqual({start: location.start - 4, length: 4}); @@ -591,9 +593,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'key'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'key') !; + const completion = completions.entries.find(entry => entry.name === 'key')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('property'); expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 5}); @@ -612,9 +614,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'field'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === '$title_1') !; + const completion = completions.entries.find(entry => entry.name === '$title_1')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('property'); expect(completion.replacementSpan).toEqual({start: location.start, length: 8}); @@ -631,9 +633,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'click'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'click') !; + const completion = completions.entries.find(entry => entry.name === 'click')!; expect(completion).toBeDefined(); expect(completion.kind).toBe(CompletionKind.ATTRIBUTE); expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); @@ -652,9 +654,9 @@ describe('completions', () => { } `); const location = mockHost.getLocationMarkerFor(fileName, 'handleClick'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'handleClick') !; + const completion = completions.entries.find(entry => entry.name === 'handleClick')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('method'); expect(completion.replacementSpan).toEqual({start: location.start - 3, length: 3}); @@ -671,9 +673,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'div'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'div') !; + const completion = completions.entries.find(entry => entry.name === 'div')!; expect(completion).toBeDefined(); expect(completion.kind).toBe('html element'); expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); @@ -690,9 +692,9 @@ describe('completions', () => { export class FooComponent {} `); const location = mockHost.getLocationMarkerFor(fileName, 'model'); - const completions = ngLS.getCompletionsAtPosition(fileName, location.start) !; + const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'ngModel') !; + const completion = completions.entries.find(entry => entry.name === 'ngModel')!; expect(completion).toBeDefined(); expect(completion.kind).toBe(CompletionKind.ATTRIBUTE); expect(completion.replacementSpan).toEqual({start: location.start - 5, length: 5}); @@ -741,14 +743,14 @@ describe('completions', () => { it('should be able to get the completions (ref- prefix)', () => { mockHost.override(TEST_TEMPLATE, `<form ref-itemForm="ngF~{reference}"></form>`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference'); - const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !; + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start)!; expectContain(completions, CompletionKind.REFERENCE, ['ngForm']); }); it('should be able to get the completions (# prefix)', () => { mockHost.override(TEST_TEMPLATE, `<form #itemForm="ngF~{reference}"></form>`); const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'reference'); - const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start) !; + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start)!; expectContain(completions, CompletionKind.REFERENCE, ['ngForm']); }); }); @@ -789,9 +791,9 @@ describe('completions', () => { }); function expectContain( - completions: ts.CompletionInfo | undefined, kind: CompletionKind, names: string[]) { + completions: ts.CompletionInfo|undefined, kind: CompletionKind, names: string[]) { expect(completions).toBeDefined(); for (const name of names) { - expect(completions !.entries).toContain(jasmine.objectContaining({ name, kind } as any)); + expect(completions!.entries).toContain(jasmine.objectContaining({name, kind} as any)); } } diff --git a/packages/language-service/test/definitions_spec.ts b/packages/language-service/test/definitions_spec.ts index 69d34a2f38cc5..dcf5f25bea4b9 100644 --- a/packages/language-service/test/definitions_spec.ts +++ b/packages/language-service/test/definitions_spec.ts @@ -22,7 +22,9 @@ describe('definitions', () => { const ngHost = new TypeScriptServiceHost(mockHost, service); const ngService = createLanguageService(ngHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should be able to find field in an interpolation', () => { const fileName = mockHost.addCode(` @@ -36,12 +38,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('name'); @@ -55,20 +57,20 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(PARSING_CASES); expect(def.name).toBe('title'); expect(def.kind).toBe('property'); const fileContent = mockHost.readFile(def.fileName); - expect(fileContent !.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) + expect(fileContent!.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) .toEqual(`title = 'Some title';`); }); @@ -84,12 +86,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'myClick'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(mockHost.getLocationMarkerFor(fileName, 'my')); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('myClick'); @@ -109,12 +111,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'include'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('include'); @@ -134,7 +136,7 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above. const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); @@ -142,14 +144,14 @@ describe('definitions', () => { // There should be exactly 1 definition expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; const refFileName = '/app/parsing-cases.ts'; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('TestComponent'); expect(def.kind).toBe('component'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; const begin = '/*BeginTestComponent*/ '; const start = content.indexOf(begin) + begin.length; const end = content.indexOf(' /*EndTestComponent*/'); @@ -171,7 +173,7 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); @@ -179,14 +181,14 @@ describe('definitions', () => { // There should be exactly 1 definition expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; const refFileName = '/app/parsing-cases.ts'; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('testEvent'); expect(def.kind).toBe('event'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; const ref = `@Output('test') testEvent = new EventEmitter();`; expect(def.textSpan).toEqual({ start: content.indexOf(ref), @@ -208,7 +210,7 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(fileName, 'my'); @@ -216,14 +218,14 @@ describe('definitions', () => { // There should be exactly 1 definition expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; const refFileName = '/app/parsing-cases.ts'; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('name'); expect(def.kind).toBe('property'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; const ref = `@Input('tcName') name = 'test';`; expect(def.textSpan).toEqual({ start: content.indexOf(ref), @@ -245,14 +247,14 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(4); + expect(definitions!.length).toBe(4); const refFileName = '/node_modules/@angular/common/common.d.ts'; - for (const def of definitions !) { + for (const def of definitions!) { expect(def.fileName).toBe(refFileName); expect(def.name).toBe('async'); expect(def.kind).toBe('pipe'); @@ -268,14 +270,14 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); + expect(definitions!.length).toBe(1); const refFileName = '/node_modules/@angular/common/common.d.ts'; - for (const def of definitions !) { + for (const def of definitions!) { expect(def.fileName).toBe(refFileName); expect(def.name).toBe('date'); expect(def.kind).toBe('pipe'); @@ -292,17 +294,17 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); expect(textSpan).toEqual(boundedText); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); + expect(definitions!.length).toBe(1); const refFileName = '/node_modules/@angular/common/common.d.ts'; - const def = definitions ![0]; + const def = definitions![0]; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('NgForOf'); expect(def.kind).toBe('directive'); @@ -317,17 +319,17 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); // The two definitions are setter and getter of 'ngForTrackBy'. - expect(definitions !.length).toBe(2); + expect(definitions!.length).toBe(2); const refFileName = '/node_modules/@angular/common/common.d.ts'; - definitions !.forEach(def => { + definitions!.forEach(def => { expect(def.fileName).toBe(refFileName); expect(def.name).toBe('ngForTrackBy'); expect(def.kind).toBe('method'); @@ -343,19 +345,19 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); + expect(definitions!.length).toBe(1); const refFileName = '/app/parsing-cases.ts'; - const def = definitions ![0]; + const def = definitions![0]; expect(def.fileName).toBe(refFileName); expect(def.name).toBe('heroes'); expect(def.kind).toBe('property'); - const content = mockHost.readFile(refFileName) !; + const content = mockHost.readFile(refFileName)!; expect(content.substring(def.textSpan.start, def.textSpan.start + def.textSpan.length)) .toEqual(`heroes: Hero[] = [this.hero];`); }); @@ -370,28 +372,28 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(TEST_TEMPLATE, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; // Get the marker for bounded text in the code added above const boundedText = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'my'); expect(textSpan).toEqual(boundedText); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(2); - const [def1, def2] = definitions !; + expect(definitions!.length).toBe(2); + const [def1, def2] = definitions!; const refFileName = '/app/parsing-cases.ts'; expect(def1.fileName).toBe(refFileName); expect(def1.name).toBe('model'); expect(def1.kind).toBe('property'); - let content = mockHost.readFile(refFileName) !; + let content = mockHost.readFile(refFileName)!; expect(content.substring(def1.textSpan.start, def1.textSpan.start + def1.textSpan.length)) .toEqual(`@Input() model: string = 'model';`); expect(def2.fileName).toBe(refFileName); expect(def2.name).toBe('modelChange'); expect(def2.kind).toBe('event'); - content = mockHost.readFile(refFileName) !; + content = mockHost.readFile(refFileName)!; expect(content.substring(def2.textSpan.start, def2.textSpan.start + def2.textSpan.length)) .toEqual(`@Output() modelChange: EventEmitter<string> = new EventEmitter();`); }); @@ -407,13 +409,13 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual({start: marker.start - 2, length: 9}); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const [def] = definitions !; + expect(definitions!.length).toBe(1); + const [def] = definitions!; expect(def.fileName).toBe('/app/test.ng'); expect(def.textSpan).toEqual({start: 0, length: 0}); }); @@ -430,13 +432,13 @@ describe('definitions', () => { const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual({start: marker.start - 2, length: 10}); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const [def] = definitions !; + expect(definitions!.length).toBe(1); + const [def] = definitions!; expect(def.fileName).toBe('/app/test.css'); expect(def.textSpan).toEqual({start: 0, length: 0}); }); @@ -453,12 +455,12 @@ describe('definitions', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'name'); const result = ngService.getDefinitionAndBoundSpan(fileName, marker.start); expect(result).toBeDefined(); - const {textSpan, definitions} = result !; + const {textSpan, definitions} = result!; expect(textSpan).toEqual(marker); expect(definitions).toBeDefined(); - expect(definitions !.length).toBe(1); - const def = definitions ![0]; + expect(definitions!.length).toBe(1); + const def = definitions![0]; expect(def.fileName).toBe(fileName); expect(def.name).toBe('name'); diff --git a/packages/language-service/test/diagnostic_messages_spec.ts b/packages/language-service/test/diagnostic_messages_spec.ts index a4dd95e6ecb7d..cc44671fa0f55 100644 --- a/packages/language-service/test/diagnostic_messages_spec.ts +++ b/packages/language-service/test/diagnostic_messages_spec.ts @@ -7,7 +7,8 @@ */ import * as ts from 'typescript'; -import {DiagnosticMessage, createDiagnostic} from '../src/diagnostic_messages'; + +import {createDiagnostic, DiagnosticMessage} from '../src/diagnostic_messages'; describe('create diagnostic', () => { it('should format and create diagnostics correctly', () => { diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index dd51b1d13f24e..6f2aa589c006e 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -34,7 +34,9 @@ describe('diagnostics', () => { const ngHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should produce no diagnostics for test.ng', () => { // there should not be any errors on existing external template @@ -300,7 +302,8 @@ describe('diagnostics', () => { expect(messageText) .toBe( `The template context of 'CounterDirective' does not define an implicit value.\n` + - `If the context type is a base type or 'any', consider refining it to a more specific type.`, ); + `If the context type is a base type or 'any', consider refining it to a more specific type.`, + ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); @@ -337,7 +340,8 @@ describe('diagnostics', () => { expect(category).toBe(ts.DiagnosticCategory.Error); expect(messageText) .toBe( - `Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, ); + `Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, + ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); expect(length).toBe(span.length); @@ -355,7 +359,8 @@ describe('diagnostics', () => { expect(category).toBe(ts.DiagnosticCategory.Error); expect(messageText) .toBe( - `Identifier 'missingField' is not defined. 'Person' does not contain such a member`, ); + `Identifier 'missingField' is not defined. 'Person' does not contain such a member`, + ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); expect(length).toBe(span.length); @@ -396,7 +401,7 @@ describe('diagnostics', () => { it('should reject it when not in an event binding', () => { const content = mockHost.override(TEST_TEMPLATE, '<div [tabIndex]="$event"></div>'); - const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !; + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE)!; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) @@ -410,7 +415,7 @@ describe('diagnostics', () => { it('should reject invalid properties on an event type', () => { const content = mockHost.override( TEST_TEMPLATE, '<div string-model (modelChange)="$event.notSubstring()"></div>'); - const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE) !; + const diagnostics = ngLS.getSemanticDiagnostics(TEST_TEMPLATE)!; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) @@ -436,14 +441,14 @@ describe('diagnostics', () => { template: '<div></div>' }) export class MyComponent {}`); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; expect(diagnostics.length).toBe(1); const {messageText, start, length} = diagnostics[0]; expect(messageText) .toBe( `Component 'MyComponent' is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration.`); - const content = mockHost.readFile(fileName) !; - expect(content.substring(start !, start ! + length !)).toBe('MyComponent'); + const content = mockHost.readFile(fileName)!; + expect(content.substring(start!, start! + length!)).toBe('MyComponent'); }); @@ -495,7 +500,7 @@ describe('diagnostics', () => { }`); const tsDiags = tsLS.getSemanticDiagnostics(APP_COMPONENT); expect(tsDiags).toEqual([]); - const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; + const ngDiags = ngLS.getSemanticDiagnostics(APP_COMPONENT)!; expect(ngDiags.length).toBe(1); const {messageText, start, length} = ngDiags[0]; const keyword = `() => 'foo'`; @@ -504,9 +509,9 @@ describe('diagnostics', () => { // messageText is a three-part chain const firstPart = messageText as ts.DiagnosticMessageChain; expect(firstPart.messageText).toBe(`Error during template compile of 'AppComponent'`); - const secondPart = firstPart.next !; + const secondPart = firstPart.next!; expect(secondPart[0].messageText).toBe('Function expressions are not supported in decorators'); - const thirdPart = secondPart[0].next !; + const thirdPart = secondPart[0].next!; expect(thirdPart[0].messageText) .toBe('Consider changing the function expression into an exported function'); expect(thirdPart[0].next).toBeFalsy(); @@ -568,7 +573,7 @@ describe('diagnostics', () => { export class AppComponent { onClick() { } }`); - const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; + const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT)!; const {messageText, start, length} = diagnostics[0]; expect(messageText).toBe('Unexpected callable expression. Expected a method call'); const keyword = `"onClick"`; @@ -682,7 +687,7 @@ describe('diagnostics', () => { .toBe( 'Invalid providers for "AppComponent in /app/app.component.ts" - only instances of Provider and Type are allowed, got: [?null?]'); // TODO: Looks like this is the wrong span. Should point to 'null' instead. - expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); + expect(content.substring(start!, start! + length!)).toBe('AppComponent'); }); // Issue #15768 @@ -815,12 +820,12 @@ describe('diagnostics', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile'); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeDefined(); - const {start, length} = urlDiagnostic !; + const {start, length} = urlDiagnostic!; expect(start).toBe(marker.start); expect(length).toBe(marker.length); }); @@ -832,7 +837,7 @@ describe('diagnostics', () => { }) export class MyComponent {}`); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeUndefined(); @@ -849,9 +854,9 @@ describe('diagnostics', () => { const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diags.length).toBe(1); const {file, messageText, start, length} = diags[0]; - expect(file !.fileName).toBe(APP_COMPONENT); + expect(file!.fileName).toBe(APP_COMPONENT); expect(messageText).toBe(`Component 'AppComponent' must have a template or templateUrl`); - expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); + expect(content.substring(start!, start! + length!)).toBe('AppComponent'); }); it('should report diagnostic for both template and templateUrl', () => { @@ -867,10 +872,10 @@ describe('diagnostics', () => { const diags = ngLS.getSemanticDiagnostics(APP_COMPONENT); expect(diags.length).toBe(1); const {file, messageText, start, length} = diags[0]; - expect(file !.fileName).toBe(APP_COMPONENT); + expect(file!.fileName).toBe(APP_COMPONENT); expect(messageText) .toBe(`Component 'AppComponent' must not have both template and templateUrl`); - expect(content.substring(start !, start ! + length !)).toBe('AppComponent'); + expect(content.substring(start!, start! + length!)).toBe('AppComponent'); }); it('should report errors for invalid styleUrls', () => { @@ -882,12 +887,12 @@ describe('diagnostics', () => { const marker = mockHost.getReferenceMarkerFor(fileName, 'notAFile'); - const diagnostics = ngLS.getSemanticDiagnostics(fileName) !; + const diagnostics = ngLS.getSemanticDiagnostics(fileName)!; const urlDiagnostic = diagnostics.find(d => d.messageText === 'URL does not point to a valid file'); expect(urlDiagnostic).toBeDefined(); - const {start, length} = urlDiagnostic !; + const {start, length} = urlDiagnostic!; expect(start).toBe(marker.start); expect(length).toBe(marker.length); }); @@ -902,7 +907,7 @@ describe('diagnostics', () => { }) export class AppComponent {}`); - const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT) !; + const diagnostics = ngLS.getSemanticDiagnostics(APP_COMPONENT)!; expect(diagnostics.length).toBe(0); }); }); @@ -926,14 +931,14 @@ describe('diagnostics', () => { `element references do not contain such a member`); // Assert that the span is actually highlight the bounded text. The span // would be off if CRLF endings are not handled properly. - expect(content.substring(start !, start ! + length !)).toBe(`line${i}`); + expect(content.substring(start!, start! + length!)).toBe(`line${i}`); } }); it('should work correctly with CRLF endings in inline template', () => { const fileName = mockHost.addCode( '\n@Component({template:`\r\n\r\n{{line}}`})export class ComponentCRLF {}'); - const content = mockHost.readFile(fileName) !; + const content = mockHost.readFile(fileName)!; const ngDiags = ngLS.getSemanticDiagnostics(fileName); expect(ngDiags.length).toBeGreaterThan(0); const {messageText, start, length} = ngDiags[0]; @@ -942,7 +947,7 @@ describe('diagnostics', () => { `Identifier 'line' is not defined. ` + `The component declaration, template variable declarations, and ` + `element references do not contain such a member`); - expect(content.substring(start !, start ! + length !)).toBe('line'); + expect(content.substring(start!, start! + length!)).toBe('line'); }); it('should not produce diagnostics for non-exported directives', () => { @@ -972,8 +977,7 @@ describe('diagnostics', () => { `Consider using the safe navigation operator (optional?.toLowerCase) ` + `or non-null assertion operator (optional!.toLowerCase).`); expect(category).toBe(ts.DiagnosticCategory.Suggestion); - expect(content.substring(start !, start ! + length !)).toBe('optional.toLowerCase()'); - + expect(content.substring(start!, start! + length!)).toBe('optional.toLowerCase()'); }); it('should suggest ? or ! operator if property receiver is nullable', () => { @@ -987,7 +991,7 @@ describe('diagnostics', () => { `Consider using the safe navigation operator (optional?.length) ` + `or non-null assertion operator (optional!.length).`); expect(category).toBe(ts.DiagnosticCategory.Suggestion); - expect(content.substring(start !, start ! + length !)).toBe('optional.length'); + expect(content.substring(start!, start! + length!)).toBe('optional.length'); }); it('should report error if method is not found on non-nullable receiver', () => { @@ -1003,7 +1007,7 @@ describe('diagnostics', () => { expect(messageText) .toBe(`Identifier 'someMethod' is not defined. 'string' does not contain such a member`); expect(category).toBe(ts.DiagnosticCategory.Error); - expect(content.substring(start !, start ! + length !)).toBe(expression); + expect(content.substring(start!, start! + length!)).toBe(expression); } }); @@ -1020,7 +1024,7 @@ describe('diagnostics', () => { expect(messageText) .toBe(`Identifier 'someProp' is not defined. 'string' does not contain such a member`); expect(category).toBe(ts.DiagnosticCategory.Error); - expect(content.substring(start !, start ! + length !)).toBe(expression); + expect(content.substring(start!, start! + length!)).toBe(expression); } }); @@ -1030,12 +1034,12 @@ describe('diagnostics', () => { <p>{{myClick()()}}</p> `); - const content = mockHost.readFile(TEST_TEMPLATE) !; + const content = mockHost.readFile(TEST_TEMPLATE)!; const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE); expect(diags.length).toBe(1); - const {messageText, start, length} = diags[0] !; + const {messageText, start, length} = diags[0]!; expect(messageText).toBe(`Call target 'myClick()' has non-callable type 'void'.`); - expect(content.substring(start !, start ! + length !)).toBe('myClick()()'); + expect(content.substring(start!, start! + length!)).toBe('myClick()()'); }); }); }); diff --git a/packages/language-service/test/expression_diagnostics_spec.ts b/packages/language-service/test/expression_diagnostics_spec.ts index 8bc33a2a70e68..43640d2443512 100644 --- a/packages/language-service/test/expression_diagnostics_spec.ts +++ b/packages/language-service/test/expression_diagnostics_spec.ts @@ -13,7 +13,7 @@ import * as ts from 'typescript'; import {getTemplateExpressionDiagnostics} from '../src/expression_diagnostics'; -import {DiagnosticContext, MockLanguageServiceHost, getDiagnosticTemplateInfo} from './mocks'; +import {DiagnosticContext, getDiagnosticTemplateInfo, MockLanguageServiceHost} from './mocks'; describe('expression diagnostics', () => { let registry: ts.DocumentRegistry; @@ -27,15 +27,15 @@ describe('expression diagnostics', () => { registry = ts.createDocumentRegistry(false, '/src'); host = new MockLanguageServiceHost(['app/app.component.ts'], FILES, '/src'); service = ts.createLanguageService(host, registry); - const program = service.getProgram() !; + const program = service.getProgram()!; const checker = program.getTypeChecker(); - const symbolResolverHost = new ReflectorHost(() => program !, host); - context = new DiagnosticContext(service, program !, checker, symbolResolverHost); + const symbolResolverHost = new ReflectorHost(() => program!, host); + context = new DiagnosticContext(service, program!, checker, symbolResolverHost); type = context.getStaticSymbol('app/app.component.ts', 'AppComponent'); }); it('should have no diagnostics in default app', () => { - function messageToString(messageText: string | ts.DiagnosticMessageChain): string { + function messageToString(messageText: string|ts.DiagnosticMessageChain): string { if (typeof messageText == 'string') { return messageText; } else { @@ -107,13 +107,14 @@ describe('expression diagnostics', () => { {{p.name.first}} {{p.name.last}} </div> `)); - it('should reject misspelled field in *ngFor', () => reject( - ` + it('should reject misspelled field in *ngFor', + () => reject( + ` <div *ngFor="let p of people"> {{p.names.first}} {{p.name.last}} </div> `, - 'Identifier \'names\' is not defined')); + 'Identifier \'names\' is not defined')); it('should accept an async expression', () => accept('{{(promised_person | async)?.name.first || ""}}')); it('should reject an async misspelled field', @@ -124,25 +125,27 @@ describe('expression diagnostics', () => { {{p.name.first}} {{p.name.last}} </div> `)); - it('should reject misspelled field an async *ngFor', () => reject( - ` + it('should reject misspelled field an async *ngFor', + () => reject( + ` <div *ngFor="let p of promised_people | async"> {{p.name.first}} {{p.nume.last}} </div> `, - 'Identifier \'nume\' is not defined')); + 'Identifier \'nume\' is not defined')); it('should accept an async *ngIf', () => accept(` <div *ngIf="promised_person | async as p"> {{p.name.first}} {{p.name.last}} </div> `)); - it('should reject misspelled field in async *ngIf', () => reject( - ` + it('should reject misspelled field in async *ngIf', + () => reject( + ` <div *ngIf="promised_person | async as p"> {{p.name.first}} {{p.nume.last}} </div> `, - 'Identifier \'nume\' is not defined')); + 'Identifier \'nume\' is not defined')); it('should reject access to potentially undefined field', () => reject( `<div>{{maybe_person.name.first}}`, diff --git a/packages/language-service/test/global_symbols_spec.ts b/packages/language-service/test/global_symbols_spec.ts index f85241bb42bd7..bb0aee8a775d2 100644 --- a/packages/language-service/test/global_symbols_spec.ts +++ b/packages/language-service/test/global_symbols_spec.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript/lib/tsserverlibrary'; -import {EMPTY_SYMBOL_TABLE, createGlobalSymbolTable} from '../src/global_symbols'; +import {createGlobalSymbolTable, EMPTY_SYMBOL_TABLE} from '../src/global_symbols'; import {getSymbolQuery} from '../src/typescript_symbols'; import {MockTypescriptHost} from './test_utils'; @@ -18,7 +18,7 @@ describe('GlobalSymbolTable', () => { const tsLS = ts.createLanguageService(mockHost); it(`contains $any()`, () => { - const program = tsLS.getProgram() !; + const program = tsLS.getProgram()!; const typeChecker = program.getTypeChecker(); const source = ts.createSourceFile('foo.ts', '', ts.ScriptTarget.ES2015); const query = getSymbolQuery(program, typeChecker, source, () => EMPTY_SYMBOL_TABLE); diff --git a/packages/language-service/test/hover_spec.ts b/packages/language-service/test/hover_spec.ts index 9a22801c065cf..425d9078f4da6 100644 --- a/packages/language-service/test/hover_spec.ts +++ b/packages/language-service/test/hover_spec.ts @@ -22,7 +22,9 @@ describe('hover', () => { const ngLSHost = new TypeScriptServiceHost(mockHost, tsLS); const ngLS = createLanguageService(ngLSHost); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); describe('location of hover', () => { it('should find members in a text interpolation', () => { @@ -30,7 +32,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -40,7 +42,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -50,7 +52,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -60,7 +62,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -70,7 +72,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -80,7 +82,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'anyValue'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.anyValue: any'); }); @@ -92,7 +94,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const documentation = toText(quickInfo !.documentation); + const documentation = toText(quickInfo!.documentation); expect(documentation).toBe('This is the title of the `TemplateReference` Component.'); }); @@ -102,7 +104,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); @@ -112,7 +114,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(variable) hero: Hero'); }); @@ -123,7 +125,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'hero'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(variable) hero: Readonly<Hero>'); }); @@ -133,7 +135,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'name'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(variable) name: { readonly name: "name"; }'); }); @@ -144,7 +146,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'myClick'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(method) TemplateReference.myClick: (event: any) => void'); }); @@ -154,7 +156,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'trackBy'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(method) NgForOf<T, U>.ngForTrackBy: TrackByFunction<T>'); }); @@ -164,7 +166,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'heroes'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.heroes: Hero[]'); }); @@ -175,7 +177,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'date'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)) .toBe( @@ -187,7 +189,7 @@ describe('hover', () => { const position = content.indexOf('$any'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, position); expect(quickInfo).toBeDefined(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual({ start: position, length: '$any(title)'.length, @@ -202,7 +204,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const documentation = toText(quickInfo !.documentation); + const documentation = toText(quickInfo!.documentation); expect(documentation).toBe('This Component provides the `test-comp` selector.'); }); @@ -211,7 +213,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const {displayParts, documentation} = quickInfo !; + const {displayParts, documentation} = quickInfo!; expect(toText(displayParts)) .toBe('(component) AppModule.TestComponent: typeof TestComponent'); expect(toText(documentation)).toBe('This Component provides the `test-comp` selector.'); @@ -222,7 +224,7 @@ describe('hover', () => { const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeDefined(); - const {displayParts, textSpan} = quickInfo !; + const {displayParts, textSpan} = quickInfo!; expect(toText(displayParts)).toBe('(directive) AppModule.StringModel: typeof StringModel'); expect(content.substring(textSpan.start, textSpan.start + textSpan.length)) .toBe('string-model'); @@ -233,7 +235,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'test'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(event) TestComponent.testEvent: EventEmitter<any>'); }); @@ -243,7 +245,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'tcName'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TestComponent.name: string'); }); @@ -254,7 +256,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'model'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) StringModel.model: string'); }); @@ -264,7 +266,7 @@ describe('hover', () => { const marker = mockHost.getDefinitionMarkerFor(TEST_TEMPLATE, 'ngFor'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(directive) NgForOf: typeof NgForOf'); }); @@ -272,12 +274,12 @@ describe('hover', () => { describe('hovering on TypeScript nodes', () => { it('should work for component TypeScript declarations', () => { - const content = mockHost.readFile(PARSING_CASES) !; + const content = mockHost.readFile(PARSING_CASES)!; const position = content.indexOf('TemplateReference'); expect(position).toBeGreaterThan(0); const quickInfo = ngLS.getQuickInfoAtPosition(PARSING_CASES, position); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual({ start: position, length: 'TemplateReference'.length, @@ -286,12 +288,12 @@ describe('hover', () => { }); it('should work for directive TypeScript declarations', () => { - const content = mockHost.readFile(PARSING_CASES) !; + const content = mockHost.readFile(PARSING_CASES)!; const position = content.indexOf('StringModel'); expect(position).toBeGreaterThan(0); const quickInfo = ngLS.getQuickInfoAtPosition(PARSING_CASES, position); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual({ start: position, length: 'StringModel'.length, @@ -313,7 +315,7 @@ describe('hover', () => { const marker = mockHost.getReferenceMarkerFor(TEST_TEMPLATE, 'title'); const quickInfo = ngLS.getQuickInfoAtPosition(TEST_TEMPLATE, marker.start); expect(quickInfo).toBeTruthy(); - const {textSpan, displayParts} = quickInfo !; + const {textSpan, displayParts} = quickInfo!; expect(textSpan).toEqual(marker); expect(toText(displayParts)).toBe('(property) TemplateReference.title: string'); }); diff --git a/packages/language-service/test/html_info_spec.ts b/packages/language-service/test/html_info_spec.ts index 62cefdbfc22ce..3781eb3f73670 100644 --- a/packages/language-service/test/html_info_spec.ts +++ b/packages/language-service/test/html_info_spec.ts @@ -32,7 +32,6 @@ describe('html_info', () => { } } }); - }); function uniqueElements<T>(a: T[], b: T[]): T[] { diff --git a/packages/language-service/test/language_service_spec.ts b/packages/language-service/test/language_service_spec.ts index a271928230bd0..3fd10de9cd4d2 100644 --- a/packages/language-service/test/language_service_spec.ts +++ b/packages/language-service/test/language_service_spec.ts @@ -21,20 +21,25 @@ describe('service without angular', () => { const fileName = '/app/test.ng'; const position = mockHost.getLocationMarkerFor(fileName, 'h1-content').start; - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); - it('should not crash a get diagnostics', - () => { expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow(); }); + it('should not crash a get diagnostics', () => { + expect(() => ngService.getSemanticDiagnostics(fileName)).not.toThrow(); + }); - it('should not crash a completion', - () => { expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow(); }); + it('should not crash a completion', () => { + expect(() => ngService.getCompletionsAtPosition(fileName, position)).not.toThrow(); + }); it('should not crash a get definition', () => { expect(() => ngService.getDefinitionAndBoundSpan(fileName, position)).not.toThrow(); }); - it('should not crash a hover', - () => { expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow(); }); + it('should not crash a hover', () => { + expect(() => ngService.getQuickInfoAtPosition(fileName, position)).not.toThrow(); + }); it('should not crash with an incomplete class', () => { mockHost.addCode('\nexport class'); diff --git a/packages/language-service/test/mocks.ts b/packages/language-service/test/mocks.ts index b58ea156519dd..4fdcc66d12151 100644 --- a/packages/language-service/test/mocks.ts +++ b/packages/language-service/test/mocks.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotSummaryResolver, CompileMetadataResolver, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, ParseTreeResult, Parser, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, TemplateParser, analyzeNgModules, createOfflineCompileUrlResolver} from '@angular/compiler'; +import {analyzeNgModules, AotSummaryResolver, CompileMetadataResolver, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, TemplateParser} from '@angular/compiler'; import {Directory, MockAotContext} from '@angular/compiler-cli/test/mocks'; import {setup} from '@angular/compiler-cli/test/test_support'; import {ViewEncapsulation, ɵConsole as Console} from '@angular/core'; @@ -45,11 +45,17 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { this.context = new MockAotContext(currentDirectory, files); } - getCompilationSettings(): ts.CompilerOptions { return this.options; } + getCompilationSettings(): ts.CompilerOptions { + return this.options; + } - getScriptFileNames(): string[] { return this.scripts; } + getScriptFileNames(): string[] { + return this.scripts; + } - getScriptVersion(fileName: string): string { return '0'; } + getScriptVersion(fileName: string): string { + return '0'; + } getScriptSnapshot(fileName: string): ts.IScriptSnapshot|undefined { const content = this.internalReadFile(fileName); @@ -58,15 +64,25 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { } } - getCurrentDirectory(): string { return this.context.currentDirectory; } + getCurrentDirectory(): string { + return this.context.currentDirectory; + } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } - readFile(fileName: string): string { return this.internalReadFile(fileName) as string; } + readFile(fileName: string): string { + return this.internalReadFile(fileName) as string; + } - readResource(fileName: string): Promise<string> { return Promise.resolve(''); } + readResource(fileName: string): Promise<string> { + return Promise.resolve(''); + } - assumeFileExists(fileName: string): void { this.assumedExist.add(fileName); } + assumeFileExists(fileName: string): void { + this.assumedExist.add(fileName); + } fileExists(fileName: string): boolean { return this.assumedExist.has(fileName) || this.internalReadFile(fileName) != null; @@ -99,10 +115,18 @@ export class MockLanguageServiceHost implements ts.LanguageServiceHost { const staticSymbolCache = new StaticSymbolCache(); const summaryResolver = new AotSummaryResolver( { - loadSummary(filePath: string) { return null; }, - isSourceFile(sourceFilePath: string) { return true; }, - toSummaryFileName(sourceFilePath: string) { return sourceFilePath; }, - fromSummaryFileName(filePath: string): string{return filePath;}, + loadSummary(filePath: string) { + return null; + }, + isSourceFile(sourceFilePath: string) { + return true; + }, + toSummaryFileName(sourceFilePath: string) { + return sourceFilePath; + }, + fromSummaryFileName(filePath: string): string { + return filePath; + }, }, staticSymbolCache); @@ -117,7 +141,9 @@ export class DiagnosticContext { public service: ts.LanguageService, public program: ts.Program, public checker: ts.TypeChecker, public host: StaticSymbolResolverHost) {} - private collectError(e: any, path?: string) { this._errors.push({e, path}); } + private collectError(e: any, path?: string) { + this._errors.push({e, path}); + } private get staticSymbolResolver(): StaticSymbolResolver { let result = this._staticSymbolResolver; @@ -133,7 +159,7 @@ export class DiagnosticContext { if (!this._reflector) { const ssr = this.staticSymbolResolver; const result = this._reflector = new StaticReflector( - summaryResolver, ssr, [], [], (e, filePath) => this.collectError(e, filePath !)); + summaryResolver, ssr, [], [], (e, filePath) => this.collectError(e, filePath!)); this._reflector = result; return result; } @@ -148,11 +174,15 @@ export class DiagnosticContext { const pipeResolver = new PipeResolver(this.reflector); const elementSchemaRegistry = new DomElementSchemaRegistry(); const resourceLoader = new class extends ResourceLoader { - get(url: string): Promise<string> { return Promise.resolve(''); } + get(url: string): Promise<string> { + return Promise.resolve(''); + } }; const urlResolver = createOfflineCompileUrlResolver(); const htmlParser = new class extends HtmlParser { - parse(): ParseTreeResult { return new ParseTreeResult([], []); } + parse(): ParseTreeResult { + return new ParseTreeResult([], []); + } }; // This tracks the CompileConfig in codegen.ts. Currently these options @@ -174,7 +204,11 @@ export class DiagnosticContext { get analyzedModules(): NgAnalyzedModules { let analyzedModules = this._analyzedModules; if (!analyzedModules) { - const analyzeHost = {isSourceFile(filePath: string) { return true; }}; + const analyzeHost = { + isSourceFile(filePath: string) { + return true; + } + }; const programFiles = this.program.getSourceFiles().map(sf => sf.fileName); analyzedModules = this._analyzedModules = analyzeNgModules(programFiles, analyzeHost, this.staticSymbolResolver, this.resolver); @@ -198,7 +232,7 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat const config = new CompilerConfig(); const parser = new TemplateParser( config, context.reflector, expressionParser, new DomElementSchemaRegistry(), htmlParser, - null !, []); + null!, []); const htmlResult = htmlParser.parse(template, '', {tokenizeExpansionForms: true}); const analyzedModules = context.analyzedModules; // let errors: Diagnostic[]|undefined = undefined; @@ -214,8 +248,11 @@ function compileTemplate(context: DiagnosticContext, type: StaticSymbol, templat return { htmlAst: htmlResult.rootNodes, templateAst: parseResult.templateAst, - directive: metadata, directives, pipes, - parseErrors: parseResult.errors, expressionParser + directive: metadata, + directives, + pipes, + parseErrors: parseResult.errors, + expressionParser }; } } @@ -236,7 +273,9 @@ export function getDiagnosticTemplateInfo( sourceFile, context.program, context.checker, compiledTemplate.pipes)); return { fileName: templateFile, - offset: 0, query, members, + offset: 0, + query, + members, htmlAst: compiledTemplate.htmlAst, templateAst: compiledTemplate.templateAst, source: sourceFile.text, @@ -246,6 +285,6 @@ export function getDiagnosticTemplateInfo( } } -function removeMissing<T>(values: (T | null | undefined)[]): T[] { +function removeMissing<T>(values: (T|null|undefined)[]): T[] { return values.filter(e => !!e) as T[]; } diff --git a/packages/language-service/test/reflector_host_spec.ts b/packages/language-service/test/reflector_host_spec.ts index 717c91e5368cd..39aa4cc922911 100644 --- a/packages/language-service/test/reflector_host_spec.ts +++ b/packages/language-service/test/reflector_host_spec.ts @@ -15,7 +15,6 @@ import {TypeScriptServiceHost} from '../src/typescript_host'; import {MockTypescriptHost} from './test_utils'; describe('reflector_host_spec', () => { - // Regression #21811 it('should be able to find angular under windows', () => { const originalJoin = path.join; @@ -24,15 +23,16 @@ describe('reflector_host_spec', () => { new MockTypescriptHost(['/app/main.ts', '/app/parsing-cases.ts'], 'node_modules', { ...path, join: (...args: string[]) => originalJoin.apply(path, args), - posix: - {...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)} + posix: {...path.posix, join: (...args: string[]) => originalPosixJoin.apply(path, args)} }); const reflectorHost = new ReflectorHost(() => undefined as any, mockHost); if (process.platform !== 'win32') { // If we call this in Windows it will cause a 'Maximum call stack size exceeded error' // Because we are spying on the same function that we are call faking - spyOn(path, 'join').and.callFake((...args: string[]) => { return path.win32.join(...args); }); + spyOn(path, 'join').and.callFake((...args: string[]) => { + return path.win32.join(...args); + }); } const result = reflectorHost.moduleNameToFileName('@angular/core'); diff --git a/packages/language-service/test/template_spec.ts b/packages/language-service/test/template_spec.ts index 7617e2779baa4..1574e3ef34248 100644 --- a/packages/language-service/test/template_spec.ts +++ b/packages/language-service/test/template_spec.ts @@ -11,7 +11,6 @@ import {getClassDeclFromDecoratorProp} from '../src/template'; import {MockTypescriptHost} from './test_utils'; describe('getClassDeclFromTemplateNode', () => { - it('should find class declaration in syntax-only mode', () => { const sourceFile = ts.createSourceFile( 'foo.ts', ` @@ -28,24 +27,24 @@ describe('getClassDeclFromTemplateNode', () => { } const classDecl = sourceFile.forEachChild(visit); expect(classDecl).toBeTruthy(); - expect(classDecl !.kind).toBe(ts.SyntaxKind.ClassDeclaration); - expect((classDecl as ts.ClassDeclaration).name !.text).toBe('MyComponent'); + expect(classDecl!.kind).toBe(ts.SyntaxKind.ClassDeclaration); + expect((classDecl as ts.ClassDeclaration).name!.text).toBe('MyComponent'); }); it('should return class declaration for AppComponent', () => { const host = new MockTypescriptHost(['/app/app.component.ts']); const tsLS = ts.createLanguageService(host); - const sourceFile = tsLS.getProgram() !.getSourceFile('/app/app.component.ts'); + const sourceFile = tsLS.getProgram()!.getSourceFile('/app/app.component.ts'); expect(sourceFile).toBeTruthy(); - const classDecl = sourceFile !.forEachChild(function visit(node): ts.Node | undefined { + const classDecl = sourceFile!.forEachChild(function visit(node): ts.Node|undefined { if (ts.isPropertyAssignment(node)) { return getClassDeclFromDecoratorProp(node); } return node.forEachChild(visit); }); expect(classDecl).toBeTruthy(); - expect(ts.isClassDeclaration(classDecl !)).toBe(true); - expect((classDecl as ts.ClassDeclaration).name !.text).toBe('AppComponent'); + expect(ts.isClassDeclaration(classDecl!)).toBe(true); + expect((classDecl as ts.ClassDeclaration).name!.text).toBe('AppComponent'); }); }); diff --git a/packages/language-service/test/test_utils.ts b/packages/language-service/test/test_utils.ts index 7973e2e37bda9..c58e76ee6f15e 100644 --- a/packages/language-service/test/test_utils.ts +++ b/packages/language-service/test/test_utils.ts @@ -57,11 +57,11 @@ function isFile(path: string) { function loadTourOfHeroes(): ReadonlyMap<string, string> { const {TEST_SRCDIR} = process.env; const root = - path.join(TEST_SRCDIR !, 'angular', 'packages', 'language-service', 'test', 'project'); + path.join(TEST_SRCDIR!, 'angular', 'packages', 'language-service', 'test', 'project'); const dirs = [root]; const files = new Map<string, string>(); while (dirs.length) { - const dirPath = dirs.pop() !; + const dirPath = dirs.pop()!; for (const filePath of fs.readdirSync(dirPath)) { const absPath = path.join(dirPath, filePath); if (isFile(absPath)) { @@ -140,11 +140,17 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { this.projectVersion++; } - getCompilationSettings(): ts.CompilerOptions { return {...this.options}; } + getCompilationSettings(): ts.CompilerOptions { + return {...this.options}; + } - getProjectVersion(): string { return this.projectVersion.toString(); } + getProjectVersion(): string { + return this.projectVersion.toString(); + } - getScriptFileNames(): string[] { return this.scriptNames; } + getScriptFileNames(): string[] { + return this.scriptNames; + } getScriptVersion(fileName: string): string { return (this.scriptVersion.get(fileName) || 0).toString(); @@ -156,9 +162,13 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { return undefined; } - getCurrentDirectory(): string { return '/'; } + getCurrentDirectory(): string { + return '/'; + } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } directoryExists(directoryName: string): boolean { if (this.overrideDirectory.has(directoryName)) return true; @@ -172,7 +182,9 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { return this.pathExists(effectiveName); } - fileExists(fileName: string): boolean { return this.getRawFileContent(fileName) != null; } + fileExists(fileName: string): boolean { + return this.getRawFileContent(fileName) != null; + } readFile(fileName: string): string|undefined { const content = this.getRawFileContent(fileName); @@ -242,7 +254,7 @@ export class MockTypescriptHost implements ts.LanguageServiceHost { private pathExists(path: string): boolean { if (this.existsCache.has(path)) { - return this.existsCache.get(path) !; + return this.existsCache.get(path)!; } const exists = fs.existsSync(path); @@ -411,8 +423,9 @@ function getReferenceMarkers(value: string): ReferenceResult { let adjustment = 0; const text = value.replace( - referenceMarker, (match: string, text: string, reference: string, _: string, - definition: string, definitionName: string, index: number): string => { + referenceMarker, + (match: string, text: string, reference: string, _: string, definition: string, + definitionName: string, index: number): string => { const result = reference ? text : text.replace(/ᐱ/g, ''); const span: Span = {start: index - adjustment, end: index - adjustment + result.length}; const markers = reference ? references : definitions; diff --git a/packages/language-service/test/ts_plugin_spec.ts b/packages/language-service/test/ts_plugin_spec.ts index 37c373d39862a..97d93a253c871 100644 --- a/packages/language-service/test/ts_plugin_spec.ts +++ b/packages/language-service/test/ts_plugin_spec.ts @@ -26,7 +26,7 @@ const mockProject = { describe('plugin', () => { const mockHost = new MockTypescriptHost(['/app/main.ts']); const tsLS = ts.createLanguageService(mockHost); - const program = tsLS.getProgram() !; + const program = tsLS.getProgram()!; const plugin = create({ languageService: tsLS, languageServiceHost: mockHost, @@ -35,7 +35,9 @@ describe('plugin', () => { config: {}, }); - beforeEach(() => { mockHost.reset(); }); + beforeEach(() => { + mockHost.reset(); + }); it('should produce TypeScript diagnostics', () => { const fileName = '/foo.ts'; @@ -117,7 +119,7 @@ describe('plugin', () => { const marker = mockHost.getLocationMarkerFor(MY_COMPONENT, 'tree'); const completions = plugin.getCompletionsAtPosition(MY_COMPONENT, marker.start, undefined); expect(completions).toBeDefined(); - expect(completions !.entries).toEqual([ + expect(completions!.entries).toEqual([ { name: 'children', kind: CompletionKind.PROPERTY as any, diff --git a/packages/language-service/test/typescript_host_spec.ts b/packages/language-service/test/typescript_host_spec.ts index dadf9e9e7c585..7d383c46d6a03 100644 --- a/packages/language-service/test/typescript_host_spec.ts +++ b/packages/language-service/test/typescript_host_spec.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {TypeScriptServiceHost} from '../src/typescript_host'; -import {MockTypescriptHost, findDirectiveMetadataByName} from './test_utils'; +import {findDirectiveMetadataByName, MockTypescriptHost} from './test_utils'; describe('TypeScriptServiceHost', () => { @@ -62,7 +62,7 @@ describe('TypeScriptServiceHost', () => { expect(oldModules.ngModules).toEqual([]); // Now add a script, this would change the program const fileName = '/app/main.ts'; - const content = tsLSHost.readFile(fileName) !; + const content = tsLSHost.readFile(fileName)!; tsLSHost.addScript(fileName, content); // If the caches are not cleared, we would get back an empty array. // But if the caches are cleared then the analyzed modules will be non-empty. @@ -121,8 +121,8 @@ describe('TypeScriptServiceHost', () => { expect(oldModules.symbolsMissingModule).toEqual([]); // Expect to find AppComponent in the old modules const oldFile = oldModules.files.find(f => f.fileName === fileName); - expect(oldFile !.directives.length).toBe(1); - const appComp = oldFile !.directives[0]; + expect(oldFile!.directives.length).toBe(1); + const appComp = oldFile!.directives[0]; expect(appComp.name).toBe('AppComponent'); expect(oldModules.ngModuleByPipeOrDirective.has(appComp)).toBe(true); @@ -154,8 +154,8 @@ describe('TypeScriptServiceHost', () => { expect(newModules.symbolsMissingModule).toEqual([]); // Expect to find HelloComponent in the new modules const newFile = newModules.files.find(f => f.fileName === fileName); - expect(newFile !.directives.length).toBe(1); - const helloComp = newFile !.directives[0]; + expect(newFile!.directives.length).toBe(1); + const helloComp = newFile!.directives[0]; expect(helloComp.name).toBe('HelloComponent'); expect(newModules.ngModuleByPipeOrDirective.has(helloComp)).toBe(true); expect(newModules.ngModuleByPipeOrDirective.has(appComp)).toBe(false); diff --git a/packages/language-service/test/typescript_symbols_spec.ts b/packages/language-service/test/typescript_symbols_spec.ts index aa4064949b885..058d49a0dc3f6 100644 --- a/packages/language-service/test/typescript_symbols_spec.ts +++ b/packages/language-service/test/typescript_symbols_spec.ts @@ -18,9 +18,15 @@ import {DiagnosticContext, MockLanguageServiceHost} from './mocks'; function emptyPipes(): SymbolTable { return { size: 0, - get(key: string) { return undefined; }, - has(key: string) { return false; }, - values(): Symbol[]{return [];} + get(key: string) { + return undefined; + }, + has(key: string) { + return false; + }, + values(): Symbol[] { + return []; + } }; } @@ -35,9 +41,9 @@ describe('symbol query', () => { const host = new MockLanguageServiceHost( ['/quickstart/app/app.component.ts'], QUICKSTART, '/quickstart'); const service = ts.createLanguageService(host, registry); - program = service.getProgram() !; + program = service.getProgram()!; checker = program.getTypeChecker(); - sourceFile = program.getSourceFile('/quickstart/app/app.component.ts') !; + sourceFile = program.getSourceFile('/quickstart/app/app.component.ts')!; const symbolResolverHost = new ReflectorHost(() => program, host); context = new DiagnosticContext(service, program, checker, symbolResolverHost); query = getSymbolQuery(program, checker, sourceFile, emptyPipes); @@ -67,7 +73,7 @@ describe('symbol query', () => { } else { const symbol = query.getBuiltinType(builtinType); const got: ts.TypeFlags = (symbol as any).tsType.flags; - expect(got).toBe(want !); + expect(got).toBe(want!); } } }); @@ -75,8 +81,8 @@ describe('symbol query', () => { describe('toSymbolTableFactory(tsVersion)', () => { it('should return a Map for versions of TypeScript >= 2.2', () => { - const a = { name: 'a' } as ts.Symbol; - const b = { name: 'b' } as ts.Symbol; + const a = {name: 'a'} as ts.Symbol; + const b = {name: 'b'} as ts.Symbol; expect(toSymbolTableFactory([a, b]) instanceof Map).toEqual(true); }); }); diff --git a/packages/language-service/test/utils_spec.ts b/packages/language-service/test/utils_spec.ts index ce50568219374..3d940c36dab93 100644 --- a/packages/language-service/test/utils_spec.ts +++ b/packages/language-service/test/utils_spec.ts @@ -28,7 +28,7 @@ describe('getDirectiveClassLike', () => { } }); expect(result).toBeTruthy(); - const {decoratorId, classId} = result !; + const {decoratorId, classId} = result!; expect(decoratorId.kind).toBe(ts.SyntaxKind.Identifier); expect(decoratorId.text).toBe('NgModule'); expect(classId.text).toBe('AppModule'); From 2463548fa7559053ec5488d32cd184a239502871 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Thu, 2 Apr 2020 11:03:11 +0100 Subject: [PATCH 113/262] fix(ngcc): sniff `main` property for ESM5 format (#36396) Previously, `main` was only checked for `umd` or `commonjs` formats. Now if there are `import` or `export` statements in the source file it will be deemed to be in `esm5` format. Fixes #35788 PR Close #36396 --- .../ngcc/src/packages/entry_point.ts | 20 ++++++++++++++----- .../ngcc/test/packages/entry_point_spec.ts | 16 +++++++++++++++ 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point.ts b/packages/compiler-cli/ngcc/src/packages/entry_point.ts index cc74e8e82a269..7a8097c79c21b 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point.ts @@ -199,7 +199,7 @@ export function getEntryPointFormat( return undefined; } const pathToMain = join(entryPoint.path, mainFile); - return isUmdModule(fs, pathToMain) ? 'umd' : 'commonjs'; + return sniffModuleFormat(fs, pathToMain); case 'module': return 'esm5'; default: @@ -226,15 +226,25 @@ function loadEntryPointPackage( } } -function isUmdModule(fs: FileSystem, sourceFilePath: AbsoluteFsPath): boolean { +function sniffModuleFormat(fs: FileSystem, sourceFilePath: AbsoluteFsPath): EntryPointFormat| + undefined { const resolvedPath = resolveFileWithPostfixes(fs, sourceFilePath, ['', '.js', '/index.js']); if (resolvedPath === null) { - return false; + return undefined; } + const sourceFile = ts.createSourceFile(sourceFilePath, fs.readFile(resolvedPath), ts.ScriptTarget.ES5); - return sourceFile.statements.length > 0 && - parseStatementForUmdModule(sourceFile.statements[0]) !== null; + if (sourceFile.statements.length === 0) { + return undefined; + } + if (ts.isExternalModule(sourceFile)) { + return 'esm5'; + } else if (parseStatementForUmdModule(sourceFile.statements[0]) !== null) { + return 'umd'; + } else { + return 'commonjs'; + } } function mergeConfigAndPackageJson( diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index 3ac8b1f32c869..c5b8e143f0b0a 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -425,6 +425,22 @@ runInEachFileSystem(() => { expect(getEntryPointFormat(fs, entryPoint, 'module')).toBe('esm5'); }); + it('should return `esm5` for `main` if the file contains import or export statements', () => { + const name = _( + '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'); + loadTestFiles([{name, contents: `import * as core from '@angular/core;`}]); + expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + + loadTestFiles([{name, contents: `import {Component} from '@angular/core;`}]); + expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + + loadTestFiles([{name, contents: `export function foo() {}`}]); + expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + + loadTestFiles([{name, contents: `export * from 'abc';`}]); + expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + }); + it('should return `umd` for `main` if the file contains a UMD wrapper function', () => { loadTestFiles([{ name: _( From 6b3aa60446a9473f5005b86998b79536d4d7b641 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Thu, 2 Apr 2020 16:47:17 +0100 Subject: [PATCH 114/262] fix(ngcc): support simple `browser` property in entry-points (#36396) The `browser` package.json property is now supported to the same level as `main` - i.e. it is sniffed for UMD, ESM5 and CommonJS. The `browser` property can also contain an object with file overrides but this is not supported by ngcc. Fixes #36062 PR Close #36396 --- .../ngcc/src/packages/entry_point.ts | 12 ++- .../ngcc/test/integration/ngcc_spec.ts | 2 +- .../ngcc/test/packages/entry_point_spec.ts | 94 +++++++++++-------- 3 files changed, 64 insertions(+), 44 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point.ts b/packages/compiler-cli/ngcc/src/packages/entry_point.ts index 7a8097c79c21b..1c6e56fa4fe51 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point.ts @@ -50,6 +50,7 @@ export interface JsonObject { } export interface PackageJsonFormatPropertiesMap { + browser?: string; fesm2015?: string; fesm5?: string; es2015?: string; // if exists then it is actually FESM2015 @@ -75,7 +76,7 @@ export interface EntryPointPackageJson extends JsonObject, PackageJsonFormatProp export type EntryPointJsonProperty = Exclude<PackageJsonFormatProperties, 'types'|'typings'>; // We need to keep the elements of this const and the `EntryPointJsonProperty` type in sync. export const SUPPORTED_FORMAT_PROPERTIES: EntryPointJsonProperty[] = - ['fesm2015', 'fesm5', 'es2015', 'esm2015', 'esm5', 'main', 'module']; + ['fesm2015', 'fesm5', 'es2015', 'esm2015', 'esm5', 'main', 'module', 'browser']; /** @@ -193,13 +194,18 @@ export function getEntryPointFormat( return 'esm2015'; case 'esm5': return 'esm5'; + case 'browser': + const browserFile = entryPoint.packageJson['browser']; + if (typeof browserFile !== 'string') { + return undefined; + } + return sniffModuleFormat(fs, join(entryPoint.path, browserFile)); case 'main': const mainFile = entryPoint.packageJson['main']; if (mainFile === undefined) { return undefined; } - const pathToMain = join(entryPoint.path, mainFile); - return sniffModuleFormat(fs, pathToMain); + return sniffModuleFormat(fs, join(entryPoint.path, mainFile)); case 'module': return 'esm5'; default: diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 8092d757b73b3..9e9ff8ea91e9d 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -793,7 +793,7 @@ runInEachFileSystem(() => { const propertiesToConsider = ['es1337', 'fesm42']; const errorMessage = 'No supported format property to consider among [es1337, fesm42]. Supported ' + - 'properties: fesm2015, fesm5, es2015, esm2015, esm5, main, module'; + 'properties: fesm2015, fesm5, es2015, esm2015, esm5, main, module, browser'; expect(() => mainNgcc({basePath: '/node_modules', propertiesToConsider})) .toThrowError(errorMessage); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index c5b8e143f0b0a..f07c779942b0c 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -10,7 +10,7 @@ import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '../../../ import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint, getEntryPointFormat, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point'; +import {EntryPoint, EntryPointJsonProperty, getEntryPointFormat, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT, SUPPORTED_FORMAT_PROPERTIES} from '../../src/packages/entry_point'; import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { @@ -206,7 +206,7 @@ runInEachFileSystem(() => { for (let prop of SUPPORTED_FORMAT_PROPERTIES) { // Ignore the UMD format - if (prop === 'main') continue; + if (prop === 'main' || prop === 'browser') continue; // Let's give 'module' a specific path, otherwise compute it based on the property. const typingsPath = prop === 'module' ? 'index' : `${prop}/missing_typings`; @@ -425,67 +425,80 @@ runInEachFileSystem(() => { expect(getEntryPointFormat(fs, entryPoint, 'module')).toBe('esm5'); }); - it('should return `esm5` for `main` if the file contains import or export statements', () => { - const name = _( - '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'); - loadTestFiles([{name, contents: `import * as core from '@angular/core;`}]); - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + (['browser', 'main'] as EntryPointJsonProperty[]).forEach(browserOrMain => { + it('should return `esm5` for `' + browserOrMain + + '` if the file contains import or export statements', + () => { + const name = _( + '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'); + loadTestFiles([{name, contents: `import * as core from '@angular/core;`}]); + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5'); - loadTestFiles([{name, contents: `import {Component} from '@angular/core;`}]); - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + loadTestFiles([{name, contents: `import {Component} from '@angular/core;`}]); + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5'); - loadTestFiles([{name, contents: `export function foo() {}`}]); - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); + loadTestFiles([{name, contents: `export function foo() {}`}]); + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5'); - loadTestFiles([{name, contents: `export * from 'abc';`}]); - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('esm5'); - }); + loadTestFiles([{name, contents: `export * from 'abc';`}]); + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('esm5'); + }); - it('should return `umd` for `main` if the file contains a UMD wrapper function', () => { - loadTestFiles([{ - name: _( - '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'), - contents: ` + it('should return `umd` for `' + browserOrMain + + '` if the file contains a UMD wrapper function', + () => { + loadTestFiles([{ + name: _( + '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'), + contents: ` (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : typeof define === 'function' && define.amd ? define('@angular/common', ['exports', '@angular/core'], factory) : (global = global || self, factory((global.ng = global.ng || {}, global.ng.common = {}), global.ng.core)); }(this, function (exports, core) { 'use strict'; })); ` - }]); - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('umd'); - }); + }]); + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('umd'); + }); - it('should return `commonjs` for `main` if the file does not contain a UMD wrapper function', () => { - loadTestFiles([{ - name: _( - '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'), - contents: ` + it('should return `commonjs` for `' + browserOrMain + + '` if the file does not contain a UMD wrapper function', + () => { + loadTestFiles([{ + name: _( + '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'), + contents: ` const core = require('@angular/core); module.exports = {}; ` - }]); - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('commonjs'); - }); + }]); + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('commonjs'); + }); - it('should resolve the format path with suitable postfixes', () => { - loadTestFiles([{ - name: _( - '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'), - contents: ` + it('should resolve the format path with suitable postfixes', () => { + loadTestFiles([{ + name: _( + '/project/node_modules/some_package/valid_entry_point/bundles/valid_entry_point/index.js'), + contents: ` (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core')) : typeof define === 'function' && define.amd ? define('@angular/common', ['exports', '@angular/core'], factory) : (global = global || self, factory((global.ng = global.ng || {}, global.ng.common = {}), global.ng.core)); }(this, function (exports, core) { 'use strict'; })); ` - }]); + }]); + + entryPoint.packageJson.main = './bundles/valid_entry_point/index'; + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('umd'); - entryPoint.packageJson.main = './bundles/valid_entry_point/index'; - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('umd'); + entryPoint.packageJson.main = './bundles/valid_entry_point'; + expect(getEntryPointFormat(fs, entryPoint, browserOrMain)).toBe('umd'); + }); + }); - entryPoint.packageJson.main = './bundles/valid_entry_point'; - expect(getEntryPointFormat(fs, entryPoint, 'main')).toBe('umd'); + it('should return `undefined` if the `browser` property is not a string', () => { + entryPoint.packageJson.browser = {} as any; + expect(getEntryPointFormat(fs, entryPoint, 'browser')).toBeUndefined(); }); }); }); @@ -503,6 +516,7 @@ export function createPackageJson( fesm5: `./fesm5/${packageName}.js`, esm5: `./esm5/${packageName}.js`, main: `./bundles/${packageName}/index.js`, + browser: `./bundles/${packageName}/index.js`, module: './index.js', }; if (excludes) { From f9fb8338f56a7fa5b033c9a71a917af0f8a84a4f Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Fri, 3 Apr 2020 22:00:51 +0100 Subject: [PATCH 115/262] fix(ngcc): support ignoring deep-imports via package config (#36423) Recently we added support for ignoring specified deep-import warnings by providing sets of regular expressions within the `ngcc.config.js` file. But this was only working for the project level configuration. This commit fixes ngcc so that it will also read these regular expressions from package level configuration too. Fixes #35750 PR Close #36423 --- .../ngcc/src/packages/configuration.ts | 4 +- .../ngcc/test/packages/configuration_spec.ts | 48 ++++++++++++++++++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/configuration.ts b/packages/compiler-cli/ngcc/src/packages/configuration.ts index 10b45e9b31217..5b718f7ca20bc 100644 --- a/packages/compiler-cli/ngcc/src/packages/configuration.ts +++ b/packages/compiler-cli/ngcc/src/packages/configuration.ts @@ -241,9 +241,11 @@ export class NgccConfiguration { const configFilePath = join(packagePath, NGCC_CONFIG_FILENAME); if (this.fs.exists(configFilePath)) { try { + const packageConfig = this.evalSrcFile(configFilePath); return { + ...packageConfig, versionRange: version || '*', - entryPoints: this.processEntryPoints(packagePath, this.evalSrcFile(configFilePath)), + entryPoints: this.processEntryPoints(packagePath, packageConfig), }; } catch (e) { throw new Error(`Invalid package configuration file at "${configFilePath}": ` + e.message); diff --git a/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts b/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts index b9c06673973c0..edf2a718ccf50 100644 --- a/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/configuration_spec.ts @@ -102,6 +102,20 @@ runInEachFileSystem(() => { .toHaveBeenCalledWith(_Abs('/project-1/node_modules/package-1/ngcc.config.js')); }); + it('should read extra package config from package level file', () => { + loadTestFiles(packageWithConfigFiles( + 'package-1', 'entry-point-1', '1.0.0', 'ignorableDeepImportMatchers: [ /xxx/ ]')); + const configuration = new NgccConfiguration(fs, _Abs('/project-1')); + const config = + configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0'); + + expect(config).toEqual({ + versionRange: '1.0.0', + entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}, + ignorableDeepImportMatchers: [/xxx/], + }); + }); + it('should used cached configuration for a package if available', () => { loadTestFiles(packageWithConfigFiles('package-1', 'entry-point-1', '1.0.0')); const configuration = new NgccConfiguration(fs, _Abs('/project-1')); @@ -169,6 +183,31 @@ runInEachFileSystem(() => { }); }); + it('should return configuration for a package found in a project level file', () => { + loadTestFiles([{ + name: _Abs('/project-1/ngcc.config.js'), + contents: ` + module.exports = { + packages: { + 'package-1': { + entryPoints: { + './entry-point-1': {} + }, + ignorableDeepImportMatchers: [ /xxx/ ], + }, + }, + };` + }]); + const configuration = new NgccConfiguration(fs, _Abs('/project-1')); + const config = + configuration.getConfig(_Abs('/project-1/node_modules/package-1'), '1.0.0'); + expect(config).toEqual({ + versionRange: '*', + entryPoints: {[_Abs('/project-1/node_modules/package-1/entry-point-1')]: {}}, + ignorableDeepImportMatchers: [/xxx/], + }); + }); + it('should return configuration for the correct version of a package found in a project level file', () => { loadTestFiles([{ @@ -569,11 +608,16 @@ runInEachFileSystem(() => { }); }); - function packageWithConfigFiles(packageName: string, entryPointName: string, version: string) { + function packageWithConfigFiles( + packageName: string, entryPointName: string, version: string, extraConfig: string = '') { return [ { name: _Abs(`/project-1/node_modules/${packageName}/ngcc.config.js`), - contents: `module.exports = {entryPoints: { './${entryPointName}': {}}}` + contents: ` + module.exports = { + entryPoints: { './${entryPointName}': {} }, + ${extraConfig} + };` }, { name: _Abs(`/project-1/node_modules/${packageName}/package.json`), From 4c7f89ff6d35f1ca639b54b7d08c26042dd9b8b7 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Sat, 7 Mar 2020 16:23:11 +0000 Subject: [PATCH 116/262] ci: exclude ngcc directory from fw-compiler pull-approve rule (#35933) ngcc has its own pull-approve group PR Close #35933 --- .pullapprove.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.pullapprove.yml b/.pullapprove.yml index 6d79b06082e3e..29637b8f9a52b 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -123,10 +123,10 @@ pullapprove_conditions: groups: # ========================================================= # Global Approvers - # + # # All reviews performed for global approvals require using # the `Reviewed-for:` specifier to set the approval - # specificity as documented at: + # specificity as documented at: # https://docs.pullapprove.com/reviewed-for/ # ========================================================= global-approvers: @@ -141,10 +141,10 @@ groups: # ========================================================= # Global Approvers For Docs - # + # # All reviews performed for global docs approvals require # using the `Reviewed-for:` specifier to set the approval - # specificity as documented at: + # specificity as documented at: # https://docs.pullapprove.com/reviewed-for/ # ========================================================= global-docs-approvers: @@ -198,6 +198,10 @@ groups: 'aio/content/guide/aot-metadata-errors.md', 'aio/content/guide/template-typecheck.md ' ]) + - > + not contains_any_globs(files, [ + 'packages/compiler-cli/ngcc/**' + ]) reviewers: users: - alxhub From 76a8cd57ae920211a0989ab665d8f727da68de67 Mon Sep 17 00:00:00 2001 From: Alan Agius <alan.agius4@gmail.com> Date: Mon, 6 Apr 2020 10:43:47 +0200 Subject: [PATCH 117/262] fix(ngcc): add process title (#36448) Add process.title, so it's clearly in the task manager when ngcc is running See: https://github.com/angular/angular/issues/36414#issuecomment-609644282 PR Close #36448 --- packages/compiler-cli/ngcc/main-ngcc.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/compiler-cli/ngcc/main-ngcc.ts b/packages/compiler-cli/ngcc/main-ngcc.ts index 05279057c13a2..770a0b79a7ce9 100644 --- a/packages/compiler-cli/ngcc/main-ngcc.ts +++ b/packages/compiler-cli/ngcc/main-ngcc.ts @@ -15,6 +15,8 @@ import {LogLevel} from './src/logging/logger'; // CLI entry point if (require.main === module) { + process.title = 'ngcc'; + const startTime = Date.now(); const args = process.argv.slice(2); From ee70a18a758fecc42f012f8399109564b2086b1e Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Mon, 6 Apr 2020 13:41:41 +0100 Subject: [PATCH 118/262] fix(ngcc): don't crash on cyclic source-map references (#36452) The source-map flattening was throwing an error when there is a cyclic dependency between source files and source-maps. The error was either a custom one describing the cycle, or a "Maximum call stack size exceeded" one. Now this is handled more leniently, resulting in a partially loaded source file (or source-map) and a warning logged. Fixes #35727 Fixes #35757 Fixes https://github.com/angular/angular-cli/issues/17106 Fixes https://github.com/angular/angular-cli/issues/17115 PR Close #36452 --- .../ngcc/src/rendering/source_maps.ts | 2 +- .../ngcc/src/sourcemaps/source_file_loader.ts | 129 +++++++++++------- .../sourcemaps/source_file_loader_spec.ts | 99 ++++++++++---- 3 files changed, 156 insertions(+), 74 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/rendering/source_maps.ts b/packages/compiler-cli/ngcc/src/rendering/source_maps.ts index 07d040db86f9d..3106a8e517bfc 100644 --- a/packages/compiler-cli/ngcc/src/rendering/source_maps.ts +++ b/packages/compiler-cli/ngcc/src/rendering/source_maps.ts @@ -36,7 +36,7 @@ export function renderSourceAndMap( {file: generatedPath, source: generatedPath, includeContent: true}); try { - const loader = new SourceFileLoader(fs); + const loader = new SourceFileLoader(fs, logger); const generatedFile = loader.loadSourceFile( generatedPath, generatedContent, {map: generatedMap, mapPath: generatedMapPath}); diff --git a/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts b/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts index 50626436c3e55..52a581c8bf179 100644 --- a/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts +++ b/packages/compiler-cli/ngcc/src/sourcemaps/source_file_loader.ts @@ -8,6 +8,7 @@ import {commentRegex, fromComment, mapFileCommentRegex} from 'convert-source-map'; import {absoluteFrom, AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system'; +import {Logger} from '../logging/logger'; import {RawSourceMap} from './raw_source_map'; import {SourceFile} from './source_file'; @@ -22,61 +23,70 @@ import {SourceFile} from './source_file'; * mappings to other `SourceFile` objects as necessary. */ export class SourceFileLoader { - constructor(private fs: FileSystem) {} + private currentPaths: AbsoluteFsPath[] = []; + + constructor(private fs: FileSystem, private logger: Logger) {} /** * Load a source file, compute its source map, and recursively load any referenced source files. * * @param sourcePath The path to the source file to load. - * @param contents The contents of the source file to load (if known). - * The contents may be known because the source file was inlined into a source map. + * @param contents The contents of the source file to load. + * @param mapAndPath The raw source-map and the path to the source-map file. + * @returns a SourceFile object created from the `contents` and provided source-map info. + */ + loadSourceFile(sourcePath: AbsoluteFsPath, contents: string, mapAndPath: MapAndPath): SourceFile; + /** + * The overload used internally to load source files referenced in a source-map. + * + * In this case there is no guarantee that it will return a non-null SourceMap. + * + * @param sourcePath The path to the source file to load. + * @param contents The contents of the source file to load, if provided inline. * If it is not known the contents will be read from the file at the `sourcePath`. - * @param mapAndPath The raw source-map and the path to the source-map file, if known. - * @param previousPaths An internal parameter used for cyclic dependency tracking. + * @param mapAndPath The raw source-map and the path to the source-map file. + * * @returns a SourceFile if the content for one was provided or able to be loaded from disk, * `null` otherwise. */ - loadSourceFile(sourcePath: AbsoluteFsPath, contents: string, mapAndPath: MapAndPath): SourceFile; - loadSourceFile(sourcePath: AbsoluteFsPath, contents: string|null): SourceFile|null; - loadSourceFile(sourcePath: AbsoluteFsPath): SourceFile|null; + loadSourceFile(sourcePath: AbsoluteFsPath, contents?: string|null, mapAndPath?: null): SourceFile + |null; loadSourceFile( - sourcePath: AbsoluteFsPath, contents: string|null, mapAndPath: null, - previousPaths: AbsoluteFsPath[]): SourceFile|null; - loadSourceFile( - sourcePath: AbsoluteFsPath, contents: string|null = null, mapAndPath: MapAndPath|null = null, - previousPaths: AbsoluteFsPath[] = []): SourceFile|null { - if (contents === null) { - if (!this.fs.exists(sourcePath)) { - return null; + sourcePath: AbsoluteFsPath, contents: string|null = null, + mapAndPath: MapAndPath|null = null): SourceFile|null { + const previousPaths = this.currentPaths.slice(); + try { + if (contents === null) { + if (!this.fs.exists(sourcePath)) { + return null; + } + contents = this.readSourceFile(sourcePath); } - // Track source file paths if we have loaded them from disk so that we don't get into an - // infinite recursion - if (previousPaths.includes(sourcePath)) { - throw new Error(`Circular source file mapping dependency: ${ - previousPaths.join(' -> ')} -> ${sourcePath}`); + // If not provided try to load the source map based on the source itself + if (mapAndPath === null) { + mapAndPath = this.loadSourceMap(sourcePath, contents); } - previousPaths = previousPaths.concat([sourcePath]); - contents = this.fs.readFile(sourcePath); - } - - // If not provided try to load the source map based on the source itself - if (mapAndPath === null) { - mapAndPath = this.loadSourceMap(sourcePath, contents); - } + let map: RawSourceMap|null = null; + let inline = true; + let sources: (SourceFile|null)[] = []; + if (mapAndPath !== null) { + const basePath = mapAndPath.mapPath || sourcePath; + sources = this.processSources(basePath, mapAndPath.map); + map = mapAndPath.map; + inline = mapAndPath.mapPath === null; + } - let map: RawSourceMap|null = null; - let inline = true; - let sources: (SourceFile|null)[] = []; - if (mapAndPath !== null) { - const basePath = mapAndPath.mapPath || sourcePath; - sources = this.processSources(basePath, mapAndPath.map, previousPaths); - map = mapAndPath.map; - inline = mapAndPath.mapPath === null; + return new SourceFile(sourcePath, contents, map, inline, sources); + } catch (e) { + this.logger.warn( + `Unable to fully load ${sourcePath} for source-map flattening: ${e.message}`); + return null; + } finally { + // We are finished with this recursion so revert the paths being tracked + this.currentPaths = previousPaths; } - - return new SourceFile(sourcePath, contents, map, inline, sources); } /** @@ -97,15 +107,17 @@ export class SourceFileLoader { try { const fileName = external[1] || external[2]; const externalMapPath = this.fs.resolve(this.fs.dirname(sourcePath), fileName); - return {map: this.loadRawSourceMap(externalMapPath), mapPath: externalMapPath}; - } catch { + return {map: this.readRawSourceMap(externalMapPath), mapPath: externalMapPath}; + } catch (e) { + this.logger.warn( + `Unable to fully load ${sourcePath} for source-map flattening: ${e.message}`); return null; } } const impliedMapPath = absoluteFrom(sourcePath + '.map'); if (this.fs.exists(impliedMapPath)) { - return {map: this.loadRawSourceMap(impliedMapPath), mapPath: impliedMapPath}; + return {map: this.readRawSourceMap(impliedMapPath), mapPath: impliedMapPath}; } return null; @@ -115,24 +127,47 @@ export class SourceFileLoader { * Iterate over each of the "sources" for this source file's source map, recursively loading each * source file and its associated source map. */ - private processSources( - basePath: AbsoluteFsPath, map: RawSourceMap, - previousPaths: AbsoluteFsPath[]): (SourceFile|null)[] { + private processSources(basePath: AbsoluteFsPath, map: RawSourceMap): (SourceFile|null)[] { const sourceRoot = this.fs.resolve(this.fs.dirname(basePath), map.sourceRoot || ''); return map.sources.map((source, index) => { const path = this.fs.resolve(sourceRoot, source); const content = map.sourcesContent && map.sourcesContent[index] || null; - return this.loadSourceFile(path, content, null, previousPaths); + return this.loadSourceFile(path, content, null); }); } + /** + * Load the contents of the source file from disk. + * + * @param sourcePath The path to the source file. + */ + private readSourceFile(sourcePath: AbsoluteFsPath): string { + this.trackPath(sourcePath); + return this.fs.readFile(sourcePath); + } + /** * Load the source map from the file at `mapPath`, parsing its JSON contents into a `RawSourceMap` * object. + * + * @param mapPath The path to the source-map file. */ - private loadRawSourceMap(mapPath: AbsoluteFsPath): RawSourceMap { + private readRawSourceMap(mapPath: AbsoluteFsPath): RawSourceMap { + this.trackPath(mapPath); return JSON.parse(this.fs.readFile(mapPath)); } + + /** + * Track source file paths if we have loaded them from disk so that we don't get into an infinite + * recursion. + */ + private trackPath(path: AbsoluteFsPath): void { + if (this.currentPaths.includes(path)) { + throw new Error( + `Circular source file mapping dependency: ${this.currentPaths.join(' -> ')} -> ${path}`); + } + this.currentPaths.push(path); + } } /** A small helper structure that is returned from `loadSourceMap()`. */ diff --git a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts index c0d644b288ffe..47caddf9fa88e 100644 --- a/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts +++ b/packages/compiler-cli/ngcc/test/sourcemaps/source_file_loader_spec.ts @@ -11,16 +11,19 @@ import {fromObject} from 'convert-source-map'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {RawSourceMap} from '../../src/sourcemaps/raw_source_map'; import {SourceFileLoader as SourceFileLoader} from '../../src/sourcemaps/source_file_loader'; +import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { describe('SourceFileLoader', () => { let fs: FileSystem; + let logger: MockLogger; let _: typeof absoluteFrom; let registry: SourceFileLoader; beforeEach(() => { fs = getFileSystem(); + logger = new MockLogger(); _ = absoluteFrom; - registry = new SourceFileLoader(fs); + registry = new SourceFileLoader(fs, logger); }); describe('loadSourceFile', () => { @@ -182,31 +185,75 @@ runInEachFileSystem(() => { }); }); - it('should fail if there is a cyclic dependency in files loaded from disk', () => { - fs.ensureDir(_('/foo/src')); - - const aPath = _('/foo/src/a.js'); - fs.writeFile( - aPath, - 'a content\n' + - fromObject(createRawSourceMap({file: 'a.js', sources: ['b.js']})).toComment()); - - const bPath = _('/foo/src/b.js'); - fs.writeFile( - bPath, - 'b content\n' + - fromObject(createRawSourceMap({file: 'b.js', sources: ['c.js']})).toComment()); - - const cPath = _('/foo/src/c.js'); - fs.writeFile( - cPath, - 'c content\n' + - fromObject(createRawSourceMap({file: 'c.js', sources: ['a.js']})).toComment()); - - expect(() => registry.loadSourceFile(aPath)) - .toThrowError(`Circular source file mapping dependency: ${aPath} -> ${bPath} -> ${ - cPath} -> ${aPath}`); - }); + it('should log a warning if there is a cyclic dependency in source files loaded from disk', + () => { + fs.ensureDir(_('/foo/src')); + + const aMap = createRawSourceMap({file: 'a.js', sources: ['b.js']}); + + const aPath = _('/foo/src/a.js'); + fs.writeFile(aPath, 'a content\n' + fromObject(aMap).toComment()); + + const bPath = _('/foo/src/b.js'); + fs.writeFile( + bPath, + 'b content\n' + + fromObject(createRawSourceMap({file: 'b.js', sources: ['c.js']})).toComment()); + + const cPath = _('/foo/src/c.js'); + fs.writeFile( + cPath, + 'c content\n' + + fromObject(createRawSourceMap({file: 'c.js', sources: ['a.js']})).toComment()); + + const sourceFile = registry.loadSourceFile(aPath)!; + expect(sourceFile).not.toBe(null!); + expect(sourceFile.contents).toEqual('a content\n'); + expect(sourceFile.sourcePath).toEqual(_('/foo/src/a.js')); + expect(sourceFile.rawMap).toEqual(aMap); + expect(sourceFile.sources.length).toEqual(1); + + expect(logger.logs.warn[0][0]) + .toContain( + `Circular source file mapping dependency: ` + + `${aPath} -> ${bPath} -> ${cPath} -> ${aPath}`); + }); + + it('should log a warning if there is a cyclic dependency in source maps loaded from disk', + () => { + fs.ensureDir(_('/foo/src')); + + // Create a self-referencing source-map + const aMap = createRawSourceMap({ + file: 'a.js', + sources: ['a.js'], + sourcesContent: ['inline a.js content\n//# sourceMappingURL=a.js.map'] + }); + const aMapPath = _('/foo/src/a.js.map'); + fs.writeFile(aMapPath, JSON.stringify(aMap)); + + const aPath = _('/foo/src/a.js'); + fs.writeFile(aPath, 'a.js content\n//# sourceMappingURL=a.js.map'); + + const sourceFile = registry.loadSourceFile(aPath)!; + expect(sourceFile).not.toBe(null!); + expect(sourceFile.contents).toEqual('a.js content\n'); + expect(sourceFile.sourcePath).toEqual(_('/foo/src/a.js')); + expect(sourceFile.rawMap).toEqual(aMap); + expect(sourceFile.sources.length).toEqual(1); + + expect(logger.logs.warn[0][0]) + .toContain( + `Circular source file mapping dependency: ` + + `${aPath} -> ${aMapPath} -> ${aMapPath}`); + + const innerSourceFile = sourceFile.sources[0]!; + expect(innerSourceFile).not.toBe(null!); + expect(innerSourceFile.contents).toEqual('inline a.js content\n'); + expect(innerSourceFile.sourcePath).toEqual(_('/foo/src/a.js')); + expect(innerSourceFile.rawMap).toEqual(null); + expect(innerSourceFile.sources.length).toEqual(0); + }); it('should not fail if there is a cyclic dependency in filenames of inline sources', () => { fs.ensureDir(_('/foo/src')); From d43c30688ab88a631eb5e1aae2556f054ab2ee07 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Thu, 2 Apr 2020 11:01:43 +0200 Subject: [PATCH 119/262] fix(core): avoid migration error when non-existent symbol is imported (#36367) In rare cases a project with configured `rootDirs` that has imports to non-existent identifiers could fail in the migration. This happens because based on the application code, the migration could end up trying to resolve the `ts.Symbol` of such non-existent identifiers. This isn't a problem usually, but due to a upstream bug in the TypeScript compiler, a runtime error is thrown. This is because TypeScript is unable to compute a relative path from the originating source file to the imported source file which _should_ provide the non-existent identifier. An issue for this has been reported upstream: https://github.com/microsoft/TypeScript/issues/37731. The issue only surfaces since our migrations don't provide an absolute base path that is used for resolving the root directories. To fix this, we ensure that we never use relative paths when parsing tsconfig files. More details can be found in the TS issue. Fixes #36346. PR Close #36367 --- .../migrations/dynamic-queries/index.ts | 14 +-- .../migrations/missing-injectable/index.ts | 16 ++-- .../migrations/module-with-providers/index.ts | 13 +-- .../migrations/move-document/index.ts | 11 +-- .../migrations/renderer-to-renderer2/index.ts | 17 ++-- .../migrations/static-queries/index.ts | 84 ++++++++-------- .../template-var-assignment/index.ts | 10 +- .../index.ts | 19 ++-- .../schematics/test/all-migrations.spec.ts | 96 +++++++++++++++++++ .../utils/typescript/compiler_host.ts | 31 +++++- .../utils/typescript/parse_tsconfig.ts | 8 ++ 11 files changed, 211 insertions(+), 108 deletions(-) create mode 100644 packages/core/schematics/test/all-migrations.spec.ts diff --git a/packages/core/schematics/migrations/dynamic-queries/index.ts b/packages/core/schematics/migrations/dynamic-queries/index.ts index e84e3940cf93b..ececbb9a434bf 100644 --- a/packages/core/schematics/migrations/dynamic-queries/index.ts +++ b/packages/core/schematics/migrations/dynamic-queries/index.ts @@ -6,23 +6,21 @@ * found in the LICENSE file at https://angular.io/license */ -import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {Rule, SchematicsException, Tree} from '@angular-devkit/schematics'; +import {relative} from 'path'; import * as ts from 'typescript'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; import {identifyDynamicQueryNodes, removeOptionsParameter, removeStaticFlag} from './util'; - /** * Runs the dynamic queries migration for all TypeScript projects in the current CLI workspace. */ export default function(): Rule { - return (tree: Tree, ctx: SchematicContext) => { + return (tree: Tree) => { const {buildPaths, testPaths} = getProjectTsConfigPaths(tree); const basePath = process.cwd(); const allPaths = [...buildPaths, ...testPaths]; @@ -39,9 +37,7 @@ export default function(): Rule { } function runDynamicQueryMigration(tree: Tree, tsconfigPath: string, basePath: string) { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); - const program = ts.createProgram(parsed.fileNames, parsed.options, host); + const {program} = createMigrationProgram(tree, tsconfigPath, basePath); const typeChecker = program.getTypeChecker(); const sourceFiles = program.getSourceFiles().filter( f => !f.isDeclarationFile && !program.isSourceFileFromExternalLibrary(f)); diff --git a/packages/core/schematics/migrations/missing-injectable/index.ts b/packages/core/schematics/migrations/missing-injectable/index.ts index dcdad8eaeaf1b..7212f0551417a 100644 --- a/packages/core/schematics/migrations/missing-injectable/index.ts +++ b/packages/core/schematics/migrations/missing-injectable/index.ts @@ -7,11 +7,10 @@ */ import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {relative} from 'path'; import * as ts from 'typescript'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; import {NgDefinitionCollector} from './definition_collector'; import {MissingInjectableTransform} from './transform'; import {UpdateRecorder} from './update_recorder'; @@ -43,11 +42,8 @@ export default function(): Rule { function runMissingInjectableMigration( tree: Tree, tsconfigPath: string, basePath: string): string[] { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); + const {program} = createMigrationProgram(tree, tsconfigPath, basePath); const failures: string[] = []; - - const program = ts.createProgram(parsed.fileNames, parsed.options, host); const typeChecker = program.getTypeChecker(); const definitionCollector = new NgDefinitionCollector(typeChecker); const sourceFiles = program.getSourceFiles().filter( @@ -83,7 +79,7 @@ function runMissingInjectableMigration( /** Gets the update recorder for the specified source file. */ function getUpdateRecorder(sourceFile: ts.SourceFile): UpdateRecorder { if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !; + return updateRecorders.get(sourceFile)!; } const treeRecorder = tree.beginUpdate(relative(basePath, sourceFile.fileName)); const recorder: UpdateRecorder = { @@ -111,7 +107,9 @@ function runMissingInjectableMigration( treeRecorder.remove(node.getStart(), node.getWidth()); treeRecorder.insertRight(node.getStart(), newText); }, - commitUpdate() { tree.commitUpdate(treeRecorder); } + commitUpdate() { + tree.commitUpdate(treeRecorder); + } }; updateRecorders.set(sourceFile, recorder); return recorder; diff --git a/packages/core/schematics/migrations/module-with-providers/index.ts b/packages/core/schematics/migrations/module-with-providers/index.ts index d36beb8aa8626..85f14c45a80ec 100644 --- a/packages/core/schematics/migrations/module-with-providers/index.ts +++ b/packages/core/schematics/migrations/module-with-providers/index.ts @@ -7,18 +7,16 @@ */ import {Rule, SchematicContext, SchematicsException, Tree, UpdateRecorder} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {relative} from 'path'; import * as ts from 'typescript'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; import {Collector} from './collector'; import {AnalysisFailure, ModuleWithProvidersTransform} from './transform'; - /** * Runs the ModuleWithProviders migration for all TypeScript projects in the current CLI workspace. */ @@ -47,11 +45,8 @@ export default function(): Rule { } function runModuleWithProvidersMigration(tree: Tree, tsconfigPath: string, basePath: string) { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); + const {program} = createMigrationProgram(tree, tsconfigPath, basePath); const failures: string[] = []; - - const program = ts.createProgram(parsed.fileNames, parsed.options, host); const typeChecker = program.getTypeChecker(); const collector = new Collector(typeChecker); const sourceFiles = program.getSourceFiles().filter( @@ -86,7 +81,7 @@ function runModuleWithProvidersMigration(tree: Tree, tsconfigPath: string, baseP /** Gets the update recorder for the specified source file. */ function getUpdateRecorder(sourceFile: ts.SourceFile): UpdateRecorder { if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !; + return updateRecorders.get(sourceFile)!; } const recorder = tree.beginUpdate(relative(basePath, sourceFile.fileName)); updateRecorders.set(sourceFile, recorder); diff --git a/packages/core/schematics/migrations/move-document/index.ts b/packages/core/schematics/migrations/move-document/index.ts index 2fb42f0753e45..dafaf061ede76 100644 --- a/packages/core/schematics/migrations/move-document/index.ts +++ b/packages/core/schematics/migrations/move-document/index.ts @@ -7,18 +7,16 @@ */ import {Rule, SchematicsException, Tree} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {relative} from 'path'; import * as ts from 'typescript'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; import {COMMON_IMPORT, DOCUMENT_TOKEN_NAME, DocumentImportVisitor, ResolvedDocumentImport} from './document_import_visitor'; import {addToImport, createImport, removeFromImport} from './move-import'; - /** Entry point for the V8 move-document migration. */ export default function(): Rule { return (tree: Tree) => { @@ -42,10 +40,7 @@ export default function(): Rule { * new import source. */ function runMoveDocumentMigration(tree: Tree, tsconfigPath: string, basePath: string) { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); - - const program = ts.createProgram(parsed.fileNames, parsed.options, host); + const {program} = createMigrationProgram(tree, tsconfigPath, basePath); const typeChecker = program.getTypeChecker(); const visitor = new DocumentImportVisitor(typeChecker); const sourceFiles = program.getSourceFiles().filter( diff --git a/packages/core/schematics/migrations/renderer-to-renderer2/index.ts b/packages/core/schematics/migrations/renderer-to-renderer2/index.ts index 7144db130eb63..eb8780317f094 100644 --- a/packages/core/schematics/migrations/renderer-to-renderer2/index.ts +++ b/packages/core/schematics/migrations/renderer-to-renderer2/index.ts @@ -6,15 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {Rule, SchematicsException, Tree} from '@angular-devkit/schematics'; +import {relative} from 'path'; import * as ts from 'typescript'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; -import {HelperFunction, getHelper} from './helpers'; +import {getHelper, HelperFunction} from './helpers'; import {migrateExpression, replaceImport} from './migration'; import {findCoreImport, findRendererReferences} from './util'; @@ -42,8 +41,7 @@ export default function(): Rule { } function runRendererToRenderer2Migration(tree: Tree, tsconfigPath: string, basePath: string) { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath, fileName => { + const {program} = createMigrationProgram(tree, tsconfigPath, basePath, fileName => { // In case the module augmentation file has been requested, we return a source file that // augments "@angular/core" to include a named export called "Renderer". This ensures that // we can rely on the type checker for this migration in v9 where "Renderer" has been removed. @@ -56,10 +54,7 @@ function runRendererToRenderer2Migration(tree: Tree, tsconfigPath: string, baseP `; } return null; - }); - - const program = - ts.createProgram(parsed.fileNames.concat(MODULE_AUGMENTATION_FILENAME), parsed.options, host); + }, [MODULE_AUGMENTATION_FILENAME]); const typeChecker = program.getTypeChecker(); const printer = ts.createPrinter(); const sourceFiles = program.getSourceFiles().filter( diff --git a/packages/core/schematics/migrations/static-queries/index.ts b/packages/core/schematics/migrations/static-queries/index.ts index 9200776c437e5..1a4c5ac7e62b8 100644 --- a/packages/core/schematics/migrations/static-queries/index.ts +++ b/packages/core/schematics/migrations/static-queries/index.ts @@ -8,14 +8,13 @@ import {logging} from '@angular-devkit/core'; import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {relative} from 'path'; import {from} from 'rxjs'; import * as ts from 'typescript'; import {NgComponentTemplateVisitor} from '../../utils/ng_component_template'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; import {NgQueryResolveVisitor} from './angular/ng_query_visitor'; import {QueryTemplateStrategy} from './strategies/template_strategy/template_strategy'; @@ -107,49 +106,46 @@ async function runMigration(tree: Tree, context: SchematicContext) { */ function analyzeProject( tree: Tree, tsconfigPath: string, basePath: string, analyzedFiles: Set<string>, - logger: logging.LoggerApi): - AnalyzedProject|null { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); - const program = ts.createProgram(parsed.fileNames, parsed.options, host); - const syntacticDiagnostics = program.getSyntacticDiagnostics(); - - // Syntactic TypeScript errors can throw off the query analysis and therefore we want - // to notify the developer that we couldn't analyze parts of the project. Developers - // can just re-run the migration after fixing these failures. - if (syntacticDiagnostics.length) { - logger.warn( - `\nTypeScript project "${tsconfigPath}" has syntactical errors which could cause ` + - `an incomplete migration. Please fix the following failures and rerun the migration:`); - logger.error(ts.formatDiagnostics(syntacticDiagnostics, host)); - logger.info( - 'Migration can be rerun with: "ng update @angular/core --from 7 --to 8 --migrate-only"\n'); - } + logger: logging.LoggerApi): AnalyzedProject|null { + const {program, host} = createMigrationProgram(tree, tsconfigPath, basePath); + const syntacticDiagnostics = program.getSyntacticDiagnostics(); + + // Syntactic TypeScript errors can throw off the query analysis and therefore we want + // to notify the developer that we couldn't analyze parts of the project. Developers + // can just re-run the migration after fixing these failures. + if (syntacticDiagnostics.length) { + logger.warn( + `\nTypeScript project "${tsconfigPath}" has syntactical errors which could cause ` + + `an incomplete migration. Please fix the following failures and rerun the migration:`); + logger.error(ts.formatDiagnostics(syntacticDiagnostics, host)); + logger.info( + 'Migration can be rerun with: "ng update @angular/core --from 7 --to 8 --migrate-only"\n'); + } - const typeChecker = program.getTypeChecker(); - const sourceFiles = program.getSourceFiles().filter( - f => !f.isDeclarationFile && !program.isSourceFileFromExternalLibrary(f)); - const queryVisitor = new NgQueryResolveVisitor(typeChecker); - - // Analyze all project source-files and collect all queries that - // need to be migrated. - sourceFiles.forEach(sourceFile => { - const relativePath = relative(basePath, sourceFile.fileName); - - // Only look for queries within the current source files if the - // file has not been analyzed before. - if (!analyzedFiles.has(relativePath)) { - analyzedFiles.add(relativePath); - queryVisitor.visitNode(sourceFile); - } - }); - - if (queryVisitor.resolvedQueries.size === 0) { - return null; - } + const typeChecker = program.getTypeChecker(); + const sourceFiles = program.getSourceFiles().filter( + f => !f.isDeclarationFile && !program.isSourceFileFromExternalLibrary(f)); + const queryVisitor = new NgQueryResolveVisitor(typeChecker); - return {program, host, tsconfigPath, typeChecker, basePath, queryVisitor, sourceFiles}; + // Analyze all project source-files and collect all queries that + // need to be migrated. + sourceFiles.forEach(sourceFile => { + const relativePath = relative(basePath, sourceFile.fileName); + + // Only look for queries within the current source files if the + // file has not been analyzed before. + if (!analyzedFiles.has(relativePath)) { + analyzedFiles.add(relativePath); + queryVisitor.visitNode(sourceFile); } + }); + + if (queryVisitor.resolvedQueries.size === 0) { + return null; + } + + return {program, host, tsconfigPath, typeChecker, basePath, queryVisitor, sourceFiles}; +} /** * Runs the static query migration for the given project. The schematic analyzes all @@ -179,7 +175,7 @@ async function runStaticQueryMigration( // is necessary in order to be able to check component templates for static query usage. resolvedTemplates.forEach(template => { if (classMetadata.has(template.container)) { - classMetadata.get(template.container) !.template = template; + classMetadata.get(template.container)!.template = template; } }); } diff --git a/packages/core/schematics/migrations/template-var-assignment/index.ts b/packages/core/schematics/migrations/template-var-assignment/index.ts index 464841c158f9d..b7eeede2428f2 100644 --- a/packages/core/schematics/migrations/template-var-assignment/index.ts +++ b/packages/core/schematics/migrations/template-var-assignment/index.ts @@ -8,13 +8,11 @@ import {logging, normalize} from '@angular-devkit/core'; import {Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; -import * as ts from 'typescript'; +import {relative} from 'path'; import {NgComponentTemplateVisitor} from '../../utils/ng_component_template'; import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; import {analyzeResolvedTemplate} from './analyze_template'; @@ -47,9 +45,7 @@ export default function(): Rule { */ function runTemplateVariableAssignmentCheck( tree: Tree, tsconfigPath: string, basePath: string, logger: Logger) { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); - const program = ts.createProgram(parsed.fileNames, parsed.options, host); + const {program} = createMigrationProgram(tree, tsconfigPath, basePath); const typeChecker = program.getTypeChecker(); const templateVisitor = new NgComponentTemplateVisitor(typeChecker); const sourceFiles = program.getSourceFiles().filter( diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts index a911f4c79bd51..7b9698b1dbe92 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/index.ts @@ -7,13 +7,14 @@ */ import {Rule, SchematicsException, Tree,} from '@angular-devkit/schematics'; -import {dirname, relative} from 'path'; +import {relative} from 'path'; import * as ts from 'typescript'; + import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths'; -import {createMigrationCompilerHost} from '../../utils/typescript/compiler_host'; -import {parseTsconfigFile} from '../../utils/typescript/parse_tsconfig'; -import {UpdateRecorder} from './update_recorder'; +import {createMigrationProgram} from '../../utils/typescript/compiler_host'; + import {UndecoratedClassesWithDecoratedFieldsTransform} from './transform'; +import {UpdateRecorder} from './update_recorder'; /** * Migration that adds an Angular decorator to classes that have Angular field decorators. @@ -37,9 +38,7 @@ export default function(): Rule { } function runUndecoratedClassesMigration(tree: Tree, tsconfigPath: string, basePath: string) { - const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); - const host = createMigrationCompilerHost(tree, parsed.options, basePath); - const program = ts.createProgram(parsed.fileNames, parsed.options, host); + const {program} = createMigrationProgram(tree, tsconfigPath, basePath); const typeChecker = program.getTypeChecker(); const sourceFiles = program.getSourceFiles().filter( file => !file.isDeclarationFile && !program.isSourceFileFromExternalLibrary(file)); @@ -61,7 +60,7 @@ function runUndecoratedClassesMigration(tree: Tree, tsconfigPath: string, basePa /** Gets the update recorder for the specified source file. */ function getUpdateRecorder(sourceFile: ts.SourceFile): UpdateRecorder { if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !; + return updateRecorders.get(sourceFile)!; } const treeRecorder = tree.beginUpdate(relative(basePath, sourceFile.fileName)); const recorder: UpdateRecorder = { @@ -81,7 +80,9 @@ function runUndecoratedClassesMigration(tree: Tree, tsconfigPath: string, basePa treeRecorder.remove(namedBindings.getStart(), namedBindings.getWidth()); treeRecorder.insertRight(namedBindings.getStart(), newNamedBindings); }, - commitUpdate() { tree.commitUpdate(treeRecorder); } + commitUpdate() { + tree.commitUpdate(treeRecorder); + } }; updateRecorders.set(sourceFile, recorder); return recorder; diff --git a/packages/core/schematics/test/all-migrations.spec.ts b/packages/core/schematics/test/all-migrations.spec.ts new file mode 100644 index 0000000000000..5d2544105a02a --- /dev/null +++ b/packages/core/schematics/test/all-migrations.spec.ts @@ -0,0 +1,96 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {getSystemPath, normalize, virtualFs} from '@angular-devkit/core'; +import {TempScopedNodeJsSyncHost} from '@angular-devkit/core/node/testing'; +import {HostTree} from '@angular-devkit/schematics'; +import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; +import * as shx from 'shelljs'; + +describe('all migrations', () => { + let runner: SchematicTestRunner; + let host: TempScopedNodeJsSyncHost; + let tree: UnitTestTree; + let tmpDirPath: string; + let previousWorkingDir: string; + + const migrationCollectionPath = require.resolve('../migrations.json'); + const allMigrationSchematics = Object.keys(require(migrationCollectionPath).schematics); + + beforeEach(() => { + runner = new SchematicTestRunner('test', migrationCollectionPath); + host = new TempScopedNodeJsSyncHost(); + tree = new UnitTestTree(new HostTree(host)); + + writeFile('/node_modules/@angular/core/index.d.ts', `export const MODULE: any;`); + writeFile('/angular.json', JSON.stringify({ + projects: {t: {architect: {build: {options: {tsConfig: './tsconfig.json'}}}}} + })); + writeFile('/tsconfig.json', `{}`); + + + previousWorkingDir = shx.pwd(); + tmpDirPath = getSystemPath(host.root); + + // Switch into the temporary directory path. This allows us to run + // the schematic against our custom unit test tree. + shx.cd(tmpDirPath); + }); + + afterEach(() => { + shx.cd(previousWorkingDir); + shx.rm('-r', tmpDirPath); + }); + + function writeFile(filePath: string, contents: string) { + host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); + } + + async function runMigration(migrationName: string) { + await runner.runSchematicAsync(migrationName, undefined, tree).toPromise(); + } + + if (!allMigrationSchematics.length) { + throw Error('No migration schematics found.'); + } + + allMigrationSchematics.forEach(name => { + describe(name, () => createTests(name)); + }); + + function createTests(migrationName: string) { + // Regression test for: https://github.com/angular/angular/issues/36346. + it('should not throw if non-existent symbols are imported with rootDirs', async () => { + writeFile(`/tsconfig.json`, JSON.stringify({ + compilerOptions: { + rootDirs: [ + './generated', + ] + } + })); + writeFile('/index.ts', ` + import {Renderer} from '@angular/core'; + + const variableDecl: Renderer = null; + + export class Test { + constructor(renderer: Renderer) {} + } + `); + + let error: any = null; + try { + await runMigration(migrationName); + } catch (e) { + error = e; + } + + expect(error).toBe(null); + }); + } +}); diff --git a/packages/core/schematics/utils/typescript/compiler_host.ts b/packages/core/schematics/utils/typescript/compiler_host.ts index 5103890dfef37..2257b32006d5f 100644 --- a/packages/core/schematics/utils/typescript/compiler_host.ts +++ b/packages/core/schematics/utils/typescript/compiler_host.ts @@ -6,12 +6,39 @@ * found in the LICENSE file at https://angular.io/license */ import {Tree} from '@angular-devkit/schematics'; -import {relative} from 'path'; +import {dirname, relative, resolve} from 'path'; import * as ts from 'typescript'; +import {parseTsconfigFile} from './parse_tsconfig'; + +export type FakeReadFileFn = (fileName: string) => string|null; + +/** + * Creates a TypeScript program instance for a TypeScript project within + * the virtual file system tree. + * @param tree Virtual file system tree that contains the source files. + * @param tsconfigPath Virtual file system path that resolves to the TypeScript project. + * @param basePath Base path for the virtual file system tree. + * @param fakeFileRead Optional file reader function. Can be used to overwrite files in + * the TypeScript program, or to add in-memory files (e.g. to add global types). + * @param additionalFiles Additional file paths that should be added to the program. + */ +export function createMigrationProgram( + tree: Tree, tsconfigPath: string, basePath: string, fakeFileRead?: FakeReadFileFn, + additionalFiles?: string[]) { + // Resolve the tsconfig path to an absolute path. This is needed as TypeScript otherwise + // is not able to resolve root directories in the given tsconfig. More details can be found + // in the following issue: https://github.com/microsoft/TypeScript/issues/37731. + tsconfigPath = resolve(basePath, tsconfigPath); + const parsed = parseTsconfigFile(tsconfigPath, dirname(tsconfigPath)); + const host = createMigrationCompilerHost(tree, parsed.options, basePath, fakeFileRead); + const program = + ts.createProgram(parsed.fileNames.concat(additionalFiles || []), parsed.options, host); + return {parsed, host, program}; +} export function createMigrationCompilerHost( tree: Tree, options: ts.CompilerOptions, basePath: string, - fakeRead?: (fileName: string) => string | null): ts.CompilerHost { + fakeRead?: FakeReadFileFn): ts.CompilerHost { const host = ts.createCompilerHost(options, true); // We need to overwrite the host "readFile" method, as we want the TypeScript diff --git a/packages/core/schematics/utils/typescript/parse_tsconfig.ts b/packages/core/schematics/utils/typescript/parse_tsconfig.ts index 220448a0efa85..9cbed072fd4f6 100644 --- a/packages/core/schematics/utils/typescript/parse_tsconfig.ts +++ b/packages/core/schematics/utils/typescript/parse_tsconfig.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import * as path from 'path'; import * as ts from 'typescript'; export function parseTsconfigFile(tsconfigPath: string, basePath: string): ts.ParsedCommandLine { @@ -17,5 +18,12 @@ export function parseTsconfigFile(tsconfigPath: string, basePath: string): ts.Pa readFile: ts.sys.readFile, }; + // Throw if incorrect arguments are passed to this function. Passing relative base paths + // results in root directories not being resolved and in later type checking runtime errors. + // More details can be found here: https://github.com/microsoft/TypeScript/issues/37731. + if (!path.isAbsolute(basePath)) { + throw Error('Unexpected relative base path has been specified.'); + } + return ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, {}); } From 09c84169d5caec16722a03af327662fcbd63ca31 Mon Sep 17 00:00:00 2001 From: Priyash Patil <38959321+priyashpatil@users.noreply.github.com> Date: Mon, 6 Apr 2020 22:54:44 +0300 Subject: [PATCH 120/262] docs: fix broken guide link (tutorial/index --> tutorial) (#36453) Replace broken link (`tutorial/index`) with `tutorial`. PR Close #36453 --- aio/content/guide/architecture-next-steps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/architecture-next-steps.md b/aio/content/guide/architecture-next-steps.md index e44796d132667..33ccf67485a95 100644 --- a/aio/content/guide/architecture-next-steps.md +++ b/aio/content/guide/architecture-next-steps.md @@ -3,7 +3,7 @@ After you understand the basic Angular building blocks, you can learn more about the features and tools that can help you develop and deliver Angular applications. -* Work through the [Tour of Heroes](tutorial/index) tutorial to get a feel for how to fit the basic building blocks together to create a well-designed application. +* Work through the [Tour of Heroes](tutorial) tutorial to get a feel for how to fit the basic building blocks together to create a well-designed application. * Check out the [Glossary](guide/glossary) to understand Angular-specific terms and usage. From aece3669e55eb08f425059b1fd5e636288c1be0e Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Mon, 6 Apr 2020 22:57:58 +0300 Subject: [PATCH 121/262] build(docs-infra): switch docs examples to Ivy (#36143) The docs examples are switched to Ivy. On CI, the tests are run with both Ivy and ViewEngine. Partially addresses: [FW-1609](https://angular-team.atlassian.net/browse/FW-1609) PR Close #36143 --- .circleci/config.yml | 10 ++-- aio/README.md | 8 ++-- .../dependency-injection/example-config.json | 13 ----- .../tsconfig.json | 12 ++--- .../rollup-config.js | 6 +-- .../tsconfig-aot.json | 19 ++++---- .../upgrade-phonecat-2-hybrid/tsconfig.json | 12 ++--- .../upgrade-phonecat-3-final/tsconfig.json | 12 ++--- aio/package.json | 2 +- .../customizer/package-json/cli-ajs.json | 2 +- .../customizer/package-json/cli.json | 2 +- .../package-json/getting-started.json | 2 +- .../customizer/package-json/i18n.json | 2 +- .../customizer/package-json/schematics.json | 2 +- aio/tools/examples/README.md | 2 +- aio/tools/examples/example-boilerplate.js | 30 ++++++------ .../examples/example-boilerplate.spec.js | 47 ++++++++++++++++++- aio/tools/examples/run-example-e2e.js | 10 ++-- .../shared/boilerplate/cli/tsconfig.json | 1 - .../boilerplate/ivy/cli/tsconfig.app.json | 33 ------------- .../boilerplate/viewengine/cli/tsconfig.json | 27 +++++++++++ .../systemjs/rollup-config.js | 4 +- .../systemjs/tsconfig-aot.json | 9 ++-- 23 files changed, 146 insertions(+), 121 deletions(-) delete mode 100644 aio/tools/examples/shared/boilerplate/ivy/cli/tsconfig.app.json create mode 100644 aio/tools/examples/shared/boilerplate/viewengine/cli/tsconfig.json rename aio/tools/examples/shared/boilerplate/{ivy => viewengine}/systemjs/rollup-config.js (86%) rename aio/tools/examples/shared/boilerplate/{ivy => viewengine}/systemjs/tsconfig-aot.json (81%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3c45a7265481a..17abb95464c05 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -455,7 +455,7 @@ jobs: test_docs_examples: parameters: - ivy: + viewengine: type: boolean default: false executor: @@ -471,7 +471,7 @@ jobs: # Run examples tests. The "CIRCLE_NODE_INDEX" will be set if "parallelism" is enabled. # Since the parallelism is set to "5", there will be five parallel CircleCI containers. # with either "0", "1", etc as node index. This can be passed to the "--shard" argument. - - run: yarn --cwd aio example-e2e --setup --local <<# parameters.ivy >>--ivy<</ parameters.ivy >> --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} --retry 2 + - run: yarn --cwd aio example-e2e --setup --local <<# parameters.viewengine >>--viewengine<</ parameters.viewengine >> --cliSpecsConcurrency=5 --shard=${CIRCLE_NODE_INDEX}/${CIRCLE_NODE_TOTAL} --retry 2 # This job should only be run on PR builds, where `CI_PULL_REQUEST` is not `false`. aio_preview: @@ -823,8 +823,8 @@ workflows: requires: - build-npm-packages - test_docs_examples: - name: test_docs_examples_ivy - ivy: true + name: test_docs_examples_viewengine + viewengine: true requires: - build-npm-packages - aio_preview: @@ -851,7 +851,7 @@ workflows: - test_aio_local - test_aio_local_viewengine - test_docs_examples - - test_docs_examples_ivy + - test_docs_examples_viewengine # Get the artifacts to publish from the build-packages-dist job # since the publishing script expects the legacy outputs layout. - build-npm-packages diff --git a/aio/README.md b/aio/README.md index 8cb7af568db3d..b46467d2bf181 100644 --- a/aio/README.md +++ b/aio/README.md @@ -18,8 +18,8 @@ Here are the most important tasks you might need to use: * `yarn build` - create a production build of the application (after installing dependencies, boilerplate, etc). * `yarn build-local` - same as `build`, but use `setup-local` instead of `setup`. -* `yarn build-local-with-viewengine` - same as `build-local`, but in addition also turns on `ViewEngine` mode in aio. - (Note: Docs examples run in `ViewEngine` mode by default. To turn on `ivy` mode in examples, see `yarn boilerplate:add` below.) +* `yarn build-local-with-viewengine` - same as `build-local`, but in addition also turns on `ViewEngine` (pre-Ivy) mode in aio. + (Note: To turn on `ViewEngine` mode in docs examples, see `yarn boilerplate:add:viewengine` below.) * `yarn start` - run a development web server that watches the files; then builds the doc-viewer and reloads the page, as necessary. * `yarn serve-and-sync` - run both the `docs-watch` and `start` in the same console. @@ -34,7 +34,7 @@ Here are the most important tasks you might need to use: * `yarn docs-test` - run the unit tests for the doc generation code. * `yarn boilerplate:add` - generate all the boilerplate code for the examples, so that they can be run locally. -* `yarn boilerplate:add:ivy` - same as `boilerplate:add` but also turns on `ivy` mode. +* `yarn boilerplate:add:viewengine` - same as `boilerplate:add` but also turns on `ViewEngine` (pre-Ivy) mode. * `yarn boilerplate:remove` - remove all the boilerplate code that was added via `yarn boilerplate:add`. * `yarn generate-stackblitz` - generate the stackblitz files that are used by the `live-example` tags in the docs. @@ -44,7 +44,7 @@ Here are the most important tasks you might need to use: - `--setup`: generate boilerplate, force webdriver update & other setup, then run tests. - `--local`: run e2e tests with the local version of Angular contained in the "dist" folder. _Requires `--setup` in order to take effect._ - - `--ivy`: run e2e tests in `ivy` mode. + - `--viewengine`: run e2e tests in `ViewEngine` (pre-Ivy) mode. - `--filter=foo`: limit e2e tests to those containing the word "foo". > **Note for Windows users** diff --git a/aio/content/examples/dependency-injection/example-config.json b/aio/content/examples/dependency-injection/example-config.json index d56f4ce8b0d03..e69de29bb2d1d 100644 --- a/aio/content/examples/dependency-injection/example-config.json +++ b/aio/content/examples/dependency-injection/example-config.json @@ -1,13 +0,0 @@ -{ - "e2e": [ - { - "cmd": "yarn", - "args": [ - "e2e", - "--protractor-config=e2e/protractor-puppeteer.conf.js", - "--no-webdriver-update", - "--port={PORT}" - ] - } - ] -} diff --git a/aio/content/examples/upgrade-phonecat-1-typescript/tsconfig.json b/aio/content/examples/upgrade-phonecat-1-typescript/tsconfig.json index 341d5a61ccc7f..a89a619231e07 100644 --- a/aio/content/examples/upgrade-phonecat-1-typescript/tsconfig.json +++ b/aio/content/examples/upgrade-phonecat-1-typescript/tsconfig.json @@ -12,15 +12,15 @@ ], "noImplicitAny": true, "skipLibCheck": true, - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types" + ] }, "compileOnSave": true, "exclude": [ "node_modules/*", "**/*-aot.ts", "aot/**/*" - ], - "angularCompilerOptions": { - "enableIvy": false - } -} \ No newline at end of file + ] +} diff --git a/aio/content/examples/upgrade-phonecat-2-hybrid/rollup-config.js b/aio/content/examples/upgrade-phonecat-2-hybrid/rollup-config.js index 6cfaf379e72c6..c431e9d8e5e2a 100644 --- a/aio/content/examples/upgrade-phonecat-2-hybrid/rollup-config.js +++ b/aio/content/examples/upgrade-phonecat-2-hybrid/rollup-config.js @@ -1,11 +1,11 @@ // #docregion import nodeResolve from 'rollup-plugin-node-resolve' -import commonjs from 'rollup-plugin-commonjs'; -import uglify from 'rollup-plugin-uglify' +import commonjs from 'rollup-plugin-commonjs'; +import uglify from 'rollup-plugin-uglify' //paths are relative to the execution path export default { - input: 'app/main-aot.js', + input: 'app/main.js', output: { file: 'aot/dist/build.js', // output a single application bundle format: 'iife', diff --git a/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig-aot.json b/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig-aot.json index a2b95ecb34cb6..4ff59fe863803 100644 --- a/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig-aot.json +++ b/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig-aot.json @@ -6,20 +6,23 @@ "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "lib": ["es2015", "dom"], + "lib": [ + "es2015", + "dom" + ], "removeComments": false, "noImplicitAny": true, "skipLibCheck": true, - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types" + ] }, - "files": [ "app/app.module.ts", - "app/main-aot.ts" + "app/main.ts" ], - "angularCompilerOptions": { - "skipMetadataEmit" : true, - "enableIvy": false, - } + "skipMetadataEmit": true + } } diff --git a/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig.json b/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig.json index 6daafd7a8949f..d1f02feb5b96e 100644 --- a/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig.json +++ b/aio/content/examples/upgrade-phonecat-2-hybrid/tsconfig.json @@ -12,14 +12,14 @@ ], "noImplicitAny": true, "skipLibCheck": true, - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types" + ] }, "compileOnSave": true, "exclude": [ "node_modules/*", "**/*-aot.ts" - ], - "angularCompilerOptions": { - "enableIvy": false - } -} \ No newline at end of file + ] +} diff --git a/aio/content/examples/upgrade-phonecat-3-final/tsconfig.json b/aio/content/examples/upgrade-phonecat-3-final/tsconfig.json index 6daafd7a8949f..d1f02feb5b96e 100644 --- a/aio/content/examples/upgrade-phonecat-3-final/tsconfig.json +++ b/aio/content/examples/upgrade-phonecat-3-final/tsconfig.json @@ -12,14 +12,14 @@ ], "noImplicitAny": true, "skipLibCheck": true, - "suppressImplicitAnyIndexErrors": true + "suppressImplicitAnyIndexErrors": true, + "typeRoots": [ + "node_modules/@types" + ] }, "compileOnSave": true, "exclude": [ "node_modules/*", "**/*-aot.ts" - ], - "angularCompilerOptions": { - "enableIvy": false - } -} \ No newline at end of file + ] +} diff --git a/aio/package.json b/aio/package.json index 5316812276ef7..9663d40ab016b 100644 --- a/aio/package.json +++ b/aio/package.json @@ -66,7 +66,7 @@ "preserve-and-sync": "yarn docs", "serve-and-sync": "run-p \"start\" \"docs-watch --watch-only\"", "boilerplate:add": "node ./tools/examples/example-boilerplate add", - "boilerplate:add:ivy": "yarn boilerplate:add --ivy", + "boilerplate:add:viewengine": "yarn boilerplate:add --viewengine", "boilerplate:remove": "node ./tools/examples/example-boilerplate remove", "boilerplate:test": "node tools/examples/test.js", "generate-stackblitz": "node ./tools/stackblitz-builder/generateStackblitz", diff --git a/aio/tools/example-zipper/customizer/package-json/cli-ajs.json b/aio/tools/example-zipper/customizer/package-json/cli-ajs.json index f19a131a9a24b..ef9c75606a26d 100644 --- a/aio/tools/example-zipper/customizer/package-json/cli-ajs.json +++ b/aio/tools/example-zipper/customizer/package-json/cli-ajs.json @@ -1,7 +1,7 @@ { "scripts": [ { "name": "ng", "command": "ng" }, - { "name": "build", "command": "ng build --prod" }, + { "name": "build", "command": "ng build" }, { "name": "start", "command": "ng serve" }, { "name": "test", "command": "ng test" }, { "name": "lint", "command": "ng lint" }, diff --git a/aio/tools/example-zipper/customizer/package-json/cli.json b/aio/tools/example-zipper/customizer/package-json/cli.json index 965bd82407a45..ebbbbc1341ba3 100644 --- a/aio/tools/example-zipper/customizer/package-json/cli.json +++ b/aio/tools/example-zipper/customizer/package-json/cli.json @@ -1,7 +1,7 @@ { "scripts": [ { "name": "ng", "command": "ng" }, - { "name": "build", "command": "ng build --prod" }, + { "name": "build", "command": "ng build" }, { "name": "start", "command": "ng serve" }, { "name": "test", "command": "ng test" }, { "name": "lint", "command": "ng lint" }, diff --git a/aio/tools/example-zipper/customizer/package-json/getting-started.json b/aio/tools/example-zipper/customizer/package-json/getting-started.json index 965bd82407a45..ebbbbc1341ba3 100644 --- a/aio/tools/example-zipper/customizer/package-json/getting-started.json +++ b/aio/tools/example-zipper/customizer/package-json/getting-started.json @@ -1,7 +1,7 @@ { "scripts": [ { "name": "ng", "command": "ng" }, - { "name": "build", "command": "ng build --prod" }, + { "name": "build", "command": "ng build" }, { "name": "start", "command": "ng serve" }, { "name": "test", "command": "ng test" }, { "name": "lint", "command": "ng lint" }, diff --git a/aio/tools/example-zipper/customizer/package-json/i18n.json b/aio/tools/example-zipper/customizer/package-json/i18n.json index 57320e769eb0e..f3434be8d1dc2 100644 --- a/aio/tools/example-zipper/customizer/package-json/i18n.json +++ b/aio/tools/example-zipper/customizer/package-json/i18n.json @@ -2,7 +2,7 @@ "scripts": [ { "name": "start", "command": "ng serve" }, { "name": "start:fr", "command": "ng serve --configuration=fr" }, - { "name": "build", "command": "ng build --prod" }, + { "name": "build", "command": "ng build" }, { "name": "build:fr", "command": "ng build --configuration=production-fr" }, { "name": "test", "command": "ng test" }, { "name": "lint", "command": "ng lint" }, diff --git a/aio/tools/example-zipper/customizer/package-json/schematics.json b/aio/tools/example-zipper/customizer/package-json/schematics.json index 44e2cc572eac7..947a1917c20f0 100644 --- a/aio/tools/example-zipper/customizer/package-json/schematics.json +++ b/aio/tools/example-zipper/customizer/package-json/schematics.json @@ -1,7 +1,7 @@ { "scripts": [ { "name": "ng", "command": "ng" }, - { "name": "build", "command": "ng build --prod" }, + { "name": "build", "command": "ng build" }, { "name": "build:lib", "command": "ng build my-lib" }, { "name": "start", "command": "ng serve" }, { "name": "test", "command": "ng test" }, diff --git a/aio/tools/examples/README.md b/aio/tools/examples/README.md index 1a0ccfa0bec94..85a83bdc8ab66 100644 --- a/aio/tools/examples/README.md +++ b/aio/tools/examples/README.md @@ -32,12 +32,12 @@ Currently you will find the next project types: * cli - For CLI based examples. This is the default one, to be used in the majority of the examples. * getting-started - CLI-based with its own set of styles. * i18n - CLI-based with additional scripts for internationalization. -* ivy - CLI-based with additional configuration for running the examples with the Ivy renderer and ngstc compiler. * schematics - CLI-based with additional scripts for building schematics. * service-worker - CLI-based with additional packages and configuration for service workers. * systemjs - Currently in deprecation, only used in a few examples. * testing - CLI-based with additional styles for jasmine testing. * universal - CLI-based with an extra server target. +* viewengine - Additional configuration for running CLI-/SystemJS-based examples with `ViewEngine` (the pre-Ivy compiler/renderer). There is also a `common` folder that contains files used in all different examples. diff --git a/aio/tools/examples/example-boilerplate.js b/aio/tools/examples/example-boilerplate.js index 13f63d221f5a5..3899f4509bced 100644 --- a/aio/tools/examples/example-boilerplate.js +++ b/aio/tools/examples/example-boilerplate.js @@ -50,11 +50,6 @@ BOILERPLATE_PATHS['getting-started'] = [ 'src/styles.css' ]; -BOILERPLATE_PATHS.ivy = { - systemjs: ['rollup-config.js', 'tsconfig-aot.json'], - cli: ['tsconfig.app.json'] -}; - BOILERPLATE_PATHS.schematics = [ ...cliRelativePath, 'angular.json' @@ -65,13 +60,18 @@ BOILERPLATE_PATHS['cli-ajs'] = [ 'package.json' ]; +BOILERPLATE_PATHS.viewengine = { + systemjs: ['rollup-config.js', 'tsconfig-aot.json'], + cli: ['tsconfig.json'] +}; + const EXAMPLE_CONFIG_FILENAME = 'example-config.json'; class ExampleBoilerPlate { /** * Add boilerplate files to all the examples */ - add(ivy = false) { + add(viewengine = false) { // Get all the examples folders, indicated by those that contain a `example-config.json` file const exampleFolders = this.getFoldersContaining(EXAMPLES_BASE_PATH, EXAMPLE_CONFIG_FILENAME, 'node_modules'); @@ -82,7 +82,7 @@ class ExampleBoilerPlate { `Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`); } - if (ivy) { + if (!viewengine) { shelljs.exec(`yarn --cwd ${SHARED_PATH} ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points`); } @@ -107,13 +107,13 @@ class ExampleBoilerPlate { BOILERPLATE_PATHS.common.forEach(filePath => this.copyFile(BOILERPLATE_COMMON_BASE_PATH, exampleFolder, filePath)); } - // Copy Ivy specific files - if (ivy) { - const ivyBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli'; - const ivyBoilerPlateBasePath = - path.resolve(BOILERPLATE_BASE_PATH, 'ivy', ivyBoilerPlateType); - BOILERPLATE_PATHS.ivy[ivyBoilerPlateType].forEach( - filePath => this.copyFile(ivyBoilerPlateBasePath, exampleFolder, filePath)); + // Copy ViewEngine (pre-Ivy) specific files + if (viewengine) { + const veBoilerPlateType = boilerPlateType === 'systemjs' ? 'systemjs' : 'cli'; + const veBoilerPlateBasePath = + path.resolve(BOILERPLATE_BASE_PATH, 'viewengine', veBoilerPlateType); + BOILERPLATE_PATHS.viewengine[veBoilerPlateType].forEach( + filePath => this.copyFile(veBoilerPlateBasePath, exampleFolder, filePath)); } }); } @@ -125,7 +125,7 @@ class ExampleBoilerPlate { main() { yargs.usage('$0 <cmd> [args]') - .command('add', 'add the boilerplate to each example', (yrgs) => this.add(yrgs.argv.ivy)) + .command('add', 'add the boilerplate to each example', yrgs => this.add(yrgs.argv.viewengine)) .command('remove', 'remove the boilerplate from each example', () => this.remove()) .demandCommand(1, 'Please supply a command from the list above') .argv; diff --git a/aio/tools/examples/example-boilerplate.spec.js b/aio/tools/examples/example-boilerplate.spec.js index 85426d0f4537c..1a4f8fb2ede5c 100644 --- a/aio/tools/examples/example-boilerplate.spec.js +++ b/aio/tools/examples/example-boilerplate.spec.js @@ -14,18 +14,29 @@ describe('example-boilerplate tool', () => { i18n: 2, universal: 2, systemjs: 7, - common: 1 + common: 1, + viewengine: { + cli: 1, + systemjs: 2, + }, }; const exampleFolders = ['a/b', 'c/d']; beforeEach(() => { spyOn(fs, 'ensureSymlinkSync'); spyOn(fs, 'existsSync').and.returnValue(true); + spyOn(shelljs, 'exec'); spyOn(exampleBoilerPlate, 'copyFile'); spyOn(exampleBoilerPlate, 'getFoldersContaining').and.returnValue(exampleFolders); spyOn(exampleBoilerPlate, 'loadJsonFile').and.returnValue({}); }); + it('should run `ngcc`', () => { + exampleBoilerPlate.add(); + expect(shelljs.exec).toHaveBeenCalledWith( + `yarn --cwd ${sharedDir} ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points`); + }); + it('should process all the example folders', () => { const examplesDir = path.resolve(__dirname, '../../content/examples'); exampleBoilerPlate.add(); @@ -50,7 +61,7 @@ describe('example-boilerplate tool', () => { it('should copy all the source boilerplate files for systemjs', () => { const boilerplateDir = path.resolve(sharedDir, 'boilerplate'); - exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { projectType: 'systemjs' } : {}) + exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { projectType: 'systemjs' } : {}); exampleBoilerPlate.add(); expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes( (BPFiles.cli) + @@ -110,6 +121,38 @@ describe('example-boilerplate tool', () => { expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve('a/b/example-config.json')); expect(exampleBoilerPlate.loadJsonFile).toHaveBeenCalledWith(path.resolve('c/d/example-config.json')); }); + + describe('(viewengine: true)', () => { + it('should not run `ngcc`', () => { + exampleBoilerPlate.add(true); + expect(shelljs.exec).not.toHaveBeenCalled(); + }); + + it('should copy all the source boilerplate files for systemjs', () => { + const boilerplateDir = path.resolve(sharedDir, 'boilerplate'); + exampleBoilerPlate.loadJsonFile.and.callFake(filePath => filePath.indexOf('a/b') !== -1 ? { projectType: 'systemjs' } : {}); + exampleBoilerPlate.add(true); + expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes( + (BPFiles.cli + BPFiles.viewengine.cli) + + (BPFiles.systemjs + BPFiles.viewengine.systemjs) + + (BPFiles.common * exampleFolders.length) + ); + // for example + expect(exampleBoilerPlate.copyFile).toHaveBeenCalledWith(`${boilerplateDir}/viewengine/systemjs`, 'a/b', 'tsconfig-aot.json'); + }); + + it('should copy all the source boilerplate files for cli', () => { + const boilerplateDir = path.resolve(sharedDir, 'boilerplate'); + exampleBoilerPlate.add(true); + expect(exampleBoilerPlate.copyFile).toHaveBeenCalledTimes( + (BPFiles.cli * exampleFolders.length) + + (BPFiles.viewengine.cli * exampleFolders.length) + + (BPFiles.common * exampleFolders.length) + ); + // for example + expect(exampleBoilerPlate.copyFile).toHaveBeenCalledWith(`${boilerplateDir}/viewengine/cli`, 'a/b', 'tsconfig.json'); + }); + }); }); describe('remove', () => { diff --git a/aio/tools/examples/run-example-e2e.js b/aio/tools/examples/run-example-e2e.js index ab51992f38051..2213a5c4545d3 100644 --- a/aio/tools/examples/run-example-e2e.js +++ b/aio/tools/examples/run-example-e2e.js @@ -28,7 +28,7 @@ const fixmeIvyExamples = [ 'i18n', ]; -if (argv.ivy) { +if (!argv.viewengine) { IGNORED_EXAMPLES.push(...fixmeIvyExamples); } @@ -46,7 +46,7 @@ if (argv.ivy) { * Must be used in conjunction with --setup as this is when the packages are copied. * e.g. --setup --local * - * --ivy to turn on `ivy` mode + * --viewengine to turn on `ViewEngine` mode * * --shard to shard the specs into groups to allow you to run them in parallel * e.g. --shard=0/2 // the even specs: 0, 2, 4, etc @@ -64,7 +64,7 @@ function runE2e() { // Run setup. console.log('runE2e: setup boilerplate'); const installPackagesCommand = `example-use-${argv.local ? 'local' : 'npm'}`; - const addBoilerplateCommand = `boilerplate:add${argv.ivy ? ':ivy' : ''}`; + const addBoilerplateCommand = `boilerplate:add${argv.viewengine ? ':viewengine' : ''}`; shelljs.exec(`yarn ${installPackagesCommand}`, {cwd: AIO_PATH}); shelljs.exec(`yarn ${addBoilerplateCommand}`, {cwd: AIO_PATH}); } @@ -185,7 +185,7 @@ function runE2eTestsSystemJS(appDir, outputFile) { // Only run AOT tests in ViewEngine mode. The current AOT setup does not work in Ivy. // See https://github.com/angular/angular/issues/35989. - if (!argv.ivy && fs.existsSync(appDir + '/aot/index.html')) { + if (argv.viewengine && fs.existsSync(appDir + '/aot/index.html')) { run = run.then((ok) => ok && runProtractorAoT(appDir, outputFile)); } return run; @@ -311,7 +311,7 @@ function reportStatus(status, outputFile) { IGNORED_EXAMPLES.filter(example => !fixmeIvyExamples.find(ex => ex.startsWith(example))) .forEach(function(val) { log.push(' ' + val); }); - if (argv.ivy) { + if (!argv.viewengine) { log.push(''); log.push('Suites ignored due to breakage with Ivy:'); fixmeIvyExamples.forEach(function(val) { log.push(' ' + val); }); diff --git a/aio/tools/examples/shared/boilerplate/cli/tsconfig.json b/aio/tools/examples/shared/boilerplate/cli/tsconfig.json index e4816a58e77b2..30956ae7ea265 100644 --- a/aio/tools/examples/shared/boilerplate/cli/tsconfig.json +++ b/aio/tools/examples/shared/boilerplate/cli/tsconfig.json @@ -20,7 +20,6 @@ ] }, "angularCompilerOptions": { - "enableIvy": false, "fullTemplateTypeCheck": true, "strictInjectionParameters": true } diff --git a/aio/tools/examples/shared/boilerplate/ivy/cli/tsconfig.app.json b/aio/tools/examples/shared/boilerplate/ivy/cli/tsconfig.app.json deleted file mode 100644 index 5360c33dd7c56..0000000000000 --- a/aio/tools/examples/shared/boilerplate/ivy/cli/tsconfig.app.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": [ - "src/main.ts", - "src/polyfills.ts" - ], - "include": [ - "src/**/*.d.ts" - ], - "exclude": [ - "src/test.ts", - "src/**/*.spec.ts", - "src/**/*-specs.ts", - "src/**/*.avoid.ts", - "src/**/*.0.ts", - "src/**/*.1.ts", - "src/**/*.1b.ts", - "src/**/*.2.ts", - "src/**/*.3.ts", - "src/**/*.4.ts", - "src/**/*.5.ts", - "src/**/*.6.ts", - "src/**/*.7.ts", - "src/**/testing" - ], - "angularCompilerOptions": { - "enableIvy": true - } -} diff --git a/aio/tools/examples/shared/boilerplate/viewengine/cli/tsconfig.json b/aio/tools/examples/shared/boilerplate/viewengine/cli/tsconfig.json new file mode 100644 index 0000000000000..e4816a58e77b2 --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/viewengine/cli/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "module": "esnext", + "moduleResolution": "node", + "importHelpers": true, + "target": "es2015", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ] + }, + "angularCompilerOptions": { + "enableIvy": false, + "fullTemplateTypeCheck": true, + "strictInjectionParameters": true + } +} diff --git a/aio/tools/examples/shared/boilerplate/ivy/systemjs/rollup-config.js b/aio/tools/examples/shared/boilerplate/viewengine/systemjs/rollup-config.js similarity index 86% rename from aio/tools/examples/shared/boilerplate/ivy/systemjs/rollup-config.js rename to aio/tools/examples/shared/boilerplate/viewengine/systemjs/rollup-config.js index ec1bbb59083cd..752e637e50409 100644 --- a/aio/tools/examples/shared/boilerplate/ivy/systemjs/rollup-config.js +++ b/aio/tools/examples/shared/boilerplate/viewengine/systemjs/rollup-config.js @@ -5,7 +5,7 @@ import uglify from 'rollup-plugin-uglify' //paths are relative to the execution path export default { - input: 'app/main.js', + input: 'app/main-aot.js', output: { file: 'aot/dist/build.js', // output a single application bundle format: 'iife', @@ -13,7 +13,7 @@ export default { sourcemapFile: 'aot/dist/build.js.map' }, plugins: [ - nodeResolve({ jsnext: true, module: true }), + nodeResolve({jsnext: true, module: true}), commonjs({ include: ['node_modules/rxjs/**'] }), diff --git a/aio/tools/examples/shared/boilerplate/ivy/systemjs/tsconfig-aot.json b/aio/tools/examples/shared/boilerplate/viewengine/systemjs/tsconfig-aot.json similarity index 81% rename from aio/tools/examples/shared/boilerplate/ivy/systemjs/tsconfig-aot.json rename to aio/tools/examples/shared/boilerplate/viewengine/systemjs/tsconfig-aot.json index d68fa9f6eca02..068667697026a 100644 --- a/aio/tools/examples/shared/boilerplate/ivy/systemjs/tsconfig-aot.json +++ b/aio/tools/examples/shared/boilerplate/viewengine/systemjs/tsconfig-aot.json @@ -7,24 +7,23 @@ "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": [ - "es2018", + "es2015", "dom" ], "removeComments": false, "noImplicitAny": true, "skipLibCheck": true, "suppressImplicitAnyIndexErrors": true, - "importHelpers": true, "typeRoots": [ "node_modules/@types" ] }, "files": [ "app/app.module.ts", - "app/main.ts" + "app/main-aot.ts" ], "angularCompilerOptions": { - "skipMetadataEmit": true, - "enableIvy": true + "enableIvy": false, + "skipMetadataEmit": true } } From d707124fd958715a9e4e707e14b02731590180d6 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Mon, 23 Mar 2020 17:31:55 +0200 Subject: [PATCH 122/262] test(docs-infra): fix unit tests and run them for specific docs examples on CI (#36143) Previously, only e2e tests were run for docs examples on CI. As a result, unit tests (which are included in the zipped archives we provide for users to download and play with the examples locally) were often outdated and broken. This commit configures specific docs examples that have meaningful unit tests to run them on CI (via the `run-example-e2e.js` script). Where necessary, the unit tests are fixed to ensure they pass and reflect the changes in the corresponding component/service. This commit also removes some auto-generated unit tests that are not meaningful (e.g. make trivial assertions, such that a component instance is truthy) and are often broken anyway (e.g. because the corresponding component has been changed in ways that make the tests fail). PR Close #36143 --- .../src/app/app.component.spec.ts | 27 -------------- .../src/app/app.component.spec.ts | 27 -------------- .../src/app/app.component.spec.ts | 32 ----------------- .../src/app/item.directive.spec.ts | 8 ----- .../item-detail/item-detail.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 16 --------- .../src/app/app.component.spec.ts | 27 -------------- .../item-detail/item-detail.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 32 ----------------- .../customer-dashboard.component.spec.ts | 25 ------------- .../forms-overview/example-config.json | 6 ++++ .../src/app/reactive/reactive.module.spec.ts | 13 ------- .../src/app/template/template.module.spec.ts | 13 ------- aio/content/examples/http/example-config.json | 6 +++- .../app/aliasing/aliasing.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 27 -------------- .../in-the-metadata.component.spec.ts | 25 ------------- .../input-output.component.spec.ts | 25 ------------- .../item-detail/item-detail.component.spec.ts | 25 ------------- .../item-output/item-output.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 16 --------- .../src/app/app.component.spec.ts | 36 ------------------- .../app/customers/customers.component.spec.ts | 25 ------------- .../src/app/orders/orders.component.spec.ts | 25 ------------- .../ngmodules/src/app/app.component.spec.ts | 32 ----------------- .../src/app/contact/contact.component.spec.ts | 25 ------------- .../src/app/items/items.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 27 -------------- .../item-detail/item-detail.component.spec.ts | 25 ------------- .../app/item-list/item-list.component.spec.ts | 25 ------------- .../string-init/string-init.component.spec.ts | 25 ------------- .../providers/src/app/app.component.spec.ts | 32 ----------------- .../providers/src/app/user.service.spec.ts | 12 ------- .../src/app/app.component.spec.ts | 27 -------------- .../page-not-found.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 27 -------------- .../examples/setup/example-config.json | 6 ++++ .../setup/src/app/app.component.spec.ts | 4 +-- .../src/app/app.component.spec.ts | 27 -------------- .../src/app/app.component.spec.ts | 27 -------------- .../examples/testing/example-config.json | 6 +++- .../src/app/about/about.component.spec.ts | 2 +- .../testing/src/app/app-routing.module.ts | 18 +++++----- .../src/app/app.component.router.spec.ts | 20 ++++++----- .../examples/testing/src/app/app.module.ts | 3 +- .../testing/src/app/demo/demo.testbed.spec.ts | 14 ++++---- .../src/app/welcome/welcome.component.spec.ts | 22 ++++-------- .../src/app/welcome/welcome.component.ts | 4 +-- aio/content/examples/testing/src/tests.sb.ts | 1 + .../toh-pt0/src/app/app.component.spec.ts | 32 ----------------- .../src/app/heroes/heroes.component.spec.ts | 25 ------------- .../src/app/heroes/heroes.component.spec.ts | 25 ------------- .../src/app/heroes/heroes.component.spec.ts | 25 ------------- .../src/app/heroes/heroes.component.spec.ts | 25 ------------- .../toh-pt4/src/app/message.service.spec.ts | 15 -------- .../app/messages/messages.component.spec.ts | 25 ------------- .../app/dashboard/dashboard.component.spec.ts | 25 ------------- .../src/app/heroes/heroes.component.spec.ts | 25 ------------- .../toh-pt5/src/app/message.service.spec.ts | 15 -------- .../app/messages/messages.component.spec.ts | 25 ------------- .../examples/toh-pt6/example-config.json | 6 ++++ .../hero-search/hero-search.component.spec.ts | 29 --------------- .../src/app/heroes/heroes.component.spec.ts | 27 -------------- .../toh-pt6/src/app/message.service.spec.ts | 15 -------- .../app/messages/messages.component.spec.ts | 25 ------------- .../src/app/app.component.spec.ts | 27 -------------- .../src/app/sizer/sizer.component.spec.ts | 25 ------------- .../app/dashboard/dashboard.component.spec.ts | 25 ------------- .../hero-search/hero-search.component.spec.ts | 25 ------------- .../src/app/heroes/heroes.component.spec.ts | 25 ------------- .../universal/src/app/message.service.spec.ts | 15 -------- .../app/messages/messages.component.spec.ts | 25 ------------- .../upgrade-phonecat-3-final/README.md | 3 -- .../run-unit-tests.sh | 6 ---- aio/content/guide/testing.md | 12 ------- aio/tools/examples/run-example-e2e.js | 3 ++ 76 files changed, 74 insertions(+), 1478 deletions(-) delete mode 100644 aio/content/examples/attribute-binding/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/binding-syntax/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/bootstrapping/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/bootstrapping/src/app/item.directive.spec.ts delete mode 100644 aio/content/examples/built-in-directives/src/app/item-detail/item-detail.component.spec.ts delete mode 100644 aio/content/examples/built-in-template-functions/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/event-binding/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts delete mode 100644 aio/content/examples/feature-modules/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts delete mode 100644 aio/content/examples/forms-overview/src/app/reactive/reactive.module.spec.ts delete mode 100644 aio/content/examples/forms-overview/src/app/template/template.module.spec.ts delete mode 100644 aio/content/examples/inputs-outputs/src/app/aliasing/aliasing.component.spec.ts delete mode 100644 aio/content/examples/inputs-outputs/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.spec.ts delete mode 100644 aio/content/examples/inputs-outputs/src/app/input-output/input-output.component.spec.ts delete mode 100644 aio/content/examples/inputs-outputs/src/app/item-detail/item-detail.component.spec.ts delete mode 100644 aio/content/examples/inputs-outputs/src/app/item-output/item-output.component.spec.ts delete mode 100644 aio/content/examples/interpolation/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/lazy-loading-ngmodules/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/lazy-loading-ngmodules/src/app/customers/customers.component.spec.ts delete mode 100644 aio/content/examples/lazy-loading-ngmodules/src/app/orders/orders.component.spec.ts delete mode 100644 aio/content/examples/ngmodules/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/ngmodules/src/app/contact/contact.component.spec.ts delete mode 100644 aio/content/examples/ngmodules/src/app/items/items.component.spec.ts delete mode 100644 aio/content/examples/property-binding/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts delete mode 100644 aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts delete mode 100644 aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts delete mode 100644 aio/content/examples/providers/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/providers/src/app/user.service.spec.ts delete mode 100644 aio/content/examples/reactive-forms/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/router/src/app/page-not-found/page-not-found.component.spec.ts delete mode 100755 aio/content/examples/service-worker-getting-started/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/template-expression-operators/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/template-reference-variables/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/toh-pt0/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/toh-pt4/src/app/message.service.spec.ts delete mode 100644 aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/message.service.spec.ts delete mode 100644 aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/message.service.spec.ts delete mode 100644 aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts delete mode 100644 aio/content/examples/two-way-binding/src/app/app.component.spec.ts delete mode 100644 aio/content/examples/two-way-binding/src/app/sizer/sizer.component.spec.ts delete mode 100644 aio/content/examples/universal/src/app/dashboard/dashboard.component.spec.ts delete mode 100644 aio/content/examples/universal/src/app/hero-search/hero-search.component.spec.ts delete mode 100644 aio/content/examples/universal/src/app/heroes/heroes.component.spec.ts delete mode 100644 aio/content/examples/universal/src/app/message.service.spec.ts delete mode 100644 aio/content/examples/universal/src/app/messages/messages.component.spec.ts delete mode 100644 aio/content/examples/upgrade-phonecat-3-final/run-unit-tests.sh diff --git a/aio/content/examples/attribute-binding/src/app/app.component.spec.ts b/aio/content/examples/attribute-binding/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/attribute-binding/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/binding-syntax/src/app/app.component.spec.ts b/aio/content/examples/binding-syntax/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/binding-syntax/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/bootstrapping/src/app/app.component.spec.ts b/aio/content/examples/bootstrapping/src/app/app.component.spec.ts deleted file mode 100644 index 0e3504562b3ce..0000000000000 --- a/aio/content/examples/bootstrapping/src/app/app.component.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }); - TestBed.compileComponents(); - }); - - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - - it(`should have as title 'app works!'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app works!'); - })); - - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('app works!'); - })); -}); diff --git a/aio/content/examples/bootstrapping/src/app/item.directive.spec.ts b/aio/content/examples/bootstrapping/src/app/item.directive.spec.ts deleted file mode 100644 index 0c184d30da550..0000000000000 --- a/aio/content/examples/bootstrapping/src/app/item.directive.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ItemDirective } from './item.directive'; - -describe('ItemDirective', () => { - it('should create an instance', () => { - const directive = new ItemDirective(); - expect(directive).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/built-in-directives/src/app/item-detail/item-detail.component.spec.ts b/aio/content/examples/built-in-directives/src/app/item-detail/item-detail.component.spec.ts deleted file mode 100644 index 7559cb65f6d15..0000000000000 --- a/aio/content/examples/built-in-directives/src/app/item-detail/item-detail.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemDetailComponent } from './item-detail.component'; - -describe('ItemDetailComponent', () => { - let component: ItemDetailComponent; - let fixture: ComponentFixture<ItemDetailComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemDetailComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/built-in-template-functions/src/app/app.component.spec.ts b/aio/content/examples/built-in-template-functions/src/app/app.component.spec.ts deleted file mode 100644 index f28fb061be0f1..0000000000000 --- a/aio/content/examples/built-in-template-functions/src/app/app.component.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/event-binding/src/app/app.component.spec.ts b/aio/content/examples/event-binding/src/app/app.component.spec.ts deleted file mode 100644 index 70abd5114b1be..0000000000000 --- a/aio/content/examples/event-binding/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'Featured product:'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('Featured product:'); - })); - it('should render title in a p tag', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('p').textContent).toContain('Featured product:'); - })); -}); diff --git a/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts b/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts deleted file mode 100644 index 7559cb65f6d15..0000000000000 --- a/aio/content/examples/event-binding/src/app/item-detail/item-detail.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemDetailComponent } from './item-detail.component'; - -describe('ItemDetailComponent', () => { - let component: ItemDetailComponent; - let fixture: ComponentFixture<ItemDetailComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemDetailComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/feature-modules/src/app/app.component.spec.ts b/aio/content/examples/feature-modules/src/app/app.component.spec.ts deleted file mode 100644 index 0e3504562b3ce..0000000000000 --- a/aio/content/examples/feature-modules/src/app/app.component.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }); - TestBed.compileComponents(); - }); - - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - - it(`should have as title 'app works!'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app works!'); - })); - - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('app works!'); - })); -}); diff --git a/aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts b/aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts deleted file mode 100644 index 2420d05521314..0000000000000 --- a/aio/content/examples/feature-modules/src/app/customer-dashboard/customer-dashboard/customer-dashboard.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CustomerDashboardComponent } from './customer-dashboard.component'; - -describe('CustomerDashboardComponent', () => { - let component: CustomerDashboardComponent; - let fixture: ComponentFixture<CustomerDashboardComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ CustomerDashboardComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(CustomerDashboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/forms-overview/example-config.json b/aio/content/examples/forms-overview/example-config.json index e69de29bb2d1d..a3fb39d2be439 100644 --- a/aio/content/examples/forms-overview/example-config.json +++ b/aio/content/examples/forms-overview/example-config.json @@ -0,0 +1,6 @@ +{ + "e2e": [ + {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, + {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} + ] +} diff --git a/aio/content/examples/forms-overview/src/app/reactive/reactive.module.spec.ts b/aio/content/examples/forms-overview/src/app/reactive/reactive.module.spec.ts deleted file mode 100644 index 3add422b837f8..0000000000000 --- a/aio/content/examples/forms-overview/src/app/reactive/reactive.module.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ReactiveModule } from './reactive.module'; - -describe('ReactiveModule', () => { - let reactiveModule: ReactiveModule; - - beforeEach(() => { - reactiveModule = new ReactiveModule(); - }); - - it('should create an instance', () => { - expect(reactiveModule).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/forms-overview/src/app/template/template.module.spec.ts b/aio/content/examples/forms-overview/src/app/template/template.module.spec.ts deleted file mode 100644 index cb28c36acd91e..0000000000000 --- a/aio/content/examples/forms-overview/src/app/template/template.module.spec.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { TemplateModule } from './template.module'; - -describe('TemplateModule', () => { - let templateModule: TemplateModule; - - beforeEach(() => { - templateModule = new TemplateModule(); - }); - - it('should create an instance', () => { - expect(templateModule).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/http/example-config.json b/aio/content/examples/http/example-config.json index 317e9458f3dbd..f6afa36536eb6 100644 --- a/aio/content/examples/http/example-config.json +++ b/aio/content/examples/http/example-config.json @@ -1,3 +1,7 @@ { - "projectType": "testing" + "projectType": "testing", + "e2e": [ + {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, + {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} + ] } diff --git a/aio/content/examples/inputs-outputs/src/app/aliasing/aliasing.component.spec.ts b/aio/content/examples/inputs-outputs/src/app/aliasing/aliasing.component.spec.ts deleted file mode 100644 index 8f93c989bc148..0000000000000 --- a/aio/content/examples/inputs-outputs/src/app/aliasing/aliasing.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AliasingComponent } from './aliasing.component'; - -describe('AliasingComponent', () => { - let component: AliasingComponent; - let fixture: ComponentFixture<AliasingComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AliasingComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AliasingComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/inputs-outputs/src/app/app.component.spec.ts b/aio/content/examples/inputs-outputs/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/inputs-outputs/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.spec.ts b/aio/content/examples/inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.spec.ts deleted file mode 100644 index eaa33528a97a2..0000000000000 --- a/aio/content/examples/inputs-outputs/src/app/in-the-metadata/in-the-metadata.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InTheMetadataComponent } from './in-the-metadata.component'; - -describe('InTheMetadataComponent', () => { - let component: InTheMetadataComponent; - let fixture: ComponentFixture<InTheMetadataComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ InTheMetadataComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(InTheMetadataComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/inputs-outputs/src/app/input-output/input-output.component.spec.ts b/aio/content/examples/inputs-outputs/src/app/input-output/input-output.component.spec.ts deleted file mode 100644 index 7e49af8ac459b..0000000000000 --- a/aio/content/examples/inputs-outputs/src/app/input-output/input-output.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InputOutputComponent } from './input-output.component'; - -describe('InputOutputComponent', () => { - let component: InputOutputComponent; - let fixture: ComponentFixture<InputOutputComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ InputOutputComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(InputOutputComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/inputs-outputs/src/app/item-detail/item-detail.component.spec.ts b/aio/content/examples/inputs-outputs/src/app/item-detail/item-detail.component.spec.ts deleted file mode 100644 index 7559cb65f6d15..0000000000000 --- a/aio/content/examples/inputs-outputs/src/app/item-detail/item-detail.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemDetailComponent } from './item-detail.component'; - -describe('ItemDetailComponent', () => { - let component: ItemDetailComponent; - let fixture: ComponentFixture<ItemDetailComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemDetailComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/inputs-outputs/src/app/item-output/item-output.component.spec.ts b/aio/content/examples/inputs-outputs/src/app/item-output/item-output.component.spec.ts deleted file mode 100644 index c3074913527e3..0000000000000 --- a/aio/content/examples/inputs-outputs/src/app/item-output/item-output.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemOutputComponent } from './item-output.component'; - -describe('ItemOutputComponent', () => { - let component: ItemOutputComponent; - let fixture: ComponentFixture<ItemOutputComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemOutputComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemOutputComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/interpolation/src/app/app.component.spec.ts b/aio/content/examples/interpolation/src/app/app.component.spec.ts deleted file mode 100644 index f28fb061be0f1..0000000000000 --- a/aio/content/examples/interpolation/src/app/app.component.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/lazy-loading-ngmodules/src/app/app.component.spec.ts b/aio/content/examples/lazy-loading-ngmodules/src/app/app.component.spec.ts deleted file mode 100644 index 37a8e88df0534..0000000000000 --- a/aio/content/examples/lazy-loading-ngmodules/src/app/app.component.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }); - TestBed.compileComponents(); - }); - - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - - it(`should have as title 'customer-app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('customer-app'); - })); - - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('customer-app'); - })); -}); diff --git a/aio/content/examples/lazy-loading-ngmodules/src/app/customers/customers.component.spec.ts b/aio/content/examples/lazy-loading-ngmodules/src/app/customers/customers.component.spec.ts deleted file mode 100644 index 1543c2d317554..0000000000000 --- a/aio/content/examples/lazy-loading-ngmodules/src/app/customers/customers.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { CustomersComponent } from './customers.component'; - -describe('CustomerListComponent', () => { - let component: CustomersComponent; - let fixture: ComponentFixture<CustomersComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ CustomersComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(CustomersComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/lazy-loading-ngmodules/src/app/orders/orders.component.spec.ts b/aio/content/examples/lazy-loading-ngmodules/src/app/orders/orders.component.spec.ts deleted file mode 100644 index bc78306cb04bc..0000000000000 --- a/aio/content/examples/lazy-loading-ngmodules/src/app/orders/orders.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { OrdersComponent } from './orders.component'; - -describe('OrderListComponent', () => { - let component: OrdersComponent; - let fixture: ComponentFixture<OrdersComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ OrdersComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(OrdersComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/ngmodules/src/app/app.component.spec.ts b/aio/content/examples/ngmodules/src/app/app.component.spec.ts deleted file mode 100644 index 0e3504562b3ce..0000000000000 --- a/aio/content/examples/ngmodules/src/app/app.component.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }); - TestBed.compileComponents(); - }); - - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - - it(`should have as title 'app works!'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app works!'); - })); - - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('app works!'); - })); -}); diff --git a/aio/content/examples/ngmodules/src/app/contact/contact.component.spec.ts b/aio/content/examples/ngmodules/src/app/contact/contact.component.spec.ts deleted file mode 100644 index 427633e0a0b85..0000000000000 --- a/aio/content/examples/ngmodules/src/app/contact/contact.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ContactComponent } from './contact.component'; - -describe('ContactComponent', () => { - let component: ContactComponent; - let fixture: ComponentFixture<ContactComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ContactComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ContactComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/ngmodules/src/app/items/items.component.spec.ts b/aio/content/examples/ngmodules/src/app/items/items.component.spec.ts deleted file mode 100644 index b77cce74ec477..0000000000000 --- a/aio/content/examples/ngmodules/src/app/items/items.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemsComponent } from './items.component'; - -describe('ItemsComponent', () => { - let component: ItemsComponent; - let fixture: ComponentFixture<ItemsComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/property-binding/src/app/app.component.spec.ts b/aio/content/examples/property-binding/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/property-binding/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts b/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts deleted file mode 100644 index 7559cb65f6d15..0000000000000 --- a/aio/content/examples/property-binding/src/app/item-detail/item-detail.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemDetailComponent } from './item-detail.component'; - -describe('ItemDetailComponent', () => { - let component: ItemDetailComponent; - let fixture: ComponentFixture<ItemDetailComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemDetailComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts b/aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts deleted file mode 100644 index e11a57d78cd9e..0000000000000 --- a/aio/content/examples/property-binding/src/app/item-list/item-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ItemListComponent } from './item-list.component'; - -describe('ItemListComponent', () => { - let component: ItemListComponent; - let fixture: ComponentFixture<ItemListComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ItemListComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ItemListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts b/aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts deleted file mode 100644 index 2c8e97ec821d2..0000000000000 --- a/aio/content/examples/property-binding/src/app/string-init/string-init.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { StringInitComponent } from './string-init.component'; - -describe('StringInitComponent', () => { - let component: StringInitComponent; - let fixture: ComponentFixture<StringInitComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ StringInitComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(StringInitComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/providers/src/app/app.component.spec.ts b/aio/content/examples/providers/src/app/app.component.spec.ts deleted file mode 100644 index 0e3504562b3ce..0000000000000 --- a/aio/content/examples/providers/src/app/app.component.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }); - TestBed.compileComponents(); - }); - - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - - it(`should have as title 'app works!'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app works!'); - })); - - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('app works!'); - })); -}); diff --git a/aio/content/examples/providers/src/app/user.service.spec.ts b/aio/content/examples/providers/src/app/user.service.spec.ts deleted file mode 100644 index dcf556571711f..0000000000000 --- a/aio/content/examples/providers/src/app/user.service.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; -import { UserService } from './user.service'; - -describe('UserService', () => { - beforeEach(() => { - TestBed.configureTestingModule({}); - }); - - it('should ...', inject([UserService], (service: UserService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/reactive-forms/src/app/app.component.spec.ts b/aio/content/examples/reactive-forms/src/app/app.component.spec.ts deleted file mode 100644 index 355989efcd19e..0000000000000 --- a/aio/content/examples/reactive-forms/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to reactive-forms!'); - })); -}); diff --git a/aio/content/examples/router/src/app/page-not-found/page-not-found.component.spec.ts b/aio/content/examples/router/src/app/page-not-found/page-not-found.component.spec.ts deleted file mode 100644 index 697a9465727a1..0000000000000 --- a/aio/content/examples/router/src/app/page-not-found/page-not-found.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { PageNotFoundComponent } from './page-not-found.component'; - -describe('PageNotFoundComponent', () => { - let component: PageNotFoundComponent; - let fixture: ComponentFixture<PageNotFoundComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ PageNotFoundComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(PageNotFoundComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/service-worker-getting-started/src/app/app.component.spec.ts b/aio/content/examples/service-worker-getting-started/src/app/app.component.spec.ts deleted file mode 100755 index b59df0cbc1d08..0000000000000 --- a/aio/content/examples/service-worker-getting-started/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('Service Workers'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to Service Workers!'); - })); -}); diff --git a/aio/content/examples/setup/example-config.json b/aio/content/examples/setup/example-config.json index e69de29bb2d1d..a3fb39d2be439 100644 --- a/aio/content/examples/setup/example-config.json +++ b/aio/content/examples/setup/example-config.json @@ -0,0 +1,6 @@ +{ + "e2e": [ + {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, + {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} + ] +} diff --git a/aio/content/examples/setup/src/app/app.component.spec.ts b/aio/content/examples/setup/src/app/app.component.spec.ts index 4998dec904895..eebc33ed8a879 100644 --- a/aio/content/examples/setup/src/app/app.component.spec.ts +++ b/aio/content/examples/setup/src/app/app.component.spec.ts @@ -1,10 +1,10 @@ import { AppComponent } from './app.component'; import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; +import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; -describe('AppComponent', function () { +describe('AppComponent', () => { let de: DebugElement; let comp: AppComponent; let fixture: ComponentFixture<AppComponent>; diff --git a/aio/content/examples/template-expression-operators/src/app/app.component.spec.ts b/aio/content/examples/template-expression-operators/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/template-expression-operators/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/template-reference-variables/src/app/app.component.spec.ts b/aio/content/examples/template-reference-variables/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/template-reference-variables/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/testing/example-config.json b/aio/content/examples/testing/example-config.json index 317e9458f3dbd..f6afa36536eb6 100644 --- a/aio/content/examples/testing/example-config.json +++ b/aio/content/examples/testing/example-config.json @@ -1,3 +1,7 @@ { - "projectType": "testing" + "projectType": "testing", + "e2e": [ + {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, + {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} + ] } diff --git a/aio/content/examples/testing/src/app/about/about.component.spec.ts b/aio/content/examples/testing/src/app/about/about.component.spec.ts index 80bebd99a7e72..0960de315c97f 100644 --- a/aio/content/examples/testing/src/app/about/about.component.spec.ts +++ b/aio/content/examples/testing/src/app/about/about.component.spec.ts @@ -10,7 +10,7 @@ describe('AboutComponent (highlightDirective)', () => { // #docregion tests beforeEach(() => { fixture = TestBed.configureTestingModule({ - declarations: [ AboutComponent, HighlightDirective], + declarations: [ AboutComponent, HighlightDirective ], schemas: [ NO_ERRORS_SCHEMA ] }) .createComponent(AboutComponent); diff --git a/aio/content/examples/testing/src/app/app-routing.module.ts b/aio/content/examples/testing/src/app/app-routing.module.ts index 97fa809ad9d34..937f6035c356b 100644 --- a/aio/content/examples/testing/src/app/app-routing.module.ts +++ b/aio/content/examples/testing/src/app/app-routing.module.ts @@ -1,16 +1,18 @@ -import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; import { AboutComponent } from './about/about.component'; +export const routes: Routes = [ + { path: '', redirectTo: 'dashboard', pathMatch: 'full'}, + { path: 'about', component: AboutComponent }, + { path: 'heroes', loadChildren: () => import('./hero/hero.module').then(m => m.HeroModule)}, +]; + @NgModule({ imports: [ - RouterModule.forRoot([ - { path: '', redirectTo: 'dashboard', pathMatch: 'full'}, - { path: 'about', component: AboutComponent }, - { path: 'heroes', loadChildren: () => import('./hero/hero.module').then(m => m.HeroModule)} - ]) + RouterModule.forRoot(routes), ], exports: [ RouterModule ] // re-export the module declarations }) -export class AppRoutingModule { }; +export class AppRoutingModule { } diff --git a/aio/content/examples/testing/src/app/app.component.router.spec.ts b/aio/content/examples/testing/src/app/app.component.router.spec.ts index df04f405fce18..6e183a3aad622 100644 --- a/aio/content/examples/testing/src/app/app.component.router.spec.ts +++ b/aio/content/examples/testing/src/app/app.component.router.spec.ts @@ -1,16 +1,13 @@ // For more examples: // https://github.com/angular/angular/blob/master/modules/@angular/router/test/integration.spec.ts -import { async, ComponentFixture, fakeAsync, TestBed, tick, -} from '@angular/core/testing'; +import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { asyncData } from '../testing'; import { RouterTestingModule } from '@angular/router/testing'; import { SpyLocation } from '@angular/common/testing'; -// r - for relatively obscure router symbols -import * as r from '@angular/router'; import { Router, RouterLinkWithHref } from '@angular/router'; import { By } from '@angular/platform-browser'; @@ -19,6 +16,7 @@ import { Location } from '@angular/common'; import { click } from '../testing'; +import { routes } from './app-routing.module'; import { AppModule } from './app.module'; import { AppComponent } from './app.component'; import { AboutComponent } from './about/about.component'; @@ -37,7 +35,10 @@ describe('AppComponent & RouterTestingModule', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ AppModule, RouterTestingModule ], + imports: [ + AppModule, + RouterTestingModule.withRoutes(routes), + ], providers: [ { provide: HeroService, useClass: TestHeroService } ] @@ -48,7 +49,7 @@ describe('AppComponent & RouterTestingModule', () => { it('should navigate to "Dashboard" immediately', fakeAsync(() => { createComponent(); tick(); // wait for async data to arrive - expect(location.path()).toEqual('/dashboard', 'after initialNavigation()'); + expectPathToBe('/dashboard', 'after initialNavigation()'); expectElementOf(DashboardComponent); })); @@ -96,14 +97,17 @@ xdescribe('AppComponent & Lazy Loading (not working yet)', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [ AppModule, RouterTestingModule ] + imports: [ + AppModule, + RouterTestingModule.withRoutes(routes), + ], }) .compileComponents(); })); beforeEach(fakeAsync(() => { createComponent(); - loader = TestBed.inject(NgModuleFactoryLoader); + loader = TestBed.inject(NgModuleFactoryLoader) as SpyNgModuleFactoryLoader; loader.stubbedModules = { expected: HeroModule }; router.resetConfig([{path: 'heroes', loadChildren: 'expected'}]); })); diff --git a/aio/content/examples/testing/src/app/app.module.ts b/aio/content/examples/testing/src/app/app.module.ts index aecf6ea5e279d..65f620dca7718 100644 --- a/aio/content/examples/testing/src/app/app.module.ts +++ b/aio/content/examples/testing/src/app/app.module.ts @@ -44,7 +44,8 @@ import { InMemoryDataService } from './in-memory-data.service'; AboutComponent, BannerComponent, TwainComponent, - WelcomeComponent ], + WelcomeComponent, + ], bootstrap: [ AppComponent ] }) export class AppModule { } diff --git a/aio/content/examples/testing/src/app/demo/demo.testbed.spec.ts b/aio/content/examples/testing/src/app/demo/demo.testbed.spec.ts index 2e7560444607d..c22391b16a8cf 100644 --- a/aio/content/examples/testing/src/app/demo/demo.testbed.spec.ts +++ b/aio/content/examples/testing/src/app/demo/demo.testbed.spec.ts @@ -110,7 +110,7 @@ describe('demo (with TestBed):', () => { }); // Inject both the service-to-test and its (spy) dependency masterService = TestBed.inject(MasterService); - valueServiceSpy = TestBed.inject(ValueService); + valueServiceSpy = TestBed.inject(ValueService) as jasmine.SpyObj<ValueService>; }); // #enddocregion master-service-before-each @@ -373,14 +373,14 @@ describe('demo (with TestBed):', () => { expect(el.context).toBe(childComp, 'context is the child component'); - expect(el.attributes['account']).toBe(childComp.id, 'account attribute'); - expect(el.attributes['bank']).toBe(childComp.bank, 'bank attribute'); + expect(el.attributes.account).toBe(childComp.id, 'account attribute'); + expect(el.attributes.bank).toBe(childComp.bank, 'bank attribute'); - expect(el.classes['closed']).toBe(true, 'closed class'); - expect(el.classes['open']).toBe(false, 'open class'); + expect(el.classes.closed).toBe(true, 'closed class'); + expect(el.classes.open).toBeFalsy('open class'); - expect(el.styles['color']).toBe(comp.color, 'color style'); - expect(el.styles['width']).toBe(comp.width + 'px', 'width style'); + expect(el.styles.color).toBe(comp.color, 'color style'); + expect(el.styles.width).toBe(comp.width + 'px', 'width style'); // #enddocregion dom-attributes // Removed on 12/02/2016 when ceased public discussion of the `Renderer`. Revive in future? diff --git a/aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts b/aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts index a85ca4be9912d..67ff86b1d304f 100644 --- a/aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts +++ b/aio/content/examples/testing/src/app/welcome/welcome.component.spec.ts @@ -58,7 +58,7 @@ describe('WelcomeComponent', () => { let el: HTMLElement; // the DOM element with the welcome message // #docregion setup, user-service-stub - let userServiceStub: Partial<UserService>; + let userServiceStub: Partial<UserService>; // #enddocregion user-service-stub beforeEach(() => { @@ -66,7 +66,7 @@ describe('WelcomeComponent', () => { // #docregion user-service-stub userServiceStub = { isLoggedIn: true, - user: { name: 'Test User'} + user: { name: 'Test User' }, }; // #enddocregion user-service-stub @@ -74,10 +74,10 @@ describe('WelcomeComponent', () => { TestBed.configureTestingModule({ declarations: [ WelcomeComponent ], // #enddocregion setup - // providers: [ UserService ] // NO! Don't provide the real service! - // Provide a test-double instead + // providers: [ UserService ], // NO! Don't provide the real service! + // Provide a test-double instead // #docregion setup - providers: [ {provide: UserService, useValue: userServiceStub } ] + providers: [ { provide: UserService, useValue: userServiceStub } ], }); // #enddocregion config-test-module @@ -85,7 +85,7 @@ describe('WelcomeComponent', () => { comp = fixture.componentInstance; // #enddocregion setup - // #docregion injected-service + // #docregion injected-service // UserService actually injected into the component userService = fixture.debugElement.injector.get(UserService); // #enddocregion injected-service @@ -132,14 +132,4 @@ describe('WelcomeComponent', () => { it('TestBed and Component UserService should be the same', () => { expect(userService === componentUserService).toBe(true); }); - - // #docregion stub-not-injected - it('stub object and injected UserService should not be the same', () => { - expect(userServiceStub === userService).toBe(false); - - // Changing the stub object has no effect on the injected service - userServiceStub.isLoggedIn = false; - expect(userService.isLoggedIn).toBe(true); - }); - // #enddocregion stub-not-injected }); diff --git a/aio/content/examples/testing/src/app/welcome/welcome.component.ts b/aio/content/examples/testing/src/app/welcome/welcome.component.ts index 802f30cc4a12b..5eff2cd9fb672 100644 --- a/aio/content/examples/testing/src/app/welcome/welcome.component.ts +++ b/aio/content/examples/testing/src/app/welcome/welcome.component.ts @@ -1,6 +1,6 @@ // #docregion import { Component, OnInit } from '@angular/core'; -import { UserService } from '../model/user.service'; +import { UserService } from '../model/user.service'; // #docregion component @Component({ @@ -8,7 +8,7 @@ import { UserService } from '../model/user.service'; template: '<h3 class="welcome"><i>{{welcome}}</i></h3>' }) // #docregion class -export class WelcomeComponent implements OnInit { +export class WelcomeComponent implements OnInit { welcome: string; constructor(private userService: UserService) { } diff --git a/aio/content/examples/testing/src/tests.sb.ts b/aio/content/examples/testing/src/tests.sb.ts index 2cb3b440f6568..8c3e9ae454c3b 100644 --- a/aio/content/examples/testing/src/tests.sb.ts +++ b/aio/content/examples/testing/src/tests.sb.ts @@ -18,6 +18,7 @@ import './app/hero/hero-detail.component.spec.ts'; import './app/hero/hero-list.component.spec.ts'; import './app/model/hero.service.spec.ts'; import './app/model/testing/http-client.spec.ts'; +import './app/shared/canvas.component.spec.ts'; import './app/shared/highlight.directive.spec.ts'; import './app/shared/title-case.pipe.spec.ts'; import './app/twain/twain.component.spec.ts'; diff --git a/aio/content/examples/toh-pt0/src/app/app.component.spec.ts b/aio/content/examples/toh-pt0/src/app/app.component.spec.ts deleted file mode 100644 index 8ea1e2a3e1c6c..0000000000000 --- a/aio/content/examples/toh-pt0/src/app/app.component.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; - -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 9c3b1c4d9f779..0000000000000 --- a/aio/content/examples/toh-pt1/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroesComponent } from './heroes.component'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 9c3b1c4d9f779..0000000000000 --- a/aio/content/examples/toh-pt2/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroesComponent } from './heroes.component'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 9c3b1c4d9f779..0000000000000 --- a/aio/content/examples/toh-pt3/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroesComponent } from './heroes.component'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 9c3b1c4d9f779..0000000000000 --- a/aio/content/examples/toh-pt4/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroesComponent } from './heroes.component'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt4/src/app/message.service.spec.ts b/aio/content/examples/toh-pt4/src/app/message.service.spec.ts deleted file mode 100644 index 63ecfd8ff6292..0000000000000 --- a/aio/content/examples/toh-pt4/src/app/message.service.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { MessageService } from './message.service'; - -describe('MessageService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [MessageService] - }); - }); - - it('should be created', inject([MessageService], (service: MessageService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts b/aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts deleted file mode 100644 index 3c2b2b15372cc..0000000000000 --- a/aio/content/examples/toh-pt4/src/app/messages/messages.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MessagesComponent } from './messages.component'; - -describe('MessagesComponent', () => { - let component: MessagesComponent; - let fixture: ComponentFixture<MessagesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MessagesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MessagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts b/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts deleted file mode 100644 index fea6bfb4dbe7e..0000000000000 --- a/aio/content/examples/toh-pt5/src/app/dashboard/dashboard.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DashboardComponent } from './dashboard.component'; - -describe('DashboardComponent', () => { - let component: DashboardComponent; - let fixture: ComponentFixture<DashboardComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ DashboardComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DashboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 9c3b1c4d9f779..0000000000000 --- a/aio/content/examples/toh-pt5/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroesComponent } from './heroes.component'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt5/src/app/message.service.spec.ts b/aio/content/examples/toh-pt5/src/app/message.service.spec.ts deleted file mode 100644 index 63ecfd8ff6292..0000000000000 --- a/aio/content/examples/toh-pt5/src/app/message.service.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { MessageService } from './message.service'; - -describe('MessageService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [MessageService] - }); - }); - - it('should be created', inject([MessageService], (service: MessageService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts b/aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts deleted file mode 100644 index 3c2b2b15372cc..0000000000000 --- a/aio/content/examples/toh-pt5/src/app/messages/messages.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MessagesComponent } from './messages.component'; - -describe('MessagesComponent', () => { - let component: MessagesComponent; - let fixture: ComponentFixture<MessagesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MessagesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MessagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt6/example-config.json b/aio/content/examples/toh-pt6/example-config.json index e69de29bb2d1d..a3fb39d2be439 100644 --- a/aio/content/examples/toh-pt6/example-config.json +++ b/aio/content/examples/toh-pt6/example-config.json @@ -0,0 +1,6 @@ +{ + "e2e": [ + {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, + {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} + ] +} diff --git a/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts b/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts deleted file mode 100644 index 8414f1c223a3b..0000000000000 --- a/aio/content/examples/toh-pt6/src/app/hero-search/hero-search.component.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; - -import { HeroSearchComponent } from './hero-search.component'; - - -describe('HeroSearchComponent', () => { - let component: HeroSearchComponent; - let fixture: ComponentFixture<HeroSearchComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroSearchComponent ], - imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroSearchComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 6991d6901058b..0000000000000 --- a/aio/content/examples/toh-pt6/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { HeroesComponent } from './heroes.component'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ], - imports: [RouterTestingModule.withRoutes([]), HttpClientTestingModule], - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/toh-pt6/src/app/message.service.spec.ts b/aio/content/examples/toh-pt6/src/app/message.service.spec.ts deleted file mode 100644 index 63ecfd8ff6292..0000000000000 --- a/aio/content/examples/toh-pt6/src/app/message.service.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { MessageService } from './message.service'; - -describe('MessageService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [MessageService] - }); - }); - - it('should be created', inject([MessageService], (service: MessageService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts b/aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts deleted file mode 100644 index 3c2b2b15372cc..0000000000000 --- a/aio/content/examples/toh-pt6/src/app/messages/messages.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MessagesComponent } from './messages.component'; - -describe('MessagesComponent', () => { - let component: MessagesComponent; - let fixture: ComponentFixture<MessagesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MessagesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MessagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/two-way-binding/src/app/app.component.spec.ts b/aio/content/examples/two-way-binding/src/app/app.component.spec.ts deleted file mode 100644 index 1f327e657486c..0000000000000 --- a/aio/content/examples/two-way-binding/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - it('should create the app', async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - })); - it(`should have as title 'app'`, async(() => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('app'); - })); - it('should render title', async(() => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!'); - })); -}); diff --git a/aio/content/examples/two-way-binding/src/app/sizer/sizer.component.spec.ts b/aio/content/examples/two-way-binding/src/app/sizer/sizer.component.spec.ts deleted file mode 100644 index 3c3a3ada0522b..0000000000000 --- a/aio/content/examples/two-way-binding/src/app/sizer/sizer.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SizerComponent } from './sizer.component'; - -describe('SizerComponent', () => { - let component: SizerComponent; - let fixture: ComponentFixture<SizerComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ SizerComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(SizerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/universal/src/app/dashboard/dashboard.component.spec.ts b/aio/content/examples/universal/src/app/dashboard/dashboard.component.spec.ts deleted file mode 100644 index fea6bfb4dbe7e..0000000000000 --- a/aio/content/examples/universal/src/app/dashboard/dashboard.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { DashboardComponent } from './dashboard.component'; - -describe('DashboardComponent', () => { - let component: DashboardComponent; - let fixture: ComponentFixture<DashboardComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ DashboardComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(DashboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/universal/src/app/hero-search/hero-search.component.spec.ts b/aio/content/examples/universal/src/app/hero-search/hero-search.component.spec.ts deleted file mode 100644 index 901bb7f2ab657..0000000000000 --- a/aio/content/examples/universal/src/app/hero-search/hero-search.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroSearchComponent } from './hero-search.component'; - -describe('HeroSearchComponent', () => { - let component: HeroSearchComponent; - let fixture: ComponentFixture<HeroSearchComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroSearchComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroSearchComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/universal/src/app/heroes/heroes.component.spec.ts b/aio/content/examples/universal/src/app/heroes/heroes.component.spec.ts deleted file mode 100644 index 9c3b1c4d9f779..0000000000000 --- a/aio/content/examples/universal/src/app/heroes/heroes.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroesComponent } from './heroes.component'; - -describe('HeroesComponent', () => { - let component: HeroesComponent; - let fixture: ComponentFixture<HeroesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ HeroesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(HeroesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/universal/src/app/message.service.spec.ts b/aio/content/examples/universal/src/app/message.service.spec.ts deleted file mode 100644 index 63ecfd8ff6292..0000000000000 --- a/aio/content/examples/universal/src/app/message.service.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { TestBed, inject } from '@angular/core/testing'; - -import { MessageService } from './message.service'; - -describe('MessageService', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [MessageService] - }); - }); - - it('should be created', inject([MessageService], (service: MessageService) => { - expect(service).toBeTruthy(); - })); -}); diff --git a/aio/content/examples/universal/src/app/messages/messages.component.spec.ts b/aio/content/examples/universal/src/app/messages/messages.component.spec.ts deleted file mode 100644 index 3c2b2b15372cc..0000000000000 --- a/aio/content/examples/universal/src/app/messages/messages.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MessagesComponent } from './messages.component'; - -describe('MessagesComponent', () => { - let component: MessagesComponent; - let fixture: ComponentFixture<MessagesComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MessagesComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MessagesComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should be created', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/aio/content/examples/upgrade-phonecat-3-final/README.md b/aio/content/examples/upgrade-phonecat-3-final/README.md index 7448da44e62d9..83d1f4a7c4163 100644 --- a/aio/content/examples/upgrade-phonecat-3-final/README.md +++ b/aio/content/examples/upgrade-phonecat-3-final/README.md @@ -3,9 +3,6 @@ structure. The following changes from vanilla Phonecat are applied: -* Karma config for unit tests is in karma.conf.ng1.js because the boilerplate - Karma config is not compatible with the way tests in this project need to be run. - The shell script run-unit-tests.sh can be used to run the unit tests. * E2E tests have been moved to the parent directory, where `run-e2e-tests` can discover and run them along with all the other examples. * Most of the phone JSON and image data removed in the interest of keeping diff --git a/aio/content/examples/upgrade-phonecat-3-final/run-unit-tests.sh b/aio/content/examples/upgrade-phonecat-3-final/run-unit-tests.sh deleted file mode 100644 index d90e45c2e944c..0000000000000 --- a/aio/content/examples/upgrade-phonecat-3-final/run-unit-tests.sh +++ /dev/null @@ -1,6 +0,0 @@ -## The boilerplate Karma configuration won't work with AngularJS tests -## which require their own special loading configuration, `karma.conf.ng1.js`. -## This scripts runs the AngularJS tests with that AngularJS config. - -PATH=$(npm bin):$PATH -tsc && karma start karma.conf.ng1.js diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index 6d5a2ef7ebf73..9052d2513be33 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -1103,18 +1103,6 @@ explains when and why you must get the service from the component's injector ins </div> -{@a service-from-injector} - -#### Always get the service from an injector - -Do _not_ reference the `userServiceStub` object -that's provided to the testing module in the body of your test. -**It does not work!** -The `userService` instance injected into the component is a completely _different_ object, -a clone of the provided `userServiceStub`. - -<code-example path="testing/src/app/welcome/welcome.component.spec.ts" region="stub-not-injected" header="app/welcome/welcome.component.spec.ts"></code-example> - {@a welcome-spec-setup} #### Final setup and tests diff --git a/aio/tools/examples/run-example-e2e.js b/aio/tools/examples/run-example-e2e.js index 2213a5c4545d3..0c202226d5ada 100644 --- a/aio/tools/examples/run-example-e2e.js +++ b/aio/tools/examples/run-example-e2e.js @@ -9,6 +9,9 @@ const findFreePort = require('find-free-port'); shelljs.set('-e'); +// Set `CHROME_BIN` as an environment variable for Karma to pick up in unit tests. +process.env.CHROME_BIN = require('puppeteer').executablePath(); + const AIO_PATH = path.join(__dirname, '../../'); const SHARED_PATH = path.join(__dirname, '/shared'); const EXAMPLES_PATH = path.join(AIO_PATH, './content/examples/'); From 4c5e085c937b374ea2ee57d86a7ecd0acd7bba5f Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Mon, 23 Mar 2020 17:31:56 +0200 Subject: [PATCH 123/262] build(docs-infra): update docs examples `package.json` templates wrt `core-js` (#36143) The `core-js` dependency is no longer included in `package.json` for `cli`-type examples, but only for the `systemjs` ones. This commit updates the `package.json` templates to reflect that (and also updates the `npm-packages` guide accordingly). PR Close #36143 --- aio/content/guide/npm-packages.md | 3 --- aio/tools/example-zipper/customizer/package-json/base.json | 1 - aio/tools/example-zipper/customizer/package-json/systemjs.json | 1 + aio/tools/examples/shared/boilerplate/systemjs/package.json | 1 + 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/aio/content/guide/npm-packages.md b/aio/content/guide/npm-packages.md index d8296bdc0b76b..a9ed9618c4884 100644 --- a/aio/content/guide/npm-packages.md +++ b/aio/content/guide/npm-packages.md @@ -93,9 +93,6 @@ features that Angular requires. The [Browser Support](guide/browser-support) guide explains which browsers need polyfills and how you can add them. -The `package.json` for a new Angular workspace installs the [core-js](https://github.com/zloirock/core-js) package, -which polyfills missing features for several popular browser. - {@a dev-dependencies} diff --git a/aio/tools/example-zipper/customizer/package-json/base.json b/aio/tools/example-zipper/customizer/package-json/base.json index d585295bc23ff..f4b452fdc55ee 100644 --- a/aio/tools/example-zipper/customizer/package-json/base.json +++ b/aio/tools/example-zipper/customizer/package-json/base.json @@ -13,7 +13,6 @@ "@angular/router", "@angular/upgrade", "angular-in-memory-web-api", - "core-js", "rxjs", "zone.js" ], diff --git a/aio/tools/example-zipper/customizer/package-json/systemjs.json b/aio/tools/example-zipper/customizer/package-json/systemjs.json index 3d81cba99e3a7..3deb16df0295a 100644 --- a/aio/tools/example-zipper/customizer/package-json/systemjs.json +++ b/aio/tools/example-zipper/customizer/package-json/systemjs.json @@ -25,6 +25,7 @@ "@angular/platform-browser-dynamic", "@angular/router", "@angular/upgrade", + "core-js", "rxjs", "systemjs", "tslib", diff --git a/aio/tools/examples/shared/boilerplate/systemjs/package.json b/aio/tools/examples/shared/boilerplate/systemjs/package.json index 8bee75863e913..c9927b1c7cc0e 100644 --- a/aio/tools/examples/shared/boilerplate/systemjs/package.json +++ b/aio/tools/examples/shared/boilerplate/systemjs/package.json @@ -38,6 +38,7 @@ "@angular/platform-browser-dynamic": "~9.0.3", "@angular/router": "~9.0.3", "@angular/upgrade": "~9.0.3", + "core-js": "^2.5.4", "rxjs": "~6.5.4", "tslib": "^1.10.0", "zone.js": "~0.10.3" From 8660806ddc247d2ec48f60e741c1bfe409096728 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Mon, 23 Mar 2020 17:31:56 +0200 Subject: [PATCH 124/262] build(docs-infra): renamed `e2e` property of `example-config.json` to `tests` (#36143) Each docs example has an `example-config.json` configuration file. Among other things, this file can be used to specify what commands to run in order to test the example. (If not specified, the `run-example-e2e.js` script will run a default `yarn e2e` command.) Previously, the property specifying the test commands was called `e2e`. This is because in the past only e2e tests were run for docs examples. Since recently, some examples may specify commands for other types of tests (such as unit tests). Therefore, calling the property that holds the list of test commands `e2e` no longer makes sense and can be misleading to people looking at the configuration files. This commit renamed the property to the more generic `tests`. In the future, the `run-example-e2e.js` script (and corresponding npm script) should be renamed and refactored to also avoid giving the impression that only e2e tests are run. Discussed in: https://github.com/angular/angular/pull/36143#discussion_r395148379 PR Close #36143 --- .../examples/component-interaction/example-config.json | 2 +- aio/content/examples/forms-overview/example-config.json | 2 +- aio/content/examples/http/example-config.json | 2 +- aio/content/examples/i18n/example-config.json | 2 +- .../examples/observables-in-angular/example-config.json | 2 +- aio/content/examples/observables/example-config.json | 2 +- .../examples/practical-observable-usage/example-config.json | 2 +- aio/content/examples/rx-library/example-config.json | 2 +- .../service-worker-getting-started/example-config.json | 2 +- aio/content/examples/setup/example-config.json | 2 +- aio/content/examples/testing/example-config.json | 2 +- aio/content/examples/toh-pt6/example-config.json | 2 +- aio/tools/examples/run-example-e2e.js | 4 ++-- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/aio/content/examples/component-interaction/example-config.json b/aio/content/examples/component-interaction/example-config.json index d56f4ce8b0d03..05e262817d211 100644 --- a/aio/content/examples/component-interaction/example-config.json +++ b/aio/content/examples/component-interaction/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ { "cmd": "yarn", "args": [ diff --git a/aio/content/examples/forms-overview/example-config.json b/aio/content/examples/forms-overview/example-config.json index a3fb39d2be439..5f2a94dfa8cc6 100644 --- a/aio/content/examples/forms-overview/example-config.json +++ b/aio/content/examples/forms-overview/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} ] diff --git a/aio/content/examples/http/example-config.json b/aio/content/examples/http/example-config.json index f6afa36536eb6..f000fdf0b14a8 100644 --- a/aio/content/examples/http/example-config.json +++ b/aio/content/examples/http/example-config.json @@ -1,6 +1,6 @@ { "projectType": "testing", - "e2e": [ + "tests": [ {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} ] diff --git a/aio/content/examples/i18n/example-config.json b/aio/content/examples/i18n/example-config.json index 408f4c2d0c679..4ff904f87578a 100644 --- a/aio/content/examples/i18n/example-config.json +++ b/aio/content/examples/i18n/example-config.json @@ -1,6 +1,6 @@ { "projectType": "i18n", - "e2e": [ + "tests": [ { "cmd": "yarn", "args": [ diff --git a/aio/content/examples/observables-in-angular/example-config.json b/aio/content/examples/observables-in-angular/example-config.json index f2b127257b88b..c07fa9794c5b5 100644 --- a/aio/content/examples/observables-in-angular/example-config.json +++ b/aio/content/examples/observables-in-angular/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ { "cmd": "yarn", "args": [ "tsc", "--project", "./tsconfig.app.json" ] diff --git a/aio/content/examples/observables/example-config.json b/aio/content/examples/observables/example-config.json index f2b127257b88b..c07fa9794c5b5 100644 --- a/aio/content/examples/observables/example-config.json +++ b/aio/content/examples/observables/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ { "cmd": "yarn", "args": [ "tsc", "--project", "./tsconfig.app.json" ] diff --git a/aio/content/examples/practical-observable-usage/example-config.json b/aio/content/examples/practical-observable-usage/example-config.json index f2b127257b88b..c07fa9794c5b5 100644 --- a/aio/content/examples/practical-observable-usage/example-config.json +++ b/aio/content/examples/practical-observable-usage/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ { "cmd": "yarn", "args": [ "tsc", "--project", "./tsconfig.app.json" ] diff --git a/aio/content/examples/rx-library/example-config.json b/aio/content/examples/rx-library/example-config.json index f2b127257b88b..c07fa9794c5b5 100644 --- a/aio/content/examples/rx-library/example-config.json +++ b/aio/content/examples/rx-library/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ { "cmd": "yarn", "args": [ "tsc", "--project", "./tsconfig.app.json" ] diff --git a/aio/content/examples/service-worker-getting-started/example-config.json b/aio/content/examples/service-worker-getting-started/example-config.json index f6a1e8b458409..ad715b0711530 100644 --- a/aio/content/examples/service-worker-getting-started/example-config.json +++ b/aio/content/examples/service-worker-getting-started/example-config.json @@ -1,6 +1,6 @@ { "projectType": "service-worker", - "e2e": [ + "tests": [ {"cmd": "yarn", "args": ["e2e", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]}, {"cmd": "yarn", "args": ["build", "--prod"]}, {"cmd": "node", "args": ["--eval", "assert(fs.existsSync('./dist/ngsw.json'), 'ngsw.json is missing')"]}, diff --git a/aio/content/examples/setup/example-config.json b/aio/content/examples/setup/example-config.json index a3fb39d2be439..5f2a94dfa8cc6 100644 --- a/aio/content/examples/setup/example-config.json +++ b/aio/content/examples/setup/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} ] diff --git a/aio/content/examples/testing/example-config.json b/aio/content/examples/testing/example-config.json index f6afa36536eb6..f000fdf0b14a8 100644 --- a/aio/content/examples/testing/example-config.json +++ b/aio/content/examples/testing/example-config.json @@ -1,6 +1,6 @@ { "projectType": "testing", - "e2e": [ + "tests": [ {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} ] diff --git a/aio/content/examples/toh-pt6/example-config.json b/aio/content/examples/toh-pt6/example-config.json index a3fb39d2be439..5f2a94dfa8cc6 100644 --- a/aio/content/examples/toh-pt6/example-config.json +++ b/aio/content/examples/toh-pt6/example-config.json @@ -1,5 +1,5 @@ { - "e2e": [ + "tests": [ {"cmd": "yarn", "args": ["test", "--browsers=ChromeHeadless", "--no-watch"]}, {"cmd": "yarn", "args": ["e2e", "--prod", "--protractor-config=e2e/protractor-puppeteer.conf.js", "--no-webdriver-update", "--port={PORT}"]} ] diff --git a/aio/tools/examples/run-example-e2e.js b/aio/tools/examples/run-example-e2e.js index 0c202226d5ada..d3bef175847cb 100644 --- a/aio/tools/examples/run-example-e2e.js +++ b/aio/tools/examples/run-example-e2e.js @@ -265,7 +265,7 @@ function runE2eTestsCLI(appDir, outputFile, bufferOutput, port) { // `--no-webdriver-update` is needed to preserve the ChromeDriver version already installed. const config = loadExampleConfig(appDir); - const commands = config.e2e || [{ + const testCommands = config.tests || [{ cmd: 'yarn', args: [ 'e2e', @@ -277,7 +277,7 @@ function runE2eTestsCLI(appDir, outputFile, bufferOutput, port) { }]; let bufferedOutput = `\n\n============== AIO example output for: ${appDir}\n\n`; - const e2eSpawnPromise = commands.reduce((prevSpawnPromise, {cmd, args}) => { + const e2eSpawnPromise = testCommands.reduce((prevSpawnPromise, {cmd, args}) => { // Replace the port placeholder with the specified port if present. Specs that // define their e2e test commands in the example config are able to use the // given available port. This ensures that the CLI tests can be run concurrently. From eb8c6c7eff0fad5f427c16d2b809141b8b63b118 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@umich.edu> Date: Thu, 2 Apr 2020 21:48:16 -0700 Subject: [PATCH 125/262] test(language-service): Move pipe tests to TEST_TEMPLATE (#36407) This commit simplifies the completion tests for pipes by moving them to TEST_TEMPLATE. PR Close #36407 --- .../language-service/test/completions_spec.ts | 27 ++++++++++--------- .../test/project/app/expression-cases.ts | 7 ----- .../language-service/test/project/app/main.ts | 4 +-- .../test/project/app/parsing-cases.ts | 9 +------ .../test/typescript_host_spec.ts | 2 +- 5 files changed, 18 insertions(+), 31 deletions(-) diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index 9e12a5db67938..0bf3e4238e8c6 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -469,21 +469,24 @@ describe('completions', () => { describe('for pipes', () => { it('should be able to get a list of pipe values', () => { - for (const location of ['before-pipe', 'in-pipe', 'after-pipe']) { - const marker = mockHost.getLocationMarkerFor(PARSING_CASES, location); - const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); - expectContain(completions, CompletionKind.PIPE, [ - 'async', - 'uppercase', - 'lowercase', - 'titlecase', - ]); - } + // TODO(kyliau): does not work for case {{ title | ~{cursor} }} + // space before and after pipe ^^^ + mockHost.override(TEST_TEMPLATE, `{{ title|~{cursor} }}`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.PIPE, [ + 'async', + 'lowercase', + 'slice', + 'titlecase', + 'uppercase', + ]); }); it('should be able to resolve lowercase', () => { - const marker = mockHost.getLocationMarkerFor(EXPRESSION_CASES, 'string-pipe'); - const completions = ngLS.getCompletionsAtPosition(EXPRESSION_CASES, marker.start); + mockHost.override(TEST_TEMPLATE, `{{ (title | lowercase).~{cursor} }}`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.METHOD, [ 'charAt', 'replace', diff --git a/packages/language-service/test/project/app/expression-cases.ts b/packages/language-service/test/project/app/expression-cases.ts index decc717a62baf..b8ebc80194bc9 100644 --- a/packages/language-service/test/project/app/expression-cases.ts +++ b/packages/language-service/test/project/app/expression-cases.ts @@ -39,10 +39,3 @@ export class PrivateReference { }) export class ExpectNumericType { } - -@Component({ - template: '{{ (name | lowercase).~{string-pipe}substring }}', -}) -export class LowercasePipe { - name: string = 'name'; -} diff --git a/packages/language-service/test/project/app/main.ts b/packages/language-service/test/project/app/main.ts index daa4ef3c0bd5b..edd01e1289fe3 100644 --- a/packages/language-service/test/project/app/main.ts +++ b/packages/language-service/test/project/app/main.ts @@ -21,7 +21,6 @@ import * as ParsingCases from './parsing-cases'; declarations: [ AppComponent, ExpressionCases.ExpectNumericType, - ExpressionCases.LowercasePipe, ExpressionCases.PrivateReference, ExpressionCases.WrongFieldReference, ExpressionCases.WrongSubFieldReference, @@ -38,7 +37,6 @@ import * as ParsingCases from './parsing-cases'; ParsingCases.HintModel, ParsingCases.NoValueAttribute, ParsingCases.NumberModel, - ParsingCases.Pipes, ParsingCases.References, ParsingCases.StringModel, ParsingCases.TemplateReference, @@ -51,4 +49,4 @@ export class AppModule { declare function bootstrap(v: any): void; - bootstrap(AppComponent); +bootstrap(AppComponent); diff --git a/packages/language-service/test/project/app/parsing-cases.ts b/packages/language-service/test/project/app/parsing-cases.ts index 3239e008cf836..3158b8a2154fe 100644 --- a/packages/language-service/test/project/app/parsing-cases.ts +++ b/packages/language-service/test/project/app/parsing-cases.ts @@ -31,13 +31,6 @@ export class CaseMissingClosing { export class CaseUnknown { } -@Component({ - template: '<h1>{{data | ~{before-pipe}lowe~{in-pipe}rcase~{after-pipe} }}', -}) -export class Pipes { - data = 'Some string'; -} - @Component({ template: '<h1 h~{no-value-attribute}></h1>', }) @@ -175,7 +168,7 @@ export class TemplateReference { myClick(event: any) {} birthday = new Date(); readonlyHeroes: ReadonlyArray<Readonly<Hero>> = this.heroes; - constNames = [{name: 'name'}] as const ; + constNames = [{name: 'name'}] as const; } @Component({ diff --git a/packages/language-service/test/typescript_host_spec.ts b/packages/language-service/test/typescript_host_spec.ts index 7d383c46d6a03..07a09575f9b26 100644 --- a/packages/language-service/test/typescript_host_spec.ts +++ b/packages/language-service/test/typescript_host_spec.ts @@ -94,7 +94,7 @@ describe('TypeScriptServiceHost', () => { const tsLS = ts.createLanguageService(tsLSHost); const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS); const templates = ngLSHost.getTemplates('/app/parsing-cases.ts'); - expect(templates.length).toBe(9); + expect(templates.length).toBe(8); }); it('should be able to find external template', () => { From 93302b7fb8cdb6bbfef9cac34bf811b4284c931a Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 6 Apr 2020 13:21:00 -0700 Subject: [PATCH 126/262] build: update to latest version of husky (#36459) PR Close #36459 --- package.json | 10 ++-- yarn.lock | 138 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 132 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 5b6197158ce0b..80271bf367b77 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,6 @@ "preinstall": "node tools/yarn/check-yarn.js", "postinstall": "node scripts/webdriver-manager-update.js && node --preserve-symlinks --preserve-symlinks-main ./tools/postinstall-patches.js", "check-env": "gulp check-env", - "commitmsg": "yarn -s ng-dev commit-message pre-commit-validate", "test-ivy-aot": "bazelisk test --config=ivy --build_tag_filters=-no-ivy-aot,-fixme-ivy-aot --test_tag_filters=-no-ivy-aot,-fixme-ivy-aot", "test-non-ivy": "bazelisk test --build_tag_filters=-ivy-only --test_tag_filters=-ivy-only", "test-fixme-ivy-aot": "bazelisk test --config=ivy --build_tag_filters=-no-ivy-aot --test_tag_filters=-no-ivy-aot", @@ -172,7 +171,7 @@ "gulp-filter": "^5.1.0", "gulp-git": "^2.7.0", "gulp-tslint": "8.1.2", - "husky": "^0.14.3", + "husky": "^4.2.3", "jpm": "1.3.1", "json5": "^2.1.2", "karma-browserstack-launcher": "^1.3.0", @@ -197,5 +196,10 @@ "**/graceful-fs": "4.2.2", "**/webdriver-manager": "12.1.7" }, - "cldr-data-coverage": "full" + "cldr-data-coverage": "full", + "husky": { + "hooks": { + "commit-msg": "yarn -s ng-dev commit-message pre-commit-validate" + } + } } diff --git a/yarn.lock b/yarn.lock index 085e917efcae1..959ad17be4342 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1367,6 +1367,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.34.tgz#0a5d6ae5d22612f0cf5f10320e1fc5d2a745dcb8" integrity sha512-BneGN0J9ke24lBRn44hVHNeDlrXRYF+VRp0HbSUNnEZahXGAysHZIqnf/hER6aabdBgzM4YOV4jrR8gj4Zfi0g== +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + "@types/q@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" @@ -3014,6 +3019,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -3226,6 +3236,11 @@ ci-info@^1.5.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -3565,6 +3580,11 @@ compare-semver@^1.0.0: dependencies: semver "^5.0.1" +compare-versions@^3.5.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -4017,6 +4037,17 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + coverage-istanbul-loader@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/coverage-istanbul-loader/-/coverage-istanbul-loader-2.0.3.tgz#87d42f03fa0fd3fa8743ec76945d9d67f105722a" @@ -5682,6 +5713,13 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +find-versions@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" + integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== + dependencies: + semver-regex "^2.0.0" + find@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/find/-/find-0.3.0.tgz#4082e8fc8d8320f1a382b5e4f521b9bc50775cb8" @@ -7151,14 +7189,21 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -husky@^0.14.3: - version "0.14.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3" - integrity sha512-e21wivqHpstpoiWA/Yi8eFti8E+sQDSS53cpJsPptPs295QTOQR0ZwnHo2TXy1XOpZFD9rPOd3NpmqTK6uMLJA== +husky@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.3.tgz#3b18d2ee5febe99e27f2983500202daffbc3151e" + integrity sha512-VxTsSTRwYveKXN4SaH1/FefRJYCtx+wx04sSVcOpD7N2zjoHxa+cEJ07Qg5NmV3HAK+IRKOyNVpi2YBIVccIfQ== dependencies: - is-ci "^1.0.10" - normalize-path "^1.0.0" - strip-indent "^2.0.0" + chalk "^3.0.0" + ci-info "^2.0.0" + compare-versions "^3.5.1" + cosmiconfig "^6.0.0" + find-versions "^3.2.0" + opencollective-postinstall "^2.0.2" + pkg-dir "^4.2.0" + please-upgrade-node "^3.2.0" + slash "^3.0.0" + which-pm-runs "^1.0.0" iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13: version "0.4.24" @@ -7214,6 +7259,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-from@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" @@ -8536,6 +8589,11 @@ liftoff@^2.1.0: rechoir "^0.6.2" resolve "^1.1.7" +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + listenercount@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" @@ -9836,11 +9894,6 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" - integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= - normalize-path@^2.0.0, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -10143,6 +10196,11 @@ open@^6.3.0: dependencies: is-wsl "^1.1.0" +opencollective-postinstall@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89" + integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw== + opener@~1.4.0: version "1.4.3" resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" @@ -10433,6 +10491,13 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0: version "5.1.5" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" @@ -10474,6 +10539,16 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + parse-ms@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" @@ -10610,6 +10685,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pathval@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" @@ -10687,7 +10767,7 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -pkg-dir@^4.1.0: +pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -10706,6 +10786,13 @@ pkginfo@0.3.x: resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" integrity sha1-Wyn2qB9wcXFC4J52W76rl7T4HiE= +please-upgrade-node@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== + dependencies: + semver-compare "^1.0.0" + plist@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.1.tgz#a9b931d17c304e8912ef0ba3bdd6182baf2e1f8c" @@ -11952,6 +12039,11 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -12329,6 +12421,11 @@ selfsigned@^1.10.7: dependencies: node-forge "0.9.0" +semver-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -12343,6 +12440,11 @@ semver-intersect@1.4.0: dependencies: semver "^5.0.0" +semver-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" + integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== + "semver@2 || 3 || 4 || 5", semver@^5.0.0, semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -12572,6 +12674,11 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + "slice-stream@>= 1.0.0 < 2": version "1.0.0" resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" @@ -14698,6 +14805,11 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + which@1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/which/-/which-1.2.4.tgz#1557f96080604e5b11b3599eb9f45b50a9efd722" From 416c786774dccc20d824737207be4e55cb53c9cc Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Mon, 30 Mar 2020 09:14:02 +0900 Subject: [PATCH 127/262] fix(zone.js): should not try to patch fetch if it is not writable (#36311) Close #36142 In Firefox extensions, the `window.fetch` is not configurable, that means ``` const desc = Object.getOwnPropertyDescriptor(window, 'fetch'); desc.writable === false; ``` So in this case, we should not try to patch `fetch`, otherwise, it will throw error ('fetch is ReadOnly`) PR Close #36311 --- packages/zone.js/lib/common/promise.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/zone.js/lib/common/promise.ts b/packages/zone.js/lib/common/promise.ts index d588e1d52088d..8f41b06478cbf 100644 --- a/packages/zone.js/lib/common/promise.ts +++ b/packages/zone.js/lib/common/promise.ts @@ -1,3 +1,5 @@ +import {patchMethod} from './utils'; + /** * @license * Copyright Google Inc. All Rights Reserved. @@ -500,8 +502,8 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr api.patchThen = patchThen; function zoneify(fn: Function) { - return function(this: unknown) { - let resultPromise = fn.apply(this, arguments); + return function(self: any, args: any[]) { + let resultPromise = fn.apply(self, args); if (resultPromise instanceof ZoneAwarePromise) { return resultPromise; } @@ -515,11 +517,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr if (NativePromise) { patchThen(NativePromise); - const fetch = global['fetch']; - if (typeof fetch == 'function') { - global[api.symbol('fetch')] = fetch; - global['fetch'] = zoneify(fetch); - } + patchMethod(global, 'fetch', delegate => zoneify(delegate)); } // This is not part of public API, but it is useful for tests, so we expose it. From 7d0af179e38120f0fe6555e121b9ecd5fc4653fe Mon Sep 17 00:00:00 2001 From: Andrew Kushnir <akushnir@google.com> Date: Mon, 6 Apr 2020 15:44:00 -0700 Subject: [PATCH 128/262] style(forms): reformat of the `forms` package after clang update (#36466) PR Close #36466 --- .../directives/abstract_control_directive.ts | 52 +- .../abstract_form_group_directive.ts | 20 +- .../src/directives/checkbox_value_accessor.ts | 10 +- .../forms/src/directives/control_container.ts | 10 +- .../src/directives/default_value_accessor.ts | 15 +- packages/forms/src/directives/ng_control.ts | 8 +- .../forms/src/directives/ng_control_status.ts | 42 +- packages/forms/src/directives/ng_form.ts | 51 +- packages/forms/src/directives/ng_model.ts | 347 +-- .../forms/src/directives/ng_model_group.ts | 4 +- .../src/directives/normalize_validator.ts | 6 +- .../src/directives/number_value_accessor.ts | 10 +- .../radio_control_value_accessor.ts | 27 +- .../src/directives/range_value_accessor.ts | 10 +- .../form_control_directive.ts | 173 +- .../reactive_directives/form_control_name.ts | 32 +- .../form_group_directive.ts | 54 +- .../reactive_directives/form_group_name.ts | 16 +- .../forms/src/directives/reactive_errors.ts | 5 +- .../select_control_value_accessor.ts | 14 +- .../select_multiple_control_value_accessor.ts | 40 +- packages/forms/src/directives/shared.ts | 43 +- packages/forms/src/directives/validators.ts | 101 +- packages/forms/src/form_builder.ts | 4 +- packages/forms/src/form_providers.ts | 9 +- packages/forms/src/model.ts | 262 +- packages/forms/src/validators.ts | 37 +- packages/forms/test/directives_spec.ts | 92 +- packages/forms/test/form_array_spec.ts | 1918 +++++++-------- packages/forms/test/form_builder_spec.ts | 315 +-- packages/forms/test/form_control_spec.ts | 1890 +++++++-------- packages/forms/test/form_group_spec.ts | 2098 +++++++++-------- .../forms/test/reactive_integration_spec.ts | 168 +- packages/forms/test/spies.ts | 8 +- .../forms/test/template_integration_spec.ts | 151 +- packages/forms/test/validators_spec.ts | 710 +++--- .../test/value_accessor_integration_spec.ts | 171 +- 37 files changed, 4620 insertions(+), 4303 deletions(-) diff --git a/packages/forms/src/directives/abstract_control_directive.ts b/packages/forms/src/directives/abstract_control_directive.ts index 5c20cda5515ae..61e9bf84d9e23 100644 --- a/packages/forms/src/directives/abstract_control_directive.ts +++ b/packages/forms/src/directives/abstract_control_directive.ts @@ -31,7 +31,9 @@ export abstract class AbstractControlDirective { * @description * Reports the value of the control if it is present, otherwise null. */ - get value(): any { return this.control ? this.control.value : null; } + get value(): any { + return this.control ? this.control.value : null; + } /** * @description @@ -39,14 +41,18 @@ export abstract class AbstractControlDirective { * validation errors exist with the current value. * If the control is not present, null is returned. */ - get valid(): boolean|null { return this.control ? this.control.valid : null; } + get valid(): boolean|null { + return this.control ? this.control.valid : null; + } /** * @description * Reports whether the control is invalid, meaning that an error exists in the input value. * If the control is not present, null is returned. */ - get invalid(): boolean|null { return this.control ? this.control.invalid : null; } + get invalid(): boolean|null { + return this.control ? this.control.invalid : null; + } /** * @description @@ -54,7 +60,9 @@ export abstract class AbstractControlDirective { * errors are not yet available for the input value. If the control is not present, null is * returned. */ - get pending(): boolean|null { return this.control ? this.control.pending : null; } + get pending(): boolean|null { + return this.control ? this.control.pending : null; + } /** * @description @@ -62,41 +70,53 @@ export abstract class AbstractControlDirective { * in the UI and is exempt from validation checks and excluded from aggregate * values of ancestor controls. If the control is not present, null is returned. */ - get disabled(): boolean|null { return this.control ? this.control.disabled : null; } + get disabled(): boolean|null { + return this.control ? this.control.disabled : null; + } /** * @description * Reports whether the control is enabled, meaning that the control is included in ancestor * calculations of validity or value. If the control is not present, null is returned. */ - get enabled(): boolean|null { return this.control ? this.control.enabled : null; } + get enabled(): boolean|null { + return this.control ? this.control.enabled : null; + } /** * @description * Reports the control's validation errors. If the control is not present, null is returned. */ - get errors(): ValidationErrors|null { return this.control ? this.control.errors : null; } + get errors(): ValidationErrors|null { + return this.control ? this.control.errors : null; + } /** * @description * Reports whether the control is pristine, meaning that the user has not yet changed * the value in the UI. If the control is not present, null is returned. */ - get pristine(): boolean|null { return this.control ? this.control.pristine : null; } + get pristine(): boolean|null { + return this.control ? this.control.pristine : null; + } /** * @description * Reports whether the control is dirty, meaning that the user has changed * the value in the UI. If the control is not present, null is returned. */ - get dirty(): boolean|null { return this.control ? this.control.dirty : null; } + get dirty(): boolean|null { + return this.control ? this.control.dirty : null; + } /** * @description * Reports whether the control is touched, meaning that the user has triggered * a `blur` event on it. If the control is not present, null is returned. */ - get touched(): boolean|null { return this.control ? this.control.touched : null; } + get touched(): boolean|null { + return this.control ? this.control.touched : null; + } /** * @description @@ -104,14 +124,18 @@ export abstract class AbstractControlDirective { * 'VALID', 'INVALID', 'DISABLED', and 'PENDING'. * If the control is not present, null is returned. */ - get status(): string|null { return this.control ? this.control.status : null; } + get status(): string|null { + return this.control ? this.control.status : null; + } /** * @description * Reports whether the control is untouched, meaning that the user has not yet triggered * a `blur` event on it. If the control is not present, null is returned. */ - get untouched(): boolean|null { return this.control ? this.control.untouched : null; } + get untouched(): boolean|null { + return this.control ? this.control.untouched : null; + } /** * @description @@ -137,7 +161,9 @@ export abstract class AbstractControlDirective { * Returns an array that represents the path from the top-level form to this control. * Each index is the string name of the control on that level. */ - get path(): string[]|null { return null; } + get path(): string[]|null { + return null; + } /** * @description diff --git a/packages/forms/src/directives/abstract_form_group_directive.ts b/packages/forms/src/directives/abstract_form_group_directive.ts index 9a73f32656e4d..6d7e5caddc9d9 100644 --- a/packages/forms/src/directives/abstract_form_group_directive.ts +++ b/packages/forms/src/directives/abstract_form_group_directive.ts @@ -31,7 +31,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn * @internal */ // TODO(issue/24571): remove '!'. - _parent !: ControlContainer; + _parent!: ControlContainer; /** * @description @@ -40,7 +40,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn * @internal */ // TODO(issue/24571): remove '!'. - _validators !: any[]; + _validators!: any[]; /** * @description @@ -49,7 +49,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn * @internal */ // TODO(issue/24571): remove '!'. - _asyncValidators !: any[]; + _asyncValidators!: any[]; /** * @description @@ -58,7 +58,7 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn */ ngOnInit(): void { this._checkParentType(); - this.formDirective !.addFormGroup(this); + this.formDirective!.addFormGroup(this); } /** @@ -76,7 +76,9 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn * @description * The `FormGroup` bound to this directive. */ - get control(): FormGroup { return this.formDirective !.getFormGroup(this); } + get control(): FormGroup { + return this.formDirective!.getFormGroup(this); + } /** * @description @@ -90,13 +92,17 @@ export class AbstractFormGroupDirective extends ControlContainer implements OnIn * @description * The top-level directive for this group if present, otherwise null. */ - get formDirective(): Form|null { return this._parent ? this._parent.formDirective : null; } + get formDirective(): Form|null { + return this._parent ? this._parent.formDirective : null; + } /** * @description * The synchronous validators registered with this group. */ - get validator(): ValidatorFn|null { return composeValidators(this._validators); } + get validator(): ValidatorFn|null { + return composeValidators(this._validators); + } /** * @description diff --git a/packages/forms/src/directives/checkbox_value_accessor.ts b/packages/forms/src/directives/checkbox_value_accessor.ts index 9a526222661bf..4a1dd17654f1f 100644 --- a/packages/forms/src/directives/checkbox_value_accessor.ts +++ b/packages/forms/src/directives/checkbox_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, ElementRef, Renderer2, forwardRef} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Renderer2} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; @@ -75,7 +75,9 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; } + registerOnChange(fn: (_: any) => {}): void { + this.onChange = fn; + } /** * @description @@ -83,7 +85,9 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnTouched(fn: () => {}): void { this.onTouched = fn; } + registerOnTouched(fn: () => {}): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the input element. diff --git a/packages/forms/src/directives/control_container.ts b/packages/forms/src/directives/control_container.ts index 254d3c7827b8e..678b18f473ae9 100644 --- a/packages/forms/src/directives/control_container.ts +++ b/packages/forms/src/directives/control_container.ts @@ -23,17 +23,21 @@ export abstract class ControlContainer extends AbstractControlDirective { * The name for the control */ // TODO(issue/24571): remove '!'. - name !: string | number | null; + name!: string|number|null; /** * @description * The top-level form directive for the control. */ - get formDirective(): Form|null { return null; } + get formDirective(): Form|null { + return null; + } /** * @description * The path to this group. */ - get path(): string[]|null { return null; } + get path(): string[]|null { + return null; + } } diff --git a/packages/forms/src/directives/default_value_accessor.ts b/packages/forms/src/directives/default_value_accessor.ts index 1e946e679571f..b900b5fbe3785 100644 --- a/packages/forms/src/directives/default_value_accessor.ts +++ b/packages/forms/src/directives/default_value_accessor.ts @@ -7,7 +7,8 @@ */ import {ɵgetDOM as getDOM} from '@angular/common'; -import {Directive, ElementRef, Inject, InjectionToken, Optional, Renderer2, forwardRef} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Inject, InjectionToken, Optional, Renderer2} from '@angular/core'; + import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; export const DEFAULT_VALUE_ACCESSOR: any = { @@ -112,7 +113,9 @@ export class DefaultValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnChange(fn: (_: any) => void): void { this.onChange = fn; } + registerOnChange(fn: (_: any) => void): void { + this.onChange = fn; + } /** * @description @@ -120,7 +123,9 @@ export class DefaultValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnTouched(fn: () => void): void { this.onTouched = fn; } + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the input element. @@ -139,7 +144,9 @@ export class DefaultValueAccessor implements ControlValueAccessor { } /** @internal */ - _compositionStart(): void { this._composing = true; } + _compositionStart(): void { + this._composing = true; + } /** @internal */ _compositionEnd(value: any): void { diff --git a/packages/forms/src/directives/ng_control.ts b/packages/forms/src/directives/ng_control.ts index de09f7ff83d1a..47e92f6db49e0 100644 --- a/packages/forms/src/directives/ng_control.ts +++ b/packages/forms/src/directives/ng_control.ts @@ -66,7 +66,9 @@ export abstract class NgControl extends AbstractControlDirective { * * @throws An exception that this method is not implemented */ - get validator(): ValidatorFn|null { return <ValidatorFn>unimplemented(); } + get validator(): ValidatorFn|null { + return <ValidatorFn>unimplemented(); + } /** * @description @@ -74,7 +76,9 @@ export abstract class NgControl extends AbstractControlDirective { * * @throws An exception that this method is not implemented */ - get asyncValidator(): AsyncValidatorFn|null { return <AsyncValidatorFn>unimplemented(); } + get asyncValidator(): AsyncValidatorFn|null { + return <AsyncValidatorFn>unimplemented(); + } /** * @description diff --git a/packages/forms/src/directives/ng_control_status.ts b/packages/forms/src/directives/ng_control_status.ts index 735c1b5938463..12c7f5d5254d4 100644 --- a/packages/forms/src/directives/ng_control_status.ts +++ b/packages/forms/src/directives/ng_control_status.ts @@ -15,15 +15,31 @@ import {NgControl} from './ng_control'; export class AbstractControlStatus { private _cd: AbstractControlDirective; - constructor(cd: AbstractControlDirective) { this._cd = cd; } + constructor(cd: AbstractControlDirective) { + this._cd = cd; + } - get ngClassUntouched(): boolean { return this._cd.control ? this._cd.control.untouched : false; } - get ngClassTouched(): boolean { return this._cd.control ? this._cd.control.touched : false; } - get ngClassPristine(): boolean { return this._cd.control ? this._cd.control.pristine : false; } - get ngClassDirty(): boolean { return this._cd.control ? this._cd.control.dirty : false; } - get ngClassValid(): boolean { return this._cd.control ? this._cd.control.valid : false; } - get ngClassInvalid(): boolean { return this._cd.control ? this._cd.control.invalid : false; } - get ngClassPending(): boolean { return this._cd.control ? this._cd.control.pending : false; } + get ngClassUntouched(): boolean { + return this._cd.control ? this._cd.control.untouched : false; + } + get ngClassTouched(): boolean { + return this._cd.control ? this._cd.control.touched : false; + } + get ngClassPristine(): boolean { + return this._cd.control ? this._cd.control.pristine : false; + } + get ngClassDirty(): boolean { + return this._cd.control ? this._cd.control.dirty : false; + } + get ngClassValid(): boolean { + return this._cd.control ? this._cd.control.valid : false; + } + get ngClassInvalid(): boolean { + return this._cd.control ? this._cd.control.invalid : false; + } + get ngClassPending(): boolean { + return this._cd.control ? this._cd.control.pending : false; + } } export const ngControlStatusHost = { @@ -61,14 +77,16 @@ export const ngControlStatusHost = { */ @Directive({selector: '[formControlName],[ngModel],[formControl]', host: ngControlStatusHost}) export class NgControlStatus extends AbstractControlStatus { - constructor(@Self() cd: NgControl) { super(cd); } + constructor(@Self() cd: NgControl) { + super(cd); + } } /** * @description * Directive automatically applied to Angular form groups that sets CSS classes * based on control status (valid/invalid/dirty/etc). - * + * * @see `NgControlStatus` * * @ngModule ReactiveFormsModule @@ -81,5 +99,7 @@ export class NgControlStatus extends AbstractControlStatus { host: ngControlStatusHost }) export class NgControlStatusGroup extends AbstractControlStatus { - constructor(@Self() cd: ControlContainer) { super(cd); } + constructor(@Self() cd: ControlContainer) { + super(cd); + } } diff --git a/packages/forms/src/directives/ng_form.ts b/packages/forms/src/directives/ng_form.ts index 9720671b11f74..5952d0263791a 100644 --- a/packages/forms/src/directives/ng_form.ts +++ b/packages/forms/src/directives/ng_form.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AfterViewInit, Directive, EventEmitter, Inject, Input, Optional, Self, forwardRef} from '@angular/core'; +import {AfterViewInit, Directive, EventEmitter, forwardRef, Inject, Input, Optional, Self} from '@angular/core'; import {AbstractControl, FormControl, FormGroup, FormHooks} from '../model'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators'; @@ -96,8 +96,7 @@ const resolvedPromise = (() => Promise.resolve(null))(); outputs: ['ngSubmit'], exportAs: 'ngForm' }) -export class NgForm extends ControlContainer implements Form, - AfterViewInit { +export class NgForm extends ControlContainer implements Form, AfterViewInit { /** * @description * Returns whether the form submission has been triggered. @@ -128,7 +127,7 @@ export class NgForm extends ControlContainer implements Form, * */ // TODO(issue/24571): remove '!'. - @Input('ngFormOptions') options !: {updateOn?: FormHooks}; + @Input('ngFormOptions') options!: {updateOn?: FormHooks}; constructor( @Optional() @Self() @Inject(NG_VALIDATORS) validators: any[], @@ -142,32 +141,42 @@ export class NgForm extends ControlContainer implements Form, * @description * Lifecycle method called after the view is initialized. For internal use only. */ - ngAfterViewInit() { this._setUpdateStrategy(); } + ngAfterViewInit() { + this._setUpdateStrategy(); + } /** * @description * The directive instance. */ - get formDirective(): Form { return this; } + get formDirective(): Form { + return this; + } /** * @description * The internal `FormGroup` instance. */ - get control(): FormGroup { return this.form; } + get control(): FormGroup { + return this.form; + } /** * @description * Returns an array representing the path to this group. Because this directive * always lives at the top level of a form, it is always an empty array. */ - get path(): string[] { return []; } + get path(): string[] { + return []; + } /** * @description * Returns a map of the controls in this group. */ - get controls(): {[key: string]: AbstractControl} { return this.form.controls; } + get controls(): {[key: string]: AbstractControl} { + return this.form.controls; + } /** * @description @@ -179,7 +188,7 @@ export class NgForm extends ControlContainer implements Form, addControl(dir: NgModel): void { resolvedPromise.then(() => { const container = this._findContainer(dir.path); - (dir as{control: FormControl}).control = + (dir as {control: FormControl}).control = <FormControl>container.registerControl(dir.name, dir.control); setUpControl(dir.control, dir); dir.control.updateValueAndValidity({emitEvent: false}); @@ -193,7 +202,9 @@ export class NgForm extends ControlContainer implements Form, * * @param dir The `NgModel` directive instance. */ - getControl(dir: NgModel): FormControl { return <FormControl>this.form.get(dir.path); } + getControl(dir: NgModel): FormControl { + return <FormControl>this.form.get(dir.path); + } /** * @description @@ -248,7 +259,9 @@ export class NgForm extends ControlContainer implements Form, * * @param dir The `NgModelGroup` directive instance. */ - getFormGroup(dir: NgModelGroup): FormGroup { return <FormGroup>this.form.get(dir.path); } + getFormGroup(dir: NgModelGroup): FormGroup { + return <FormGroup>this.form.get(dir.path); + } /** * Sets the new value for the provided `NgControl` directive. @@ -258,7 +271,7 @@ export class NgForm extends ControlContainer implements Form, */ updateModel(dir: NgControl, value: any): void { resolvedPromise.then(() => { - const ctrl = <FormControl>this.form.get(dir.path !); + const ctrl = <FormControl>this.form.get(dir.path!); ctrl.setValue(value); }); } @@ -269,7 +282,9 @@ export class NgForm extends ControlContainer implements Form, * * @param value The new value */ - setValue(value: {[key: string]: any}): void { this.control.setValue(value); } + setValue(value: {[key: string]: any}): void { + this.control.setValue(value); + } /** * @description @@ -279,7 +294,7 @@ export class NgForm extends ControlContainer implements Form, * @param $event The "submit" event object */ onSubmit($event: Event): boolean { - (this as{submitted: boolean}).submitted = true; + (this as {submitted: boolean}).submitted = true; syncPendingControls(this.form, this._directives); this.ngSubmit.emit($event); return false; @@ -289,7 +304,9 @@ export class NgForm extends ControlContainer implements Form, * @description * Method called when the "reset" event is triggered on the form. */ - onReset(): void { this.resetForm(); } + onReset(): void { + this.resetForm(); + } /** * @description @@ -299,7 +316,7 @@ export class NgForm extends ControlContainer implements Form, */ resetForm(value: any = undefined): void { this.form.reset(value); - (this as{submitted: boolean}).submitted = false; + (this as {submitted: boolean}).submitted = false; } private _setUpdateStrategy() { diff --git a/packages/forms/src/directives/ng_model.ts b/packages/forms/src/directives/ng_model.ts index b85aa6f2407cd..67cf5c0ecddb2 100644 --- a/packages/forms/src/directives/ng_model.ts +++ b/packages/forms/src/directives/ng_model.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, EventEmitter, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core'; +import {Directive, EventEmitter, forwardRef, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges} from '@angular/core'; import {FormControl, FormHooks} from '../model'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators'; @@ -64,17 +64,17 @@ const resolvedPromise = (() => Promise.resolve(null))(); * (also known as 'banana-box syntax'), the value in the UI always syncs back to * the domain model in your class. * - * To inspect the properties of the associated `FormControl` (like validity state), - * export the directive into a local template variable using `ngModel` as the key (ex: `#myVar="ngModel"`). - * You then access the control using the directive's `control` property, - * but most properties used (like `valid` and `dirty`) fall through to the control anyway for direct access. - * See a full list of properties directly available in `AbstractControlDirective`. + * To inspect the properties of the associated `FormControl` (like validity state), + * export the directive into a local template variable using `ngModel` as the key (ex: + * `#myVar="ngModel"`). You then access the control using the directive's `control` property, but + * most properties used (like `valid` and `dirty`) fall through to the control anyway for direct + * access. See a full list of properties directly available in `AbstractControlDirective`. * - * @see `RadioControlValueAccessor` + * @see `RadioControlValueAccessor` * @see `SelectControlValueAccessor` - * + * * @usageNotes - * + * * ### Using ngModel on a standalone control * * The following examples show a simple standalone control using `ngModel`: @@ -84,23 +84,23 @@ const resolvedPromise = (() => Promise.resolve(null))(); * When using the `ngModel` within `<form>` tags, you'll also need to supply a `name` attribute * so that the control can be registered with the parent form under that name. * - * In the context of a parent form, it's often unnecessary to include one-way or two-way binding, - * as the parent form syncs the value for you. You access its properties by exporting it into a - * local template variable using `ngForm` such as (`#f="ngForm"`). Use the variable where + * In the context of a parent form, it's often unnecessary to include one-way or two-way binding, + * as the parent form syncs the value for you. You access its properties by exporting it into a + * local template variable using `ngForm` such as (`#f="ngForm"`). Use the variable where * needed on form submission. * * If you do need to populate initial values into your form, using a one-way binding for * `ngModel` tends to be sufficient as long as you use the exported form's value rather * than the domain model's value on submit. - * + * * ### Using ngModel within a form * * The following example shows controls using `ngModel` within a form: * * {@example forms/ts/simpleForm/simple_form_example.ts region='Component'} - * + * * ### Using a standalone ngModel within a group - * + * * The following example shows you how to use a standalone ngModel control * within a form. This controls the display of the form, but doesn't contain form data. * @@ -111,11 +111,11 @@ const resolvedPromise = (() => Promise.resolve(null))(); * </form> * <!-- form value: {login: ''} --> * ``` - * + * * ### Setting the ngModel name attribute through options - * - * The following example shows you an alternate way to set the name attribute. The name attribute is used - * within a custom form component, and the name `@Input` property serves a different purpose. + * + * The following example shows you an alternate way to set the name attribute. The name attribute is + * used within a custom form component, and the name `@Input` property serves a different purpose. * * ```html * <form> @@ -133,8 +133,7 @@ const resolvedPromise = (() => Promise.resolve(null))(); providers: [formControlBinding], exportAs: 'ngModel' }) -export class NgModel extends NgControl implements OnChanges, - OnDestroy { +export class NgModel extends NgControl implements OnChanges, OnDestroy { public readonly control: FormControl = new FormControl(); // At runtime we coerce arbitrary values assigned to the "disabled" input to a "boolean". @@ -161,14 +160,14 @@ export class NgModel extends NgControl implements OnChanges, * uses this name as a key to retrieve this control's value. */ // TODO(issue/24571): remove '!'. - @Input() name !: string; + @Input() name!: string; /** * @description * Tracks whether the control is disabled. */ // TODO(issue/24571): remove '!'. - @Input('disabled') isDisabled !: boolean; + @Input('disabled') isDisabled!: boolean; /** * @description @@ -192,8 +191,7 @@ export class NgModel extends NgControl implements OnChanges, * */ // TODO(issue/24571): remove '!'. - @Input('ngModelOptions') - options !: {name?: string, standalone?: boolean, updateOn?: FormHooks}; + @Input('ngModelOptions') options!: {name?: string, standalone?: boolean, updateOn?: FormHooks}; /** * @description @@ -202,151 +200,156 @@ export class NgModel extends NgControl implements OnChanges, */ @Output('ngModelChange') update = new EventEmitter(); - constructor(@Optional() @Host() parent: ControlContainer, - @Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>, - @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>, - @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) - valueAccessors: ControlValueAccessor[]) { - super(); - this._parent = parent; - this._rawValidators = validators || []; - this._rawAsyncValidators = asyncValidators || []; - this.valueAccessor = selectValueAccessor(this, valueAccessors); - } - - /** - * @description - * A lifecycle method called when the directive's inputs change. For internal use - * only. - * - * @param changes A object of key/value pairs for the set of changed inputs. - */ - ngOnChanges(changes: SimpleChanges) { - this._checkForErrors(); - if (!this._registered) this._setUpControl(); - if ('isDisabled' in changes) { - this._updateDisabled(changes); - } - - if (isPropertyUpdated(changes, this.viewModel)) { - this._updateValue(this.model); - this.viewModel = this.model; - } - } - - /** - * @description - * Lifecycle method called before the directive's instance is destroyed. For internal - * use only. - */ - ngOnDestroy(): void { this.formDirective && this.formDirective.removeControl(this); } - - /** - * @description - * Returns an array that represents the path from the top-level form to this control. - * Each index is the string name of the control on that level. - */ - get path(): string[] { - return this._parent ? controlPath(this.name, this._parent) : [this.name]; - } - - /** - * @description - * The top-level directive for this control if present, otherwise null. - */ - get formDirective(): any { return this._parent ? this._parent.formDirective : null; } - - /** - * @description - * Synchronous validator function composed of all the synchronous validators - * registered with this directive. - */ - get validator(): ValidatorFn|null { return composeValidators(this._rawValidators); } - - /** - * @description - * Async validator function composed of all the async validators registered with this - * directive. - */ - get asyncValidator(): AsyncValidatorFn|null { - return composeAsyncValidators(this._rawAsyncValidators); - } - - /** - * @description - * Sets the new value for the view model and emits an `ngModelChange` event. - * - * @param newValue The new value emitted by `ngModelChange`. - */ - viewToModelUpdate(newValue: any): void { - this.viewModel = newValue; - this.update.emit(newValue); - } - - private _setUpControl(): void { - this._setUpdateStrategy(); - this._isStandalone() ? this._setUpStandalone() : - this.formDirective.addControl(this); - this._registered = true; - } - - private _setUpdateStrategy(): void { - if (this.options && this.options.updateOn != null) { - this.control._updateOn = this.options.updateOn; - } - } - - private _isStandalone(): boolean { - return !this._parent || !!(this.options && this.options.standalone); - } - - private _setUpStandalone(): void { - setUpControl(this.control, this); - this.control.updateValueAndValidity({emitEvent: false}); - } - - private _checkForErrors(): void { - if (!this._isStandalone()) { - this._checkParentType(); - } - this._checkName(); - } - - private _checkParentType(): void { - if (!(this._parent instanceof NgModelGroup) && - this._parent instanceof AbstractFormGroupDirective) { - TemplateDrivenErrors.formGroupNameException(); - } else if ( - !(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) { - TemplateDrivenErrors.modelParentException(); - } - } - - private _checkName(): void { - if (this.options && this.options.name) this.name = this.options.name; - - if (!this._isStandalone() && !this.name) { - TemplateDrivenErrors.missingNameException(); - } - } - - private _updateValue(value: any): void { - resolvedPromise.then( - () => { this.control.setValue(value, {emitViewToModelChange: false}); }); - } - - private _updateDisabled(changes: SimpleChanges) { - const disabledValue = changes['isDisabled'].currentValue; - - const isDisabled = - disabledValue === '' || (disabledValue && disabledValue !== 'false'); - - resolvedPromise.then(() => { - if (isDisabled && !this.control.disabled) { - this.control.disable(); - } else if (!isDisabled && this.control.disabled) { - this.control.enable(); - } - }); - } + constructor( + @Optional() @Host() parent: ControlContainer, + @Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>, + @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: + Array<AsyncValidator|AsyncValidatorFn>, + @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { + super(); + this._parent = parent; + this._rawValidators = validators || []; + this._rawAsyncValidators = asyncValidators || []; + this.valueAccessor = selectValueAccessor(this, valueAccessors); + } + + /** + * @description + * A lifecycle method called when the directive's inputs change. For internal use + * only. + * + * @param changes A object of key/value pairs for the set of changed inputs. + */ + ngOnChanges(changes: SimpleChanges) { + this._checkForErrors(); + if (!this._registered) this._setUpControl(); + if ('isDisabled' in changes) { + this._updateDisabled(changes); + } + + if (isPropertyUpdated(changes, this.viewModel)) { + this._updateValue(this.model); + this.viewModel = this.model; + } + } + + /** + * @description + * Lifecycle method called before the directive's instance is destroyed. For internal + * use only. + */ + ngOnDestroy(): void { + this.formDirective && this.formDirective.removeControl(this); + } + + /** + * @description + * Returns an array that represents the path from the top-level form to this control. + * Each index is the string name of the control on that level. + */ + get path(): string[] { + return this._parent ? controlPath(this.name, this._parent) : [this.name]; + } + + /** + * @description + * The top-level directive for this control if present, otherwise null. + */ + get formDirective(): any { + return this._parent ? this._parent.formDirective : null; + } + + /** + * @description + * Synchronous validator function composed of all the synchronous validators + * registered with this directive. + */ + get validator(): ValidatorFn|null { + return composeValidators(this._rawValidators); + } + + /** + * @description + * Async validator function composed of all the async validators registered with this + * directive. + */ + get asyncValidator(): AsyncValidatorFn|null { + return composeAsyncValidators(this._rawAsyncValidators); + } + + /** + * @description + * Sets the new value for the view model and emits an `ngModelChange` event. + * + * @param newValue The new value emitted by `ngModelChange`. + */ + viewToModelUpdate(newValue: any): void { + this.viewModel = newValue; + this.update.emit(newValue); + } + + private _setUpControl(): void { + this._setUpdateStrategy(); + this._isStandalone() ? this._setUpStandalone() : this.formDirective.addControl(this); + this._registered = true; + } + + private _setUpdateStrategy(): void { + if (this.options && this.options.updateOn != null) { + this.control._updateOn = this.options.updateOn; + } + } + + private _isStandalone(): boolean { + return !this._parent || !!(this.options && this.options.standalone); + } + + private _setUpStandalone(): void { + setUpControl(this.control, this); + this.control.updateValueAndValidity({emitEvent: false}); + } + + private _checkForErrors(): void { + if (!this._isStandalone()) { + this._checkParentType(); + } + this._checkName(); + } + + private _checkParentType(): void { + if (!(this._parent instanceof NgModelGroup) && + this._parent instanceof AbstractFormGroupDirective) { + TemplateDrivenErrors.formGroupNameException(); + } else if (!(this._parent instanceof NgModelGroup) && !(this._parent instanceof NgForm)) { + TemplateDrivenErrors.modelParentException(); + } + } + + private _checkName(): void { + if (this.options && this.options.name) this.name = this.options.name; + + if (!this._isStandalone() && !this.name) { + TemplateDrivenErrors.missingNameException(); + } + } + + private _updateValue(value: any): void { + resolvedPromise.then(() => { + this.control.setValue(value, {emitViewToModelChange: false}); + }); + } + + private _updateDisabled(changes: SimpleChanges) { + const disabledValue = changes['isDisabled'].currentValue; + + const isDisabled = disabledValue === '' || (disabledValue && disabledValue !== 'false'); + + resolvedPromise.then(() => { + if (isDisabled && !this.control.disabled) { + this.control.disable(); + } else if (!isDisabled && this.control.disabled) { + this.control.enable(); + } + }); + } } diff --git a/packages/forms/src/directives/ng_model_group.ts b/packages/forms/src/directives/ng_model_group.ts index c7cabf035e72e..55ec88d51de84 100644 --- a/packages/forms/src/directives/ng_model_group.ts +++ b/packages/forms/src/directives/ng_model_group.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core'; +import {Directive, forwardRef, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf} from '@angular/core'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators'; @@ -54,7 +54,7 @@ export class NgModelGroup extends AbstractFormGroupDirective implements OnInit, * to a key in the parent `NgForm`. */ // TODO(issue/24571): remove '!'. - @Input('ngModelGroup') name !: string; + @Input('ngModelGroup') name!: string; constructor( @Host() @SkipSelf() parent: ControlContainer, diff --git a/packages/forms/src/directives/normalize_validator.ts b/packages/forms/src/directives/normalize_validator.ts index 3a08e61558c6d..f12aa0aae5c69 100644 --- a/packages/forms/src/directives/normalize_validator.ts +++ b/packages/forms/src/directives/normalize_validator.ts @@ -9,7 +9,7 @@ import {AbstractControl} from '../model'; import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; -export function normalizeValidator(validator: ValidatorFn | Validator): ValidatorFn { +export function normalizeValidator(validator: ValidatorFn|Validator): ValidatorFn { if ((<Validator>validator).validate) { return (c: AbstractControl) => (<Validator>validator).validate(c); } else { @@ -17,8 +17,8 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato } } -export function normalizeAsyncValidator(validator: AsyncValidatorFn | AsyncValidator): - AsyncValidatorFn { +export function normalizeAsyncValidator(validator: AsyncValidatorFn| + AsyncValidator): AsyncValidatorFn { if ((<AsyncValidator>validator).validate) { return (c: AbstractControl) => (<AsyncValidator>validator).validate(c); } else { diff --git a/packages/forms/src/directives/number_value_accessor.ts b/packages/forms/src/directives/number_value_accessor.ts index df5edc43fa607..dc85ae7b0d9fd 100644 --- a/packages/forms/src/directives/number_value_accessor.ts +++ b/packages/forms/src/directives/number_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, ElementRef, Renderer2, forwardRef} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Renderer2} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; @@ -84,7 +84,9 @@ export class NumberValueAccessor implements ControlValueAccessor { * @param fn The callback function */ registerOnChange(fn: (_: number|null) => void): void { - this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); }; + this.onChange = (value) => { + fn(value == '' ? null : parseFloat(value)); + }; } /** @@ -93,7 +95,9 @@ export class NumberValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnTouched(fn: () => void): void { this.onTouched = fn; } + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the input element. diff --git a/packages/forms/src/directives/radio_control_value_accessor.ts b/packages/forms/src/directives/radio_control_value_accessor.ts index bca1040d21dad..6f5ee4905b8d9 100644 --- a/packages/forms/src/directives/radio_control_value_accessor.ts +++ b/packages/forms/src/directives/radio_control_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, ElementRef, Injectable, Injector, Input, OnDestroy, OnInit, Renderer2, forwardRef} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Injectable, Injector, Input, OnDestroy, OnInit, Renderer2} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; import {NgControl} from './ng_control'; @@ -93,17 +93,16 @@ export class RadioControlRegistry { host: {'(change)': 'onChange()', '(blur)': 'onTouched()'}, providers: [RADIO_VALUE_ACCESSOR] }) -export class RadioControlValueAccessor implements ControlValueAccessor, - OnDestroy, OnInit { +export class RadioControlValueAccessor implements ControlValueAccessor, OnDestroy, OnInit { /** @internal */ // TODO(issue/24571): remove '!'. - _state !: boolean; + _state!: boolean; /** @internal */ // TODO(issue/24571): remove '!'. - _control !: NgControl; + _control!: NgControl; /** @internal */ // TODO(issue/24571): remove '!'. - _fn !: Function; + _fn!: Function; /** * @description @@ -122,7 +121,7 @@ export class RadioControlValueAccessor implements ControlValueAccessor, * Tracks the name of the radio input element. */ // TODO(issue/24571): remove '!'. - @Input() name !: string; + @Input() name!: string; /** * @description @@ -130,7 +129,7 @@ export class RadioControlValueAccessor implements ControlValueAccessor, * to a key in the parent `FormGroup` or `FormArray`. */ // TODO(issue/24571): remove '!'. - @Input() formControlName !: string; + @Input() formControlName!: string; /** * @description @@ -156,7 +155,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor, * @description * Lifecycle method called before the directive's instance is destroyed. For internal use only. */ - ngOnDestroy(): void { this._registry.remove(this); } + ngOnDestroy(): void { + this._registry.remove(this); + } /** * @description @@ -188,7 +189,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor, * * @param value */ - fireUncheck(value: any): void { this.writeValue(value); } + fireUncheck(value: any): void { + this.writeValue(value); + } /** * @description @@ -196,7 +199,9 @@ export class RadioControlValueAccessor implements ControlValueAccessor, * * @param fn The callback function */ - registerOnTouched(fn: () => {}): void { this.onTouched = fn; } + registerOnTouched(fn: () => {}): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the input element. diff --git a/packages/forms/src/directives/range_value_accessor.ts b/packages/forms/src/directives/range_value_accessor.ts index e386fe14445a6..7a01f7c1d81ee 100644 --- a/packages/forms/src/directives/range_value_accessor.ts +++ b/packages/forms/src/directives/range_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, ElementRef, Renderer2, StaticProvider, forwardRef} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Renderer2, StaticProvider} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; @@ -82,7 +82,9 @@ export class RangeValueAccessor implements ControlValueAccessor { * @param fn The callback function */ registerOnChange(fn: (_: number|null) => void): void { - this.onChange = (value) => { fn(value == '' ? null : parseFloat(value)); }; + this.onChange = (value) => { + fn(value == '' ? null : parseFloat(value)); + }; } /** @@ -91,7 +93,9 @@ export class RangeValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnTouched(fn: () => void): void { this.onTouched = fn; } + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the range input element. diff --git a/packages/forms/src/directives/reactive_directives/form_control_directive.ts b/packages/forms/src/directives/reactive_directives/form_control_directive.ts index c329d5ab31f6f..28d1957a94e13 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_directive.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, EventEmitter, Inject, InjectionToken, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core'; +import {Directive, EventEmitter, forwardRef, Inject, InjectionToken, Input, OnChanges, Optional, Output, Self, SimpleChanges} from '@angular/core'; import {FormControl} from '../../model'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators'; @@ -31,7 +31,7 @@ export const formControlBinding: any = { /** * @description * * Syncs a standalone `FormControl` instance to a form control element. - * + * * @see [Reactive Forms Guide](guide/reactive-forms) * @see `FormControl` * @see `AbstractControl` @@ -39,7 +39,7 @@ export const formControlBinding: any = { * @usageNotes * * ### Registering a single form control - * + * * The following examples shows how to register a standalone control and set its value. * * {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'} @@ -129,14 +129,16 @@ export class FormControlDirective extends NgControl implements OnChanges { * Tracks the `FormControl` instance bound to the directive. */ // TODO(issue/24571): remove '!'. - @Input('formControl') form !: FormControl; + @Input('formControl') form!: FormControl; /** * @description * Triggers a warning that this input should not be used with reactive forms. */ @Input('disabled') - set isDisabled(isDisabled: boolean) { ReactiveErrors.disabledAttrWarning(); } + set isDisabled(isDisabled: boolean) { + ReactiveErrors.disabledAttrWarning(); + } // TODO(kara): remove next 4 properties once deprecation period is over @@ -164,81 +166,88 @@ export class FormControlDirective extends NgControl implements OnChanges { */ _ngModelWarningSent = false; - constructor(@Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>, - @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: Array<AsyncValidator|AsyncValidatorFn>, - @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) - valueAccessors: ControlValueAccessor[], - @Optional() @Inject(NG_MODEL_WITH_FORM_CONTROL_WARNING) private _ngModelWarningConfig: string|null) { - super(); - this._rawValidators = validators || []; - this._rawAsyncValidators = asyncValidators || []; - this.valueAccessor = selectValueAccessor(this, valueAccessors); - } - - /** - * @description - * A lifecycle method called when the directive's inputs change. For internal use - * only. - * - * @param changes A object of key/value pairs for the set of changed inputs. - */ - ngOnChanges(changes: SimpleChanges): void { - if (this._isControlChanged(changes)) { - setUpControl(this.form, this); - if (this.control.disabled && this.valueAccessor !.setDisabledState) { - this.valueAccessor !.setDisabledState !(true); - } - this.form.updateValueAndValidity({emitEvent: false}); - } - if (isPropertyUpdated(changes, this.viewModel)) { - _ngModelWarning( - 'formControl', FormControlDirective, this, this._ngModelWarningConfig); - this.form.setValue(this.model); - this.viewModel = this.model; - } - } - - /** - * @description - * Returns an array that represents the path from the top-level form to this control. - * Each index is the string name of the control on that level. - */ - get path(): string[] { return []; } - - /** - * @description - * Synchronous validator function composed of all the synchronous validators - * registered with this directive. - */ - get validator(): ValidatorFn|null { return composeValidators(this._rawValidators); } - - /** - * @description - * Async validator function composed of all the async validators registered with this - * directive. - */ - get asyncValidator(): AsyncValidatorFn|null { - return composeAsyncValidators(this._rawAsyncValidators); - } - - /** - * @description - * The `FormControl` bound to this directive. - */ - get control(): FormControl { return this.form; } - - /** - * @description - * Sets the new value for the view model and emits an `ngModelChange` event. - * - * @param newValue The new value for the view model. - */ - viewToModelUpdate(newValue: any): void { - this.viewModel = newValue; - this.update.emit(newValue); - } - - private _isControlChanged(changes: {[key: string]: any}): boolean { - return changes.hasOwnProperty('form'); - } + constructor( + @Optional() @Self() @Inject(NG_VALIDATORS) validators: Array<Validator|ValidatorFn>, + @Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: + Array<AsyncValidator|AsyncValidatorFn>, + @Optional() @Self() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[], + @Optional() @Inject(NG_MODEL_WITH_FORM_CONTROL_WARNING) private _ngModelWarningConfig: string| + null) { + super(); + this._rawValidators = validators || []; + this._rawAsyncValidators = asyncValidators || []; + this.valueAccessor = selectValueAccessor(this, valueAccessors); + } + + /** + * @description + * A lifecycle method called when the directive's inputs change. For internal use + * only. + * + * @param changes A object of key/value pairs for the set of changed inputs. + */ + ngOnChanges(changes: SimpleChanges): void { + if (this._isControlChanged(changes)) { + setUpControl(this.form, this); + if (this.control.disabled && this.valueAccessor!.setDisabledState) { + this.valueAccessor!.setDisabledState!(true); + } + this.form.updateValueAndValidity({emitEvent: false}); + } + if (isPropertyUpdated(changes, this.viewModel)) { + _ngModelWarning('formControl', FormControlDirective, this, this._ngModelWarningConfig); + this.form.setValue(this.model); + this.viewModel = this.model; + } + } + + /** + * @description + * Returns an array that represents the path from the top-level form to this control. + * Each index is the string name of the control on that level. + */ + get path(): string[] { + return []; + } + + /** + * @description + * Synchronous validator function composed of all the synchronous validators + * registered with this directive. + */ + get validator(): ValidatorFn|null { + return composeValidators(this._rawValidators); + } + + /** + * @description + * Async validator function composed of all the async validators registered with this + * directive. + */ + get asyncValidator(): AsyncValidatorFn|null { + return composeAsyncValidators(this._rawAsyncValidators); + } + + /** + * @description + * The `FormControl` bound to this directive. + */ + get control(): FormControl { + return this.form; + } + + /** + * @description + * Sets the new value for the view model and emits an `ngModelChange` event. + * + * @param newValue The new value for the view model. + */ + viewToModelUpdate(newValue: any): void { + this.viewModel = newValue; + this.update.emit(newValue); + } + + private _isControlChanged(changes: {[key: string]: any}): boolean { + return changes.hasOwnProperty('form'); + } } diff --git a/packages/forms/src/directives/reactive_directives/form_control_name.ts b/packages/forms/src/directives/reactive_directives/form_control_name.ts index a466ea4f45605..6a4e9da351a45 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_name.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, EventEmitter, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf, forwardRef} from '@angular/core'; +import {Directive, EventEmitter, forwardRef, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf} from '@angular/core'; import {FormControl} from '../../model'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators'; @@ -31,13 +31,13 @@ export const controlNameBinding: any = { * @description * Syncs a `FormControl` in an existing `FormGroup` to a form control * element by name. - * + * * @see [Reactive Forms Guide](guide/reactive-forms) * @see `FormControl` * @see `AbstractControl` * * @usageNotes - * + * * ### Register `FormControl` within a group * * The following example shows how to register multiple form controls within a form group @@ -140,7 +140,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { * Tracks the `FormControl` instance bound to the directive. */ // TODO(issue/24571): remove '!'. - readonly control !: FormControl; + readonly control!: FormControl; /** * @description @@ -152,14 +152,16 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { * to indices when iterating over controls in a `FormArray`. */ // TODO(issue/24571): remove '!'. - @Input('formControlName') name !: string | number | null; + @Input('formControlName') name!: string|number|null; /** * @description * Triggers a warning that this input should not be used with reactive forms. */ @Input('disabled') - set isDisabled(isDisabled: boolean) { ReactiveErrors.disabledAttrWarning(); } + set isDisabled(isDisabled: boolean) { + ReactiveErrors.disabledAttrWarning(); + } // TODO(kara): remove next 4 properties once deprecation period is over @@ -244,21 +246,25 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { * Each index is the string name of the control on that level. */ get path(): string[] { - return controlPath(this.name == null ? this.name : this.name.toString(), this._parent !); + return controlPath(this.name == null ? this.name : this.name.toString(), this._parent!); } /** * @description * The top-level directive for this group if present, otherwise null. */ - get formDirective(): any { return this._parent ? this._parent.formDirective : null; } + get formDirective(): any { + return this._parent ? this._parent.formDirective : null; + } /** * @description * Synchronous validator function composed of all the synchronous validators * registered with this directive. */ - get validator(): ValidatorFn|null { return composeValidators(this._rawValidators); } + get validator(): ValidatorFn|null { + return composeValidators(this._rawValidators); + } /** * @description @@ -266,7 +272,7 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { * directive. */ get asyncValidator(): AsyncValidatorFn { - return composeAsyncValidators(this._rawAsyncValidators) !; + return composeAsyncValidators(this._rawAsyncValidators)!; } private _checkParentType(): void { @@ -282,9 +288,9 @@ export class FormControlName extends NgControl implements OnChanges, OnDestroy { private _setUpControl() { this._checkParentType(); - (this as{control: FormControl}).control = this.formDirective.addControl(this); - if (this.control.disabled && this.valueAccessor !.setDisabledState) { - this.valueAccessor !.setDisabledState !(true); + (this as {control: FormControl}).control = this.formDirective.addControl(this); + if (this.control.disabled && this.valueAccessor!.setDisabledState) { + this.valueAccessor!.setDisabledState!(true); } this._added = true; } diff --git a/packages/forms/src/directives/reactive_directives/form_group_directive.ts b/packages/forms/src/directives/reactive_directives/form_group_directive.ts index 2d3e617adef39..4fabe81ea4c0f 100644 --- a/packages/forms/src/directives/reactive_directives/form_group_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_group_directive.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, EventEmitter, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges, forwardRef} from '@angular/core'; +import {Directive, EventEmitter, forwardRef, Inject, Input, OnChanges, Optional, Output, Self, SimpleChanges} from '@angular/core'; + import {FormArray, FormControl, FormGroup} from '../../model'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators'; import {ControlContainer} from '../control_container'; @@ -31,7 +32,7 @@ export const formDirectiveProvider: any = { * `FormGroup` instance to match any child `FormControl`, `FormGroup`, * and `FormArray` instances to child `FormControlName`, `FormGroupName`, * and `FormArrayName` directives. - * + * * @see [Reactive Forms Guide](guide/reactive-forms) * @see `AbstractControl` * @@ -51,8 +52,7 @@ export const formDirectiveProvider: any = { host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'}, exportAs: 'ngForm' }) -export class FormGroupDirective extends ControlContainer implements Form, - OnChanges { +export class FormGroupDirective extends ControlContainer implements Form, OnChanges { /** * @description * Reports whether the form submission has been triggered. @@ -60,7 +60,7 @@ export class FormGroupDirective extends ControlContainer implements Form, public readonly submitted: boolean = false; // TODO(issue/24571): remove '!'. - private _oldForm !: FormGroup; + private _oldForm!: FormGroup; /** * @description @@ -72,7 +72,7 @@ export class FormGroupDirective extends ControlContainer implements Form, * @description * Tracks the `FormGroup` bound to this directive. */ - @Input('formGroup') form: FormGroup = null !; + @Input('formGroup') form: FormGroup = null!; /** * @description @@ -105,20 +105,26 @@ export class FormGroupDirective extends ControlContainer implements Form, * @description * Returns this directive's instance. */ - get formDirective(): Form { return this; } + get formDirective(): Form { + return this; + } /** * @description * Returns the `FormGroup` bound to this directive. */ - get control(): FormGroup { return this.form; } + get control(): FormGroup { + return this.form; + } /** * @description * Returns an array representing the path to this group. Because this directive * always lives at the top level of a form, it always an empty array. */ - get path(): string[] { return []; } + get path(): string[] { + return []; + } /** * @description @@ -141,7 +147,9 @@ export class FormGroupDirective extends ControlContainer implements Form, * * @param dir The `FormControlName` directive instance. */ - getControl(dir: FormControlName): FormControl { return <FormControl>this.form.get(dir.path); } + getControl(dir: FormControlName): FormControl { + return <FormControl>this.form.get(dir.path); + } /** * @description @@ -149,7 +157,9 @@ export class FormGroupDirective extends ControlContainer implements Form, * * @param dir The `FormControlName` directive instance. */ - removeControl(dir: FormControlName): void { removeDir<FormControlName>(this.directives, dir); } + removeControl(dir: FormControlName): void { + removeDir<FormControlName>(this.directives, dir); + } /** * Adds a new `FormGroupName` directive instance to the form. @@ -175,7 +185,9 @@ export class FormGroupDirective extends ControlContainer implements Form, * * @param dir The `FormGroupName` directive instance. */ - getFormGroup(dir: FormGroupName): FormGroup { return <FormGroup>this.form.get(dir.path); } + getFormGroup(dir: FormGroupName): FormGroup { + return <FormGroup>this.form.get(dir.path); + } /** * Adds a new `FormArrayName` directive instance to the form. @@ -201,7 +213,9 @@ export class FormGroupDirective extends ControlContainer implements Form, * * @param dir The `FormArrayName` directive instance. */ - getFormArray(dir: FormArrayName): FormArray { return <FormArray>this.form.get(dir.path); } + getFormArray(dir: FormArrayName): FormArray { + return <FormArray>this.form.get(dir.path); + } /** * Sets the new value for the provided `FormControlName` directive. @@ -222,7 +236,7 @@ export class FormGroupDirective extends ControlContainer implements Form, * @param $event The "submit" event object */ onSubmit($event: Event): boolean { - (this as{submitted: boolean}).submitted = true; + (this as {submitted: boolean}).submitted = true; syncPendingControls(this.form, this.directives); this.ngSubmit.emit($event); return false; @@ -232,7 +246,9 @@ export class FormGroupDirective extends ControlContainer implements Form, * @description * Method called when the "reset" event is triggered on the form. */ - onReset(): void { this.resetForm(); } + onReset(): void { + this.resetForm(); + } /** * @description @@ -242,7 +258,7 @@ export class FormGroupDirective extends ControlContainer implements Form, */ resetForm(value: any = undefined): void { this.form.reset(value); - (this as{submitted: boolean}).submitted = false; + (this as {submitted: boolean}).submitted = false; } @@ -253,7 +269,7 @@ export class FormGroupDirective extends ControlContainer implements Form, if (dir.control !== newCtrl) { cleanUpControl(dir.control, dir); if (newCtrl) setUpControl(newCtrl, dir); - (dir as{control: FormControl}).control = newCtrl; + (dir as {control: FormControl}).control = newCtrl; } }); @@ -268,10 +284,10 @@ export class FormGroupDirective extends ControlContainer implements Form, private _updateValidators() { const sync = composeValidators(this._validators); - this.form.validator = Validators.compose([this.form.validator !, sync !]); + this.form.validator = Validators.compose([this.form.validator!, sync!]); const async = composeAsyncValidators(this._asyncValidators); - this.form.asyncValidator = Validators.composeAsync([this.form.asyncValidator !, async !]); + this.form.asyncValidator = Validators.composeAsync([this.form.asyncValidator!, async!]); } private _checkFormPresent() { diff --git a/packages/forms/src/directives/reactive_directives/form_group_name.ts b/packages/forms/src/directives/reactive_directives/form_group_name.ts index 92ca96a17bea0..c3f48352fe75a 100644 --- a/packages/forms/src/directives/reactive_directives/form_group_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_group_name.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core'; +import {Directive, forwardRef, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf} from '@angular/core'; import {FormArray} from '../../model'; import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators'; @@ -82,7 +82,7 @@ export class FormGroupName extends AbstractFormGroupDirective implements OnInit, * to indices when iterating over groups in a `FormArray`. */ // TODO(issue/24571): remove '!'. - @Input('formGroupName') name !: string | number | null; + @Input('formGroupName') name!: string|number|null; constructor( @Optional() @Host() @SkipSelf() parent: ControlContainer, @@ -152,7 +152,7 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy * to indices when iterating over arrays in a `FormArray`. */ // TODO(issue/24571): remove '!'. - @Input('formArrayName') name !: string | number | null; + @Input('formArrayName') name!: string|number|null; constructor( @Optional() @Host() @SkipSelf() parent: ControlContainer, @@ -172,7 +172,7 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy */ ngOnInit(): void { this._checkParentType(); - this.formDirective !.addFormArray(this); + this.formDirective!.addFormArray(this); } /** @@ -189,7 +189,9 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy * @description * The `FormArray` bound to this directive. */ - get control(): FormArray { return this.formDirective !.getFormArray(this); } + get control(): FormArray { + return this.formDirective!.getFormArray(this); + } /** * @description @@ -213,7 +215,9 @@ export class FormArrayName extends ControlContainer implements OnInit, OnDestroy * Synchronous validator function composed of all the synchronous validators registered with this * directive. */ - get validator(): ValidatorFn|null { return composeValidators(this._validators); } + get validator(): ValidatorFn|null { + return composeValidators(this._validators); + } /** * @description diff --git a/packages/forms/src/directives/reactive_errors.ts b/packages/forms/src/directives/reactive_errors.ts index acca6a319f49f..b7e46673e6bf1 100644 --- a/packages/forms/src/directives/reactive_errors.ts +++ b/packages/forms/src/directives/reactive_errors.ts @@ -83,8 +83,9 @@ export class ReactiveErrors { in Angular v7. For more information on this, see our API docs here: - https://angular.io/api/forms/${directiveName === 'formControl' ? 'FormControlDirective' - : 'FormControlName'}#use-with-ngmodel + https://angular.io/api/forms/${ + directiveName === 'formControl' ? 'FormControlDirective' : + 'FormControlName'}#use-with-ngmodel `); } } diff --git a/packages/forms/src/directives/select_control_value_accessor.ts b/packages/forms/src/directives/select_control_value_accessor.ts index a8fa16e8cb9c8..9edb9d47e6ecf 100644 --- a/packages/forms/src/directives/select_control_value_accessor.ts +++ b/packages/forms/src/directives/select_control_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, forwardRef, ɵlooseIdentical as looseIdentical} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, ɵlooseIdentical as looseIdentical} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; @@ -16,7 +16,7 @@ export const SELECT_VALUE_ACCESSOR: StaticProvider = { multi: true }; -function _buildValueString(id: string | null, value: any): string { +function _buildValueString(id: string|null, value: any): string { if (id == null) return `${value}`; if (value && typeof value === 'object') value = 'Object'; return `${id}: ${value}`.slice(0, 50); @@ -160,7 +160,9 @@ export class SelectControlValueAccessor implements ControlValueAccessor { * * @param fn The callback function */ - registerOnTouched(fn: () => any): void { this.onTouched = fn; } + registerOnTouched(fn: () => any): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the select input element. @@ -172,7 +174,9 @@ export class SelectControlValueAccessor implements ControlValueAccessor { } /** @internal */ - _registerOption(): string { return (this._idCounter++).toString(); } + _registerOption(): string { + return (this._idCounter++).toString(); + } /** @internal */ _getOptionId(value: any): string|null { @@ -206,7 +210,7 @@ export class NgSelectOption implements OnDestroy { * ID of the option element */ // TODO(issue/24571): remove '!'. - id !: string; + id!: string; constructor( private _element: ElementRef, private _renderer: Renderer2, diff --git a/packages/forms/src/directives/select_multiple_control_value_accessor.ts b/packages/forms/src/directives/select_multiple_control_value_accessor.ts index 5e0800947b773..5bc28e20c07fd 100644 --- a/packages/forms/src/directives/select_multiple_control_value_accessor.ts +++ b/packages/forms/src/directives/select_multiple_control_value_accessor.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, ElementRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, forwardRef, ɵlooseIdentical as looseIdentical} from '@angular/core'; +import {Directive, ElementRef, forwardRef, Host, Input, OnDestroy, Optional, Renderer2, StaticProvider, ɵlooseIdentical as looseIdentical} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; @@ -36,24 +36,24 @@ interface HTMLOption { /** Mock interface for HTMLCollection */ abstract class HTMLCollection { // TODO(issue/24571): remove '!'. - length !: number; + length!: number; abstract item(_: number): HTMLOption; } /** * @description - * The `ControlValueAccessor` for writing multi-select control values and listening to multi-select control - * changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and `NgModel` - * directives. - * + * The `ControlValueAccessor` for writing multi-select control values and listening to multi-select + * control changes. The value accessor is used by the `FormControlDirective`, `FormControlName`, and + * `NgModel` directives. + * * @see `SelectControlValueAccessor` * * @usageNotes - * + * * ### Using a multi-select control - * + * * The follow example shows you how to use a multi-select control with a reactive form. - * + * * ```ts * const countryControl = new FormControl(); * ``` @@ -65,9 +65,9 @@ abstract class HTMLCollection { * </option> * </select> * ``` - * + * * ### Customizing option selection - * + * * To customize the default option comparison algorithm, `<select>` supports `compareWith` input. * See the `SelectControlValueAccessor` for usage. * @@ -135,9 +135,13 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor if (Array.isArray(value)) { // convert values to ids const ids = value.map((v) => this._getOptionId(v)); - optionSelectedStateSetter = (opt, o) => { opt._setSelected(ids.indexOf(o.toString()) > -1); }; + optionSelectedStateSetter = (opt, o) => { + opt._setSelected(ids.indexOf(o.toString()) > -1); + }; } else { - optionSelectedStateSetter = (opt, o) => { opt._setSelected(false); }; + optionSelectedStateSetter = (opt, o) => { + opt._setSelected(false); + }; } this._optionMap.forEach(optionSelectedStateSetter); } @@ -182,7 +186,9 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor * * @param fn The callback function */ - registerOnTouched(fn: () => any): void { this.onTouched = fn; } + registerOnTouched(fn: () => any): void { + this.onTouched = fn; + } /** * Sets the "disabled" property on the select input element. @@ -203,7 +209,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor /** @internal */ _getOptionId(value: any): string|null { for (const id of Array.from(this._optionMap.keys())) { - if (this._compareWith(this._optionMap.get(id) !._value, value)) return id; + if (this._compareWith(this._optionMap.get(id)!._value, value)) return id; } return null; } @@ -211,7 +217,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor /** @internal */ _getOptionValue(valueString: string): any { const id: string = _extractId(valueString); - return this._optionMap.has(id) ? this._optionMap.get(id) !._value : valueString; + return this._optionMap.has(id) ? this._optionMap.get(id)!._value : valueString; } } @@ -228,7 +234,7 @@ export class SelectMultipleControlValueAccessor implements ControlValueAccessor @Directive({selector: 'option'}) export class ɵNgSelectMultipleOption implements OnDestroy { // TODO(issue/24571): remove '!'. - id !: string; + id!: string; /** @internal */ _value: any; diff --git a/packages/forms/src/directives/shared.ts b/packages/forms/src/directives/shared.ts index 17347db421cdf..2bdf5e51b40b6 100644 --- a/packages/forms/src/directives/shared.ts +++ b/packages/forms/src/directives/shared.ts @@ -28,43 +28,44 @@ import {SelectMultipleControlValueAccessor} from './select_multiple_control_valu import {AsyncValidator, AsyncValidatorFn, Validator, ValidatorFn} from './validators'; -export function controlPath(name: string | null, parent: ControlContainer): string[] { - return [...parent.path !, name !]; +export function controlPath(name: string|null, parent: ControlContainer): string[] { + return [...parent.path!, name!]; } export function setUpControl(control: FormControl, dir: NgControl): void { if (!control) _throwError(dir, 'Cannot find control with'); if (!dir.valueAccessor) _throwError(dir, 'No value accessor for form control with'); - control.validator = Validators.compose([control.validator !, dir.validator]); - control.asyncValidator = Validators.composeAsync([control.asyncValidator !, dir.asyncValidator]); - dir.valueAccessor !.writeValue(control.value); + control.validator = Validators.compose([control.validator!, dir.validator]); + control.asyncValidator = Validators.composeAsync([control.asyncValidator!, dir.asyncValidator]); + dir.valueAccessor!.writeValue(control.value); setUpViewChangePipeline(control, dir); setUpModelChangePipeline(control, dir); setUpBlurPipeline(control, dir); - if (dir.valueAccessor !.setDisabledState) { - control.registerOnDisabledChange( - (isDisabled: boolean) => { dir.valueAccessor !.setDisabledState !(isDisabled); }); + if (dir.valueAccessor!.setDisabledState) { + control.registerOnDisabledChange((isDisabled: boolean) => { + dir.valueAccessor!.setDisabledState!(isDisabled); + }); } // re-run validation when validator binding changes, e.g. minlength=3 -> minlength=4 - dir._rawValidators.forEach((validator: Validator | ValidatorFn) => { + dir._rawValidators.forEach((validator: Validator|ValidatorFn) => { if ((<Validator>validator).registerOnValidatorChange) - (<Validator>validator).registerOnValidatorChange !(() => control.updateValueAndValidity()); + (<Validator>validator).registerOnValidatorChange!(() => control.updateValueAndValidity()); }); - dir._rawAsyncValidators.forEach((validator: AsyncValidator | AsyncValidatorFn) => { + dir._rawAsyncValidators.forEach((validator: AsyncValidator|AsyncValidatorFn) => { if ((<Validator>validator).registerOnValidatorChange) - (<Validator>validator).registerOnValidatorChange !(() => control.updateValueAndValidity()); + (<Validator>validator).registerOnValidatorChange!(() => control.updateValueAndValidity()); }); } export function cleanUpControl(control: FormControl, dir: NgControl) { - dir.valueAccessor !.registerOnChange(() => _noControlError(dir)); - dir.valueAccessor !.registerOnTouched(() => _noControlError(dir)); + dir.valueAccessor!.registerOnChange(() => _noControlError(dir)); + dir.valueAccessor!.registerOnTouched(() => _noControlError(dir)); dir._rawValidators.forEach((validator: any) => { if (validator.registerOnValidatorChange) { @@ -82,7 +83,7 @@ export function cleanUpControl(control: FormControl, dir: NgControl) { } function setUpViewChangePipeline(control: FormControl, dir: NgControl): void { - dir.valueAccessor !.registerOnChange((newValue: any) => { + dir.valueAccessor!.registerOnChange((newValue: any) => { control._pendingValue = newValue; control._pendingChange = true; control._pendingDirty = true; @@ -92,7 +93,7 @@ function setUpViewChangePipeline(control: FormControl, dir: NgControl): void { } function setUpBlurPipeline(control: FormControl, dir: NgControl): void { - dir.valueAccessor !.registerOnTouched(() => { + dir.valueAccessor!.registerOnTouched(() => { control._pendingTouched = true; if (control.updateOn === 'blur' && control._pendingChange) updateControl(control, dir); @@ -110,7 +111,7 @@ function updateControl(control: FormControl, dir: NgControl): void { function setUpModelChangePipeline(control: FormControl, dir: NgControl): void { control.registerOnChange((newValue: any, emitModelEvent: boolean) => { // control -> view - dir.valueAccessor !.writeValue(newValue); + dir.valueAccessor!.writeValue(newValue); // control -> ngModel if (emitModelEvent) dir.viewToModelUpdate(newValue); @@ -118,7 +119,7 @@ function setUpModelChangePipeline(control: FormControl, dir: NgControl): void { } export function setUpFormContainer( - control: FormGroup | FormArray, dir: AbstractFormGroupDirective | FormArrayName) { + control: FormGroup|FormArray, dir: AbstractFormGroupDirective|FormArrayName) { if (control == null) _throwError(dir, 'Cannot find control with'); control.validator = Validators.compose([control.validator, dir.validator]); control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]); @@ -130,9 +131,9 @@ function _noControlError(dir: NgControl) { function _throwError(dir: AbstractControlDirective, message: string): void { let messageEnd: string; - if (dir.path !.length > 1) { + if (dir.path!.length > 1) { messageEnd = `path: '${dir.path!.join(' -> ')}'`; - } else if (dir.path ![0]) { + } else if (dir.path![0]) { messageEnd = `name: '${dir.path}'`; } else { messageEnd = 'unspecified name attribute'; @@ -226,7 +227,7 @@ export function removeDir<T>(list: T[], el: T): void { // TODO(kara): remove after deprecation period export function _ngModelWarning( name: string, type: {_ngModelWarningSentOnce: boolean}, - instance: {_ngModelWarningSent: boolean}, warningConfig: string | null) { + instance: {_ngModelWarningSent: boolean}, warningConfig: string|null) { if (!isDevMode() || warningConfig === 'never') return; if (((warningConfig === null || warningConfig === 'once') && !type._ngModelWarningSentOnce) || diff --git a/packages/forms/src/directives/validators.ts b/packages/forms/src/directives/validators.ts index e8d6c0d251098..27d5c1a72708a 100644 --- a/packages/forms/src/directives/validators.ts +++ b/packages/forms/src/directives/validators.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, Input, OnChanges, SimpleChanges, StaticProvider, forwardRef} from '@angular/core'; +import {Directive, forwardRef, Input, OnChanges, SimpleChanges, StaticProvider} from '@angular/core'; import {Observable} from 'rxjs'; import {AbstractControl} from '../model'; @@ -136,11 +136,11 @@ export const CHECKBOX_REQUIRED_VALIDATOR: StaticProvider = { * @description * A directive that adds the `required` validator to any controls marked with the * `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list. - * + * * @see [Form Validation](guide/form-validation) * * @usageNotes - * + * * ### Adding a required validator using template-driven forms * * ``` @@ -159,16 +159,18 @@ export const CHECKBOX_REQUIRED_VALIDATOR: StaticProvider = { }) export class RequiredValidator implements Validator { // TODO(issue/24571): remove '!'. - private _required !: boolean; + private _required!: boolean; // TODO(issue/24571): remove '!'. - private _onChange !: () => void; + private _onChange!: () => void; /** * @description * Tracks changes to the required attribute bound to this directive. */ @Input() - get required(): boolean|string { return this._required; } + get required(): boolean|string { + return this._required; + } set required(value: boolean|string) { this._required = value != null && value !== false && `${value}` !== 'false'; @@ -190,22 +192,25 @@ export class RequiredValidator implements Validator { * * @param fn The callback function */ - registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } + registerOnValidatorChange(fn: () => void): void { + this._onChange = fn; + } } /** * A Directive that adds the `required` validator to checkbox controls marked with the * `required` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list. - * + * * @see [Form Validation](guide/form-validation) * * @usageNotes - * + * * ### Adding a required checkbox validator using template-driven forms * - * The following example shows how to add a checkbox required validator to an input attached to an ngModel binding. - * + * The following example shows how to add a checkbox required validator to an input attached to an + * ngModel binding. + * * ``` * <input type="checkbox" name="active" ngModel required> * ``` @@ -248,11 +253,12 @@ export const EMAIL_VALIDATOR: any = { * @see [Form Validation](guide/form-validation) * * @usageNotes - * + * * ### Adding an email validator * - * The following example shows how to add an email validator to an input attached to an ngModel binding. - * + * The following example shows how to add an email validator to an input attached to an ngModel + * binding. + * * ``` * <input type="email" name="email" ngModel email> * <input type="email" name="email" ngModel email="true"> @@ -269,9 +275,9 @@ export const EMAIL_VALIDATOR: any = { }) export class EmailValidator implements Validator { // TODO(issue/24571): remove '!'. - private _enabled !: boolean; + private _enabled!: boolean; // TODO(issue/24571): remove '!'. - private _onChange !: () => void; + private _onChange!: () => void; /** * @description @@ -298,7 +304,9 @@ export class EmailValidator implements Validator { * * @param fn The callback function */ - registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } + registerOnValidatorChange(fn: () => void): void { + this._onChange = fn; + } } /** @@ -308,7 +316,9 @@ export class EmailValidator implements Validator { * * @publicApi */ -export interface ValidatorFn { (control: AbstractControl): ValidationErrors|null; } +export interface ValidatorFn { + (control: AbstractControl): ValidationErrors|null; +} /** * @description @@ -334,7 +344,7 @@ export const MIN_LENGTH_VALIDATOR: any = { /** * A directive that adds minimum length validation to controls marked with the * `minlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list. - * + * * @see [Form Validation](guide/form-validation) * * @usageNotes @@ -357,19 +367,18 @@ export const MIN_LENGTH_VALIDATOR: any = { providers: [MIN_LENGTH_VALIDATOR], host: {'[attr.minlength]': 'minlength ? minlength : null'} }) -export class MinLengthValidator implements Validator, - OnChanges { +export class MinLengthValidator implements Validator, OnChanges { // TODO(issue/24571): remove '!'. - private _validator !: ValidatorFn; + private _validator!: ValidatorFn; // TODO(issue/24571): remove '!'. - private _onChange !: () => void; + private _onChange!: () => void; /** * @description * Tracks changes to the the minimum length bound to this directive. */ // TODO(issue/24571): remove '!'. - @Input() minlength !: string | number; + @Input() minlength!: string|number; /** * @description @@ -400,7 +409,9 @@ export class MinLengthValidator implements Validator, * * @param fn The callback function */ - registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } + registerOnValidatorChange(fn: () => void): void { + this._onChange = fn; + } private _createValidator(): void { this._validator = Validators.minLength( @@ -421,7 +432,7 @@ export const MAX_LENGTH_VALIDATOR: any = { /** * A directive that adds max length validation to controls marked with the * `maxlength` attribute. The directive is provided with the `NG_VALIDATORS` multi-provider list. - * + * * @see [Form Validation](guide/form-validation) * * @usageNotes @@ -444,19 +455,18 @@ export const MAX_LENGTH_VALIDATOR: any = { providers: [MAX_LENGTH_VALIDATOR], host: {'[attr.maxlength]': 'maxlength ? maxlength : null'} }) -export class MaxLengthValidator implements Validator, - OnChanges { +export class MaxLengthValidator implements Validator, OnChanges { // TODO(issue/24571): remove '!'. - private _validator !: ValidatorFn; + private _validator!: ValidatorFn; // TODO(issue/24571): remove '!'. - private _onChange !: () => void; + private _onChange!: () => void; /** * @description * Tracks changes to the the maximum length bound to this directive. */ // TODO(issue/24571): remove '!'. - @Input() maxlength !: string | number; + @Input() maxlength!: string|number; /** * @description @@ -487,7 +497,9 @@ export class MaxLengthValidator implements Validator, * * @param fn The callback function */ - registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } + registerOnValidatorChange(fn: () => void): void { + this._onChange = fn; + } private _createValidator(): void { this._validator = Validators.maxLength( @@ -511,7 +523,7 @@ export const PATTERN_VALIDATOR: any = { * A directive that adds regex pattern validation to controls marked with the * `pattern` attribute. The regex must match the entire control value. * The directive is provided with the `NG_VALIDATORS` multi-provider list. - * + * * @see [Form Validation](guide/form-validation) * * @usageNotes @@ -524,7 +536,7 @@ export const PATTERN_VALIDATOR: any = { * ```html * <input name="firstName" ngModel pattern="[a-zA-Z ]*"> * ``` - * + * * @ngModule ReactiveFormsModule * @ngModule FormsModule * @publicApi @@ -534,19 +546,18 @@ export const PATTERN_VALIDATOR: any = { providers: [PATTERN_VALIDATOR], host: {'[attr.pattern]': 'pattern ? pattern : null'} }) -export class PatternValidator implements Validator, - OnChanges { +export class PatternValidator implements Validator, OnChanges { // TODO(issue/24571): remove '!'. - private _validator !: ValidatorFn; + private _validator!: ValidatorFn; // TODO(issue/24571): remove '!'. - private _onChange !: () => void; + private _onChange!: () => void; /** * @description * Tracks changes to the pattern bound to this directive. */ // TODO(issue/24571): remove '!'. - @Input() pattern !: string | RegExp; + @Input() pattern!: string|RegExp; /** * @description @@ -567,7 +578,9 @@ export class PatternValidator implements Validator, * Method that validates whether the value matches the * the pattern requirement. */ - validate(control: AbstractControl): ValidationErrors|null { return this._validator(control); } + validate(control: AbstractControl): ValidationErrors|null { + return this._validator(control); + } /** * @description @@ -575,7 +588,11 @@ export class PatternValidator implements Validator, * * @param fn The callback function */ - registerOnValidatorChange(fn: () => void): void { this._onChange = fn; } + registerOnValidatorChange(fn: () => void): void { + this._onChange = fn; + } - private _createValidator(): void { this._validator = Validators.pattern(this.pattern); } + private _createValidator(): void { + this._validator = Validators.pattern(this.pattern); + } } diff --git a/packages/forms/src/form_builder.ts b/packages/forms/src/form_builder.ts index aa6faa7c816bc..d59cbeffaaa69 100644 --- a/packages/forms/src/form_builder.ts +++ b/packages/forms/src/form_builder.ts @@ -11,8 +11,8 @@ import {Injectable} from '@angular/core'; import {AsyncValidatorFn, ValidatorFn} from './directives/validators'; import {AbstractControl, AbstractControlOptions, FormArray, FormControl, FormGroup, FormHooks} from './model'; -function isAbstractControlOptions(options: AbstractControlOptions | {[key: string]: any}): - options is AbstractControlOptions { +function isAbstractControlOptions(options: AbstractControlOptions| + {[key: string]: any}): options is AbstractControlOptions { return (<AbstractControlOptions>options).asyncValidators !== undefined || (<AbstractControlOptions>options).validators !== undefined || (<AbstractControlOptions>options).updateOn !== undefined; diff --git a/packages/forms/src/form_providers.ts b/packages/forms/src/form_providers.ts index 84934e932760f..2fdd72b476078 100644 --- a/packages/forms/src/form_providers.ts +++ b/packages/forms/src/form_providers.ts @@ -52,14 +52,13 @@ export class ReactiveFormsModule { * binding is used with reactive form directives. */ static withConfig(opts: { - /** @deprecated as of v6 */ warnOnNgModelWithFormControl: 'never' | 'once' | 'always' + /** @deprecated as of v6 */ warnOnNgModelWithFormControl: 'never'|'once'|'always' }): ModuleWithProviders<ReactiveFormsModule> { return { ngModule: ReactiveFormsModule, - providers: [{ - provide: NG_MODEL_WITH_FORM_CONTROL_WARNING, - useValue: opts.warnOnNgModelWithFormControl - }] + providers: [ + {provide: NG_MODEL_WITH_FORM_CONTROL_WARNING, useValue: opts.warnOnNgModelWithFormControl} + ] }; } } diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index ddbcfd76fc946..4dbe67666fb2f 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -44,7 +44,7 @@ export const PENDING = 'PENDING'; */ export const DISABLED = 'DISABLED'; -function _find(control: AbstractControl, path: Array<string|number>| string, delimiter: string) { +function _find(control: AbstractControl, path: Array<string|number>|string, delimiter: string) { if (path == null) return null; if (!Array.isArray(path)) { @@ -55,7 +55,7 @@ function _find(control: AbstractControl, path: Array<string|number>| string, del // Not using Array.reduce here due to a Chrome 80 bug // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982 let controlToFind: AbstractControl|null = control; - path.forEach((name: string | number) => { + path.forEach((name: string|number) => { if (controlToFind instanceof FormGroup) { controlToFind = controlToFind.controls.hasOwnProperty(name as string) ? controlToFind.controls[name] : @@ -69,9 +69,8 @@ function _find(control: AbstractControl, path: Array<string|number>| string, del return controlToFind; } -function coerceToValidator( - validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null): ValidatorFn| - null { +function coerceToValidator(validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions| + null): ValidatorFn|null { const validator = (isOptionsObj(validatorOrOpts) ? (validatorOrOpts as AbstractControlOptions).validators : validatorOrOpts) as ValidatorFn | @@ -81,8 +80,9 @@ function coerceToValidator( } function coerceToAsyncValidator( - asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null, validatorOrOpts?: ValidatorFn | - ValidatorFn[] | AbstractControlOptions | null): AsyncValidatorFn|null { + asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null, + validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null): AsyncValidatorFn| + null { const origAsyncValidator = (isOptionsObj(validatorOrOpts) ? (validatorOrOpts as AbstractControlOptions).asyncValidators : asyncValidator) as AsyncValidatorFn | @@ -92,7 +92,7 @@ function coerceToAsyncValidator( origAsyncValidator || null; } -export type FormHooks = 'change' | 'blur' | 'submit'; +export type FormHooks = 'change'|'blur'|'submit'; /** * Interface for options provided to an `AbstractControl`. @@ -118,8 +118,8 @@ export interface AbstractControlOptions { } -function isOptionsObj( - validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null): boolean { +function isOptionsObj(validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions| + null): boolean { return validatorOrOpts != null && !Array.isArray(validatorOrOpts) && typeof validatorOrOpts === 'object'; } @@ -142,21 +142,21 @@ function isOptionsObj( export abstract class AbstractControl { /** @internal */ // TODO(issue/24571): remove '!'. - _pendingDirty !: boolean; + _pendingDirty!: boolean; /** @internal */ // TODO(issue/24571): remove '!'. - _pendingTouched !: boolean; + _pendingTouched!: boolean; /** @internal */ _onCollectionChange = () => {}; /** @internal */ // TODO(issue/24571): remove '!'. - _updateOn !: FormHooks; + _updateOn!: FormHooks; // TODO(issue/24571): remove '!'. - private _parent !: FormGroup | FormArray; + private _parent!: FormGroup|FormArray; private _asyncValidationSubscription: any; /** @@ -184,7 +184,9 @@ export abstract class AbstractControl { /** * The parent control. */ - get parent(): FormGroup|FormArray { return this._parent; } + get parent(): FormGroup|FormArray { + return this._parent; + } /** * The validation status of the control. There are four possible @@ -199,7 +201,7 @@ export abstract class AbstractControl { * both valid AND invalid or invalid AND disabled. */ // TODO(issue/24571): remove '!'. - public readonly status !: string; + public readonly status!: string; /** * A control is `valid` when its `status` is `VALID`. @@ -209,7 +211,9 @@ export abstract class AbstractControl { * @returns True if the control has passed all of its validation tests, * false otherwise. */ - get valid(): boolean { return this.status === VALID; } + get valid(): boolean { + return this.status === VALID; + } /** * A control is `invalid` when its `status` is `INVALID`. @@ -219,7 +223,9 @@ export abstract class AbstractControl { * @returns True if this control has failed one or more of its validation checks, * false otherwise. */ - get invalid(): boolean { return this.status === INVALID; } + get invalid(): boolean { + return this.status === INVALID; + } /** * A control is `pending` when its `status` is `PENDING`. @@ -229,7 +235,9 @@ export abstract class AbstractControl { * @returns True if this control is in the process of conducting a validation check, * false otherwise. */ - get pending(): boolean { return this.status == PENDING; } + get pending(): boolean { + return this.status == PENDING; + } /** * A control is `disabled` when its `status` is `DISABLED`. @@ -242,7 +250,9 @@ export abstract class AbstractControl { * * @returns True if the control is disabled, false otherwise. */ - get disabled(): boolean { return this.status === DISABLED; } + get disabled(): boolean { + return this.status === DISABLED; + } /** * A control is `enabled` as long as its `status` is not `DISABLED`. @@ -253,14 +263,16 @@ export abstract class AbstractControl { * @see {@link AbstractControl.status} * */ - get enabled(): boolean { return this.status !== DISABLED; } + get enabled(): boolean { + return this.status !== DISABLED; + } /** * An object containing any errors generated by failing validation, * or null if there are no errors. */ // TODO(issue/24571): remove '!'. - public readonly errors !: ValidationErrors | null; + public readonly errors!: ValidationErrors|null; /** * A control is `pristine` if the user has not yet changed @@ -278,7 +290,9 @@ export abstract class AbstractControl { * @returns True if the user has changed the value of this control in the UI; compare `pristine`. * Programmatic changes to a control's value do not mark it dirty. */ - get dirty(): boolean { return !this.pristine; } + get dirty(): boolean { + return !this.pristine; + } /** * True if the control is marked as `touched`. @@ -294,7 +308,9 @@ export abstract class AbstractControl { * A control is `untouched` if the user has not yet triggered * a `blur` event on it. */ - get untouched(): boolean { return !this.touched; } + get untouched(): boolean { + return !this.touched; + } /** * A multicasting observable that emits an event every time the value of the control changes, in @@ -302,7 +318,7 @@ export abstract class AbstractControl { * without passing along {emitEvent: false} as a function argument. */ // TODO(issue/24571): remove '!'. - public readonly valueChanges !: Observable<any>; + public readonly valueChanges!: Observable<any>; /** * A multicasting observable that emits an event every time the validation `status` of the control @@ -312,7 +328,7 @@ export abstract class AbstractControl { * */ // TODO(issue/24571): remove '!'. - public readonly statusChanges !: Observable<any>; + public readonly statusChanges!: Observable<any>; /** * Reports the update strategy of the `AbstractControl` (meaning @@ -355,7 +371,9 @@ export abstract class AbstractControl { * `updateValueAndValidity()` for the new validation to take effect. * */ - clearValidators(): void { this.validator = null; } + clearValidators(): void { + this.validator = null; + } /** * Empties out the async validator list. @@ -364,7 +382,9 @@ export abstract class AbstractControl { * `updateValueAndValidity()` for the new validation to take effect. * */ - clearAsyncValidators(): void { this.asyncValidator = null; } + clearAsyncValidators(): void { + this.asyncValidator = null; + } /** * Marks the control as `touched`. A control is touched by focus and @@ -380,7 +400,7 @@ export abstract class AbstractControl { * marks all direct ancestors. Default is false. */ markAsTouched(opts: {onlySelf?: boolean} = {}): void { - (this as{touched: boolean}).touched = true; + (this as {touched: boolean}).touched = true; if (this._parent && !opts.onlySelf) { this._parent.markAsTouched(opts); @@ -413,11 +433,12 @@ export abstract class AbstractControl { * marks all direct ancestors. Default is false. */ markAsUntouched(opts: {onlySelf?: boolean} = {}): void { - (this as{touched: boolean}).touched = false; + (this as {touched: boolean}).touched = false; this._pendingTouched = false; - this._forEachChild( - (control: AbstractControl) => { control.markAsUntouched({onlySelf: true}); }); + this._forEachChild((control: AbstractControl) => { + control.markAsUntouched({onlySelf: true}); + }); if (this._parent && !opts.onlySelf) { this._parent._updateTouched(opts); @@ -438,7 +459,7 @@ export abstract class AbstractControl { * marks all direct ancestors. Default is false. */ markAsDirty(opts: {onlySelf?: boolean} = {}): void { - (this as{pristine: boolean}).pristine = false; + (this as {pristine: boolean}).pristine = false; if (this._parent && !opts.onlySelf) { this._parent.markAsDirty(opts); @@ -462,10 +483,12 @@ export abstract class AbstractControl { * marks all direct ancestors. Default is false.. */ markAsPristine(opts: {onlySelf?: boolean} = {}): void { - (this as{pristine: boolean}).pristine = true; + (this as {pristine: boolean}).pristine = true; this._pendingDirty = false; - this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); }); + this._forEachChild((control: AbstractControl) => { + control.markAsPristine({onlySelf: true}); + }); if (this._parent && !opts.onlySelf) { this._parent._updatePristine(opts); @@ -489,7 +512,7 @@ export abstract class AbstractControl { * */ markAsPending(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { - (this as{status: string}).status = PENDING; + (this as {status: string}).status = PENDING; if (opts.emitEvent !== false) { (this.statusChanges as EventEmitter<any>).emit(this.status); @@ -522,10 +545,11 @@ export abstract class AbstractControl { // parent's dirtiness based on the children. const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf); - (this as{status: string}).status = DISABLED; - (this as{errors: ValidationErrors | null}).errors = null; - this._forEachChild( - (control: AbstractControl) => { control.disable({...opts, onlySelf: true}); }); + (this as {status: string}).status = DISABLED; + (this as {errors: ValidationErrors | null}).errors = null; + this._forEachChild((control: AbstractControl) => { + control.disable({...opts, onlySelf: true}); + }); this._updateValue(); if (opts.emitEvent !== false) { @@ -560,9 +584,10 @@ export abstract class AbstractControl { // parent's dirtiness based on the children. const skipPristineCheck = this._parentMarkedDirty(opts.onlySelf); - (this as{status: string}).status = VALID; - this._forEachChild( - (control: AbstractControl) => { control.enable({...opts, onlySelf: true}); }); + (this as {status: string}).status = VALID; + this._forEachChild((control: AbstractControl) => { + control.enable({...opts, onlySelf: true}); + }); this.updateValueAndValidity({onlySelf: true, emitEvent: opts.emitEvent}); this._updateAncestors({...opts, skipPristineCheck}); @@ -583,7 +608,9 @@ export abstract class AbstractControl { /** * @param parent Sets the parent of the control */ - setParent(parent: FormGroup|FormArray): void { this._parent = parent; } + setParent(parent: FormGroup|FormArray): void { + this._parent = parent; + } /** * Sets the value of the control. Abstract method (implemented in sub-classes). @@ -620,8 +647,8 @@ export abstract class AbstractControl { if (this.enabled) { this._cancelExistingSubscription(); - (this as{errors: ValidationErrors | null}).errors = this._runValidator(); - (this as{status: string}).status = this._calculateStatus(); + (this as {errors: ValidationErrors | null}).errors = this._runValidator(); + (this as {status: string}).status = this._calculateStatus(); if (this.status === VALID || this.status === PENDING) { this._runAsyncValidator(opts.emitEvent); @@ -645,7 +672,7 @@ export abstract class AbstractControl { } private _setInitialStatus() { - (this as{status: string}).status = this._allControlsDisabled() ? DISABLED : VALID; + (this as {status: string}).status = this._allControlsDisabled() ? DISABLED : VALID; } private _runValidator(): ValidationErrors|null { @@ -654,10 +681,10 @@ export abstract class AbstractControl { private _runAsyncValidator(emitEvent?: boolean): void { if (this.asyncValidator) { - (this as{status: string}).status = PENDING; + (this as {status: string}).status = PENDING; const obs = toObservable(this.asyncValidator(this)); this._asyncValidationSubscription = - obs.subscribe((errors: ValidationErrors | null) => this.setErrors(errors, {emitEvent})); + obs.subscribe((errors: ValidationErrors|null) => this.setErrors(errors, {emitEvent})); } } @@ -690,7 +717,7 @@ export abstract class AbstractControl { * ``` */ setErrors(errors: ValidationErrors|null, opts: {emitEvent?: boolean} = {}): void { - (this as{errors: ValidationErrors | null}).errors = errors; + (this as {errors: ValidationErrors | null}).errors = errors; this._updateControlsErrors(opts.emitEvent !== false); } @@ -711,7 +738,9 @@ export abstract class AbstractControl { * * * `this.form.get(['person', 'name']);` */ - get(path: Array<string|number>|string): AbstractControl|null { return _find(this, path, '.'); } + get(path: Array<string|number>|string): AbstractControl|null { + return _find(this, path, '.'); + } /** * @description @@ -794,7 +823,7 @@ export abstract class AbstractControl { /** @internal */ _updateControlsErrors(emitEvent: boolean): void { - (this as{status: string}).status = this._calculateStatus(); + (this as {status: string}).status = this._calculateStatus(); if (emitEvent) { (this.statusChanges as EventEmitter<string>).emit(this.status); @@ -807,8 +836,8 @@ export abstract class AbstractControl { /** @internal */ _initObservables() { - (this as{valueChanges: Observable<any>}).valueChanges = new EventEmitter(); - (this as{statusChanges: Observable<any>}).statusChanges = new EventEmitter(); + (this as {valueChanges: Observable<any>}).valueChanges = new EventEmitter(); + (this as {statusChanges: Observable<any>}).statusChanges = new EventEmitter(); } @@ -852,7 +881,7 @@ export abstract class AbstractControl { /** @internal */ _updatePristine(opts: {onlySelf?: boolean} = {}): void { - (this as{pristine: boolean}).pristine = !this._anyControlsDirty(); + (this as {pristine: boolean}).pristine = !this._anyControlsDirty(); if (this._parent && !opts.onlySelf) { this._parent._updatePristine(opts); @@ -861,7 +890,7 @@ export abstract class AbstractControl { /** @internal */ _updateTouched(opts: {onlySelf?: boolean} = {}): void { - (this as{touched: boolean}).touched = this._anyControlsTouched(); + (this as {touched: boolean}).touched = this._anyControlsTouched(); if (this._parent && !opts.onlySelf) { this._parent._updateTouched(opts); @@ -878,12 +907,14 @@ export abstract class AbstractControl { } /** @internal */ - _registerOnCollectionChange(fn: () => void): void { this._onCollectionChange = fn; } + _registerOnCollectionChange(fn: () => void): void { + this._onCollectionChange = fn; + } /** @internal */ _setUpdateStrategy(opts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null): void { if (isOptionsObj(opts) && (opts as AbstractControlOptions).updateOn != null) { - this._updateOn = (opts as AbstractControlOptions).updateOn !; + this._updateOn = (opts as AbstractControlOptions).updateOn!; } } @@ -1006,18 +1037,18 @@ export class FormControl extends AbstractControl { _pendingChange: any; /** - * Creates a new `FormControl` instance. - * - * @param formState Initializes the control with an initial value, - * or an object that defines the initial value and disabled state. - * - * @param validatorOrOpts A synchronous validator function, or an array of - * such functions, or an `AbstractControlOptions` object that contains validation functions - * and a validation trigger. - * - * @param asyncValidator A single async validator or array of async validator functions - * - */ + * Creates a new `FormControl` instance. + * + * @param formState Initializes the control with an initial value, + * or an object that defines the initial value and disabled state. + * + * @param validatorOrOpts A synchronous validator function, or an array of + * such functions, or an `AbstractControlOptions` object that contains validation functions + * and a validation trigger. + * + * @param asyncValidator A single async validator or array of async validator functions + * + */ constructor( formState: any = null, validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null, @@ -1060,7 +1091,7 @@ export class FormControl extends AbstractControl { emitModelToViewChange?: boolean, emitViewToModelChange?: boolean } = {}): void { - (this as{value: any}).value = this._pendingValue = value; + (this as {value: any}).value = this._pendingValue = value; if (this._onChange.length && options.emitModelToViewChange !== false) { this._onChange.forEach( (changeFn) => changeFn(this.value, options.emitViewToModelChange !== false)); @@ -1120,19 +1151,25 @@ export class FormControl extends AbstractControl { /** * @internal */ - _anyControls(condition: Function): boolean { return false; } + _anyControls(condition: Function): boolean { + return false; + } /** * @internal */ - _allControlsDisabled(): boolean { return this.disabled; } + _allControlsDisabled(): boolean { + return this.disabled; + } /** * Register a listener for change events. * * @param fn The method that is called when the value changes */ - registerOnChange(fn: Function): void { this._onChange.push(fn); } + registerOnChange(fn: Function): void { + this._onChange.push(fn); + } /** * @internal @@ -1172,11 +1209,11 @@ export class FormControl extends AbstractControl { private _applyFormState(formState: any) { if (this._isBoxedValue(formState)) { - (this as{value: any}).value = this._pendingValue = formState.value; + (this as {value: any}).value = this._pendingValue = formState.value; formState.disabled ? this.disable({onlySelf: true, emitEvent: false}) : this.enable({onlySelf: true, emitEvent: false}); } else { - (this as{value: any}).value = this._pendingValue = formState; + (this as {value: any}).value = this._pendingValue = formState; } } } @@ -1255,18 +1292,18 @@ export class FormControl extends AbstractControl { */ export class FormGroup extends AbstractControl { /** - * Creates a new `FormGroup` instance. - * - * @param controls A collection of child controls. The key for each child is the name - * under which it is registered. - * - * @param validatorOrOpts A synchronous validator function, or an array of - * such functions, or an `AbstractControlOptions` object that contains validation functions - * and a validation trigger. - * - * @param asyncValidator A single async validator or array of async validator functions - * - */ + * Creates a new `FormGroup` instance. + * + * @param controls A collection of child controls. The key for each child is the name + * under which it is registered. + * + * @param validatorOrOpts A synchronous validator function, or an array of + * such functions, or an `AbstractControlOptions` object that contains validation functions + * and a validation trigger. + * + * @param asyncValidator A single async validator or array of async validator functions + * + */ constructor( public controls: {[key: string]: AbstractControl}, validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null, @@ -1556,7 +1593,9 @@ export class FormGroup extends AbstractControl { } /** @internal */ - _updateValue(): void { (this as{value: any}).value = this._reduceValue(); } + _updateValue(): void { + (this as {value: any}).value = this._reduceValue(); + } /** @internal */ _anyControls(condition: Function): boolean { @@ -1581,8 +1620,9 @@ export class FormGroup extends AbstractControl { /** @internal */ _reduceChildren(initValue: any, fn: Function) { let res = initValue; - this._forEachChild( - (control: AbstractControl, name: string) => { res = fn(res, control, name); }); + this._forEachChild((control: AbstractControl, name: string) => { + res = fn(res, control, name); + }); return res; } @@ -1647,7 +1687,7 @@ export class FormGroup extends AbstractControl { * ], {validators: myValidator, asyncValidators: myAsyncValidator}); * ``` * - * ### Set the updateOn property for all controls in a form array + * ### Set the updateOn property for all controls in a form array * * The options object is used to set a default value for each child * control's `updateOn` property. If you set `updateOn` to `'blur'` at the @@ -1672,18 +1712,18 @@ export class FormGroup extends AbstractControl { */ export class FormArray extends AbstractControl { /** - * Creates a new `FormArray` instance. - * - * @param controls An array of child controls. Each child control is given an index - * where it is registered. - * - * @param validatorOrOpts A synchronous validator function, or an array of - * such functions, or an `AbstractControlOptions` object that contains validation functions - * and a validation trigger. - * - * @param asyncValidator A single async validator or array of async validator functions - * - */ + * Creates a new `FormArray` instance. + * + * @param controls An array of child controls. Each child control is given an index + * where it is registered. + * + * @param validatorOrOpts A synchronous validator function, or an array of + * such functions, or an `AbstractControlOptions` object that contains validation functions + * and a validation trigger. + * + * @param asyncValidator A single async validator or array of async validator functions + * + */ constructor( public controls: AbstractControl[], validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null, @@ -1702,7 +1742,9 @@ export class FormArray extends AbstractControl { * * @param index Index in the array to retrieve the control */ - at(index: number): AbstractControl { return this.controls[index]; } + at(index: number): AbstractControl { + return this.controls[index]; + } /** * Insert a new `AbstractControl` at the end of the array. @@ -1762,7 +1804,9 @@ export class FormArray extends AbstractControl { /** * Length of the control array. */ - get length(): number { return this.controls.length; } + get length(): number { + return this.controls.length; + } /** * Sets the value of the `FormArray`. It accepts an array that matches @@ -1979,12 +2023,14 @@ export class FormArray extends AbstractControl { /** @internal */ _forEachChild(cb: Function): void { - this.controls.forEach((control: AbstractControl, index: number) => { cb(control, index); }); + this.controls.forEach((control: AbstractControl, index: number) => { + cb(control, index); + }); } /** @internal */ _updateValue(): void { - (this as{value: any}).value = + (this as {value: any}).value = this.controls.filter((control) => control.enabled || this.disabled) .map((control) => control.value); } diff --git a/packages/forms/src/validators.ts b/packages/forms/src/validators.ts index 0b7a171bf3d84..51bc05f4380d2 100644 --- a/packages/forms/src/validators.ts +++ b/packages/forms/src/validators.ts @@ -7,8 +7,9 @@ */ import {InjectionToken, ɵisObservable as isObservable, ɵisPromise as isPromise} from '@angular/core'; -import {Observable, forkJoin, from} from 'rxjs'; +import {forkJoin, from, Observable} from 'rxjs'; import {map} from 'rxjs/operators'; + import {AsyncValidatorFn, ValidationErrors, Validator, ValidatorFn} from './directives/validators'; import {AbstractControl, FormControl} from './model'; @@ -19,7 +20,8 @@ function isEmptyInputValue(value: any): boolean { /** * @description - * An `InjectionToken` for registering additional synchronous validators used with `AbstractControl`s. + * An `InjectionToken` for registering additional synchronous validators used with + * `AbstractControl`s. * * @see `NG_ASYNC_VALIDATORS` * @@ -48,7 +50,8 @@ export const NG_VALIDATORS = new InjectionToken<Array<Validator|Function>>('NgVa /** * @description - * An `InjectionToken` for registering additional asynchronous validators used with `AbstractControl`s. + * An `InjectionToken` for registering additional asynchronous validators used with + * `AbstractControl`s. * * @see `NG_VALIDATORS` * @@ -124,7 +127,7 @@ export class Validators { * */ static min(min: number): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { + return (control: AbstractControl): ValidationErrors|null => { if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) { return null; // don't validate empty values to allow optional controls } @@ -157,7 +160,7 @@ export class Validators { * */ static max(max: number): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { + return (control: AbstractControl): ValidationErrors|null => { if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) { return null; // don't validate empty values to allow optional controls } @@ -221,11 +224,13 @@ export class Validators { * @description * Validator that requires the control's value pass an email validation test. * - * Tests the value using a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) + * Tests the value using a [regular + * expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) * pattern suitable for common usecases. The pattern is based on the definition of a valid email - * address in the [WHATWG HTML specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) - * with some enhancements to incorporate more RFC rules (such as rules related to domain names and - * the lengths of different parts of the address). + * address in the [WHATWG HTML + * specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with + * some enhancements to incorporate more RFC rules (such as rules related to domain names and the + * lengths of different parts of the address). * * The differences from the WHATWG version include: * - Disallow `local-part` (the part before the `@` symbol) to begin or end with a period (`.`). @@ -285,7 +290,7 @@ export class Validators { * */ static minLength(minLength: number): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { + return (control: AbstractControl): ValidationErrors|null => { if (isEmptyInputValue(control.value)) { return null; // don't validate empty values to allow optional controls } @@ -323,7 +328,7 @@ export class Validators { * */ static maxLength(maxLength: number): ValidatorFn { - return (control: AbstractControl): ValidationErrors | null => { + return (control: AbstractControl): ValidationErrors|null => { const length: number = control.value ? control.value.length : 0; return length > maxLength ? {'maxlength': {'requiredLength': maxLength, 'actualLength': length}} : @@ -379,7 +384,7 @@ export class Validators { regexStr = pattern.toString(); regex = pattern; } - return (control: AbstractControl): ValidationErrors | null => { + return (control: AbstractControl): ValidationErrors|null => { if (isEmptyInputValue(control.value)) { return null; // don't validate empty values to allow optional controls } @@ -396,7 +401,9 @@ export class Validators { * @see `updateValueAndValidity()` * */ - static nullValidator(control: AbstractControl): ValidationErrors|null { return null; } + static nullValidator(control: AbstractControl): ValidationErrors|null { + return null; + } /** * @description @@ -469,8 +476,8 @@ function _mergeErrors(arrayOfErrors: ValidationErrors[]): ValidationErrors|null // Not using Array.reduce here due to a Chrome 80 bug // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982 - arrayOfErrors.forEach((errors: ValidationErrors | null) => { - res = errors != null ? {...res !, ...errors} : res !; + arrayOfErrors.forEach((errors: ValidationErrors|null) => { + res = errors != null ? {...res!, ...errors} : res!; }); return Object.keys(res).length === 0 ? null : res; diff --git a/packages/forms/test/directives_spec.ts b/packages/forms/test/directives_spec.ts index 0876818c2a489..06e72afbe53a5 100644 --- a/packages/forms/test/directives_spec.ts +++ b/packages/forms/test/directives_spec.ts @@ -19,22 +19,30 @@ class DummyControlValueAccessor implements ControlValueAccessor { registerOnChange(fn: any) {} registerOnTouched(fn: any) {} - writeValue(obj: any): void { this.writtenValue = obj; } + writeValue(obj: any): void { + this.writtenValue = obj; + } } class CustomValidatorDirective implements Validator { - validate(c: FormControl): ValidationErrors { return {'custom': true}; } + validate(c: FormControl): ValidationErrors { + return {'custom': true}; + } } function asyncValidator(expected: any, timeout = 0) { return (c: AbstractControl): any => { - let resolve: (result: any) => void = undefined !; - const promise = new Promise(res => { resolve = res; }); + let resolve: (result: any) => void = undefined!; + const promise = new Promise(res => { + resolve = res; + }); const res = c.value != expected ? {'async': true} : null; if (timeout == 0) { resolve(res); } else { - setTimeout(() => { resolve(res); }, timeout); + setTimeout(() => { + resolve(res); + }, timeout); } return promise; }; @@ -44,16 +52,21 @@ function asyncValidator(expected: any, timeout = 0) { describe('Form Directives', () => { let defaultAccessor: DefaultValueAccessor; - beforeEach(() => { defaultAccessor = new DefaultValueAccessor(null !, null !, null !); }); + beforeEach(() => { + defaultAccessor = new DefaultValueAccessor(null!, null!, null!); + }); describe('shared', () => { describe('selectValueAccessor', () => { let dir: NgControl; - beforeEach(() => { dir = <any>new SpyNgControl(); }); + beforeEach(() => { + dir = <any>new SpyNgControl(); + }); - it('should throw when given an empty array', - () => { expect(() => selectValueAccessor(dir, [])).toThrowError(); }); + it('should throw when given an empty array', () => { + expect(() => selectValueAccessor(dir, [])).toThrowError(); + }); it('should throw when accessor is not provided as array', () => { expect(() => selectValueAccessor(dir, {} as any[])) @@ -61,49 +74,51 @@ function asyncValidator(expected: any, timeout = 0) { `Value accessor was not provided as an array for form control with unspecified name attribute`); }); - it('should return the default value accessor when no other provided', - () => { expect(selectValueAccessor(dir, [defaultAccessor])).toEqual(defaultAccessor); }); + it('should return the default value accessor when no other provided', () => { + expect(selectValueAccessor(dir, [defaultAccessor])).toEqual(defaultAccessor); + }); it('should return checkbox accessor when provided', () => { - const checkboxAccessor = new CheckboxControlValueAccessor(null !, null !); + const checkboxAccessor = new CheckboxControlValueAccessor(null!, null!); expect(selectValueAccessor(dir, [ defaultAccessor, checkboxAccessor ])).toEqual(checkboxAccessor); }); it('should return select accessor when provided', () => { - const selectAccessor = new SelectControlValueAccessor(null !, null !); + const selectAccessor = new SelectControlValueAccessor(null!, null!); expect(selectValueAccessor(dir, [ defaultAccessor, selectAccessor ])).toEqual(selectAccessor); }); it('should return select multiple accessor when provided', () => { - const selectMultipleAccessor = new SelectMultipleControlValueAccessor(null !, null !); + const selectMultipleAccessor = new SelectMultipleControlValueAccessor(null!, null!); expect(selectValueAccessor(dir, [ defaultAccessor, selectMultipleAccessor ])).toEqual(selectMultipleAccessor); }); it('should throw when more than one build-in accessor is provided', () => { - const checkboxAccessor = new CheckboxControlValueAccessor(null !, null !); - const selectAccessor = new SelectControlValueAccessor(null !, null !); + const checkboxAccessor = new CheckboxControlValueAccessor(null!, null!); + const selectAccessor = new SelectControlValueAccessor(null!, null!); expect(() => selectValueAccessor(dir, [checkboxAccessor, selectAccessor])).toThrowError(); }); it('should return custom accessor when provided', () => { const customAccessor: ControlValueAccessor = new SpyValueAccessor() as any; - const checkboxAccessor = new CheckboxControlValueAccessor(null !, null !); - expect(selectValueAccessor(dir, <any>[defaultAccessor, customAccessor, checkboxAccessor])) - .toEqual(customAccessor); + const checkboxAccessor = new CheckboxControlValueAccessor(null!, null!); + expect(selectValueAccessor(dir, <any>[ + defaultAccessor, customAccessor, checkboxAccessor + ])).toEqual(customAccessor); }); it('should return custom accessor when provided with select multiple', () => { const customAccessor: ControlValueAccessor = new SpyValueAccessor() as any; - const selectMultipleAccessor = new SelectMultipleControlValueAccessor(null !, null !); - expect(selectValueAccessor( - dir, <any>[defaultAccessor, customAccessor, selectMultipleAccessor])) - .toEqual(customAccessor); + const selectMultipleAccessor = new SelectMultipleControlValueAccessor(null!, null!); + expect(selectValueAccessor(dir, <any>[ + defaultAccessor, customAccessor, selectMultipleAccessor + ])).toEqual(customAccessor); }); it('should throw when more than one custom accessor is provided', () => { @@ -116,13 +131,13 @@ function asyncValidator(expected: any, timeout = 0) { it('should compose functions', () => { const dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true}); const dummy2 = (_: any /** TODO #9100 */) => ({'dummy2': true}); - const v = composeValidators([dummy1, dummy2]) !; + const v = composeValidators([dummy1, dummy2])!; expect(v(new FormControl(''))).toEqual({'dummy1': true, 'dummy2': true}); }); it('should compose validator directives', () => { const dummy1 = (_: any /** TODO #9100 */) => ({'dummy1': true}); - const v = composeValidators([dummy1, new CustomValidatorDirective()]) !; + const v = composeValidators([dummy1, new CustomValidatorDirective()])!; expect(v(new FormControl(''))).toEqual({'dummy1': true, 'custom': true}); }); }); @@ -137,8 +152,8 @@ function asyncValidator(expected: any, timeout = 0) { form = new FormGroupDirective([], []); formModel = new FormGroup({ 'login': new FormControl(), - 'passwords': new FormGroup( - {'password': new FormControl(), 'passwordConfirm': new FormControl()}) + 'passwords': + new FormGroup({'password': new FormControl(), 'passwordConfirm': new FormControl()}) }); form.form = formModel; @@ -174,7 +189,7 @@ function asyncValidator(expected: any, timeout = 0) { describe('addControl', () => { it('should throw when no control found', () => { - const dir = new FormControlName(form, null !, null !, [defaultAccessor], null); + const dir = new FormControlName(form, null!, null!, [defaultAccessor], null); dir.name = 'invalidName'; expect(() => form.addControl(dir)) @@ -182,7 +197,7 @@ function asyncValidator(expected: any, timeout = 0) { }); it('should throw for a named control when no value accessor', () => { - const dir = new FormControlName(form, null !, null !, null !, null); + const dir = new FormControlName(form, null!, null!, null!, null); dir.name = 'login'; expect(() => form.addControl(dir)) @@ -190,8 +205,8 @@ function asyncValidator(expected: any, timeout = 0) { }); it('should throw when no value accessor with path', () => { - const group = new FormGroupName(form, null !, null !); - const dir = new FormControlName(group, null !, null !, null !, null); + const group = new FormGroupName(form, null!, null!); + const dir = new FormControlName(group, null!, null!, null!, null); group.name = 'passwords'; dir.name = 'password'; @@ -321,7 +336,7 @@ function asyncValidator(expected: any, timeout = 0) { personControlGroupDir = new NgModelGroup(form, [], []); personControlGroupDir.name = 'person'; - loginControlDir = new NgModel(personControlGroupDir, null !, null !, [defaultAccessor]); + loginControlDir = new NgModel(personControlGroupDir, null!, null!, [defaultAccessor]); loginControlDir.name = 'login'; loginControlDir.valueAccessor = new DummyControlValueAccessor(); }); @@ -509,7 +524,9 @@ function asyncValidator(expected: any, timeout = 0) { controlDir.form = control; }); - it('should reexport control properties', () => { checkProperties(control); }); + it('should reexport control properties', () => { + checkProperties(control); + }); it('should reexport control methods', () => { expect(controlDir.hasError('required')).toBe(control.hasError('required')); @@ -544,7 +561,7 @@ function asyncValidator(expected: any, timeout = 0) { beforeEach(() => { ngModel = new NgModel( - null !, [Validators.required], [asyncValidator('expected')], [defaultAccessor]); + null!, [Validators.required], [asyncValidator('expected')], [defaultAccessor]); ngModel.valueAccessor = new DummyControlValueAccessor(); control = ngModel.control; }); @@ -577,7 +594,7 @@ function asyncValidator(expected: any, timeout = 0) { }); it('should throw when no value accessor with named control', () => { - const namedDir = new NgModel(null !, null !, null !, null !); + const namedDir = new NgModel(null!, null!, null!, null!); namedDir.name = 'one'; expect(() => namedDir.ngOnChanges({})) @@ -585,7 +602,7 @@ function asyncValidator(expected: any, timeout = 0) { }); it('should throw when no value accessor with unnamed control', () => { - const unnamedDir = new NgModel(null !, null !, null !, null !); + const unnamedDir = new NgModel(null!, null!, null!, null!); expect(() => unnamedDir.ngOnChanges({})) .toThrowError( @@ -641,7 +658,6 @@ function asyncValidator(expected: any, timeout = 0) { ngModel.ngOnChanges({isDisabled: new SimpleChange(null, 'anything else', false)}); tick(); expect(ngModel.control.disabled).toEqual(true); - })); }); @@ -656,7 +672,7 @@ function asyncValidator(expected: any, timeout = 0) { parent.form = new FormGroup({'name': formModel}); controlNameDir = new FormControlName(parent, [], [], [defaultAccessor], null); controlNameDir.name = 'name'; - (controlNameDir as{control: FormControl}).control = formModel; + (controlNameDir as {control: FormControl}).control = formModel; }); it('should reexport control properties', () => { diff --git a/packages/forms/test/form_array_spec.ts b/packages/forms/test/form_array_spec.ts index 6bac92e453617..1bdc729233621 100644 --- a/packages/forms/test/form_array_spec.ts +++ b/packages/forms/test/form_array_spec.ts @@ -10,1229 +10,1263 @@ import {fakeAsync, tick} from '@angular/core/testing'; import {AsyncTestCompleter, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; import {AbstractControl, FormArray, FormControl, FormGroup, ValidationErrors, ValidatorFn} from '@angular/forms'; import {Validators} from '@angular/forms/src/validators'; -import {of } from 'rxjs'; +import {of} from 'rxjs'; (function() { - function asyncValidator(expected: string, timeouts = {}) { - return (c: AbstractControl) => { - let resolve: (result: any) => void = undefined !; - const promise = new Promise<ValidationErrors|null>(res => { resolve = res; }); - const t = (timeouts as any)[c.value] != null ? (timeouts as any)[c.value] : 0; - const res = c.value != expected ? {'async': true} : null; - - if (t == 0) { +function asyncValidator(expected: string, timeouts = {}) { + return (c: AbstractControl) => { + let resolve: (result: any) => void = undefined!; + const promise = new Promise<ValidationErrors|null>(res => { + resolve = res; + }); + const t = (timeouts as any)[c.value] != null ? (timeouts as any)[c.value] : 0; + const res = c.value != expected ? {'async': true} : null; + + if (t == 0) { + resolve(res); + } else { + setTimeout(() => { resolve(res); - } else { - setTimeout(() => { resolve(res); }, t); - } + }, t); + } + + return promise; + }; +} + +describe('FormArray', () => { + describe('adding/removing', () => { + let a: FormArray; + let c1: FormControl, c2: FormControl, c3: FormControl; + + beforeEach(() => { + a = new FormArray([]); + c1 = new FormControl(1); + c2 = new FormControl(2); + c3 = new FormControl(3); + }); - return promise; - }; - } + it('should support pushing', () => { + a.push(c1); + expect(a.length).toEqual(1); + expect(a.controls).toEqual([c1]); + }); - describe('FormArray', () => { + it('should support removing', () => { + a.push(c1); + a.push(c2); + a.push(c3); - describe('adding/removing', () => { - let a: FormArray; - let c1: FormControl, c2: FormControl, c3: FormControl; + a.removeAt(1); - beforeEach(() => { - a = new FormArray([]); - c1 = new FormControl(1); - c2 = new FormControl(2); - c3 = new FormControl(3); - }); + expect(a.controls).toEqual([c1, c3]); + }); - it('should support pushing', () => { - a.push(c1); - expect(a.length).toEqual(1); - expect(a.controls).toEqual([c1]); - }); + it('should support clearing', () => { + a.push(c1); + a.push(c2); + a.push(c3); - it('should support removing', () => { - a.push(c1); - a.push(c2); - a.push(c3); + a.clear(); - a.removeAt(1); + expect(a.controls).toEqual([]); - expect(a.controls).toEqual([c1, c3]); - }); + a.clear(); - it('should support clearing', () => { - a.push(c1); - a.push(c2); - a.push(c3); + expect(a.controls).toEqual([]); + }); - a.clear(); + it('should support inserting', () => { + a.push(c1); + a.push(c3); - expect(a.controls).toEqual([]); + a.insert(1, c2); - a.clear(); + expect(a.controls).toEqual([c1, c2, c3]); + }); + }); - expect(a.controls).toEqual([]); - }); + describe('value', () => { + it('should be the reduced value of the child controls', () => { + const a = new FormArray([new FormControl(1), new FormControl(2)]); + expect(a.value).toEqual([1, 2]); + }); + + it('should be an empty array when there are no child controls', () => { + const a = new FormArray([]); + expect(a.value).toEqual([]); + }); + }); - it('should support inserting', () => { - a.push(c1); - a.push(c3); + describe('getRawValue()', () => { + let a: FormArray; - a.insert(1, c2); + it('should work with nested form groups/arrays', () => { + a = new FormArray([ + new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), + new FormArray([new FormControl('v4'), new FormControl('v5')]) + ]); + a.at(0).get('c3')!.disable(); + (a.at(1) as FormArray).at(1).disable(); - expect(a.controls).toEqual([c1, c2, c3]); - }); + expect(a.getRawValue()).toEqual([{'c2': 'v2', 'c3': 'v3'}, ['v4', 'v5']]); }); + }); - describe('value', () => { - it('should be the reduced value of the child controls', () => { - const a = new FormArray([new FormControl(1), new FormControl(2)]); - expect(a.value).toEqual([1, 2]); - }); + describe('markAllAsTouched', () => { + it('should mark all descendants as touched', () => { + const formArray: FormArray = new FormArray([ + new FormControl('v1'), new FormControl('v2'), new FormGroup({'c1': new FormControl('v1')}), + new FormArray([new FormGroup({'c2': new FormControl('v2')})]) + ]); - it('should be an empty array when there are no child controls', () => { - const a = new FormArray([]); - expect(a.value).toEqual([]); - }); - }); + expect(formArray.touched).toBe(false); - describe('getRawValue()', () => { - let a: FormArray; + const control1 = formArray.at(0) as FormControl; - it('should work with nested form groups/arrays', () => { - a = new FormArray([ - new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), - new FormArray([new FormControl('v4'), new FormControl('v5')]) - ]); - a.at(0).get('c3') !.disable(); - (a.at(1) as FormArray).at(1).disable(); + expect(control1.touched).toBe(false); - expect(a.getRawValue()).toEqual([{'c2': 'v2', 'c3': 'v3'}, ['v4', 'v5']]); - }); - }); + const group1 = formArray.at(2) as FormGroup; + + expect(group1.touched).toBe(false); + + const group1Control1 = group1.get('c1') as FormControl; + + expect(group1Control1.touched).toBe(false); + + const innerFormArray = formArray.at(3) as FormArray; - describe('markAllAsTouched', () => { - it('should mark all descendants as touched', () => { - const formArray: FormArray = new FormArray([ - new FormControl('v1'), new FormControl('v2'), - new FormGroup({'c1': new FormControl('v1')}), - new FormArray([new FormGroup({'c2': new FormControl('v2')})]) - ]); + expect(innerFormArray.touched).toBe(false); - expect(formArray.touched).toBe(false); + const innerFormArrayGroup = innerFormArray.at(0) as FormGroup; - const control1 = formArray.at(0) as FormControl; + expect(innerFormArrayGroup.touched).toBe(false); - expect(control1.touched).toBe(false); + const innerFormArrayGroupControl1 = innerFormArrayGroup.get('c2') as FormControl; - const group1 = formArray.at(2) as FormGroup; + expect(innerFormArrayGroupControl1.touched).toBe(false); - expect(group1.touched).toBe(false); + formArray.markAllAsTouched(); - const group1Control1 = group1.get('c1') as FormControl; + expect(formArray.touched).toBe(true); - expect(group1Control1.touched).toBe(false); + expect(control1.touched).toBe(true); - const innerFormArray = formArray.at(3) as FormArray; + expect(group1.touched).toBe(true); - expect(innerFormArray.touched).toBe(false); + expect(group1Control1.touched).toBe(true); - const innerFormArrayGroup = innerFormArray.at(0) as FormGroup; + expect(innerFormArray.touched).toBe(true); - expect(innerFormArrayGroup.touched).toBe(false); + expect(innerFormArrayGroup.touched).toBe(true); - const innerFormArrayGroupControl1 = innerFormArrayGroup.get('c2') as FormControl; + expect(innerFormArrayGroupControl1.touched).toBe(true); + }); + }); - expect(innerFormArrayGroupControl1.touched).toBe(false); + describe('setValue', () => { + let c: FormControl, c2: FormControl, a: FormArray; - formArray.markAllAsTouched(); + beforeEach(() => { + c = new FormControl(''); + c2 = new FormControl(''); + a = new FormArray([c, c2]); + }); - expect(formArray.touched).toBe(true); + it('should set its own value', () => { + a.setValue(['one', 'two']); + expect(a.value).toEqual(['one', 'two']); + }); - expect(control1.touched).toBe(true); + it('should set child values', () => { + a.setValue(['one', 'two']); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + }); - expect(group1.touched).toBe(true); + it('should set values for disabled child controls', () => { + c2.disable(); + a.setValue(['one', 'two']); + expect(c2.value).toEqual('two'); + expect(a.value).toEqual(['one']); + expect(a.getRawValue()).toEqual(['one', 'two']); + }); - expect(group1Control1.touched).toBe(true); + it('should set value for disabled arrays', () => { + a.disable(); + a.setValue(['one', 'two']); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + expect(a.value).toEqual(['one', 'two']); + }); - expect(innerFormArray.touched).toBe(true); + it('should set parent values', () => { + const form = new FormGroup({'parent': a}); + a.setValue(['one', 'two']); + expect(form.value).toEqual({'parent': ['one', 'two']}); + }); - expect(innerFormArrayGroup.touched).toBe(true); + it('should not update the parent explicitly specified', () => { + const form = new FormGroup({'parent': a}); + a.setValue(['one', 'two'], {onlySelf: true}); - expect(innerFormArrayGroupControl1.touched).toBe(true); - }); + expect(form.value).toEqual({parent: ['', '']}); + }); + + it('should throw if fields are missing from supplied value (subset)', () => { + expect(() => a.setValue([, 'two'])) + .toThrowError(new RegExp(`Must supply a value for form control at index: 0`)); + }); + + it('should throw if a value is provided for a missing control (superset)', () => { + expect(() => a.setValue([ + 'one', 'two', 'three' + ])).toThrowError(new RegExp(`Cannot find form control at index 2`)); }); - describe('setValue', () => { - let c: FormControl, c2: FormControl, a: FormArray; + it('should throw if a value is not provided for a disabled control', () => { + c2.disable(); + expect(() => a.setValue(['one'])) + .toThrowError(new RegExp(`Must supply a value for form control at index: 1`)); + }); + + it('should throw if no controls are set yet', () => { + const empty = new FormArray([]); + expect(() => empty.setValue(['one'])) + .toThrowError(new RegExp(`no form controls registered with this array`)); + }); + + describe('setValue() events', () => { + let form: FormGroup; + let logger: any[]; beforeEach(() => { - c = new FormControl(''); - c2 = new FormControl(''); - a = new FormArray([c, c2]); + form = new FormGroup({'parent': a}); + logger = []; }); - it('should set its own value', () => { - a.setValue(['one', 'two']); - expect(a.value).toEqual(['one', 'two']); - }); + it('should emit one valueChange event per control', () => { + form.valueChanges.subscribe(() => logger.push('form')); + a.valueChanges.subscribe(() => logger.push('array')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - it('should set child values', () => { a.setValue(['one', 'two']); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); + expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); - it('should set values for disabled child controls', () => { - c2.disable(); - a.setValue(['one', 'two']); - expect(c2.value).toEqual('two'); - expect(a.value).toEqual(['one']); - expect(a.getRawValue()).toEqual(['one', 'two']); - }); + it('should not fire an event when explicitly specified', fakeAsync(() => { + form.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + a.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c2.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); - it('should set value for disabled arrays', () => { - a.disable(); - a.setValue(['one', 'two']); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); - expect(a.value).toEqual(['one', 'two']); - }); + a.setValue(['one', 'two'], {emitEvent: false}); + tick(); + })); + + it('should emit one statusChange event per control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + a.statusChanges.subscribe(() => logger.push('array')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); - it('should set parent values', () => { - const form = new FormGroup({'parent': a}); a.setValue(['one', 'two']); - expect(form.value).toEqual({'parent': ['one', 'two']}); + expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); + }); + }); - it('should not update the parent explicitly specified', () => { - const form = new FormGroup({'parent': a}); - a.setValue(['one', 'two'], {onlySelf: true}); + describe('patchValue', () => { + let c: FormControl, c2: FormControl, a: FormArray; - expect(form.value).toEqual({parent: ['', '']}); - }); + beforeEach(() => { + c = new FormControl(''); + c2 = new FormControl(''); + a = new FormArray([c, c2]); + }); - it('should throw if fields are missing from supplied value (subset)', () => { - expect(() => a.setValue([, 'two'])) - .toThrowError(new RegExp(`Must supply a value for form control at index: 0`)); - }); + it('should set its own value', () => { + a.patchValue(['one', 'two']); + expect(a.value).toEqual(['one', 'two']); + }); - it('should throw if a value is provided for a missing control (superset)', () => { - expect(() => a.setValue([ - 'one', 'two', 'three' - ])).toThrowError(new RegExp(`Cannot find form control at index 2`)); - }); + it('should set child values', () => { + a.patchValue(['one', 'two']); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + }); - it('should throw if a value is not provided for a disabled control', () => { - c2.disable(); - expect(() => a.setValue(['one'])) - .toThrowError(new RegExp(`Must supply a value for form control at index: 1`)); - }); + it('should patch disabled control values', () => { + c2.disable(); + a.patchValue(['one', 'two']); + expect(c2.value).toEqual('two'); + expect(a.value).toEqual(['one']); + expect(a.getRawValue()).toEqual(['one', 'two']); + }); - it('should throw if no controls are set yet', () => { - const empty = new FormArray([]); - expect(() => empty.setValue(['one'])) - .toThrowError(new RegExp(`no form controls registered with this array`)); - }); + it('should patch disabled control arrays', () => { + a.disable(); + a.patchValue(['one', 'two']); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + expect(a.value).toEqual(['one', 'two']); + }); - describe('setValue() events', () => { - let form: FormGroup; - let logger: any[]; - - beforeEach(() => { - form = new FormGroup({'parent': a}); - logger = []; - }); - - it('should emit one valueChange event per control', () => { - form.valueChanges.subscribe(() => logger.push('form')); - a.valueChanges.subscribe(() => logger.push('array')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - - a.setValue(['one', 'two']); - expect(logger).toEqual(['control1', 'control2', 'array', 'form']); - }); - - it('should not fire an event when explicitly specified', fakeAsync(() => { - form.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - a.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c2.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - - a.setValue(['one', 'two'], {emitEvent: false}); - tick(); - })); - - it('should emit one statusChange event per control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - a.statusChanges.subscribe(() => logger.push('array')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - - a.setValue(['one', 'two']); - expect(logger).toEqual(['control1', 'control2', 'array', 'form']); - }); - }); + it('should set parent values', () => { + const form = new FormGroup({'parent': a}); + a.patchValue(['one', 'two']); + expect(form.value).toEqual({'parent': ['one', 'two']}); + }); + + it('should not update the parent explicitly specified', () => { + const form = new FormGroup({'parent': a}); + a.patchValue(['one', 'two'], {onlySelf: true}); + + expect(form.value).toEqual({parent: ['', '']}); + }); + + it('should ignore fields that are missing from supplied value (subset)', () => { + a.patchValue([, 'two']); + expect(a.value).toEqual(['', 'two']); + }); + + it('should not ignore fields that are null', () => { + a.patchValue([null]); + expect(a.value).toEqual([null, '']); }); - describe('patchValue', () => { - let c: FormControl, c2: FormControl, a: FormArray; + it('should ignore any value provided for a missing control (superset)', () => { + a.patchValue([, , 'three']); + expect(a.value).toEqual(['', '']); + }); + + describe('patchValue() events', () => { + let form: FormGroup; + let logger: any[]; beforeEach(() => { - c = new FormControl(''); - c2 = new FormControl(''); - a = new FormArray([c, c2]); + form = new FormGroup({'parent': a}); + logger = []; }); - it('should set its own value', () => { - a.patchValue(['one', 'two']); - expect(a.value).toEqual(['one', 'two']); - }); + it('should emit one valueChange event per control', () => { + form.valueChanges.subscribe(() => logger.push('form')); + a.valueChanges.subscribe(() => logger.push('array')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - it('should set child values', () => { a.patchValue(['one', 'two']); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); + expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); - it('should patch disabled control values', () => { - c2.disable(); - a.patchValue(['one', 'two']); - expect(c2.value).toEqual('two'); - expect(a.value).toEqual(['one']); - expect(a.getRawValue()).toEqual(['one', 'two']); - }); + it('should not emit valueChange events for skipped controls', () => { + form.valueChanges.subscribe(() => logger.push('form')); + a.valueChanges.subscribe(() => logger.push('array')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - it('should patch disabled control arrays', () => { - a.disable(); - a.patchValue(['one', 'two']); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); - expect(a.value).toEqual(['one', 'two']); + a.patchValue(['one']); + expect(logger).toEqual(['control1', 'array', 'form']); }); - it('should set parent values', () => { - const form = new FormGroup({'parent': a}); + it('should not fire an event when explicitly specified', fakeAsync(() => { + form.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + a.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c2.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + + a.patchValue(['one', 'two'], {emitEvent: false}); + tick(); + })); + + it('should emit one statusChange event per control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + a.statusChanges.subscribe(() => logger.push('array')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); + a.patchValue(['one', 'two']); - expect(form.value).toEqual({'parent': ['one', 'two']}); + expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); + }); + }); - it('should not update the parent explicitly specified', () => { - const form = new FormGroup({'parent': a}); - a.patchValue(['one', 'two'], {onlySelf: true}); + describe('reset()', () => { + let c: FormControl, c2: FormControl, a: FormArray; - expect(form.value).toEqual({parent: ['', '']}); - }); + beforeEach(() => { + c = new FormControl('initial value'); + c2 = new FormControl(''); + a = new FormArray([c, c2]); + }); - it('should ignore fields that are missing from supplied value (subset)', () => { - a.patchValue([, 'two']); - expect(a.value).toEqual(['', 'two']); - }); + it('should set its own value if value passed', () => { + a.setValue(['new value', 'new value']); - it('should not ignore fields that are null', () => { - a.patchValue([null]); - expect(a.value).toEqual([null, '']); - }); + a.reset(['initial value', '']); + expect(a.value).toEqual(['initial value', '']); + }); - it('should ignore any value provided for a missing control (superset)', () => { - a.patchValue([, , 'three']); - expect(a.value).toEqual(['', '']); - }); + it('should not update the parent when explicitly specified', () => { + const form = new FormGroup({'a': a}); + a.reset(['one', 'two'], {onlySelf: true}); - describe('patchValue() events', () => { - let form: FormGroup; - let logger: any[]; - - beforeEach(() => { - form = new FormGroup({'parent': a}); - logger = []; - }); - - it('should emit one valueChange event per control', () => { - form.valueChanges.subscribe(() => logger.push('form')); - a.valueChanges.subscribe(() => logger.push('array')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - - a.patchValue(['one', 'two']); - expect(logger).toEqual(['control1', 'control2', 'array', 'form']); - }); - - it('should not emit valueChange events for skipped controls', () => { - form.valueChanges.subscribe(() => logger.push('form')); - a.valueChanges.subscribe(() => logger.push('array')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - - a.patchValue(['one']); - expect(logger).toEqual(['control1', 'array', 'form']); - }); - - it('should not fire an event when explicitly specified', fakeAsync(() => { - form.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - a.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c2.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - - a.patchValue(['one', 'two'], {emitEvent: false}); - tick(); - })); - - it('should emit one statusChange event per control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - a.statusChanges.subscribe(() => logger.push('array')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - - a.patchValue(['one', 'two']); - expect(logger).toEqual(['control1', 'control2', 'array', 'form']); - }); - }); + expect(form.value).toEqual({a: ['initial value', '']}); }); - describe('reset()', () => { - let c: FormControl, c2: FormControl, a: FormArray; + it('should set its own value if boxed value passed', () => { + a.setValue(['new value', 'new value']); - beforeEach(() => { - c = new FormControl('initial value'); - c2 = new FormControl(''); - a = new FormArray([c, c2]); - }); + a.reset([{value: 'initial value', disabled: false}, '']); + expect(a.value).toEqual(['initial value', '']); + }); - it('should set its own value if value passed', () => { - a.setValue(['new value', 'new value']); + it('should clear its own value if no value passed', () => { + a.setValue(['new value', 'new value']); - a.reset(['initial value', '']); - expect(a.value).toEqual(['initial value', '']); - }); + a.reset(); + expect(a.value).toEqual([null, null]); + }); - it('should not update the parent when explicitly specified', () => { - const form = new FormGroup({'a': a}); - a.reset(['one', 'two'], {onlySelf: true}); + it('should set the value of each of its child controls if value passed', () => { + a.setValue(['new value', 'new value']); - expect(form.value).toEqual({a: ['initial value', '']}); - }); + a.reset(['initial value', '']); + expect(c.value).toBe('initial value'); + expect(c2.value).toBe(''); + }); - it('should set its own value if boxed value passed', () => { - a.setValue(['new value', 'new value']); + it('should clear the value of each of its child controls if no value', () => { + a.setValue(['new value', 'new value']); - a.reset([{value: 'initial value', disabled: false}, '']); - expect(a.value).toEqual(['initial value', '']); - }); + a.reset(); + expect(c.value).toBe(null); + expect(c2.value).toBe(null); + }); - it('should clear its own value if no value passed', () => { - a.setValue(['new value', 'new value']); + it('should set the value of its parent if value passed', () => { + const form = new FormGroup({'a': a}); + a.setValue(['new value', 'new value']); - a.reset(); - expect(a.value).toEqual([null, null]); - }); + a.reset(['initial value', '']); + expect(form.value).toEqual({'a': ['initial value', '']}); + }); - it('should set the value of each of its child controls if value passed', () => { - a.setValue(['new value', 'new value']); + it('should clear the value of its parent if no value passed', () => { + const form = new FormGroup({'a': a}); + a.setValue(['new value', 'new value']); - a.reset(['initial value', '']); - expect(c.value).toBe('initial value'); - expect(c2.value).toBe(''); - }); + a.reset(); + expect(form.value).toEqual({'a': [null, null]}); + }); - it('should clear the value of each of its child controls if no value', () => { - a.setValue(['new value', 'new value']); + it('should mark itself as pristine', () => { + a.markAsDirty(); + expect(a.pristine).toBe(false); - a.reset(); - expect(c.value).toBe(null); - expect(c2.value).toBe(null); - }); + a.reset(); + expect(a.pristine).toBe(true); + }); - it('should set the value of its parent if value passed', () => { - const form = new FormGroup({'a': a}); - a.setValue(['new value', 'new value']); + it('should mark all child controls as pristine', () => { + c.markAsDirty(); + c2.markAsDirty(); + expect(c.pristine).toBe(false); + expect(c2.pristine).toBe(false); - a.reset(['initial value', '']); - expect(form.value).toEqual({'a': ['initial value', '']}); - }); + a.reset(); + expect(c.pristine).toBe(true); + expect(c2.pristine).toBe(true); + }); - it('should clear the value of its parent if no value passed', () => { - const form = new FormGroup({'a': a}); - a.setValue(['new value', 'new value']); + it('should mark the parent as pristine if all siblings pristine', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'a': a, 'c3': c3}); - a.reset(); - expect(form.value).toEqual({'a': [null, null]}); - }); + a.markAsDirty(); + expect(form.pristine).toBe(false); - it('should mark itself as pristine', () => { - a.markAsDirty(); - expect(a.pristine).toBe(false); + a.reset(); + expect(form.pristine).toBe(true); + }); - a.reset(); - expect(a.pristine).toBe(true); - }); + it('should not mark the parent pristine if any dirty siblings', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'a': a, 'c3': c3}); - it('should mark all child controls as pristine', () => { - c.markAsDirty(); - c2.markAsDirty(); - expect(c.pristine).toBe(false); - expect(c2.pristine).toBe(false); + a.markAsDirty(); + c3.markAsDirty(); + expect(form.pristine).toBe(false); - a.reset(); - expect(c.pristine).toBe(true); - expect(c2.pristine).toBe(true); - }); + a.reset(); + expect(form.pristine).toBe(false); + }); - it('should mark the parent as pristine if all siblings pristine', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'a': a, 'c3': c3}); + it('should mark itself as untouched', () => { + a.markAsTouched(); + expect(a.untouched).toBe(false); - a.markAsDirty(); - expect(form.pristine).toBe(false); + a.reset(); + expect(a.untouched).toBe(true); + }); - a.reset(); - expect(form.pristine).toBe(true); - }); + it('should mark all child controls as untouched', () => { + c.markAsTouched(); + c2.markAsTouched(); + expect(c.untouched).toBe(false); + expect(c2.untouched).toBe(false); + + a.reset(); + expect(c.untouched).toBe(true); + expect(c2.untouched).toBe(true); + }); - it('should not mark the parent pristine if any dirty siblings', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'a': a, 'c3': c3}); + it('should mark the parent untouched if all siblings untouched', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'a': a, 'c3': c3}); - a.markAsDirty(); - c3.markAsDirty(); - expect(form.pristine).toBe(false); + a.markAsTouched(); + expect(form.untouched).toBe(false); - a.reset(); - expect(form.pristine).toBe(false); - }); + a.reset(); + expect(form.untouched).toBe(true); + }); - it('should mark itself as untouched', () => { - a.markAsTouched(); - expect(a.untouched).toBe(false); + it('should not mark the parent untouched if any touched siblings', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'a': a, 'c3': c3}); - a.reset(); - expect(a.untouched).toBe(true); + a.markAsTouched(); + c3.markAsTouched(); + expect(form.untouched).toBe(false); + + a.reset(); + expect(form.untouched).toBe(false); + }); + + it('should retain previous disabled state', () => { + a.disable(); + a.reset(); + + expect(a.disabled).toBe(true); + }); + + it('should set child disabled state if boxed value passed', () => { + a.disable(); + a.reset([{value: '', disabled: false}, '']); + + expect(c.disabled).toBe(false); + expect(a.disabled).toBe(false); + }); + + + describe('reset() events', () => { + let form: FormGroup, c3: FormControl, logger: any[]; + + beforeEach(() => { + c3 = new FormControl(''); + form = new FormGroup({'a': a, 'c3': c3}); + logger = []; }); - it('should mark all child controls as untouched', () => { - c.markAsTouched(); - c2.markAsTouched(); - expect(c.untouched).toBe(false); - expect(c2.untouched).toBe(false); + it('should emit one valueChange event per reset control', () => { + form.valueChanges.subscribe(() => logger.push('form')); + a.valueChanges.subscribe(() => logger.push('array')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); + c3.valueChanges.subscribe(() => logger.push('control3')); a.reset(); - expect(c.untouched).toBe(true); - expect(c2.untouched).toBe(true); + expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); - it('should mark the parent untouched if all siblings untouched', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'a': a, 'c3': c3}); + it('should not fire an event when explicitly specified', fakeAsync(() => { + form.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + a.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c2.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c3.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + + a.reset([], {emitEvent: false}); + tick(); + })); - a.markAsTouched(); - expect(form.untouched).toBe(false); + it('should emit one statusChange event per reset control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + a.statusChanges.subscribe(() => logger.push('array')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); + c3.statusChanges.subscribe(() => logger.push('control3')); a.reset(); - expect(form.untouched).toBe(true); + expect(logger).toEqual(['control1', 'control2', 'array', 'form']); }); - it('should not mark the parent untouched if any touched siblings', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'a': a, 'c3': c3}); + it('should mark as pristine and not dirty before emitting valueChange and statusChange events when resetting', + () => { + const pristineAndNotDirty = () => { + expect(a.pristine).toBe(true); + expect(a.dirty).toBe(false); + }; - a.markAsTouched(); - c3.markAsTouched(); - expect(form.untouched).toBe(false); + c2.markAsDirty(); + expect(a.pristine).toBe(false); + expect(a.dirty).toBe(true); - a.reset(); - expect(form.untouched).toBe(false); - }); + a.valueChanges.subscribe(pristineAndNotDirty); + a.statusChanges.subscribe(pristineAndNotDirty); - it('should retain previous disabled state', () => { - a.disable(); - a.reset(); + a.reset(); + }); + }); + }); - expect(a.disabled).toBe(true); - }); + describe('errors', () => { + it('should run the validator when the value changes', () => { + const simpleValidator = (c: FormArray) => + c.controls[0].value != 'correct' ? {'broken': true} : null; - it('should set child disabled state if boxed value passed', () => { - a.disable(); - a.reset([{value: '', disabled: false}, '']); + const c = new FormControl(null); + const g = new FormArray([c], simpleValidator as ValidatorFn); - expect(c.disabled).toBe(false); - expect(a.disabled).toBe(false); - }); + c.setValue('correct'); + expect(g.valid).toEqual(true); + expect(g.errors).toEqual(null); - describe('reset() events', () => { - let form: FormGroup, c3: FormControl, logger: any[]; - - beforeEach(() => { - c3 = new FormControl(''); - form = new FormGroup({'a': a, 'c3': c3}); - logger = []; - }); - - it('should emit one valueChange event per reset control', () => { - form.valueChanges.subscribe(() => logger.push('form')); - a.valueChanges.subscribe(() => logger.push('array')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - c3.valueChanges.subscribe(() => logger.push('control3')); - - a.reset(); - expect(logger).toEqual(['control1', 'control2', 'array', 'form']); - }); - - it('should not fire an event when explicitly specified', fakeAsync(() => { - form.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - a.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c2.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c3.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - - a.reset([], {emitEvent: false}); - tick(); - })); - - it('should emit one statusChange event per reset control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - a.statusChanges.subscribe(() => logger.push('array')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - c3.statusChanges.subscribe(() => logger.push('control3')); - - a.reset(); - expect(logger).toEqual(['control1', 'control2', 'array', 'form']); - }); - - it('should mark as pristine and not dirty before emitting valueChange and statusChange events when resetting', - () => { - const pristineAndNotDirty = () => { - expect(a.pristine).toBe(true); - expect(a.dirty).toBe(false); - }; - - c2.markAsDirty(); - expect(a.pristine).toBe(false); - expect(a.dirty).toBe(true); - - a.valueChanges.subscribe(pristineAndNotDirty); - a.statusChanges.subscribe(pristineAndNotDirty); - - a.reset(); - }); - }); + c.setValue('incorrect'); + + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({'broken': true}); }); + }); - describe('errors', () => { - it('should run the validator when the value changes', () => { - const simpleValidator = (c: FormArray) => - c.controls[0].value != 'correct' ? {'broken': true} : null; - const c = new FormControl(null); - const g = new FormArray([c], simpleValidator as ValidatorFn); + describe('dirty', () => { + let c: FormControl; + let a: FormArray; - c.setValue('correct'); + beforeEach(() => { + c = new FormControl('value'); + a = new FormArray([c]); + }); - expect(g.valid).toEqual(true); - expect(g.errors).toEqual(null); + it('should be false after creating a control', () => { + expect(a.dirty).toEqual(false); + }); - c.setValue('incorrect'); + it('should be true after changing the value of the control', () => { + c.markAsDirty(); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({'broken': true}); - }); + expect(a.dirty).toEqual(true); }); + }); + describe('touched', () => { + let c: FormControl; + let a: FormArray; - describe('dirty', () => { - let c: FormControl; - let a: FormArray; - - beforeEach(() => { - c = new FormControl('value'); - a = new FormArray([c]); - }); + beforeEach(() => { + c = new FormControl('value'); + a = new FormArray([c]); + }); - it('should be false after creating a control', () => { expect(a.dirty).toEqual(false); }); + it('should be false after creating a control', () => { + expect(a.touched).toEqual(false); + }); - it('should be true after changing the value of the control', () => { - c.markAsDirty(); + it('should be true after child control is marked as touched', () => { + c.markAsTouched(); - expect(a.dirty).toEqual(true); - }); + expect(a.touched).toEqual(true); }); + }); - describe('touched', () => { - let c: FormControl; - let a: FormArray; - beforeEach(() => { - c = new FormControl('value'); - a = new FormArray([c]); - }); + describe('pending', () => { + let c: FormControl; + let a: FormArray; - it('should be false after creating a control', () => { expect(a.touched).toEqual(false); }); + beforeEach(() => { + c = new FormControl('value'); + a = new FormArray([c]); + }); - it('should be true after child control is marked as touched', () => { - c.markAsTouched(); + it('should be false after creating a control', () => { + expect(c.pending).toEqual(false); + expect(a.pending).toEqual(false); + }); - expect(a.touched).toEqual(true); - }); + it('should be true after changing the value of the control', () => { + c.markAsPending(); + + expect(c.pending).toEqual(true); + expect(a.pending).toEqual(true); }); + it('should not update the parent when onlySelf = true', () => { + c.markAsPending({onlySelf: true}); - describe('pending', () => { - let c: FormControl; - let a: FormArray; + expect(c.pending).toEqual(true); + expect(a.pending).toEqual(false); + }); - beforeEach(() => { - c = new FormControl('value'); - a = new FormArray([c]); - }); + describe('status change events', () => { + let logger: string[]; - it('should be false after creating a control', () => { - expect(c.pending).toEqual(false); - expect(a.pending).toEqual(false); + beforeEach(() => { + logger = []; + a.statusChanges.subscribe((status) => logger.push(status)); }); - it('should be true after changing the value of the control', () => { + it('should emit event after marking control as pending', () => { c.markAsPending(); - - expect(c.pending).toEqual(true); - expect(a.pending).toEqual(true); + expect(logger).toEqual(['PENDING']); }); - it('should not update the parent when onlySelf = true', () => { + it('should not emit event from parent when onlySelf is true', () => { c.markAsPending({onlySelf: true}); - - expect(c.pending).toEqual(true); - expect(a.pending).toEqual(false); + expect(logger).toEqual([]); }); - describe('status change events', () => { - let logger: string[]; - - beforeEach(() => { - logger = []; - a.statusChanges.subscribe((status) => logger.push(status)); - }); - - it('should emit event after marking control as pending', () => { - c.markAsPending(); - expect(logger).toEqual(['PENDING']); - }); - - it('should not emit event from parent when onlySelf is true', () => { - c.markAsPending({onlySelf: true}); - expect(logger).toEqual([]); - }); - - it('should not emit event when emitEvent = false', () => { - c.markAsPending({emitEvent: false}); - expect(logger).toEqual([]); - }); - - it('should emit event when parent is markedAsPending', () => { - a.markAsPending(); - expect(logger).toEqual(['PENDING']); - }); + it('should not emit event when emitEvent = false', () => { + c.markAsPending({emitEvent: false}); + expect(logger).toEqual([]); }); + it('should emit event when parent is markedAsPending', () => { + a.markAsPending(); + expect(logger).toEqual(['PENDING']); + }); }); + }); - describe('valueChanges', () => { - let a: FormArray; - let c1: any /** TODO #9100 */, c2: any /** TODO #9100 */; + describe('valueChanges', () => { + let a: FormArray; + let c1: any /** TODO #9100 */, c2: any /** TODO #9100 */; - beforeEach(() => { - c1 = new FormControl('old1'); - c2 = new FormControl('old2'); - a = new FormArray([c1, c2]); - }); + beforeEach(() => { + c1 = new FormControl('old1'); + c2 = new FormControl('old2'); + a = new FormArray([c1, c2]); + }); - it('should fire an event after the value has been updated', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - a.valueChanges.subscribe({ - next: (value: any) => { - expect(a.value).toEqual(['new1', 'old2']); - expect(value).toEqual(['new1', 'old2']); - async.done(); - } - }); - c1.setValue('new1'); - })); + it('should fire an event after the value has been updated', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + a.valueChanges.subscribe({ + next: (value: any) => { + expect(a.value).toEqual(['new1', 'old2']); + expect(value).toEqual(['new1', 'old2']); + async.done(); + } + }); + c1.setValue('new1'); + })); + + it('should fire an event after the control\'s observable fired an event', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + let controlCallbackIsCalled = false; + + + c1.valueChanges.subscribe({ + next: (value: any) => { + controlCallbackIsCalled = true; + } + }); + + a.valueChanges.subscribe({ + next: (value: any) => { + expect(controlCallbackIsCalled).toBe(true); + async.done(); + } + }); + + c1.setValue('new1'); + })); + + it('should fire an event when a control is removed', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + a.valueChanges.subscribe({ + next: (value: any) => { + expect(value).toEqual(['old1']); + async.done(); + } + }); + + a.removeAt(1); + })); + + it('should fire an event when a control is added', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + a.removeAt(1); + + a.valueChanges.subscribe({ + next: (value: any) => { + expect(value).toEqual(['old1', 'old2']); + async.done(); + } + }); + + a.push(c2); + })); + }); - it('should fire an event after the control\'s observable fired an event', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - let controlCallbackIsCalled = false; + describe('get', () => { + it('should return null when path is null', () => { + const g = new FormGroup({}); + expect(g.get(null!)).toEqual(null); + }); + it('should return null when path is empty', () => { + const g = new FormGroup({}); + expect(g.get([])).toEqual(null); + }); - c1.valueChanges.subscribe({next: (value: any) => { controlCallbackIsCalled = true; }}); + it('should return null when path is invalid', () => { + const g = new FormGroup({}); + expect(g.get('invalid')).toEqual(null); + }); - a.valueChanges.subscribe({ - next: (value: any) => { - expect(controlCallbackIsCalled).toBe(true); - async.done(); - } - }); + it('should return a child of a control group', () => { + const g = new FormGroup({ + 'one': new FormControl('111'), + 'nested': new FormGroup({'two': new FormControl('222')}) + }); - c1.setValue('new1'); - })); + expect(g.get(['one'])!.value).toEqual('111'); + expect(g.get('one')!.value).toEqual('111'); + expect(g.get(['nested', 'two'])!.value).toEqual('222'); + expect(g.get('nested.two')!.value).toEqual('222'); + }); - it('should fire an event when a control is removed', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - a.valueChanges.subscribe({ - next: (value: any) => { - expect(value).toEqual(['old1']); - async.done(); - } - }); + it('should return an element of an array', () => { + const g = new FormGroup({'array': new FormArray([new FormControl('111')])}); - a.removeAt(1); - })); + expect(g.get(['array', 0])!.value).toEqual('111'); + }); + }); - it('should fire an event when a control is added', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - a.removeAt(1); + describe('validator', () => { + function simpleValidator(c: AbstractControl): ValidationErrors|null { + return c.get([0])!.value === 'correct' ? null : {'broken': true}; + } - a.valueChanges.subscribe({ - next: (value: any) => { - expect(value).toEqual(['old1', 'old2']); - async.done(); - } - }); + function arrayRequiredValidator(c: AbstractControl): ValidationErrors|null { + return Validators.required(c.get([0]) as AbstractControl); + } - a.push(c2); - })); + it('should set a single validator', () => { + const a = new FormArray([new FormControl()], simpleValidator); + expect(a.valid).toBe(false); + expect(a.errors).toEqual({'broken': true}); + + a.setValue(['correct']); + expect(a.valid).toBe(true); }); - describe('get', () => { - it('should return null when path is null', () => { - const g = new FormGroup({}); - expect(g.get(null !)).toEqual(null); - }); + it('should set a single validator from options obj', () => { + const a = new FormArray([new FormControl()], {validators: simpleValidator}); + expect(a.valid).toBe(false); + expect(a.errors).toEqual({'broken': true}); - it('should return null when path is empty', () => { - const g = new FormGroup({}); - expect(g.get([])).toEqual(null); - }); + a.setValue(['correct']); + expect(a.valid).toBe(true); + }); - it('should return null when path is invalid', () => { - const g = new FormGroup({}); - expect(g.get('invalid')).toEqual(null); - }); + it('should set multiple validators from an array', () => { + const a = new FormArray([new FormControl()], [simpleValidator, arrayRequiredValidator]); + expect(a.valid).toBe(false); + expect(a.errors).toEqual({'required': true, 'broken': true}); - it('should return a child of a control group', () => { - const g = new FormGroup({ - 'one': new FormControl('111'), - 'nested': new FormGroup({'two': new FormControl('222')}) - }); + a.setValue(['c']); + expect(a.valid).toBe(false); + expect(a.errors).toEqual({'broken': true}); - expect(g.get(['one']) !.value).toEqual('111'); - expect(g.get('one') !.value).toEqual('111'); - expect(g.get(['nested', 'two']) !.value).toEqual('222'); - expect(g.get('nested.two') !.value).toEqual('222'); - }); + a.setValue(['correct']); + expect(a.valid).toBe(true); + }); - it('should return an element of an array', () => { - const g = new FormGroup({'array': new FormArray([new FormControl('111')])}); + it('should set multiple validators from options obj', () => { + const a = new FormArray( + [new FormControl()], {validators: [simpleValidator, arrayRequiredValidator]}); + expect(a.valid).toBe(false); + expect(a.errors).toEqual({'required': true, 'broken': true}); - expect(g.get(['array', 0]) !.value).toEqual('111'); - }); + a.setValue(['c']); + expect(a.valid).toBe(false); + expect(a.errors).toEqual({'broken': true}); + + a.setValue(['correct']); + expect(a.valid).toBe(true); }); + }); - describe('validator', () => { - function simpleValidator(c: AbstractControl): ValidationErrors|null { - return c.get([0]) !.value === 'correct' ? null : {'broken': true}; - } + describe('asyncValidator', () => { + function otherObservableValidator() { + return of({'other': true}); + } - function arrayRequiredValidator(c: AbstractControl): ValidationErrors|null { - return Validators.required(c.get([0]) as AbstractControl); - } + it('should run the async validator', fakeAsync(() => { + const c = new FormControl('value'); + const g = new FormArray([c], null!, asyncValidator('expected')); - it('should set a single validator', () => { - const a = new FormArray([new FormControl()], simpleValidator); - expect(a.valid).toBe(false); - expect(a.errors).toEqual({'broken': true}); + expect(g.pending).toEqual(true); - a.setValue(['correct']); - expect(a.valid).toBe(true); - }); + tick(); - it('should set a single validator from options obj', () => { - const a = new FormArray([new FormControl()], {validators: simpleValidator}); - expect(a.valid).toBe(false); - expect(a.errors).toEqual({'broken': true}); + expect(g.errors).toEqual({'async': true}); + expect(g.pending).toEqual(false); + })); - a.setValue(['correct']); - expect(a.valid).toBe(true); - }); + it('should set a single async validator from options obj', fakeAsync(() => { + const g = new FormArray( + [new FormControl('value')], {asyncValidators: asyncValidator('expected')}); - it('should set multiple validators from an array', () => { - const a = new FormArray([new FormControl()], [simpleValidator, arrayRequiredValidator]); - expect(a.valid).toBe(false); - expect(a.errors).toEqual({'required': true, 'broken': true}); + expect(g.pending).toEqual(true); - a.setValue(['c']); - expect(a.valid).toBe(false); - expect(a.errors).toEqual({'broken': true}); + tick(); - a.setValue(['correct']); - expect(a.valid).toBe(true); - }); + expect(g.errors).toEqual({'async': true}); + expect(g.pending).toEqual(false); + })); - it('should set multiple validators from options obj', () => { - const a = new FormArray( - [new FormControl()], {validators: [simpleValidator, arrayRequiredValidator]}); - expect(a.valid).toBe(false); - expect(a.errors).toEqual({'required': true, 'broken': true}); + it('should set multiple async validators from an array', fakeAsync(() => { + const g = new FormArray( + [new FormControl('value')], null!, + [asyncValidator('expected'), otherObservableValidator]); - a.setValue(['c']); - expect(a.valid).toBe(false); - expect(a.errors).toEqual({'broken': true}); + expect(g.pending).toEqual(true); - a.setValue(['correct']); - expect(a.valid).toBe(true); - }); - }); + tick(); - describe('asyncValidator', () => { - function otherObservableValidator() { return of ({'other': true}); } + expect(g.errors).toEqual({'async': true, 'other': true}); + expect(g.pending).toEqual(false); + })); - it('should run the async validator', fakeAsync(() => { - const c = new FormControl('value'); - const g = new FormArray([c], null !, asyncValidator('expected')); + it('should set multiple async validators from options obj', fakeAsync(() => { + const g = new FormArray( + [new FormControl('value')], + {asyncValidators: [asyncValidator('expected'), otherObservableValidator]}); - expect(g.pending).toEqual(true); + expect(g.pending).toEqual(true); - tick(); - - expect(g.errors).toEqual({'async': true}); - expect(g.pending).toEqual(false); - })); + tick(); - it('should set a single async validator from options obj', fakeAsync(() => { - const g = new FormArray( - [new FormControl('value')], {asyncValidators: asyncValidator('expected')}); + expect(g.errors).toEqual({'async': true, 'other': true}); + expect(g.pending).toEqual(false); + })); + }); - expect(g.pending).toEqual(true); + describe('disable() & enable()', () => { + let a: FormArray; + let c: FormControl; + let c2: FormControl; - tick(); + beforeEach(() => { + c = new FormControl(null); + c2 = new FormControl(null); + a = new FormArray([c, c2]); + }); - expect(g.errors).toEqual({'async': true}); - expect(g.pending).toEqual(false); - })); + it('should mark the array as disabled', () => { + expect(a.disabled).toBe(false); + expect(a.valid).toBe(true); - it('should set multiple async validators from an array', fakeAsync(() => { - const g = new FormArray( - [new FormControl('value')], null !, - [asyncValidator('expected'), otherObservableValidator]); + a.disable(); + expect(a.disabled).toBe(true); + expect(a.valid).toBe(false); - expect(g.pending).toEqual(true); + a.enable(); + expect(a.disabled).toBe(false); + expect(a.valid).toBe(true); + }); - tick(); + it('should set the array status as disabled', () => { + expect(a.status).toBe('VALID'); - expect(g.errors).toEqual({'async': true, 'other': true}); - expect(g.pending).toEqual(false); - })); + a.disable(); + expect(a.status).toBe('DISABLED'); - it('should set multiple async validators from options obj', fakeAsync(() => { - const g = new FormArray( - [new FormControl('value')], - {asyncValidators: [asyncValidator('expected'), otherObservableValidator]}); + a.enable(); + expect(a.status).toBe('VALID'); + }); - expect(g.pending).toEqual(true); + it('should mark children of the array as disabled', () => { + expect(c.disabled).toBe(false); + expect(c2.disabled).toBe(false); - tick(); + a.disable(); + expect(c.disabled).toBe(true); + expect(c2.disabled).toBe(true); - expect(g.errors).toEqual({'async': true, 'other': true}); - expect(g.pending).toEqual(false); - })); + a.enable(); + expect(c.disabled).toBe(false); + expect(c2.disabled).toBe(false); }); - describe('disable() & enable()', () => { - let a: FormArray; - let c: FormControl; - let c2: FormControl; - - beforeEach(() => { - c = new FormControl(null); - c2 = new FormControl(null); - a = new FormArray([c, c2]); + it('should ignore disabled controls in validation', () => { + const g = new FormGroup({ + nested: new FormArray([new FormControl(null, Validators.required)]), + two: new FormControl('two') }); + expect(g.valid).toBe(false); - it('should mark the array as disabled', () => { - expect(a.disabled).toBe(false); - expect(a.valid).toBe(true); + g.get('nested')!.disable(); + expect(g.valid).toBe(true); - a.disable(); - expect(a.disabled).toBe(true); - expect(a.valid).toBe(false); + g.get('nested')!.enable(); + expect(g.valid).toBe(false); + }); - a.enable(); - expect(a.disabled).toBe(false); - expect(a.valid).toBe(true); - }); + it('should ignore disabled controls when serializing value', () => { + const g = new FormGroup( + {nested: new FormArray([new FormControl('one')]), two: new FormControl('two')}); + expect(g.value).toEqual({'nested': ['one'], 'two': 'two'}); - it('should set the array status as disabled', () => { - expect(a.status).toBe('VALID'); + g.get('nested')!.disable(); + expect(g.value).toEqual({'two': 'two'}); - a.disable(); - expect(a.status).toBe('DISABLED'); + g.get('nested')!.enable(); + expect(g.value).toEqual({'nested': ['one'], 'two': 'two'}); + }); - a.enable(); - expect(a.status).toBe('VALID'); - }); + it('should ignore disabled controls when determining dirtiness', () => { + const g = new FormGroup({nested: a, two: new FormControl('two')}); + g.get(['nested', 0])!.markAsDirty(); + expect(g.dirty).toBe(true); - it('should mark children of the array as disabled', () => { - expect(c.disabled).toBe(false); - expect(c2.disabled).toBe(false); + g.get('nested')!.disable(); + expect(g.get('nested')!.dirty).toBe(true); + expect(g.dirty).toEqual(false); - a.disable(); - expect(c.disabled).toBe(true); - expect(c2.disabled).toBe(true); + g.get('nested')!.enable(); + expect(g.dirty).toEqual(true); + }); - a.enable(); - expect(c.disabled).toBe(false); - expect(c2.disabled).toBe(false); - }); + it('should ignore disabled controls when determining touched state', () => { + const g = new FormGroup({nested: a, two: new FormControl('two')}); + g.get(['nested', 0])!.markAsTouched(); + expect(g.touched).toBe(true); - it('should ignore disabled controls in validation', () => { - const g = new FormGroup({ - nested: new FormArray([new FormControl(null, Validators.required)]), - two: new FormControl('two') - }); - expect(g.valid).toBe(false); + g.get('nested')!.disable(); + expect(g.get('nested')!.touched).toBe(true); + expect(g.touched).toEqual(false); - g.get('nested') !.disable(); - expect(g.valid).toBe(true); + g.get('nested')!.enable(); + expect(g.touched).toEqual(true); + }); - g.get('nested') !.enable(); - expect(g.valid).toBe(false); - }); + it('should keep empty, disabled arrays disabled when updating validity', () => { + const arr = new FormArray([]); + expect(arr.status).toEqual('VALID'); - it('should ignore disabled controls when serializing value', () => { - const g = new FormGroup( - {nested: new FormArray([new FormControl('one')]), two: new FormControl('two')}); - expect(g.value).toEqual({'nested': ['one'], 'two': 'two'}); + arr.disable(); + expect(arr.status).toEqual('DISABLED'); - g.get('nested') !.disable(); - expect(g.value).toEqual({'two': 'two'}); + arr.updateValueAndValidity(); + expect(arr.status).toEqual('DISABLED'); - g.get('nested') !.enable(); - expect(g.value).toEqual({'nested': ['one'], 'two': 'two'}); - }); + arr.push(new FormControl({value: '', disabled: true})); + expect(arr.status).toEqual('DISABLED'); - it('should ignore disabled controls when determining dirtiness', () => { - const g = new FormGroup({nested: a, two: new FormControl('two')}); - g.get(['nested', 0]) !.markAsDirty(); - expect(g.dirty).toBe(true); + arr.push(new FormControl()); + expect(arr.status).toEqual('VALID'); + }); - g.get('nested') !.disable(); - expect(g.get('nested') !.dirty).toBe(true); - expect(g.dirty).toEqual(false); + it('should re-enable empty, disabled arrays', () => { + const arr = new FormArray([]); + arr.disable(); + expect(arr.status).toEqual('DISABLED'); - g.get('nested') !.enable(); - expect(g.dirty).toEqual(true); - }); + arr.enable(); + expect(arr.status).toEqual('VALID'); + }); - it('should ignore disabled controls when determining touched state', () => { - const g = new FormGroup({nested: a, two: new FormControl('two')}); - g.get(['nested', 0]) !.markAsTouched(); - expect(g.touched).toBe(true); + it('should not run validators on disabled controls', () => { + const validator = jasmine.createSpy('validator'); + const arr = new FormArray([new FormControl()], validator); + expect(validator.calls.count()).toEqual(1); - g.get('nested') !.disable(); - expect(g.get('nested') !.touched).toBe(true); - expect(g.touched).toEqual(false); + arr.disable(); + expect(validator.calls.count()).toEqual(1); - g.get('nested') !.enable(); - expect(g.touched).toEqual(true); - }); + arr.setValue(['value']); + expect(validator.calls.count()).toEqual(1); - it('should keep empty, disabled arrays disabled when updating validity', () => { - const arr = new FormArray([]); - expect(arr.status).toEqual('VALID'); + arr.enable(); + expect(validator.calls.count()).toEqual(2); + }); + + describe('disabled errors', () => { + it('should clear out array errors when disabled', () => { + const arr = new FormArray([new FormControl()], () => ({'expected': true})); + expect(arr.errors).toEqual({'expected': true}); arr.disable(); - expect(arr.status).toEqual('DISABLED'); + expect(arr.errors).toEqual(null); - arr.updateValueAndValidity(); - expect(arr.status).toEqual('DISABLED'); + arr.enable(); + expect(arr.errors).toEqual({'expected': true}); + }); - arr.push(new FormControl({value: '', disabled: true})); - expect(arr.status).toEqual('DISABLED'); + it('should re-populate array errors when enabled from a child', () => { + const arr = new FormArray([new FormControl()], () => ({'expected': true})); + arr.disable(); + expect(arr.errors).toEqual(null); arr.push(new FormControl()); - expect(arr.status).toEqual('VALID'); + expect(arr.errors).toEqual({'expected': true}); }); - it('should re-enable empty, disabled arrays', () => { - const arr = new FormArray([]); - arr.disable(); - expect(arr.status).toEqual('DISABLED'); + it('should clear out async array errors when disabled', fakeAsync(() => { + const arr = new FormArray([new FormControl()], null!, asyncValidator('expected')); + tick(); + expect(arr.errors).toEqual({'async': true}); - arr.enable(); - expect(arr.status).toEqual('VALID'); - }); + arr.disable(); + expect(arr.errors).toEqual(null); + + arr.enable(); + tick(); + expect(arr.errors).toEqual({'async': true}); + })); - it('should not run validators on disabled controls', () => { - const validator = jasmine.createSpy('validator'); - const arr = new FormArray([new FormControl()], validator); - expect(validator.calls.count()).toEqual(1); + it('should re-populate async array errors when enabled from a child', fakeAsync(() => { + const arr = new FormArray([new FormControl()], null!, asyncValidator('expected')); + tick(); + expect(arr.errors).toEqual({'async': true}); - arr.disable(); - expect(validator.calls.count()).toEqual(1); + arr.disable(); + expect(arr.errors).toEqual(null); - arr.setValue(['value']); - expect(validator.calls.count()).toEqual(1); + arr.push(new FormControl()); + tick(); + expect(arr.errors).toEqual({'async': true}); + })); + }); - arr.enable(); - expect(validator.calls.count()).toEqual(2); - }); + describe('disabled events', () => { + let logger: string[]; + let c: FormControl; + let a: FormArray; + let form: FormGroup; - describe('disabled errors', () => { - it('should clear out array errors when disabled', () => { - const arr = new FormArray([new FormControl()], () => ({'expected': true})); - expect(arr.errors).toEqual({'expected': true}); + beforeEach(() => { + logger = []; + c = new FormControl('', Validators.required); + a = new FormArray([c]); + form = new FormGroup({a: a}); + }); - arr.disable(); - expect(arr.errors).toEqual(null); + it('should emit value change events in the right order', () => { + c.valueChanges.subscribe(() => logger.push('control')); + a.valueChanges.subscribe(() => logger.push('array')); + form.valueChanges.subscribe(() => logger.push('form')); - arr.enable(); - expect(arr.errors).toEqual({'expected': true}); - }); + a.disable(); + expect(logger).toEqual(['control', 'array', 'form']); + }); - it('should re-populate array errors when enabled from a child', () => { - const arr = new FormArray([new FormControl()], () => ({'expected': true})); - arr.disable(); - expect(arr.errors).toEqual(null); + it('should emit status change events in the right order', () => { + c.statusChanges.subscribe(() => logger.push('control')); + a.statusChanges.subscribe(() => logger.push('array')); + form.statusChanges.subscribe(() => logger.push('form')); - arr.push(new FormControl()); - expect(arr.errors).toEqual({'expected': true}); - }); + a.disable(); + expect(logger).toEqual(['control', 'array', 'form']); + }); - it('should clear out async array errors when disabled', fakeAsync(() => { - const arr = new FormArray([new FormControl()], null !, asyncValidator('expected')); - tick(); - expect(arr.errors).toEqual({'async': true}); + it('should not emit value change events when emitEvent = false', () => { + c.valueChanges.subscribe(() => logger.push('control')); + a.valueChanges.subscribe(() => logger.push('array')); + form.valueChanges.subscribe(() => logger.push('form')); - arr.disable(); - expect(arr.errors).toEqual(null); + a.disable({emitEvent: false}); + expect(logger).toEqual([]); + a.enable({emitEvent: false}); + expect(logger).toEqual([]); + }); - arr.enable(); - tick(); - expect(arr.errors).toEqual({'async': true}); - })); + it('should not emit status change events when emitEvent = false', () => { + c.statusChanges.subscribe(() => logger.push('control')); + a.statusChanges.subscribe(() => logger.push('array')); + form.statusChanges.subscribe(() => logger.push('form')); - it('should re-populate async array errors when enabled from a child', fakeAsync(() => { - const arr = new FormArray([new FormControl()], null !, asyncValidator('expected')); - tick(); - expect(arr.errors).toEqual({'async': true}); + a.disable({emitEvent: false}); + expect(logger).toEqual([]); + a.enable({emitEvent: false}); + expect(logger).toEqual([]); + }); + }); - arr.disable(); - expect(arr.errors).toEqual(null); + describe('setControl()', () => { + let c: FormControl; + let a: FormArray; - arr.push(new FormControl()); - tick(); - expect(arr.errors).toEqual({'async': true}); - })); + beforeEach(() => { + c = new FormControl('one'); + a = new FormArray([c]); }); - describe('disabled events', () => { - let logger: string[]; - let c: FormControl; - let a: FormArray; - let form: FormGroup; - - beforeEach(() => { - logger = []; - c = new FormControl('', Validators.required); - a = new FormArray([c]); - form = new FormGroup({a: a}); - }); - - it('should emit value change events in the right order', () => { - c.valueChanges.subscribe(() => logger.push('control')); - a.valueChanges.subscribe(() => logger.push('array')); - form.valueChanges.subscribe(() => logger.push('form')); - - a.disable(); - expect(logger).toEqual(['control', 'array', 'form']); - }); - - it('should emit status change events in the right order', () => { - c.statusChanges.subscribe(() => logger.push('control')); - a.statusChanges.subscribe(() => logger.push('array')); - form.statusChanges.subscribe(() => logger.push('form')); - - a.disable(); - expect(logger).toEqual(['control', 'array', 'form']); - }); - - it('should not emit value change events when emitEvent = false', () => { - c.valueChanges.subscribe(() => logger.push('control')); - a.valueChanges.subscribe(() => logger.push('array')); - form.valueChanges.subscribe(() => logger.push('form')); - - a.disable({emitEvent: false}); - expect(logger).toEqual([]); - a.enable({emitEvent: false}); - expect(logger).toEqual([]); - }); - - it('should not emit status change events when emitEvent = false', () => { - c.statusChanges.subscribe(() => logger.push('control')); - a.statusChanges.subscribe(() => logger.push('array')); - form.statusChanges.subscribe(() => logger.push('form')); - - a.disable({emitEvent: false}); - expect(logger).toEqual([]); - a.enable({emitEvent: false}); - expect(logger).toEqual([]); - }); + it('should replace existing control with new control', () => { + const c2 = new FormControl('new!', Validators.minLength(10)); + a.setControl(0, c2); + expect(a.controls[0]).toEqual(c2); + expect(a.value).toEqual(['new!']); + expect(a.valid).toBe(false); }); - describe('setControl()', () => { - let c: FormControl; - let a: FormArray; - - beforeEach(() => { - c = new FormControl('one'); - a = new FormArray([c]); - }); - - it('should replace existing control with new control', () => { - const c2 = new FormControl('new!', Validators.minLength(10)); - a.setControl(0, c2); - - expect(a.controls[0]).toEqual(c2); - expect(a.value).toEqual(['new!']); - expect(a.valid).toBe(false); - }); - - it('should add control if control did not exist before', () => { - const c2 = new FormControl('new!', Validators.minLength(10)); - a.setControl(1, c2); - - expect(a.controls[1]).toEqual(c2); - expect(a.value).toEqual(['one', 'new!']); - expect(a.valid).toBe(false); - }); - - it('should remove control if new control is null', () => { - a.setControl(0, null !); - expect(a.controls[0]).not.toBeDefined(); - expect(a.value).toEqual([]); - }); - - it('should only emit value change event once', () => { - const logger: string[] = []; - const c2 = new FormControl('new!'); - a.valueChanges.subscribe(() => logger.push('change!')); - a.setControl(0, c2); - expect(logger).toEqual(['change!']); - }); + it('should add control if control did not exist before', () => { + const c2 = new FormControl('new!', Validators.minLength(10)); + a.setControl(1, c2); + expect(a.controls[1]).toEqual(c2); + expect(a.value).toEqual(['one', 'new!']); + expect(a.valid).toBe(false); }); + it('should remove control if new control is null', () => { + a.setControl(0, null!); + expect(a.controls[0]).not.toBeDefined(); + expect(a.value).toEqual([]); + }); + + it('should only emit value change event once', () => { + const logger: string[] = []; + const c2 = new FormControl('new!'); + a.valueChanges.subscribe(() => logger.push('change!')); + a.setControl(0, c2); + expect(logger).toEqual(['change!']); + }); }); }); +}); })(); diff --git a/packages/forms/test/form_builder_spec.ts b/packages/forms/test/form_builder_spec.ts index e04cd74677b15..05e2a735ce62b 100644 --- a/packages/forms/test/form_builder_spec.ts +++ b/packages/forms/test/form_builder_spec.ts @@ -8,195 +8,208 @@ import {fakeAsync, tick} from '@angular/core/testing'; import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; import {FormBuilder, Validators} from '@angular/forms'; -import {of } from 'rxjs'; +import {of} from 'rxjs'; (function() { - function syncValidator(_: any /** TODO #9100 */): any /** TODO #9100 */ { return null; } - function asyncValidator(_: any /** TODO #9100 */) { return Promise.resolve(null); } - - describe('Form Builder', () => { - let b: FormBuilder; - - beforeEach(() => { b = new FormBuilder(); }); - - it('should create controls from a value', () => { - const g = b.group({'login': 'some value'}); - - expect(g.controls['login'].value).toEqual('some value'); - }); +function syncValidator(_: any /** TODO #9100 */): any /** TODO #9100 */ { + return null; +} +function asyncValidator(_: any /** TODO #9100 */) { + return Promise.resolve(null); +} + +describe('Form Builder', () => { + let b: FormBuilder; + + beforeEach(() => { + b = new FormBuilder(); + }); - it('should create controls from a boxed value', () => { - const g = b.group({'login': {value: 'some value', disabled: true}}); + it('should create controls from a value', () => { + const g = b.group({'login': 'some value'}); - expect(g.controls['login'].value).toEqual('some value'); - expect(g.controls['login'].disabled).toEqual(true); - }); + expect(g.controls['login'].value).toEqual('some value'); + }); - it('should create controls from an array', () => { - const g = b.group( - {'login': ['some value'], 'password': ['some value', syncValidator, asyncValidator]}); + it('should create controls from a boxed value', () => { + const g = b.group({'login': {value: 'some value', disabled: true}}); - expect(g.controls['login'].value).toEqual('some value'); - expect(g.controls['password'].value).toEqual('some value'); - expect(g.controls['password'].validator).toEqual(syncValidator); - expect(g.controls['password'].asyncValidator).toEqual(asyncValidator); - }); + expect(g.controls['login'].value).toEqual('some value'); + expect(g.controls['login'].disabled).toEqual(true); + }); - it('should use controls whose form state is a primitive value', () => { - const g = b.group({'login': b.control('some value', syncValidator, asyncValidator)}); + it('should create controls from an array', () => { + const g = b.group( + {'login': ['some value'], 'password': ['some value', syncValidator, asyncValidator]}); - expect(g.controls['login'].value).toEqual('some value'); - expect(g.controls['login'].validator).toBe(syncValidator); - expect(g.controls['login'].asyncValidator).toBe(asyncValidator); - }); + expect(g.controls['login'].value).toEqual('some value'); + expect(g.controls['password'].value).toEqual('some value'); + expect(g.controls['password'].validator).toEqual(syncValidator); + expect(g.controls['password'].asyncValidator).toEqual(asyncValidator); + }); - it('should support controls with no validators and whose form state is null', () => { - const g = b.group({'login': b.control(null)}); - expect(g.controls['login'].value).toBeNull(); - expect(g.controls['login'].validator).toBeNull(); - expect(g.controls['login'].asyncValidator).toBeNull(); - }); + it('should use controls whose form state is a primitive value', () => { + const g = b.group({'login': b.control('some value', syncValidator, asyncValidator)}); - it('should support controls with validators and whose form state is null', () => { - const g = b.group({'login': b.control(null, syncValidator, asyncValidator)}); - expect(g.controls['login'].value).toBeNull(); - expect(g.controls['login'].validator).toBe(syncValidator); - expect(g.controls['login'].asyncValidator).toBe(asyncValidator); - }); + expect(g.controls['login'].value).toEqual('some value'); + expect(g.controls['login'].validator).toBe(syncValidator); + expect(g.controls['login'].asyncValidator).toBe(asyncValidator); + }); - it('should support controls with no validators and whose form state is undefined', () => { - const g = b.group({'login': b.control(undefined)}); - expect(g.controls['login'].value).toBeNull(); - expect(g.controls['login'].validator).toBeNull(); - expect(g.controls['login'].asyncValidator).toBeNull(); - }); + it('should support controls with no validators and whose form state is null', () => { + const g = b.group({'login': b.control(null)}); + expect(g.controls['login'].value).toBeNull(); + expect(g.controls['login'].validator).toBeNull(); + expect(g.controls['login'].asyncValidator).toBeNull(); + }); - it('should support controls with validators and whose form state is undefined', () => { - const g = b.group({'login': b.control(undefined, syncValidator, asyncValidator)}); - expect(g.controls['login'].value).toBeNull(); - expect(g.controls['login'].validator).toBe(syncValidator); - expect(g.controls['login'].asyncValidator).toBe(asyncValidator); - }); + it('should support controls with validators and whose form state is null', () => { + const g = b.group({'login': b.control(null, syncValidator, asyncValidator)}); + expect(g.controls['login'].value).toBeNull(); + expect(g.controls['login'].validator).toBe(syncValidator); + expect(g.controls['login'].asyncValidator).toBe(asyncValidator); + }); - it('should create groups with a custom validator', () => { - const g = b.group( - {'login': 'some value'}, {'validator': syncValidator, 'asyncValidator': asyncValidator}); + it('should support controls with no validators and whose form state is undefined', () => { + const g = b.group({'login': b.control(undefined)}); + expect(g.controls['login'].value).toBeNull(); + expect(g.controls['login'].validator).toBeNull(); + expect(g.controls['login'].asyncValidator).toBeNull(); + }); - expect(g.validator).toBe(syncValidator); - expect(g.asyncValidator).toBe(asyncValidator); - }); + it('should support controls with validators and whose form state is undefined', () => { + const g = b.group({'login': b.control(undefined, syncValidator, asyncValidator)}); + expect(g.controls['login'].value).toBeNull(); + expect(g.controls['login'].validator).toBe(syncValidator); + expect(g.controls['login'].asyncValidator).toBe(asyncValidator); + }); - it('should create control arrays', () => { - const c = b.control('three'); - const e = b.control(null); - const f = b.control(undefined); - const a = b.array( - ['one', ['two', syncValidator], c, b.array(['four']), e, f], syncValidator, - asyncValidator); - - expect(a.value).toEqual(['one', 'two', 'three', ['four'], null, null]); - expect(a.validator).toBe(syncValidator); - expect(a.asyncValidator).toBe(asyncValidator); - }); + it('should create groups with a custom validator', () => { + const g = b.group( + {'login': 'some value'}, {'validator': syncValidator, 'asyncValidator': asyncValidator}); - it('should create control arrays with multiple async validators', fakeAsync(() => { - function asyncValidator1() { return of ({'async1': true}); } - function asyncValidator2() { return of ({'async2': true}); } + expect(g.validator).toBe(syncValidator); + expect(g.asyncValidator).toBe(asyncValidator); + }); - const a = b.array(['one', 'two'], null, [asyncValidator1, asyncValidator2]); - expect(a.value).toEqual(['one', 'two']); + it('should create control arrays', () => { + const c = b.control('three'); + const e = b.control(null); + const f = b.control(undefined); + const a = b.array( + ['one', ['two', syncValidator], c, b.array(['four']), e, f], syncValidator, asyncValidator); - tick(); + expect(a.value).toEqual(['one', 'two', 'three', ['four'], null, null]); + expect(a.validator).toBe(syncValidator); + expect(a.asyncValidator).toBe(asyncValidator); + }); - expect(a.errors).toEqual({'async1': true, 'async2': true}); - })); + it('should create control arrays with multiple async validators', fakeAsync(() => { + function asyncValidator1() { + return of({'async1': true}); + } + function asyncValidator2() { + return of({'async2': true}); + } + + const a = b.array(['one', 'two'], null, [asyncValidator1, asyncValidator2]); + expect(a.value).toEqual(['one', 'two']); + + tick(); + + expect(a.errors).toEqual({'async1': true, 'async2': true}); + })); + + it('should create control arrays with multiple sync validators', () => { + function syncValidator1() { + return {'sync1': true}; + } + function syncValidator2() { + return {'sync2': true}; + } + + const a = b.array(['one', 'two'], [syncValidator1, syncValidator2]); + expect(a.value).toEqual(['one', 'two']); + expect(a.errors).toEqual({'sync1': true, 'sync2': true}); + }); - it('should create control arrays with multiple sync validators', () => { - function syncValidator1() { return {'sync1': true}; } - function syncValidator2() { return {'sync2': true}; } + describe('updateOn', () => { + it('should default to on change', () => { + const c = b.control(''); + expect(c.updateOn).toEqual('change'); + }); - const a = b.array(['one', 'two'], [syncValidator1, syncValidator2]); - expect(a.value).toEqual(['one', 'two']); - expect(a.errors).toEqual({'sync1': true, 'sync2': true}); + it('should default to on change with an options obj', () => { + const c = b.control('', {validators: Validators.required}); + expect(c.updateOn).toEqual('change'); }); - describe('updateOn', () => { - it('should default to on change', () => { - const c = b.control(''); - expect(c.updateOn).toEqual('change'); - }); + it('should set updateOn when updating on blur', () => { + const c = b.control('', {updateOn: 'blur'}); + expect(c.updateOn).toEqual('blur'); + }); - it('should default to on change with an options obj', () => { - const c = b.control('', {validators: Validators.required}); - expect(c.updateOn).toEqual('change'); - }); + describe('in groups and arrays', () => { + it('should default to group updateOn when not set in control', () => { + const g = b.group({one: b.control(''), two: b.control('')}, {updateOn: 'blur'}); - it('should set updateOn when updating on blur', () => { - const c = b.control('', {updateOn: 'blur'}); - expect(c.updateOn).toEqual('blur'); + expect(g.get('one')!.updateOn).toEqual('blur'); + expect(g.get('two')!.updateOn).toEqual('blur'); }); - describe('in groups and arrays', () => { - it('should default to group updateOn when not set in control', () => { - const g = b.group({one: b.control(''), two: b.control('')}, {updateOn: 'blur'}); + it('should default to array updateOn when not set in control', () => { + const a = b.array([b.control(''), b.control('')], {updateOn: 'blur'}); - expect(g.get('one') !.updateOn).toEqual('blur'); - expect(g.get('two') !.updateOn).toEqual('blur'); - }); + expect(a.get([0])!.updateOn).toEqual('blur'); + expect(a.get([1])!.updateOn).toEqual('blur'); + }); - it('should default to array updateOn when not set in control', () => { - const a = b.array([b.control(''), b.control('')], {updateOn: 'blur'}); + it('should set updateOn with nested groups', () => { + const g = b.group( + { + group: b.group({one: b.control(''), two: b.control('')}), + }, + {updateOn: 'blur'}); - expect(a.get([0]) !.updateOn).toEqual('blur'); - expect(a.get([1]) !.updateOn).toEqual('blur'); - }); - - it('should set updateOn with nested groups', () => { - const g = b.group( - { - group: b.group({one: b.control(''), two: b.control('')}), - }, - {updateOn: 'blur'}); + expect(g.get('group.one')!.updateOn).toEqual('blur'); + expect(g.get('group.two')!.updateOn).toEqual('blur'); + expect(g.get('group')!.updateOn).toEqual('blur'); + }); - expect(g.get('group.one') !.updateOn).toEqual('blur'); - expect(g.get('group.two') !.updateOn).toEqual('blur'); - expect(g.get('group') !.updateOn).toEqual('blur'); - }); + it('should set updateOn with nested arrays', () => { + const g = b.group( + { + arr: b.array([b.control(''), b.control('')]), + }, + {updateOn: 'blur'}); - it('should set updateOn with nested arrays', () => { - const g = b.group( - { - arr: b.array([b.control(''), b.control('')]), - }, - {updateOn: 'blur'}); + expect(g.get(['arr', 0])!.updateOn).toEqual('blur'); + expect(g.get(['arr', 1])!.updateOn).toEqual('blur'); + expect(g.get('arr')!.updateOn).toEqual('blur'); + }); - expect(g.get(['arr', 0]) !.updateOn).toEqual('blur'); - expect(g.get(['arr', 1]) !.updateOn).toEqual('blur'); - expect(g.get('arr') !.updateOn).toEqual('blur'); - }); + it('should allow control updateOn to override group updateOn', () => { + const g = b.group( + {one: b.control('', {updateOn: 'change'}), two: b.control('')}, {updateOn: 'blur'}); - it('should allow control updateOn to override group updateOn', () => { - const g = b.group( - {one: b.control('', {updateOn: 'change'}), two: b.control('')}, {updateOn: 'blur'}); + expect(g.get('one')!.updateOn).toEqual('change'); + expect(g.get('two')!.updateOn).toEqual('blur'); + }); - expect(g.get('one') !.updateOn).toEqual('change'); - expect(g.get('two') !.updateOn).toEqual('blur'); + it('should set updateOn with complex setup', () => { + const g = b.group({ + group: b.group( + {one: b.control('', {updateOn: 'change'}), two: b.control('')}, {updateOn: 'blur'}), + groupTwo: b.group({one: b.control('')}, {updateOn: 'submit'}), + three: b.control('') }); - it('should set updateOn with complex setup', () => { - const g = b.group({ - group: b.group( - {one: b.control('', {updateOn: 'change'}), two: b.control('')}, {updateOn: 'blur'}), - groupTwo: b.group({one: b.control('')}, {updateOn: 'submit'}), - three: b.control('') - }); - - expect(g.get('group.one') !.updateOn).toEqual('change'); - expect(g.get('group.two') !.updateOn).toEqual('blur'); - expect(g.get('groupTwo.one') !.updateOn).toEqual('submit'); - expect(g.get('three') !.updateOn).toEqual('change'); - }); + expect(g.get('group.one')!.updateOn).toEqual('change'); + expect(g.get('group.two')!.updateOn).toEqual('blur'); + expect(g.get('groupTwo.one')!.updateOn).toEqual('submit'); + expect(g.get('three')!.updateOn).toEqual('change'); }); }); }); +}); })(); diff --git a/packages/forms/test/form_control_spec.ts b/packages/forms/test/form_control_spec.ts index 0cf27f38cb7f1..2f40bc982efb4 100644 --- a/packages/forms/test/form_control_spec.ts +++ b/packages/forms/test/form_control_spec.ts @@ -14,1240 +14,1260 @@ import {AbstractControl, AsyncValidatorFn, FormControl, FormGroup, ValidationErr import {FormArray} from '@angular/forms/src/model'; (function() { - function asyncValidator(expected: string, timeouts = {}): AsyncValidatorFn { - return (c: AbstractControl) => { - let resolve: (result: any) => void = undefined !; - const promise = new Promise<ValidationErrors|null>(res => { resolve = res; }); - const t = (timeouts as any)[c.value] != null ? (timeouts as any)[c.value] : 0; - const res = c.value != expected ? {'async': true} : null; - - if (t == 0) { +function asyncValidator(expected: string, timeouts = {}): AsyncValidatorFn { + return (c: AbstractControl) => { + let resolve: (result: any) => void = undefined!; + const promise = new Promise<ValidationErrors|null>(res => { + resolve = res; + }); + const t = (timeouts as any)[c.value] != null ? (timeouts as any)[c.value] : 0; + const res = c.value != expected ? {'async': true} : null; + + if (t == 0) { + resolve(res); + } else { + setTimeout(() => { resolve(res); - } else { - setTimeout(() => { resolve(res); }, t); - } + }, t); + } - return promise; - }; - } + return promise; + }; +} - function asyncValidatorReturningObservable(c: AbstractControl) { - const e = new EventEmitter(); - Promise.resolve(null).then(() => { e.emit({'async': true}); }); - return e; - } +function asyncValidatorReturningObservable(c: AbstractControl) { + const e = new EventEmitter(); + Promise.resolve(null).then(() => { + e.emit({'async': true}); + }); + return e; +} - function otherAsyncValidator() { return Promise.resolve({'other': true}); } +function otherAsyncValidator() { + return Promise.resolve({'other': true}); +} - function syncValidator(_: any /** TODO #9100 */): any /** TODO #9100 */ { return null; } +function syncValidator(_: any /** TODO #9100 */): any /** TODO #9100 */ { + return null; +} - describe('FormControl', () => { - it('should default the value to null', () => { - const c = new FormControl(); - expect(c.value).toBe(null); - }); +describe('FormControl', () => { + it('should default the value to null', () => { + const c = new FormControl(); + expect(c.value).toBe(null); + }); - describe('markAllAsTouched', () => { - it('should mark only the control itself as touched', () => { - const control = new FormControl(''); - expect(control.touched).toBe(false); - control.markAllAsTouched(); - expect(control.touched).toBe(true); - }); + describe('markAllAsTouched', () => { + it('should mark only the control itself as touched', () => { + const control = new FormControl(''); + expect(control.touched).toBe(false); + control.markAllAsTouched(); + expect(control.touched).toBe(true); }); + }); - describe('boxed values', () => { - it('should support valid boxed values on creation', () => { - const c = new FormControl({value: 'some val', disabled: true}, null !, null !); - expect(c.disabled).toBe(true); - expect(c.value).toBe('some val'); - expect(c.status).toBe('DISABLED'); - }); + describe('boxed values', () => { + it('should support valid boxed values on creation', () => { + const c = new FormControl({value: 'some val', disabled: true}, null!, null!); + expect(c.disabled).toBe(true); + expect(c.value).toBe('some val'); + expect(c.status).toBe('DISABLED'); + }); - it('should honor boxed value with disabled control when validating', () => { - const c = new FormControl({value: '', disabled: true}, Validators.required); - expect(c.disabled).toBe(true); - expect(c.valid).toBe(false); - expect(c.status).toBe('DISABLED'); - }); + it('should honor boxed value with disabled control when validating', () => { + const c = new FormControl({value: '', disabled: true}, Validators.required); + expect(c.disabled).toBe(true); + expect(c.valid).toBe(false); + expect(c.status).toBe('DISABLED'); + }); - it('should not treat objects as boxed values if they have more than two props', () => { - const c = new FormControl({value: '', disabled: true, test: 'test'}, null !, null !); - expect(c.value).toEqual({value: '', disabled: true, test: 'test'}); - expect(c.disabled).toBe(false); - }); + it('should not treat objects as boxed values if they have more than two props', () => { + const c = new FormControl({value: '', disabled: true, test: 'test'}, null!, null!); + expect(c.value).toEqual({value: '', disabled: true, test: 'test'}); + expect(c.disabled).toBe(false); + }); - it('should not treat objects as boxed values if disabled is missing', () => { - const c = new FormControl({value: '', test: 'test'}, null !, null !); - expect(c.value).toEqual({value: '', test: 'test'}); - expect(c.disabled).toBe(false); - }); + it('should not treat objects as boxed values if disabled is missing', () => { + const c = new FormControl({value: '', test: 'test'}, null!, null!); + expect(c.value).toEqual({value: '', test: 'test'}); + expect(c.disabled).toBe(false); + }); + }); + describe('updateOn', () => { + it('should default to on change', () => { + const c = new FormControl(''); + expect(c.updateOn).toEqual('change'); }); - describe('updateOn', () => { + it('should default to on change with an options obj', () => { + const c = new FormControl('', {validators: Validators.required}); + expect(c.updateOn).toEqual('change'); + }); - it('should default to on change', () => { - const c = new FormControl(''); - expect(c.updateOn).toEqual('change'); - }); + it('should set updateOn when updating on blur', () => { + const c = new FormControl('', {updateOn: 'blur'}); + expect(c.updateOn).toEqual('blur'); + }); - it('should default to on change with an options obj', () => { - const c = new FormControl('', {validators: Validators.required}); - expect(c.updateOn).toEqual('change'); - }); + describe('in groups and arrays', () => { + it('should default to group updateOn when not set in control', () => { + const g = + new FormGroup({one: new FormControl(), two: new FormControl()}, {updateOn: 'blur'}); - it('should set updateOn when updating on blur', () => { - const c = new FormControl('', {updateOn: 'blur'}); - expect(c.updateOn).toEqual('blur'); + expect(g.get('one')!.updateOn).toEqual('blur'); + expect(g.get('two')!.updateOn).toEqual('blur'); }); - describe('in groups and arrays', () => { - it('should default to group updateOn when not set in control', () => { - const g = - new FormGroup({one: new FormControl(), two: new FormControl()}, {updateOn: 'blur'}); + it('should default to array updateOn when not set in control', () => { + const a = new FormArray([new FormControl(), new FormControl()], {updateOn: 'blur'}); - expect(g.get('one') !.updateOn).toEqual('blur'); - expect(g.get('two') !.updateOn).toEqual('blur'); - }); + expect(a.get([0])!.updateOn).toEqual('blur'); + expect(a.get([1])!.updateOn).toEqual('blur'); + }); - it('should default to array updateOn when not set in control', () => { - const a = new FormArray([new FormControl(), new FormControl()], {updateOn: 'blur'}); + it('should set updateOn with nested groups', () => { + const g = new FormGroup( + { + group: new FormGroup({one: new FormControl(), two: new FormControl()}), + }, + {updateOn: 'blur'}); - expect(a.get([0]) !.updateOn).toEqual('blur'); - expect(a.get([1]) !.updateOn).toEqual('blur'); - }); + expect(g.get('group.one')!.updateOn).toEqual('blur'); + expect(g.get('group.two')!.updateOn).toEqual('blur'); + expect(g.get('group')!.updateOn).toEqual('blur'); + }); - it('should set updateOn with nested groups', () => { - const g = new FormGroup( - { - group: new FormGroup({one: new FormControl(), two: new FormControl()}), - }, - {updateOn: 'blur'}); + it('should set updateOn with nested arrays', () => { + const g = new FormGroup( + { + arr: new FormArray([new FormControl(), new FormControl()]), + }, + {updateOn: 'blur'}); - expect(g.get('group.one') !.updateOn).toEqual('blur'); - expect(g.get('group.two') !.updateOn).toEqual('blur'); - expect(g.get('group') !.updateOn).toEqual('blur'); - }); + expect(g.get(['arr', 0])!.updateOn).toEqual('blur'); + expect(g.get(['arr', 1])!.updateOn).toEqual('blur'); + expect(g.get('arr')!.updateOn).toEqual('blur'); + }); - it('should set updateOn with nested arrays', () => { - const g = new FormGroup( - { - arr: new FormArray([new FormControl(), new FormControl()]), - }, - {updateOn: 'blur'}); + it('should allow control updateOn to override group updateOn', () => { + const g = new FormGroup( + {one: new FormControl('', {updateOn: 'change'}), two: new FormControl()}, + {updateOn: 'blur'}); - expect(g.get(['arr', 0]) !.updateOn).toEqual('blur'); - expect(g.get(['arr', 1]) !.updateOn).toEqual('blur'); - expect(g.get('arr') !.updateOn).toEqual('blur'); - }); + expect(g.get('one')!.updateOn).toEqual('change'); + expect(g.get('two')!.updateOn).toEqual('blur'); + }); - it('should allow control updateOn to override group updateOn', () => { - const g = new FormGroup( + it('should set updateOn with complex setup', () => { + const g = new FormGroup({ + group: new FormGroup( {one: new FormControl('', {updateOn: 'change'}), two: new FormControl()}, - {updateOn: 'blur'}); - - expect(g.get('one') !.updateOn).toEqual('change'); - expect(g.get('two') !.updateOn).toEqual('blur'); + {updateOn: 'blur'}), + groupTwo: new FormGroup({one: new FormControl()}, {updateOn: 'submit'}), + three: new FormControl() }); - it('should set updateOn with complex setup', () => { - const g = new FormGroup({ - group: new FormGroup( - {one: new FormControl('', {updateOn: 'change'}), two: new FormControl()}, - {updateOn: 'blur'}), - groupTwo: new FormGroup({one: new FormControl()}, {updateOn: 'submit'}), - three: new FormControl() - }); - - expect(g.get('group.one') !.updateOn).toEqual('change'); - expect(g.get('group.two') !.updateOn).toEqual('blur'); - expect(g.get('groupTwo.one') !.updateOn).toEqual('submit'); - expect(g.get('three') !.updateOn).toEqual('change'); - }); - - + expect(g.get('group.one')!.updateOn).toEqual('change'); + expect(g.get('group.two')!.updateOn).toEqual('blur'); + expect(g.get('groupTwo.one')!.updateOn).toEqual('submit'); + expect(g.get('three')!.updateOn).toEqual('change'); }); - }); + }); - describe('validator', () => { - - it('should run validator with the initial value', () => { - const c = new FormControl('value', Validators.required); - expect(c.valid).toEqual(true); - }); + describe('validator', () => { + it('should run validator with the initial value', () => { + const c = new FormControl('value', Validators.required); + expect(c.valid).toEqual(true); + }); - it('should rerun the validator when the value changes', () => { - const c = new FormControl('value', Validators.required); - c.setValue(null); - expect(c.valid).toEqual(false); - }); + it('should rerun the validator when the value changes', () => { + const c = new FormControl('value', Validators.required); + c.setValue(null); + expect(c.valid).toEqual(false); + }); - it('should support arrays of validator functions if passed', () => { - const c = new FormControl('value', [Validators.required, Validators.minLength(3)]); - c.setValue('a'); - expect(c.valid).toEqual(false); + it('should support arrays of validator functions if passed', () => { + const c = new FormControl('value', [Validators.required, Validators.minLength(3)]); + c.setValue('a'); + expect(c.valid).toEqual(false); - c.setValue('aaa'); - expect(c.valid).toEqual(true); - }); + c.setValue('aaa'); + expect(c.valid).toEqual(true); + }); - it('should support single validator from options obj', () => { - const c = new FormControl(null, {validators: Validators.required}); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({required: true}); + it('should support single validator from options obj', () => { + const c = new FormControl(null, {validators: Validators.required}); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({required: true}); - c.setValue('value'); - expect(c.valid).toEqual(true); - }); + c.setValue('value'); + expect(c.valid).toEqual(true); + }); - it('should support multiple validators from options obj', () => { - const c = - new FormControl(null, {validators: [Validators.required, Validators.minLength(3)]}); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({required: true}); + it('should support multiple validators from options obj', () => { + const c = new FormControl(null, {validators: [Validators.required, Validators.minLength(3)]}); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({required: true}); - c.setValue('aa'); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({minlength: {requiredLength: 3, actualLength: 2}}); + c.setValue('aa'); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({minlength: {requiredLength: 3, actualLength: 2}}); - c.setValue('aaa'); - expect(c.valid).toEqual(true); - }); + c.setValue('aaa'); + expect(c.valid).toEqual(true); + }); - it('should support a null validators value', () => { - const c = new FormControl(null, {validators: null}); - expect(c.valid).toEqual(true); - }); + it('should support a null validators value', () => { + const c = new FormControl(null, {validators: null}); + expect(c.valid).toEqual(true); + }); - it('should support an empty options obj', () => { - const c = new FormControl(null, {}); - expect(c.valid).toEqual(true); - }); + it('should support an empty options obj', () => { + const c = new FormControl(null, {}); + expect(c.valid).toEqual(true); + }); - it('should return errors', () => { - const c = new FormControl(null, Validators.required); - expect(c.errors).toEqual({'required': true}); - }); + it('should return errors', () => { + const c = new FormControl(null, Validators.required); + expect(c.errors).toEqual({'required': true}); + }); - it('should set single validator', () => { - const c = new FormControl(null); - expect(c.valid).toEqual(true); + it('should set single validator', () => { + const c = new FormControl(null); + expect(c.valid).toEqual(true); - c.setValidators(Validators.required); + c.setValidators(Validators.required); - c.setValue(null); - expect(c.valid).toEqual(false); + c.setValue(null); + expect(c.valid).toEqual(false); - c.setValue('abc'); - expect(c.valid).toEqual(true); - }); + c.setValue('abc'); + expect(c.valid).toEqual(true); + }); - it('should set multiple validators from array', () => { - const c = new FormControl(''); - expect(c.valid).toEqual(true); + it('should set multiple validators from array', () => { + const c = new FormControl(''); + expect(c.valid).toEqual(true); - c.setValidators([Validators.minLength(5), Validators.required]); + c.setValidators([Validators.minLength(5), Validators.required]); - c.setValue(''); - expect(c.valid).toEqual(false); + c.setValue(''); + expect(c.valid).toEqual(false); - c.setValue('abc'); - expect(c.valid).toEqual(false); + c.setValue('abc'); + expect(c.valid).toEqual(false); - c.setValue('abcde'); - expect(c.valid).toEqual(true); - }); + c.setValue('abcde'); + expect(c.valid).toEqual(true); + }); - it('should clear validators', () => { - const c = new FormControl('', Validators.required); - expect(c.valid).toEqual(false); + it('should clear validators', () => { + const c = new FormControl('', Validators.required); + expect(c.valid).toEqual(false); - c.clearValidators(); - expect(c.validator).toEqual(null); + c.clearValidators(); + expect(c.validator).toEqual(null); - c.setValue(''); - expect(c.valid).toEqual(true); - }); + c.setValue(''); + expect(c.valid).toEqual(true); + }); - it('should add after clearing', () => { - const c = new FormControl('', Validators.required); - expect(c.valid).toEqual(false); + it('should add after clearing', () => { + const c = new FormControl('', Validators.required); + expect(c.valid).toEqual(false); - c.clearValidators(); - expect(c.validator).toEqual(null); + c.clearValidators(); + expect(c.validator).toEqual(null); - c.setValidators([Validators.required]); - expect(c.validator).not.toBe(null); - }); + c.setValidators([Validators.required]); + expect(c.validator).not.toBe(null); }); + }); - describe('asyncValidator', () => { - it('should run validator with the initial value', fakeAsync(() => { - const c = new FormControl('value', null !, asyncValidator('expected')); - tick(); + describe('asyncValidator', () => { + it('should run validator with the initial value', fakeAsync(() => { + const c = new FormControl('value', null!, asyncValidator('expected')); + tick(); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'async': true}); - })); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'async': true}); + })); - it('should support validators returning observables', fakeAsync(() => { - const c = new FormControl('value', null !, asyncValidatorReturningObservable); - tick(); + it('should support validators returning observables', fakeAsync(() => { + const c = new FormControl('value', null!, asyncValidatorReturningObservable); + tick(); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'async': true}); - })); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'async': true}); + })); - it('should rerun the validator when the value changes', fakeAsync(() => { - const c = new FormControl('value', null !, asyncValidator('expected')); + it('should rerun the validator when the value changes', fakeAsync(() => { + const c = new FormControl('value', null!, asyncValidator('expected')); - c.setValue('expected'); - tick(); + c.setValue('expected'); + tick(); - expect(c.valid).toEqual(true); - })); + expect(c.valid).toEqual(true); + })); - it('should run the async validator only when the sync validator passes', fakeAsync(() => { - const c = new FormControl('', Validators.required, asyncValidator('expected')); - tick(); + it('should run the async validator only when the sync validator passes', fakeAsync(() => { + const c = new FormControl('', Validators.required, asyncValidator('expected')); + tick(); - expect(c.errors).toEqual({'required': true}); + expect(c.errors).toEqual({'required': true}); - c.setValue('some value'); - tick(); + c.setValue('some value'); + tick(); - expect(c.errors).toEqual({'async': true}); - })); + expect(c.errors).toEqual({'async': true}); + })); - it('should mark the control as pending while running the async validation', fakeAsync(() => { - const c = new FormControl('', null !, asyncValidator('expected')); + it('should mark the control as pending while running the async validation', fakeAsync(() => { + const c = new FormControl('', null!, asyncValidator('expected')); - expect(c.pending).toEqual(true); + expect(c.pending).toEqual(true); - tick(); + tick(); - expect(c.pending).toEqual(false); - })); + expect(c.pending).toEqual(false); + })); - it('should only use the latest async validation run', fakeAsync(() => { - const c = new FormControl( - '', null !, asyncValidator('expected', {'long': 200, 'expected': 100})); + it('should only use the latest async validation run', fakeAsync(() => { + const c = + new FormControl('', null!, asyncValidator('expected', {'long': 200, 'expected': 100})); - c.setValue('long'); - c.setValue('expected'); + c.setValue('long'); + c.setValue('expected'); - tick(300); + tick(300); - expect(c.valid).toEqual(true); - })); + expect(c.valid).toEqual(true); + })); - it('should support arrays of async validator functions if passed', fakeAsync(() => { - const c = - new FormControl('value', null !, [asyncValidator('expected'), otherAsyncValidator]); - tick(); + it('should support arrays of async validator functions if passed', fakeAsync(() => { + const c = + new FormControl('value', null!, [asyncValidator('expected'), otherAsyncValidator]); + tick(); - expect(c.errors).toEqual({'async': true, 'other': true}); - })); + expect(c.errors).toEqual({'async': true, 'other': true}); + })); - it('should support a single async validator from options obj', fakeAsync(() => { - const c = new FormControl('value', {asyncValidators: asyncValidator('expected')}); - expect(c.pending).toEqual(true); - tick(); + it('should support a single async validator from options obj', fakeAsync(() => { + const c = new FormControl('value', {asyncValidators: asyncValidator('expected')}); + expect(c.pending).toEqual(true); + tick(); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'async': true}); - })); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'async': true}); + })); - it('should support multiple async validators from options obj', fakeAsync(() => { - const c = new FormControl( - 'value', {asyncValidators: [asyncValidator('expected'), otherAsyncValidator]}); - expect(c.pending).toEqual(true); - tick(); + it('should support multiple async validators from options obj', fakeAsync(() => { + const c = new FormControl( + 'value', {asyncValidators: [asyncValidator('expected'), otherAsyncValidator]}); + expect(c.pending).toEqual(true); + tick(); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'async': true, 'other': true}); - })); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'async': true, 'other': true}); + })); - it('should support a mix of validators from options obj', fakeAsync(() => { - const c = new FormControl( - '', {validators: Validators.required, asyncValidators: asyncValidator('expected')}); - tick(); - expect(c.errors).toEqual({required: true}); + it('should support a mix of validators from options obj', fakeAsync(() => { + const c = new FormControl( + '', {validators: Validators.required, asyncValidators: asyncValidator('expected')}); + tick(); + expect(c.errors).toEqual({required: true}); - c.setValue('value'); - expect(c.pending).toBe(true); + c.setValue('value'); + expect(c.pending).toBe(true); - tick(); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'async': true}); - })); + tick(); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'async': true}); + })); - it('should add single async validator', fakeAsync(() => { - const c = new FormControl('value', null !); + it('should add single async validator', fakeAsync(() => { + const c = new FormControl('value', null!); - c.setAsyncValidators(asyncValidator('expected')); - expect(c.asyncValidator).not.toEqual(null); + c.setAsyncValidators(asyncValidator('expected')); + expect(c.asyncValidator).not.toEqual(null); - c.setValue('expected'); - tick(); + c.setValue('expected'); + tick(); - expect(c.valid).toEqual(true); - })); + expect(c.valid).toEqual(true); + })); - it('should add async validator from array', fakeAsync(() => { - const c = new FormControl('value', null !); + it('should add async validator from array', fakeAsync(() => { + const c = new FormControl('value', null!); - c.setAsyncValidators([asyncValidator('expected')]); - expect(c.asyncValidator).not.toEqual(null); + c.setAsyncValidators([asyncValidator('expected')]); + expect(c.asyncValidator).not.toEqual(null); - c.setValue('expected'); - tick(); + c.setValue('expected'); + tick(); - expect(c.valid).toEqual(true); - })); + expect(c.valid).toEqual(true); + })); - it('should clear async validators', fakeAsync(() => { - const c = new FormControl('value', [asyncValidator('expected'), otherAsyncValidator]); + it('should clear async validators', fakeAsync(() => { + const c = new FormControl('value', [asyncValidator('expected'), otherAsyncValidator]); - c.clearValidators(); + c.clearValidators(); - expect(c.asyncValidator).toEqual(null); - })); + expect(c.asyncValidator).toEqual(null); + })); - it('should not change validity state if control is disabled while async validating', - fakeAsync(() => { - const c = new FormControl('value', [asyncValidator('expected')]); - c.disable(); - tick(); - expect(c.status).toEqual('DISABLED'); - })); + it('should not change validity state if control is disabled while async validating', + fakeAsync(() => { + const c = new FormControl('value', [asyncValidator('expected')]); + c.disable(); + tick(); + expect(c.status).toEqual('DISABLED'); + })); + }); + + describe('dirty', () => { + it('should be false after creating a control', () => { + const c = new FormControl('value'); + expect(c.dirty).toEqual(false); }); - describe('dirty', () => { - it('should be false after creating a control', () => { - const c = new FormControl('value'); - expect(c.dirty).toEqual(false); - }); + it('should be true after changing the value of the control', () => { + const c = new FormControl('value'); + c.markAsDirty(); + expect(c.dirty).toEqual(true); + }); + }); - it('should be true after changing the value of the control', () => { - const c = new FormControl('value'); - c.markAsDirty(); - expect(c.dirty).toEqual(true); - }); + describe('touched', () => { + it('should be false after creating a control', () => { + const c = new FormControl('value'); + expect(c.touched).toEqual(false); }); - describe('touched', () => { - it('should be false after creating a control', () => { - const c = new FormControl('value'); - expect(c.touched).toEqual(false); - }); + it('should be true after markAsTouched runs', () => { + const c = new FormControl('value'); + c.markAsTouched(); + expect(c.touched).toEqual(true); + }); + }); - it('should be true after markAsTouched runs', () => { - const c = new FormControl('value'); - c.markAsTouched(); - expect(c.touched).toEqual(true); - }); + describe('setValue', () => { + let g: FormGroup, c: FormControl; + beforeEach(() => { + c = new FormControl('oldValue'); + g = new FormGroup({'one': c}); }); - describe('setValue', () => { - let g: FormGroup, c: FormControl; - beforeEach(() => { - c = new FormControl('oldValue'); - g = new FormGroup({'one': c}); - }); + it('should set the value of the control', () => { + c.setValue('newValue'); + expect(c.value).toEqual('newValue'); + }); - it('should set the value of the control', () => { - c.setValue('newValue'); - expect(c.value).toEqual('newValue'); - }); + it('should invoke ngOnChanges if it is present', () => { + let ngOnChanges: any; + c.registerOnChange((v: any) => ngOnChanges = ['invoked', v]); - it('should invoke ngOnChanges if it is present', () => { - let ngOnChanges: any; - c.registerOnChange((v: any) => ngOnChanges = ['invoked', v]); + c.setValue('newValue'); - c.setValue('newValue'); + expect(ngOnChanges).toEqual(['invoked', 'newValue']); + }); - expect(ngOnChanges).toEqual(['invoked', 'newValue']); - }); + it('should not invoke on change when explicitly specified', () => { + let onChange: any = null; + c.registerOnChange((v: any) => onChange = ['invoked', v]); - it('should not invoke on change when explicitly specified', () => { - let onChange: any = null; - c.registerOnChange((v: any) => onChange = ['invoked', v]); + c.setValue('newValue', {emitModelToViewChange: false}); - c.setValue('newValue', {emitModelToViewChange: false}); + expect(onChange).toBeNull(); + }); - expect(onChange).toBeNull(); - }); + it('should set the parent', () => { + c.setValue('newValue'); + expect(g.value).toEqual({'one': 'newValue'}); + }); - it('should set the parent', () => { - c.setValue('newValue'); - expect(g.value).toEqual({'one': 'newValue'}); - }); + it('should not set the parent when explicitly specified', () => { + c.setValue('newValue', {onlySelf: true}); + expect(g.value).toEqual({'one': 'oldValue'}); + }); - it('should not set the parent when explicitly specified', () => { - c.setValue('newValue', {onlySelf: true}); - expect(g.value).toEqual({'one': 'oldValue'}); - }); + it('should fire an event', fakeAsync(() => { + c.valueChanges.subscribe((value) => { + expect(value).toEqual('newValue'); + }); + + c.setValue('newValue'); + tick(); + })); + + it('should not fire an event when explicitly specified', fakeAsync(() => { + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + + c.setValue('newValue', {emitEvent: false}); + tick(); + })); + + it('should work on a disabled control', () => { + g.addControl('two', new FormControl('two')); + c.disable(); + c.setValue('new value'); + expect(c.value).toEqual('new value'); + expect(g.value).toEqual({'two': 'two'}); + }); + }); - it('should fire an event', fakeAsync(() => { - c.valueChanges.subscribe((value) => { expect(value).toEqual('newValue'); }); + describe('patchValue', () => { + let g: FormGroup, c: FormControl; + beforeEach(() => { + c = new FormControl('oldValue'); + g = new FormGroup({'one': c}); + }); - c.setValue('newValue'); - tick(); - })); + it('should set the value of the control', () => { + c.patchValue('newValue'); + expect(c.value).toEqual('newValue'); + }); - it('should not fire an event when explicitly specified', fakeAsync(() => { - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); + it('should invoke ngOnChanges if it is present', () => { + let ngOnChanges: any; + c.registerOnChange((v: any) => ngOnChanges = ['invoked', v]); - c.setValue('newValue', {emitEvent: false}); - tick(); - })); + c.patchValue('newValue'); - it('should work on a disabled control', () => { - g.addControl('two', new FormControl('two')); - c.disable(); - c.setValue('new value'); - expect(c.value).toEqual('new value'); - expect(g.value).toEqual({'two': 'two'}); - }); + expect(ngOnChanges).toEqual(['invoked', 'newValue']); }); - describe('patchValue', () => { - let g: FormGroup, c: FormControl; - beforeEach(() => { - c = new FormControl('oldValue'); - g = new FormGroup({'one': c}); - }); + it('should not invoke on change when explicitly specified', () => { + let onChange: any = null; + c.registerOnChange((v: any) => onChange = ['invoked', v]); - it('should set the value of the control', () => { - c.patchValue('newValue'); - expect(c.value).toEqual('newValue'); - }); + c.patchValue('newValue', {emitModelToViewChange: false}); - it('should invoke ngOnChanges if it is present', () => { - let ngOnChanges: any; - c.registerOnChange((v: any) => ngOnChanges = ['invoked', v]); + expect(onChange).toBeNull(); + }); - c.patchValue('newValue'); + it('should set the parent', () => { + c.patchValue('newValue'); + expect(g.value).toEqual({'one': 'newValue'}); + }); - expect(ngOnChanges).toEqual(['invoked', 'newValue']); - }); + it('should not set the parent when explicitly specified', () => { + c.patchValue('newValue', {onlySelf: true}); + expect(g.value).toEqual({'one': 'oldValue'}); + }); - it('should not invoke on change when explicitly specified', () => { - let onChange: any = null; - c.registerOnChange((v: any) => onChange = ['invoked', v]); + it('should fire an event', fakeAsync(() => { + c.valueChanges.subscribe((value) => { + expect(value).toEqual('newValue'); + }); - c.patchValue('newValue', {emitModelToViewChange: false}); + c.patchValue('newValue'); + tick(); + })); - expect(onChange).toBeNull(); - }); + it('should not fire an event when explicitly specified', fakeAsync(() => { + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); - it('should set the parent', () => { - c.patchValue('newValue'); - expect(g.value).toEqual({'one': 'newValue'}); - }); + c.patchValue('newValue', {emitEvent: false}); - it('should not set the parent when explicitly specified', () => { - c.patchValue('newValue', {onlySelf: true}); - expect(g.value).toEqual({'one': 'oldValue'}); - }); - - it('should fire an event', fakeAsync(() => { - c.valueChanges.subscribe((value) => { expect(value).toEqual('newValue'); }); + tick(); + })); - c.patchValue('newValue'); - tick(); - })); + it('should patch value on a disabled control', () => { + g.addControl('two', new FormControl('two')); + c.disable(); - it('should not fire an event when explicitly specified', fakeAsync(() => { - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); + c.patchValue('new value'); + expect(c.value).toEqual('new value'); + expect(g.value).toEqual({'two': 'two'}); + }); + }); - c.patchValue('newValue', {emitEvent: false}); + describe('reset()', () => { + let c: FormControl; - tick(); - })); + beforeEach(() => { + c = new FormControl('initial value'); + }); - it('should patch value on a disabled control', () => { - g.addControl('two', new FormControl('two')); - c.disable(); + it('should reset to a specific value if passed', () => { + c.setValue('new value'); + expect(c.value).toBe('new value'); - c.patchValue('new value'); - expect(c.value).toEqual('new value'); - expect(g.value).toEqual({'two': 'two'}); - }); + c.reset('initial value'); + expect(c.value).toBe('initial value'); }); - describe('reset()', () => { - let c: FormControl; + it('should not set the parent when explicitly specified', () => { + const g = new FormGroup({'one': c}); + c.patchValue('newValue', {onlySelf: true}); + expect(g.value).toEqual({'one': 'initial value'}); + }); - beforeEach(() => { c = new FormControl('initial value'); }); + it('should reset to a specific value if passed with boxed value', () => { + c.setValue('new value'); + expect(c.value).toBe('new value'); - it('should reset to a specific value if passed', () => { - c.setValue('new value'); - expect(c.value).toBe('new value'); + c.reset({value: 'initial value', disabled: false}); + expect(c.value).toBe('initial value'); + }); - c.reset('initial value'); - expect(c.value).toBe('initial value'); - }); + it('should clear the control value if no value is passed', () => { + c.setValue('new value'); + expect(c.value).toBe('new value'); - it('should not set the parent when explicitly specified', () => { - const g = new FormGroup({'one': c}); - c.patchValue('newValue', {onlySelf: true}); - expect(g.value).toEqual({'one': 'initial value'}); - }); + c.reset(); + expect(c.value).toBe(null); + }); - it('should reset to a specific value if passed with boxed value', () => { - c.setValue('new value'); - expect(c.value).toBe('new value'); + it('should update the value of any parent controls with passed value', () => { + const g = new FormGroup({'one': c}); + c.setValue('new value'); + expect(g.value).toEqual({'one': 'new value'}); - c.reset({value: 'initial value', disabled: false}); - expect(c.value).toBe('initial value'); - }); + c.reset('initial value'); + expect(g.value).toEqual({'one': 'initial value'}); + }); - it('should clear the control value if no value is passed', () => { - c.setValue('new value'); - expect(c.value).toBe('new value'); + it('should update the value of any parent controls with null value', () => { + const g = new FormGroup({'one': c}); + c.setValue('new value'); + expect(g.value).toEqual({'one': 'new value'}); - c.reset(); - expect(c.value).toBe(null); - }); + c.reset(); + expect(g.value).toEqual({'one': null}); + }); - it('should update the value of any parent controls with passed value', () => { - const g = new FormGroup({'one': c}); - c.setValue('new value'); - expect(g.value).toEqual({'one': 'new value'}); + it('should mark the control as pristine', () => { + c.markAsDirty(); + expect(c.pristine).toBe(false); - c.reset('initial value'); - expect(g.value).toEqual({'one': 'initial value'}); - }); + c.reset(); + expect(c.pristine).toBe(true); + }); - it('should update the value of any parent controls with null value', () => { - const g = new FormGroup({'one': c}); - c.setValue('new value'); - expect(g.value).toEqual({'one': 'new value'}); + it('should set the parent pristine state if all pristine', () => { + const g = new FormGroup({'one': c}); + c.markAsDirty(); + expect(g.pristine).toBe(false); - c.reset(); - expect(g.value).toEqual({'one': null}); - }); + c.reset(); + expect(g.pristine).toBe(true); + }); - it('should mark the control as pristine', () => { - c.markAsDirty(); - expect(c.pristine).toBe(false); + it('should not set the parent pristine state if it has other dirty controls', () => { + const c2 = new FormControl('two'); + const g = new FormGroup({'one': c, 'two': c2}); + c.markAsDirty(); + c2.markAsDirty(); - c.reset(); - expect(c.pristine).toBe(true); - }); + c.reset(); + expect(g.pristine).toBe(false); + }); - it('should set the parent pristine state if all pristine', () => { - const g = new FormGroup({'one': c}); - c.markAsDirty(); - expect(g.pristine).toBe(false); + it('should mark the control as untouched', () => { + c.markAsTouched(); + expect(c.untouched).toBe(false); - c.reset(); - expect(g.pristine).toBe(true); - }); + c.reset(); + expect(c.untouched).toBe(true); + }); - it('should not set the parent pristine state if it has other dirty controls', () => { - const c2 = new FormControl('two'); - const g = new FormGroup({'one': c, 'two': c2}); - c.markAsDirty(); - c2.markAsDirty(); + it('should set the parent untouched state if all untouched', () => { + const g = new FormGroup({'one': c}); + c.markAsTouched(); + expect(g.untouched).toBe(false); - c.reset(); - expect(g.pristine).toBe(false); - }); + c.reset(); + expect(g.untouched).toBe(true); + }); - it('should mark the control as untouched', () => { - c.markAsTouched(); - expect(c.untouched).toBe(false); + it('should not set the parent untouched state if other touched controls', () => { + const c2 = new FormControl('two'); + const g = new FormGroup({'one': c, 'two': c2}); + c.markAsTouched(); + c2.markAsTouched(); - c.reset(); - expect(c.untouched).toBe(true); - }); + c.reset(); + expect(g.untouched).toBe(false); + }); - it('should set the parent untouched state if all untouched', () => { - const g = new FormGroup({'one': c}); - c.markAsTouched(); - expect(g.untouched).toBe(false); + it('should retain the disabled state of the control', () => { + c.disable(); + c.reset(); - c.reset(); - expect(g.untouched).toBe(true); - }); + expect(c.disabled).toBe(true); + }); - it('should not set the parent untouched state if other touched controls', () => { - const c2 = new FormControl('two'); - const g = new FormGroup({'one': c, 'two': c2}); - c.markAsTouched(); - c2.markAsTouched(); + it('should set disabled state based on boxed value if passed', () => { + c.disable(); + c.reset({value: null, disabled: false}); - c.reset(); - expect(g.untouched).toBe(false); - }); + expect(c.disabled).toBe(false); + }); - it('should retain the disabled state of the control', () => { - c.disable(); - c.reset(); + describe('reset() events', () => { + let g: FormGroup, c2: FormControl, logger: any[]; - expect(c.disabled).toBe(true); + beforeEach(() => { + c2 = new FormControl('two'); + g = new FormGroup({'one': c, 'two': c2}); + logger = []; }); - it('should set disabled state based on boxed value if passed', () => { - c.disable(); - c.reset({value: null, disabled: false}); + it('should emit one valueChange event per reset control', () => { + g.valueChanges.subscribe(() => logger.push('group')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - expect(c.disabled).toBe(false); + c.reset(); + expect(logger).toEqual(['control1', 'group']); }); - describe('reset() events', () => { - let g: FormGroup, c2: FormControl, logger: any[]; + it('should not fire an event when explicitly specified', fakeAsync(() => { + g.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c2.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); - beforeEach(() => { - c2 = new FormControl('two'); - g = new FormGroup({'one': c, 'two': c2}); - logger = []; - }); + c.reset(null, {emitEvent: false}); - it('should emit one valueChange event per reset control', () => { - g.valueChanges.subscribe(() => logger.push('group')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); + tick(); + })); - c.reset(); - expect(logger).toEqual(['control1', 'group']); - }); + it('should emit one statusChange event per reset control', () => { + g.statusChanges.subscribe(() => logger.push('group')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); - it('should not fire an event when explicitly specified', fakeAsync(() => { - g.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c2.valueChanges.subscribe((value) => { throw 'Should not happen'; }); + c.reset(); + expect(logger).toEqual(['control1', 'group']); + }); - c.reset(null, {emitEvent: false}); + it('should emit one statusChange event per disabled control', () => { + g.statusChanges.subscribe(() => logger.push('group')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); - tick(); - })); + c.reset({value: null, disabled: true}); + expect(logger).toEqual(['control1', 'group']); + }); + }); + }); - it('should emit one statusChange event per reset control', () => { - g.statusChanges.subscribe(() => logger.push('group')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); + describe('valueChanges & statusChanges', () => { + let c: FormControl; - c.reset(); - expect(logger).toEqual(['control1', 'group']); - }); + beforeEach(() => { + c = new FormControl('old', Validators.required); + }); - it('should emit one statusChange event per disabled control', () => { - g.statusChanges.subscribe(() => logger.push('group')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); + it('should fire an event after the value has been updated', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + c.valueChanges.subscribe({ + next: (value: any) => { + expect(c.value).toEqual('new'); + expect(value).toEqual('new'); + async.done(); + } + }); + c.setValue('new'); + })); + + it('should fire an event after the status has been updated to invalid', fakeAsync(() => { + c.statusChanges.subscribe({ + next: (status: any) => { + expect(c.status).toEqual('INVALID'); + expect(status).toEqual('INVALID'); + } + }); + + c.setValue(''); + tick(); + })); + + it('should fire an event after the status has been updated to pending', fakeAsync(() => { + const c = new FormControl('old', Validators.required, asyncValidator('expected')); + + const log: any[] /** TODO #9100 */ = []; + c.valueChanges.subscribe({next: (value: any) => log.push(`value: '${value}'`)}); + + c.statusChanges.subscribe({next: (status: any) => log.push(`status: '${status}'`)}); + + c.setValue(''); + tick(); + + c.setValue('nonEmpty'); + tick(); + + c.setValue('expected'); + tick(); + + expect(log).toEqual([ + 'value: \'\'', + 'status: \'INVALID\'', + 'value: \'nonEmpty\'', + 'status: \'PENDING\'', + 'status: \'INVALID\'', + 'value: \'expected\'', + 'status: \'PENDING\'', + 'status: \'VALID\'', + ]); + })); + + // TODO: remove the if statement after making observable delivery sync + it('should update set errors and status before emitting an event', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + c.valueChanges.subscribe((value: any /** TODO #9100 */) => { + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'required': true}); + async.done(); + }); + c.setValue(''); + })); + + it('should return a cold observable', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + c.setValue('will be ignored'); + c.valueChanges.subscribe({ + next: (value: any) => { + expect(value).toEqual('new'); + async.done(); + } + }); + c.setValue('new'); + })); + }); - c.reset({value: null, disabled: true}); - expect(logger).toEqual(['control1', 'group']); - }); - }); + describe('setErrors', () => { + it('should set errors on a control', () => { + const c = new FormControl('someValue'); + + c.setErrors({'someError': true}); + expect(c.valid).toEqual(false); + expect(c.errors).toEqual({'someError': true}); }); - describe('valueChanges & statusChanges', () => { - let c: FormControl; + it('should reset the errors and validity when the value changes', () => { + const c = new FormControl('someValue', Validators.required); - beforeEach(() => { c = new FormControl('old', Validators.required); }); + c.setErrors({'someError': true}); + c.setValue(''); - it('should fire an event after the value has been updated', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - c.valueChanges.subscribe({ - next: (value: any) => { - expect(c.value).toEqual('new'); - expect(value).toEqual('new'); - async.done(); - } - }); - c.setValue('new'); - })); + expect(c.errors).toEqual({'required': true}); + }); - it('should fire an event after the status has been updated to invalid', fakeAsync(() => { - c.statusChanges.subscribe({ - next: (status: any) => { - expect(c.status).toEqual('INVALID'); - expect(status).toEqual('INVALID'); - } - }); + it('should update the parent group\'s validity', () => { + const c = new FormControl('someValue'); + const g = new FormGroup({'one': c}); - c.setValue(''); - tick(); - })); + expect(g.valid).toEqual(true); - it('should fire an event after the status has been updated to pending', fakeAsync(() => { - const c = new FormControl('old', Validators.required, asyncValidator('expected')); + c.setErrors({'someError': true}); - const log: any[] /** TODO #9100 */ = []; - c.valueChanges.subscribe({next: (value: any) => log.push(`value: '${value}'`)}); + expect(g.valid).toEqual(false); + }); - c.statusChanges.subscribe({next: (status: any) => log.push(`status: '${status}'`)}); + it('should not reset parent\'s errors', () => { + const c = new FormControl('someValue'); + const g = new FormGroup({'one': c}); - c.setValue(''); - tick(); + g.setErrors({'someGroupError': true}); + c.setErrors({'someError': true}); - c.setValue('nonEmpty'); - tick(); + expect(g.errors).toEqual({'someGroupError': true}); + }); - c.setValue('expected'); - tick(); + it('should reset errors when updating a value', () => { + const c = new FormControl('oldValue'); + const g = new FormGroup({'one': c}); - expect(log).toEqual([ - 'value: \'\'', - 'status: \'INVALID\'', - 'value: \'nonEmpty\'', - 'status: \'PENDING\'', - 'status: \'INVALID\'', - 'value: \'expected\'', - 'status: \'PENDING\'', - 'status: \'VALID\'', - ]); - })); + g.setErrors({'someGroupError': true}); + c.setErrors({'someError': true}); - // TODO: remove the if statement after making observable delivery sync - it('should update set errors and status before emitting an event', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - c.valueChanges.subscribe((value: any /** TODO #9100 */) => { - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'required': true}); - async.done(); - }); - c.setValue(''); - })); + c.setValue('newValue'); - it('should return a cold observable', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - c.setValue('will be ignored'); - c.valueChanges.subscribe({ - next: (value: any) => { - expect(value).toEqual('new'); - async.done(); - } - }); - c.setValue('new'); - })); + expect(c.errors).toEqual(null); + expect(g.errors).toEqual(null); }); + }); - describe('setErrors', () => { - it('should set errors on a control', () => { - const c = new FormControl('someValue'); - - c.setErrors({'someError': true}); + describe('disable() & enable()', () => { + it('should mark the control as disabled', () => { + const c = new FormControl(null); + expect(c.disabled).toBe(false); + expect(c.valid).toBe(true); - expect(c.valid).toEqual(false); - expect(c.errors).toEqual({'someError': true}); - }); + c.disable(); + expect(c.disabled).toBe(true); + expect(c.valid).toBe(false); - it('should reset the errors and validity when the value changes', () => { - const c = new FormControl('someValue', Validators.required); + c.enable(); + expect(c.disabled).toBe(false); + expect(c.valid).toBe(true); + }); - c.setErrors({'someError': true}); - c.setValue(''); + it('should set the control status as disabled', () => { + const c = new FormControl(null); + expect(c.status).toEqual('VALID'); - expect(c.errors).toEqual({'required': true}); - }); + c.disable(); + expect(c.status).toEqual('DISABLED'); - it('should update the parent group\'s validity', () => { - const c = new FormControl('someValue'); - const g = new FormGroup({'one': c}); + c.enable(); + expect(c.status).toEqual('VALID'); + }); - expect(g.valid).toEqual(true); + it('should retain the original value when disabled', () => { + const c = new FormControl('some value'); + expect(c.value).toEqual('some value'); - c.setErrors({'someError': true}); + c.disable(); + expect(c.value).toEqual('some value'); - expect(g.valid).toEqual(false); - }); + c.enable(); + expect(c.value).toEqual('some value'); + }); - it('should not reset parent\'s errors', () => { - const c = new FormControl('someValue'); - const g = new FormGroup({'one': c}); + it('should keep the disabled control in the group, but return false for contains()', () => { + const c = new FormControl(''); + const g = new FormGroup({'one': c}); - g.setErrors({'someGroupError': true}); - c.setErrors({'someError': true}); + expect(g.get('one')).toBeDefined(); + expect(g.contains('one')).toBe(true); - expect(g.errors).toEqual({'someGroupError': true}); - }); + c.disable(); + expect(g.get('one')).toBeDefined(); + expect(g.contains('one')).toBe(false); + }); - it('should reset errors when updating a value', () => { - const c = new FormControl('oldValue'); - const g = new FormGroup({'one': c}); + it('should mark the parent group disabled if all controls are disabled', () => { + const c = new FormControl(); + const c2 = new FormControl(); + const g = new FormGroup({'one': c, 'two': c2}); + expect(g.enabled).toBe(true); - g.setErrors({'someGroupError': true}); - c.setErrors({'someError': true}); + c.disable(); + expect(g.enabled).toBe(true); - c.setValue('newValue'); + c2.disable(); + expect(g.enabled).toBe(false); - expect(c.errors).toEqual(null); - expect(g.errors).toEqual(null); - }); + c.enable(); + expect(g.enabled).toBe(true); }); - describe('disable() & enable()', () => { + it('should update the parent group value when child control status changes', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const g = new FormGroup({'one': c, 'two': c2}); + expect(g.value).toEqual({'one': 'one', 'two': 'two'}); - it('should mark the control as disabled', () => { - const c = new FormControl(null); - expect(c.disabled).toBe(false); - expect(c.valid).toBe(true); + c.disable(); + expect(g.value).toEqual({'two': 'two'}); - c.disable(); - expect(c.disabled).toBe(true); - expect(c.valid).toBe(false); + c2.disable(); + expect(g.value).toEqual({'one': 'one', 'two': 'two'}); - c.enable(); - expect(c.disabled).toBe(false); - expect(c.valid).toBe(true); - }); + c.enable(); + expect(g.value).toEqual({'one': 'one'}); + }); - it('should set the control status as disabled', () => { - const c = new FormControl(null); - expect(c.status).toEqual('VALID'); + it('should mark the parent array disabled if all controls are disabled', () => { + const c = new FormControl(); + const c2 = new FormControl(); + const a = new FormArray([c, c2]); + expect(a.enabled).toBe(true); - c.disable(); - expect(c.status).toEqual('DISABLED'); + c.disable(); + expect(a.enabled).toBe(true); - c.enable(); - expect(c.status).toEqual('VALID'); - }); + c2.disable(); + expect(a.enabled).toBe(false); - it('should retain the original value when disabled', () => { - const c = new FormControl('some value'); - expect(c.value).toEqual('some value'); + c.enable(); + expect(a.enabled).toBe(true); + }); - c.disable(); - expect(c.value).toEqual('some value'); + it('should update the parent array value when child control status changes', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const a = new FormArray([c, c2]); + expect(a.value).toEqual(['one', 'two']); - c.enable(); - expect(c.value).toEqual('some value'); - }); + c.disable(); + expect(a.value).toEqual(['two']); - it('should keep the disabled control in the group, but return false for contains()', () => { - const c = new FormControl(''); - const g = new FormGroup({'one': c}); + c2.disable(); + expect(a.value).toEqual(['one', 'two']); - expect(g.get('one')).toBeDefined(); - expect(g.contains('one')).toBe(true); + c.enable(); + expect(a.value).toEqual(['one']); + }); - c.disable(); - expect(g.get('one')).toBeDefined(); - expect(g.contains('one')).toBe(false); - }); + it('should ignore disabled array controls when determining dirtiness', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const a = new FormArray([c, c2]); + c.markAsDirty(); + expect(a.dirty).toBe(true); - it('should mark the parent group disabled if all controls are disabled', () => { - const c = new FormControl(); - const c2 = new FormControl(); - const g = new FormGroup({'one': c, 'two': c2}); - expect(g.enabled).toBe(true); + c.disable(); + expect(c.dirty).toBe(true); + expect(a.dirty).toBe(false); - c.disable(); - expect(g.enabled).toBe(true); + c.enable(); + expect(a.dirty).toBe(true); + }); - c2.disable(); - expect(g.enabled).toBe(false); + it('should not make a dirty array not dirty when disabling controls', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const a = new FormArray([c, c2]); - c.enable(); - expect(g.enabled).toBe(true); - }); + a.markAsDirty(); + expect(a.dirty).toBe(true); + expect(c.dirty).toBe(false); - it('should update the parent group value when child control status changes', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const g = new FormGroup({'one': c, 'two': c2}); - expect(g.value).toEqual({'one': 'one', 'two': 'two'}); + c.disable(); + expect(a.dirty).toBe(true); - c.disable(); - expect(g.value).toEqual({'two': 'two'}); + c.enable(); + expect(a.dirty).toBe(true); + }); - c2.disable(); - expect(g.value).toEqual({'one': 'one', 'two': 'two'}); + it('should ignore disabled controls in validation', () => { + const c = new FormControl(null, Validators.required); + const c2 = new FormControl(null); + const g = new FormGroup({one: c, two: c2}); + expect(g.valid).toBe(false); - c.enable(); - expect(g.value).toEqual({'one': 'one'}); - }); + c.disable(); + expect(g.valid).toBe(true); - it('should mark the parent array disabled if all controls are disabled', () => { - const c = new FormControl(); - const c2 = new FormControl(); - const a = new FormArray([c, c2]); - expect(a.enabled).toBe(true); + c.enable(); + expect(g.valid).toBe(false); + }); - c.disable(); - expect(a.enabled).toBe(true); + it('should ignore disabled controls when serializing value in a group', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const g = new FormGroup({one: c, two: c2}); + expect(g.value).toEqual({one: 'one', two: 'two'}); - c2.disable(); - expect(a.enabled).toBe(false); + c.disable(); + expect(g.value).toEqual({two: 'two'}); - c.enable(); - expect(a.enabled).toBe(true); - }); + c.enable(); + expect(g.value).toEqual({one: 'one', two: 'two'}); + }); - it('should update the parent array value when child control status changes', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const a = new FormArray([c, c2]); - expect(a.value).toEqual(['one', 'two']); + it('should ignore disabled controls when serializing value in an array', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const a = new FormArray([c, c2]); + expect(a.value).toEqual(['one', 'two']); - c.disable(); - expect(a.value).toEqual(['two']); + c.disable(); + expect(a.value).toEqual(['two']); - c2.disable(); - expect(a.value).toEqual(['one', 'two']); + c.enable(); + expect(a.value).toEqual(['one', 'two']); + }); - c.enable(); - expect(a.value).toEqual(['one']); - }); + it('should ignore disabled controls when determining dirtiness', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const g = new FormGroup({one: c, two: c2}); + c.markAsDirty(); + expect(g.dirty).toBe(true); - it('should ignore disabled array controls when determining dirtiness', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const a = new FormArray([c, c2]); - c.markAsDirty(); - expect(a.dirty).toBe(true); + c.disable(); + expect(c.dirty).toBe(true); + expect(g.dirty).toBe(false); - c.disable(); - expect(c.dirty).toBe(true); - expect(a.dirty).toBe(false); + c.enable(); + expect(g.dirty).toBe(true); + }); - c.enable(); - expect(a.dirty).toBe(true); - }); + it('should not make a dirty group not dirty when disabling controls', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const g = new FormGroup({one: c, two: c2}); - it('should not make a dirty array not dirty when disabling controls', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const a = new FormArray([c, c2]); + g.markAsDirty(); + expect(g.dirty).toBe(true); + expect(c.dirty).toBe(false); - a.markAsDirty(); - expect(a.dirty).toBe(true); - expect(c.dirty).toBe(false); + c.disable(); + expect(g.dirty).toBe(true); - c.disable(); - expect(a.dirty).toBe(true); + c.enable(); + expect(g.dirty).toBe(true); + }); - c.enable(); - expect(a.dirty).toBe(true); - }); + it('should ignore disabled controls when determining touched state', () => { + const c = new FormControl('one'); + const c2 = new FormControl('two'); + const g = new FormGroup({one: c, two: c2}); + c.markAsTouched(); + expect(g.touched).toBe(true); - it('should ignore disabled controls in validation', () => { - const c = new FormControl(null, Validators.required); - const c2 = new FormControl(null); - const g = new FormGroup({one: c, two: c2}); - expect(g.valid).toBe(false); + c.disable(); + expect(c.touched).toBe(true); + expect(g.touched).toBe(false); - c.disable(); - expect(g.valid).toBe(true); + c.enable(); + expect(g.touched).toBe(true); + }); - c.enable(); - expect(g.valid).toBe(false); - }); + it('should not run validators on disabled controls', () => { + const validator = jasmine.createSpy('validator'); + const c = new FormControl('', validator); + expect(validator.calls.count()).toEqual(1); - it('should ignore disabled controls when serializing value in a group', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const g = new FormGroup({one: c, two: c2}); - expect(g.value).toEqual({one: 'one', two: 'two'}); + c.disable(); + expect(validator.calls.count()).toEqual(1); - c.disable(); - expect(g.value).toEqual({two: 'two'}); + c.setValue('value'); + expect(validator.calls.count()).toEqual(1); - c.enable(); - expect(g.value).toEqual({one: 'one', two: 'two'}); - }); + c.enable(); + expect(validator.calls.count()).toEqual(2); + }); - it('should ignore disabled controls when serializing value in an array', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const a = new FormArray([c, c2]); - expect(a.value).toEqual(['one', 'two']); + describe('disabled errors', () => { + it('should clear out the errors when disabled', () => { + const c = new FormControl('', Validators.required); + expect(c.errors).toEqual({required: true}); c.disable(); - expect(a.value).toEqual(['two']); + expect(c.errors).toEqual(null); c.enable(); - expect(a.value).toEqual(['one', 'two']); + expect(c.errors).toEqual({required: true}); }); - it('should ignore disabled controls when determining dirtiness', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const g = new FormGroup({one: c, two: c2}); - c.markAsDirty(); - expect(g.dirty).toBe(true); - - c.disable(); - expect(c.dirty).toBe(true); - expect(g.dirty).toBe(false); - - c.enable(); - expect(g.dirty).toBe(true); - }); + it('should clear out async errors when disabled', fakeAsync(() => { + const c = new FormControl('', null!, asyncValidator('expected')); + tick(); + expect(c.errors).toEqual({'async': true}); - it('should not make a dirty group not dirty when disabling controls', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const g = new FormGroup({one: c, two: c2}); + c.disable(); + expect(c.errors).toEqual(null); - g.markAsDirty(); - expect(g.dirty).toBe(true); - expect(c.dirty).toBe(false); + c.enable(); + tick(); + expect(c.errors).toEqual({'async': true}); + })); + }); - c.disable(); - expect(g.dirty).toBe(true); + describe('disabled events', () => { + let logger: string[]; + let c: FormControl; + let g: FormGroup; - c.enable(); - expect(g.dirty).toBe(true); + beforeEach(() => { + logger = []; + c = new FormControl('', Validators.required); + g = new FormGroup({one: c}); }); - it('should ignore disabled controls when determining touched state', () => { - const c = new FormControl('one'); - const c2 = new FormControl('two'); - const g = new FormGroup({one: c, two: c2}); - c.markAsTouched(); - expect(g.touched).toBe(true); + it('should emit a statusChange event when disabled status changes', () => { + c.statusChanges.subscribe((status: string) => logger.push(status)); c.disable(); - expect(c.touched).toBe(true); - expect(g.touched).toBe(false); + expect(logger).toEqual(['DISABLED']); c.enable(); - expect(g.touched).toBe(true); + expect(logger).toEqual(['DISABLED', 'INVALID']); }); - it('should not run validators on disabled controls', () => { - const validator = jasmine.createSpy('validator'); - const c = new FormControl('', validator); - expect(validator.calls.count()).toEqual(1); + it('should emit status change events in correct order', () => { + c.statusChanges.subscribe(() => logger.push('control')); + g.statusChanges.subscribe(() => logger.push('group')); c.disable(); - expect(validator.calls.count()).toEqual(1); - - c.setValue('value'); - expect(validator.calls.count()).toEqual(1); - - c.enable(); - expect(validator.calls.count()).toEqual(2); + expect(logger).toEqual(['control', 'group']); }); - describe('disabled errors', () => { - it('should clear out the errors when disabled', () => { - const c = new FormControl('', Validators.required); - expect(c.errors).toEqual({required: true}); - - c.disable(); - expect(c.errors).toEqual(null); - - c.enable(); - expect(c.errors).toEqual({required: true}); - }); - - it('should clear out async errors when disabled', fakeAsync(() => { - const c = new FormControl('', null !, asyncValidator('expected')); - tick(); - expect(c.errors).toEqual({'async': true}); - - c.disable(); - expect(c.errors).toEqual(null); - - c.enable(); - tick(); - expect(c.errors).toEqual({'async': true}); - })); + it('should throw when sync validator passed into async validator param', () => { + const fn = () => new FormControl('', syncValidator, syncValidator); + // test for the specific error since without the error check it would still throw an error + // but + // not a meaningful one + expect(fn).toThrowError(`Expected validator to return Promise or Observable.`); }); - describe('disabled events', () => { - let logger: string[]; - let c: FormControl; - let g: FormGroup; - - beforeEach(() => { - logger = []; - c = new FormControl('', Validators.required); - g = new FormGroup({one: c}); - }); - - it('should emit a statusChange event when disabled status changes', () => { - c.statusChanges.subscribe((status: string) => logger.push(status)); - - c.disable(); - expect(logger).toEqual(['DISABLED']); - - c.enable(); - expect(logger).toEqual(['DISABLED', 'INVALID']); - - }); - - it('should emit status change events in correct order', () => { - c.statusChanges.subscribe(() => logger.push('control')); - g.statusChanges.subscribe(() => logger.push('group')); + it('should not emit value change events when emitEvent = false', () => { + c.valueChanges.subscribe(() => logger.push('control')); + g.valueChanges.subscribe(() => logger.push('group')); - c.disable(); - expect(logger).toEqual(['control', 'group']); - }); - - it('should throw when sync validator passed into async validator param', () => { - const fn = () => new FormControl('', syncValidator, syncValidator); - // test for the specific error since without the error check it would still throw an error - // but - // not a meaningful one - expect(fn).toThrowError(`Expected validator to return Promise or Observable.`); - }); + c.disable({emitEvent: false}); + expect(logger).toEqual([]); + c.enable({emitEvent: false}); + expect(logger).toEqual([]); + }); - it('should not emit value change events when emitEvent = false', () => { - c.valueChanges.subscribe(() => logger.push('control')); - g.valueChanges.subscribe(() => logger.push('group')); + it('should not emit status change events when emitEvent = false', () => { + c.statusChanges.subscribe(() => logger.push('control')); + g.statusChanges.subscribe(() => logger.push('form')); - c.disable({emitEvent: false}); - expect(logger).toEqual([]); - c.enable({emitEvent: false}); - expect(logger).toEqual([]); - }); + c.disable({emitEvent: false}); + expect(logger).toEqual([]); + c.enable({emitEvent: false}); + expect(logger).toEqual([]); + }); + }); + }); + describe('pending', () => { + let c: FormControl; - it('should not emit status change events when emitEvent = false', () => { - c.statusChanges.subscribe(() => logger.push('control')); - g.statusChanges.subscribe(() => logger.push('form')); + beforeEach(() => { + c = new FormControl('value'); + }); - c.disable({emitEvent: false}); - expect(logger).toEqual([]); - c.enable({emitEvent: false}); - expect(logger).toEqual([]); - }); + it('should be false after creating a control', () => { + expect(c.pending).toEqual(false); + }); - }); + it('should be true after changing the value of the control', () => { + c.markAsPending(); + expect(c.pending).toEqual(true); }); - describe('pending', () => { - let c: FormControl; - beforeEach(() => { c = new FormControl('value'); }); + describe('status change events', () => { + let logger: string[]; - it('should be false after creating a control', () => { expect(c.pending).toEqual(false); }); + beforeEach(() => { + logger = []; + c.statusChanges.subscribe((status) => logger.push(status)); + }); - it('should be true after changing the value of the control', () => { + it('should emit event after marking control as pending', () => { c.markAsPending(); - expect(c.pending).toEqual(true); + expect(logger).toEqual(['PENDING']); }); - describe('status change events', () => { - let logger: string[]; - - beforeEach(() => { - logger = []; - c.statusChanges.subscribe((status) => logger.push(status)); - }); - - it('should emit event after marking control as pending', () => { - c.markAsPending(); - expect(logger).toEqual(['PENDING']); - }); - - it('should not emit event when emitEvent = false', () => { - c.markAsPending({emitEvent: false}); - expect(logger).toEqual([]); - }); - + it('should not emit event when emitEvent = false', () => { + c.markAsPending({emitEvent: false}); + expect(logger).toEqual([]); }); }); }); +}); })(); diff --git a/packages/forms/test/form_group_spec.ts b/packages/forms/test/form_group_spec.ts index e72e5cfb481e1..ec90568a2eb0c 100644 --- a/packages/forms/test/form_group_spec.ts +++ b/packages/forms/test/form_group_spec.ts @@ -10,1346 +10,1368 @@ import {EventEmitter} from '@angular/core'; import {async, fakeAsync, tick} from '@angular/core/testing'; import {AsyncTestCompleter, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; import {AbstractControl, FormArray, FormControl, FormGroup, ValidationErrors, Validators} from '@angular/forms'; -import {of } from 'rxjs'; +import {of} from 'rxjs'; (function() { - function simpleValidator(c: AbstractControl): ValidationErrors|null { - return c.get('one') !.value === 'correct' ? null : {'broken': true}; - } - - function asyncValidator(expected: string, timeouts = {}) { - return (c: AbstractControl) => { - let resolve: (result: any) => void = undefined !; - const promise = new Promise<ValidationErrors|null>(res => { resolve = res; }); - const t = (timeouts as any)[c.value] != null ? (timeouts as any)[c.value] : 0; - const res = c.value != expected ? {'async': true} : null; - - if (t == 0) { +function simpleValidator(c: AbstractControl): ValidationErrors|null { + return c.get('one')!.value === 'correct' ? null : {'broken': true}; +} + +function asyncValidator(expected: string, timeouts = {}) { + return (c: AbstractControl) => { + let resolve: (result: any) => void = undefined!; + const promise = new Promise<ValidationErrors|null>(res => { + resolve = res; + }); + const t = (timeouts as any)[c.value] != null ? (timeouts as any)[c.value] : 0; + const res = c.value != expected ? {'async': true} : null; + + if (t == 0) { + resolve(res); + } else { + setTimeout(() => { resolve(res); - } else { - setTimeout(() => { resolve(res); }, t); - } - - return promise; - }; - } - - function asyncValidatorReturningObservable(c: AbstractControl) { - const e = new EventEmitter(); - Promise.resolve(null).then(() => { e.emit({'async': true}); }); - return e; - } - - function otherObservableValidator() { return of ({'other': true}); } - - describe('FormGroup', () => { - describe('value', () => { - it('should be the reduced value of the child controls', () => { - const g = new FormGroup({'one': new FormControl('111'), 'two': new FormControl('222')}); - expect(g.value).toEqual({'one': '111', 'two': '222'}); - }); + }, t); + } - it('should be empty when there are no child controls', () => { - const g = new FormGroup({}); - expect(g.value).toEqual({}); - }); + return promise; + }; +} - it('should support nested groups', () => { - const g = new FormGroup({ - 'one': new FormControl('111'), - 'nested': new FormGroup({'two': new FormControl('222')}) - }); - expect(g.value).toEqual({'one': '111', 'nested': {'two': '222'}}); +function asyncValidatorReturningObservable(c: AbstractControl) { + const e = new EventEmitter(); + Promise.resolve(null).then(() => { + e.emit({'async': true}); + }); + return e; +} + +function otherObservableValidator() { + return of({'other': true}); +} + +describe('FormGroup', () => { + describe('value', () => { + it('should be the reduced value of the child controls', () => { + const g = new FormGroup({'one': new FormControl('111'), 'two': new FormControl('222')}); + expect(g.value).toEqual({'one': '111', 'two': '222'}); + }); - (<FormControl>(g.get('nested.two'))).setValue('333'); + it('should be empty when there are no child controls', () => { + const g = new FormGroup({}); + expect(g.value).toEqual({}); + }); - expect(g.value).toEqual({'one': '111', 'nested': {'two': '333'}}); + it('should support nested groups', () => { + const g = new FormGroup({ + 'one': new FormControl('111'), + 'nested': new FormGroup({'two': new FormControl('222')}) }); - }); + expect(g.value).toEqual({'one': '111', 'nested': {'two': '222'}}); + + (<FormControl>(g.get('nested.two'))).setValue('333'); - describe('getRawValue', () => { - let fg: FormGroup; + expect(g.value).toEqual({'one': '111', 'nested': {'two': '333'}}); + }); + }); - it('should work with nested form groups/arrays', () => { - fg = new FormGroup({ - 'c1': new FormControl('v1'), - 'group': new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), - 'array': new FormArray([new FormControl('v4'), new FormControl('v5')]) - }); - fg.get('group') !.get('c3') !.disable(); - (fg.get('array') as FormArray).at(1).disable(); + describe('getRawValue', () => { + let fg: FormGroup; - expect(fg.getRawValue()) - .toEqual({'c1': 'v1', 'group': {'c2': 'v2', 'c3': 'v3'}, 'array': ['v4', 'v5']}); + it('should work with nested form groups/arrays', () => { + fg = new FormGroup({ + 'c1': new FormControl('v1'), + 'group': new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), + 'array': new FormArray([new FormControl('v4'), new FormControl('v5')]) }); + fg.get('group')!.get('c3')!.disable(); + (fg.get('array') as FormArray).at(1).disable(); + expect(fg.getRawValue()) + .toEqual({'c1': 'v1', 'group': {'c2': 'v2', 'c3': 'v3'}, 'array': ['v4', 'v5']}); }); + }); - describe('markAllAsTouched', () => { - it('should mark all descendants as touched', () => { - const formGroup: FormGroup = new FormGroup({ - 'c1': new FormControl('v1'), - 'group': new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), - 'array': new FormArray([ - new FormControl('v4'), new FormControl('v5'), - new FormGroup({'c4': new FormControl('v4')}) - ]) - }); + describe('markAllAsTouched', () => { + it('should mark all descendants as touched', () => { + const formGroup: FormGroup = new FormGroup({ + 'c1': new FormControl('v1'), + 'group': new FormGroup({'c2': new FormControl('v2'), 'c3': new FormControl('v3')}), + 'array': new FormArray([ + new FormControl('v4'), new FormControl('v5'), new FormGroup({'c4': new FormControl('v4')}) + ]) + }); - expect(formGroup.touched).toBe(false); + expect(formGroup.touched).toBe(false); - const control1 = formGroup.get('c1') as FormControl; + const control1 = formGroup.get('c1') as FormControl; - expect(control1.touched).toBe(false); + expect(control1.touched).toBe(false); - const innerGroup = formGroup.get('group') as FormGroup; + const innerGroup = formGroup.get('group') as FormGroup; - expect(innerGroup.touched).toBe(false); + expect(innerGroup.touched).toBe(false); - const innerGroupFirstChildCtrl = innerGroup.get('c2') as FormControl; + const innerGroupFirstChildCtrl = innerGroup.get('c2') as FormControl; - expect(innerGroupFirstChildCtrl.touched).toBe(false); + expect(innerGroupFirstChildCtrl.touched).toBe(false); - formGroup.markAllAsTouched(); + formGroup.markAllAsTouched(); - expect(formGroup.touched).toBe(true); + expect(formGroup.touched).toBe(true); - expect(control1.touched).toBe(true); + expect(control1.touched).toBe(true); - expect(innerGroup.touched).toBe(true); + expect(innerGroup.touched).toBe(true); - expect(innerGroupFirstChildCtrl.touched).toBe(true); + expect(innerGroupFirstChildCtrl.touched).toBe(true); - const innerGroupSecondChildCtrl = innerGroup.get('c3') as FormControl; + const innerGroupSecondChildCtrl = innerGroup.get('c3') as FormControl; - expect(innerGroupSecondChildCtrl.touched).toBe(true); + expect(innerGroupSecondChildCtrl.touched).toBe(true); - const array = formGroup.get('array') as FormArray; + const array = formGroup.get('array') as FormArray; - expect(array.touched).toBe(true); + expect(array.touched).toBe(true); - const arrayFirstChildCtrl = array.at(0) as FormControl; + const arrayFirstChildCtrl = array.at(0) as FormControl; - expect(arrayFirstChildCtrl.touched).toBe(true); + expect(arrayFirstChildCtrl.touched).toBe(true); - const arraySecondChildCtrl = array.at(1) as FormControl; + const arraySecondChildCtrl = array.at(1) as FormControl; - expect(arraySecondChildCtrl.touched).toBe(true); + expect(arraySecondChildCtrl.touched).toBe(true); - const arrayFirstChildGroup = array.at(2) as FormGroup; + const arrayFirstChildGroup = array.at(2) as FormGroup; - expect(arrayFirstChildGroup.touched).toBe(true); + expect(arrayFirstChildGroup.touched).toBe(true); - const arrayFirstChildGroupFirstChildCtrl = arrayFirstChildGroup.get('c4') as FormControl; + const arrayFirstChildGroupFirstChildCtrl = arrayFirstChildGroup.get('c4') as FormControl; - expect(arrayFirstChildGroupFirstChildCtrl.touched).toBe(true); - }); + expect(arrayFirstChildGroupFirstChildCtrl.touched).toBe(true); }); + }); - describe('adding and removing controls', () => { - it('should update value and validity when control is added', () => { - const g = new FormGroup({'one': new FormControl('1')}); - expect(g.value).toEqual({'one': '1'}); - expect(g.valid).toBe(true); + describe('adding and removing controls', () => { + it('should update value and validity when control is added', () => { + const g = new FormGroup({'one': new FormControl('1')}); + expect(g.value).toEqual({'one': '1'}); + expect(g.valid).toBe(true); - g.addControl('two', new FormControl('2', Validators.minLength(10))); + g.addControl('two', new FormControl('2', Validators.minLength(10))); - expect(g.value).toEqual({'one': '1', 'two': '2'}); - expect(g.valid).toBe(false); - }); + expect(g.value).toEqual({'one': '1', 'two': '2'}); + expect(g.valid).toBe(false); + }); - it('should update value and validity when control is removed', () => { - const g = new FormGroup( - {'one': new FormControl('1'), 'two': new FormControl('2', Validators.minLength(10))}); - expect(g.value).toEqual({'one': '1', 'two': '2'}); - expect(g.valid).toBe(false); + it('should update value and validity when control is removed', () => { + const g = new FormGroup( + {'one': new FormControl('1'), 'two': new FormControl('2', Validators.minLength(10))}); + expect(g.value).toEqual({'one': '1', 'two': '2'}); + expect(g.valid).toBe(false); - g.removeControl('two'); + g.removeControl('two'); - expect(g.value).toEqual({'one': '1'}); - expect(g.valid).toBe(true); - }); + expect(g.value).toEqual({'one': '1'}); + expect(g.valid).toBe(true); }); + }); - describe('dirty', () => { - let c: FormControl, g: FormGroup; + describe('dirty', () => { + let c: FormControl, g: FormGroup; - beforeEach(() => { - c = new FormControl('value'); - g = new FormGroup({'one': c}); - }); + beforeEach(() => { + c = new FormControl('value'); + g = new FormGroup({'one': c}); + }); - it('should be false after creating a control', () => { expect(g.dirty).toEqual(false); }); + it('should be false after creating a control', () => { + expect(g.dirty).toEqual(false); + }); - it('should be true after changing the value of the control', () => { - c.markAsDirty(); + it('should be true after changing the value of the control', () => { + c.markAsDirty(); - expect(g.dirty).toEqual(true); - }); + expect(g.dirty).toEqual(true); }); + }); - describe('touched', () => { - let c: FormControl, g: FormGroup; + describe('touched', () => { + let c: FormControl, g: FormGroup; - beforeEach(() => { - c = new FormControl('value'); - g = new FormGroup({'one': c}); - }); + beforeEach(() => { + c = new FormControl('value'); + g = new FormGroup({'one': c}); + }); - it('should be false after creating a control', () => { expect(g.touched).toEqual(false); }); + it('should be false after creating a control', () => { + expect(g.touched).toEqual(false); + }); - it('should be true after control is marked as touched', () => { - c.markAsTouched(); + it('should be true after control is marked as touched', () => { + c.markAsTouched(); - expect(g.touched).toEqual(true); - }); + expect(g.touched).toEqual(true); + }); + }); + + describe('setValue', () => { + let c: FormControl, c2: FormControl, g: FormGroup; + + beforeEach(() => { + c = new FormControl(''); + c2 = new FormControl(''); + g = new FormGroup({'one': c, 'two': c2}); + }); + + it('should set its own value', () => { + g.setValue({'one': 'one', 'two': 'two'}); + expect(g.value).toEqual({'one': 'one', 'two': 'two'}); }); - describe('setValue', () => { - let c: FormControl, c2: FormControl, g: FormGroup; + it('should set child values', () => { + g.setValue({'one': 'one', 'two': 'two'}); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + }); + + it('should set child control values if disabled', () => { + c2.disable(); + g.setValue({'one': 'one', 'two': 'two'}); + expect(c2.value).toEqual('two'); + expect(g.value).toEqual({'one': 'one'}); + expect(g.getRawValue()).toEqual({'one': 'one', 'two': 'two'}); + }); + + it('should set group value if group is disabled', () => { + g.disable(); + g.setValue({'one': 'one', 'two': 'two'}); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + + expect(g.value).toEqual({'one': 'one', 'two': 'two'}); + }); + + it('should set parent values', () => { + const form = new FormGroup({'parent': g}); + g.setValue({'one': 'one', 'two': 'two'}); + expect(form.value).toEqual({'parent': {'one': 'one', 'two': 'two'}}); + }); + + it('should not update the parent when explicitly specified', () => { + const form = new FormGroup({'parent': g}); + g.setValue({'one': 'one', 'two': 'two'}, {onlySelf: true}); + + expect(form.value).toEqual({parent: {'one': '', 'two': ''}}); + }); + + it('should throw if fields are missing from supplied value (subset)', () => { + expect(() => g.setValue({ + 'one': 'one' + })).toThrowError(new RegExp(`Must supply a value for form control with name: 'two'`)); + }); + + it('should throw if a value is provided for a missing control (superset)', () => { + expect(() => g.setValue({'one': 'one', 'two': 'two', 'three': 'three'})) + .toThrowError(new RegExp(`Cannot find form control with name: three`)); + }); + + it('should throw if a value is not provided for a disabled control', () => { + c2.disable(); + expect(() => g.setValue({ + 'one': 'one' + })).toThrowError(new RegExp(`Must supply a value for form control with name: 'two'`)); + }); + + it('should throw if no controls are set yet', () => { + const empty = new FormGroup({}); + expect(() => empty.setValue({ + 'one': 'one' + })).toThrowError(new RegExp(`no form controls registered with this group`)); + }); + + describe('setValue() events', () => { + let form: FormGroup; + let logger: any[]; beforeEach(() => { - c = new FormControl(''); - c2 = new FormControl(''); - g = new FormGroup({'one': c, 'two': c2}); + form = new FormGroup({'parent': g}); + logger = []; }); - it('should set its own value', () => { - g.setValue({'one': 'one', 'two': 'two'}); - expect(g.value).toEqual({'one': 'one', 'two': 'two'}); - }); + it('should emit one valueChange event per control', () => { + form.valueChanges.subscribe(() => logger.push('form')); + g.valueChanges.subscribe(() => logger.push('group')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - it('should set child values', () => { g.setValue({'one': 'one', 'two': 'two'}); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); - it('should set child control values if disabled', () => { - c2.disable(); - g.setValue({'one': 'one', 'two': 'two'}); - expect(c2.value).toEqual('two'); - expect(g.value).toEqual({'one': 'one'}); - expect(g.getRawValue()).toEqual({'one': 'one', 'two': 'two'}); - }); + it('should not fire an event when explicitly specified', fakeAsync(() => { + form.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + g.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); - it('should set group value if group is disabled', () => { - g.disable(); - g.setValue({'one': 'one', 'two': 'two'}); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); + g.setValue({'one': 'one', 'two': 'two'}, {emitEvent: false}); + tick(); + })); - expect(g.value).toEqual({'one': 'one', 'two': 'two'}); - }); + it('should emit one statusChange event per control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + g.statusChanges.subscribe(() => logger.push('group')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); - it('should set parent values', () => { - const form = new FormGroup({'parent': g}); g.setValue({'one': 'one', 'two': 'two'}); - expect(form.value).toEqual({'parent': {'one': 'one', 'two': 'two'}}); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); + }); + }); - it('should not update the parent when explicitly specified', () => { - const form = new FormGroup({'parent': g}); - g.setValue({'one': 'one', 'two': 'two'}, {onlySelf: true}); + describe('patchValue', () => { + let c: FormControl, c2: FormControl, g: FormGroup; - expect(form.value).toEqual({parent: {'one': '', 'two': ''}}); - }); + beforeEach(() => { + c = new FormControl(''); + c2 = new FormControl(''); + g = new FormGroup({'one': c, 'two': c2}); + }); - it('should throw if fields are missing from supplied value (subset)', () => { - expect(() => g.setValue({ - 'one': 'one' - })).toThrowError(new RegExp(`Must supply a value for form control with name: 'two'`)); - }); + it('should set its own value', () => { + g.patchValue({'one': 'one', 'two': 'two'}); + expect(g.value).toEqual({'one': 'one', 'two': 'two'}); + }); - it('should throw if a value is provided for a missing control (superset)', () => { - expect(() => g.setValue({'one': 'one', 'two': 'two', 'three': 'three'})) - .toThrowError(new RegExp(`Cannot find form control with name: three`)); - }); + it('should set child values', () => { + g.patchValue({'one': 'one', 'two': 'two'}); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + }); - it('should throw if a value is not provided for a disabled control', () => { - c2.disable(); - expect(() => g.setValue({ - 'one': 'one' - })).toThrowError(new RegExp(`Must supply a value for form control with name: 'two'`)); - }); + it('should patch disabled control values', () => { + c2.disable(); + g.patchValue({'one': 'one', 'two': 'two'}); + expect(c2.value).toEqual('two'); + expect(g.value).toEqual({'one': 'one'}); + expect(g.getRawValue()).toEqual({'one': 'one', 'two': 'two'}); + }); - it('should throw if no controls are set yet', () => { - const empty = new FormGroup({}); - expect(() => empty.setValue({ - 'one': 'one' - })).toThrowError(new RegExp(`no form controls registered with this group`)); - }); + it('should patch disabled control groups', () => { + g.disable(); + g.patchValue({'one': 'one', 'two': 'two'}); + expect(c.value).toEqual('one'); + expect(c2.value).toEqual('two'); + expect(g.value).toEqual({'one': 'one', 'two': 'two'}); + }); - describe('setValue() events', () => { - let form: FormGroup; - let logger: any[]; - - beforeEach(() => { - form = new FormGroup({'parent': g}); - logger = []; - }); - - it('should emit one valueChange event per control', () => { - form.valueChanges.subscribe(() => logger.push('form')); - g.valueChanges.subscribe(() => logger.push('group')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - - g.setValue({'one': 'one', 'two': 'two'}); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - - it('should not fire an event when explicitly specified', fakeAsync(() => { - form.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - g.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - - g.setValue({'one': 'one', 'two': 'two'}, {emitEvent: false}); - tick(); - })); - - it('should emit one statusChange event per control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - g.statusChanges.subscribe(() => logger.push('group')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - - g.setValue({'one': 'one', 'two': 'two'}); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - }); + it('should set parent values', () => { + const form = new FormGroup({'parent': g}); + g.patchValue({'one': 'one', 'two': 'two'}); + expect(form.value).toEqual({'parent': {'one': 'one', 'two': 'two'}}); + }); + + it('should not update the parent when explicitly specified', () => { + const form = new FormGroup({'parent': g}); + g.patchValue({'one': 'one', 'two': 'two'}, {onlySelf: true}); + + expect(form.value).toEqual({parent: {'one': '', 'two': ''}}); + }); + + it('should ignore fields that are missing from supplied value (subset)', () => { + g.patchValue({'one': 'one'}); + expect(g.value).toEqual({'one': 'one', 'two': ''}); + }); + + it('should not ignore fields that are null', () => { + g.patchValue({'one': null}); + expect(g.value).toEqual({'one': null, 'two': ''}); }); - describe('patchValue', () => { - let c: FormControl, c2: FormControl, g: FormGroup; + it('should ignore any value provided for a missing control (superset)', () => { + g.patchValue({'three': 'three'}); + expect(g.value).toEqual({'one': '', 'two': ''}); + }); + + describe('patchValue() events', () => { + let form: FormGroup; + let logger: any[]; beforeEach(() => { - c = new FormControl(''); - c2 = new FormControl(''); - g = new FormGroup({'one': c, 'two': c2}); + form = new FormGroup({'parent': g}); + logger = []; }); - it('should set its own value', () => { - g.patchValue({'one': 'one', 'two': 'two'}); - expect(g.value).toEqual({'one': 'one', 'two': 'two'}); - }); + it('should emit one valueChange event per control', () => { + form.valueChanges.subscribe(() => logger.push('form')); + g.valueChanges.subscribe(() => logger.push('group')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - it('should set child values', () => { g.patchValue({'one': 'one', 'two': 'two'}); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); - it('should patch disabled control values', () => { - c2.disable(); - g.patchValue({'one': 'one', 'two': 'two'}); - expect(c2.value).toEqual('two'); - expect(g.value).toEqual({'one': 'one'}); - expect(g.getRawValue()).toEqual({'one': 'one', 'two': 'two'}); - }); + it('should not emit valueChange events for skipped controls', () => { + form.valueChanges.subscribe(() => logger.push('form')); + g.valueChanges.subscribe(() => logger.push('group')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); - it('should patch disabled control groups', () => { - g.disable(); - g.patchValue({'one': 'one', 'two': 'two'}); - expect(c.value).toEqual('one'); - expect(c2.value).toEqual('two'); - expect(g.value).toEqual({'one': 'one', 'two': 'two'}); + g.patchValue({'one': 'one'}); + expect(logger).toEqual(['control1', 'group', 'form']); }); - it('should set parent values', () => { - const form = new FormGroup({'parent': g}); - g.patchValue({'one': 'one', 'two': 'two'}); - expect(form.value).toEqual({'parent': {'one': 'one', 'two': 'two'}}); - }); + it('should not fire an event when explicitly specified', fakeAsync(() => { + form.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + g.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); - it('should not update the parent when explicitly specified', () => { - const form = new FormGroup({'parent': g}); - g.patchValue({'one': 'one', 'two': 'two'}, {onlySelf: true}); + g.patchValue({'one': 'one', 'two': 'two'}, {emitEvent: false}); + tick(); + })); - expect(form.value).toEqual({parent: {'one': '', 'two': ''}}); - }); + it('should emit one statusChange event per control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + g.statusChanges.subscribe(() => logger.push('group')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); - it('should ignore fields that are missing from supplied value (subset)', () => { - g.patchValue({'one': 'one'}); - expect(g.value).toEqual({'one': 'one', 'two': ''}); + g.patchValue({'one': 'one', 'two': 'two'}); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); + }); + }); - it('should not ignore fields that are null', () => { - g.patchValue({'one': null}); - expect(g.value).toEqual({'one': null, 'two': ''}); - }); + describe('reset()', () => { + let c: FormControl, c2: FormControl, g: FormGroup; - it('should ignore any value provided for a missing control (superset)', () => { - g.patchValue({'three': 'three'}); - expect(g.value).toEqual({'one': '', 'two': ''}); - }); + beforeEach(() => { + c = new FormControl('initial value'); + c2 = new FormControl(''); + g = new FormGroup({'one': c, 'two': c2}); + }); - describe('patchValue() events', () => { - let form: FormGroup; - let logger: any[]; - - beforeEach(() => { - form = new FormGroup({'parent': g}); - logger = []; - }); - - it('should emit one valueChange event per control', () => { - form.valueChanges.subscribe(() => logger.push('form')); - g.valueChanges.subscribe(() => logger.push('group')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - - g.patchValue({'one': 'one', 'two': 'two'}); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - - it('should not emit valueChange events for skipped controls', () => { - form.valueChanges.subscribe(() => logger.push('form')); - g.valueChanges.subscribe(() => logger.push('group')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - - g.patchValue({'one': 'one'}); - expect(logger).toEqual(['control1', 'group', 'form']); - }); - - it('should not fire an event when explicitly specified', fakeAsync(() => { - form.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - g.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - - g.patchValue({'one': 'one', 'two': 'two'}, {emitEvent: false}); - tick(); - })); - - it('should emit one statusChange event per control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - g.statusChanges.subscribe(() => logger.push('group')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - - g.patchValue({'one': 'one', 'two': 'two'}); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - }); + it('should set its own value if value passed', () => { + g.setValue({'one': 'new value', 'two': 'new value'}); + + g.reset({'one': 'initial value', 'two': ''}); + expect(g.value).toEqual({'one': 'initial value', 'two': ''}); }); - describe('reset()', () => { - let c: FormControl, c2: FormControl, g: FormGroup; + it('should set its own value if boxed value passed', () => { + g.setValue({'one': 'new value', 'two': 'new value'}); - beforeEach(() => { - c = new FormControl('initial value'); - c2 = new FormControl(''); - g = new FormGroup({'one': c, 'two': c2}); - }); + g.reset({'one': {value: 'initial value', disabled: false}, 'two': ''}); + expect(g.value).toEqual({'one': 'initial value', 'two': ''}); + }); - it('should set its own value if value passed', () => { - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should clear its own value if no value passed', () => { + g.setValue({'one': 'new value', 'two': 'new value'}); - g.reset({'one': 'initial value', 'two': ''}); - expect(g.value).toEqual({'one': 'initial value', 'two': ''}); - }); + g.reset(); + expect(g.value).toEqual({'one': null, 'two': null}); + }); - it('should set its own value if boxed value passed', () => { - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should set the value of each of its child controls if value passed', () => { + g.setValue({'one': 'new value', 'two': 'new value'}); - g.reset({'one': {value: 'initial value', disabled: false}, 'two': ''}); - expect(g.value).toEqual({'one': 'initial value', 'two': ''}); - }); + g.reset({'one': 'initial value', 'two': ''}); + expect(c.value).toBe('initial value'); + expect(c2.value).toBe(''); + }); - it('should clear its own value if no value passed', () => { - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should clear the value of each of its child controls if no value passed', () => { + g.setValue({'one': 'new value', 'two': 'new value'}); - g.reset(); - expect(g.value).toEqual({'one': null, 'two': null}); - }); + g.reset(); + expect(c.value).toBe(null); + expect(c2.value).toBe(null); + }); - it('should set the value of each of its child controls if value passed', () => { - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should set the value of its parent if value passed', () => { + const form = new FormGroup({'g': g}); + g.setValue({'one': 'new value', 'two': 'new value'}); - g.reset({'one': 'initial value', 'two': ''}); - expect(c.value).toBe('initial value'); - expect(c2.value).toBe(''); - }); + g.reset({'one': 'initial value', 'two': ''}); + expect(form.value).toEqual({'g': {'one': 'initial value', 'two': ''}}); + }); - it('should clear the value of each of its child controls if no value passed', () => { - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should clear the value of its parent if no value passed', () => { + const form = new FormGroup({'g': g}); + g.setValue({'one': 'new value', 'two': 'new value'}); - g.reset(); - expect(c.value).toBe(null); - expect(c2.value).toBe(null); - }); + g.reset(); + expect(form.value).toEqual({'g': {'one': null, 'two': null}}); + }); - it('should set the value of its parent if value passed', () => { - const form = new FormGroup({'g': g}); - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should not update the parent when explicitly specified', () => { + const form = new FormGroup({'g': g}); + g.reset({'one': 'new value', 'two': 'new value'}, {onlySelf: true}); - g.reset({'one': 'initial value', 'two': ''}); - expect(form.value).toEqual({'g': {'one': 'initial value', 'two': ''}}); - }); + expect(form.value).toEqual({g: {'one': 'initial value', 'two': ''}}); + }); - it('should clear the value of its parent if no value passed', () => { - const form = new FormGroup({'g': g}); - g.setValue({'one': 'new value', 'two': 'new value'}); + it('should mark itself as pristine', () => { + g.markAsDirty(); + expect(g.pristine).toBe(false); - g.reset(); - expect(form.value).toEqual({'g': {'one': null, 'two': null}}); - }); + g.reset(); + expect(g.pristine).toBe(true); + }); - it('should not update the parent when explicitly specified', () => { - const form = new FormGroup({'g': g}); - g.reset({'one': 'new value', 'two': 'new value'}, {onlySelf: true}); + it('should mark all child controls as pristine', () => { + c.markAsDirty(); + c2.markAsDirty(); + expect(c.pristine).toBe(false); + expect(c2.pristine).toBe(false); - expect(form.value).toEqual({g: {'one': 'initial value', 'two': ''}}); - }); + g.reset(); + expect(c.pristine).toBe(true); + expect(c2.pristine).toBe(true); + }); - it('should mark itself as pristine', () => { - g.markAsDirty(); - expect(g.pristine).toBe(false); + it('should mark the parent as pristine if all siblings pristine', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'g': g, 'c3': c3}); - g.reset(); - expect(g.pristine).toBe(true); - }); + g.markAsDirty(); + expect(form.pristine).toBe(false); - it('should mark all child controls as pristine', () => { - c.markAsDirty(); - c2.markAsDirty(); - expect(c.pristine).toBe(false); - expect(c2.pristine).toBe(false); + g.reset(); + expect(form.pristine).toBe(true); + }); - g.reset(); - expect(c.pristine).toBe(true); - expect(c2.pristine).toBe(true); - }); + it('should not mark the parent pristine if any dirty siblings', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'g': g, 'c3': c3}); - it('should mark the parent as pristine if all siblings pristine', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'g': g, 'c3': c3}); + g.markAsDirty(); + c3.markAsDirty(); + expect(form.pristine).toBe(false); - g.markAsDirty(); - expect(form.pristine).toBe(false); + g.reset(); + expect(form.pristine).toBe(false); + }); - g.reset(); - expect(form.pristine).toBe(true); - }); + it('should mark itself as untouched', () => { + g.markAsTouched(); + expect(g.untouched).toBe(false); - it('should not mark the parent pristine if any dirty siblings', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'g': g, 'c3': c3}); + g.reset(); + expect(g.untouched).toBe(true); + }); - g.markAsDirty(); - c3.markAsDirty(); - expect(form.pristine).toBe(false); + it('should mark all child controls as untouched', () => { + c.markAsTouched(); + c2.markAsTouched(); + expect(c.untouched).toBe(false); + expect(c2.untouched).toBe(false); - g.reset(); - expect(form.pristine).toBe(false); - }); + g.reset(); + expect(c.untouched).toBe(true); + expect(c2.untouched).toBe(true); + }); - it('should mark itself as untouched', () => { - g.markAsTouched(); - expect(g.untouched).toBe(false); + it('should mark the parent untouched if all siblings untouched', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'g': g, 'c3': c3}); - g.reset(); - expect(g.untouched).toBe(true); - }); + g.markAsTouched(); + expect(form.untouched).toBe(false); - it('should mark all child controls as untouched', () => { - c.markAsTouched(); - c2.markAsTouched(); - expect(c.untouched).toBe(false); - expect(c2.untouched).toBe(false); + g.reset(); + expect(form.untouched).toBe(true); + }); - g.reset(); - expect(c.untouched).toBe(true); - expect(c2.untouched).toBe(true); - }); + it('should not mark the parent untouched if any touched siblings', () => { + const c3 = new FormControl(''); + const form = new FormGroup({'g': g, 'c3': c3}); - it('should mark the parent untouched if all siblings untouched', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'g': g, 'c3': c3}); + g.markAsTouched(); + c3.markAsTouched(); + expect(form.untouched).toBe(false); - g.markAsTouched(); - expect(form.untouched).toBe(false); + g.reset(); + expect(form.untouched).toBe(false); + }); - g.reset(); - expect(form.untouched).toBe(true); - }); + it('should retain previous disabled state', () => { + g.disable(); + g.reset(); - it('should not mark the parent untouched if any touched siblings', () => { - const c3 = new FormControl(''); - const form = new FormGroup({'g': g, 'c3': c3}); + expect(g.disabled).toBe(true); + }); - g.markAsTouched(); - c3.markAsTouched(); - expect(form.untouched).toBe(false); + it('should set child disabled state if boxed value passed', () => { + g.disable(); + g.reset({'one': {value: '', disabled: false}, 'two': ''}); - g.reset(); - expect(form.untouched).toBe(false); - }); + expect(c.disabled).toBe(false); + expect(g.disabled).toBe(false); + }); - it('should retain previous disabled state', () => { - g.disable(); - g.reset(); + describe('reset() events', () => { + let form: FormGroup, c3: FormControl, logger: any[]; - expect(g.disabled).toBe(true); + beforeEach(() => { + c3 = new FormControl(''); + form = new FormGroup({'g': g, 'c3': c3}); + logger = []; }); - it('should set child disabled state if boxed value passed', () => { - g.disable(); - g.reset({'one': {value: '', disabled: false}, 'two': ''}); + it('should emit one valueChange event per reset control', () => { + form.valueChanges.subscribe(() => logger.push('form')); + g.valueChanges.subscribe(() => logger.push('group')); + c.valueChanges.subscribe(() => logger.push('control1')); + c2.valueChanges.subscribe(() => logger.push('control2')); + c3.valueChanges.subscribe(() => logger.push('control3')); - expect(c.disabled).toBe(false); - expect(g.disabled).toBe(false); + g.reset(); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); - describe('reset() events', () => { - let form: FormGroup, c3: FormControl, logger: any[]; - - beforeEach(() => { - c3 = new FormControl(''); - form = new FormGroup({'g': g, 'c3': c3}); - logger = []; - }); - - it('should emit one valueChange event per reset control', () => { - form.valueChanges.subscribe(() => logger.push('form')); - g.valueChanges.subscribe(() => logger.push('group')); - c.valueChanges.subscribe(() => logger.push('control1')); - c2.valueChanges.subscribe(() => logger.push('control2')); - c3.valueChanges.subscribe(() => logger.push('control3')); - - g.reset(); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - - it('should not fire an event when explicitly specified', fakeAsync(() => { - form.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - g.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); - - g.reset({}, {emitEvent: false}); - tick(); - })); - - it('should emit one statusChange event per reset control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - g.statusChanges.subscribe(() => logger.push('group')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - c3.statusChanges.subscribe(() => logger.push('control3')); - - g.reset(); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - - it('should emit one statusChange event per reset control', () => { - form.statusChanges.subscribe(() => logger.push('form')); - g.statusChanges.subscribe(() => logger.push('group')); - c.statusChanges.subscribe(() => logger.push('control1')); - c2.statusChanges.subscribe(() => logger.push('control2')); - c3.statusChanges.subscribe(() => logger.push('control3')); - - g.reset({'one': {value: '', disabled: true}}); - expect(logger).toEqual(['control1', 'control2', 'group', 'form']); - }); - - it('should mark as pristine and not dirty before emitting valueChange and statusChange events when resetting', - () => { - const pristineAndNotDirty = () => { - expect(form.pristine).toBe(true); - expect(form.dirty).toBe(false); - }; - - c3.markAsDirty(); - expect(form.pristine).toBe(false); - expect(form.dirty).toBe(true); - - form.valueChanges.subscribe(pristineAndNotDirty); - form.statusChanges.subscribe(pristineAndNotDirty); - - form.reset(); + it('should not fire an event when explicitly specified', fakeAsync(() => { + form.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + g.valueChanges.subscribe((value) => { + throw 'Should not happen'; + }); + c.valueChanges.subscribe((value) => { + throw 'Should not happen'; }); - }); - }); + g.reset({}, {emitEvent: false}); + tick(); + })); - describe('contains', () => { - let group: FormGroup; + it('should emit one statusChange event per reset control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + g.statusChanges.subscribe(() => logger.push('group')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); + c3.statusChanges.subscribe(() => logger.push('control3')); - beforeEach(() => { - group = new FormGroup({ - 'required': new FormControl('requiredValue'), - 'optional': new FormControl({value: 'disabled value', disabled: true}) - }); + g.reset(); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); }); - it('should return false when the component is disabled', - () => { expect(group.contains('optional')).toEqual(false); }); - - it('should return false when there is no component with the given name', - () => { expect(group.contains('something else')).toEqual(false); }); + it('should emit one statusChange event per reset control', () => { + form.statusChanges.subscribe(() => logger.push('form')); + g.statusChanges.subscribe(() => logger.push('group')); + c.statusChanges.subscribe(() => logger.push('control1')); + c2.statusChanges.subscribe(() => logger.push('control2')); + c3.statusChanges.subscribe(() => logger.push('control3')); - it('should return true when the component is enabled', () => { - expect(group.contains('required')).toEqual(true); + g.reset({'one': {value: '', disabled: true}}); + expect(logger).toEqual(['control1', 'control2', 'group', 'form']); + }); - group.enable(); + it('should mark as pristine and not dirty before emitting valueChange and statusChange events when resetting', + () => { + const pristineAndNotDirty = () => { + expect(form.pristine).toBe(true); + expect(form.dirty).toBe(false); + }; - expect(group.contains('optional')).toEqual(true); - }); + c3.markAsDirty(); + expect(form.pristine).toBe(false); + expect(form.dirty).toBe(true); - it('should support controls with dots in their name', () => { - expect(group.contains('some.name')).toBe(false); - group.addControl('some.name', new FormControl()); + form.valueChanges.subscribe(pristineAndNotDirty); + form.statusChanges.subscribe(pristineAndNotDirty); - expect(group.contains('some.name')).toBe(true); - }); + form.reset(); + }); }); + }); - describe('retrieve', () => { - let group: FormGroup; + describe('contains', () => { + let group: FormGroup; - beforeEach(() => { - group = new FormGroup({ - 'required': new FormControl('requiredValue'), - }); + beforeEach(() => { + group = new FormGroup({ + 'required': new FormControl('requiredValue'), + 'optional': new FormControl({value: 'disabled value', disabled: true}) }); + }); - it('should not get inherited properties', - () => { expect(group.get('constructor')).toBe(null); }); + it('should return false when the component is disabled', () => { + expect(group.contains('optional')).toEqual(false); }); - describe('statusChanges', () => { - let control: FormControl; - let group: FormGroup; + it('should return false when there is no component with the given name', () => { + expect(group.contains('something else')).toEqual(false); + }); - beforeEach(async(() => { - control = new FormControl('', asyncValidatorReturningObservable); - group = new FormGroup({'one': control}); - })); + it('should return true when the component is enabled', () => { + expect(group.contains('required')).toEqual(true); + group.enable(); - // TODO(kara): update these tests to use fake Async - it('should fire a statusChange if child has async validation change', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const loggedValues: string[] = []; - group.statusChanges.subscribe({ - next: (status: string) => { - loggedValues.push(status); - if (loggedValues.length === 2) { - expect(loggedValues).toEqual(['PENDING', 'INVALID']); - } - async.done(); - } - }); - control.setValue(''); - })); + expect(group.contains('optional')).toEqual(true); }); - describe('getError', () => { - it('should return the error when it is present', () => { - const c = new FormControl('', Validators.required); - const g = new FormGroup({'one': c}); - expect(c.getError('required')).toEqual(true); - expect(g.getError('required', ['one'])).toEqual(true); - }); + it('should support controls with dots in their name', () => { + expect(group.contains('some.name')).toBe(false); + group.addControl('some.name', new FormControl()); - it('should return null otherwise', () => { - const c = new FormControl('not empty', Validators.required); - const g = new FormGroup({'one': c}); - expect(c.getError('invalid')).toEqual(null); - expect(g.getError('required', ['one'])).toEqual(null); - expect(g.getError('required', ['invalid'])).toEqual(null); - }); + expect(group.contains('some.name')).toBe(true); + }); + }); - it('should be able to traverse group with single string', () => { - const c = new FormControl('', Validators.required); - const g = new FormGroup({'one': c}); - expect(c.getError('required')).toEqual(true); - expect(g.getError('required', 'one')).toEqual(true); - }); + describe('retrieve', () => { + let group: FormGroup; - it('should be able to traverse group with string delimited by dots', () => { - const c = new FormControl('', Validators.required); - const g2 = new FormGroup({'two': c}); - const g1 = new FormGroup({'one': g2}); - expect(c.getError('required')).toEqual(true); - expect(g1.getError('required', 'one.two')).toEqual(true); + beforeEach(() => { + group = new FormGroup({ + 'required': new FormControl('requiredValue'), }); + }); - it('should traverse group with form array using string and numbers', () => { - const c = new FormControl('', Validators.required); - const g2 = new FormGroup({'two': c}); - const a = new FormArray([g2]); - const g1 = new FormGroup({'one': a}); - expect(c.getError('required')).toEqual(true); - expect(g1.getError('required', ['one', 0, 'two'])).toEqual(true); - }); + it('should not get inherited properties', () => { + expect(group.get('constructor')).toBe(null); }); + }); - describe('hasError', () => { - it('should return true when it is present', () => { - const c = new FormControl('', Validators.required); - const g = new FormGroup({'one': c}); - expect(c.hasError('required')).toEqual(true); - expect(g.hasError('required', ['one'])).toEqual(true); - }); + describe('statusChanges', () => { + let control: FormControl; + let group: FormGroup; + + beforeEach(async(() => { + control = new FormControl('', asyncValidatorReturningObservable); + group = new FormGroup({'one': control}); + })); + + + // TODO(kara): update these tests to use fake Async + it('should fire a statusChange if child has async validation change', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const loggedValues: string[] = []; + group.statusChanges.subscribe({ + next: (status: string) => { + loggedValues.push(status); + if (loggedValues.length === 2) { + expect(loggedValues).toEqual(['PENDING', 'INVALID']); + } + async.done(); + } + }); + control.setValue(''); + })); + }); - it('should return false otherwise', () => { - const c = new FormControl('not empty', Validators.required); - const g = new FormGroup({'one': c}); - expect(c.hasError('invalid')).toEqual(false); - expect(g.hasError('required', ['one'])).toEqual(false); - expect(g.hasError('required', ['invalid'])).toEqual(false); - }); + describe('getError', () => { + it('should return the error when it is present', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.getError('required')).toEqual(true); + expect(g.getError('required', ['one'])).toEqual(true); + }); - it('should be able to traverse group with single string', () => { - const c = new FormControl('', Validators.required); - const g = new FormGroup({'one': c}); - expect(c.hasError('required')).toEqual(true); - expect(g.hasError('required', 'one')).toEqual(true); - }); + it('should return null otherwise', () => { + const c = new FormControl('not empty', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.getError('invalid')).toEqual(null); + expect(g.getError('required', ['one'])).toEqual(null); + expect(g.getError('required', ['invalid'])).toEqual(null); + }); - it('should be able to traverse group with string delimited by dots', () => { - const c = new FormControl('', Validators.required); - const g2 = new FormGroup({'two': c}); - const g1 = new FormGroup({'one': g2}); - expect(c.hasError('required')).toEqual(true); - expect(g1.hasError('required', 'one.two')).toEqual(true); - }); - it('should traverse group with form array using string and numbers', () => { - const c = new FormControl('', Validators.required); - const g2 = new FormGroup({'two': c}); - const a = new FormArray([g2]); - const g1 = new FormGroup({'one': a}); - expect(c.getError('required')).toEqual(true); - expect(g1.getError('required', ['one', 0, 'two'])).toEqual(true); - }); + it('should be able to traverse group with single string', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.getError('required')).toEqual(true); + expect(g.getError('required', 'one')).toEqual(true); }); - describe('validator', () => { + it('should be able to traverse group with string delimited by dots', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const g1 = new FormGroup({'one': g2}); + expect(c.getError('required')).toEqual(true); + expect(g1.getError('required', 'one.two')).toEqual(true); + }); - function containsValidator(c: AbstractControl): ValidationErrors|null { - return c.get('one') !.value && c.get('one') !.value.indexOf('c') !== -1 ? null : - {'missing': true}; - } + it('should traverse group with form array using string and numbers', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const a = new FormArray([g2]); + const g1 = new FormGroup({'one': a}); + expect(c.getError('required')).toEqual(true); + expect(g1.getError('required', ['one', 0, 'two'])).toEqual(true); + }); + }); - it('should run a single validator when the value changes', () => { - const c = new FormControl(null); - const g = new FormGroup({'one': c}, simpleValidator); + describe('hasError', () => { + it('should return true when it is present', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.hasError('required')).toEqual(true); + expect(g.hasError('required', ['one'])).toEqual(true); + }); - c.setValue('correct'); + it('should return false otherwise', () => { + const c = new FormControl('not empty', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.hasError('invalid')).toEqual(false); + expect(g.hasError('required', ['one'])).toEqual(false); + expect(g.hasError('required', ['invalid'])).toEqual(false); + }); - expect(g.valid).toEqual(true); - expect(g.errors).toEqual(null); + it('should be able to traverse group with single string', () => { + const c = new FormControl('', Validators.required); + const g = new FormGroup({'one': c}); + expect(c.hasError('required')).toEqual(true); + expect(g.hasError('required', 'one')).toEqual(true); + }); - c.setValue('incorrect'); + it('should be able to traverse group with string delimited by dots', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const g1 = new FormGroup({'one': g2}); + expect(c.hasError('required')).toEqual(true); + expect(g1.hasError('required', 'one.two')).toEqual(true); + }); + it('should traverse group with form array using string and numbers', () => { + const c = new FormControl('', Validators.required); + const g2 = new FormGroup({'two': c}); + const a = new FormArray([g2]); + const g1 = new FormGroup({'one': a}); + expect(c.getError('required')).toEqual(true); + expect(g1.getError('required', ['one', 0, 'two'])).toEqual(true); + }); + }); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({'broken': true}); - }); + describe('validator', () => { + function containsValidator(c: AbstractControl): ValidationErrors|null { + return c.get('one')!.value && c.get('one')!.value.indexOf('c') !== -1 ? null : + {'missing': true}; + } - it('should support multiple validators from array', () => { - const g = new FormGroup({one: new FormControl()}, [simpleValidator, containsValidator]); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({missing: true, broken: true}); + it('should run a single validator when the value changes', () => { + const c = new FormControl(null); + const g = new FormGroup({'one': c}, simpleValidator); - g.setValue({one: 'c'}); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({broken: true}); + c.setValue('correct'); - g.setValue({one: 'correct'}); - expect(g.valid).toEqual(true); - }); + expect(g.valid).toEqual(true); + expect(g.errors).toEqual(null); - it('should set single validator from options obj', () => { - const g = new FormGroup({one: new FormControl()}, {validators: simpleValidator}); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({broken: true}); + c.setValue('incorrect'); - g.setValue({one: 'correct'}); - expect(g.valid).toEqual(true); - }); + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({'broken': true}); + }); - it('should set multiple validators from options obj', () => { - const g = new FormGroup( - {one: new FormControl()}, {validators: [simpleValidator, containsValidator]}); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({missing: true, broken: true}); + it('should support multiple validators from array', () => { + const g = new FormGroup({one: new FormControl()}, [simpleValidator, containsValidator]); + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({missing: true, broken: true}); - g.setValue({one: 'c'}); - expect(g.valid).toEqual(false); - expect(g.errors).toEqual({broken: true}); + g.setValue({one: 'c'}); + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({broken: true}); - g.setValue({one: 'correct'}); - expect(g.valid).toEqual(true); - }); + g.setValue({one: 'correct'}); + expect(g.valid).toEqual(true); + }); + it('should set single validator from options obj', () => { + const g = new FormGroup({one: new FormControl()}, {validators: simpleValidator}); + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({broken: true}); + + g.setValue({one: 'correct'}); + expect(g.valid).toEqual(true); }); - describe('asyncValidator', () => { - it('should run the async validator', fakeAsync(() => { - const c = new FormControl('value'); - const g = new FormGroup({'one': c}, null !, asyncValidator('expected')); + it('should set multiple validators from options obj', () => { + const g = new FormGroup( + {one: new FormControl()}, {validators: [simpleValidator, containsValidator]}); + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({missing: true, broken: true}); - expect(g.pending).toEqual(true); + g.setValue({one: 'c'}); + expect(g.valid).toEqual(false); + expect(g.errors).toEqual({broken: true}); - tick(1); + g.setValue({one: 'correct'}); + expect(g.valid).toEqual(true); + }); + }); - expect(g.errors).toEqual({'async': true}); - expect(g.pending).toEqual(false); - })); + describe('asyncValidator', () => { + it('should run the async validator', fakeAsync(() => { + const c = new FormControl('value'); + const g = new FormGroup({'one': c}, null!, asyncValidator('expected')); - it('should set multiple async validators from array', fakeAsync(() => { - const g = new FormGroup( - {'one': new FormControl('value')}, null !, - [asyncValidator('expected'), otherObservableValidator]); - expect(g.pending).toEqual(true); + expect(g.pending).toEqual(true); - tick(); - expect(g.errors).toEqual({'async': true, 'other': true}); - expect(g.pending).toEqual(false); - })); + tick(1); - it('should set single async validator from options obj', fakeAsync(() => { - const g = new FormGroup( - {'one': new FormControl('value')}, {asyncValidators: asyncValidator('expected')}); - expect(g.pending).toEqual(true); + expect(g.errors).toEqual({'async': true}); + expect(g.pending).toEqual(false); + })); - tick(); - expect(g.errors).toEqual({'async': true}); - expect(g.pending).toEqual(false); - })); + it('should set multiple async validators from array', fakeAsync(() => { + const g = new FormGroup( + {'one': new FormControl('value')}, null!, + [asyncValidator('expected'), otherObservableValidator]); + expect(g.pending).toEqual(true); - it('should set multiple async validators from options obj', fakeAsync(() => { - const g = new FormGroup( - {'one': new FormControl('value')}, - {asyncValidators: [asyncValidator('expected'), otherObservableValidator]}); - expect(g.pending).toEqual(true); + tick(); + expect(g.errors).toEqual({'async': true, 'other': true}); + expect(g.pending).toEqual(false); + })); - tick(); - expect(g.errors).toEqual({'async': true, 'other': true}); - expect(g.pending).toEqual(false); - })); + it('should set single async validator from options obj', fakeAsync(() => { + const g = new FormGroup( + {'one': new FormControl('value')}, {asyncValidators: asyncValidator('expected')}); + expect(g.pending).toEqual(true); - it('should set the parent group\'s status to pending', fakeAsync(() => { - const c = new FormControl('value', null !, asyncValidator('expected')); - const g = new FormGroup({'one': c}); + tick(); + expect(g.errors).toEqual({'async': true}); + expect(g.pending).toEqual(false); + })); - expect(g.pending).toEqual(true); + it('should set multiple async validators from options obj', fakeAsync(() => { + const g = new FormGroup( + {'one': new FormControl('value')}, + {asyncValidators: [asyncValidator('expected'), otherObservableValidator]}); + expect(g.pending).toEqual(true); - tick(1); + tick(); + expect(g.errors).toEqual({'async': true, 'other': true}); + expect(g.pending).toEqual(false); + })); - expect(g.pending).toEqual(false); - })); + it('should set the parent group\'s status to pending', fakeAsync(() => { + const c = new FormControl('value', null!, asyncValidator('expected')); + const g = new FormGroup({'one': c}); - it('should run the parent group\'s async validator when children are pending', - fakeAsync(() => { - const c = new FormControl('value', null !, asyncValidator('expected')); - const g = new FormGroup({'one': c}, null !, asyncValidator('expected')); + expect(g.pending).toEqual(true); - tick(1); + tick(1); - expect(g.errors).toEqual({'async': true}); - expect(g.get('one') !.errors).toEqual({'async': true}); - })); + expect(g.pending).toEqual(false); + })); + + it('should run the parent group\'s async validator when children are pending', fakeAsync(() => { + const c = new FormControl('value', null!, asyncValidator('expected')); + const g = new FormGroup({'one': c}, null!, asyncValidator('expected')); + + tick(1); + + expect(g.errors).toEqual({'async': true}); + expect(g.get('one')!.errors).toEqual({'async': true}); + })); + }); + + describe('disable() & enable()', () => { + it('should mark the group as disabled', () => { + const g = new FormGroup({'one': new FormControl(null)}); + expect(g.disabled).toBe(false); + expect(g.valid).toBe(true); + + g.disable(); + expect(g.disabled).toBe(true); + expect(g.valid).toBe(false); + + g.enable(); + expect(g.disabled).toBe(false); + expect(g.valid).toBe(true); }); - describe('disable() & enable()', () => { - it('should mark the group as disabled', () => { - const g = new FormGroup({'one': new FormControl(null)}); - expect(g.disabled).toBe(false); - expect(g.valid).toBe(true); + it('should set the group status as disabled', () => { + const g = new FormGroup({'one': new FormControl(null)}); + expect(g.status).toEqual('VALID'); - g.disable(); - expect(g.disabled).toBe(true); - expect(g.valid).toBe(false); + g.disable(); + expect(g.status).toEqual('DISABLED'); - g.enable(); - expect(g.disabled).toBe(false); - expect(g.valid).toBe(true); - }); + g.enable(); + expect(g.status).toBe('VALID'); + }); - it('should set the group status as disabled', () => { - const g = new FormGroup({'one': new FormControl(null)}); - expect(g.status).toEqual('VALID'); + it('should mark children of the group as disabled', () => { + const c1 = new FormControl(null); + const c2 = new FormControl(null); + const g = new FormGroup({'one': c1, 'two': c2}); + expect(c1.disabled).toBe(false); + expect(c2.disabled).toBe(false); - g.disable(); - expect(g.status).toEqual('DISABLED'); + g.disable(); + expect(c1.disabled).toBe(true); + expect(c2.disabled).toBe(true); - g.enable(); - expect(g.status).toBe('VALID'); + g.enable(); + expect(c1.disabled).toBe(false); + expect(c2.disabled).toBe(false); + }); + + it('should ignore disabled controls in validation', () => { + const g = new FormGroup({ + nested: new FormGroup({one: new FormControl(null, Validators.required)}), + two: new FormControl('two') }); + expect(g.valid).toBe(false); - it('should mark children of the group as disabled', () => { - const c1 = new FormControl(null); - const c2 = new FormControl(null); - const g = new FormGroup({'one': c1, 'two': c2}); - expect(c1.disabled).toBe(false); - expect(c2.disabled).toBe(false); + g.get('nested')!.disable(); + expect(g.valid).toBe(true); - g.disable(); - expect(c1.disabled).toBe(true); - expect(c2.disabled).toBe(true); + g.get('nested')!.enable(); + expect(g.valid).toBe(false); + }); - g.enable(); - expect(c1.disabled).toBe(false); - expect(c2.disabled).toBe(false); - }); + it('should ignore disabled controls when serializing value', () => { + const g = new FormGroup( + {nested: new FormGroup({one: new FormControl('one')}), two: new FormControl('two')}); + expect(g.value).toEqual({'nested': {'one': 'one'}, 'two': 'two'}); - it('should ignore disabled controls in validation', () => { - const g = new FormGroup({ - nested: new FormGroup({one: new FormControl(null, Validators.required)}), - two: new FormControl('two') - }); - expect(g.valid).toBe(false); + g.get('nested')!.disable(); + expect(g.value).toEqual({'two': 'two'}); - g.get('nested') !.disable(); - expect(g.valid).toBe(true); + g.get('nested')!.enable(); + expect(g.value).toEqual({'nested': {'one': 'one'}, 'two': 'two'}); + }); - g.get('nested') !.enable(); - expect(g.valid).toBe(false); - }); + it('should update its value when disabled with disabled children', () => { + const g = new FormGroup( + {nested: new FormGroup({one: new FormControl('one'), two: new FormControl('two')})}); - it('should ignore disabled controls when serializing value', () => { - const g = new FormGroup( - {nested: new FormGroup({one: new FormControl('one')}), two: new FormControl('two')}); - expect(g.value).toEqual({'nested': {'one': 'one'}, 'two': 'two'}); + g.get('nested.two')!.disable(); + expect(g.value).toEqual({nested: {one: 'one'}}); - g.get('nested') !.disable(); - expect(g.value).toEqual({'two': 'two'}); + g.get('nested')!.disable(); + expect(g.value).toEqual({nested: {one: 'one', two: 'two'}}); - g.get('nested') !.enable(); - expect(g.value).toEqual({'nested': {'one': 'one'}, 'two': 'two'}); - }); + g.get('nested')!.enable(); + expect(g.value).toEqual({nested: {one: 'one', two: 'two'}}); + }); - it('should update its value when disabled with disabled children', () => { - const g = new FormGroup( - {nested: new FormGroup({one: new FormControl('one'), two: new FormControl('two')})}); + it('should update its value when enabled with disabled children', () => { + const g = new FormGroup( + {nested: new FormGroup({one: new FormControl('one'), two: new FormControl('two')})}); - g.get('nested.two') !.disable(); - expect(g.value).toEqual({nested: {one: 'one'}}); + g.get('nested.two')!.disable(); + expect(g.value).toEqual({nested: {one: 'one'}}); - g.get('nested') !.disable(); - expect(g.value).toEqual({nested: {one: 'one', two: 'two'}}); + g.get('nested')!.enable(); + expect(g.value).toEqual({nested: {one: 'one', two: 'two'}}); + }); - g.get('nested') !.enable(); - expect(g.value).toEqual({nested: {one: 'one', two: 'two'}}); - }); + it('should ignore disabled controls when determining dirtiness', () => { + const g = new FormGroup( + {nested: new FormGroup({one: new FormControl('one')}), two: new FormControl('two')}); + g.get('nested.one')!.markAsDirty(); + expect(g.dirty).toBe(true); - it('should update its value when enabled with disabled children', () => { - const g = new FormGroup( - {nested: new FormGroup({one: new FormControl('one'), two: new FormControl('two')})}); + g.get('nested')!.disable(); + expect(g.get('nested')!.dirty).toBe(true); + expect(g.dirty).toEqual(false); - g.get('nested.two') !.disable(); - expect(g.value).toEqual({nested: {one: 'one'}}); + g.get('nested')!.enable(); + expect(g.dirty).toEqual(true); + }); - g.get('nested') !.enable(); - expect(g.value).toEqual({nested: {one: 'one', two: 'two'}}); - }); + it('should ignore disabled controls when determining touched state', () => { + const g = new FormGroup( + {nested: new FormGroup({one: new FormControl('one')}), two: new FormControl('two')}); + g.get('nested.one')!.markAsTouched(); + expect(g.touched).toBe(true); - it('should ignore disabled controls when determining dirtiness', () => { - const g = new FormGroup( - {nested: new FormGroup({one: new FormControl('one')}), two: new FormControl('two')}); - g.get('nested.one') !.markAsDirty(); - expect(g.dirty).toBe(true); + g.get('nested')!.disable(); + expect(g.get('nested')!.touched).toBe(true); + expect(g.touched).toEqual(false); - g.get('nested') !.disable(); - expect(g.get('nested') !.dirty).toBe(true); - expect(g.dirty).toEqual(false); + g.get('nested')!.enable(); + expect(g.touched).toEqual(true); + }); - g.get('nested') !.enable(); - expect(g.dirty).toEqual(true); - }); + it('should keep empty, disabled groups disabled when updating validity', () => { + const group = new FormGroup({}); + expect(group.status).toEqual('VALID'); - it('should ignore disabled controls when determining touched state', () => { - const g = new FormGroup( - {nested: new FormGroup({one: new FormControl('one')}), two: new FormControl('two')}); - g.get('nested.one') !.markAsTouched(); - expect(g.touched).toBe(true); + group.disable(); + expect(group.status).toEqual('DISABLED'); - g.get('nested') !.disable(); - expect(g.get('nested') !.touched).toBe(true); - expect(g.touched).toEqual(false); + group.updateValueAndValidity(); + expect(group.status).toEqual('DISABLED'); - g.get('nested') !.enable(); - expect(g.touched).toEqual(true); - }); + group.addControl('one', new FormControl({value: '', disabled: true})); + expect(group.status).toEqual('DISABLED'); - it('should keep empty, disabled groups disabled when updating validity', () => { - const group = new FormGroup({}); - expect(group.status).toEqual('VALID'); + group.addControl('two', new FormControl()); + expect(group.status).toEqual('VALID'); + }); - group.disable(); - expect(group.status).toEqual('DISABLED'); + it('should re-enable empty, disabled groups', () => { + const group = new FormGroup({}); + group.disable(); + expect(group.status).toEqual('DISABLED'); - group.updateValueAndValidity(); - expect(group.status).toEqual('DISABLED'); + group.enable(); + expect(group.status).toEqual('VALID'); + }); - group.addControl('one', new FormControl({value: '', disabled: true})); - expect(group.status).toEqual('DISABLED'); + it('should not run validators on disabled controls', () => { + const validator = jasmine.createSpy('validator'); + const g = new FormGroup({'one': new FormControl()}, validator); + expect(validator.calls.count()).toEqual(1); - group.addControl('two', new FormControl()); - expect(group.status).toEqual('VALID'); - }); + g.disable(); + expect(validator.calls.count()).toEqual(1); - it('should re-enable empty, disabled groups', () => { - const group = new FormGroup({}); - group.disable(); - expect(group.status).toEqual('DISABLED'); + g.setValue({one: 'value'}); + expect(validator.calls.count()).toEqual(1); - group.enable(); - expect(group.status).toEqual('VALID'); - }); + g.enable(); + expect(validator.calls.count()).toEqual(2); + }); - it('should not run validators on disabled controls', () => { - const validator = jasmine.createSpy('validator'); - const g = new FormGroup({'one': new FormControl()}, validator); - expect(validator.calls.count()).toEqual(1); + describe('disabled errors', () => { + it('should clear out group errors when disabled', () => { + const g = new FormGroup({'one': new FormControl()}, () => ({'expected': true})); + expect(g.errors).toEqual({'expected': true}); g.disable(); - expect(validator.calls.count()).toEqual(1); - - g.setValue({one: 'value'}); - expect(validator.calls.count()).toEqual(1); + expect(g.errors).toEqual(null); g.enable(); - expect(validator.calls.count()).toEqual(2); + expect(g.errors).toEqual({'expected': true}); }); - describe('disabled errors', () => { - it('should clear out group errors when disabled', () => { - const g = new FormGroup({'one': new FormControl()}, () => ({'expected': true})); - expect(g.errors).toEqual({'expected': true}); - - g.disable(); - expect(g.errors).toEqual(null); - - g.enable(); - expect(g.errors).toEqual({'expected': true}); - }); - - it('should re-populate group errors when enabled from a child', () => { - const g = new FormGroup({'one': new FormControl()}, () => ({'expected': true})); - g.disable(); - expect(g.errors).toEqual(null); - - g.addControl('two', new FormControl()); - expect(g.errors).toEqual({'expected': true}); - }); - - it('should clear out async group errors when disabled', fakeAsync(() => { - const g = - new FormGroup({'one': new FormControl()}, null !, asyncValidator('expected')); - tick(); - expect(g.errors).toEqual({'async': true}); - - g.disable(); - expect(g.errors).toEqual(null); - - g.enable(); - tick(); - expect(g.errors).toEqual({'async': true}); - })); - - it('should re-populate async group errors when enabled from a child', fakeAsync(() => { - const g = - new FormGroup({'one': new FormControl()}, null !, asyncValidator('expected')); - tick(); - expect(g.errors).toEqual({'async': true}); - - g.disable(); - expect(g.errors).toEqual(null); - - g.addControl('two', new FormControl()); - tick(); - expect(g.errors).toEqual({'async': true}); - })); + it('should re-populate group errors when enabled from a child', () => { + const g = new FormGroup({'one': new FormControl()}, () => ({'expected': true})); + g.disable(); + expect(g.errors).toEqual(null); + + g.addControl('two', new FormControl()); + expect(g.errors).toEqual({'expected': true}); }); - describe('disabled events', () => { - let logger: string[]; - let c: FormControl; - let g: FormGroup; - let form: FormGroup; - - beforeEach(() => { - logger = []; - c = new FormControl('', Validators.required); - g = new FormGroup({one: c}); - form = new FormGroup({g: g}); - }); - - it('should emit value change events in the right order', () => { - c.valueChanges.subscribe(() => logger.push('control')); - g.valueChanges.subscribe(() => logger.push('group')); - form.valueChanges.subscribe(() => logger.push('form')); - - g.disable(); - expect(logger).toEqual(['control', 'group', 'form']); - }); - - it('should emit status change events in the right order', () => { - c.statusChanges.subscribe(() => logger.push('control')); - g.statusChanges.subscribe(() => logger.push('group')); - form.statusChanges.subscribe(() => logger.push('form')); - - g.disable(); - expect(logger).toEqual(['control', 'group', 'form']); - }); - - it('should not emit value change events when emitEvent = false', () => { - c.valueChanges.subscribe(() => logger.push('control')); - g.valueChanges.subscribe(() => logger.push('group')); - form.valueChanges.subscribe(() => logger.push('form')); - - g.disable({emitEvent: false}); - expect(logger).toEqual([]); - g.enable({emitEvent: false}); - expect(logger).toEqual([]); - }); - - it('should not emit status change events when emitEvent = false', () => { - c.statusChanges.subscribe(() => logger.push('control')); - g.statusChanges.subscribe(() => logger.push('group')); - form.statusChanges.subscribe(() => logger.push('form')); - - g.disable({emitEvent: false}); - expect(logger).toEqual([]); - g.enable({emitEvent: false}); - expect(logger).toEqual([]); - }); + it('should clear out async group errors when disabled', fakeAsync(() => { + const g = new FormGroup({'one': new FormControl()}, null!, asyncValidator('expected')); + tick(); + expect(g.errors).toEqual({'async': true}); - }); + g.disable(); + expect(g.errors).toEqual(null); + + g.enable(); + tick(); + expect(g.errors).toEqual({'async': true}); + })); + + it('should re-populate async group errors when enabled from a child', fakeAsync(() => { + const g = new FormGroup({'one': new FormControl()}, null!, asyncValidator('expected')); + tick(); + expect(g.errors).toEqual({'async': true}); + g.disable(); + expect(g.errors).toEqual(null); + + g.addControl('two', new FormControl()); + tick(); + expect(g.errors).toEqual({'async': true}); + })); }); - describe('updateTreeValidity()', () => { - let c: FormControl, c2: FormControl, c3: FormControl; - let nested: FormGroup, form: FormGroup; + describe('disabled events', () => { let logger: string[]; + let c: FormControl; + let g: FormGroup; + let form: FormGroup; beforeEach(() => { - c = new FormControl('one'); - c2 = new FormControl('two'); - c3 = new FormControl('three'); - nested = new FormGroup({one: c, two: c2}); - form = new FormGroup({nested: nested, three: c3}); logger = []; + c = new FormControl('', Validators.required); + g = new FormGroup({one: c}); + form = new FormGroup({g: g}); + }); - c.statusChanges.subscribe(() => logger.push('one')); - c2.statusChanges.subscribe(() => logger.push('two')); - c3.statusChanges.subscribe(() => logger.push('three')); - nested.statusChanges.subscribe(() => logger.push('nested')); + it('should emit value change events in the right order', () => { + c.valueChanges.subscribe(() => logger.push('control')); + g.valueChanges.subscribe(() => logger.push('group')); + form.valueChanges.subscribe(() => logger.push('form')); + + g.disable(); + expect(logger).toEqual(['control', 'group', 'form']); + }); + + it('should emit status change events in the right order', () => { + c.statusChanges.subscribe(() => logger.push('control')); + g.statusChanges.subscribe(() => logger.push('group')); form.statusChanges.subscribe(() => logger.push('form')); + + g.disable(); + expect(logger).toEqual(['control', 'group', 'form']); }); - it('should update tree validity', () => { - (form as any)._updateTreeValidity(); - expect(logger).toEqual(['one', 'two', 'nested', 'three', 'form']); + it('should not emit value change events when emitEvent = false', () => { + c.valueChanges.subscribe(() => logger.push('control')); + g.valueChanges.subscribe(() => logger.push('group')); + form.valueChanges.subscribe(() => logger.push('form')); + + g.disable({emitEvent: false}); + expect(logger).toEqual([]); + g.enable({emitEvent: false}); + expect(logger).toEqual([]); }); - it('should not emit events when turned off', () => { - (form as any)._updateTreeValidity({emitEvent: false}); + it('should not emit status change events when emitEvent = false', () => { + c.statusChanges.subscribe(() => logger.push('control')); + g.statusChanges.subscribe(() => logger.push('group')); + form.statusChanges.subscribe(() => logger.push('form')); + + g.disable({emitEvent: false}); + expect(logger).toEqual([]); + g.enable({emitEvent: false}); expect(logger).toEqual([]); }); + }); + }); + describe('updateTreeValidity()', () => { + let c: FormControl, c2: FormControl, c3: FormControl; + let nested: FormGroup, form: FormGroup; + let logger: string[]; + + beforeEach(() => { + c = new FormControl('one'); + c2 = new FormControl('two'); + c3 = new FormControl('three'); + nested = new FormGroup({one: c, two: c2}); + form = new FormGroup({nested: nested, three: c3}); + logger = []; + + c.statusChanges.subscribe(() => logger.push('one')); + c2.statusChanges.subscribe(() => logger.push('two')); + c3.statusChanges.subscribe(() => logger.push('three')); + nested.statusChanges.subscribe(() => logger.push('nested')); + form.statusChanges.subscribe(() => logger.push('form')); }); - describe('setControl()', () => { - let c: FormControl; - let g: FormGroup; + it('should update tree validity', () => { + (form as any)._updateTreeValidity(); + expect(logger).toEqual(['one', 'two', 'nested', 'three', 'form']); + }); - beforeEach(() => { - c = new FormControl('one'); - g = new FormGroup({one: c}); - }); + it('should not emit events when turned off', () => { + (form as any)._updateTreeValidity({emitEvent: false}); + expect(logger).toEqual([]); + }); + }); - it('should replace existing control with new control', () => { - const c2 = new FormControl('new!', Validators.minLength(10)); - g.setControl('one', c2); + describe('setControl()', () => { + let c: FormControl; + let g: FormGroup; - expect(g.controls['one']).toEqual(c2); - expect(g.value).toEqual({one: 'new!'}); - expect(g.valid).toBe(false); - }); + beforeEach(() => { + c = new FormControl('one'); + g = new FormGroup({one: c}); + }); - it('should add control if control did not exist before', () => { - const c2 = new FormControl('new!', Validators.minLength(10)); - g.setControl('two', c2); + it('should replace existing control with new control', () => { + const c2 = new FormControl('new!', Validators.minLength(10)); + g.setControl('one', c2); - expect(g.controls['two']).toEqual(c2); - expect(g.value).toEqual({one: 'one', two: 'new!'}); - expect(g.valid).toBe(false); - }); + expect(g.controls['one']).toEqual(c2); + expect(g.value).toEqual({one: 'new!'}); + expect(g.valid).toBe(false); + }); - it('should remove control if new control is null', () => { - g.setControl('one', null !); - expect(g.controls['one']).not.toBeDefined(); - expect(g.value).toEqual({}); - }); + it('should add control if control did not exist before', () => { + const c2 = new FormControl('new!', Validators.minLength(10)); + g.setControl('two', c2); - it('should only emit value change event once', () => { - const logger: string[] = []; - const c2 = new FormControl('new!'); - g.valueChanges.subscribe(() => logger.push('change!')); - g.setControl('one', c2); - expect(logger).toEqual(['change!']); - }); + expect(g.controls['two']).toEqual(c2); + expect(g.value).toEqual({one: 'one', two: 'new!'}); + expect(g.valid).toBe(false); + }); + it('should remove control if new control is null', () => { + g.setControl('one', null!); + expect(g.controls['one']).not.toBeDefined(); + expect(g.value).toEqual({}); }); - describe('pending', () => { - let c: FormControl; - let g: FormGroup; + it('should only emit value change event once', () => { + const logger: string[] = []; + const c2 = new FormControl('new!'); + g.valueChanges.subscribe(() => logger.push('change!')); + g.setControl('one', c2); + expect(logger).toEqual(['change!']); + }); + }); + + describe('pending', () => { + let c: FormControl; + let g: FormGroup; + + beforeEach(() => { + c = new FormControl('value'); + g = new FormGroup({'one': c}); + }); + + it('should be false after creating a control', () => { + expect(g.pending).toEqual(false); + }); + + it('should be true after changing the value of the control', () => { + c.markAsPending(); + expect(g.pending).toEqual(true); + }); + + it('should not update the parent when onlySelf = true', () => { + c.markAsPending({onlySelf: true}); + expect(g.pending).toEqual(false); + }); + + describe('status change events', () => { + let logger: string[]; beforeEach(() => { - c = new FormControl('value'); - g = new FormGroup({'one': c}); + logger = []; + g.statusChanges.subscribe((status) => logger.push(status)); }); - it('should be false after creating a control', () => { expect(g.pending).toEqual(false); }); - - it('should be true after changing the value of the control', () => { + it('should emit event after marking control as pending', () => { c.markAsPending(); - expect(g.pending).toEqual(true); + expect(logger).toEqual(['PENDING']); }); - it('should not update the parent when onlySelf = true', () => { + it('should not emit event when onlySelf = true', () => { c.markAsPending({onlySelf: true}); - expect(g.pending).toEqual(false); + expect(logger).toEqual([]); }); - describe('status change events', () => { - let logger: string[]; - - beforeEach(() => { - logger = []; - g.statusChanges.subscribe((status) => logger.push(status)); - }); - - it('should emit event after marking control as pending', () => { - c.markAsPending(); - expect(logger).toEqual(['PENDING']); - }); - - it('should not emit event when onlySelf = true', () => { - c.markAsPending({onlySelf: true}); - expect(logger).toEqual([]); - }); - - it('should not emit event when emitEvent = false', () => { - c.markAsPending({emitEvent: false}); - expect(logger).toEqual([]); - }); - - it('should emit event when parent is markedAsPending', () => { - g.markAsPending(); - expect(logger).toEqual(['PENDING']); - }); + it('should not emit event when emitEvent = false', () => { + c.markAsPending({emitEvent: false}); + expect(logger).toEqual([]); }); - }); + it('should emit event when parent is markedAsPending', () => { + g.markAsPending(); + expect(logger).toEqual(['PENDING']); + }); + }); }); +}); })(); diff --git a/packages/forms/test/reactive_integration_spec.ts b/packages/forms/test/reactive_integration_spec.ts index 9a1b144dda26e..8e8d5e0f4cb74 100644 --- a/packages/forms/test/reactive_integration_spec.ts +++ b/packages/forms/test/reactive_integration_spec.ts @@ -7,8 +7,8 @@ */ import {ɵgetDOM as getDOM} from '@angular/common'; -import {Component, Directive, Input, Type, forwardRef} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {Component, Directive, forwardRef, Input, Type} from '@angular/core'; +import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {AbstractControl, AsyncValidator, AsyncValidatorFn, COMPOSITION_BUFFER_MODE, FormArray, FormControl, FormControlDirective, FormControlName, FormGroup, FormGroupDirective, FormsModule, NG_ASYNC_VALIDATORS, NG_VALIDATORS, ReactiveFormsModule, Validators} from '@angular/forms'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {dispatchEvent, sortedClassList} from '@angular/platform-browser/testing/src/browser_util'; @@ -19,7 +19,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; { describe('reactive forms integration tests', () => { - function initTest<T>(component: Type<T>, ...directives: Type<any>[]): ComponentFixture<T> { TestBed.configureTestingModule( {declarations: [component, ...directives], imports: [FormsModule, ReactiveFormsModule]}); @@ -74,11 +73,9 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(form.value).toEqual({'login': 'updatedValue'}); }); - }); describe('re-bound form groups', () => { - it('should update DOM elements initially', () => { const fixture = initTest(FormGroupComp); fixture.componentInstance.form = new FormGroup({'login': new FormControl('oldValue')}); @@ -150,7 +147,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; }); fixture.componentInstance.form = form; fixture.detectChanges(); - expect(form.get('login') !.errors).toEqual({required: true}); + expect(form.get('login')!.errors).toEqual({required: true}); const newForm = new FormGroup({ 'login': new FormControl(''), @@ -161,34 +158,31 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; fixture.componentInstance.form = newForm; fixture.detectChanges(); - expect(newForm.get('login') !.errors).toEqual({required: true}); + expect(newForm.get('login')!.errors).toEqual({required: true}); }); it('should pick up dir validators from nested form groups', () => { const fixture = initTest(NestedFormGroupComp, LoginIsEmptyValidator); const form = new FormGroup({ - 'signin': - new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) + 'signin': new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) }); fixture.componentInstance.form = form; fixture.detectChanges(); - expect(form.get('signin') !.valid).toBe(false); + expect(form.get('signin')!.valid).toBe(false); const newForm = new FormGroup({ - 'signin': - new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) + 'signin': new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) }); fixture.componentInstance.form = newForm; fixture.detectChanges(); - expect(form.get('signin') !.valid).toBe(false); + expect(form.get('signin')!.valid).toBe(false); }); it('should strip named controls that are not found', () => { const fixture = initTest(NestedFormGroupComp, LoginIsEmptyValidator); const form = new FormGroup({ - 'signin': - new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) + 'signin': new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) }); fixture.componentInstance.form = form; fixture.detectChanges(); @@ -200,8 +194,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(emailInput.nativeElement.value).toEqual('email'); const newForm = new FormGroup({ - 'signin': - new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) + 'signin': new FormGroup({'login': new FormControl(''), 'password': new FormControl('')}) }); fixture.componentInstance.form = newForm; fixture.detectChanges(); @@ -237,7 +230,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; }); describe('nested control rebinding', () => { - it('should attach dir to control when leaf control changes', () => { const form = new FormGroup({'login': new FormControl('oldValue')}); const fixture = initTest(FormGroupComp); @@ -359,7 +351,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(newArr.value).toEqual(['last one']); - newArr.get([0]) !.setValue('set value'); + newArr.get([0])!.setValue('set value'); fixture.detectChanges(); firstInput = fixture.debugElement.query(By.css('input')).nativeElement; @@ -416,14 +408,12 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(newArr.value).toEqual(['SF', 'LA', 'Tulsa']); - newArr.get([2]) !.setValue('NY'); + newArr.get([2])!.setValue('NY'); fixture.detectChanges(); expect(lastInput.value).toEqual('NY'); }); - }); - }); describe('form arrays', () => { @@ -494,7 +484,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; cities: [{town: 'LA', state: 'CA'}, {town: 'NY', state: 'NY'}] }); }); - }); describe('programmatic changes', () => { @@ -592,13 +581,10 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; const input = fixture.debugElement.query(By.css('my-input')); expect(input.nativeElement.getAttribute('disabled')).toBe(null); }); - }); - }); describe('user input', () => { - it('should mark controls as touched after interacting with the DOM control', () => { const fixture = initTest(FormGroupComp); const login = new FormControl('oldValue'); @@ -613,14 +599,13 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(login.touched).toBe(true); }); - }); describe('submit and reset events', () => { it('should emit ngSubmit event with the original submit event on submit', () => { const fixture = initTest(FormGroupComp); fixture.componentInstance.form = new FormGroup({'login': new FormControl('loginValue')}); - fixture.componentInstance.event = null !; + fixture.componentInstance.event = null!; fixture.detectChanges(); const formEl = fixture.debugElement.query(By.css('form')).nativeElement; @@ -672,18 +657,18 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; form.reset(); expect(loginEl.value).toBe(''); }); - }); describe('value changes and status changes', () => { - it('should mark controls as dirty before emitting a value change event', () => { const fixture = initTest(FormGroupComp); const login = new FormControl('oldValue'); fixture.componentInstance.form = new FormGroup({'login': login}); fixture.detectChanges(); - login.valueChanges.subscribe(() => { expect(login.dirty).toBe(true); }); + login.valueChanges.subscribe(() => { + expect(login.dirty).toBe(true); + }); const loginEl = fixture.debugElement.query(By.css('input')).nativeElement; loginEl.value = 'newValue'; @@ -705,11 +690,12 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(login.pristine).toBe(false); - login.valueChanges.subscribe(() => { expect(login.pristine).toBe(true); }); + login.valueChanges.subscribe(() => { + expect(login.pristine).toBe(true); + }); form.reset(); }); - }); describe('setting status classes', () => { @@ -736,7 +722,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; it('should work with single fields and async validators', fakeAsync(() => { const fixture = initTest(FormControlComp); - const control = new FormControl('', null !, uniqLoginAsyncValidator('good')); + const control = new FormControl('', null!, uniqLoginAsyncValidator('good')); fixture.debugElement.componentInstance.control = control; fixture.detectChanges(); @@ -831,13 +817,10 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(sortedClassList(formEl)).toEqual(['ng-dirty', 'ng-touched', 'ng-valid']); }); - }); describe('updateOn options', () => { - describe('on blur', () => { - it('should not update value or validity based on user input until blur', () => { const fixture = initTest(FormControlComp); const control = new FormControl('', {validators: Validators.required, updateOn: 'blur'}); @@ -1141,7 +1124,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(control.value) .toEqual('Nancy', 'Expected value to change once control is blurred.'); expect(control.valid).toBe(true, 'Expected validation to run once control is blurred.'); - }); it('should update on blur with array updateOn', () => { @@ -1167,7 +1149,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(control.value) .toEqual('Nancy', 'Expected value to change once control is blurred.'); expect(control.valid).toBe(true, 'Expected validation to run once control is blurred.'); - }); @@ -1206,17 +1187,13 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(passwordControl.valid) .toBe(true, 'Expected validation to run once control is blurred.'); }); - - }); describe('on submit', () => { - it('should set initial value and validity on init', () => { const fixture = initTest(FormGroupComp); const form = new FormGroup({ - login: - new FormControl('Nancy', {validators: Validators.required, updateOn: 'submit'}) + login: new FormControl('Nancy', {validators: Validators.required, updateOn: 'submit'}) }); fixture.componentInstance.form = form; fixture.detectChanges(); @@ -1430,7 +1407,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; fixture.componentInstance.form = formGroup; fixture.detectChanges(); - const values: (string | {[key: string]: string})[] = []; + const values: (string|{[key: string]: string})[] = []; const streams = merge( control.valueChanges, control.statusChanges, formGroup.valueChanges, formGroup.statusChanges); @@ -1493,8 +1470,8 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; fixture.componentInstance.form = formGroup; fixture.detectChanges(); - formGroup.get('signin.login') !.setValidators(validatorSpy); - formGroup.get('signin') !.setValidators(groupValidatorSpy); + formGroup.get('signin.login')!.setValidators(validatorSpy); + formGroup.get('signin')!.setValidators(groupValidatorSpy); const form = fixture.debugElement.query(By.css('form')).nativeElement; dispatchEvent(form, 'submit'); @@ -1502,7 +1479,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(validatorSpy).not.toHaveBeenCalled(); expect(groupValidatorSpy).not.toHaveBeenCalled(); - }); it('should mark as untouched properly if pending touched', () => { @@ -1554,7 +1530,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(control.value).toEqual('Nancy', 'Expected value to change on submit.'); expect(control.valid).toBe(true, 'Expected validation to run on submit.'); - }); it('should update on submit with array updateOn', () => { @@ -1581,7 +1556,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(control.value).toEqual('Nancy', 'Expected value to change once control on submit'); expect(control.valid).toBe(true, 'Expected validation to run on submit.'); - }); it('should allow child control updateOn submit to override group updateOn', () => { @@ -1619,9 +1593,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(passwordControl.value).toEqual('Carson', 'Expected value to change on submit.'); expect(passwordControl.valid).toBe(true, 'Expected validation to run on submit.'); }); - }); - }); describe('ngModel interactions', () => { @@ -1636,7 +1608,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; }); describe('deprecation warnings', () => { - it('should warn once by default when using ngModel with formControlName', fakeAsync(() => { const fixture = initTest(FormGroupNgModel); fixture.componentInstance.form = @@ -1679,8 +1650,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; fakeAsync(() => { TestBed.configureTestingModule({ declarations: [FormControlNgModel], - imports: - [ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'always'})] + imports: [ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'always'})] }); const fixture = TestBed.createComponent(FormControlNgModel); @@ -1710,7 +1680,6 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(warnSpy).not.toHaveBeenCalled(); })); - }); it('should support ngModel for complex forms', fakeAsync(() => { @@ -1794,9 +1763,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(fixture.componentInstance.login) .toEqual('Nancy', 'Expected ngModel value to update on submit.'); - })); - }); describe('validations', () => { @@ -1969,9 +1936,9 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; .toEqual(pattern.nativeElement.getAttribute('pattern')); fixture.componentInstance.required = false; - fixture.componentInstance.minLen = null !; - fixture.componentInstance.maxLen = null !; - fixture.componentInstance.pattern = null !; + fixture.componentInstance.minLen = null!; + fixture.componentInstance.maxLen = null!; + fixture.componentInstance.pattern = null!; fixture.detectChanges(); expect(form.hasError('required', ['login'])).toEqual(false); @@ -2011,9 +1978,9 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; fixture.detectChanges(); fixture.componentInstance.required = false; - fixture.componentInstance.minLen = null !; - fixture.componentInstance.maxLen = null !; - fixture.componentInstance.pattern = null !; + fixture.componentInstance.minLen = null!; + fixture.componentInstance.maxLen = null!; + fixture.componentInstance.pattern = null!; fixture.detectChanges(); expect(newForm.hasError('required', ['login'])).toEqual(false); @@ -2111,7 +2078,7 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; const fixture = initTest(FormControlComp); const resultArr: number[] = []; fixture.componentInstance.control = - new FormControl('', null !, observableValidator(resultArr)); + new FormControl('', null!, observableValidator(resultArr)); fixture.detectChanges(); tick(100); @@ -2130,12 +2097,9 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(resultArr.length) .toEqual(2, `Expected original observable to be canceled on the next value change.`); })); - - }); describe('errors', () => { - it('should throw if a form isn\'t passed into formGroup', () => { const fixture = initTest(FormGroupComp); @@ -2335,11 +2299,9 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; expect(() => fixture.detectChanges()) .toThrowError(new RegExp('If you define both a name and a formControlName')); }); - }); describe('IME events', () => { - it('should determine IME event handling depending on platform by default', () => { const fixture = initTest(FormControlComp); fixture.componentInstance.control = new FormControl('oldValue'); @@ -2417,16 +2379,16 @@ import {MyInput, MyInputForm} from './value_accessor_integration_spec'; // formControl should update normally expect(fixture.componentInstance.control.value).toEqual('updatedValue'); }); - }); - }); } function uniqLoginAsyncValidator(expectedValue: string, timeout: number = 0) { return (c: AbstractControl) => { let resolve: (result: any) => void; - const promise = new Promise<any>(res => { resolve = res; }); + const promise = new Promise<any>(res => { + resolve = res; + }); const res = (c.value == expectedValue) ? null : {'uniqLogin': true}; setTimeout(() => resolve(res), timeout); return promise; @@ -2452,22 +2414,22 @@ class LoginIsEmptyValidator { @Directive({ selector: '[uniq-login-validator]', - providers: [{ - provide: NG_ASYNC_VALIDATORS, - useExisting: forwardRef(() => UniqLoginValidator), - multi: true - }] + providers: [ + {provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => UniqLoginValidator), multi: true} + ] }) class UniqLoginValidator implements AsyncValidator { @Input('uniq-login-validator') expected: any; - validate(c: AbstractControl) { return uniqLoginAsyncValidator(this.expected)(c); } + validate(c: AbstractControl) { + return uniqLoginAsyncValidator(this.expected)(c); + } } @Component({selector: 'form-control-comp', template: `<input type="text" [formControl]="control">`}) class FormControlComp { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; } @Component({ @@ -2479,11 +2441,11 @@ class FormControlComp { }) class FormGroupComp { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; // TODO(issue/24571): remove '!'. - event !: Event; + event!: Event; } @Component({ @@ -2499,7 +2461,7 @@ class FormGroupComp { }) class NestedFormGroupComp { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; } @Component({ @@ -2515,9 +2477,9 @@ class NestedFormGroupComp { }) class FormArrayComp { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; // TODO(issue/24571): remove '!'. - cityArray !: FormArray; + cityArray!: FormArray; } @Component({ @@ -2534,9 +2496,9 @@ class FormArrayComp { }) class FormArrayNestedGroup { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; // TODO(issue/24571): remove '!'. - cityArray !: FormArray; + cityArray!: FormArray; } @Component({ @@ -2549,11 +2511,11 @@ class FormArrayNestedGroup { }) class FormGroupNgModel { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; // TODO(issue/24571): remove '!'. - login !: string; + login!: string; // TODO(issue/24571): remove '!'. - password !: string; + password!: string; } @Component({ @@ -2565,13 +2527,13 @@ class FormGroupNgModel { }) class FormControlNgModel { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; // TODO(issue/24571): remove '!'. - login !: string; + login!: string; // TODO(issue/24571): remove '!'. - passwordControl !: FormControl; + passwordControl!: FormControl; // TODO(issue/24571): remove '!'. - password !: string; + password!: string; } @Component({ @@ -2586,7 +2548,7 @@ class FormControlNgModel { }) class LoginIsEmptyWrapper { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; } @Component({ @@ -2601,15 +2563,15 @@ class LoginIsEmptyWrapper { }) class ValidationBindingsForm { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; // TODO(issue/24571): remove '!'. - required !: boolean; + required!: boolean; // TODO(issue/24571): remove '!'. - minLen !: number; + minLen!: number; // TODO(issue/24571): remove '!'. - maxLen !: number; + maxLen!: number; // TODO(issue/24571): remove '!'. - pattern !: string; + pattern!: string; } @Component({ @@ -2618,7 +2580,7 @@ class ValidationBindingsForm { }) class FormControlCheckboxRequiredValidator { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; } @Component({ @@ -2630,5 +2592,5 @@ class FormControlCheckboxRequiredValidator { }) class UniqLoginWrapper { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; } diff --git a/packages/forms/test/spies.ts b/packages/forms/test/spies.ts index 1f6b3940c7558..27bbcd0d98944 100644 --- a/packages/forms/test/spies.ts +++ b/packages/forms/test/spies.ts @@ -16,6 +16,10 @@ export class SpyChangeDetectorRef extends SpyObject { } } -export class SpyNgControl extends SpyObject { path = []; } +export class SpyNgControl extends SpyObject { + path = []; +} -export class SpyValueAccessor extends SpyObject { writeValue: any; } +export class SpyValueAccessor extends SpyObject { + writeValue: any; +} diff --git a/packages/forms/test/template_integration_spec.ts b/packages/forms/test/template_integration_spec.ts index a78ad61c26cf0..0cde9665d1c3d 100644 --- a/packages/forms/test/template_integration_spec.ts +++ b/packages/forms/test/template_integration_spec.ts @@ -7,8 +7,8 @@ */ import {ɵgetDOM as getDOM} from '@angular/common'; -import {Component, Directive, Type, forwardRef} from '@angular/core'; -import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing'; +import {Component, Directive, forwardRef, Type} from '@angular/core'; +import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {AbstractControl, AsyncValidator, COMPOSITION_BUFFER_MODE, FormControl, FormsModule, NG_ASYNC_VALIDATORS, NgForm, NgModel} from '@angular/forms'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {dispatchEvent, sortedClassList} from '@angular/platform-browser/testing/src/browser_util'; @@ -18,7 +18,6 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat { describe('template-driven forms integration tests', () => { - function initTest<T>(component: Type<T>, ...directives: Type<any>[]): ComponentFixture<T> { TestBed.configureTestingModule( {declarations: [component, ...directives], imports: [FormsModule]}); @@ -57,7 +56,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(form.valid).toBe(false); })); - it('should report properties which are written outside of template bindings', async() => { + it('should report properties which are written outside of template bindings', async () => { // For example ngModel writes to `checked` property programmatically // (template does not contain binding to `checked` explicitly) // https://github.com/angular/angular/issues/33695 @@ -131,9 +130,9 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - expect(form.control.get('name') !.value).toEqual({first: 'Nancy', last: 'Drew'}); - expect(form.control.get('name.first') !.value).toEqual('Nancy'); - expect(form.control.get('email') !.value).toEqual('some email'); + expect(form.control.get('name')!.value).toEqual({first: 'Nancy', last: 'Drew'}); + expect(form.control.get('name.first')!.value).toEqual('Nancy'); + expect(form.control.get('email')!.value).toEqual('some email'); })); it('should remove controls and control groups from form control model', fakeAsync(() => { @@ -145,7 +144,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - expect(form.control.get('email') !.value).toEqual('some email'); + expect(form.control.get('email')!.value).toEqual('some email'); expect(form.value).toEqual({name: {first: 'Nancy'}, email: 'some email'}); // should remove individual control successfully @@ -156,8 +155,8 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(form.control.get('email')).toBe(null); expect(form.value).toEqual({name: {first: 'Nancy'}}); - expect(form.control.get('name') !.value).toEqual({first: 'Nancy'}); - expect(form.control.get('name.first') !.value).toEqual('Nancy'); + expect(form.control.get('name')!.value).toEqual({first: 'Nancy'}); + expect(form.control.get('name.first')!.value).toEqual('Nancy'); // should remove form group successfully fixture.componentInstance.groupShowing = false; @@ -192,7 +191,6 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat })); it('should set status classes with ngModel and async validators', fakeAsync(() => { - const fixture = initTest(NgModelAsyncValidation, NgAsyncValidator); fixture.whenStable().then(() => { fixture.detectChanges(); @@ -252,7 +250,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat it('should not create a template-driven form when ngNoForm is used', () => { const fixture = initTest(NgNoFormComp); fixture.detectChanges(); - expect(fixture.debugElement.children[0].providerTokens !.length).toEqual(0); + expect(fixture.debugElement.children[0].providerTokens!.length).toEqual(0); }); it('should not add novalidate when ngNoForm is used', () => { @@ -304,9 +302,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat }); describe('updateOn', () => { - describe('blur', () => { - it('should default updateOn to change', fakeAsync(() => { const fixture = initTest(NgModelForm); fixture.componentInstance.name = ''; @@ -484,8 +480,8 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat const values: any[] = []; const form = fixture.debugElement.children[0].injector.get(NgForm); - const sub = merge(form.valueChanges !, form.statusChanges !) - .subscribe(val => values.push(val)); + const sub = + merge(form.valueChanges!, form.statusChanges!).subscribe(val => values.push(val)); const input = fixture.debugElement.query(By.css('input')).nativeElement; input.value = 'Nancy Drew'; @@ -560,13 +556,10 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat .toEqual( ['fired', 'fired'], 'Expected ngModelChanges to fire again on blur if value changed.'); - })); - }); describe('submit', () => { - it('should set control updateOn to submit properly', fakeAsync(() => { const fixture = initTest(NgModelForm); fixture.componentInstance.name = ''; @@ -700,8 +693,8 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - form.control.get('name') !.setValidators(groupValidatorSpy); - form.control.get('name.last') !.setValidators(validatorSpy); + form.control.get('name')!.setValidators(groupValidatorSpy); + form.control.get('name.last')!.setValidators(validatorSpy); const formEl = fixture.debugElement.query(By.css('form')).nativeElement; dispatchEvent(formEl, 'submit'); @@ -816,8 +809,8 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat const values: any[] = []; const form = fixture.debugElement.children[0].injector.get(NgForm); - const sub = merge(form.valueChanges !, form.statusChanges !) - .subscribe(val => values.push(val)); + const sub = + merge(form.valueChanges!, form.statusChanges!).subscribe(val => values.push(val)); const input = fixture.debugElement.query(By.css('input')).nativeElement; input.value = 'Nancy Drew'; @@ -898,11 +891,9 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat ['fired', 'fired'], 'Expected ngModelChanges to fire again on submit if value changed.'); })); - }); describe('ngFormOptions', () => { - it('should use ngFormOptions value when ngModelOptions are not set', fakeAsync(() => { const fixture = initTest(NgModelOptionsStandalone); fixture.componentInstance.options = {name: 'two'}; @@ -911,12 +902,12 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - const controlOne = form.control.get('one') !as FormControl; + const controlOne = form.control.get('one')! as FormControl; expect((controlOne as any)._updateOn).toBeUndefined(); expect(controlOne.updateOn) .toEqual('blur', 'Expected first control to inherit updateOn from parent form.'); - const controlTwo = form.control.get('two') !as FormControl; + const controlTwo = form.control.get('two')! as FormControl; expect((controlTwo as any)._updateOn).toBeUndefined(); expect(controlTwo.updateOn) .toEqual('blur', 'Expected last control to inherit updateOn from parent form.'); @@ -952,12 +943,12 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - const controlOne = form.control.get('one') !as FormControl; + const controlOne = form.control.get('one')! as FormControl; expect((controlOne as any)._updateOn).toBeUndefined(); expect(controlOne.updateOn) .toEqual('change', 'Expected control updateOn to inherit form updateOn.'); - const controlTwo = form.control.get('two') !as FormControl; + const controlTwo = form.control.get('two')! as FormControl; expect((controlTwo as any)._updateOn) .toEqual('blur', 'Expected control to set blur override.'); expect(controlTwo.updateOn) @@ -1016,15 +1007,13 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(fixture.componentInstance.two) .toEqual('Nancy Drew', 'Expected standalone ngModel not to inherit blur update.'); })); - }); - }); describe('submit and reset events', () => { it('should emit ngSubmit event with the original submit event on submit', fakeAsync(() => { const fixture = initTest(NgModelForm); - fixture.componentInstance.event = null !; + fixture.componentInstance.event = null!; const form = fixture.debugElement.query(By.css('form')); dispatchEvent(form.nativeElement, 'submit'); @@ -1097,11 +1086,11 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(form.valid).toEqual(true); expect(form.value).toEqual({}); - let formValidity: string = undefined !; - let formValue: Object = undefined !; + let formValidity: string = undefined!; + let formValue: Object = undefined!; - form.statusChanges !.subscribe((status: string) => formValidity = status); - form.valueChanges !.subscribe((value: string) => formValue = value); + form.statusChanges!.subscribe((status: string) => formValidity = status); + form.valueChanges!.subscribe((value: string) => formValue = value); tick(); @@ -1116,8 +1105,9 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat fixture.detectChanges(); tick(); - form.get('name') !.valueChanges.subscribe( - () => { expect(form.get('name') !.dirty).toBe(true); }); + form.get('name')!.valueChanges.subscribe(() => { + expect(form.get('name')!.dirty).toBe(true); + }); const inputEl = fixture.debugElement.query(By.css('input')).nativeElement; inputEl.value = 'newValue'; @@ -1138,10 +1128,11 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat inputEl.value = 'newValue'; dispatchEvent(inputEl, 'input'); - expect(form.get('name') !.pristine).toBe(false); + expect(form.get('name')!.pristine).toBe(false); - form.get('name') !.valueChanges.subscribe( - () => { expect(form.get('name') !.pristine).toBe(true); }); + form.get('name')!.valueChanges.subscribe(() => { + expect(form.get('name')!.pristine).toBe(true); + }); dispatchEvent(formEl, 'reset'); })); @@ -1160,7 +1151,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat const form = fixture.debugElement.children[0].injector.get(NgForm); expect(form.value).toEqual({name: {first: '', last: 'Drew'}, email: 'some email'}); expect(form.valid).toBe(false); - expect(form.control.get('name.first') !.disabled).toBe(false); + expect(form.control.get('name.first')!.disabled).toBe(false); fixture.componentInstance.isDisabled = true; fixture.detectChanges(); @@ -1168,7 +1159,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(form.value).toEqual({name: {last: 'Drew'}, email: 'some email'}); expect(form.valid).toBe(true); - expect(form.control.get('name.first') !.disabled).toBe(true); + expect(form.control.get('name.first')!.disabled).toBe(true); })); it('should add disabled attribute in the UI if disable() is called programmatically', @@ -1180,7 +1171,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - form.control.get('name.first') !.disable(); + form.control.get('name.first')!.disable(); fixture.detectChanges(); tick(); @@ -1197,7 +1188,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat fixture.detectChanges(); fixture.whenStable().then(() => { const form = fixture.debugElement.children[0].injector.get(NgForm); - expect(form.control.get('name') !.disabled).toBe(true); + expect(form.control.get('name')!.disabled).toBe(true); const customInput = fixture.debugElement.query(By.css('[name="custom"]')); expect(customInput.nativeElement.disabled).toEqual(true); @@ -1219,7 +1210,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat fixture.detectChanges(); tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - expect(form.control.get('name') !.disabled).toBe(true); + expect(form.control.get('name')!.disabled).toBe(true); const input = fixture.debugElement.query(By.css('input')); expect(input.nativeElement.disabled).toEqual(true); @@ -1229,18 +1220,16 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); expect(input.nativeElement.disabled).toEqual(false); })); - }); describe('validation directives', () => { - it('required validator should validate checkbox', fakeAsync(() => { const fixture = initTest(NgModelCheckboxRequiredValidator); fixture.detectChanges(); tick(); const control = - fixture.debugElement.children[0].injector.get(NgForm).control.get('checkbox') !; + fixture.debugElement.children[0].injector.get(NgForm).control.get('checkbox')!; const input = fixture.debugElement.query(By.css('input')); expect(input.nativeElement.checked).toBe(false); @@ -1276,7 +1265,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat tick(); const control = - fixture.debugElement.children[0].injector.get(NgForm).control.get('email') !; + fixture.debugElement.children[0].injector.get(NgForm).control.get('email')!; const input = fixture.debugElement.query(By.css('input')); expect(control.hasError('email')).toBe(false); @@ -1476,9 +1465,9 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat .toEqual(pattern.nativeElement.getAttribute('pattern')); fixture.componentInstance.required = false; - fixture.componentInstance.minLen = null !; - fixture.componentInstance.maxLen = null !; - fixture.componentInstance.pattern = null !; + fixture.componentInstance.minLen = null!; + fixture.componentInstance.maxLen = null!; + fixture.componentInstance.pattern = null!; fixture.detectChanges(); expect(form.control.hasError('required', ['required'])).toEqual(false); @@ -1522,7 +1511,6 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(onNgModelChange).toHaveBeenCalledTimes(2); tick(); })); - }); describe('IME events', () => { @@ -1611,7 +1599,6 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat // ngModel should update normally expect(fixture.componentInstance.name).toEqual('updatedValue'); })); - }); describe('ngModel corner cases', () => { @@ -1650,7 +1637,6 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat expect(() => fixture.detectChanges()).not.toThrowError(); })); }); - }); } @@ -1662,7 +1648,7 @@ import {NgModelCustomComp, NgModelCustomWrapper} from './value_accessor_integrat }) class StandaloneNgModel { // TODO(issue/24571): remove '!'. - name !: string; + name!: string; } @Component({ @@ -1675,9 +1661,9 @@ class StandaloneNgModel { }) class NgModelForm { // TODO(issue/24571): remove '!'. - name !: string | null; + name!: string|null; // TODO(issue/24571): remove '!'. - event !: Event; + event!: Event; options = {}; onReset() {} @@ -1701,13 +1687,13 @@ class NgModelNativeValidateForm { }) class NgModelGroupForm { // TODO(issue/24571): remove '!'. - first !: string; + first!: string; // TODO(issue/24571): remove '!'. - last !: string; + last!: string; // TODO(issue/24571): remove '!'. - email !: string; + email!: string; // TODO(issue/24571): remove '!'. - isDisabled !: boolean; + isDisabled!: boolean; options = {updateOn: 'change'}; } @@ -1724,7 +1710,7 @@ class NgModelGroupForm { }) class NgModelValidBinding { // TODO(issue/24571): remove '!'. - first !: string; + first!: string; } @@ -1741,11 +1727,11 @@ class NgModelValidBinding { }) class NgModelNgIfForm { // TODO(issue/24571): remove '!'. - first !: string; + first!: string; groupShowing = true; emailShowing = true; // TODO(issue/24571): remove '!'. - email !: string; + email!: string; } @Component({ @@ -1781,9 +1767,9 @@ class InvalidNgModelNoName { }) class NgModelOptionsStandalone { // TODO(issue/24571): remove '!'. - one !: string; + one!: string; // TODO(issue/24571): remove '!'. - two !: string; + two!: string; options: {name?: string, standalone?: boolean, updateOn?: string} = {standalone: true}; formOptions = {}; } @@ -1801,13 +1787,13 @@ class NgModelOptionsStandalone { }) class NgModelValidationBindings { // TODO(issue/24571): remove '!'. - required !: boolean; + required!: boolean; // TODO(issue/24571): remove '!'. - minLen !: number; + minLen!: number; // TODO(issue/24571): remove '!'. - maxLen !: number; + maxLen!: number; // TODO(issue/24571): remove '!'. - pattern !: string; + pattern!: string; } @Component({ @@ -1820,11 +1806,11 @@ class NgModelValidationBindings { }) class NgModelMultipleValidators { // TODO(issue/24571): remove '!'. - required !: boolean; + required!: boolean; // TODO(issue/24571): remove '!'. - minLen !: number; + minLen!: number; // TODO(issue/24571): remove '!'. - pattern !: string | RegExp; + pattern!: string|RegExp; } @Component({ @@ -1847,12 +1833,13 @@ class NgModelEmailValidator { @Directive({ selector: '[ng-async-validator]', - providers: [ - {provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => NgAsyncValidator), multi: true} - ] + providers: + [{provide: NG_ASYNC_VALIDATORS, useExisting: forwardRef(() => NgAsyncValidator), multi: true}] }) class NgAsyncValidator implements AsyncValidator { - validate(c: AbstractControl) { return Promise.resolve(null); } + validate(c: AbstractControl) { + return Promise.resolve(null); + } } @Component({ @@ -1873,11 +1860,13 @@ class NgModelAsyncValidation { }) class NgModelChangesForm { // TODO(issue/24571): remove '!'. - name !: string; + name!: string; events: string[] = []; options: any; - log() { this.events.push('fired'); } + log() { + this.events.push('fired'); + } } @Component({ diff --git a/packages/forms/test/validators_spec.ts b/packages/forms/test/validators_spec.ts index 0d3f1189655ae..0a6719421b8d1 100644 --- a/packages/forms/test/validators_spec.ts +++ b/packages/forms/test/validators_spec.ts @@ -11,453 +11,487 @@ import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; import {AbstractControl, AsyncValidatorFn, FormArray, FormControl, Validators} from '@angular/forms'; import {normalizeAsyncValidator} from '@angular/forms/src/directives/normalize_validator'; import {AsyncValidator, ValidationErrors, ValidatorFn} from '@angular/forms/src/directives/validators'; -import {Observable, of , timer} from 'rxjs'; +import {Observable, of, timer} from 'rxjs'; import {first, map} from 'rxjs/operators'; (function() { - function validator(key: string, error: any): ValidatorFn { - return (c: AbstractControl) => { - const r: ValidationErrors = {}; - r[key] = error; - return r; - }; +function validator(key: string, error: any): ValidatorFn { + return (c: AbstractControl) => { + const r: ValidationErrors = {}; + r[key] = error; + return r; + }; +} + +class AsyncValidatorDirective implements AsyncValidator { + constructor(private expected: string, private error: any) {} + + validate(c: any): Observable<ValidationErrors> { + return Observable.create((obs: any) => { + const error = this.expected !== c.value ? this.error : null; + obs.next(error); + obs.complete(); + }); } +} - class AsyncValidatorDirective implements AsyncValidator { - constructor(private expected: string, private error: any) {} +describe('Validators', () => { + describe('min', () => { + it('should not error on an empty string', () => { + expect(Validators.min(2)(new FormControl(''))).toBeNull(); + }); - validate(c: any): Observable<ValidationErrors> { - return Observable.create((obs: any) => { - const error = this.expected !== c.value ? this.error : null; - obs.next(error); - obs.complete(); - }); - } - } + it('should not error on null', () => { + expect(Validators.min(2)(new FormControl(null))).toBeNull(); + }); - describe('Validators', () => { - describe('min', () => { - it('should not error on an empty string', - () => { expect(Validators.min(2)(new FormControl(''))).toBeNull(); }); + it('should not error on undefined', () => { + expect(Validators.min(2)(new FormControl(undefined))).toBeNull(); + }); - it('should not error on null', - () => { expect(Validators.min(2)(new FormControl(null))).toBeNull(); }); + it('should return null if NaN after parsing', () => { + expect(Validators.min(2)(new FormControl('a'))).toBeNull(); + }); - it('should not error on undefined', - () => { expect(Validators.min(2)(new FormControl(undefined))).toBeNull(); }); + it('should return a validation error on small values', () => { + expect(Validators.min(2)(new FormControl(1))).toEqual({'min': {'min': 2, 'actual': 1}}); + }); - it('should return null if NaN after parsing', - () => { expect(Validators.min(2)(new FormControl('a'))).toBeNull(); }); + it('should return a validation error on small values converted from strings', () => { + expect(Validators.min(2)(new FormControl('1'))).toEqual({'min': {'min': 2, 'actual': '1'}}); + }); - it('should return a validation error on small values', () => { - expect(Validators.min(2)(new FormControl(1))).toEqual({'min': {'min': 2, 'actual': 1}}); - }); + it('should not error on big values', () => { + expect(Validators.min(2)(new FormControl(3))).toBeNull(); + }); + + it('should not error on equal values', () => { + expect(Validators.min(2)(new FormControl(2))).toBeNull(); + }); - it('should return a validation error on small values converted from strings', () => { - expect(Validators.min(2)(new FormControl('1'))).toEqual({'min': {'min': 2, 'actual': '1'}}); + it('should not error on equal values when value is string', () => { + expect(Validators.min(2)(new FormControl('2'))).toBeNull(); + }); + + it('should validate as expected when min value is a string', () => { + expect(Validators.min('2' as any)(new FormControl(1))).toEqual({ + 'min': {'min': '2', 'actual': 1} }); + }); - it('should not error on big values', - () => { expect(Validators.min(2)(new FormControl(3))).toBeNull(); }); + it('should return null if min value is undefined', () => { + expect(Validators.min(undefined as any)(new FormControl(3))).toBeNull(); + }); + + it('should return null if min value is null', () => { + expect(Validators.min(null as any)(new FormControl(3))).toBeNull(); + }); + }); - it('should not error on equal values', - () => { expect(Validators.min(2)(new FormControl(2))).toBeNull(); }); + describe('max', () => { + it('should not error on an empty string', () => { + expect(Validators.max(2)(new FormControl(''))).toBeNull(); + }); - it('should not error on equal values when value is string', - () => { expect(Validators.min(2)(new FormControl('2'))).toBeNull(); }); + it('should not error on null', () => { + expect(Validators.max(2)(new FormControl(null))).toBeNull(); + }); - it('should validate as expected when min value is a string', () => { - expect(Validators.min('2' as any)(new FormControl(1))).toEqual({ - 'min': {'min': '2', 'actual': 1} - }); - }); + it('should not error on undefined', () => { + expect(Validators.max(2)(new FormControl(undefined))).toBeNull(); + }); - it('should return null if min value is undefined', - () => { expect(Validators.min(undefined as any)(new FormControl(3))).toBeNull(); }); + it('should return null if NaN after parsing', () => { + expect(Validators.max(2)(new FormControl('aaa'))).toBeNull(); + }); - it('should return null if min value is null', - () => { expect(Validators.min(null as any)(new FormControl(3))).toBeNull(); }); + it('should return a validation error on big values', () => { + expect(Validators.max(2)(new FormControl(3))).toEqual({'max': {'max': 2, 'actual': 3}}); }); - describe('max', () => { - it('should not error on an empty string', - () => { expect(Validators.max(2)(new FormControl(''))).toBeNull(); }); + it('should return a validation error on big values converted from strings', () => { + expect(Validators.max(2)(new FormControl('3'))).toEqual({'max': {'max': 2, 'actual': '3'}}); + }); - it('should not error on null', - () => { expect(Validators.max(2)(new FormControl(null))).toBeNull(); }); + it('should not error on small values', () => { + expect(Validators.max(2)(new FormControl(1))).toBeNull(); + }); - it('should not error on undefined', - () => { expect(Validators.max(2)(new FormControl(undefined))).toBeNull(); }); + it('should not error on equal values', () => { + expect(Validators.max(2)(new FormControl(2))).toBeNull(); + }); - it('should return null if NaN after parsing', - () => { expect(Validators.max(2)(new FormControl('aaa'))).toBeNull(); }); + it('should not error on equal values when value is string', () => { + expect(Validators.max(2)(new FormControl('2'))).toBeNull(); + }); - it('should return a validation error on big values', () => { - expect(Validators.max(2)(new FormControl(3))).toEqual({'max': {'max': 2, 'actual': 3}}); + it('should validate as expected when max value is a string', () => { + expect(Validators.max('2' as any)(new FormControl(3))).toEqual({ + 'max': {'max': '2', 'actual': 3} }); + }); - it('should return a validation error on big values converted from strings', () => { - expect(Validators.max(2)(new FormControl('3'))).toEqual({'max': {'max': 2, 'actual': '3'}}); - }); + it('should return null if max value is undefined', () => { + expect(Validators.max(undefined as any)(new FormControl(3))).toBeNull(); + }); - it('should not error on small values', - () => { expect(Validators.max(2)(new FormControl(1))).toBeNull(); }); + it('should return null if max value is null', () => { + expect(Validators.max(null as any)(new FormControl(3))).toBeNull(); + }); + }); - it('should not error on equal values', - () => { expect(Validators.max(2)(new FormControl(2))).toBeNull(); }); - it('should not error on equal values when value is string', - () => { expect(Validators.max(2)(new FormControl('2'))).toBeNull(); }); + describe('required', () => { + it('should error on an empty string', () => { + expect(Validators.required(new FormControl(''))).toEqual({'required': true}); + }); - it('should validate as expected when max value is a string', () => { - expect(Validators.max('2' as any)(new FormControl(3))).toEqual({ - 'max': {'max': '2', 'actual': 3} - }); - }); + it('should error on null', () => { + expect(Validators.required(new FormControl(null))).toEqual({'required': true}); + }); - it('should return null if max value is undefined', - () => { expect(Validators.max(undefined as any)(new FormControl(3))).toBeNull(); }); + it('should not error on undefined', () => { + expect(Validators.required(new FormControl(undefined))).toEqual({'required': true}); + }); - it('should return null if max value is null', - () => { expect(Validators.max(null as any)(new FormControl(3))).toBeNull(); }); + it('should not error on a non-empty string', () => { + expect(Validators.required(new FormControl('not empty'))).toBeNull(); }); + it('should accept zero as valid', () => { + expect(Validators.required(new FormControl(0))).toBeNull(); + }); - describe('required', () => { - it('should error on an empty string', - () => { expect(Validators.required(new FormControl(''))).toEqual({'required': true}); }); + it('should error on an empty array', + () => expect(Validators.required(new FormControl([]))).toEqual({'required': true})); - it('should error on null', - () => { expect(Validators.required(new FormControl(null))).toEqual({'required': true}); }); + it('should not error on a non-empty array', + () => expect(Validators.required(new FormControl([1, 2]))).toBeNull()); + }); - it('should not error on undefined', () => { - expect(Validators.required(new FormControl(undefined))).toEqual({'required': true}); - }); + describe('requiredTrue', () => { + it('should error on false', + () => expect(Validators.requiredTrue(new FormControl(false))).toEqual({'required': true})); + + it('should not error on true', + () => expect(Validators.requiredTrue(new FormControl(true))).toBeNull()); + }); + + describe('email', () => { + it('should not error on an empty string', + () => expect(Validators.email(new FormControl(''))).toBeNull()); - it('should not error on a non-empty string', - () => { expect(Validators.required(new FormControl('not empty'))).toBeNull(); }); + it('should not error on null', + () => expect(Validators.email(new FormControl(null))).toBeNull()); - it('should accept zero as valid', - () => { expect(Validators.required(new FormControl(0))).toBeNull(); }); + it('should error on invalid email', + () => expect(Validators.email(new FormControl('some text'))).toEqual({'email': true})); - it('should error on an empty array', - () => expect(Validators.required(new FormControl([]))).toEqual({'required': true})); + it('should not error on valid email', + () => expect(Validators.email(new FormControl('test@gmail.com'))).toBeNull()); + }); - it('should not error on a non-empty array', - () => expect(Validators.required(new FormControl([1, 2]))).toBeNull()); + describe('minLength', () => { + it('should not error on an empty string', () => { + expect(Validators.minLength(2)(new FormControl(''))).toBeNull(); }); - describe('requiredTrue', () => { - it('should error on false', - () => expect(Validators.requiredTrue(new FormControl(false))).toEqual({'required': true})); + it('should not error on null', () => { + expect(Validators.minLength(2)(new FormControl(null))).toBeNull(); + }); - it('should not error on true', - () => expect(Validators.requiredTrue(new FormControl(true))).toBeNull()); + it('should not error on undefined', () => { + expect(Validators.minLength(2)(new FormControl(undefined))).toBeNull(); }); - describe('email', () => { - it('should not error on an empty string', - () => expect(Validators.email(new FormControl(''))).toBeNull()); + it('should not error on valid strings', () => { + expect(Validators.minLength(2)(new FormControl('aa'))).toBeNull(); + }); - it('should not error on null', - () => expect(Validators.email(new FormControl(null))).toBeNull()); + it('should error on short strings', () => { + expect(Validators.minLength(2)(new FormControl('a'))).toEqual({ + 'minlength': {'requiredLength': 2, 'actualLength': 1} + }); + }); - it('should error on invalid email', - () => expect(Validators.email(new FormControl('some text'))).toEqual({'email': true})); + it('should not error when FormArray has valid length', () => { + const fa = new FormArray([new FormControl(''), new FormControl('')]); + expect(Validators.minLength(2)(fa)).toBeNull(); + }); - it('should not error on valid email', - () => expect(Validators.email(new FormControl('test@gmail.com'))).toBeNull()); + it('should error when FormArray has invalid length', () => { + const fa = new FormArray([new FormControl('')]); + expect(Validators.minLength(2)(fa)).toEqual({ + 'minlength': {'requiredLength': 2, 'actualLength': 1} + }); }); + }); - describe('minLength', () => { - it('should not error on an empty string', - () => { expect(Validators.minLength(2)(new FormControl(''))).toBeNull(); }); + describe('maxLength', () => { + it('should not error on an empty string', () => { + expect(Validators.maxLength(2)(new FormControl(''))).toBeNull(); + }); - it('should not error on null', - () => { expect(Validators.minLength(2)(new FormControl(null))).toBeNull(); }); + it('should not error on null', () => { + expect(Validators.maxLength(2)(new FormControl(null))).toBeNull(); + }); - it('should not error on undefined', - () => { expect(Validators.minLength(2)(new FormControl(undefined))).toBeNull(); }); + it('should not error on undefined', () => { + expect(Validators.maxLength(2)(new FormControl(undefined))).toBeNull(); + }); - it('should not error on valid strings', - () => { expect(Validators.minLength(2)(new FormControl('aa'))).toBeNull(); }); + it('should not error on valid strings', () => { + expect(Validators.maxLength(2)(new FormControl('aa'))).toBeNull(); + }); - it('should error on short strings', () => { - expect(Validators.minLength(2)(new FormControl('a'))).toEqual({ - 'minlength': {'requiredLength': 2, 'actualLength': 1} - }); + it('should error on long strings', () => { + expect(Validators.maxLength(2)(new FormControl('aaa'))).toEqual({ + 'maxlength': {'requiredLength': 2, 'actualLength': 3} }); + }); - it('should not error when FormArray has valid length', () => { - const fa = new FormArray([new FormControl(''), new FormControl('')]); - expect(Validators.minLength(2)(fa)).toBeNull(); - }); + it('should not error when FormArray has valid length', () => { + const fa = new FormArray([new FormControl(''), new FormControl('')]); + expect(Validators.maxLength(2)(fa)).toBeNull(); + }); - it('should error when FormArray has invalid length', () => { - const fa = new FormArray([new FormControl('')]); - expect(Validators.minLength(2)(fa)).toEqual({ - 'minlength': {'requiredLength': 2, 'actualLength': 1} - }); + it('should error when FormArray has invalid length', () => { + const fa = new FormArray([new FormControl(''), new FormControl('')]); + expect(Validators.maxLength(1)(fa)).toEqual({ + 'maxlength': {'requiredLength': 1, 'actualLength': 2} }); }); + }); - describe('maxLength', () => { - it('should not error on an empty string', - () => { expect(Validators.maxLength(2)(new FormControl(''))).toBeNull(); }); + describe('pattern', () => { + it('should not error on an empty string', () => { + expect(Validators.pattern('[a-zA-Z ]+')(new FormControl(''))).toBeNull(); + }); - it('should not error on null', - () => { expect(Validators.maxLength(2)(new FormControl(null))).toBeNull(); }); + it('should not error on null', () => { + expect(Validators.pattern('[a-zA-Z ]+')(new FormControl(null))).toBeNull(); + }); - it('should not error on undefined', - () => { expect(Validators.maxLength(2)(new FormControl(undefined))).toBeNull(); }); + it('should not error on undefined', () => { + expect(Validators.pattern('[a-zA-Z ]+')(new FormControl(undefined))).toBeNull(); + }); - it('should not error on valid strings', - () => { expect(Validators.maxLength(2)(new FormControl('aa'))).toBeNull(); }); + it('should not error on null value and "null" pattern', () => { + expect(Validators.pattern('null')(new FormControl(null))).toBeNull(); + }); - it('should error on long strings', () => { - expect(Validators.maxLength(2)(new FormControl('aaa'))).toEqual({ - 'maxlength': {'requiredLength': 2, 'actualLength': 3} - }); - }); + it('should not error on valid strings', + () => expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaAA'))).toBeNull()); - it('should not error when FormArray has valid length', () => { - const fa = new FormArray([new FormControl(''), new FormControl('')]); - expect(Validators.maxLength(2)(fa)).toBeNull(); + it('should error on failure to match string', () => { + expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaa0'))).toEqual({ + 'pattern': {'requiredPattern': '^[a-zA-Z ]*$', 'actualValue': 'aaa0'} }); + }); - it('should error when FormArray has invalid length', () => { - const fa = new FormArray([new FormControl(''), new FormControl('')]); - expect(Validators.maxLength(1)(fa)).toEqual({ - 'maxlength': {'requiredLength': 1, 'actualLength': 2} - }); + it('should accept RegExp object', () => { + const pattern: RegExp = new RegExp('[a-zA-Z ]+'); + expect(Validators.pattern(pattern)(new FormControl('aaAA'))).toBeNull(); + }); + + it('should error on failure to match RegExp object', () => { + const pattern: RegExp = new RegExp('^[a-zA-Z ]*$'); + expect(Validators.pattern(pattern)(new FormControl('aaa0'))).toEqual({ + 'pattern': {'requiredPattern': '/^[a-zA-Z ]*$/', 'actualValue': 'aaa0'} }); }); - describe('pattern', () => { - it('should not error on an empty string', - () => { expect(Validators.pattern('[a-zA-Z ]+')(new FormControl(''))).toBeNull(); }); + it('should not error on "null" pattern', + () => expect(Validators.pattern(null!)(new FormControl('aaAA'))).toBeNull()); - it('should not error on null', - () => { expect(Validators.pattern('[a-zA-Z ]+')(new FormControl(null))).toBeNull(); }); + it('should not error on "undefined" pattern', + () => expect(Validators.pattern(undefined!)(new FormControl('aaAA'))).toBeNull()); - it('should not error on undefined', () => { - expect(Validators.pattern('[a-zA-Z ]+')(new FormControl(undefined))).toBeNull(); - }); + it('should work with pattern string containing both boundary symbols', + () => expect(Validators.pattern('^[aA]*$')(new FormControl('aaAA'))).toBeNull()); - it('should not error on null value and "null" pattern', - () => { expect(Validators.pattern('null')(new FormControl(null))).toBeNull(); }); + it('should work with pattern string containing only start boundary symbols', + () => expect(Validators.pattern('^[aA]*')(new FormControl('aaAA'))).toBeNull()); - it('should not error on valid strings', - () => expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaAA'))).toBeNull()); + it('should work with pattern string containing only end boundary symbols', + () => expect(Validators.pattern('[aA]*$')(new FormControl('aaAA'))).toBeNull()); - it('should error on failure to match string', () => { - expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaa0'))).toEqual({ - 'pattern': {'requiredPattern': '^[a-zA-Z ]*$', 'actualValue': 'aaa0'} - }); - }); + it('should work with pattern string not containing any boundary symbols', + () => expect(Validators.pattern('[aA]*')(new FormControl('aaAA'))).toBeNull()); + }); - it('should accept RegExp object', () => { - const pattern: RegExp = new RegExp('[a-zA-Z ]+'); - expect(Validators.pattern(pattern)(new FormControl('aaAA'))).toBeNull(); - }); + describe('compose', () => { + it('should return null when given null', () => { + expect(Validators.compose(null!)).toBe(null); + }); - it('should error on failure to match RegExp object', () => { - const pattern: RegExp = new RegExp('^[a-zA-Z ]*$'); - expect(Validators.pattern(pattern)(new FormControl('aaa0'))).toEqual({ - 'pattern': {'requiredPattern': '/^[a-zA-Z ]*$/', 'actualValue': 'aaa0'} - }); - }); + it('should collect errors from all the validators', () => { + const c = Validators.compose([validator('a', true), validator('b', true)])!; + expect(c(new FormControl(''))).toEqual({'a': true, 'b': true}); + }); - it('should not error on "null" pattern', - () => expect(Validators.pattern(null !)(new FormControl('aaAA'))).toBeNull()); + it('should run validators left to right', () => { + const c = Validators.compose([validator('a', 1), validator('a', 2)])!; + expect(c(new FormControl(''))).toEqual({'a': 2}); + }); - it('should not error on "undefined" pattern', - () => expect(Validators.pattern(undefined !)(new FormControl('aaAA'))).toBeNull()); + it('should return null when no errors', () => { + const c = Validators.compose([Validators.nullValidator, Validators.nullValidator])!; + expect(c(new FormControl(''))).toBeNull(); + }); - it('should work with pattern string containing both boundary symbols', - () => expect(Validators.pattern('^[aA]*$')(new FormControl('aaAA'))).toBeNull()); + it('should ignore nulls', () => { + const c = Validators.compose([null!, Validators.required])!; + expect(c(new FormControl(''))).toEqual({'required': true}); + }); + }); - it('should work with pattern string containing only start boundary symbols', - () => expect(Validators.pattern('^[aA]*')(new FormControl('aaAA'))).toBeNull()); + describe('composeAsync', () => { + describe('promises', () => { + function promiseValidator(response: {[key: string]: any}): AsyncValidatorFn { + return (c: AbstractControl) => { + const res = c.value != 'expected' ? response : null; + return Promise.resolve(res); + }; + } + + it('should return null when given null', () => { + expect(Validators.composeAsync(null!)).toBeNull(); + }); - it('should work with pattern string containing only end boundary symbols', - () => expect(Validators.pattern('[aA]*$')(new FormControl('aaAA'))).toBeNull()); + it('should collect errors from all the validators', fakeAsync(() => { + const v = Validators.composeAsync( + [promiseValidator({'one': true}), promiseValidator({'two': true})])!; - it('should work with pattern string not containing any boundary symbols', - () => expect(Validators.pattern('[aA]*')(new FormControl('aaAA'))).toBeNull()); - }); + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); + tick(); - describe('compose', () => { - it('should return null when given null', - () => { expect(Validators.compose(null !)).toBe(null); }); + expect(errorMap!).toEqual({'one': true, 'two': true}); + })); - it('should collect errors from all the validators', () => { - const c = Validators.compose([validator('a', true), validator('b', true)]) !; - expect(c(new FormControl(''))).toEqual({'a': true, 'b': true}); - }); + it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => { + const v = Validators.composeAsync( + [normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))])!; - it('should run validators left to right', () => { - const c = Validators.compose([validator('a', 1), validator('a', 2)]) !; - expect(c(new FormControl(''))).toEqual({'a': 2}); - }); + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); + tick(); - it('should return null when no errors', () => { - const c = Validators.compose([Validators.nullValidator, Validators.nullValidator]) !; - expect(c(new FormControl(''))).toBeNull(); - }); + expect(errorMap!).toEqual({'one': true}); + })); - it('should ignore nulls', () => { - const c = Validators.compose([null !, Validators.required]) !; - expect(c(new FormControl(''))).toEqual({'required': true}); - }); - }); + it('should return null when no errors', fakeAsync(() => { + const v = Validators.composeAsync([promiseValidator({'one': true})])!; + + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('expected')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); + tick(); - describe('composeAsync', () => { + expect(errorMap).toBeNull(); + })); - describe('promises', () => { - function promiseValidator(response: {[key: string]: any}): AsyncValidatorFn { - return (c: AbstractControl) => { - const res = c.value != 'expected' ? response : null; - return Promise.resolve(res); - }; - } + it('should ignore nulls', fakeAsync(() => { + const v = Validators.composeAsync([promiseValidator({'one': true}), null!])!; - it('should return null when given null', - () => { expect(Validators.composeAsync(null !)).toBeNull(); }); + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); + tick(); - it('should collect errors from all the validators', fakeAsync(() => { - const v = Validators.composeAsync( - [promiseValidator({'one': true}), promiseValidator({'two': true})]) !; + expect(errorMap!).toEqual({'one': true}); + })); + }); - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - tick(); + describe('observables', () => { + function observableValidator(response: {[key: string]: any}): AsyncValidatorFn { + return (c: AbstractControl) => { + const res = c.value != 'expected' ? response : null; + return of(res); + }; + } - expect(errorMap !).toEqual({'one': true, 'two': true}); - })); + it('should return null when given null', () => { + expect(Validators.composeAsync(null!)).toBeNull(); + }); - it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => { - const v = Validators.composeAsync([normalizeAsyncValidator( - new AsyncValidatorDirective('expected', {'one': true}))]) !; + it('should collect errors from all the validators', () => { + const v = Validators.composeAsync( + [observableValidator({'one': true}), observableValidator({'two': true})])!; - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - tick(); + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); - expect(errorMap !).toEqual({'one': true}); - })); + expect(errorMap!).toEqual({'one': true, 'two': true}); + }); - it('should return null when no errors', fakeAsync(() => { - const v = Validators.composeAsync([promiseValidator({'one': true})]) !; + it('should normalize and evaluate async validator-directives correctly', () => { + const v = Validators.composeAsync( + [normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))])!; - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('expected')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - tick(); + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors)!; - expect(errorMap).toBeNull(); - })); + expect(errorMap!).toEqual({'one': true}); + }); - it('should ignore nulls', fakeAsync(() => { - const v = Validators.composeAsync([promiseValidator({'one': true}), null !]) !; + it('should return null when no errors', () => { + const v = Validators.composeAsync([observableValidator({'one': true})])!; - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - tick(); + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('expected')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); - expect(errorMap !).toEqual({'one': true}); - })); + expect(errorMap).toBeNull(); }); - describe('observables', () => { - function observableValidator(response: {[key: string]: any}): AsyncValidatorFn { - return (c: AbstractControl) => { - const res = c.value != 'expected' ? response : null; - return of (res); - }; - } - - it('should return null when given null', - () => { expect(Validators.composeAsync(null !)).toBeNull(); }); - - it('should collect errors from all the validators', () => { - const v = Validators.composeAsync( - [observableValidator({'one': true}), observableValidator({'two': true})]) !; - - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - - expect(errorMap !).toEqual({'one': true, 'two': true}); - }); - - it('should normalize and evaluate async validator-directives correctly', () => { - const v = Validators.composeAsync( - [normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))]) !; - - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors) !; - - expect(errorMap !).toEqual({'one': true}); - }); - - it('should return null when no errors', () => { - const v = Validators.composeAsync([observableValidator({'one': true})]) !; - - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('expected')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - - expect(errorMap).toBeNull(); - }); - - it('should ignore nulls', () => { - const v = Validators.composeAsync([observableValidator({'one': true}), null !]) !; - - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - - expect(errorMap !).toEqual({'one': true}); - }); - - it('should wait for all validators before setting errors', fakeAsync(() => { - function getTimerObs(time: number, errorMap: {[key: string]: any}): AsyncValidatorFn { - return (c: AbstractControl) => { return timer(time).pipe(map(() => errorMap)); }; - } - - const v = Validators.composeAsync( - [getTimerObs(100, {one: true}), getTimerObs(200, {two: true})]) !; - - let errorMap: {[key: string]: any}|null = undefined !; - (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) - .pipe(first()) - .subscribe((errors: {[key: string]: any} | null) => errorMap = errors); - - tick(100); - expect(errorMap).not.toBeDefined( - `Expected errors not to be set until all validators came back.`); - - tick(100); - expect(errorMap !) - .toEqual( - {one: true, two: true}, - `Expected errors to merge once all validators resolved.`); - })); + it('should ignore nulls', () => { + const v = Validators.composeAsync([observableValidator({'one': true}), null!])!; + + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); + + expect(errorMap!).toEqual({'one': true}); }); + it('should wait for all validators before setting errors', fakeAsync(() => { + function getTimerObs(time: number, errorMap: {[key: string]: any}): AsyncValidatorFn { + return (c: AbstractControl) => { + return timer(time).pipe(map(() => errorMap)); + }; + } + + const v = Validators.composeAsync( + [getTimerObs(100, {one: true}), getTimerObs(200, {two: true})])!; + + let errorMap: {[key: string]: any}|null = undefined!; + (v(new FormControl('invalid')) as Observable<ValidationErrors|null>) + .pipe(first()) + .subscribe((errors: {[key: string]: any}|null) => errorMap = errors); + + tick(100); + expect(errorMap).not.toBeDefined( + `Expected errors not to be set until all validators came back.`); + + tick(100); + expect(errorMap!).toEqual( + {one: true, two: true}, `Expected errors to merge once all validators resolved.`); + })); }); }); +}); })(); diff --git a/packages/forms/test/value_accessor_integration_spec.ts b/packages/forms/test/value_accessor_integration_spec.ts index 7eac63877db49..852e04bde4cb6 100644 --- a/packages/forms/test/value_accessor_integration_spec.ts +++ b/packages/forms/test/value_accessor_integration_spec.ts @@ -7,14 +7,13 @@ */ import {Component, Directive, EventEmitter, Input, Output, Type, ViewChild} from '@angular/core'; -import {ComponentFixture, TestBed, async, fakeAsync, tick} from '@angular/core/testing'; +import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {AbstractControl, ControlValueAccessor, FormControl, FormGroup, FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, NgForm, NgModel, ReactiveFormsModule, Validators} from '@angular/forms'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'; { describe('value accessors', () => { - function initTest<T>(component: Type<T>, ...directives: Type<any>[]): ComponentFixture<T> { TestBed.configureTestingModule( {declarations: [component, ...directives], imports: [FormsModule, ReactiveFormsModule]}); @@ -64,7 +63,11 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.detectChanges(); const input = fixture.debugElement.query(By.css('input')); - form.valueChanges.subscribe({next: (value) => { throw 'Should not happen'; }}); + form.valueChanges.subscribe({ + next: (value) => { + throw 'Should not happen'; + } + }); input.nativeElement.value = 'updatedValue'; dispatchEvent(input.nativeElement, 'change'); @@ -160,9 +163,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' }); describe('select controls', () => { - describe('in reactive forms', () => { - it(`should support primitive values`, () => { if (isNode) return; const fixture = initTest(FormControlNameSelect); @@ -197,7 +198,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' it('should throw an error if compareWith is not a function', () => { const fixture = initTest(FormControlSelectWithCompareFn); - fixture.componentInstance.compareFn = null !; + fixture.componentInstance.compareFn = null!; expect(() => fixture.detectChanges()) .toThrowError(/compareWith must be a function, but received null/); }); @@ -238,7 +239,6 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(select.nativeElement.value).toEqual('3: Object'); expect(nyOption.nativeElement.selected).toBe(true); }); - }); describe('in template-driven forms', () => { @@ -336,7 +336,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' dispatchEvent(select.nativeElement, 'change'); fixture.detectChanges(); tick(); - expect(comp.selectedCity !['name']).toEqual('NYC'); + expect(comp.selectedCity!['name']).toEqual('NYC'); select.nativeElement.value = '0: null'; dispatchEvent(select.nativeElement, 'change'); @@ -348,7 +348,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' it('should throw an error when compareWith is not a function', () => { const fixture = initTest(NgModelSelectWithCustomCompareFnForm); const comp = fixture.componentInstance; - comp.compareFn = null !; + comp.compareFn = null!; expect(() => fixture.detectChanges()) .toThrowError(/compareWith must be a function, but received null/); }); @@ -398,16 +398,11 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(select.nativeElement.value).toEqual('3: Object'); expect(nyOption.nativeElement.selected).toBe(true); })); - - }); - }); describe('select multiple controls', () => { - describe('in reactive forms', () => { - it('should support primitive values', () => { if (isNode) return; const fixture = initTest(FormControlSelectMultiple); @@ -432,7 +427,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' it('should throw an error when compareWith is not a function', () => { const fixture = initTest(FormControlSelectMultipleWithCompareFn); - fixture.componentInstance.compareFn = null !; + fixture.componentInstance.compareFn = null!; expect(() => fixture.detectChanges()) .toThrowError(/compareWith must be a function, but received null/); }); @@ -448,7 +443,6 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(select.nativeElement.value).toEqual('0: Object'); expect(sfOption.nativeElement.selected).toBe(true); })); - }); describe('in template-driven forms', () => { @@ -520,7 +514,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' it('should throw an error when compareWith is not a function', () => { const fixture = initTest(NgModelSelectMultipleWithCustomCompareFnForm); const comp = fixture.componentInstance; - comp.compareFn = null !; + comp.compareFn = null!; expect(() => fixture.detectChanges()) .toThrowError(/compareWith must be a function, but received null/); }); @@ -539,13 +533,10 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(select.nativeElement.value).toEqual('0: Object'); expect(sfOption.nativeElement.selected).toBe(true); })); - }); describe('should support <type=radio>', () => { - describe('in reactive forms', () => { - it('should support basic functionality', () => { const fixture = initTest(FormControlRadioButtons); const form = @@ -562,10 +553,10 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.detectChanges(); // view -> model - expect(form.get('food') !.value).toEqual('chicken'); + expect(form.get('food')!.value).toEqual('chicken'); expect(inputs[1].nativeElement.checked).toEqual(false); - form.get('food') !.setValue('fish'); + form.get('food')!.setValue('fish'); fixture.detectChanges(); // programmatic change -> view @@ -606,16 +597,16 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.componentInstance.form = form; fixture.detectChanges(); - form.get('food') !.setValue(null); + form.get('food')!.setValue(null); fixture.detectChanges(); const inputs = fixture.debugElement.queryAll(By.css('input')); expect(inputs[0].nativeElement.checked).toEqual(false); - form.get('food') !.setValue('chicken'); + form.get('food')!.setValue('chicken'); fixture.detectChanges(); - form.get('food') !.setValue(undefined); + form.get('food')!.setValue(undefined); fixture.detectChanges(); expect(inputs[0].nativeElement.checked).toEqual(false); }); @@ -706,13 +697,12 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.detectChanges(); // view -> model - expect(form.get('food') !.value).toEqual('chicken'); - expect(form.get('nested.food') !.value).toEqual('fish'); + expect(form.get('food')!.value).toEqual('chicken'); + expect(form.get('nested.food')!.value).toEqual('fish'); expect(inputs[1].nativeElement.checked).toEqual(false); expect(inputs[2].nativeElement.checked).toEqual(false); expect(inputs[3].nativeElement.checked).toEqual(true); - }); it('should disable all radio buttons when disable() is called', () => { @@ -728,7 +718,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(inputs[2].nativeElement.disabled).toEqual(false); expect(inputs[3].nativeElement.disabled).toEqual(false); - form.get('food') !.disable(); + form.get('food')!.disable(); expect(inputs[0].nativeElement.disabled).toEqual(true); expect(inputs[1].nativeElement.disabled).toEqual(true); expect(inputs[2].nativeElement.disabled).toEqual(false); @@ -780,7 +770,6 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(inputs[0].nativeElement.checked).toBe(false); expect(inputs[1].nativeElement.checked).toBe(true); }); - }); describe('in template-driven forms', () => { @@ -860,7 +849,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.detectChanges(); tick(); - fixture.componentInstance.food = null !; + fixture.componentInstance.food = null!; fixture.detectChanges(); tick(); @@ -872,7 +861,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.detectChanges(); tick(); - fixture.componentInstance.food = undefined !; + fixture.componentInstance.food = undefined!; fixture.detectChanges(); tick(); expect(inputs[0].nativeElement.checked).toEqual(false); @@ -886,7 +875,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' tick(); const form = fixture.debugElement.children[0].injector.get(NgForm); - form.control.get('food') !.disable(); + form.control.get('food')!.disable(); tick(); const inputs = fixture.debugElement.queryAll(By.css('input')); @@ -911,15 +900,11 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(inputs[2].nativeElement.disabled).toBe(false); expect(inputs[3].nativeElement.disabled).toBe(false); })); - }); - }); describe('should support <type=range>', () => { - describe('in reactive forms', () => { - it('with basic use case', () => { const fixture = initTest(FormControlRangeInput); const control = new FormControl(10); @@ -968,7 +953,6 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' const input = fixture.debugElement.query(By.css('input')); expect(input.nativeElement.value).toEqual(''); }); - }); describe('in template-driven forms', () => { @@ -987,15 +971,12 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' tick(); // view -> model fixture.detectChanges(); - expect(typeof(fixture.componentInstance.val)).toBe('number'); + expect(typeof (fixture.componentInstance.val)).toBe('number'); })); - }); - }); describe('custom value accessors', () => { - describe('in reactive forms', () => { it('should support basic functionality', () => { const fixture = initTest(WrappedValueForm, WrappedValue); @@ -1014,9 +995,9 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' expect(form.value).toEqual({'login': 'bb'}); // custom validator - expect(form.get('login') !.errors).toEqual({'err': true}); + expect(form.get('login')!.errors).toEqual({'err': true}); form.setValue({login: 'expected'}); - expect(form.get('login') !.errors).toEqual(null); + expect(form.get('login')!.errors).toEqual(null); }); it('should support non builtin input elements that fire a change event without a \'target\' property', @@ -1042,7 +1023,7 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' }); fixture.detectChanges(); expect(fixture.componentInstance.form.status).toEqual('DISABLED'); - expect(fixture.componentInstance.form.get('login') !.status).toEqual('DISABLED'); + expect(fixture.componentInstance.form.get('login')!.status).toEqual('DISABLED'); }); it('should support custom accessors without setDisabledState - formControlDirective', @@ -1061,9 +1042,9 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' fixture.componentInstance.form = new FormGroup({'login': new FormControl('aa')}); fixture.detectChanges(); - expect(fixture.componentInstance.myInput !.control).toBeDefined(); - expect(fixture.componentInstance.myInput !.control) - .toEqual(fixture.componentInstance.myInput !.controlDir.control); + expect(fixture.componentInstance.myInput!.control).toBeDefined(); + expect(fixture.componentInstance.myInput!.control) + .toEqual(fixture.componentInstance.myInput!.controlDir.control); }); }); @@ -1089,16 +1070,14 @@ import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util' }); })); }); - }); - }); } @Component({selector: 'form-control-comp', template: `<input type="text" [formControl]="control">`}) export class FormControlComp { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; } @Component({ @@ -1110,13 +1089,13 @@ export class FormControlComp { }) export class FormGroupComp { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; // TODO(issue/24571): remove '!'. - myGroup !: FormGroup; + myGroup!: FormGroup; // TODO(issue/24571): remove '!'. - event !: Event; + event!: Event; } @Component({ @@ -1125,7 +1104,7 @@ export class FormGroupComp { }) class FormControlNumberInput { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; } @Component({ @@ -1167,7 +1146,7 @@ class FormControlSelectNgValue { }) class FormControlSelectWithCompareFn { compareFn: - (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2? o1.id === o2.id: o1 === o2 + (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2 ? o1.id === o2.id : o1 === o2 cities = [{id: 1, name: 'SF'}, {id: 2, name: 'NY'}]; form = new FormGroup({city: new FormControl({id: 1, name: 'SF'})}); } @@ -1211,7 +1190,7 @@ class FormControlSelectMultipleNgValue { }) class FormControlSelectMultipleWithCompareFn { compareFn: - (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2? o1.id === o2.id: o1 === o2 + (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2 ? o1.id === o2.id : o1 === o2 cities = [{id: 1, name: 'SF'}, {id: 2, name: 'NY'}]; form = new FormGroup({city: new FormControl([{id: 1, name: 'SF'}])}); } @@ -1254,7 +1233,7 @@ class NgModelSelectWithNullForm { }) class NgModelSelectWithCustomCompareFnForm { compareFn: - (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2? o1.id === o2.id: o1 === o2 + (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2 ? o1.id === o2.id : o1 === o2 selectedCity: any = {}; cities: any[] = []; } @@ -1270,7 +1249,7 @@ class NgModelSelectWithCustomCompareFnForm { }) class NgModelSelectMultipleWithCustomCompareFnForm { compareFn: - (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2? o1.id === o2.id: o1 === o2 + (o1: any, o2: any) => boolean = (o1: any, o2: any) => o1 && o2 ? o1.id === o2.id : o1 === o2 selectedCities: any[] = []; cities: any[] = []; } @@ -1285,7 +1264,7 @@ class NgModelSelectMultipleWithCustomCompareFnForm { }) class NgModelSelectMultipleForm { // TODO(issue/24571): remove '!'. - selectedCities !: any[]; + selectedCities!: any[]; cities: any[] = []; } @@ -1295,7 +1274,7 @@ class NgModelSelectMultipleForm { }) class FormControlRangeInput { // TODO(issue/24571): remove '!'. - control !: FormControl; + control!: FormControl; } @Component({selector: 'ng-model-range-form', template: '<input type="range" [(ngModel)]="val">'}) @@ -1317,7 +1296,7 @@ class NgModelRangeForm { }) export class FormControlRadioButtons { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; showRadio = new FormControl('yes'); } @@ -1335,9 +1314,9 @@ export class FormControlRadioButtons { }) class NgModelRadioForm { // TODO(issue/24571): remove '!'. - food !: string; + food!: string; // TODO(issue/24571): remove '!'. - drink !: string; + drink!: string; } @Directive({ @@ -1351,37 +1330,55 @@ class NgModelRadioForm { class WrappedValue implements ControlValueAccessor { value: any; // TODO(issue/24571): remove '!'. - onChange !: Function; + onChange!: Function; - writeValue(value: any) { this.value = `!${value}!`; } + writeValue(value: any) { + this.value = `!${value}!`; + } - registerOnChange(fn: (value: any) => void) { this.onChange = fn; } + registerOnChange(fn: (value: any) => void) { + this.onChange = fn; + } registerOnTouched(fn: any) {} - handleOnInput(value: any) { this.onChange(value.substring(1, value.length - 1)); } + handleOnInput(value: any) { + this.onChange(value.substring(1, value.length - 1)); + } - validate(c: AbstractControl) { return c.value === 'expected' ? null : {'err': true}; } + validate(c: AbstractControl) { + return c.value === 'expected' ? null : {'err': true}; + } } @Component({selector: 'my-input', template: ''}) export class MyInput implements ControlValueAccessor { @Output('input') onInput = new EventEmitter(); // TODO(issue/24571): remove '!'. - value !: string; + value!: string; control: AbstractControl|null = null; - constructor(public controlDir: NgControl) { controlDir.valueAccessor = this; } + constructor(public controlDir: NgControl) { + controlDir.valueAccessor = this; + } - ngOnInit() { this.control = this.controlDir.control; } + ngOnInit() { + this.control = this.controlDir.control; + } - writeValue(value: any) { this.value = `!${value}!`; } + writeValue(value: any) { + this.value = `!${value}!`; + } - registerOnChange(fn: (value: any) => void) { this.onInput.subscribe({next: fn}); } + registerOnChange(fn: (value: any) => void) { + this.onInput.subscribe({next: fn}); + } registerOnTouched(fn: any) {} - dispatchChangeEvent() { this.onInput.emit(this.value.substring(1, this.value.length - 1)); } + dispatchChangeEvent() { + this.onInput.emit(this.value.substring(1, this.value.length - 1)); + } } @Component({ @@ -1393,7 +1390,7 @@ export class MyInput implements ControlValueAccessor { }) export class MyInputForm { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; @ViewChild(MyInput) myInput: MyInput|null = null; } @@ -1406,7 +1403,7 @@ export class MyInputForm { }) class WrappedValueForm { // TODO(issue/24571): remove '!'. - form !: FormGroup; + form!: FormGroup; } @Component({ @@ -1418,18 +1415,24 @@ class WrappedValueForm { }) export class NgModelCustomComp implements ControlValueAccessor { // TODO(issue/24571): remove '!'. - model !: string; + model!: string; @Input('disabled') isDisabled: boolean = false; // TODO(issue/24571): remove '!'. - changeFn !: (value: any) => void; + changeFn!: (value: any) => void; - writeValue(value: any) { this.model = value; } + writeValue(value: any) { + this.model = value; + } - registerOnChange(fn: (value: any) => void) { this.changeFn = fn; } + registerOnChange(fn: (value: any) => void) { + this.changeFn = fn; + } registerOnTouched() {} - setDisabledState(isDisabled: boolean) { this.isDisabled = isDisabled; } + setDisabledState(isDisabled: boolean) { + this.isDisabled = isDisabled; + } } @Component({ @@ -1442,6 +1445,6 @@ export class NgModelCustomComp implements ControlValueAccessor { }) export class NgModelCustomWrapper { // TODO(issue/24571): remove '!'. - name !: string; + name!: string; isDisabled = false; } From d2623f13d96ed2d4c35a5f43db4b15539ee46a30 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir <akushnir@google.com> Date: Tue, 7 Apr 2020 09:59:25 -0700 Subject: [PATCH 129/262] style(zone.js): fix lint errors after clang update (#36487) Recent ZoneJS-related commit (https://github.com/angular/angular/commit/416c786774dccc20d824737207be4e55cb53c9cc) update the `promise.ts` file, but it looks like original PR was not rebased after clang update. As a result, the `lint` CircleCI job started to fail in master after merging that PR (https://github.com/angular/angular/pull/36311). This commit updates the format of the `promise.ts` script according to the new clang rules. PR Close #36487 --- packages/zone.js/lib/common/promise.ts | 77 +++++++++++++++++--------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/packages/zone.js/lib/common/promise.ts b/packages/zone.js/lib/common/promise.ts index 8f41b06478cbf..50d14321c5f3b 100644 --- a/packages/zone.js/lib/common/promise.ts +++ b/packages/zone.js/lib/common/promise.ts @@ -34,9 +34,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr if (rejection) { console.error( 'Unhandled Promise rejection:', - rejection instanceof Error ? rejection.message : rejection, '; Zone:', - (<Zone>e.zone).name, '; Task:', e.task && (<Task>e.task).source, '; Value:', rejection, - rejection instanceof Error ? rejection.stack : undefined); + rejection instanceof Error ? rejection.message : rejection, + '; Zone:', (<Zone>e.zone).name, '; Task:', e.task && (<Task>e.task).source, + '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); } else { console.error(e); } @@ -45,9 +45,11 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr api.microtaskDrainDone = () => { while (_uncaughtPromiseErrors.length) { - const uncaughtPromiseError: UncaughtPromiseError = _uncaughtPromiseErrors.shift() !; + const uncaughtPromiseError: UncaughtPromiseError = _uncaughtPromiseErrors.shift()!; try { - uncaughtPromiseError.zone.runGuarded(() => { throw uncaughtPromiseError; }); + uncaughtPromiseError.zone.runGuarded(() => { + throw uncaughtPromiseError; + }); } catch (error) { handleUnhandledRejection(error); } @@ -67,11 +69,17 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr } } - function isThenable(value: any): boolean { return value && value.then; } + function isThenable(value: any): boolean { + return value && value.then; + } - function forwardResolution(value: any): any { return value; } + function forwardResolution(value: any): any { + return value; + } - function forwardRejection(rejection: any): any { return ZoneAwarePromise.reject(rejection); } + function forwardRejection(rejection: any): any { + return ZoneAwarePromise.reject(rejection); + } const symbolState: string = __symbol__('state'); const symbolValue: string = __symbol__('value'); @@ -127,7 +135,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr then = value && value.then; } } catch (err) { - onceWrapper(() => { resolvePromise(promise, false, err); })(); + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); return promise; } // if (value instanceof ZoneAwarePromise) { @@ -142,7 +152,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); } catch (err) { - onceWrapper(() => { resolvePromise(promise, false, err); })(); + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); } } else { (promise as any)[symbolState] = state; @@ -197,7 +209,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr uncaughtPromiseError.rejection = value; uncaughtPromiseError.promise = promise; uncaughtPromiseError.zone = Zone.current; - uncaughtPromiseError.task = Zone.currentTask !; + uncaughtPromiseError.task = Zone.currentTask!; _uncaughtPromiseErrors.push(uncaughtPromiseError); api.scheduleMicroTask(); // to make sure that it is running } @@ -233,8 +245,8 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr function scheduleResolveOrReject<R, U1, U2>( promise: ZoneAwarePromise<any>, zone: Zone, chainPromise: ZoneAwarePromise<any>, - onFulfilled?: ((value: R) => U1) | null | undefined, - onRejected?: ((error: any) => U2) | null | undefined): void { + onFulfilled?: ((value: R) => U1)|null|undefined, + onRejected?: ((error: any) => U2)|null|undefined): void { clearRejectedNoCatch(promise); const promiseState = (promise as any)[symbolState]; const delegate = promiseState ? @@ -269,7 +281,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr const noop = function() {}; class ZoneAwarePromise<R> implements Promise<R> { - static toString() { return ZONE_AWARE_PROMISE_TO_STRING; } + static toString() { + return ZONE_AWARE_PROMISE_TO_STRING; + } static resolve<R>(value: R): Promise<R> { return resolvePromise(<ZoneAwarePromise<R>>new this(null as any), RESOLVED, value); @@ -286,8 +300,12 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr resolve = res; reject = rej; }); - function onResolve(value: any) { resolve(value); } - function onReject(error: any) { reject(error); } + function onResolve(value: any) { + resolve(value); + } + function onReject(error: any) { + reject(error); + } for (let value of values) { if (!isThenable(value)) { @@ -298,7 +316,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr return promise; } - static all<R>(values: any): Promise<R> { return ZoneAwarePromise.allWithCallback(values); } + static all<R>(values: any): Promise<R> { + return ZoneAwarePromise.allWithCallback(values); + } static allSettled<R>(values: any): Promise<R> { const P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; @@ -336,22 +356,22 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; unresolvedCount--; if (unresolvedCount === 0) { - resolve !(resolvedValues); + resolve!(resolvedValues); } }, (err: any) => { if (!callback) { - reject !(err); + reject!(err); } else { resolvedValues[curValueIndex] = callback.errorCallback(err); unresolvedCount--; if (unresolvedCount === 0) { - resolve !(resolvedValues); + resolve!(resolvedValues); } } }); } catch (thenErr) { - reject !(thenErr); + reject!(thenErr); } unresolvedCount++; @@ -362,7 +382,7 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr unresolvedCount -= 2; if (unresolvedCount === 0) { - resolve !(resolvedValues); + resolve!(resolvedValues); } return promise; @@ -384,9 +404,13 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr } } - get[Symbol.toStringTag]() { return 'Promise' as any; } + get[Symbol.toStringTag]() { + return 'Promise' as any; + } - get[Symbol.species]() { return ZoneAwarePromise; } + get[Symbol.species]() { + return ZoneAwarePromise; + } then<TResult1 = R, TResult2 = never>( onFulfilled?: ((value: R) => TResult1 | PromiseLike<TResult1>)|undefined|null, @@ -492,8 +516,9 @@ Zone.__load_patch('ZoneAwarePromise', (global: any, Zone: ZoneType, api: _ZonePr proto[symbolThen] = originalThen; Ctor.prototype.then = function(onResolve: any, onReject: any) { - const wrapped = - new ZoneAwarePromise((resolve, reject) => { originalThen.call(this, resolve, reject); }); + const wrapped = new ZoneAwarePromise((resolve, reject) => { + originalThen.call(this, resolve, reject); + }); return wrapped.then(onResolve, onReject); }; (Ctor as any)[symbolThenPatched] = true; From 2dd6f25647c0c9e74401af7d1da7489a03f7e5ba Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 6 Apr 2020 12:15:05 -0700 Subject: [PATCH 130/262] ci: manually set available resources for bazel on windows CI (#36458) PR Close #36458 --- .circleci/bazel.linux.rc | 3 ++- .circleci/bazel.windows.rc | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.circleci/bazel.linux.rc b/.circleci/bazel.linux.rc index 4889f934b22ff..afb8fd47f114e 100644 --- a/.circleci/bazel.linux.rc +++ b/.circleci/bazel.linux.rc @@ -14,7 +14,8 @@ build --repository_cache=/home/circleci/bazel_repository_cache # Bazel doesn't calculate the memory ceiling correctly when running under Docker. # Limit Bazel to consuming resources that fit in CircleCI "xlarge" class # https://circleci.com/docs/2.0/configuration-reference/#resource_class -build --local_resources=14336,8.0,1.0 +build --local_cpu_resources=8 +build --local_ram_resources=14336 # All build executed remotely should be done using our RBE configuration. build:remote --google_default_credentials diff --git a/.circleci/bazel.windows.rc b/.circleci/bazel.windows.rc index 9efa954554f1b..ce3e53392c8a4 100644 --- a/.circleci/bazel.windows.rc +++ b/.circleci/bazel.windows.rc @@ -10,6 +10,10 @@ try-import %workspace%/.circleci/bazel.common.rc # speeding up the analysis time significantly with Bazel managed node dependencies on the CI. build --repository_cache=C:/Users/circleci/bazel_repository_cache +# Manually set the local resources used in windows CI runs +build --local_ram_resources=13500 +build --local_cpu_resources=4 + # All windows jobs run on master and should use http caching build --remote_http_cache=https://storage.googleapis.com/angular-team-cache build --remote_accept_cached=true From 2c7d366c82011453ed82486fe51d6edbce97b1d6 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz <ayazhafiz@lyft.com> Date: Sat, 28 Mar 2020 23:26:51 -0700 Subject: [PATCH 131/262] refactor(language-service): provide service for attribute binding type (#36301) This commit refactors the process for determining the type of an Angular attribute to be use a function that takes an attribute name and returns the Angular attribute kind and name, rather than requiring the user to query match the attribute name with the regex and query the matching array. This refactor prepares for a future change that will improve the experience of completing attributes in `()`, `[]`, or `[()]` contexts. PR Close #36301 --- .../language-service/src/binding_utils.ts | 69 ++++++++++++++ packages/language-service/src/completions.ts | 94 +++++++------------ 2 files changed, 105 insertions(+), 58 deletions(-) create mode 100644 packages/language-service/src/binding_utils.ts diff --git a/packages/language-service/src/binding_utils.ts b/packages/language-service/src/binding_utils.ts new file mode 100644 index 0000000000000..99902a8aacf6b --- /dev/null +++ b/packages/language-service/src/binding_utils.ts @@ -0,0 +1,69 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Matches an Angular attribute to a binding type. See `ATTR` for more details. + * + * This is adapted from packages/compiler/src/render3/r3_template_transform.ts + * to allow empty binding names and match template attributes. + */ +const BIND_NAME_REGEXP = + /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@)|(\*))(.*))|\[\(([^\)]*)\)\]|\[([^\]]*)\]|\(([^\)]*)\))$/; +/** + * Represents possible Angular attribute bindings, as indices on a match of `BIND_NAME_REGEXP`. + */ +export enum ATTR { + /** "bind-" */ + KW_BIND = 1, + /** "let-" */ + KW_LET = 2, + /** "ref-/#" */ + KW_REF = 3, + /** "on-" */ + KW_ON = 4, + /** "bindon-" */ + KW_BINDON = 5, + /** "@" */ + KW_AT = 6, + /** + * "*" + * Microsyntax template starts with '*'. See https://angular.io/api/core/TemplateRef + */ + KW_MICROSYNTAX = 7, + /** The identifier after "bind-", "let-", "ref-/#", "on-", "bindon-", "@", or "*" */ + IDENT_KW = 8, + /** Identifier inside [()] */ + IDENT_BANANA_BOX = 9, + /** Identifier inside [] */ + IDENT_PROPERTY = 10, + /** Identifier inside () */ + IDENT_EVENT = 11, +} + +export interface BindingDescriptor { + kind: ATTR; + name: string; +} +/** + * Returns a descriptor for a given Angular attribute, or undefined if the attribute is + * not an Angular attribute. + */ +export function getBindingDescriptor(attribute: string): BindingDescriptor|undefined { + const bindParts = attribute.match(BIND_NAME_REGEXP); + if (!bindParts) return; + // The first match element is skipped because it matches the entire attribute text, including the + // binding part. + const kind = bindParts.findIndex((val, i) => i > 0 && val !== undefined); + if (!(kind in ATTR)) { + throw TypeError(`"${kind}" is not a valid Angular binding kind for "${attribute}"`); + } + return { + kind, + name: bindParts[ATTR.IDENT_KW], + }; +} diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index dc0895c26e6fb..e5afe71617630 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -9,6 +9,7 @@ import {AbsoluteSourceSpan, AST, AstPath, AttrAst, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, Element, ElementAst, EmptyExpr, ExpressionBinding, getHtmlTagDefinition, HtmlAstPath, NAMED_ENTITIES, Node as HtmlAst, NullTemplateVisitor, ParseSpan, ReferenceAst, TagContentType, TemplateBinding, Text, VariableBinding} from '@angular/compiler'; import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; +import {ATTR, getBindingDescriptor} from './binding_utils'; import {AstResult} from './common'; import {getExpressionScope} from './expression_diagnostics'; import {getExpressionCompletions} from './expressions'; @@ -45,35 +46,6 @@ const ANGULAR_ELEMENTS: ReadonlyArray<ng.CompletionEntry> = [ }, ]; -// This is adapted from packages/compiler/src/render3/r3_template_transform.ts -// to allow empty binding names. -const BIND_NAME_REGEXP = - /^(?:(?:(?:(bind-)|(let-)|(ref-|#)|(on-)|(bindon-)|(@))(.*))|\[\(([^\)]*)\)\]|\[([^\]]*)\]|\(([^\)]*)\))$/; -enum ATTR { - // Group 1 = "bind-" - KW_BIND_IDX = 1, - // Group 2 = "let-" - KW_LET_IDX = 2, - // Group 3 = "ref-/#" - KW_REF_IDX = 3, - // Group 4 = "on-" - KW_ON_IDX = 4, - // Group 5 = "bindon-" - KW_BINDON_IDX = 5, - // Group 6 = "@" - KW_AT_IDX = 6, - // Group 7 = the identifier after "bind-", "let-", "ref-/#", "on-", "bindon-" or "@" - IDENT_KW_IDX = 7, - // Group 8 = identifier inside [()] - IDENT_BANANA_BOX_IDX = 8, - // Group 9 = identifier inside [] - IDENT_PROPERTY_IDX = 9, - // Group 10 = identifier inside () - IDENT_EVENT_IDX = 10, -} -// Microsyntax template starts with '*'. See https://angular.io/api/core/TemplateRef -const TEMPLATE_ATTR_PREFIX = '*'; - function isIdentifierPart(code: number) { // Identifiers consist of alphanumeric characters, '_', or '$'. return isAsciiLetter(code) || isDigit(code) || code == $$ || code == $_; @@ -233,34 +205,39 @@ function attributeCompletions(info: AstResult, path: AstPath<HtmlAst>): ng.Compl // matching using regex. This is because the regexp would incorrectly identify // bind parts for cases like [()|] // ^ cursor is here - const bindParts = attr.name.match(BIND_NAME_REGEXP); - const isTemplateRef = attr.name.startsWith(TEMPLATE_ATTR_PREFIX); - const isBinding = bindParts !== null || isTemplateRef; - - if (!isBinding) { + const binding = getBindingDescriptor(attr.name); + if (!binding) { + // This is a normal HTML attribute, not an Angular attribute. return attributeCompletionsForElement(info, elem.name); } const results: string[] = []; const ngAttrs = angularAttributes(info, elem.name); - if (!bindParts) { - // If bindParts is null then this must be a TemplateRef. - results.push(...ngAttrs.templateRefs); - } else if ( - bindParts[ATTR.KW_BIND_IDX] !== undefined || - bindParts[ATTR.IDENT_PROPERTY_IDX] !== undefined) { - // property binding via bind- or [] - results.push(...propertyNames(elem.name), ...ngAttrs.inputs); - } else if ( - bindParts[ATTR.KW_ON_IDX] !== undefined || bindParts[ATTR.IDENT_EVENT_IDX] !== undefined) { - // event binding via on- or () - results.push(...eventNames(elem.name), ...ngAttrs.outputs); - } else if ( - bindParts[ATTR.KW_BINDON_IDX] !== undefined || - bindParts[ATTR.IDENT_BANANA_BOX_IDX] !== undefined) { - // banana-in-a-box binding via bindon- or [()] - results.push(...ngAttrs.bananas); + switch (binding.kind) { + case ATTR.KW_MICROSYNTAX: + // template reference attribute: *attrName + results.push(...ngAttrs.templateRefs); + break; + + case ATTR.KW_BIND: + case ATTR.IDENT_PROPERTY: + // property binding via bind- or [] + results.push(...propertyNames(elem.name), ...ngAttrs.inputs); + break; + + case ATTR.KW_ON: + case ATTR.IDENT_EVENT: + // event binding via on- or () + results.push(...eventNames(elem.name), ...ngAttrs.outputs); + break; + + case ATTR.KW_BINDON: + case ATTR.IDENT_BANANA_BOX: + // banana-in-a-box binding via bindon- or [()] + results.push(...ngAttrs.bananas); + break; } + return results.map(name => { return { name, @@ -321,8 +298,8 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C // In order to provide accurate attribute value completion, we need to know // what the LHS is, and construct the proper AST if it is missing. const htmlAttr = htmlPath.tail as Attribute; - const bindParts = htmlAttr.name.match(BIND_NAME_REGEXP); - if (bindParts && bindParts[ATTR.KW_REF_IDX] !== undefined) { + const binding = getBindingDescriptor(htmlAttr.name); + if (binding && binding.kind === ATTR.KW_REF) { let refAst: ReferenceAst|undefined; let elemAst: ElementAst|undefined; if (templatePath.tail instanceof ReferenceAst) { @@ -456,11 +433,12 @@ class ExpressionVisitor extends NullTemplateVisitor { } visitAttr(ast: AttrAst) { - if (ast.name.startsWith(TEMPLATE_ATTR_PREFIX)) { + const binding = getBindingDescriptor(ast.name); + if (binding && binding.kind === ATTR.KW_MICROSYNTAX) { // This a template binding given by micro syntax expression. // First, verify the attribute consists of some binding we can give completions for. // The sourceSpan of AttrAst points to the RHS of the attribute - const templateKey = ast.name.substring(TEMPLATE_ATTR_PREFIX.length); + const templateKey = binding.name; const templateValue = ast.sourceSpan.toString(); const templateUrl = ast.sourceSpan.start.file.url; // TODO(kyliau): We are unable to determine the absolute offset of the key @@ -470,13 +448,13 @@ class ExpressionVisitor extends NullTemplateVisitor { const {templateBindings} = this.info.expressionParser.parseTemplateBindings( templateKey, templateValue, templateUrl, absKeyOffset, absValueOffset); // Find the template binding that contains the position. - const binding = templateBindings.find(b => inSpan(this.position, b.sourceSpan)); + const templateBinding = templateBindings.find(b => inSpan(this.position, b.sourceSpan)); - if (!binding) { + if (!templateBinding) { return; } - this.microSyntaxInAttributeValue(ast, binding); + this.microSyntaxInAttributeValue(ast, templateBinding); } else { const expressionAst = this.info.expressionParser.parseBinding( ast.value, ast.sourceSpan.toString(), ast.sourceSpan.start.offset); From 5fa7b8ba562ffce90cdd31116c173eb3eac1c161 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Tue, 7 Apr 2020 19:14:57 +0300 Subject: [PATCH 132/262] fix(ngcc): detect non-emitted, non-imported TypeScript helpers (#36418) When TypeScript downlevels ES2015+ code to ES5, it uses some helper functions to emulate some ES2015+ features, such as spread syntax. The TypeScript compiler can be configured to emit these helpers into the transpiled code (which is controlled by the `noEmitHelpers` option - false by default). It can also be configured to import these helpers from the `tslib` module (which is controlled by the `importHelpers` option - false by default). While most of the time the helpers will be either emitted or imported, it is possible that one configures their app to neither emit nor import them. In that case, the helpers could, for example, be made available on the global object. This is what `@nativescript/angular` v9.0.0-next-2019-11-12-155500-01 does. See, for example, [common.js][1]. Ngcc must be able to detect and statically evaluate these helpers. Previously, it was only able to detect emitted or imported helpers. This commit adds support for detecting these helpers if they are neither emitted nor imported. It does this by checking identifiers for which no declaration (either concrete or inline) can be found against a list of known TypeScript helper function names. [1]: https://unpkg.com/browse/@nativescript/angular@9.0.0-next-2019-11-12-155500-01/common.js PR Close #36418 --- .../compiler-cli/ngcc/src/host/esm5_host.ts | 18 ++++- .../ngcc/test/host/commonjs_host_spec.ts | 68 ++++++++++++++++ .../ngcc/test/host/esm5_host_spec.ts | 62 +++++++++++++++ .../ngcc/test/host/umd_host_spec.ts | 78 +++++++++++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) diff --git a/packages/compiler-cli/ngcc/src/host/esm5_host.ts b/packages/compiler-cli/ngcc/src/host/esm5_host.ts index 67c7abb291d09..17fd2134c83ad 100644 --- a/packages/compiler-cli/ngcc/src/host/esm5_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm5_host.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {ClassDeclaration, ClassMember, ClassMemberKind, Declaration, Decorator, FunctionDefinition, isNamedVariableDeclaration, Parameter, reflectObjectLiteral} from '../../../src/ngtsc/reflection'; -import {getNameText, getTsHelperFnFromDeclaration, hasNameIdentifier} from '../utils'; +import {getNameText, getTsHelperFnFromDeclaration, getTsHelperFnFromIdentifier, hasNameIdentifier} from '../utils'; import {Esm2015ReflectionHost, getPropertyValueFromSymbol, isAssignment, isAssignmentStatement, ParamInfo} from './esm2015_host'; import {NgccClassSymbol} from './ngcc_host'; @@ -192,6 +192,22 @@ export class Esm5ReflectionHost extends Esm2015ReflectionHost { getDeclarationOfIdentifier(id: ts.Identifier): Declaration|null { const superDeclaration = super.getDeclarationOfIdentifier(id); + if (superDeclaration === null) { + const nonEmittedNorImportedTsHelperDeclaration = getTsHelperFnFromIdentifier(id); + if (nonEmittedNorImportedTsHelperDeclaration !== null) { + // No declaration could be found for this identifier and its name matches a known TS helper + // function. This can happen if a package is compiled with `noEmitHelpers: true` and + // `importHelpers: false` (the default). This is, for example, the case with + // `@nativescript/angular@9.0.0-next-2019-11-12-155500-01`. + return { + expression: id, + known: nonEmittedNorImportedTsHelperDeclaration, + node: null, + viaModule: null, + }; + } + } + if (superDeclaration === null || superDeclaration.node === null || superDeclaration.known !== null) { return superDeclaration; diff --git a/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts b/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts index 421bab1b0d2f5..b4a4231371e53 100644 --- a/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts @@ -2000,6 +2000,74 @@ exports.ExternalModule = ExternalModule; testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib'); testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib'); }); + + it('should recognize undeclared, unimported TypeScript helpers (by name)', () => { + const file: TestFile = { + name: _('/test.js'), + contents: ` + var a = __assign({foo: 'bar'}, {baz: 'qux'}); + var b = __spread(['foo', 'bar'], ['baz', 'qux']); + var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']); + `, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); + + const testForHelper = + (varName: string, helperName: string, knownAs: KnownDeclaration) => { + const node = + getDeclaration(bundle.program, file.name, varName, ts.isVariableDeclaration); + const helperIdentifier = getIdentifierFromCallExpression(node); + const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); + + expect(helperDeclaration).toEqual({ + known: knownAs, + expression: helperIdentifier, + node: null, + viaModule: null, + }); + }; + + testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign); + testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread); + testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays); + }); + + it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => { + const file: TestFile = { + name: _('/test.js'), + contents: ` + var a = __assign$1({foo: 'bar'}, {baz: 'qux'}); + var b = __spread$2(['foo', 'bar'], ['baz', 'qux']); + var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']); + `, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = + createHost(bundle, new CommonJsReflectionHost(new MockLogger(), false, bundle)); + + const testForHelper = + (varName: string, helperName: string, knownAs: KnownDeclaration) => { + const node = + getDeclaration(bundle.program, file.name, varName, ts.isVariableDeclaration); + const helperIdentifier = getIdentifierFromCallExpression(node); + const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); + + expect(helperDeclaration).toEqual({ + known: knownAs, + expression: helperIdentifier, + node: null, + viaModule: null, + }); + }; + + testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign); + testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread); + testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays); + }); }); describe('getExportsOfModule()', () => { diff --git a/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts b/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts index 8182a8807de0b..0f5190a3c2a43 100644 --- a/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts @@ -2124,6 +2124,68 @@ runInEachFileSystem(() => { testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib'); testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib'); }); + + it('should recognize undeclared, unimported TypeScript helpers (by name)', () => { + const file: TestFile = { + name: _('/test.js'), + contents: ` + var a = __assign({foo: 'bar'}, {baz: 'qux'}); + var b = __spread(['foo', 'bar'], ['baz', 'qux']); + var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']); + `, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); + + const testForHelper = (varName: string, helperName: string, knownAs: KnownDeclaration) => { + const node = getDeclaration(bundle.program, file.name, varName, ts.isVariableDeclaration); + const helperIdentifier = getIdentifierFromCallExpression(node); + const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); + + expect(helperDeclaration).toEqual({ + known: knownAs, + expression: helperIdentifier, + node: null, + viaModule: null, + }); + }; + + testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign); + testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread); + testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays); + }); + + it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => { + const file: TestFile = { + name: _('/test.js'), + contents: ` + var a = __assign$1({foo: 'bar'}, {baz: 'qux'}); + var b = __spread$2(['foo', 'bar'], ['baz', 'qux']); + var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']); + `, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = createHost(bundle, new Esm5ReflectionHost(new MockLogger(), false, bundle)); + + const testForHelper = (varName: string, helperName: string, knownAs: KnownDeclaration) => { + const node = getDeclaration(bundle.program, file.name, varName, ts.isVariableDeclaration); + const helperIdentifier = getIdentifierFromCallExpression(node); + const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); + + expect(helperDeclaration).toEqual({ + known: knownAs, + expression: helperIdentifier, + node: null, + viaModule: null, + }); + }; + + testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign); + testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread); + testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays); + }); }); describe('getExportsOfModule()', () => { diff --git a/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts b/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts index 89319ab05f7d5..5aea2a1f13287 100644 --- a/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/host/umd_host_spec.ts @@ -2101,6 +2101,84 @@ runInEachFileSystem(() => { testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread, 'tslib'); testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays, 'tslib'); }); + + it('should recognize undeclared, unimported TypeScript helpers (by name)', () => { + const file: TestFile = { + name: _('/test.js'), + contents: ` + (function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define('test', ['exports'], factory) : + (factory(global.test)); + }(this, (function (exports) { 'use strict'; + var a = __assign({foo: 'bar'}, {baz: 'qux'}); + var b = __spread(['foo', 'bar'], ['baz', 'qux']); + var c = __spreadArrays(['foo', 'bar'], ['baz', 'qux']); + }))); + `, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); + const {factoryFn} = parseStatementForUmdModule( + getSourceFileOrError(bundle.program, file.name).statements[0])!; + + const testForHelper = (varName: string, helperName: string, knownAs: KnownDeclaration) => { + const node = getVariableDeclaration(factoryFn, varName); + const helperIdentifier = getIdentifierFromCallExpression(node); + const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); + + expect(helperDeclaration).toEqual({ + known: knownAs, + expression: helperIdentifier, + node: null, + viaModule: null, + }); + }; + + testForHelper('a', '__assign', KnownDeclaration.TsHelperAssign); + testForHelper('b', '__spread', KnownDeclaration.TsHelperSpread); + testForHelper('c', '__spreadArrays', KnownDeclaration.TsHelperSpreadArrays); + }); + + it('should recognize suffixed, undeclared, unimported TypeScript helpers (by name)', () => { + const file: TestFile = { + name: _('/test.js'), + contents: ` + (function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define('test', ['exports'], factory) : + (factory(global.test)); + }(this, (function (exports) { 'use strict'; + var a = __assign$1({foo: 'bar'}, {baz: 'qux'}); + var b = __spread$2(['foo', 'bar'], ['baz', 'qux']); + var c = __spreadArrays$3(['foo', 'bar'], ['baz', 'qux']); + }))); + `, + }; + loadTestFiles([file]); + const bundle = makeTestBundleProgram(file.name); + const host = createHost(bundle, new UmdReflectionHost(new MockLogger(), false, bundle)); + const {factoryFn} = parseStatementForUmdModule( + getSourceFileOrError(bundle.program, file.name).statements[0])!; + + const testForHelper = (varName: string, helperName: string, knownAs: KnownDeclaration) => { + const node = getVariableDeclaration(factoryFn, varName); + const helperIdentifier = getIdentifierFromCallExpression(node); + const helperDeclaration = host.getDeclarationOfIdentifier(helperIdentifier); + + expect(helperDeclaration).toEqual({ + known: knownAs, + expression: helperIdentifier, + node: null, + viaModule: null, + }); + }; + + testForHelper('a', '__assign$1', KnownDeclaration.TsHelperAssign); + testForHelper('b', '__spread$2', KnownDeclaration.TsHelperSpread); + testForHelper('c', '__spreadArrays$3', KnownDeclaration.TsHelperSpreadArrays); + }); }); describe('getExportsOfModule()', () => { From e145fa13b166b19e0dced619cc86d2e88fedd275 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@google.com> Date: Mon, 6 Apr 2020 16:14:09 -0700 Subject: [PATCH 133/262] test(language-service): delete expression-cases.ts (#36468) This commit deletes `expression-cases.ts` and moves the test cases to inline expressions in TEST_TEMPLATE. PR Close #36468 --- .../language-service/test/diagnostics_spec.ts | 44 ++++++++++--------- .../test/project/app/expression-cases.ts | 41 ----------------- .../language-service/test/project/app/main.ts | 6 --- .../test/project/app/parsing-cases.ts | 1 + .../language-service/test/ts_plugin_spec.ts | 4 +- 5 files changed, 26 insertions(+), 70 deletions(-) delete mode 100644 packages/language-service/test/project/app/expression-cases.ts diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index 6f2aa589c006e..1bea06f6cd086 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -246,30 +246,32 @@ describe('diagnostics', () => { expect(diags).toEqual([]); }); - describe('in expression-cases.ts', () => { - it('should report access to an unknown field', () => { - const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); - expect(diags).toContain( - `Identifier 'foo' is not defined. ` + - `The component declaration, template variable declarations, ` + - `and element references do not contain such a member`); - }); + it('should report access to an unknown field', () => { + mockHost.override(TEST_TEMPLATE, `{{ foo }}`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE).map(d => d.messageText); + expect(diags).toContain( + `Identifier 'foo' is not defined. ` + + `The component declaration, template variable declarations, ` + + `and element references do not contain such a member`); + }); - it('should report access to an unknown sub-field', () => { - const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); - expect(diags).toContain( - `Identifier 'nam' is not defined. 'Person' does not contain such a member`); - }); + it('should report access to an unknown sub-field', () => { + mockHost.override(TEST_TEMPLATE, `{{ hero.nam }}`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE).map(d => d.messageText); + expect(diags).toContain( + `Identifier 'nam' is not defined. 'Hero' does not contain such a member`); + }); - it('should report access to a private member', () => { - const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); - expect(diags).toContain(`Identifier 'myField' refers to a private member of the component`); - }); + it('should report access to a private member', () => { + mockHost.override(TEST_TEMPLATE, `{{ myField }}`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE).map(d => d.messageText); + expect(diags).toContain(`Identifier 'myField' refers to a private member of the component`); + }); - it('should report numeric operator errors', () => { - const diags = ngLS.getSemanticDiagnostics(EXPRESSION_CASES).map(d => d.messageText); - expect(diags).toContain('Expected a number type'); - }); + it('should report numeric operator errors', () => { + mockHost.override(TEST_TEMPLATE, `{{ 'a' % 2 }}`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE).map(d => d.messageText); + expect(diags).toContain('Expected a number type'); }); describe('in ng-for-cases.ts', () => { diff --git a/packages/language-service/test/project/app/expression-cases.ts b/packages/language-service/test/project/app/expression-cases.ts deleted file mode 100644 index b8ebc80194bc9..0000000000000 --- a/packages/language-service/test/project/app/expression-cases.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {Component} from '@angular/core'; - -export interface Person { - name: string; - age: number; -} - -@Component({ - template: '{{~{start-foo}foo~{end-foo}}}', -}) -export class WrongFieldReference { - bar = 'bar'; -} - -@Component({ - template: '{{~{start-nam}person.nam~{end-nam}}}', -}) -export class WrongSubFieldReference { - person: Person = {name: 'Bob', age: 23}; -} - -@Component({ - template: '{{~{start-myField}myField~{end-myField}}}', -}) -export class PrivateReference { - private myField = 'My Field'; -} - -@Component({ - template: '{{~{start-mod}"a" ~{end-mod}% 2}}', -}) -export class ExpectNumericType { -} diff --git a/packages/language-service/test/project/app/main.ts b/packages/language-service/test/project/app/main.ts index edd01e1289fe3..27f0f8d17ce21 100644 --- a/packages/language-service/test/project/app/main.ts +++ b/packages/language-service/test/project/app/main.ts @@ -9,9 +9,7 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; - import {AppComponent} from './app.component'; -import * as ExpressionCases from './expression-cases'; import * as NgForCases from './ng-for-cases'; import * as NgIfCases from './ng-if-cases'; import * as ParsingCases from './parsing-cases'; @@ -20,10 +18,6 @@ import * as ParsingCases from './parsing-cases'; imports: [CommonModule, FormsModule], declarations: [ AppComponent, - ExpressionCases.ExpectNumericType, - ExpressionCases.PrivateReference, - ExpressionCases.WrongFieldReference, - ExpressionCases.WrongSubFieldReference, NgForCases.UnknownEven, NgForCases.UnknownPeople, NgForCases.UnknownTrackBy, diff --git a/packages/language-service/test/project/app/parsing-cases.ts b/packages/language-service/test/project/app/parsing-cases.ts index 3158b8a2154fe..da5c203034d45 100644 --- a/packages/language-service/test/project/app/parsing-cases.ts +++ b/packages/language-service/test/project/app/parsing-cases.ts @@ -169,6 +169,7 @@ export class TemplateReference { birthday = new Date(); readonlyHeroes: ReadonlyArray<Readonly<Hero>> = this.heroes; constNames = [{name: 'name'}] as const; + private myField = 'My Field'; } @Component({ diff --git a/packages/language-service/test/ts_plugin_spec.ts b/packages/language-service/test/ts_plugin_spec.ts index 97d93a253c871..84817cf1ad1ca 100644 --- a/packages/language-service/test/ts_plugin_spec.ts +++ b/packages/language-service/test/ts_plugin_spec.ts @@ -57,8 +57,8 @@ describe('plugin', () => { const compilerDiags = tsLS.getCompilerOptionsDiagnostics(); expect(compilerDiags).toEqual([]); const sourceFiles = program.getSourceFiles().filter(f => !f.fileName.endsWith('.d.ts')); - // there are six .ts files in the test project - expect(sourceFiles.length).toBe(6); + // there are five .ts files in the test project + expect(sourceFiles.length).toBe(5); for (const {fileName} of sourceFiles) { const syntacticDiags = tsLS.getSyntacticDiagnostics(fileName); expect(syntacticDiags).toEqual([]); From 95fc3d4c5cc8eb50e9b280f3d6990889b966796a Mon Sep 17 00:00:00 2001 From: crisbeto <crisbeto@abv.bg> Date: Tue, 3 Mar 2020 21:05:26 +0100 Subject: [PATCH 134/262] fix(core): ngOnDestroy on multi providers called with incorrect context (#35840) Currently destroy hooks are stored in memory as `[1, hook, 5, hook]` where the numbers represent the index at which to find the context and `hook` is the function to be invoked. This breaks down for `multi` providers, because the value at the index will be an array of providers, resulting in the hook being invoked with an array of all the multi provider values, rather than the provider that was destroyed. In ViewEngine `ngOnDestroy` wasn't being called for `multi` providers at all. These changes fix the issue by changing the structure of the destroy hooks to `[1, hook, 5, [0, hook, 3, hook]]` where the indexes inside the inner array point to the provider inside of the multi provider array. Note that this is slightly different from the original design which called for the structure to be `[1, hook, 5, [hook, hook]`, because in the process of implementing it, I realized that we wouldn't get passing the correct context if only some of the `multi` providers have `ngOnDestroy` and others don't. I've run the newly-added `view_destroy_hooks` benchmark against these changes and compared it to master. The difference seems to be insignificant (between 1% and 2% slower). Fixes #35231. PR Close #35840 --- aio/scripts/_payload-limits.json | 2 +- integration/_payload-limits.json | 4 +- packages/core/src/render3/di_setup.ts | 61 +++-- .../src/render3/instructions/lview_debug.ts | 181 ++++++++----- .../core/src/render3/instructions/shared.ts | 234 ++++++++--------- packages/core/src/render3/interfaces/view.ts | 49 +++- .../core/src/render3/node_manipulation.ts | 103 ++++---- .../core/test/acceptance/providers_spec.ts | 241 ++++++++++++++---- 8 files changed, 579 insertions(+), 296 deletions(-) diff --git a/aio/scripts/_payload-limits.json b/aio/scripts/_payload-limits.json index e83f14b8a127c..e10ce7bf43874 100755 --- a/aio/scripts/_payload-limits.json +++ b/aio/scripts/_payload-limits.json @@ -12,7 +12,7 @@ "master": { "uncompressed": { "runtime-es2015": 2987, - "main-es2015": 451469, + "main-es2015": 452060, "polyfills-es2015": 52195 } } diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 6d1421d89fcf1..0bff4575c24b8 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -3,7 +3,7 @@ "master": { "uncompressed": { "runtime-es2015": 1485, - "main-es2015": 141569, + "main-es2015": 142073, "polyfills-es2015": 36657 } } @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime-es2015": 1485, - "main-es2015": 147647, + "main-es2015": 148196, "polyfills-es2015": 36657 } } diff --git a/packages/core/src/render3/di_setup.ts b/packages/core/src/render3/di_setup.ts index 483ae76f4497c..5119bc37060ea 100644 --- a/packages/core/src/render3/di_setup.ts +++ b/packages/core/src/render3/di_setup.ts @@ -10,6 +10,7 @@ import {resolveForwardRef} from '../di/forward_ref'; import {ClassProvider, Provider} from '../di/interface/provider'; import {isClassProvider, isTypeProvider, providerToFactory} from '../di/r3_injector'; +import {assertDefined} from '../util/assert'; import {diPublicInInjector, getNodeInjectable, getOrCreateNodeInjectorForNode} from './di'; import {ɵɵdirectiveInject} from './instructions/all'; @@ -17,7 +18,7 @@ import {DirectiveDef} from './interfaces/definition'; import {NodeInjectorFactory} from './interfaces/injector'; import {TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNodeProviderIndexes} from './interfaces/node'; import {isComponentDef} from './interfaces/type_checks'; -import {LView, TData, TVIEW, TView} from './interfaces/view'; +import {DestroyHookData, LView, TData, TVIEW, TView} from './interfaces/view'; import {getLView, getPreviousOrParentTNode, getTView} from './state'; @@ -149,7 +150,7 @@ function resolveProvider( if (!isViewProvider && doesViewProvidersFactoryExist) { lInjectablesBlueprint[existingViewProvidersFactoryIndex].providerFactory = factory; } - registerDestroyHooksIfSupported(tView, provider, tInjectables.length); + registerDestroyHooksIfSupported(tView, provider, tInjectables.length, 0); tInjectables.push(token); tNode.directiveStart++; tNode.directiveEnd++; @@ -160,16 +161,19 @@ function resolveProvider( lView.push(factory); } else { // Cases 1.b and 2.b - registerDestroyHooksIfSupported( - tView, provider, existingProvidersFactoryIndex > -1 ? - existingProvidersFactoryIndex : - existingViewProvidersFactoryIndex); - multiFactoryAdd( - lInjectablesBlueprint ![isViewProvider ? existingViewProvidersFactoryIndex : existingProvidersFactoryIndex], + const indexInFactory = multiFactoryAdd( + lInjectablesBlueprint! + [isViewProvider ? existingViewProvidersFactoryIndex : + existingProvidersFactoryIndex], providerFactory, !isViewProvider && isComponent); + registerDestroyHooksIfSupported( + tView, provider, + existingProvidersFactoryIndex > -1 ? existingProvidersFactoryIndex : + existingViewProvidersFactoryIndex, + indexInFactory); } if (!isViewProvider && isComponent && doesViewProvidersFactoryExist) { - lInjectablesBlueprint[existingViewProvidersFactoryIndex].componentProviders !++; + lInjectablesBlueprint[existingViewProvidersFactoryIndex].componentProviders!++; } } } @@ -180,28 +184,47 @@ function resolveProvider( * @param tView `TView` in which to register the hook. * @param provider Provider whose hook should be registered. * @param contextIndex Index under which to find the context for the hook when it's being invoked. + * @param indexInFactory Only required for `multi` providers. Index of the provider in the multi + * provider factory. */ function registerDestroyHooksIfSupported( - tView: TView, provider: Exclude<Provider, any[]>, contextIndex: number) { + tView: TView, provider: Exclude<Provider, any[]>, contextIndex: number, + indexInFactory?: number) { const providerIsTypeProvider = isTypeProvider(provider); if (providerIsTypeProvider || isClassProvider(provider)) { const prototype = ((provider as ClassProvider).useClass || provider).prototype; const ngOnDestroy = prototype.ngOnDestroy; if (ngOnDestroy) { - (tView.destroyHooks || (tView.destroyHooks = [])).push(contextIndex, ngOnDestroy); + const hooks = tView.destroyHooks || (tView.destroyHooks = []); + + if (!providerIsTypeProvider && ((provider as ClassProvider)).multi) { + ngDevMode && + assertDefined( + indexInFactory, 'indexInFactory when registering multi factory destroy hook'); + const existingCallbacksIndex = hooks.indexOf(contextIndex); + + if (existingCallbacksIndex === -1) { + hooks.push(contextIndex, [indexInFactory, ngOnDestroy]); + } else { + (hooks[existingCallbacksIndex + 1] as DestroyHookData).push(indexInFactory!, ngOnDestroy); + } + } else { + hooks.push(contextIndex, ngOnDestroy); + } } } } /** * Add a factory in a multi factory. + * @returns Index at which the factory was inserted. */ function multiFactoryAdd( - multiFactory: NodeInjectorFactory, factory: () => any, isComponentProvider: boolean): void { - multiFactory.multi !.push(factory); + multiFactory: NodeInjectorFactory, factory: () => any, isComponentProvider: boolean): number { if (isComponentProvider) { - multiFactory.componentProviders !++; + multiFactory.componentProviders!++; } + return multiFactory.multi!.push(factory) - 1; } /** @@ -220,7 +243,7 @@ function indexOf(item: any, arr: any[], begin: number, end: number) { function multiProvidersFactoryResolver( this: NodeInjectorFactory, _: undefined, tData: TData, lData: LView, tNode: TDirectiveHostNode): any[] { - return multiResolve(this.multi !, []); + return multiResolve(this.multi!, []); } /** @@ -231,12 +254,12 @@ function multiProvidersFactoryResolver( function multiViewProvidersFactoryResolver( this: NodeInjectorFactory, _: undefined, tData: TData, lView: LView, tNode: TDirectiveHostNode): any[] { - const factories = this.multi !; + const factories = this.multi!; let result: any[]; if (this.providerFactory) { - const componentCount = this.providerFactory.componentProviders !; + const componentCount = this.providerFactory.componentProviders!; const multiProviders = - getNodeInjectable(lView, lView[TVIEW], this.providerFactory !.index !, tNode); + getNodeInjectable(lView, lView[TVIEW], this.providerFactory!.index!, tNode); // Copy the section of the array which contains `multi` `providers` from the component result = multiProviders.slice(0, componentCount); // Insert the `viewProvider` instances. @@ -258,7 +281,7 @@ function multiViewProvidersFactoryResolver( */ function multiResolve(factories: Array<() => any>, result: any[]): any[] { for (let i = 0; i < factories.length; i++) { - const factory = factories[i] !as() => null; + const factory = factories[i]! as () => null; result.push(factory()); } return result; diff --git a/packages/core/src/render3/instructions/lview_debug.ts b/packages/core/src/render3/instructions/lview_debug.ts index d2b513dc3cf06..fd3030084afce 100644 --- a/packages/core/src/render3/instructions/lview_debug.ts +++ b/packages/core/src/render3/instructions/lview_debug.ts @@ -19,9 +19,9 @@ import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18 import {PropertyAliases, TConstants, TContainerNode, TElementNode, TNode as ITNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TViewNode} from '../interfaces/node'; import {SelectorFlags} from '../interfaces/projection'; import {LQueries, TQueries} from '../interfaces/query'; -import {RComment, RElement, RNode, Renderer3, RendererFactory3} from '../interfaces/renderer'; -import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '../interfaces/styling'; -import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, ExpandoInstructions, FLAGS, HEADER_OFFSET, HOST, HookData, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, TData, TVIEW, TView as ITView, TView, TViewType, T_HOST} from '../interfaces/view'; +import {RComment, RElement, Renderer3, RendererFactory3, RNode} from '../interfaces/renderer'; +import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling'; +import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_VIEW, DestroyHookData, ExpandoInstructions, FLAGS, HEADER_OFFSET, HookData, HOST, INJECTOR, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, RENDERER_FACTORY, SANITIZER, T_HOST, TData, TVIEW, TView as ITView, TView, TViewType} from '../interfaces/view'; import {attachDebugObject} from '../util/debug_utils'; import {getLContainerActiveIndex, getTNode, unwrapRNode} from '../util/view_utils'; @@ -56,9 +56,9 @@ const NG_DEV_MODE = ((typeof ngDevMode === 'undefined' || !!ngDevMode) && initNg * ``` */ -let LVIEW_COMPONENT_CACHE !: Map<string|null, Array<any>>; -let LVIEW_EMBEDDED_CACHE !: Map<string|null, Array<any>>; -let LVIEW_ROOT !: Array<any>; +let LVIEW_COMPONENT_CACHE!: Map<string|null, Array<any>>; +let LVIEW_EMBEDDED_CACHE!: Map<string|null, Array<any>>; +let LVIEW_ROOT!: Array<any>; interface TViewDebug extends ITView { type: TViewType; @@ -75,7 +75,7 @@ export function cloneToLViewFromTViewBlueprint(tView: TView): LView { return lView.concat(tView.blueprint) as any; } -function getLViewToClone(type: TViewType, name: string | null): Array<any> { +function getLViewToClone(type: TViewType, name: string|null): Array<any> { switch (type) { case TViewType.Root: if (LVIEW_ROOT === undefined) LVIEW_ROOT = new (createNamedArrayType('LRootView'))(); @@ -100,7 +100,7 @@ function getLViewToClone(type: TViewType, name: string | null): Array<any> { throw new Error('unreachable code'); } -function nameSuffix(text: string | null | undefined): string { +function nameSuffix(text: string|null|undefined): string { if (text == null) return ''; const index = text.lastIndexOf('_Template'); return '_' + (index === -1 ? text : text.substr(0, index)); @@ -134,7 +134,7 @@ export const TViewConstructor = class TView implements ITView { public contentCheckHooks: HookData|null, // public viewHooks: HookData|null, // public viewCheckHooks: HookData|null, // - public destroyHooks: HookData|null, // + public destroyHooks: DestroyHookData|null, // public cleanup: any[]|null, // public contentQueries: number[]|null, // public components: number[]|null, // @@ -143,7 +143,7 @@ export const TViewConstructor = class TView implements ITView { public firstChild: ITNode|null, // public schemas: SchemaMetadata[]|null, // public consts: TConstants|null, // - ) {} + ) {} get template_(): string { const buf: string[] = []; @@ -183,7 +183,7 @@ class TNode implements ITNode { public residualClasses: KeyValueArray<any>|undefined|null, // public classBindings: TStylingRange, // public styleBindings: TStylingRange, // - ) {} + ) {} get type_(): string { switch (this.type) { @@ -236,8 +236,12 @@ class TNode implements ITNode { return buf.join(''); } - get styleBindings_(): DebugStyleBindings { return toDebugStyleBinding(this, false); } - get classBindings_(): DebugStyleBindings { return toDebugStyleBinding(this, true); } + get styleBindings_(): DebugStyleBindings { + return toDebugStyleBinding(this, false); + } + get classBindings_(): DebugStyleBindings { + return toDebugStyleBinding(this, true); + } } export const TNodeDebug = TNode; export type TNodeDebug = TNode; @@ -281,17 +285,16 @@ function toDebugStyleBinding(tNode: TNode, isClassBased: boolean): DebugStyleBin return bindings; } -function processTNodeChildren(tNode: ITNode | null, buf: string[]) { +function processTNodeChildren(tNode: ITNode|null, buf: string[]) { while (tNode) { - buf.push((tNode as any as{template_: string}).template_); + buf.push((tNode as any as {template_: string}).template_); tNode = tNode.next; } } -const TViewData = NG_DEV_MODE && createNamedArrayType('TViewData') || null !as ArrayConstructor; -let TVIEWDATA_EMPTY: - unknown[]; // can't initialize here or it will not be tree shaken, because `LView` - // constructor could have side-effects. +const TViewData = NG_DEV_MODE && createNamedArrayType('TViewData') || null! as ArrayConstructor; +let TVIEWDATA_EMPTY: unknown[]; // can't initialize here or it will not be tree shaken, because + // `LView` constructor could have side-effects. /** * This function clones a blueprint and creates TData. * @@ -303,21 +306,21 @@ export function cloneToTViewData(list: any[]): TData { } export const LViewBlueprint = - NG_DEV_MODE && createNamedArrayType('LViewBlueprint') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('LViewBlueprint') || null! as ArrayConstructor; export const MatchesArray = - NG_DEV_MODE && createNamedArrayType('MatchesArray') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('MatchesArray') || null! as ArrayConstructor; export const TViewComponents = - NG_DEV_MODE && createNamedArrayType('TViewComponents') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('TViewComponents') || null! as ArrayConstructor; export const TNodeLocalNames = - NG_DEV_MODE && createNamedArrayType('TNodeLocalNames') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('TNodeLocalNames') || null! as ArrayConstructor; export const TNodeInitialInputs = - NG_DEV_MODE && createNamedArrayType('TNodeInitialInputs') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('TNodeInitialInputs') || null! as ArrayConstructor; export const TNodeInitialData = - NG_DEV_MODE && createNamedArrayType('TNodeInitialData') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('TNodeInitialData') || null! as ArrayConstructor; export const LCleanup = - NG_DEV_MODE && createNamedArrayType('LCleanup') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('LCleanup') || null! as ArrayConstructor; export const TCleanup = - NG_DEV_MODE && createNamedArrayType('TCleanup') || null !as ArrayConstructor; + NG_DEV_MODE && createNamedArrayType('TCleanup') || null! as ArrayConstructor; @@ -330,8 +333,8 @@ export function attachLContainerDebug(lContainer: LContainer) { } export function toDebug(obj: LView): LViewDebug; -export function toDebug(obj: LView | null): LViewDebug|null; -export function toDebug(obj: LView | LContainer | null): LViewDebug|LContainerDebug|null; +export function toDebug(obj: LView|null): LViewDebug|null; +export function toDebug(obj: LView|LContainer|null): LViewDebug|LContainerDebug|null; export function toDebug(obj: any): any { if (obj) { const debug = (obj as any).debug; @@ -390,10 +393,18 @@ export class LViewDebug { indexWithinInitPhase: flags >> LViewFlags.IndexWithinInitPhaseShift, }; } - get parent(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[PARENT]); } - get host(): string|null { return toHtml(this._raw_lView[HOST], true); } - get html(): string { return (this.nodes || []).map(node => toHtml(node.native, true)).join(''); } - get context(): {}|null { return this._raw_lView[CONTEXT]; } + get parent(): LViewDebug|LContainerDebug|null { + return toDebug(this._raw_lView[PARENT]); + } + get host(): string|null { + return toHtml(this._raw_lView[HOST], true); + } + get html(): string { + return (this.nodes || []).map(node => toHtml(node.native, true)).join(''); + } + get context(): {}|null { + return this._raw_lView[CONTEXT]; + } /** * The tree of nodes associated with the current `LView`. The nodes have been normalized into * a @@ -405,18 +416,42 @@ export class LViewDebug { return toDebugNodes(tNode, lView); } - get tView(): ITView { return this._raw_lView[TVIEW]; } - get cleanup(): any[]|null { return this._raw_lView[CLEANUP]; } - get injector(): Injector|null { return this._raw_lView[INJECTOR]; } - get rendererFactory(): RendererFactory3 { return this._raw_lView[RENDERER_FACTORY]; } - get renderer(): Renderer3 { return this._raw_lView[RENDERER]; } - get sanitizer(): Sanitizer|null { return this._raw_lView[SANITIZER]; } - get childHead(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[CHILD_HEAD]); } - get next(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[NEXT]); } - get childTail(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lView[CHILD_TAIL]); } - get declarationView(): LViewDebug|null { return toDebug(this._raw_lView[DECLARATION_VIEW]); } - get queries(): LQueries|null { return this._raw_lView[QUERIES]; } - get tHost(): TViewNode|TElementNode|null { return this._raw_lView[T_HOST]; } + get tView(): ITView { + return this._raw_lView[TVIEW]; + } + get cleanup(): any[]|null { + return this._raw_lView[CLEANUP]; + } + get injector(): Injector|null { + return this._raw_lView[INJECTOR]; + } + get rendererFactory(): RendererFactory3 { + return this._raw_lView[RENDERER_FACTORY]; + } + get renderer(): Renderer3 { + return this._raw_lView[RENDERER]; + } + get sanitizer(): Sanitizer|null { + return this._raw_lView[SANITIZER]; + } + get childHead(): LViewDebug|LContainerDebug|null { + return toDebug(this._raw_lView[CHILD_HEAD]); + } + get next(): LViewDebug|LContainerDebug|null { + return toDebug(this._raw_lView[NEXT]); + } + get childTail(): LViewDebug|LContainerDebug|null { + return toDebug(this._raw_lView[CHILD_TAIL]); + } + get declarationView(): LViewDebug|null { + return toDebug(this._raw_lView[DECLARATION_VIEW]); + } + get queries(): LQueries|null { + return this._raw_lView[QUERIES]; + } + get tHost(): TViewNode|TElementNode|null { + return this._raw_lView[T_HOST]; + } /** * Normalized view of child views (and containers) attached at this location. @@ -445,7 +480,7 @@ export interface DebugNode { * @param tNode * @param lView */ -export function toDebugNodes(tNode: ITNode | null, lView: LView): DebugNode[]|null { +export function toDebugNodes(tNode: ITNode|null, lView: LView): DebugNode[]|null { if (tNode) { const debugNodes: DebugNode[] = []; let tNodeCursor: ITNode|null = tNode; @@ -474,20 +509,32 @@ export function buildDebugNode(tNode: ITNode, lView: LView, nodeIndex: number): export class LContainerDebug { constructor(private readonly _raw_lContainer: LContainer) {} - get activeIndex(): number { return getLContainerActiveIndex(this._raw_lContainer); } + get activeIndex(): number { + return getLContainerActiveIndex(this._raw_lContainer); + } get hasTransplantedViews(): boolean { return (this._raw_lContainer[ACTIVE_INDEX] & ActiveIndexFlag.HAS_TRANSPLANTED_VIEWS) === ActiveIndexFlag.HAS_TRANSPLANTED_VIEWS; } get views(): LViewDebug[] { return this._raw_lContainer.slice(CONTAINER_HEADER_OFFSET) - .map(toDebug as(l: LView) => LViewDebug); + .map(toDebug as (l: LView) => LViewDebug); + } + get parent(): LViewDebug|LContainerDebug|null { + return toDebug(this._raw_lContainer[PARENT]); + } + get movedViews(): LView[]|null { + return this._raw_lContainer[MOVED_VIEWS]; + } + get host(): RElement|RComment|LView { + return this._raw_lContainer[HOST]; + } + get native(): RComment { + return this._raw_lContainer[NATIVE]; + } + get next() { + return toDebug(this._raw_lContainer[NEXT]); } - get parent(): LViewDebug|LContainerDebug|null { return toDebug(this._raw_lContainer[PARENT]); } - get movedViews(): LView[]|null { return this._raw_lContainer[MOVED_VIEWS]; } - get host(): RElement|RComment|LView { return this._raw_lContainer[HOST]; } - get native(): RComment { return this._raw_lContainer[NATIVE]; } - get next() { return toDebug(this._raw_lContainer[NEXT]); } } /** @@ -508,7 +555,9 @@ export function readLViewValue(value: any): LView|null { export class I18NDebugItem { [key: string]: any; - get tNode() { return getTNode(this._lView[TVIEW], this.nodeIndex); } + get tNode() { + return getTNode(this._lView[TVIEW], this.nodeIndex); + } constructor( public __raw_opCode: any, private _lView: LView, public nodeIndex: number, @@ -524,15 +573,16 @@ export class I18NDebugItem { * @param lView The view the opCodes are acting on */ export function attachI18nOpCodesDebug( - mutateOpCodes: I18nMutateOpCodes, updateOpCodes: I18nUpdateOpCodes, icus: TIcu[] | null, + mutateOpCodes: I18nMutateOpCodes, updateOpCodes: I18nUpdateOpCodes, icus: TIcu[]|null, lView: LView) { attachDebugObject(mutateOpCodes, new I18nMutateOpCodesDebug(mutateOpCodes, lView)); attachDebugObject(updateOpCodes, new I18nUpdateOpCodesDebug(updateOpCodes, icus, lView)); if (icus) { icus.forEach(icu => { - icu.create.forEach( - icuCase => { attachDebugObject(icuCase, new I18nMutateOpCodesDebug(icuCase, lView)); }); + icu.create.forEach(icuCase => { + attachDebugObject(icuCase, new I18nMutateOpCodesDebug(icuCase, lView)); + }); icu.update.forEach(icuCase => { attachDebugObject(icuCase, new I18nUpdateOpCodesDebug(icuCase, icus, lView)); }); @@ -645,7 +695,7 @@ export class I18nUpdateOpCodesDebug implements I18nOpCodesDebug { if (opCode < 0) { // It's a binding index whose value is negative // We cannot know the value of the binding so we only show the index - value += `�${-opCode - 1}�`; + value += `�${- opCode - 1}�`; } else { const nodeIndex = opCode >>> I18nUpdateOpCode.SHIFT_REF; let tIcuIndex: number; @@ -658,20 +708,23 @@ export class I18nUpdateOpCodesDebug implements I18nOpCodesDebug { __raw_opCode: opCode, checkBit, type: 'Attr', - attrValue: value, attrName, sanitizeFn, + attrValue: value, + attrName, + sanitizeFn, }); break; case I18nUpdateOpCode.Text: results.push({ __raw_opCode: opCode, checkBit, - type: 'Text', nodeIndex, + type: 'Text', + nodeIndex, text: value, }); break; case I18nUpdateOpCode.IcuSwitch: tIcuIndex = __raw_opCodes[++j] as number; - tIcu = icus ![tIcuIndex]; + tIcu = icus![tIcuIndex]; let result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuSwitch'); result['tIcuIndex'] = tIcuIndex; result['checkBit'] = checkBit; @@ -681,7 +734,7 @@ export class I18nUpdateOpCodesDebug implements I18nOpCodesDebug { break; case I18nUpdateOpCode.IcuUpdate: tIcuIndex = __raw_opCodes[++j] as number; - tIcu = icus ![tIcuIndex]; + tIcu = icus![tIcuIndex]; result = new I18NDebugItem(opCode, __lView, nodeIndex, 'IcuUpdate'); result['tIcuIndex'] = tIcuIndex; result['checkBit'] = checkBit; @@ -698,4 +751,6 @@ export class I18nUpdateOpCodesDebug implements I18nOpCodesDebug { } } -export interface I18nOpCodesDebug { operations: any[]; } +export interface I18nOpCodesDebug { + operations: any[]; +} diff --git a/packages/core/src/render3/instructions/shared.ts b/packages/core/src/render3/instructions/shared.ts index 5c07128a5688a..deedddd0cc010 100644 --- a/packages/core/src/render3/instructions/shared.ts +++ b/packages/core/src/render3/instructions/shared.ts @@ -24,11 +24,11 @@ import {executeCheckHooks, executeInitAndCheckHooks, incrementInitPhaseFlags} fr import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS} from '../interfaces/container'; import {ComponentDef, ComponentTemplate, DirectiveDef, DirectiveDefListOrFactory, PipeDefListOrFactory, RenderFlags, ViewQueriesFunction} from '../interfaces/definition'; import {INJECTOR_BLOOM_PARENT_SIZE, NodeInjectorFactory} from '../interfaces/injector'; -import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliasValue, PropertyAliases, TAttributes, TConstants, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node'; -import {RComment, RElement, RNode, RText, Renderer3, RendererFactory3, isProceduralRenderer} from '../interfaces/renderer'; +import {AttributeMarker, InitialInputData, InitialInputs, LocalRefExtractor, PropertyAliases, PropertyAliasValue, TAttributes, TConstants, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeProviderIndexes, TNodeType, TProjectionNode, TViewNode} from '../interfaces/node'; +import {isProceduralRenderer, RComment, RElement, Renderer3, RendererFactory3, RNode, RText} from '../interfaces/renderer'; import {SanitizerFn} from '../interfaces/sanitization'; import {isComponentDef, isComponentHost, isContentQueryHost, isLContainer, isRootView} from '../interfaces/type_checks'; -import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, INJECTOR, InitPhaseState, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, TData, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; +import {CHILD_HEAD, CHILD_TAIL, CLEANUP, CONTEXT, DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, FLAGS, HEADER_OFFSET, HOST, InitPhaseState, INJECTOR, LView, LViewFlags, NEXT, PARENT, RENDERER, RENDERER_FACTORY, RootContext, RootContextFlags, SANITIZER, T_HOST, TData, TVIEW, TView, TViewType} from '../interfaces/view'; import {assertNodeOfPossibleTypes} from '../node_assert'; import {isNodeMatchingSelectorList} from '../node_selector_matcher'; import {enterView, getBindingsEnabled, getCheckNoChangesMode, getIsParent, getPreviousOrParentTNode, getSelectedIndex, getTView, leaveView, setBindingIndex, setBindingRootForHostBindings, setCheckNoChangesMode, setCurrentQueryIndex, setPreviousOrParentTNode, setSelectedIndex} from '../state'; @@ -39,7 +39,7 @@ import {getLViewParent} from '../util/view_traversal_utils'; import {getComponentLViewByIndex, getNativeByIndex, getNativeByTNode, getTNode, isCreationMode, readPatchedLView, resetPreOrderHookFlags, unwrapLView, viewAttachedToChangeDetector} from '../util/view_utils'; import {selectIndexInternal} from './advance'; -import {LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeDebug, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor, attachLContainerDebug, attachLViewDebug, cloneToLViewFromTViewBlueprint, cloneToTViewData} from './lview_debug'; +import {attachLContainerDebug, attachLViewDebug, cloneToLViewFromTViewBlueprint, cloneToTViewData, LCleanup, LViewBlueprint, MatchesArray, TCleanup, TNodeDebug, TNodeInitialInputs, TNodeLocalNames, TViewComponents, TViewConstructor} from './lview_debug'; @@ -129,7 +129,7 @@ function refreshContentQueries(tView: TView, lView: LView): void { ngDevMode && assertDefined(directiveDef.contentQueries, 'contentQueries function should be defined'); setCurrentQueryIndex(queryStartIdx); - directiveDef.contentQueries !(RenderFlags.Update, lView[directiveDefIdx], directiveDefIdx); + directiveDef.contentQueries!(RenderFlags.Update, lView[directiveDefIdx], directiveDefIdx); } } } @@ -155,8 +155,7 @@ function renderChildComponents(hostLView: LView, components: number[]): void { * @param renderer A renderer to use * @returns the element created */ -export function elementCreate( - name: string, renderer: Renderer3, namespace: string | null): RElement { +export function elementCreate(name: string, renderer: Renderer3, namespace: string|null): RElement { if (isProceduralRenderer(renderer)) { return renderer.createElement(name, namespace); } else { @@ -166,10 +165,9 @@ export function elementCreate( } export function createLView<T>( - parentLView: LView | null, tView: TView, context: T | null, flags: LViewFlags, - host: RElement | null, tHostNode: TViewNode | TElementNode | null, - rendererFactory?: RendererFactory3 | null, renderer?: Renderer3 | null, - sanitizer?: Sanitizer | null, injector?: Injector | null): LView { + parentLView: LView|null, tView: TView, context: T|null, flags: LViewFlags, host: RElement|null, + tHostNode: TViewNode|TElementNode|null, rendererFactory?: RendererFactory3|null, + renderer?: Renderer3|null, sanitizer?: Sanitizer|null, injector?: Injector|null): LView { const lView = ngDevMode ? cloneToLViewFromTViewBlueprint(tView) : tView.blueprint.slice() as LView; lView[HOST] = host; @@ -177,18 +175,19 @@ export function createLView<T>( resetPreOrderHookFlags(lView); lView[PARENT] = lView[DECLARATION_VIEW] = parentLView; lView[CONTEXT] = context; - lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY]) !; + lView[RENDERER_FACTORY] = (rendererFactory || parentLView && parentLView[RENDERER_FACTORY])!; ngDevMode && assertDefined(lView[RENDERER_FACTORY], 'RendererFactory is required'); - lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER]) !; + lView[RENDERER] = (renderer || parentLView && parentLView[RENDERER])!; ngDevMode && assertDefined(lView[RENDERER], 'Renderer is required'); - lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null !; + lView[SANITIZER] = sanitizer || parentLView && parentLView[SANITIZER] || null!; lView[INJECTOR as any] = injector || parentLView && parentLView[INJECTOR] || null; lView[T_HOST] = tHostNode; - ngDevMode && assertEqual( - tView.type == TViewType.Embedded ? parentLView !== null : true, true, - 'Embedded views must have parentLView'); + ngDevMode && + assertEqual( + tView.type == TViewType.Embedded ? parentLView !== null : true, true, + 'Embedded views must have parentLView'); lView[DECLARATION_COMPONENT_VIEW] = - tView.type == TViewType.Embedded ? parentLView ![DECLARATION_COMPONENT_VIEW] : lView; + tView.type == TViewType.Embedded ? parentLView![DECLARATION_COMPONENT_VIEW] : lView; ngDevMode && attachLViewDebug(lView); return lView; } @@ -208,23 +207,23 @@ export function createLView<T>( * @param attrs Any attrs for the native element, if applicable */ export function getOrCreateTNode( - tView: TView, tHostNode: TNode | null, index: number, type: TNodeType.Element, - name: string | null, attrs: TAttributes | null): TElementNode; + tView: TView, tHostNode: TNode|null, index: number, type: TNodeType.Element, name: string|null, + attrs: TAttributes|null): TElementNode; export function getOrCreateTNode( - tView: TView, tHostNode: TNode | null, index: number, type: TNodeType.Container, - name: string | null, attrs: TAttributes | null): TContainerNode; + tView: TView, tHostNode: TNode|null, index: number, type: TNodeType.Container, + name: string|null, attrs: TAttributes|null): TContainerNode; export function getOrCreateTNode( - tView: TView, tHostNode: TNode | null, index: number, type: TNodeType.Projection, name: null, - attrs: TAttributes | null): TProjectionNode; + tView: TView, tHostNode: TNode|null, index: number, type: TNodeType.Projection, name: null, + attrs: TAttributes|null): TProjectionNode; export function getOrCreateTNode( - tView: TView, tHostNode: TNode | null, index: number, type: TNodeType.ElementContainer, - name: string | null, attrs: TAttributes | null): TElementContainerNode; + tView: TView, tHostNode: TNode|null, index: number, type: TNodeType.ElementContainer, + name: string|null, attrs: TAttributes|null): TElementContainerNode; export function getOrCreateTNode( - tView: TView, tHostNode: TNode | null, index: number, type: TNodeType.IcuContainer, name: null, - attrs: TAttributes | null): TElementContainerNode; + tView: TView, tHostNode: TNode|null, index: number, type: TNodeType.IcuContainer, name: null, + attrs: TAttributes|null): TElementContainerNode; export function getOrCreateTNode( - tView: TView, tHostNode: TNode | null, index: number, type: TNodeType, name: string | null, - attrs: TAttributes | null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode& + tView: TView, tHostNode: TNode|null, index: number, type: TNodeType, name: string|null, + attrs: TAttributes|null): TElementNode&TContainerNode&TElementContainerNode&TProjectionNode& TIcuContainerNode { // Keep this function short, so that the VM will inline it. const adjustedIndex = index + HEADER_OFFSET; @@ -236,8 +235,8 @@ export function getOrCreateTNode( } function createTNodeAtIndex( - tView: TView, tHostNode: TNode | null, adjustedIndex: number, type: TNodeType, - name: string | null, attrs: TAttributes | null) { + tView: TView, tHostNode: TNode|null, adjustedIndex: number, type: TNodeType, name: string|null, + attrs: TAttributes|null) { const previousOrParentTNode = getPreviousOrParentTNode(); const isParent = getIsParent(); const parent = @@ -267,7 +266,7 @@ function createTNodeAtIndex( } export function assignTViewNodeToLView( - tView: TView, tParentNode: TNode | null, index: number, lView: LView): TViewNode { + tView: TView, tParentNode: TNode|null, index: number, lView: LView): TViewNode { // View nodes are not stored in data because they can be added / removed at runtime (which // would cause indices to change). Their TNodes are instead stored in tView.node. let tNode = tView.node; @@ -275,9 +274,9 @@ export function assignTViewNodeToLView( ngDevMode && tParentNode && assertNodeOfPossibleTypes(tParentNode, TNodeType.Element, TNodeType.Container); tView.node = tNode = createTNode( - tView, - tParentNode as TElementNode | TContainerNode | null, // - TNodeType.View, index, null, null) as TViewNode; + tView, + tParentNode as TElementNode | TContainerNode | null, // + TNodeType.View, index, null, null) as TViewNode; } return lView[T_HOST] = tNode as TViewNode; @@ -294,8 +293,9 @@ export function assignTViewNodeToLView( * @param numSlotsToAlloc The number of slots to alloc in the LView, should be >0 */ export function allocExpando(tView: TView, lView: LView, numSlotsToAlloc: number) { - ngDevMode && assertGreaterThan( - numSlotsToAlloc, 0, 'The number of slots to alloc should be greater than 0'); + ngDevMode && + assertGreaterThan( + numSlotsToAlloc, 0, 'The number of slots to alloc should be greater than 0'); if (numSlotsToAlloc > 0) { if (tView.firstCreatePass) { for (let i = 0; i < numSlotsToAlloc; i++) { @@ -365,7 +365,7 @@ export function renderView<T>(tView: TView, lView: LView, context: T): void { // in case a child component has projected a container. The LContainer needs // to exist so the embedded views are properly attached by the container. if (tView.staticViewQueries) { - executeViewQueryFn(RenderFlags.Update, tView.viewQuery !, context); + executeViewQueryFn(RenderFlags.Update, tView.viewQuery!, context); } // Render child component views. @@ -389,7 +389,7 @@ export function renderView<T>(tView: TView, lView: LView, context: T): void { * - refreshing child (embedded and component) views. */ export function refreshView<T>( - tView: TView, lView: LView, templateFn: ComponentTemplate<{}>| null, context: T) { + tView: TView, lView: LView, templateFn: ComponentTemplate<{}>|null, context: T) { ngDevMode && assertEqual(isCreationMode(lView), false, 'Should be run in update mode'); const flags = lView[FLAGS]; if ((flags & LViewFlags.Destroyed) === LViewFlags.Destroyed) return; @@ -505,7 +505,7 @@ export function refreshView<T>( } export function renderComponentOrTemplate<T>( - tView: TView, lView: LView, templateFn: ComponentTemplate<{}>| null, context: T) { + tView: TView, lView: LView, templateFn: ComponentTemplate<{}>|null, context: T) { const rendererFactory = lView[RENDERER_FACTORY]; const normalExecutionPath = !getCheckNoChangesMode(); const creationModeIsActive = isCreationMode(lView); @@ -618,10 +618,10 @@ export function getOrCreateTComponentView(def: ComponentDef<any>): TView { * @param consts Constants for this view */ export function createTView( - type: TViewType, viewIndex: number, templateFn: ComponentTemplate<any>| null, decls: number, - vars: number, directives: DirectiveDefListOrFactory | null, pipes: PipeDefListOrFactory | null, - viewQuery: ViewQueriesFunction<any>| null, schemas: SchemaMetadata[] | null, - consts: TConstants | null): TView { + type: TViewType, viewIndex: number, templateFn: ComponentTemplate<any>|null, decls: number, + vars: number, directives: DirectiveDefListOrFactory|null, pipes: PipeDefListOrFactory|null, + viewQuery: ViewQueriesFunction<any>|null, schemas: SchemaMetadata[]|null, + consts: TConstants|null): TView { ngDevMode && ngDevMode.tView++; const bindingStartIndex = HEADER_OFFSET + decls; // This length does not yet contain host bindings from child directives because at this point, @@ -637,7 +637,7 @@ export function createTView( templateFn, // template: ComponentTemplate<{}>|null, null, // queries: TQueries|null viewQuery, // viewQuery: ViewQueriesFunction<{}>|null, - null !, // node: TViewNode|TElementNode|null, + null!, // node: TViewNode|TElementNode|null, cloneToTViewData(blueprint).fill(null, bindingStartIndex), // data: TData, bindingStartIndex, // bindingStartIndex: number, initialViewLength, // expandoStartIndex: number, @@ -652,7 +652,7 @@ export function createTView( null, // contentCheckHooks: HookData|null, null, // viewHooks: HookData|null, null, // viewCheckHooks: HookData|null, - null, // destroyHooks: HookData|null, + null, // destroyHooks: DestroyHookData|null, null, // cleanup: any[]|null, null, // contentQueries: number[]|null, null, // components: number[]|null, @@ -670,7 +670,7 @@ export function createTView( template: templateFn, queries: null, viewQuery: viewQuery, - node: null !, + node: null!, data: blueprint.slice().fill(null, bindingStartIndex), bindingStartIndex: bindingStartIndex, expandoStartIndex: initialViewLength, @@ -711,7 +711,7 @@ function createError(text: string, token: any) { return new Error(`Renderer: ${text} [${stringifyForError(token)}]`); } -function assertHostNodeExists(rElement: RElement, elementOrSelector: RElement | string) { +function assertHostNodeExists(rElement: RElement, elementOrSelector: RElement|string) { if (!rElement) { if (typeof elementOrSelector === 'string') { throw createError('Host node with selector not found:', elementOrSelector); @@ -729,7 +729,7 @@ function assertHostNodeExists(rElement: RElement, elementOrSelector: RElement | * @param encapsulation View Encapsulation defined for component that requests host element. */ export function locateHostElement( - renderer: Renderer3, elementOrSelector: RElement | string, + renderer: Renderer3, elementOrSelector: RElement|string, encapsulation: ViewEncapsulation): RElement { if (isProceduralRenderer(renderer)) { // When using native Shadow DOM, do not clear host element to allow native slot projection @@ -738,7 +738,7 @@ export function locateHostElement( } let rElement = typeof elementOrSelector === 'string' ? - renderer.querySelector(elementOrSelector) ! : + renderer.querySelector(elementOrSelector)! : elementOrSelector; ngDevMode && assertHostNodeExists(rElement, elementOrSelector); @@ -780,7 +780,7 @@ export function storeCleanupFn(tView: TView, lView: LView, cleanupFn: Function): getLCleanup(lView).push(cleanupFn); if (tView.firstCreatePass) { - getTViewCleanup(tView).push(lView[CLEANUP] !.length - 1, null); + getTViewCleanup(tView).push(lView[CLEANUP]!.length - 1, null); } } @@ -796,8 +796,8 @@ export function storeCleanupFn(tView: TView, lView: LView, cleanupFn: Function): * @returns the TNode object */ export function createTNode( - tView: TView, tParent: TElementNode | TContainerNode | null, type: TNodeType, - adjustedIndex: number, tagName: string | null, attrs: TAttributes | null): TNode { + tView: TView, tParent: TElementNode|TContainerNode|null, type: TNodeType, adjustedIndex: number, + tagName: string|null, attrs: TAttributes|null): TNode { ngDevMode && ngDevMode.tNode++; let injectorIndex = tParent ? tParent.injectorIndex : -1; return ngDevMode ? new TNodeDebug( @@ -866,7 +866,7 @@ export function createTNode( function generatePropertyAliases( inputAliasMap: {[publicName: string]: string}, directiveDefIdx: number, - propStore: PropertyAliases | null): PropertyAliases|null { + propStore: PropertyAliases|null): PropertyAliases|null { for (let publicName in inputAliasMap) { if (inputAliasMap.hasOwnProperty(publicName)) { propStore = propStore === null ? {} : propStore; @@ -942,7 +942,7 @@ function mapPropName(name: string): string { export function elementPropertyInternal<T>( tView: TView, tNode: TNode, lView: LView, propName: string, value: T, renderer: Renderer3, - sanitizer: SanitizerFn | null | undefined, nativeOnly: boolean): void { + sanitizer: SanitizerFn|null|undefined, nativeOnly: boolean): void { ngDevMode && assertNotSame(value, NO_CHANGE as any, 'Incoming value should never be NO_CHANGE.'); const element = getNativeByTNode(tNode, lView) as RElement | RComment; let inputData = tNode.inputs; @@ -994,7 +994,7 @@ function markDirtyIfOnPush(lView: LView, viewIndex: number): void { } function setNgReflectProperty( - lView: LView, element: RElement | RComment, type: TNodeType, attrName: string, value: any) { + lView: LView, element: RElement|RComment, type: TNodeType, attrName: string, value: any) { const renderer = lView[RENDERER]; attrName = normalizeDebugBindingName(attrName); const debugValue = normalizeDebugBindingValue(value); @@ -1018,7 +1018,7 @@ function setNgReflectProperty( } export function setNgReflectProperties( - lView: LView, element: RElement | RComment, type: TNodeType, dataValue: PropertyAliasValue, + lView: LView, element: RElement|RComment, type: TNodeType, dataValue: PropertyAliasValue, value: any) { if (type === TNodeType.Element || type === TNodeType.Container) { /** @@ -1036,7 +1036,7 @@ export function setNgReflectProperties( } function validateProperty( - tView: TView, lView: LView, element: RElement | RComment, propName: string, + tView: TView, lView: LView, element: RElement|RComment, propName: string, tNode: TNode): boolean { // The property is considered valid if the element matches the schema, it exists on the element // or it is synthetic, and we are in a browser context (web worker nodes should be skipped). @@ -1050,7 +1050,7 @@ function validateProperty( return typeof Node === 'undefined' || Node === null || !(element instanceof Node); } -export function matchingSchemas(tView: TView, lView: LView, tagName: string | null): boolean { +export function matchingSchemas(tView: TView, lView: LView, tagName: string|null): boolean { const schemas = tView.schemas; if (schemas !== null) { @@ -1099,8 +1099,8 @@ export function instantiateRootComponent<T>(tView: TView, lView: LView, def: Com * Resolve the matched directives on a node. */ export function resolveDirectives( - tView: TView, lView: LView, tNode: TElementNode | TContainerNode | TElementContainerNode, - localRefs: string[] | null): boolean { + tView: TView, lView: LView, tNode: TElementNode|TContainerNode|TElementContainerNode, + localRefs: string[]|null): boolean { // Please make sure to have explicit type for `exportsMap`. Inferred type triggers bug in // tsickle. ngDevMode && assertFirstCreatePass(tView); @@ -1108,7 +1108,7 @@ export function resolveDirectives( let hasDirectives = false; if (getBindingsEnabled()) { const directiveDefs: DirectiveDef<any>[]|null = findDirectiveDefMatches(tView, lView, tNode); - const exportsMap: ({[key: string]: number} | null) = localRefs === null ? null : {'': -1}; + const exportsMap: ({[key: string]: number}|null) = localRefs === null ? null : {'': -1}; if (directiveDefs !== null) { let totalDirectiveHostVars = 0; @@ -1135,7 +1135,7 @@ export function resolveDirectives( baseResolveDirective(tView, lView, def); - saveNameToExportMap(tView.data !.length - 1, def, exportsMap); + saveNameToExportMap(tView.data!.length - 1, def, exportsMap); if (def.contentQueries !== null) tNode.flags |= TNodeFlags.hasContentQuery; if (def.hostBindings !== null || def.hostAttrs !== null || def.hostVars !== 0) @@ -1152,8 +1152,8 @@ export function resolveDirectives( } if (!preOrderCheckHooksFound && (def.onChanges || def.doCheck)) { - (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [ - ])).push(tNode.index - HEADER_OFFSET); + (tView.preOrderCheckHooks || (tView.preOrderCheckHooks = [])) + .push(tNode.index - HEADER_OFFSET); preOrderCheckHooksFound = true; } @@ -1178,9 +1178,9 @@ export function resolveDirectives( * @param def `ComponentDef`/`DirectiveDef`, which contains the `hostVars`/`hostBindings` to add. */ export function addHostBindingsToExpandoInstructions( - tView: TView, def: ComponentDef<any>| DirectiveDef<any>): void { + tView: TView, def: ComponentDef<any>|DirectiveDef<any>): void { ngDevMode && assertFirstCreatePass(tView); - const expando = tView.expandoInstructions !; + const expando = tView.expandoInstructions!; // TODO(misko): PERF we are adding `hostBindings` even if there is nothing to add! This is // suboptimal for performance. `def.hostBindings` may be null, // but we still need to push null to the array as a placeholder @@ -1244,7 +1244,7 @@ function instantiateAllDirectives( attachPatchData(directive, lView); if (initialInputs !== null) { - setInputsFromAttrs(lView, i - start, directive, def, tNode, initialInputs !); + setInputsFromAttrs(lView, i - start, directive, def, tNode, initialInputs!); } if (isComponent) { @@ -1257,7 +1257,7 @@ function instantiateAllDirectives( function invokeDirectivesHostBindings(tView: TView, lView: LView, tNode: TNode) { const start = tNode.directiveStart; const end = tNode.directiveEnd; - const expando = tView.expandoInstructions !; + const expando = tView.expandoInstructions!; const firstCreatePass = tView.firstCreatePass; const elementIndex = tNode.index - HEADER_OFFSET; try { @@ -1284,7 +1284,7 @@ function invokeDirectivesHostBindings(tView: TView, lView: LView, tNode: TNode) */ export function invokeHostBindingsInCreationMode(def: DirectiveDef<any>, directive: any) { if (def.hostBindings !== null) { - def.hostBindings !(RenderFlags.Create, directive); + def.hostBindings!(RenderFlags.Create, directive); } } @@ -1296,9 +1296,10 @@ export function invokeHostBindingsInCreationMode(def: DirectiveDef<any>, directi */ export function generateExpandoInstructionBlock( tView: TView, tNode: TNode, directiveCount: number): void { - ngDevMode && assertEqual( - tView.firstCreatePass, true, - 'Expando block should only be generated on first create pass.'); + ngDevMode && + assertEqual( + tView.firstCreatePass, true, + 'Expando block should only be generated on first create pass.'); // Important: In JS `-x` and `0-x` is not the same! If `x===0` then `-x` will produce `-0` which // requires non standard math arithmetic and it can prevent VM optimizations. @@ -1306,26 +1307,27 @@ export function generateExpandoInstructionBlock( const elementIndex = HEADER_OFFSET - tNode.index; const providerStartIndex = tNode.providerIndexes & TNodeProviderIndexes.ProvidersStartIndexMask; const providerCount = tView.data.length - providerStartIndex; - (tView.expandoInstructions || (tView.expandoInstructions = [ - ])).push(elementIndex, providerCount, directiveCount); + (tView.expandoInstructions || (tView.expandoInstructions = [])) + .push(elementIndex, providerCount, directiveCount); } /** -* Matches the current node against all available selectors. -* If a component is matched (at most one), it is returned in first position in the array. -*/ + * Matches the current node against all available selectors. + * If a component is matched (at most one), it is returned in first position in the array. + */ function findDirectiveDefMatches( tView: TView, viewData: LView, - tNode: TElementNode | TContainerNode | TElementContainerNode): DirectiveDef<any>[]|null { + tNode: TElementNode|TContainerNode|TElementContainerNode): DirectiveDef<any>[]|null { ngDevMode && assertFirstCreatePass(tView); - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Element, TNodeType.ElementContainer, TNodeType.Container); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Element, TNodeType.ElementContainer, TNodeType.Container); const registry = tView.directiveRegistry; let matches: any[]|null = null; if (registry) { for (let i = 0; i < registry.length; i++) { const def = registry[i] as ComponentDef<any>| DirectiveDef<any>; - if (isNodeMatchingSelectorList(tNode, def.selectors !, /* isProjectionMode */ false)) { + if (isNodeMatchingSelectorList(tNode, def.selectors!, /* isProjectionMode */ false)) { matches || (matches = ngDevMode ? new MatchesArray() : []); diPublicInInjector(getOrCreateNodeInjectorForNode(tNode, viewData), tView, def.type); @@ -1347,21 +1349,20 @@ function findDirectiveDefMatches( * Marks a given TNode as a component's host. This consists of: * - setting appropriate TNode flags; * - storing index of component's host element so it will be queued for view refresh during CD. -*/ + */ export function markAsComponentHost(tView: TView, hostTNode: TNode): void { ngDevMode && assertFirstCreatePass(tView); hostTNode.flags |= TNodeFlags.isComponentHost; - (tView.components || (tView.components = ngDevMode ? new TViewComponents() : [ - ])).push(hostTNode.index); + (tView.components || (tView.components = ngDevMode ? new TViewComponents() : [])) + .push(hostTNode.index); } /** Caches local names and their matching directive indices for query and template lookups. */ function cacheMatchingLocalNames( - tNode: TNode, localRefs: string[] | null, exportsMap: {[key: string]: number}): void { + tNode: TNode, localRefs: string[]|null, exportsMap: {[key: string]: number}): void { if (localRefs) { - const localNames: (string | number)[] = tNode.localNames = - ngDevMode ? new TNodeLocalNames() : []; + const localNames: (string|number)[] = tNode.localNames = ngDevMode ? new TNodeLocalNames() : []; // Local names must be stored in tNode in the same order that localRefs are defined // in the template to ensure the data is loaded in the same slots as their refs @@ -1375,12 +1376,12 @@ function cacheMatchingLocalNames( } /** -* Builds up an export map as directives are created, so local refs can be quickly mapped -* to their directive instances. -*/ + * Builds up an export map as directives are created, so local refs can be quickly mapped + * to their directive instances. + */ function saveNameToExportMap( - index: number, def: DirectiveDef<any>| ComponentDef<any>, - exportsMap: {[key: string]: number} | null) { + index: number, def: DirectiveDef<any>|ComponentDef<any>, + exportsMap: {[key: string]: number}|null) { if (exportsMap) { if (def.exportAs) { for (let i = 0; i < def.exportAs.length; i++) { @@ -1397,9 +1398,10 @@ function saveNameToExportMap( * @param index the initial index */ export function initTNodeFlags(tNode: TNode, index: number, numberOfDirectives: number) { - ngDevMode && assertNotEqual( - numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, - 'Reached the max number of directives'); + ngDevMode && + assertNotEqual( + numberOfDirectives, tNode.directiveEnd - tNode.directiveStart, + 'Reached the max number of directives'); tNode.flags |= TNodeFlags.isDirectiveHost; // When the first directive is created on a node, save the index tNode.directiveStart = index; @@ -1410,7 +1412,7 @@ export function initTNodeFlags(tNode: TNode, index: number, numberOfDirectives: function baseResolveDirective<T>(tView: TView, viewData: LView, def: DirectiveDef<T>) { tView.data.push(def); const directiveFactory = - def.factory || ((def as{factory: Function}).factory = getFactoryDef(def.type, true)); + def.factory || ((def as {factory: Function}).factory = getFactoryDef(def.type, true)); const nodeInjectorFactory = new NodeInjectorFactory(directiveFactory, isComponentDef(def), null); tView.blueprint.push(nodeInjectorFactory); viewData.push(nodeInjectorFactory); @@ -1435,8 +1437,8 @@ function addComponentLogic<T>(lView: LView, hostTNode: TElementNode, def: Compon } export function elementAttributeInternal( - tNode: TNode, lView: LView, name: string, value: any, sanitizer: SanitizerFn | null | undefined, - namespace: string | null | undefined) { + tNode: TNode, lView: LView, name: string, value: any, sanitizer: SanitizerFn|null|undefined, + namespace: string|null|undefined) { ngDevMode && assertNotSame(value, NO_CHANGE as any, 'Incoming value should never be NO_CHANGE.'); ngDevMode && validateAgainstEventAttributes(name); const element = getNativeByTNode(tNode, lView) as RElement; @@ -1472,7 +1474,7 @@ export function elementAttributeInternal( function setInputsFromAttrs<T>( lView: LView, directiveIndex: number, instance: T, def: DirectiveDef<T>, tNode: TNode, initialInputData: InitialInputData): void { - const initialInputs: InitialInputs|null = initialInputData ![directiveIndex]; + const initialInputs: InitialInputs|null = initialInputData![directiveIndex]; if (initialInputs !== null) { const setInput = def.setInput; for (let i = 0; i < initialInputs.length;) { @@ -1480,7 +1482,7 @@ function setInputsFromAttrs<T>( const privateName = initialInputs[i++]; const value = initialInputs[i++]; if (setInput !== null) { - def.setInput !(instance, value, publicName, privateName); + def.setInput!(instance, value, publicName, privateName); } else { (instance as any)[privateName] = value; } @@ -1554,7 +1556,7 @@ const LContainerArray: any = ((typeof ngDevMode === 'undefined' || ngDevMode) && * @returns LContainer */ export function createLContainer( - hostNative: RElement | RComment | LView, currentView: LView, native: RComment, + hostNative: RElement|RComment|LView, currentView: LView, native: RComment, tNode: TNode): LContainer { ngDevMode && assertLView(currentView); ngDevMode && !isProceduralRenderer(currentView[RENDERER]) && assertDomNode(native); @@ -1569,7 +1571,7 @@ export function createLContainer( tNode, // t_host native, // native, null, // view refs - ); + ); ngDevMode && attachLContainerDebug(lContainer); return lContainer; } @@ -1594,14 +1596,14 @@ function refreshDynamicEmbeddedViews(lView: LView) { ngDevMode && assertDefined(embeddedTView, 'TView must be allocated'); if (viewAttachedToChangeDetector(embeddedLView)) { refreshView( - embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT] !); + embeddedTView, embeddedLView, embeddedTView.template, embeddedLView[CONTEXT]!); } } if ((activeIndexFlag & ActiveIndexFlag.HAS_TRANSPLANTED_VIEWS) !== 0) { // We should only CD moved views if the component where they were inserted does not match // the component where they were declared and insertion is on-push. Moved views also // contains intra component moves, or check-always which need to be skipped. - refreshTransplantedViews(viewOrContainer, lView[DECLARATION_COMPONENT_VIEW] !); + refreshTransplantedViews(viewOrContainer, lView[DECLARATION_COMPONENT_VIEW]!); } } viewOrContainer = viewOrContainer[NEXT]; @@ -1619,13 +1621,13 @@ function refreshDynamicEmbeddedViews(lView: LView) { * @param declaredComponentLView The `lContainer` parent component `LView`. */ function refreshTransplantedViews(lContainer: LContainer, declaredComponentLView: LView) { - const movedViews = lContainer[MOVED_VIEWS] !; + const movedViews = lContainer[MOVED_VIEWS]!; ngDevMode && assertDefined(movedViews, 'Transplanted View flags set but missing MOVED_VIEWS'); for (let i = 0; i < movedViews.length; i++) { - const movedLView = movedViews[i] !; + const movedLView = movedViews[i]!; const insertionLContainer = movedLView[PARENT] as LContainer; ngDevMode && assertLContainer(insertionLContainer); - const insertedComponentLView = insertionLContainer[PARENT][DECLARATION_COMPONENT_VIEW] !; + const insertedComponentLView = insertionLContainer[PARENT][DECLARATION_COMPONENT_VIEW]!; ngDevMode && assertDefined(insertedComponentLView, 'Missing LView'); // Check if we have a transplanted view by compering declaration and insertion location. if (insertedComponentLView !== declaredComponentLView) { @@ -1643,7 +1645,7 @@ function refreshTransplantedViews(lContainer: LContainer, declaredComponentLView // point. const movedTView = movedLView[TVIEW]; ngDevMode && assertDefined(movedTView, 'TView must be allocated'); - refreshView(movedTView, movedLView, movedTView.template, movedLView[CONTEXT] !); + refreshView(movedTView, movedLView, movedTView.template, movedLView[CONTEXT]!); } } } @@ -1725,7 +1727,7 @@ export function addToViewTree<T extends LView|LContainer>(lView: LView, lViewOrL // of order, the change detection will run out of order, as the act of retrieving the the // LContainer from the RNode is what adds it to the queue. if (lView[CHILD_HEAD]) { - lView[CHILD_TAIL] ![NEXT] = lViewOrLContainer; + lView[CHILD_TAIL]![NEXT] = lViewOrLContainer; } else { lView[CHILD_HEAD] = lViewOrLContainer; } @@ -1758,7 +1760,7 @@ export function markViewDirty(lView: LView): LView|null { return lView; } // continue otherwise - lView = parent !; + lView = parent!; } return null; } @@ -1797,7 +1799,7 @@ export function scheduleTick(rootContext: RootContext, flags: RootContextFlags) } rootContext.clean = _CLEAN_PROMISE; - res !(null); + res!(null); }); } } @@ -1805,7 +1807,7 @@ export function scheduleTick(rootContext: RootContext, flags: RootContextFlags) export function tickRootContext(rootContext: RootContext) { for (let i = 0; i < rootContext.components.length; i++) { const rootComponent = rootContext.components[i]; - const lView = readPatchedLView(rootComponent) !; + const lView = readPatchedLView(rootComponent)!; const tView = lView[TVIEW]; renderComponentOrTemplate(tView, lView, tView.template, rootComponent); } @@ -1929,7 +1931,7 @@ function getTViewCleanup(tView: TView): any[] { * instead of the current renderer (see the componentSyntheticHost* instructions). */ export function loadComponentRenderer(tNode: TNode, lView: LView): Renderer3 { - const componentLView = unwrapLView(lView[tNode.index]) !; + const componentLView = unwrapLView(lView[tNode.index])!; return componentLView[RENDERER]; } @@ -1958,7 +1960,7 @@ export function setInputsForProperty( ngDevMode && assertDataInRange(lView, index); const def = tView.data[index] as DirectiveDef<any>; if (def.setInput !== null) { - def.setInput !(instance, value, publicName, privateName); + def.setInput!(instance, value, publicName, privateName); } else { instance[privateName] = value; } diff --git a/packages/core/src/render3/interfaces/view.ts b/packages/core/src/render3/interfaces/view.ts index 9a7e4ee0f8034..eb943a97ffae8 100644 --- a/packages/core/src/render3/interfaces/view.ts +++ b/packages/core/src/render3/interfaces/view.ts @@ -365,8 +365,10 @@ export const enum InitPhaseState { /** More flags associated with an LView (saved in LView[PREORDER_HOOK_FLAGS]) */ export const enum PreOrderHookFlags { - /** The index of the next pre-order hook to be called in the hooks array, on the first 16 - bits */ + /** + The index of the next pre-order hook to be called in the hooks array, on the first 16 + bits + */ IndexOfTheNextPreOrderHookMaskMask = 0b01111111111111111, /** @@ -617,7 +619,7 @@ export interface TView { * Even indices: Directive index * Odd indices: Hook function */ - destroyHooks: HookData|null; + destroyHooks: DestroyHookData|null; /** * When a view is destroyed, listeners need to be released and outputs need to be @@ -684,7 +686,11 @@ export interface TView { consts: TConstants|null; } -export const enum RootContextFlags {Empty = 0b00, DetectChanges = 0b01, FlushPlayers = 0b10} +export const enum RootContextFlags { + Empty = 0b00, + DetectChanges = 0b01, + FlushPlayers = 0b10 +} /** @@ -722,6 +728,15 @@ export interface RootContext { flags: RootContextFlags; } +/** Single hook callback function. */ +export type HookFn = () => void; + +/** + * Information necessary to call a hook. E.g. the callback that + * needs to invoked and the index at which to find its context. + */ +export type HookEntry = number|HookFn; + /** * Array of hooks that should be executed for a view and their directive indices. * @@ -734,7 +749,27 @@ export interface RootContext { * Special cases: * - a negative directive index flags an init hook (ngOnInit, ngAfterContentInit, ngAfterViewInit) */ -export type HookData = (number | (() => void))[]; +export type HookData = HookEntry[]; + +/** + * Array of destroy hooks that should be executed for a view and their directive indices. + * + * The array is set up as a series of number/function or number/(number|function)[]: + * - Even indices represent the context with which hooks should be called. + * - Odd indices are the hook functions themselves. If a value at an odd index is an array, + * it represents the destroy hooks of a `multi` provider where: + * - Even indices represent the index of the provider for which we've registered a destroy hook, + * inside of the `multi` provider array. + * - Odd indices are the destroy hook functions. + * For example: + * LView: `[0, 1, 2, AService, 4, [BService, CService, DService]]` + * destroyHooks: `[3, AService.ngOnDestroy, 5, [0, BService.ngOnDestroy, 2, DService.ngOnDestroy]]` + * + * In the example above `AService` is a type provider with an `ngOnDestroy`, whereas `BService`, + * `CService` and `DService` are part of a `multi` provider where only `BService` and `DService` + * have an `ngOnDestroy` hook. + */ +export type DestroyHookData = (HookEntry|HookData)[]; /** * Static data that corresponds to the instance-specific data array on an LView. @@ -764,8 +799,8 @@ export type HookData = (number | (() => void))[]; * Injector bloom filters are also stored here. */ export type TData = - (TNode | PipeDef<any>| DirectiveDef<any>| ComponentDef<any>| number | TStylingRange | - TStylingKey | Type<any>| InjectionToken<any>| TI18n | I18nUpdateOpCodes | null | string)[]; + (TNode|PipeDef<any>|DirectiveDef<any>|ComponentDef<any>|number|TStylingRange|TStylingKey| + Type<any>|InjectionToken<any>|TI18n|I18nUpdateOpCodes|null|string)[]; // Note: This hack is necessary so we don't erroneously get a circular dependency // failure based on types. diff --git a/packages/core/src/render3/node_manipulation.ts b/packages/core/src/render3/node_manipulation.ts index 50c33997e45ed..ce5315440cf40 100644 --- a/packages/core/src/render3/node_manipulation.ts +++ b/packages/core/src/render3/node_manipulation.ts @@ -10,6 +10,7 @@ import {Renderer2} from '../core'; import {ViewEncapsulation} from '../metadata/view'; import {addToArray, removeFromArray} from '../util/array_utils'; import {assertDefined, assertDomNode, assertEqual, assertString} from '../util/assert'; + import {assertLContainer, assertLView, assertTNodeForLView} from './assert'; import {attachPatchData} from './context_discovery'; import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer, MOVED_VIEWS, NATIVE, unusedValueExportToPlacateAjd as unused1} from './interfaces/container'; @@ -17,9 +18,9 @@ import {ComponentDef} from './interfaces/definition'; import {NodeInjectorFactory} from './interfaces/injector'; import {TElementNode, TNode, TNodeFlags, TNodeType, TProjectionNode, TViewNode, unusedValueExportToPlacateAjd as unused2} from './interfaces/node'; import {unusedValueExportToPlacateAjd as unused3} from './interfaces/projection'; -import {ProceduralRenderer3, RElement, RNode, RText, Renderer3, isProceduralRenderer, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; +import {isProceduralRenderer, ProceduralRenderer3, RElement, Renderer3, RNode, RText, unusedValueExportToPlacateAjd as unused4} from './interfaces/renderer'; import {isLContainer, isLView} from './interfaces/type_checks'; -import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, FLAGS, HOST, HookData, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, TVIEW, TView, T_HOST, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; +import {CHILD_HEAD, CLEANUP, DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, DestroyHookData, FLAGS, HookData, HookFn, HOST, LView, LViewFlags, NEXT, PARENT, QUERIES, RENDERER, T_HOST, TVIEW, TView, unusedValueExportToPlacateAjd as unused5} from './interfaces/view'; import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert'; import {getLViewParent} from './util/view_traversal_utils'; import {getNativeByTNode, unwrapRNode} from './util/view_utils'; @@ -74,8 +75,8 @@ const enum WalkTNodeTreeAction { * being passed as an argument. */ function applyToElementOrContainer( - action: WalkTNodeTreeAction, renderer: Renderer3, parent: RElement | null, - lNodeToHandle: RNode | LContainer | LView, beforeNode?: RNode | null) { + action: WalkTNodeTreeAction, renderer: Renderer3, parent: RElement|null, + lNodeToHandle: RNode|LContainer|LView, beforeNode?: RNode|null) { // If this slot was allocated for a text node dynamically created by i18n, the text node itself // won't be created until i18nApply() in the update block, so this node should be skipped. // For more info, see "ICU expressions should work inside an ngTemplateOutlet inside an ngFor" @@ -91,7 +92,7 @@ function applyToElementOrContainer( } else if (isLView(lNodeToHandle)) { isComponent = true; ngDevMode && assertDefined(lNodeToHandle[HOST], 'HOST must be defined for a component LView'); - lNodeToHandle = lNodeToHandle[HOST] !; + lNodeToHandle = lNodeToHandle[HOST]!; } const rNode: RNode = unwrapRNode(lNodeToHandle); ngDevMode && !isProceduralRenderer(renderer) && assertDomNode(rNode); @@ -108,7 +109,7 @@ function applyToElementOrContainer( nativeRemoveNode(renderer, rNode, isComponent); } else if (action === WalkTNodeTreeAction.Destroy) { ngDevMode && ngDevMode.rendererDestroyNode++; - (renderer as ProceduralRenderer3).destroyNode !(rNode); + (renderer as ProceduralRenderer3).destroyNode!(rNode); } if (lContainer != null) { applyContainer(renderer, action, lContainer, parent, beforeNode); @@ -136,11 +137,11 @@ export function createTextNode(value: string, renderer: Renderer3): RText { * @param beforeNode The node before which elements should be added, if insert mode */ export function addRemoveViewFromContainer( - tView: TView, lView: LView, insertMode: true, beforeNode: RNode | null): void; + tView: TView, lView: LView, insertMode: true, beforeNode: RNode|null): void; export function addRemoveViewFromContainer( tView: TView, lView: LView, insertMode: false, beforeNode: null): void; export function addRemoveViewFromContainer( - tView: TView, lView: LView, insertMode: boolean, beforeNode: RNode | null): void { + tView: TView, lView: LView, insertMode: boolean, beforeNode: RNode|null): void { const renderParent = getContainerRenderParent(tView.node as TViewNode, lView); ngDevMode && assertNodeType(tView.node as TNode, TNodeType.View); if (renderParent) { @@ -196,13 +197,13 @@ export function destroyViewTree(rootView: LView): void { if (!next) { // Only clean up view when moving to the side or up, as destroy hooks // should be called in order from the bottom up. - while (lViewOrLContainer && !lViewOrLContainer ![NEXT] && lViewOrLContainer !== rootView) { + while (lViewOrLContainer && !lViewOrLContainer![NEXT] && lViewOrLContainer !== rootView) { isLView(lViewOrLContainer) && cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer); lViewOrLContainer = getParentState(lViewOrLContainer, rootView); } if (lViewOrLContainer === null) lViewOrLContainer = rootView; isLView(lViewOrLContainer) && cleanUpView(lViewOrLContainer[TVIEW], lViewOrLContainer); - next = lViewOrLContainer && lViewOrLContainer ![NEXT]; + next = lViewOrLContainer && lViewOrLContainer![NEXT]; } lViewOrLContainer = next; } @@ -267,7 +268,7 @@ function trackMovedView(declarationContainer: LContainer, lView: LView) { const movedViews = declarationContainer[MOVED_VIEWS]; const insertedLContainer = lView[PARENT] as LContainer; ngDevMode && assertLContainer(insertedLContainer); - const insertedComponentLView = insertedLContainer[PARENT] ![DECLARATION_COMPONENT_VIEW]; + const insertedComponentLView = insertedLContainer[PARENT]![DECLARATION_COMPONENT_VIEW]; ngDevMode && assertDefined(insertedComponentLView, 'Missing insertedComponentLView'); const insertedComponentIsOnPush = (insertedComponentLView[FLAGS] & LViewFlags.CheckAlways) !== LViewFlags.CheckAlways; @@ -291,10 +292,11 @@ function trackMovedView(declarationContainer: LContainer, lView: LView) { function detachMovedView(declarationContainer: LContainer, lView: LView) { ngDevMode && assertLContainer(declarationContainer); - ngDevMode && assertDefined( - declarationContainer[MOVED_VIEWS], - 'A projected view should belong to a non-empty projected views collection'); - const movedViews = declarationContainer[MOVED_VIEWS] !; + ngDevMode && + assertDefined( + declarationContainer[MOVED_VIEWS], + 'A projected view should belong to a non-empty projected views collection'); + const movedViews = declarationContainer[MOVED_VIEWS]!; const declaredViewIndex = movedViews.indexOf(lView); movedViews.splice(declaredViewIndex, 1); } @@ -383,7 +385,7 @@ export function destroyLView(tView: TView, lView: LView) { * @param rootView The rootView, so we don't propagate too far up the view tree * @returns The correct parent LViewOrLContainer */ -export function getParentState(lViewOrLContainer: LView | LContainer, rootView: LView): LView| +export function getParentState(lViewOrLContainer: LView|LContainer, rootView: LView): LView| LContainer|null { let tNode; if (isLView(lViewOrLContainer) && (tNode = lViewOrLContainer[T_HOST]) && @@ -449,7 +451,7 @@ function cleanUpView(tView: TView, lView: LView): void { function removeListeners(tView: TView, lView: LView): void { const tCleanup = tView.cleanup; if (tCleanup !== null) { - const lCleanup = lView[CLEANUP] !; + const lCleanup = lView[CLEANUP]!; for (let i = 0; i < tCleanup.length - 1; i += 2) { if (typeof tCleanup[i] === 'string') { // This is a native DOM listener @@ -484,7 +486,7 @@ function removeListeners(tView: TView, lView: LView): void { /** Calls onDestroy hooks for this view */ function executeOnDestroys(tView: TView, lView: LView): void { - let destroyHooks: HookData|null; + let destroyHooks: DestroyHookData|null; if (tView != null && (destroyHooks = tView.destroyHooks) != null) { for (let i = 0; i < destroyHooks.length; i += 2) { @@ -492,7 +494,15 @@ function executeOnDestroys(tView: TView, lView: LView): void { // Only call the destroy hook if the context has been requested. if (!(context instanceof NodeInjectorFactory)) { - (destroyHooks[i + 1] as() => void).call(context); + const toCall = destroyHooks[i + 1] as HookFn | HookData; + + if (Array.isArray(toCall)) { + for (let j = 0; j < toCall.length; j += 2) { + (toCall[j + 1] as HookFn).call(context[toCall[j] as number]); + } + } else { + toCall.call(context); + } } } } @@ -514,8 +524,9 @@ function getRenderParent(tView: TView, tNode: TNode, currentView: LView): REleme // Skip over element and ICU containers as those are represented by a comment node and // can't be used as a render parent. let parentTNode = tNode.parent; - while (parentTNode != null && (parentTNode.type === TNodeType.ElementContainer || - parentTNode.type === TNodeType.IcuContainer)) { + while (parentTNode != null && + (parentTNode.type === TNodeType.ElementContainer || + parentTNode.type === TNodeType.IcuContainer)) { tNode = parentTNode; parentTNode = tNode.parent; } @@ -523,7 +534,7 @@ function getRenderParent(tView: TView, tNode: TNode, currentView: LView): REleme // If the parent tNode is null, then we are inserting across views: either into an embedded view // or a component view. if (parentTNode == null) { - const hostTNode = currentView[T_HOST] !; + const hostTNode = currentView[T_HOST]!; if (hostTNode.type === TNodeType.View) { // We are inserting a root element of an embedded view We might delay insertion of children // for a given view if it is disconnected. This might happen for 2 main reasons: @@ -575,7 +586,7 @@ function getRenderParent(tView: TView, tNode: TNode, currentView: LView): REleme * actual renderer being used. */ export function nativeInsertBefore( - renderer: Renderer3, parent: RElement, child: RNode, beforeNode: RNode | null): void { + renderer: Renderer3, parent: RElement, child: RNode, beforeNode: RNode|null): void { ngDevMode && ngDevMode.rendererInsertBefore++; if (isProceduralRenderer(renderer)) { renderer.insertBefore(parent, child, beforeNode); @@ -595,7 +606,7 @@ function nativeAppendChild(renderer: Renderer3, parent: RElement, child: RNode): } function nativeAppendOrInsertBefore( - renderer: Renderer3, parent: RElement, child: RNode, beforeNode: RNode | null) { + renderer: Renderer3, parent: RElement, child: RNode, beforeNode: RNode|null) { if (beforeNode !== null) { nativeInsertBefore(renderer, parent, child, beforeNode); } else { @@ -659,11 +670,11 @@ function getNativeAnchorNode(parentTNode: TNode, lView: LView): RNode|null { * @returns Whether or not the child was appended */ export function appendChild( - tView: TView, lView: LView, childEl: RNode | RNode[], childTNode: TNode): void { + tView: TView, lView: LView, childEl: RNode|RNode[], childTNode: TNode): void { const renderParent = getRenderParent(tView, childTNode, lView); if (renderParent != null) { const renderer = lView[RENDERER]; - const parentTNode: TNode = childTNode.parent || lView[T_HOST] !; + const parentTNode: TNode = childTNode.parent || lView[T_HOST]!; const anchorNode = getNativeAnchorNode(parentTNode, lView); if (Array.isArray(childEl)) { for (let i = 0; i < childEl.length; i++) { @@ -680,11 +691,12 @@ export function appendChild( * * Native nodes are returned in the order in which those appear in the native tree (DOM). */ -function getFirstNativeNode(lView: LView, tNode: TNode | null): RNode|null { +function getFirstNativeNode(lView: LView, tNode: TNode|null): RNode|null { if (tNode !== null) { - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer, - TNodeType.IcuContainer, TNodeType.Projection); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer, + TNodeType.IcuContainer, TNodeType.Projection); const tNodeType = tNode.type; if (tNodeType === TNodeType.Element) { @@ -708,10 +720,10 @@ function getFirstNativeNode(lView: LView, tNode: TNode | null): RNode|null { const componentHost = componentView[T_HOST] as TElementNode; const parentView = getLViewParent(componentView); const firstProjectedTNode: TNode|null = - (componentHost.projection as(TNode | null)[])[tNode.projection as number]; + (componentHost.projection as (TNode | null)[])[tNode.projection as number]; if (firstProjectedTNode != null) { - return getFirstNativeNode(parentView !, firstProjectedTNode); + return getFirstNativeNode(parentView!, firstProjectedTNode); } else { return getFirstNativeNode(lView, tNode.next); } @@ -757,13 +769,14 @@ export function nativeRemoveNode(renderer: Renderer3, rNode: RNode, isHostElemen * nodes on the LView or projection boundary. */ function applyNodes( - renderer: Renderer3, action: WalkTNodeTreeAction, tNode: TNode | null, lView: LView, - renderParent: RElement | null, beforeNode: RNode | null, isProjection: boolean) { + renderer: Renderer3, action: WalkTNodeTreeAction, tNode: TNode|null, lView: LView, + renderParent: RElement|null, beforeNode: RNode|null, isProjection: boolean) { while (tNode != null) { ngDevMode && assertTNodeForLView(tNode, lView); - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer, - TNodeType.Projection, TNodeType.Projection, TNodeType.IcuContainer); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer, + TNodeType.Projection, TNodeType.Projection, TNodeType.IcuContainer); const rawSlotValue = lView[tNode.index]; const tNodeType = tNode.type; if (isProjection) { @@ -814,9 +827,9 @@ function applyNodes( */ function applyView( tView: TView, lView: LView, renderer: Renderer3, action: WalkTNodeTreeAction, - renderParent: RElement | null, beforeNode: RNode | null) { - ngDevMode && assertNodeType(tView.node !, TNodeType.View); - const viewRootTNode: TNode|null = tView.node !.child; + renderParent: RElement|null, beforeNode: RNode|null) { + ngDevMode && assertNodeType(tView.node!, TNodeType.View); + const viewRootTNode: TNode|null = tView.node!.child; applyNodes(renderer, action, viewRootTNode, lView, renderParent, beforeNode, false); } @@ -833,7 +846,7 @@ function applyView( export function applyProjection(tView: TView, lView: LView, tProjectionNode: TProjectionNode) { const renderer = lView[RENDERER]; const renderParent = getRenderParent(tView, tProjectionNode, lView); - const parentTNode = tProjectionNode.parent || lView[T_HOST] !; + const parentTNode = tProjectionNode.parent || lView[T_HOST]!; let beforeNode = getNativeAnchorNode(parentTNode, lView); applyProjectionRecursive( renderer, WalkTNodeTreeAction.Create, lView, tProjectionNode, renderParent, beforeNode); @@ -855,12 +868,12 @@ export function applyProjection(tView: TView, lView: LView, tProjectionNode: TPr */ function applyProjectionRecursive( renderer: Renderer3, action: WalkTNodeTreeAction, lView: LView, - tProjectionNode: TProjectionNode, renderParent: RElement | null, beforeNode: RNode | null) { + tProjectionNode: TProjectionNode, renderParent: RElement|null, beforeNode: RNode|null) { const componentLView = lView[DECLARATION_COMPONENT_VIEW]; const componentNode = componentLView[T_HOST] as TElementNode; ngDevMode && assertEqual(typeof tProjectionNode.projection, 'number', 'expecting projection index'); - const nodeToProjectOrRNodes = componentNode.projection ![tProjectionNode.projection] !; + const nodeToProjectOrRNodes = componentNode.projection![tProjectionNode.projection]!; if (Array.isArray(nodeToProjectOrRNodes)) { // This should not exist, it is a bit of a hack. When we bootstrap a top level node and we // need to support passing projectable nodes, so we cheat and put them in the TNode @@ -895,7 +908,7 @@ function applyProjectionRecursive( */ function applyContainer( renderer: Renderer3, action: WalkTNodeTreeAction, lContainer: LContainer, - renderParent: RElement | null, beforeNode: RNode | null | undefined) { + renderParent: RElement|null, beforeNode: RNode|null|undefined) { ngDevMode && assertLContainer(lContainer); const anchor = lContainer[NATIVE]; // LContainer has its own before node. const native = unwrapRNode(lContainer); @@ -1016,4 +1029,4 @@ export function writeDirectClass(renderer: Renderer3, element: RElement, newValu element.className = newValue; } ngDevMode && ngDevMode.rendererSetClassName++; -} \ No newline at end of file +} diff --git a/packages/core/test/acceptance/providers_spec.ts b/packages/core/test/acceptance/providers_spec.ts index 0c46b74098718..90a40decf60a7 100644 --- a/packages/core/test/acceptance/providers_spec.ts +++ b/packages/core/test/acceptance/providers_spec.ts @@ -6,16 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Directive, Inject, Injectable, InjectionToken, Injector, NgModule, Optional, forwardRef} from '@angular/core'; -import {TestBed, async, inject} from '@angular/core/testing'; +import {Component, Directive, forwardRef, Inject, Injectable, InjectionToken, Injector, NgModule, Optional} from '@angular/core'; +import {async, inject, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {onlyInIvy} from '@angular/private/testing'; +import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; describe('providers', () => { - describe('inheritance', () => { - it('should NOT inherit providers', () => { const SOME_DIRS = new InjectionToken('someDirs'); @@ -52,7 +50,6 @@ describe('providers', () => { expect(otherDir.dirs.length).toEqual(1); expect(otherDir.dirs[0] instanceof SubDirective).toBe(true); }); - }); describe('lifecycles', () => { @@ -61,7 +58,9 @@ describe('providers', () => { @Injectable() class SuperInjectableWithDestroyHook { - ngOnDestroy() { logs.push('OnDestroy'); } + ngOnDestroy() { + logs.push('OnDestroy'); + } } @Injectable() @@ -86,7 +85,9 @@ describe('providers', () => { @Injectable() class InjectableWithDestroyHook { - ngOnDestroy() { logs.push('OnDestroy'); } + ngOnDestroy() { + logs.push('OnDestroy'); + } } @Component({template: '', providers: [InjectableWithDestroyHook]}) @@ -106,7 +107,9 @@ describe('providers', () => { @Injectable() class InjectableWithDestroyHook { - ngOnDestroy() { logs.push('OnDestroy'); } + ngOnDestroy() { + logs.push('OnDestroy'); + } } @Component({selector: 'my-cmp', template: ''}) @@ -137,7 +140,9 @@ describe('providers', () => { @Injectable() class InjectableWithDestroyHook { - ngOnDestroy() { logs.push('OnDestroy'); } + ngOnDestroy() { + logs.push('OnDestroy'); + } } @Component({ @@ -162,12 +167,16 @@ describe('providers', () => { @Injectable() class InjectableWithDestroyHookToken { - ngOnDestroy() { logs.push('OnDestroy Token'); } + ngOnDestroy() { + logs.push('OnDestroy Token'); + } } @Injectable() class InjectableWithDestroyHookValue { - ngOnDestroy() { logs.push('OnDestroy Value'); } + ngOnDestroy() { + logs.push('OnDestroy Value'); + } } @Component({ @@ -193,21 +202,23 @@ describe('providers', () => { @Injectable() class InjectableWithDestroyHookToken { - ngOnDestroy() { logs.push('OnDestroy Token'); } + ngOnDestroy() { + logs.push('OnDestroy Token'); + } } @Injectable() class InjectableWithDestroyHookExisting { - ngOnDestroy() { logs.push('OnDestroy Existing'); } + ngOnDestroy() { + logs.push('OnDestroy Existing'); + } } @Component({ template: '', providers: [ - InjectableWithDestroyHookExisting, { - provide: InjectableWithDestroyHookToken, - useExisting: InjectableWithDestroyHookExisting - } + InjectableWithDestroyHookExisting, + {provide: InjectableWithDestroyHookToken, useExisting: InjectableWithDestroyHookExisting} ] }) class App { @@ -225,30 +236,40 @@ describe('providers', () => { it('should invoke ngOnDestroy with the correct context when providing a type provider multiple times on the same node', () => { - const resolvedServices: (DestroyService | undefined)[] = []; - const destroyContexts: (DestroyService | undefined)[] = []; + const resolvedServices: (DestroyService|undefined)[] = []; + const destroyContexts: (DestroyService|undefined)[] = []; let parentService: DestroyService|undefined; let childService: DestroyService|undefined; @Injectable() class DestroyService { - constructor() { resolvedServices.push(this); } - ngOnDestroy() { destroyContexts.push(this); } + constructor() { + resolvedServices.push(this); + } + ngOnDestroy() { + destroyContexts.push(this); + } } @Directive({selector: '[dir-one]', providers: [DestroyService]}) class DirOne { - constructor(service: DestroyService) { childService = service; } + constructor(service: DestroyService) { + childService = service; + } } @Directive({selector: '[dir-two]', providers: [DestroyService]}) class DirTwo { - constructor(service: DestroyService) { childService = service; } + constructor(service: DestroyService) { + childService = service; + } } @Component({template: '<div dir-one dir-two></div>', providers: [DestroyService]}) class App { - constructor(service: DestroyService) { parentService = service; } + constructor(service: DestroyService) { + parentService = service; + } } TestBed.configureTestingModule({declarations: [App, DirOne, DirTwo]}); @@ -266,28 +287,36 @@ describe('providers', () => { onlyInIvy('Destroy hook of useClass provider is invoked correctly') .it('should invoke ngOnDestroy with the correct context when providing a class provider multiple times on the same node', () => { - const resolvedServices: (DestroyService | undefined)[] = []; - const destroyContexts: (DestroyService | undefined)[] = []; + const resolvedServices: (DestroyService|undefined)[] = []; + const destroyContexts: (DestroyService|undefined)[] = []; const token = new InjectionToken<any>('token'); let parentService: DestroyService|undefined; let childService: DestroyService|undefined; @Injectable() class DestroyService { - constructor() { resolvedServices.push(this); } - ngOnDestroy() { destroyContexts.push(this); } + constructor() { + resolvedServices.push(this); + } + ngOnDestroy() { + destroyContexts.push(this); + } } @Directive( {selector: '[dir-one]', providers: [{provide: token, useClass: DestroyService}]}) class DirOne { - constructor(@Inject(token) service: DestroyService) { childService = service; } + constructor(@Inject(token) service: DestroyService) { + childService = service; + } } @Directive( {selector: '[dir-two]', providers: [{provide: token, useClass: DestroyService}]}) class DirTwo { - constructor(@Inject(token) service: DestroyService) { childService = service; } + constructor(@Inject(token) service: DestroyService) { + childService = service; + } } @Component({ @@ -295,7 +324,9 @@ describe('providers', () => { providers: [{provide: token, useClass: DestroyService}] }) class App { - constructor(@Inject(token) service: DestroyService) { parentService = service; } + constructor(@Inject(token) service: DestroyService) { + parentService = service; + } } TestBed.configureTestingModule({declarations: [App, DirOne, DirTwo]}); @@ -310,21 +341,151 @@ describe('providers', () => { expect(destroyContexts).toEqual([parentService, childService]); }); + onlyInIvy('ngOnDestroy hooks for multi providers were not supported in ViewEngine') + .describe('ngOnDestroy on multi providers', () => { + it('should invoke ngOnDestroy on multi providers with the correct context', () => { + const destroyCalls: any[] = []; + const SERVICES = new InjectionToken<any>('SERVICES'); + + @Injectable() + class DestroyService { + ngOnDestroy() { + destroyCalls.push(this); + } + } + + @Injectable() + class OtherDestroyService { + ngOnDestroy() { + destroyCalls.push(this); + } + } + + @Component({ + template: '<div></div>', + providers: [ + {provide: SERVICES, useClass: DestroyService, multi: true}, + {provide: SERVICES, useClass: OtherDestroyService, multi: true}, + ] + }) + class App { + constructor(@Inject(SERVICES) s: any) {} + } + + TestBed.configureTestingModule({declarations: [App]}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + fixture.destroy(); + + expect(destroyCalls).toEqual([ + jasmine.any(DestroyService), jasmine.any(OtherDestroyService) + ]); + }); + + it('should invoke destroy hooks on multi providers with the correct context, if only some have a destroy hook', + () => { + const destroyCalls: any[] = []; + const SERVICES = new InjectionToken<any>('SERVICES'); + + @Injectable() + class Service1 { + } + + @Injectable() + class Service2 { + ngOnDestroy() { + destroyCalls.push(this); + } + } + + @Injectable() + class Service3 { + } + + @Injectable() + class Service4 { + ngOnDestroy() { + destroyCalls.push(this); + } + } + + @Component({ + template: '<div></div>', + providers: [ + {provide: SERVICES, useClass: Service1, multi: true}, + {provide: SERVICES, useClass: Service2, multi: true}, + {provide: SERVICES, useClass: Service3, multi: true}, + {provide: SERVICES, useClass: Service4, multi: true}, + ] + }) + class App { + constructor(@Inject(SERVICES) s: any) {} + } + + TestBed.configureTestingModule({declarations: [App]}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + fixture.destroy(); + + expect(destroyCalls).toEqual([jasmine.any(Service2), jasmine.any(Service4)]); + }); + + it('should not invoke ngOnDestroy on multi providers created via useFactory', () => { + let destroyCalls = 0; + const SERVICES = new InjectionToken<any>('SERVICES'); + + @Injectable() + class DestroyService { + ngOnDestroy() { + destroyCalls++; + } + } + + @Injectable() + class OtherDestroyService { + ngOnDestroy() { + destroyCalls++; + } + } + + @Component({ + template: '<div></div>', + providers: [ + {provide: SERVICES, useFactory: () => new DestroyService(), multi: true}, + {provide: SERVICES, useFactory: () => new OtherDestroyService(), multi: true}, + ] + }) + class App { + constructor(@Inject(SERVICES) s: any) {} + } + + TestBed.configureTestingModule({declarations: [App]}); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + fixture.destroy(); + + expect(destroyCalls).toBe(0); + }); + }); + + modifiedInIvy('ViewEngine did not support destroy hooks on multi providers') .it('should not invoke ngOnDestroy on multi providers', () => { - // TODO(FW-1866): currently we only assert that the hook was called, - // but we should also be checking that the correct context was passed in. let destroyCalls = 0; const SERVICES = new InjectionToken<any>('SERVICES'); @Injectable() class DestroyService { - ngOnDestroy() { destroyCalls++; } + ngOnDestroy() { + destroyCalls++; + } } @Injectable() class OtherDestroyService { - ngOnDestroy() { destroyCalls++; } + ngOnDestroy() { + destroyCalls++; + } } @Component({ @@ -343,13 +504,11 @@ describe('providers', () => { fixture.detectChanges(); fixture.destroy(); - expect(destroyCalls).toBe(2); + expect(destroyCalls).toBe(0); }); - }); describe('components and directives', () => { - class MyService { value = 'some value'; } @@ -409,7 +568,6 @@ describe('providers', () => { }); describe('forward refs', () => { - it('should support forward refs in provider deps', () => { class MyService { constructor(public dep: {value: string}) {} @@ -444,7 +602,6 @@ describe('providers', () => { }); it('should support forward refs in useClass when impl version is also provided', () => { - @Injectable({providedIn: 'root', useClass: forwardRef(() => SomeProviderImpl)}) abstract class SomeProvider { } @@ -490,11 +647,9 @@ describe('providers', () => { expect(fixture.componentInstance.foo).toBeAnInstanceOf(SomeProviderImpl); }); - }); describe('flags', () => { - class MyService { constructor(public value: OtherService|null) {} } From e0415dbf168312982e057470941819bfa1428b29 Mon Sep 17 00:00:00 2001 From: Andrew Scott <atscott01@gmail.com> Date: Mon, 6 Apr 2020 13:39:33 -0700 Subject: [PATCH 135/262] fix(router): state data missing in routerLink (#36462) fixes #33173 - router state data is missing on routerLink when used with non-anchor elements. PR Close #36462 --- packages/router/src/directives/router_link.ts | 43 +- packages/router/test/integration.spec.ts | 370 ++++++++++-------- 2 files changed, 234 insertions(+), 179 deletions(-) diff --git a/packages/router/src/directives/router_link.ts b/packages/router/src/directives/router_link.ts index c12ca2c8cf911..a6462ce08ea83 100644 --- a/packages/router/src/directives/router_link.ts +++ b/packages/router/src/directives/router_link.ts @@ -7,7 +7,7 @@ */ import {LocationStrategy} from '@angular/common'; -import {Attribute, Directive, ElementRef, HostBinding, HostListener, Input, OnChanges, OnDestroy, Renderer2, isDevMode} from '@angular/core'; +import {Attribute, Directive, ElementRef, HostBinding, HostListener, Input, isDevMode, OnChanges, OnDestroy, Renderer2} from '@angular/core'; import {Subscription} from 'rxjs'; import {QueryParamsHandling} from '../config'; @@ -114,21 +114,21 @@ import {UrlTree} from '../url_tree'; @Directive({selector: ':not(a):not(area)[routerLink]'}) export class RouterLink { // TODO(issue/24571): remove '!'. - @Input() queryParams !: {[k: string]: any}; + @Input() queryParams!: {[k: string]: any}; // TODO(issue/24571): remove '!'. - @Input() fragment !: string; + @Input() fragment!: string; // TODO(issue/24571): remove '!'. - @Input() queryParamsHandling !: QueryParamsHandling; + @Input() queryParamsHandling!: QueryParamsHandling; // TODO(issue/24571): remove '!'. - @Input() preserveFragment !: boolean; + @Input() preserveFragment!: boolean; // TODO(issue/24571): remove '!'. - @Input() skipLocationChange !: boolean; + @Input() skipLocationChange!: boolean; // TODO(issue/24571): remove '!'. - @Input() replaceUrl !: boolean; + @Input() replaceUrl!: boolean; @Input() state?: {[k: string]: any}; private commands: any[] = []; // TODO(issue/24571): remove '!'. - private preserve !: boolean; + private preserve!: boolean; constructor( private router: Router, private route: ActivatedRoute, @@ -163,6 +163,7 @@ export class RouterLink { const extras = { skipLocationChange: attrBoolValue(this.skipLocationChange), replaceUrl: attrBoolValue(this.replaceUrl), + state: this.state, }; this.router.navigateByUrl(this.urlTree, extras); return true; @@ -194,28 +195,28 @@ export class RouterLink { @Directive({selector: 'a[routerLink],area[routerLink]'}) export class RouterLinkWithHref implements OnChanges, OnDestroy { // TODO(issue/24571): remove '!'. - @HostBinding('attr.target') @Input() target !: string; + @HostBinding('attr.target') @Input() target!: string; // TODO(issue/24571): remove '!'. - @Input() queryParams !: {[k: string]: any}; + @Input() queryParams!: {[k: string]: any}; // TODO(issue/24571): remove '!'. - @Input() fragment !: string; + @Input() fragment!: string; // TODO(issue/24571): remove '!'. - @Input() queryParamsHandling !: QueryParamsHandling; + @Input() queryParamsHandling!: QueryParamsHandling; // TODO(issue/24571): remove '!'. - @Input() preserveFragment !: boolean; + @Input() preserveFragment!: boolean; // TODO(issue/24571): remove '!'. - @Input() skipLocationChange !: boolean; + @Input() skipLocationChange!: boolean; // TODO(issue/24571): remove '!'. - @Input() replaceUrl !: boolean; + @Input() replaceUrl!: boolean; @Input() state?: {[k: string]: any}; private commands: any[] = []; private subscription: Subscription; // TODO(issue/24571): remove '!'. - private preserve !: boolean; + private preserve!: boolean; // the url displayed on the anchor element. // TODO(issue/24571): remove '!'. - @HostBinding() href !: string; + @HostBinding() href!: string; constructor( private router: Router, private route: ActivatedRoute, @@ -244,8 +245,12 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy { this.preserve = value; } - ngOnChanges(changes: {}): any { this.updateTargetUrlAndHref(); } - ngOnDestroy(): any { this.subscription.unsubscribe(); } + ngOnChanges(changes: {}): any { + this.updateTargetUrlAndHref(); + } + ngOnDestroy(): any { + this.subscription.unsubscribe(); + } @HostListener('click', ['$event.button', '$event.ctrlKey', '$event.metaKey', '$event.shiftKey']) onClick(button: number, ctrlKey: boolean, metaKey: boolean, shiftKey: boolean): boolean { diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 31d9acda5b99b..6d03da7b1e461 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -9,11 +9,11 @@ import {CommonModule, Location} from '@angular/common'; import {SpyLocation} from '@angular/common/testing'; import {ChangeDetectionStrategy, Component, Injectable, NgModule, NgModuleFactoryLoader, NgModuleRef, NgZone, OnDestroy, ɵConsole as Console, ɵNoopNgZone as NoopNgZone} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync, inject, tick} from '@angular/core/testing'; +import {ComponentFixture, fakeAsync, inject, TestBed, tick} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {expect} from '@angular/platform-browser/testing/src/matchers'; -import {ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, CanActivate, CanDeactivate, ChildActivationEnd, ChildActivationStart, DefaultUrlSerializer, DetachedRouteHandle, Event, GuardsCheckEnd, GuardsCheckStart, Navigation, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, ParamMap, Params, PreloadAllModules, PreloadingStrategy, Resolve, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterEvent, RouterModule, RouterPreloader, RouterStateSnapshot, RoutesRecognized, RunGuardsAndResolvers, UrlHandlingStrategy, UrlSegmentGroup, UrlSerializer, UrlTree} from '@angular/router'; -import {Observable, Observer, Subscription, of } from 'rxjs'; +import {ActivatedRoute, ActivatedRouteSnapshot, ActivationEnd, ActivationStart, CanActivate, CanDeactivate, ChildActivationEnd, ChildActivationStart, DefaultUrlSerializer, DetachedRouteHandle, Event, GuardsCheckEnd, GuardsCheckStart, Navigation, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ParamMap, Params, PreloadAllModules, PreloadingStrategy, PRIMARY_OUTLET, Resolve, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, Router, RouteReuseStrategy, RouterEvent, RouterModule, RouterPreloader, RouterStateSnapshot, RoutesRecognized, RunGuardsAndResolvers, UrlHandlingStrategy, UrlSegmentGroup, UrlSerializer, UrlTree} from '@angular/router'; +import {Observable, Observer, of, Subscription} from 'rxjs'; import {filter, first, map, tap} from 'rxjs/operators'; import {forEach} from '../src/utils/collection'; @@ -129,8 +129,8 @@ describe('Integration', () => { router.navigateByUrl('/simple'); tick(); - expect(event !.navigationTrigger).toEqual('imperative'); - expect(event !.restoredState).toEqual(null); + expect(event!.navigationTrigger).toEqual('imperative'); + expect(event!.restoredState).toEqual(null); }))); it('should set history.state if passed using imperative navigation', @@ -141,10 +141,10 @@ describe('Integration', () => { ]); const fixture = createRoot(router, RootCmp); - let navigation: Navigation = null !; + let navigation: Navigation = null!; router.events.subscribe(e => { if (e instanceof NavigationStart) { - navigation = router.getCurrentNavigation() !; + navigation = router.getCurrentNavigation()!; } }); @@ -255,7 +255,9 @@ describe('Integration', () => { let warnings: string[] = []; class MockConsole { - warn(message: string) { warnings.push(message); } + warn(message: string) { + warnings.push(message); + } } beforeEach(() => { @@ -266,7 +268,9 @@ describe('Integration', () => { describe('with NgZone enabled', () => { it('should warn when triggered outside Angular zone', fakeAsync(inject([Router, NgZone], (router: Router, ngZone: NgZone) => { - ngZone.runOutsideAngular(() => { router.navigateByUrl('/simple'); }); + ngZone.runOutsideAngular(() => { + router.navigateByUrl('/simple'); + }); expect(warnings.length).toBe(1); expect(warnings[0]) @@ -276,19 +280,24 @@ describe('Integration', () => { it('should not warn when triggered inside Angular zone', fakeAsync(inject([Router, NgZone], (router: Router, ngZone: NgZone) => { - ngZone.run(() => { router.navigateByUrl('/simple'); }); + ngZone.run(() => { + router.navigateByUrl('/simple'); + }); expect(warnings.length).toBe(0); }))); }); describe('with NgZone disabled', () => { - beforeEach(() => { TestBed.overrideProvider(NgZone, {useValue: new NoopNgZone()}); }); + beforeEach(() => { + TestBed.overrideProvider(NgZone, {useValue: new NoopNgZone()}); + }); it('should not warn when triggered outside Angular zone', fakeAsync(inject([Router, NgZone], (router: Router, ngZone: NgZone) => { - - ngZone.runOutsideAngular(() => { router.navigateByUrl('/simple'); }); + ngZone.runOutsideAngular(() => { + router.navigateByUrl('/simple'); + }); expect(warnings.length).toBe(0); }))); @@ -331,18 +340,24 @@ describe('Integration', () => { @Component({template: '<router-outlet></router-outlet>'}) class Parent { constructor(route: ActivatedRoute) { - route.params.subscribe((s: any) => { log.push(s); }); + route.params.subscribe((s: any) => { + log.push(s); + }); } } @Component({template: 'child1'}) class Child1 { - ngOnDestroy() { log.push('child1 destroy'); } + ngOnDestroy() { + log.push('child1 destroy'); + } } @Component({template: 'child2'}) class Child2 { - constructor() { log.push('child2 constructor'); } + constructor() { + log.push('child2 constructor'); + } } @NgModule({ @@ -382,7 +397,6 @@ describe('Integration', () => { 'child2 constructor', ]); }))); - }); it('should not wait for prior navigations to start a new navigation', @@ -412,7 +426,6 @@ describe('Integration', () => { 'trueRightAway', 'trueIn2Seconds-start', 'trueRightAway', 'trueIn2Seconds-start', 'trueIn2Seconds-end', 'trueIn2Seconds-end' ]); - }))); }); @@ -464,11 +477,9 @@ describe('Integration', () => { fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const fixture = createRoot(router, RootCmp); - router.resetConfig([{ - path: 'team/:id', - component: TeamCmp, - children: [{path: 'simple', component: SimpleCmp}] - }]); + router.resetConfig([ + {path: 'team/:id', component: TeamCmp, children: [{path: 'simple', component: SimpleCmp}]} + ]); router.navigateByUrl('/team/33/simple'); advance(fixture); @@ -535,7 +546,9 @@ describe('Integration', () => { @Component({template: `record`}) class RecordLocationCmp { private storedPath: string; - constructor(loc: Location) { this.storedPath = loc.path(); } + constructor(loc: Location) { + this.storedPath = loc.path(); + } } @NgModule({declarations: [RecordLocationCmp], entryComponents: [RecordLocationCmp]}) @@ -632,11 +645,12 @@ describe('Integration', () => { providers: [{ provide: 'authGuardFail', useValue: (a: any, b: any) => { - return new Promise(res => { setTimeout(() => res(serializer.parse('/login')), 1); }); + return new Promise(res => { + setTimeout(() => res(serializer.parse('/login')), 1); + }); } }] }); - }); @@ -657,7 +671,7 @@ describe('Integration', () => { (router as any).hooks.beforePreactivation = () => { expect(location.path()).toEqual('/team/33'); expect(fixture.nativeElement).toHaveText('team 22 [ , right: ]'); - return of (null); + return of(null); }; router.navigateByUrl('/team/33'); @@ -758,7 +772,6 @@ describe('Integration', () => { it('should should set `state` with urlUpdateStrategy="eagar"', fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => { - router.urlUpdateStrategy = 'eager'; router.resetConfig([ {path: '', component: SimpleCmp}, @@ -766,10 +779,10 @@ describe('Integration', () => { ]); const fixture = createRoot(router, RootCmp); - let navigation: Navigation = null !; + let navigation: Navigation = null!; router.events.subscribe(e => { if (e instanceof NavigationStart) { - navigation = router.getCurrentNavigation() !; + navigation = router.getCurrentNavigation()!; } }); @@ -806,24 +819,24 @@ describe('Integration', () => { router.navigateByUrl('/team/33/simple'); advance(fixture); expect(location.path()).toEqual('/team/33/simple'); - const simpleNavStart = event !; + const simpleNavStart = event!; router.navigateByUrl('/team/22/user/victor'); advance(fixture); - const userVictorNavStart = event !; + const userVictorNavStart = event!; location.back(); advance(fixture); expect(location.path()).toEqual('/team/33/simple'); - expect(event !.navigationTrigger).toEqual('hashchange'); - expect(event !.restoredState !.navigationId).toEqual(simpleNavStart.id); + expect(event!.navigationTrigger).toEqual('hashchange'); + expect(event!.restoredState!.navigationId).toEqual(simpleNavStart.id); location.forward(); advance(fixture); expect(location.path()).toEqual('/team/22/user/victor'); - expect(event !.navigationTrigger).toEqual('hashchange'); - expect(event !.restoredState !.navigationId).toEqual(userVictorNavStart.id); + expect(event!.navigationTrigger).toEqual('hashchange'); + expect(event!.restoredState!.navigationId).toEqual(userVictorNavStart.id); }))); it('should navigate to the same url when config changes', @@ -1115,8 +1128,8 @@ describe('Integration', () => { const user = fixture.debugElement.children[1].componentInstance; let r1: any, r2: any; - router.navigateByUrl('/user/victor') !.then(_ => r1 = _); - router.navigateByUrl('/user/fedor') !.then(_ => r2 = _); + router.navigateByUrl('/user/victor')!.then(_ => r1 = _); + router.navigateByUrl('/user/fedor')!.then(_ => r2 = _); advance(fixture); expect(r1).toEqual(false); // returns false because it was canceled @@ -1185,7 +1198,7 @@ describe('Integration', () => { router.events.forEach(e => recordedEvents.push(e)); let e: any; - router.navigateByUrl('/invalid') !.catch(_ => e = _); + router.navigateByUrl('/invalid')!.catch(_ => e = _); advance(fixture); expect(e.message).toContain('Cannot match any routes'); @@ -1254,7 +1267,7 @@ describe('Integration', () => { router.navigateByUrl('/simple1'); advance(fixture); - const simple1NavStart = event !; + const simple1NavStart = event!; router.navigateByUrl('/throwing').catch(() => null); advance(fixture); @@ -1265,7 +1278,7 @@ describe('Integration', () => { location.back(); tick(); - expect(event !.restoredState !.navigationId).toEqual(simple1NavStart.id); + expect(event!.restoredState!.navigationId).toEqual(simple1NavStart.id); })); it('should not trigger another navigation when resetting the url back due to a NavigationError', @@ -1295,7 +1308,6 @@ describe('Integration', () => { // we do not trigger another navigation to /simple expect(events).toEqual(['/simple', '/throwing']); })); - }); it('should dispatch NavigationCancel after the url has been reset back', fakeAsync(() => { @@ -1341,7 +1353,7 @@ describe('Integration', () => { router.events.forEach(e => recordedEvents.push(e)); let e: any; - router.navigateByUrl('/invalid') !.then(_ => e = _); + router.navigateByUrl('/invalid')!.then(_ => e = _); advance(fixture); expect(e).toEqual('resolvedValue'); @@ -1360,8 +1372,9 @@ describe('Integration', () => { it('should support custom malformed uri error handler', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const customMalformedUriErrorHandler = - (e: URIError, urlSerializer: UrlSerializer, url: string): - UrlTree => { return urlSerializer.parse('/?error=The-URL-you-went-to-is-invalid'); }; + (e: URIError, urlSerializer: UrlSerializer, url: string): UrlTree => { + return urlSerializer.parse('/?error=The-URL-you-went-to-is-invalid'); + }; router.malformedUriErrorHandler = customMalformedUriErrorHandler; router.resetConfig([{path: 'simple', component: SimpleCmp}]); @@ -1482,9 +1495,13 @@ describe('Integration', () => { activations: any[] = []; deactivations: any[] = []; - recordActivate(component: any): void { this.activations.push(component); } + recordActivate(component: any): void { + this.activations.push(component); + } - recordDeactivate(component: any): void { this.deactivations.push(component); } + recordDeactivate(component: any): void { + this.deactivations.push(component); + } } TestBed.configureTestingModule({declarations: [Container]}); @@ -1517,7 +1534,6 @@ describe('Integration', () => { it('should update url and router state before activating components', fakeAsync(inject([Router], (router: Router) => { - const fixture = createRoot(router, RootCmp); router.resetConfig([{path: 'cmp', component: ComponentRecordingRoutePathAndUrl}]); @@ -1535,7 +1551,9 @@ describe('Integration', () => { describe('data', () => { class ResolveSix implements Resolve<number> { - resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): number { return 6; } + resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): number { + return 6; + } } beforeEach(() => { @@ -1601,7 +1619,7 @@ describe('Integration', () => { router.events.subscribe(e => e instanceof RouterEvent && recordedEvents.push(e)); let e: any = null; - router.navigateByUrl('/simple') !.catch(error => e = error); + router.navigateByUrl('/simple')!.catch(error => e = error); advance(fixture); expectEvents(recordedEvents, [ @@ -1695,7 +1713,7 @@ describe('Integration', () => { { provide: 'resolver2', useValue: () => { - return of (null).pipe(map(() => { + return of(null).pipe(map(() => { log.push('resolver2'); observer.next(null); observer.complete(); @@ -1764,9 +1782,8 @@ describe('Integration', () => { router.resetConfig([{ path: 'team/:id', component: TeamCmp, - children: [ - {path: 'link', component: StringLinkCmp}, {path: 'simple', component: SimpleCmp} - ] + children: + [{path: 'link', component: StringLinkCmp}, {path: 'simple', component: SimpleCmp}] }]); router.navigateByUrl('/team/22/link'); @@ -1825,7 +1842,6 @@ describe('Integration', () => { })); it('should update hrefs when query params or fragment change', fakeAsync(() => { - @Component({ selector: 'someRoot', template: @@ -1855,7 +1871,6 @@ describe('Integration', () => { })); it('should correctly use the preserve strategy', fakeAsync(() => { - @Component({ selector: 'someRoot', template: @@ -1877,7 +1892,6 @@ describe('Integration', () => { })); it('should correctly use the merge strategy', fakeAsync(() => { - @Component({ selector: 'someRoot', template: @@ -1905,8 +1919,7 @@ describe('Integration', () => { path: 'team/:id', component: TeamCmp, children: [ - {path: 'link', component: StringLinkButtonCmp}, - {path: 'simple', component: SimpleCmp} + {path: 'link', component: StringLinkButtonCmp}, {path: 'simple', component: SimpleCmp} ] }]); @@ -1928,9 +1941,8 @@ describe('Integration', () => { router.resetConfig([{ path: 'team/:id', component: TeamCmp, - children: [ - {path: 'link', component: AbsoluteLinkCmp}, {path: 'simple', component: SimpleCmp} - ] + children: + [{path: 'link', component: AbsoluteLinkCmp}, {path: 'simple', component: SimpleCmp}] }]); router.navigateByUrl('/team/22/link'); @@ -1951,9 +1963,8 @@ describe('Integration', () => { router.resetConfig([{ path: 'team/:id', component: TeamCmp, - children: [ - {path: 'link', component: RelativeLinkCmp}, {path: 'simple', component: SimpleCmp} - ] + children: + [{path: 'link', component: RelativeLinkCmp}, {path: 'simple', component: SimpleCmp}] }]); router.navigateByUrl('/team/22/link'); @@ -2019,35 +2030,42 @@ describe('Integration', () => { expect(location.path()).toEqual('/team/22/simple?q=1#f'); }))); - it('should support history state', - fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => { - const fixture = createRoot(router, RootCmp); + describe('should support history and state', () => { + let component: typeof LinkWithState|typeof DivLinkWithState; + it('for anchor elements', () => { + // Test logic in afterEach to reduce duplication + component = LinkWithState; + }); - router.resetConfig([{ - path: 'team/:id', - component: TeamCmp, - children: [ - {path: 'link', component: LinkWithState}, {path: 'simple', component: SimpleCmp} - ] - }]); + it('for non-anchor elements', () => { + // Test logic in afterEach to reduce duplication + component = DivLinkWithState; + }); - router.navigateByUrl('/team/22/link'); - advance(fixture); + afterEach(fakeAsync(inject([Router, Location], (router: Router, location: SpyLocation) => { + const fixture = createRoot(router, RootCmp); - const native = fixture.nativeElement.querySelector('a'); - expect(native.getAttribute('href')).toEqual('/team/22/simple'); - native.click(); - advance(fixture); + router.resetConfig([{ + path: 'team/:id', + component: TeamCmp, + children: [{path: 'link', component}, {path: 'simple', component: SimpleCmp}] + }]); - expect(fixture.nativeElement).toHaveText('team 22 [ simple, right: ]'); + router.navigateByUrl('/team/22/link'); + advance(fixture); - // Check the history entry - const history = (location as any)._history; + const native = fixture.nativeElement.querySelector('#link'); + native.click(); + advance(fixture); - expect(history[history.length - 1].state.foo).toBe('bar'); - expect(history[history.length - 1].state) - .toEqual({foo: 'bar', navigationId: history.length}); - }))); + expect(fixture.nativeElement).toHaveText('team 22 [ simple, right: ]'); + + // Check the history entry + const history = (location as any)._history; + expect(history[history.length - 1].state) + .toEqual({foo: 'bar', navigationId: history.length}); + }))); + }); it('should set href on area elements', fakeAsync(() => { @Component({ @@ -2232,7 +2250,9 @@ describe('Integration', () => { } } - beforeEach(() => { TestBed.configureTestingModule({providers: [AlwaysTrue]}); }); + beforeEach(() => { + TestBed.configureTestingModule({providers: [AlwaysTrue]}); + }); it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const fixture = createRoot(router, RootCmp); @@ -2253,7 +2273,9 @@ describe('Integration', () => { providers: [{ provide: 'CanActivate', useValue: (a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { - return Observable.create((observer: any) => { observer.next(false); }); + return Observable.create((observer: any) => { + observer.next(false); + }); } }] }); @@ -2310,7 +2332,9 @@ describe('Integration', () => { TestBed.configureTestingModule({ providers: [{ provide: 'alwaysFalse', - useValue: (a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { return false; } + useValue: (a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { + return false; + } }] }); }); @@ -2330,7 +2354,6 @@ describe('Integration', () => { location.go('/two'); advance(fixture); expect(location.path()).toEqual('/one'); - }))); }); @@ -2368,12 +2391,16 @@ describe('Integration', () => { providers: [ { provide: 'returnUrlTree', - useFactory: (router: Router) => () => { return router.parseUrl('/redirected'); }, + useFactory: (router: Router) => () => { + return router.parseUrl('/redirected'); + }, deps: [Router] }, { provide: 'returnRootUrlTree', - useFactory: (router: Router) => () => { return router.parseUrl('/'); }, + useFactory: (router: Router) => () => { + return router.parseUrl('/'); + }, deps: [Router] } ] @@ -2381,7 +2408,7 @@ describe('Integration', () => { it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const recordedEvents: any[] = []; - let cancelEvent: NavigationCancel = null !; + let cancelEvent: NavigationCancel = null!; router.events.forEach((e: any) => { recordedEvents.push(e); if (e instanceof NavigationCancel) cancelEvent = e; @@ -2425,7 +2452,7 @@ describe('Integration', () => { it('works with root url', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const recordedEvents: any[] = []; - let cancelEvent: NavigationCancel = null !; + let cancelEvent: NavigationCancel = null!; router.events.forEach((e: any) => { recordedEvents.push(e); if (e instanceof NavigationCancel) cancelEvent = e; @@ -2492,7 +2519,9 @@ describe('Integration', () => { {path: 'redirected', component: SimpleCmp} ]); const fixture = createRoot(router, RootCmp); - router.navigateByUrl('/one').then(v => { resolvedPath = location.path(); }); + router.navigateByUrl('/one').then(v => { + resolvedPath = location.path(); + }); tick(); expect(resolvedPath).toBe('/redirected'); @@ -2541,7 +2570,8 @@ describe('Integration', () => { }, { path: 'd/:param', - component: WrapperCmp, runGuardsAndResolvers, + component: WrapperCmp, + runGuardsAndResolvers, children: [ { path: 'e/:param', @@ -2883,14 +2913,15 @@ describe('Integration', () => { { provide: 'RecordingDeactivate', useValue: (c: any, a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { - log.push({path: a.routeConfig !.path, component: c}); + log.push({path: a.routeConfig!.path, component: c}); return true; } }, { provide: 'alwaysFalse', - useValue: - (c: any, a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { return false; } + useValue: (c: any, a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { + return false; + } }, { provide: 'alwaysFalseAndLogging', @@ -2932,13 +2963,13 @@ describe('Integration', () => { expect(location.path()).toEqual('/team/22'); let successStatus: boolean = false; - router.navigateByUrl('/team/33') !.then(res => successStatus = res); + router.navigateByUrl('/team/33')!.then(res => successStatus = res); advance(fixture); expect(location.path()).toEqual('/team/33'); expect(successStatus).toEqual(true); let canceledStatus: boolean = false; - router.navigateByUrl('/team/44') !.then(res => canceledStatus = res); + router.navigateByUrl('/team/44')!.then(res => canceledStatus = res); advance(fixture); expect(location.path()).toEqual('/team/33'); expect(canceledStatus).toEqual(false); @@ -3143,11 +3174,12 @@ describe('Integration', () => { providers: [ ClassWithNextState, { provide: 'FunctionWithNextState', - useValue: (cmp: any, currentRoute: ActivatedRouteSnapshot, - currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => { - log.push(currentState.url, nextState.url); - return true; - } + useValue: + (cmp: any, currentRoute: ActivatedRouteSnapshot, + currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => { + log.push(currentState.url, nextState.url); + return true; + } } ] }); @@ -3198,7 +3230,9 @@ describe('Integration', () => { } } - beforeEach(() => { TestBed.configureTestingModule({providers: [AlwaysTrue]}); }); + beforeEach(() => { + TestBed.configureTestingModule({providers: [AlwaysTrue]}); + }); it('works', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const fixture = createRoot(router, RootCmp); @@ -3223,7 +3257,9 @@ describe('Integration', () => { providers: [{ provide: 'CanDeactivate', useValue: (c: TeamCmp, a: ActivatedRouteSnapshot, b: RouterStateSnapshot) => { - return Observable.create((observer: any) => { observer.next(false); }); + return Observable.create((observer: any) => { + observer.next(false); + }); } }] }); @@ -3271,7 +3307,7 @@ describe('Integration', () => { expect(location.path()).toEqual('/team/22'); - router.navigateByUrl('/team/33') !.catch(() => {}); + router.navigateByUrl('/team/33')!.catch(() => {}); advance(fixture); expect(location.path()).toEqual('/team/22'); @@ -3282,7 +3318,6 @@ describe('Integration', () => { fakeAsync(inject( [Router, Location, NgModuleFactoryLoader], (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - @Component({selector: 'admin', template: '<router-outlet></router-outlet>'}) class AdminComponent { } @@ -3350,7 +3385,6 @@ describe('Integration', () => { fakeAsync(inject( [Router, Location, NgModuleFactoryLoader], (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - @Component({selector: 'lazy', template: 'lazy-loaded'}) class LazyLoadedComponent { } @@ -3418,7 +3452,6 @@ describe('Integration', () => { it('should support navigating from within the guard', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { - const fixture = createRoot(router, RootCmp); router.resetConfig([ @@ -3454,7 +3487,6 @@ describe('Integration', () => { fakeAsync(inject( [Router, Location, NgModuleFactoryLoader], (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - @Component({selector: 'lazy', template: 'lazy-loaded'}) class LazyLoadedComponent { } @@ -3477,21 +3509,23 @@ describe('Integration', () => { let navFalseResult: any; let navTrueResult: any; - router.navigateByUrl('/lazy-false').then(v => { navFalseResult = v; }); + router.navigateByUrl('/lazy-false').then(v => { + navFalseResult = v; + }); advance(fixture); - router.navigateByUrl('/lazy-true').then(v => { navTrueResult = v; }); + router.navigateByUrl('/lazy-true').then(v => { + navTrueResult = v; + }); advance(fixture); expect(navFalseResult).toBe(false); expect(navTrueResult).toBe(true); - }))); it('should execute CanLoad only once', fakeAsync(inject( [Router, Location, NgModuleFactoryLoader], (router: Router, location: Location, loader: SpyNgModuleFactoryLoader) => { - @Component({selector: 'lazy', template: 'lazy-loaded'}) class LazyLoadedComponent { } @@ -3526,10 +3560,11 @@ describe('Integration', () => { }); describe('order', () => { - class Logger { logs: string[] = []; - add(thing: string) { this.logs.push(thing); } + add(thing: string) { + this.logs.push(thing); + } } beforeEach(() => { @@ -3664,7 +3699,7 @@ describe('Integration', () => { tap(e => recordedEvents.push(e)), filter((e): e is NavigationStart => e instanceof NavigationStart), first()); - navStart$.subscribe((e: NavigationStart | NavigationError) => { + navStart$.subscribe((e: NavigationStart|NavigationError) => { router.navigate( ['/blank'], {queryParams: {state: 'redirected'}, queryParamsHandling: 'merge'}); advance(fixture); @@ -3674,7 +3709,6 @@ describe('Integration', () => { advance(fixture); expect(navigateSpy.calls.mostRecent().args[1].queryParams); - }))); }); @@ -3689,8 +3723,7 @@ describe('Integration', () => { children: [{ path: 'link', component: DummyLinkCmp, - children: - [{path: 'simple', component: SimpleCmp}, {path: '', component: BlankCmp}] + children: [{path: 'simple', component: SimpleCmp}, {path: '', component: BlankCmp}] }] }]); @@ -3745,8 +3778,7 @@ describe('Integration', () => { children: [{ path: 'link', component: DummyLinkWithParentCmp, - children: - [{path: 'simple', component: SimpleCmp}, {path: '', component: BlankCmp}] + children: [{path: 'simple', component: SimpleCmp}, {path: '', component: BlankCmp}] }] }]); @@ -3774,8 +3806,7 @@ describe('Integration', () => { children: [{ path: 'link', component: DummyLinkCmp, - children: - [{path: 'simple', component: SimpleCmp}, {path: '', component: BlankCmp}] + children: [{path: 'simple', component: SimpleCmp}, {path: '', component: BlankCmp}] }] }]); @@ -3831,7 +3862,6 @@ describe('Integration', () => { advance(fixture); expect(paragraph.textContent).toEqual('false'); })); - }); describe('lazy loading', () => { @@ -3934,8 +3964,8 @@ describe('Integration', () => { expect(location.path()).toEqual('/lazy/parent/child'); expect(fixture.nativeElement).toHaveText('parent[child]'); - const pInj = fixture.debugElement.query(By.directive(Parent)).injector !; - const cInj = fixture.debugElement.query(By.directive(Child)).injector !; + const pInj = fixture.debugElement.query(By.directive(Parent)).injector!; + const cInj = fixture.debugElement.query(By.directive(Child)).injector!; expect(pInj.get('moduleName')).toEqual('parent'); expect(pInj.get('fromParent')).toEqual('from parent'); @@ -3989,7 +4019,9 @@ describe('Integration', () => { }) class LoadedModule { static instances = 0; - constructor() { LoadedModule.instances++; } + constructor() { + LoadedModule.instances++; + } } loader.stubbedModules = {expected: LoadedModule}; @@ -4121,7 +4153,7 @@ describe('Integration', () => { router.resetConfig([{path: 'lazy', loadChildren: 'expected'}]); let recordedError: any = null; - router.navigateByUrl('/lazy/loaded') !.catch(err => recordedError = err); + router.navigateByUrl('/lazy/loaded')!.catch(err => recordedError = err); advance(fixture); expect(recordedError.message) .toEqual( @@ -4178,7 +4210,6 @@ describe('Integration', () => { it('should allow lazy loaded module in named outlet', fakeAsync(inject( [Router, NgModuleFactoryLoader], (router: Router, loader: SpyNgModuleFactoryLoader) => { - @Component({selector: 'lazy', template: 'lazy-loaded'}) class LazyComponent { } @@ -4218,7 +4249,6 @@ describe('Integration', () => { it('should allow componentless named outlet to render children', fakeAsync(inject( [Router, NgModuleFactoryLoader], (router: Router, loader: SpyNgModuleFactoryLoader) => { - const fixture = createRoot(router, RootCmp); router.resetConfig([{ @@ -4269,7 +4299,7 @@ describe('Integration', () => { lazyService: LazyLoadedServiceDefinedInModule, // should be able to inject lazy service eager: EagerParentComponent // should use the injector of the location to create a parent - ) {} + ) {} } @NgModule({ @@ -4360,7 +4390,7 @@ describe('Integration', () => { const recordedEvents: any[] = []; router.events.forEach(e => recordedEvents.push(e)); - router.navigateByUrl('/lazy/loaded') !.catch(s => {}); + router.navigateByUrl('/lazy/loaded')!.catch(s => {}); advance(fixture); expect(location.path()).toEqual('/'); @@ -4469,16 +4499,15 @@ describe('Integration', () => { advance(fixture); const config = router.config as any; - const firstConfig = config[1]._loadedConfig !; + const firstConfig = config[1]._loadedConfig!; expect(firstConfig).toBeDefined(); expect(firstConfig.routes[0].path).toEqual('LoadedModule1'); - const secondConfig = firstConfig.routes[0]._loadedConfig !; + const secondConfig = firstConfig.routes[0]._loadedConfig!; expect(secondConfig).toBeDefined(); expect(secondConfig.routes[0].path).toEqual('LoadedModule2'); }))); - }); describe('custom url handling strategies', () => { @@ -4528,9 +4557,8 @@ describe('Integration', () => { router.resetConfig([{ path: 'include', component: TeamCmp, - children: [ - {path: 'user/:name', component: UserCmp}, {path: 'simple', component: SimpleCmp} - ] + children: + [{path: 'user/:name', component: UserCmp}, {path: 'simple', component: SimpleCmp}] }]); const events: any[] = []; @@ -4592,9 +4620,8 @@ describe('Integration', () => { router.resetConfig([{ path: 'include', component: TeamCmp, - children: [ - {path: 'user/:name', component: UserCmp}, {path: 'simple', component: SimpleCmp} - ] + children: + [{path: 'user/:name', component: UserCmp}, {path: 'simple', component: SimpleCmp}] }]); const events: any[] = []; @@ -4686,19 +4713,19 @@ describe('Integration', () => { stored: {[k: string]: DetachedRouteHandle} = {}; shouldDetach(route: ActivatedRouteSnapshot): boolean { - return route.routeConfig !.path === 'a'; + return route.routeConfig!.path === 'a'; } store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void { - this.stored[route.routeConfig !.path !] = detachedTree; + this.stored[route.routeConfig!.path!] = detachedTree; } shouldAttach(route: ActivatedRouteSnapshot): boolean { - return !!this.stored[route.routeConfig !.path !]; + return !!this.stored[route.routeConfig!.path!]; } retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle { - return this.stored[route.routeConfig !.path !]; + return this.stored[route.routeConfig!.path!]; } shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { @@ -4707,10 +4734,16 @@ describe('Integration', () => { } class ShortLifecycle implements RouteReuseStrategy { - shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; } + shouldDetach(route: ActivatedRouteSnapshot): boolean { + return false; + } store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {} - shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; } - retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; } + shouldAttach(route: ActivatedRouteSnapshot): boolean { + return false; + } + retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { + return null; + } shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { if (future.routeConfig !== curr.routeConfig) { return false; @@ -4804,7 +4837,9 @@ describe('Integration', () => { !!router.parseUrl(router.url).root.children['toolpanel']); } - public ngOnDestroy(): void { this.subscription.unsubscribe(); } + public ngOnDestroy(): void { + this.subscription.unsubscribe(); + } } @Component({selector: 'tool-1-cmp', template: 'Tool 1 showing'}) @@ -4876,7 +4911,6 @@ describe('Testing router options', () => { }); describe('malformedUriErrorHandler', () => { - function malformedUriErrorHandler(e: URIError, urlSerializer: UrlSerializer, url: string) { return urlSerializer.parse('/error'); } @@ -4951,11 +4985,18 @@ class LinkWithQueryParamsAndFragment { @Component({ selector: 'link-cmp', - template: `<a [routerLink]="['../simple']" [state]="{foo: 'bar'}">link</a>` + template: `<a id="link" [routerLink]="['../simple']" [state]="{foo: 'bar'}">link</a>` }) class LinkWithState { } +@Component({ + selector: 'div-link-cmp', + template: `<div id="link" [routerLink]="['../simple']" [state]="{foo: 'bar'}">link</div>` +}) +class DivLinkWithState { +} + @Component({selector: 'simple-cmp', template: `simple`}) class SimpleCmp { } @@ -5078,7 +5119,9 @@ class OutletInNgIf { }) class DummyLinkWithParentCmp { private exact: boolean; - constructor(route: ActivatedRoute) { this.exact = (<any>route.snapshot.params).exact === 'true'; } + constructor(route: ActivatedRoute) { + this.exact = (<any>route.snapshot.params).exact === 'true'; + } } @Component({selector: 'cmp', template: ''}) @@ -5100,7 +5143,9 @@ class RootCmp { class RootCmpWithOnInit { constructor(private router: Router) {} - ngOnInit(): void { this.router.navigate(['one']); } + ngOnInit(): void { + this.router.navigate(['one']); + } } @Component({ @@ -5117,7 +5162,9 @@ class RootCmpWithNamedOutlet { @Component({selector: 'throwing-cmp', template: ''}) class ThrowingCmp { - constructor() { throw new Error('Throwing Cmp'); } + constructor() { + throw new Error('Throwing Cmp'); + } } @@ -5155,6 +5202,7 @@ class LazyComponent { RelativeLinkCmp, DummyLinkWithParentCmp, LinkWithQueryParamsAndFragment, + DivLinkWithState, LinkWithState, CollectParamsCmp, QueryParamsAndFragmentCmp, @@ -5185,6 +5233,7 @@ class LazyComponent { RelativeLinkCmp, DummyLinkWithParentCmp, LinkWithQueryParamsAndFragment, + DivLinkWithState, LinkWithState, CollectParamsCmp, QueryParamsAndFragmentCmp, @@ -5217,6 +5266,7 @@ class LazyComponent { RelativeLinkCmp, DummyLinkWithParentCmp, LinkWithQueryParamsAndFragment, + DivLinkWithState, LinkWithState, CollectParamsCmp, QueryParamsAndFragmentCmp, From 1dd0b6cc18b0fe9112cd2c7be745ef5a788642aa Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@google.com> Date: Mon, 6 Apr 2020 19:47:29 -0700 Subject: [PATCH 136/262] test(language-service): remove ng-if-cases.ts (#36470) This commit removes ng-if-cases.ts and moves all test cases to inline expressions in TEST_TEMPLATE. PR Close #36470 --- .../language-service/test/project/app/main.ts | 2 -- .../test/project/app/ng-if-cases.ts | 19 ------------------- .../language-service/test/ts_plugin_spec.ts | 4 ++-- 3 files changed, 2 insertions(+), 23 deletions(-) delete mode 100644 packages/language-service/test/project/app/ng-if-cases.ts diff --git a/packages/language-service/test/project/app/main.ts b/packages/language-service/test/project/app/main.ts index 27f0f8d17ce21..8a9a97f805df1 100644 --- a/packages/language-service/test/project/app/main.ts +++ b/packages/language-service/test/project/app/main.ts @@ -11,7 +11,6 @@ import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {AppComponent} from './app.component'; import * as NgForCases from './ng-for-cases'; -import * as NgIfCases from './ng-if-cases'; import * as ParsingCases from './parsing-cases'; @NgModule({ @@ -21,7 +20,6 @@ import * as ParsingCases from './parsing-cases'; NgForCases.UnknownEven, NgForCases.UnknownPeople, NgForCases.UnknownTrackBy, - NgIfCases.ShowIf, ParsingCases.AsyncForUsingComponent, ParsingCases.CaseIncompleteOpen, ParsingCases.CaseMissingClosing, diff --git a/packages/language-service/test/project/app/ng-if-cases.ts b/packages/language-service/test/project/app/ng-if-cases.ts deleted file mode 100644 index 3c9917d772280..0000000000000 --- a/packages/language-service/test/project/app/ng-if-cases.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {Component} from '@angular/core'; - -@Component({ - template: ` - <div ~{start-implicit}*ngIf="show; let l=unknown"~{end-implicit}> - Showing now! - </div>`, -}) -export class ShowIf { - show = false; -} diff --git a/packages/language-service/test/ts_plugin_spec.ts b/packages/language-service/test/ts_plugin_spec.ts index 84817cf1ad1ca..3831e67fe2076 100644 --- a/packages/language-service/test/ts_plugin_spec.ts +++ b/packages/language-service/test/ts_plugin_spec.ts @@ -57,8 +57,8 @@ describe('plugin', () => { const compilerDiags = tsLS.getCompilerOptionsDiagnostics(); expect(compilerDiags).toEqual([]); const sourceFiles = program.getSourceFiles().filter(f => !f.fileName.endsWith('.d.ts')); - // there are five .ts files in the test project - expect(sourceFiles.length).toBe(5); + // there are three .ts files in the test project + expect(sourceFiles.length).toBe(3); for (const {fileName} of sourceFiles) { const syntacticDiags = tsLS.getSyntacticDiagnostics(fileName); expect(syntacticDiags).toEqual([]); From 7f28845f5857184de8259f47b80daa85afc83de1 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@google.com> Date: Mon, 6 Apr 2020 20:04:56 -0700 Subject: [PATCH 137/262] test(language-service): remove ng-for-cases.ts (#36470) This commit removes ng-for-cases.ts and moves all test cases to inline expressions in TEST_TEMPLATE. PR Close #36470 --- .../language-service/test/diagnostics_spec.ts | 30 ++++++------- .../language-service/test/project/app/main.ts | 4 -- .../test/project/app/ng-for-cases.ts | 43 ------------------- 3 files changed, 15 insertions(+), 62 deletions(-) delete mode 100644 packages/language-service/test/project/app/ng-for-cases.ts diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index 1bea06f6cd086..d8e0218954494 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -274,22 +274,22 @@ describe('diagnostics', () => { expect(diags).toContain('Expected a number type'); }); - describe('in ng-for-cases.ts', () => { - it('should report an unknown field', () => { - const diags = ngLS.getSemanticDiagnostics(NG_FOR_CASES).map(d => d.messageText); - expect(diags).toContain( - `Identifier 'people_1' is not defined. ` + - `The component declaration, template variable declarations, ` + - `and element references do not contain such a member`); - }); + it('should report an unknown field', () => { + mockHost.override(TEST_TEMPLATE, `<div *ngFor="let person of people"></div>`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE).map(d => d.messageText); + expect(diags).toContain( + `Identifier 'people' is not defined. ` + + `The component declaration, template variable declarations, ` + + `and element references do not contain such a member`); + }); - it('should report an unknown value in a key expression', () => { - const diags = ngLS.getSemanticDiagnostics(NG_FOR_CASES).map(d => d.messageText); - expect(diags).toContain( - `Identifier 'trackBy_1' is not defined. ` + - `The component declaration, template variable declarations, ` + - `and element references do not contain such a member`); - }); + it('should report an unknown value in a key expression', () => { + mockHost.override(TEST_TEMPLATE, `<div *ngFor="let hero of heroes; trackBy: trackByFn"></div>`); + const diags = ngLS.getSemanticDiagnostics(TEST_TEMPLATE).map(d => d.messageText); + expect(diags).toContain( + `Identifier 'trackByFn' is not defined. ` + + `The component declaration, template variable declarations, ` + + `and element references do not contain such a member`); }); describe('embedded templates', () => { diff --git a/packages/language-service/test/project/app/main.ts b/packages/language-service/test/project/app/main.ts index 8a9a97f805df1..85d2b7a440b34 100644 --- a/packages/language-service/test/project/app/main.ts +++ b/packages/language-service/test/project/app/main.ts @@ -10,16 +10,12 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {AppComponent} from './app.component'; -import * as NgForCases from './ng-for-cases'; import * as ParsingCases from './parsing-cases'; @NgModule({ imports: [CommonModule, FormsModule], declarations: [ AppComponent, - NgForCases.UnknownEven, - NgForCases.UnknownPeople, - NgForCases.UnknownTrackBy, ParsingCases.AsyncForUsingComponent, ParsingCases.CaseIncompleteOpen, ParsingCases.CaseMissingClosing, diff --git a/packages/language-service/test/project/app/ng-for-cases.ts b/packages/language-service/test/project/app/ng-for-cases.ts deleted file mode 100644 index 9b46ed5dc3dca..0000000000000 --- a/packages/language-service/test/project/app/ng-for-cases.ts +++ /dev/null @@ -1,43 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {Component} from '@angular/core'; - -export interface Person { - name: string; - age: number; -} - -@Component({ - template: ` - <div *ngFor="let person of ~{start-people_1}people_1~{end-people_1}"> - <span>{{person.name}}</span> - </div>`, -}) -export class UnknownPeople { -} - -@Component({ - template: ` - <div ~{start-even_1}*ngFor="let person of people; let e = even_1"~{end-even_1}> - <span>{{person.name}}</span> - </div>`, -}) -export class UnknownEven { - people: Person[] = []; -} - -@Component({ - template: ` - <div *ngFor="let person of people; trackBy ~{start-trackBy_1}trackBy_1~{end-trackBy_1}"> - <span>{{person.name}}</span> - </div>`, -}) -export class UnknownTrackBy { - people: Person[] = []; -} From 4a18428de6afc12c8106898ca767a82491ee11f1 Mon Sep 17 00:00:00 2001 From: Stanislav Usov <stasusov@users.noreply.github.com> Date: Tue, 7 Apr 2020 11:23:21 +0300 Subject: [PATCH 138/262] docs(forms): Remove unnecessary repeating periods (#36474) PR Close #36474 --- packages/forms/src/model.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index 4dbe67666fb2f..169f9e7446ab1 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -480,7 +480,7 @@ export abstract class AbstractControl { * @param opts Configuration options that determine how the control emits events after * marking is applied. * * `onlySelf`: When true, mark only this control. When false or not supplied, - * marks all direct ancestors. Default is false.. + * marks all direct ancestors. Default is false. */ markAsPristine(opts: {onlySelf?: boolean} = {}): void { (this as {pristine: boolean}).pristine = true; @@ -505,7 +505,7 @@ export abstract class AbstractControl { * @param opts Configuration options that determine how the control propagates changes and * emits events after marking is applied. * * `onlySelf`: When true, mark only this control. When false or not supplied, - * marks all direct ancestors. Default is false.. + * marks all direct ancestors. Default is false. * * `emitEvent`: When true or not supplied (the default), the `statusChanges` * observable emits an event with the latest status the control is marked pending. * When false, no events are emitted. @@ -534,7 +534,7 @@ export abstract class AbstractControl { * @param opts Configuration options that determine how the control propagates * changes and emits events after the control is disabled. * * `onlySelf`: When true, mark only this control. When false or not supplied, - * marks all direct ancestors. Default is false.. + * marks all direct ancestors. Default is false. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` * observables emit events with the latest status and value when the control is disabled. @@ -573,7 +573,7 @@ export abstract class AbstractControl { * @param opts Configure options that control how the control propagates changes and * emits events when marked as untouched * * `onlySelf`: When true, mark only this control. When false or not supplied, - * marks all direct ancestors. Default is false.. + * marks all direct ancestors. Default is false. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` * observables emit events with the latest status and value when the control is enabled. @@ -635,7 +635,7 @@ export abstract class AbstractControl { * @param opts Configuration options determine how the control propagates changes and emits events * after updates and validity checks are applied. * * `onlySelf`: When true, only update this control. When false or not supplied, - * update all direct ancestors. Default is false.. + * update all direct ancestors. Default is false. * * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and * `valueChanges` * observables emit events with the latest status and value when the control is updated. From 00027130ea06231d23865dbb7172c2ed10e58c1e Mon Sep 17 00:00:00 2001 From: Ajit Singh <ajitsinghkaler0@gmail.com> Date: Sun, 8 Mar 2020 16:36:37 +0530 Subject: [PATCH 139/262] fix(docs-infra): fix resources page tabs text which is not visible on small screens (#35935) on small mobile screens the top tab bar contains text which was not visible on small screens changed text size, margin and padding so that the text could be contained in these screens (320px to 480px) PR Close #35935 --- aio/src/styles/2-modules/_resources.scss | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/aio/src/styles/2-modules/_resources.scss b/aio/src/styles/2-modules/_resources.scss index 890f051e96024..e698e699b0949 100644 --- a/aio/src/styles/2-modules/_resources.scss +++ b/aio/src/styles/2-modules/_resources.scss @@ -11,6 +11,18 @@ .resources-container { position: relative; + .group-buttons{ + @media (max-width: 480px) { + .button, a.button.mat-button{ + font-size:1.2rem; + padding:0; + } + + a.filter-button{ + margin: 0; + } + } + } } .grid-fixed:after, .grid-fixed:before { From 96a3de6364e58f24a5b852d583c78a8981ddde18 Mon Sep 17 00:00:00 2001 From: Ajit Singh <ajitsinghkaler0@gmail.com> Date: Sun, 8 Mar 2020 20:15:42 +0530 Subject: [PATCH 140/262] style(docs-infra): removed extra , from _resources.scss file (#35935) there was a typo in _resourcess.scss file there was an extra comma added some spaces too that were needed for proper styling of the code PR Close #35935 --- aio/src/styles/2-modules/_resources.scss | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/aio/src/styles/2-modules/_resources.scss b/aio/src/styles/2-modules/_resources.scss index e698e699b0949..ac6cf5be2f724 100644 --- a/aio/src/styles/2-modules/_resources.scss +++ b/aio/src/styles/2-modules/_resources.scss @@ -11,14 +11,13 @@ .resources-container { position: relative; - .group-buttons{ - @media (max-width: 480px) { - .button, a.button.mat-button{ - font-size:1.2rem; - padding:0; - } - a.filter-button{ + .group-buttons { + + @media (max-width: 480px) { + .button { + font-size: 1.2rem; + padding: 0; margin: 0; } } @@ -65,11 +64,11 @@ @media handheld and (max-width: 900px), screen and (max-width: 900px) { /* line 6, ../scss/_responsive.scss */ - .grid-fixed{ + .grid-fixed { margin: 0 auto; *zoom: 1; } - .grid-fixed:after, .grid-fixed:before, { + .grid-fixed:after, .grid-fixed:before { content: '.'; clear: both; display: block; @@ -181,7 +180,7 @@ aio-resource-list { flex-direction: column; } - .align-items-center{ + .align-items-center { align-items: center; } @@ -231,7 +230,7 @@ aio-resource-list { transform: translateY(-2px); } - @media(max-width: 900px) { + @media (max-width: 900px) { .c-resource-nav { display: none; } From 81195a238b91cefc35867b8cc0b115141761d577 Mon Sep 17 00:00:00 2001 From: ivanwonder <ivanwonder@outlook.com> Date: Wed, 1 Apr 2020 21:29:01 +0800 Subject: [PATCH 141/262] fix(language-service): use the `HtmlAst` to get the span of HTML tag (#36371) The HTML tag may include `-` (e.g. `app-root`), so use the `HtmlAst` to get the span. PR Close #36371 --- packages/language-service/src/completions.ts | 14 ++++++++++++-- packages/language-service/test/completions_spec.ts | 10 +++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index e5afe71617630..80f7b363bee58 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -55,12 +55,22 @@ function isIdentifierPart(code: number) { * Gets the span of word in a template that surrounds `position`. If there is no word around * `position`, nothing is returned. */ -function getBoundedWordSpan(templateInfo: AstResult, position: number): ts.TextSpan|undefined { +function getBoundedWordSpan( + templateInfo: AstResult, position: number, ast: HtmlAst|undefined): ts.TextSpan|undefined { const {template} = templateInfo; const templateSrc = template.source; if (!templateSrc) return; + if (ast instanceof Element) { + // The HTML tag may include `-` (e.g. `app-root`), + // so use the HtmlAst to get the span before ayazhafiz refactor the code. + return { + start: templateInfo.template.span.start + ast.startSourceSpan!.start.offset + 1, + length: ast.name.length + }; + } + // TODO(ayazhafiz): A solution based on word expansion will always be expensive compared to one // based on ASTs. Whatever penalty we incur is probably manageable for small-length (i.e. the // majority of) identifiers, but the current solution involes a number of branchings and we can't @@ -185,7 +195,7 @@ export function getTemplateCompletions( null); } - const replacementSpan = getBoundedWordSpan(templateInfo, position); + const replacementSpan = getBoundedWordSpan(templateInfo, position, mostSpecific); return result.map(entry => { return { ...entry, diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index 0bf3e4238e8c6..96f6c52c13b01 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -670,18 +670,18 @@ describe('completions', () => { @Component({ selector: 'foo-component', template: \` - <di~{div}></div> + <test-comp~{test-comp}></test-comp> \`, }) export class FooComponent {} `); - const location = mockHost.getLocationMarkerFor(fileName, 'div'); + const location = mockHost.getLocationMarkerFor(fileName, 'test-comp'); const completions = ngLS.getCompletionsAtPosition(fileName, location.start)!; expect(completions).toBeDefined(); - const completion = completions.entries.find(entry => entry.name === 'div')!; + const completion = completions.entries.find(entry => entry.name === 'test-comp')!; expect(completion).toBeDefined(); - expect(completion.kind).toBe('html element'); - expect(completion.replacementSpan).toEqual({start: location.start - 2, length: 2}); + expect(completion.kind).toBe('component'); + expect(completion.replacementSpan).toEqual({start: location.start - 9, length: 9}); }); it('should work for bindings', () => { From aecf9de7383986be245feb9c115666728e02312e Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Wed, 1 Apr 2020 17:31:04 +0300 Subject: [PATCH 142/262] fix(ngcc): correctly identify relative Windows-style import paths (#36372) Previously, `isRelativePath()` assumed paths are *nix-style. This caused Windows-style paths (such as `C:\foo\some-package\some-file.js`) to not be recognized as "relative" imports. This commit fixes this by using the OS-agnostic `isRooted()` helper and also accounting for both styles of path delimiters: `/` and `\` PR Close #36372 --- packages/compiler-cli/ngcc/src/utils.ts | 7 ++- .../test/dependencies/module_resolver_spec.ts | 15 ++++- packages/compiler-cli/ngcc/test/utils_spec.ts | 56 +++++++++++-------- .../src/ngtsc/file_system/index.ts | 2 +- .../src/ngtsc/file_system/src/helpers.ts | 11 +++- 5 files changed, 60 insertions(+), 31 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/utils.ts b/packages/compiler-cli/ngcc/src/utils.ts index f729abe386bcb..acd7ea69fae03 100644 --- a/packages/compiler-cli/ngcc/src/utils.ts +++ b/packages/compiler-cli/ngcc/src/utils.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {absoluteFrom, AbsoluteFsPath, FileSystem} from '../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, isRooted} from '../../src/ngtsc/file_system'; import {KnownDeclaration} from '../../src/ngtsc/reflection'; /** @@ -85,10 +85,11 @@ export type PathMappings = { /** * Test whether a path is "relative". * - * Relative paths start with `/`, `./` or `../`; or are simply `.` or `..`. + * Relative paths start with `/`, `./` or `../` (or the Windows equivalents); or are simply `.` or + * `..`. */ export function isRelativePath(path: string): boolean { - return /^\/|^\.\.?($|\/)/.test(path); + return isRooted(path) || /^\.\.?(\/|\\|$)/.test(path); } /** diff --git a/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts index 2ef140ca71b0b..503c157161051 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/module_resolver_spec.ts @@ -67,16 +67,29 @@ runInEachFileSystem(() => { ]); }); - describe('resolveModule()', () => { + describe('resolveModuleImport()', () => { describe('with relative paths', () => { it('should resolve sibling, child and aunt modules', () => { const resolver = new ModuleResolver(getFileSystem()); + + // With relative file paths. expect(resolver.resolveModuleImport('./x', _('/libs/local-package/index.js'))) .toEqual(new ResolvedRelativeModule(_('/libs/local-package/x.js'))); expect(resolver.resolveModuleImport('./sub-folder', _('/libs/local-package/index.js'))) .toEqual(new ResolvedRelativeModule(_('/libs/local-package/sub-folder/index.js'))); expect(resolver.resolveModuleImport('../x', _('/libs/local-package/sub-folder/index.js'))) .toEqual(new ResolvedRelativeModule(_('/libs/local-package/x.js'))); + + // With absolute file paths. + expect(resolver.resolveModuleImport( + _('/libs/local-package/x'), _('/libs/local-package/index.js'))) + .toEqual(new ResolvedRelativeModule(_('/libs/local-package/x.js'))); + expect(resolver.resolveModuleImport( + _('/libs/local-package/sub-folder'), _('/libs/local-package/index.js'))) + .toEqual(new ResolvedRelativeModule(_('/libs/local-package/sub-folder/index.js'))); + expect(resolver.resolveModuleImport( + _('/libs/local-package/x'), _('/libs/local-package/sub-folder/index.js'))) + .toEqual(new ResolvedRelativeModule(_('/libs/local-package/x.js'))); }); it('should return `null` if the resolved module relative module does not exist', () => { diff --git a/packages/compiler-cli/ngcc/test/utils_spec.ts b/packages/compiler-cli/ngcc/test/utils_spec.ts index f373e5313a013..d01b1e3e9a08c 100644 --- a/packages/compiler-cli/ngcc/test/utils_spec.ts +++ b/packages/compiler-cli/ngcc/test/utils_spec.ts @@ -7,6 +7,8 @@ */ import * as ts from 'typescript'; +import {absoluteFrom as _abs} from '../../src/ngtsc/file_system'; +import {runInEachFileSystem} from '../../src/ngtsc/file_system/testing'; import {KnownDeclaration} from '../../src/ngtsc/reflection'; import {FactoryMap, getTsHelperFnFromDeclaration, getTsHelperFnFromIdentifier, isRelativePath, stripExtension} from '../src/utils'; @@ -167,30 +169,36 @@ describe('getTsHelperFnFromIdentifier()', () => { }); }); -describe('isRelativePath()', () => { - it('should return true for relative paths', () => { - expect(isRelativePath('.')).toBe(true); - expect(isRelativePath('..')).toBe(true); - expect(isRelativePath('./')).toBe(true); - expect(isRelativePath('../')).toBe(true); - expect(isRelativePath('./abc/xyz')).toBe(true); - expect(isRelativePath('../abc/xyz')).toBe(true); - }); - - it('should return true for absolute paths', () => { - expect(isRelativePath('/')).toBe(true); - expect(isRelativePath('/abc/xyz')).toBe(true); - }); - - it('should return false for other paths', () => { - expect(isRelativePath('abc')).toBe(false); - expect(isRelativePath('abc/xyz')).toBe(false); - expect(isRelativePath('.abc')).toBe(false); - expect(isRelativePath('..abc')).toBe(false); - expect(isRelativePath('@abc')).toBe(false); - expect(isRelativePath('.abc/xyz')).toBe(false); - expect(isRelativePath('..abc/xyz')).toBe(false); - expect(isRelativePath('@abc/xyz')).toBe(false); +runInEachFileSystem(() => { + describe('isRelativePath()', () => { + it('should return true for relative paths', () => { + expect(isRelativePath('.')).toBe(true); + expect(isRelativePath('..')).toBe(true); + expect(isRelativePath('./')).toBe(true); + expect(isRelativePath('.\\')).toBe(true); + expect(isRelativePath('../')).toBe(true); + expect(isRelativePath('..\\')).toBe(true); + expect(isRelativePath('./abc/xyz')).toBe(true); + expect(isRelativePath('.\\abc\\xyz')).toBe(true); + expect(isRelativePath('../abc/xyz')).toBe(true); + expect(isRelativePath('..\\abc\\xyz')).toBe(true); + }); + + it('should return true for absolute paths', () => { + expect(isRelativePath(_abs('/'))).toBe(true); + expect(isRelativePath(_abs('/abc/xyz'))).toBe(true); + }); + + it('should return false for other paths', () => { + expect(isRelativePath('abc')).toBe(false); + expect(isRelativePath('abc/xyz')).toBe(false); + expect(isRelativePath('.abc')).toBe(false); + expect(isRelativePath('..abc')).toBe(false); + expect(isRelativePath('@abc')).toBe(false); + expect(isRelativePath('.abc/xyz')).toBe(false); + expect(isRelativePath('..abc/xyz')).toBe(false); + expect(isRelativePath('@abc/xyz')).toBe(false); + }); }); }); diff --git a/packages/compiler-cli/src/ngtsc/file_system/index.ts b/packages/compiler-cli/src/ngtsc/file_system/index.ts index 594af21923e6c..2bf3079757ecd 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/index.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/index.ts @@ -7,7 +7,7 @@ */ export {CachedFileSystem} from './src/cached_file_system'; export {NgtscCompilerHost} from './src/compiler_host'; -export {absoluteFrom, absoluteFromSourceFile, basename, dirname, getFileSystem, isRoot, join, relative, relativeFrom, resolve, setFileSystem} from './src/helpers'; +export {absoluteFrom, absoluteFromSourceFile, basename, dirname, getFileSystem, isRoot, isRooted, join, relative, relativeFrom, resolve, setFileSystem} from './src/helpers'; export {LogicalFileSystem, LogicalProjectPath} from './src/logical'; export {NodeJSFileSystem} from './src/node_js_file_system'; export {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './src/types'; diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/helpers.ts b/packages/compiler-cli/src/ngtsc/file_system/src/helpers.ts index 9cf87fedb67ab..61d676e0586f3 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/helpers.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/helpers.ts @@ -37,8 +37,8 @@ export function absoluteFromSourceFile(sf: ts.SourceFile): AbsoluteFsPath { } /** -* Convert the path `path` to a `PathSegment`, throwing an error if it's not a relative path. -*/ + * Convert the path `path` to a `PathSegment`, throwing an error if it's not a relative path. + */ export function relativeFrom(path: string): PathSegment { const normalized = normalizeSeparators(path); if (fs.isRooted(normalized)) { @@ -73,6 +73,13 @@ export function isRoot(path: AbsoluteFsPath): boolean { return fs.isRoot(path); } +/** + * Static access to `isRooted`. + */ +export function isRooted(path: string): boolean { + return fs.isRooted(path); +} + /** * Static access to `relative`. */ From f9f6e2e1b3cc102cfb482f92b36850c2d03d9e6e Mon Sep 17 00:00:00 2001 From: JoostK <joost.koehoorn@gmail.com> Date: Mon, 6 Apr 2020 21:47:40 +0200 Subject: [PATCH 143/262] style(compiler): reformat partial evaluator source tree (#36461) PR Close #36461 --- .../ngtsc/partial_evaluator/src/builtin.ts | 8 ++- .../ngtsc/partial_evaluator/src/interface.ts | 5 +- .../partial_evaluator/src/interpreter.ts | 13 +++-- .../src/ngtsc/partial_evaluator/src/result.ts | 10 ++-- .../partial_evaluator/test/evaluator_spec.ts | 55 +++++++++++-------- .../src/ngtsc/partial_evaluator/test/utils.ts | 2 +- 6 files changed, 56 insertions(+), 37 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts index b8f4e6b8acabf..c04aad5b50fad 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/builtin.ts @@ -12,7 +12,9 @@ import {DynamicValue} from './dynamic'; import {KnownFn, ResolvedValue, ResolvedValueArray} from './result'; export class ArraySliceBuiltinFn extends KnownFn { - constructor(private lhs: ResolvedValueArray) { super(); } + constructor(private lhs: ResolvedValueArray) { + super(); + } evaluate(node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue { if (args.length === 0) { @@ -24,7 +26,9 @@ export class ArraySliceBuiltinFn extends KnownFn { } export class ArrayConcatBuiltinFn extends KnownFn { - constructor(private lhs: ResolvedValueArray) { super(); } + constructor(private lhs: ResolvedValueArray) { + super(); + } evaluate(node: ts.CallExpression, args: ResolvedValueArray): ResolvedValue { const result: ResolvedValueArray = [...this.lhs]; diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts index 76b3e5698960f..f9a380a66c0d3 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts @@ -17,7 +17,7 @@ import {ResolvedValue} from './result'; export type ForeignFunctionResolver = (node: Reference<ts.FunctionDeclaration|ts.MethodDeclaration|ts.FunctionExpression>, - args: ReadonlyArray<ts.Expression>) => ts.Expression | null; + args: ReadonlyArray<ts.Expression>) => ts.Expression|null; export class PartialEvaluator { constructor( @@ -31,7 +31,8 @@ export class PartialEvaluator { originatingFile: sourceFile, absoluteModuleName: null, resolutionContext: sourceFile.fileName, - scope: new Map<ts.ParameterDeclaration, ResolvedValue>(), foreignFunctionResolver, + scope: new Map<ts.ParameterDeclaration, ResolvedValue>(), + foreignFunctionResolver, }); } } diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index e47a59d58cba6..83f32f14e2dc6 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -261,7 +261,7 @@ export class StaticInterpreter { } else if (ts.isVariableDeclaration(node)) { return this.visitVariableDeclaration(node, context); } else if (ts.isParameter(node) && context.scope.has(node)) { - return context.scope.get(node) !; + return context.scope.get(node)!; } else if (ts.isExportAssignment(node)) { return this.visitExpression(node.expression, context); } else if (ts.isEnumDeclaration(node)) { @@ -337,7 +337,8 @@ export class StaticInterpreter { } const declContext = { - ...context, ...joinModuleContext(context, node, decl), + ...context, + ...joinModuleContext(context, node, decl), }; // Visit both concrete and inline declarations. @@ -354,7 +355,7 @@ export class StaticInterpreter { const strIndex = `${rhs}`; if (lhs instanceof Map) { if (lhs.has(strIndex)) { - return lhs.get(strIndex) !; + return lhs.get(strIndex)!; } else { return undefined; } @@ -501,7 +502,7 @@ export class StaticInterpreter { return DynamicValue.fromUnsupportedSyntax(node); } - const op = UNARY_OPERATORS.get(operatorKind) !; + const op = UNARY_OPERATORS.get(operatorKind)!; const value = this.visitExpression(node.operand, context); if (value instanceof DynamicValue) { return DynamicValue.fromDynamicInput(node, value); @@ -516,7 +517,7 @@ export class StaticInterpreter { return DynamicValue.fromUnsupportedSyntax(node); } - const opRecord = BINARY_OPERATORS.get(tokenKind) !; + const opRecord = BINARY_OPERATORS.get(tokenKind)!; let lhs: ResolvedValue, rhs: ResolvedValue; if (opRecord.literal) { lhs = literal(this.visitExpression(node.left, context), node.left); @@ -621,7 +622,7 @@ function joinModuleContext(existing: Context, node: ts.Node, decl: Declaration): } } -function owningModule(context: Context, override: OwningModule | null = null): OwningModule|null { +function owningModule(context: Context, override: OwningModule|null = null): OwningModule|null { let specifier = context.absoluteModuleName; if (override !== null) { specifier = override.specifier; diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts index 96a0c49863dd2..c4f817d043254 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/result.ts @@ -21,8 +21,8 @@ import {DynamicValue} from './dynamic'; * non-primitive value, or a special `DynamicValue` type which indicates the value was not * available statically. */ -export type ResolvedValue = number | boolean | string | null | undefined | Reference | EnumValue | - ResolvedValueArray | ResolvedValueMap | ResolvedModule | KnownFn | DynamicValue<unknown>; +export type ResolvedValue = number|boolean|string|null|undefined|Reference|EnumValue| + ResolvedValueArray|ResolvedValueMap|ResolvedModule|KnownFn|DynamicValue<unknown>; /** * An array of `ResolvedValue`s. @@ -54,12 +54,14 @@ export class ResolvedModule { return undefined; } - return this.evaluate(this.exports.get(name) !); + return this.evaluate(this.exports.get(name)!); } getExports(): ResolvedValueMap { const map = new Map<string, ResolvedValue>(); - this.exports.forEach((decl, name) => { map.set(name, this.evaluate(decl)); }); + this.exports.forEach((decl, name) => { + map.set(name, this.evaluate(decl)); + }); return map; } } diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index a64fe61a51d66..8d2d773cbe8f6 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -42,11 +42,13 @@ runInEachFileSystem(() => { expect(value).toEqual('test'); }); - it('map access works', - () => { expect(evaluate('const obj = {a: "test"};', 'obj.a')).toEqual('test'); }); + it('map access works', () => { + expect(evaluate('const obj = {a: "test"};', 'obj.a')).toEqual('test'); + }); - it('resolves undefined property access', - () => { expect(evaluate('const obj: any = {}', 'obj.bar')).toEqual(undefined); }); + it('resolves undefined property access', () => { + expect(evaluate('const obj: any = {}', 'obj.bar')).toEqual(undefined); + }); it('function calls work', () => { expect(evaluate(`function foo(bar) { return bar; }`, 'foo("test")')).toEqual('test'); @@ -68,7 +70,9 @@ runInEachFileSystem(() => { expect(evaluate(`const x = false; const y = x ? 'true' : 'false';`, 'y')).toEqual('false'); }); - it('addition works', () => { expect(evaluate(`const x = 1 + 2;`, 'x')).toEqual(3); }); + it('addition works', () => { + expect(evaluate(`const x = 1 + 2;`, 'x')).toEqual(3); + }); it('static property on class works', () => { expect(evaluate(`class Foo { static bar = 'test'; }`, 'Foo.bar')).toEqual('test'); @@ -148,19 +152,22 @@ runInEachFileSystem(() => { expect(evaluate('const a: any = 3, b = 3;', 'a !== b')).toEqual(false); }); - it('parentheticals work', - () => { expect(evaluate(`const a = 3, b = 4;`, 'a * (a + b)')).toEqual(21); }); + it('parentheticals work', () => { + expect(evaluate(`const a = 3, b = 4;`, 'a * (a + b)')).toEqual(21); + }); - it('array access works', - () => { expect(evaluate(`const a = [1, 2, 3];`, 'a[1] + a[0]')).toEqual(3); }); + it('array access works', () => { + expect(evaluate(`const a = [1, 2, 3];`, 'a[1] + a[0]')).toEqual(3); + }); it('array access out of bounds is `undefined`', () => { expect(evaluate(`const a = [1, 2, 3];`, 'a[-1]')).toEqual(undefined); expect(evaluate(`const a = [1, 2, 3];`, 'a[3]')).toEqual(undefined); }); - it('array `length` property access works', - () => { expect(evaluate(`const a = [1, 2, 3];`, 'a[\'length\'] + 1')).toEqual(4); }); + it('array `length` property access works', () => { + expect(evaluate(`const a = [1, 2, 3];`, 'a[\'length\'] + 1')).toEqual(4); + }); it('array `slice` function works', () => { expect(evaluate(`const a = [1, 2, 3];`, 'a[\'slice\']()')).toEqual([1, 2, 3]); @@ -185,10 +192,13 @@ runInEachFileSystem(() => { expect(evaluate('const a = false;', 'a')).toEqual(false); }); - it('supports undefined', - () => { expect(evaluate('const a = undefined;', 'a')).toEqual(undefined); }); + it('supports undefined', () => { + expect(evaluate('const a = undefined;', 'a')).toEqual(undefined); + }); - it('supports null', () => { expect(evaluate('const a = null;', 'a')).toEqual(null); }); + it('supports null', () => { + expect(evaluate('const a = null;', 'a')).toEqual(null); + }); it('resolves unknown binary operators as dynamic value', () => { const value = evaluate('declare const window: any;', '"location" in window'); @@ -308,7 +318,7 @@ runInEachFileSystem(() => { ]); const checker = program.getTypeChecker(); const result = getDeclaration(program, _('/entry.ts'), 'target$', ts.isVariableDeclaration); - const expr = result.initializer !; + const expr = result.initializer!; const evaluator = makeEvaluator(checker); const resolved = evaluator.evaluate(expr); if (!(resolved instanceof Reference)) { @@ -338,7 +348,7 @@ runInEachFileSystem(() => { ]); const checker = program.getTypeChecker(); const result = getDeclaration(program, _('/entry.ts'), 'target$', ts.isVariableDeclaration); - const expr = result.initializer !; + const expr = result.initializer!; const evaluator = makeEvaluator(checker); const resolved = evaluator.evaluate(expr); if (!(resolved instanceof Reference)) { @@ -348,7 +358,7 @@ runInEachFileSystem(() => { expect(ts.isFunctionDeclaration(resolved.node)).toBe(true); const reference = resolved.getIdentityIn(getSourceFileOrError(program, _('/entry.ts'))); expect(reference).not.toBeNull(); - expect(reference !.getSourceFile()).toEqual(getSourceFileOrError(program, _('/entry.ts'))); + expect(reference!.getSourceFile()).toEqual(getSourceFileOrError(program, _('/entry.ts'))); }); it('reads values from default exports', () => { @@ -434,8 +444,9 @@ runInEachFileSystem(() => { .toEqual('test'); }); - it('template expressions work', - () => { expect(evaluate('const a = 2, b = 4;', '`1${a}3${b}5`')).toEqual('12345'); }); + it('template expressions work', () => { + expect(evaluate('const a = 2, b = 4;', '`1${a}3${b}5`')).toEqual('12345'); + }); it('enum resolution works', () => { const result = evaluate( @@ -469,7 +480,7 @@ runInEachFileSystem(() => { ]); const checker = program.getTypeChecker(); const result = getDeclaration(program, _('/entry.ts'), 'target$', ts.isVariableDeclaration); - const expr = result.initializer !as ts.ObjectLiteralExpression; + const expr = result.initializer! as ts.ObjectLiteralExpression; const prop = expr.properties[0] as ts.ShorthandPropertyAssignment; const evaluator = makeEvaluator(checker); const resolved = evaluator.evaluate(prop.name); @@ -487,13 +498,13 @@ runInEachFileSystem(() => { ]); const checker = program.getTypeChecker(); const result = getDeclaration(program, _('/entry.ts'), 'target$', ts.isVariableDeclaration); - const expr = result.initializer !as ts.ObjectLiteralExpression; + const expr = result.initializer! as ts.ObjectLiteralExpression; const evaluator = makeEvaluator(checker); const resolved = evaluator.evaluate(expr); if (!(resolved instanceof Map)) { return fail('Should have resolved to a Map'); } - const value = resolved.get('value') !; + const value = resolved.get('value')!; if (!(value instanceof DynamicValue)) { return fail(`Should have resolved 'value' to a DynamicValue`); } diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/utils.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/utils.ts index ac19be5c6fe21..83578c36f0eb3 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/utils.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/utils.ts @@ -31,7 +31,7 @@ export function makeExpression(code: string, expr: string, supportingFiles: Test const decl = getDeclaration(program, absoluteFrom('/entry.ts'), 'target$', ts.isVariableDeclaration); return { - expression: decl.initializer !, + expression: decl.initializer!, host, options, checker, From 64022f51d4fbbd93683cf188e9c3a986a345a73d Mon Sep 17 00:00:00 2001 From: JoostK <joost.koehoorn@gmail.com> Date: Mon, 6 Apr 2020 22:33:38 +0200 Subject: [PATCH 144/262] fix(compiler): resolve enum values in binary operations (#36461) During static evaluation of expressions, the partial evaluator may come across a binary + operator for which it needs to evaluate its operands. Any of these operands may be a reference to an enum member, in which case the enum member's value needs to be used as literal value, not the enum member reference itself. This commit fixes the behavior by resolving an `EnumValue` when used as a literal value. Fixes #35584 Resolves FW-1951 PR Close #36461 --- .../partial_evaluator/src/interpreter.ts | 32 ++++++++++--------- .../partial_evaluator/test/evaluator_spec.ts | 31 ++++++++++++++---- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index 83f32f14e2dc6..ab12a398fbd08 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -203,19 +203,13 @@ export class StaticInterpreter { const pieces: string[] = [node.head.text]; for (let i = 0; i < node.templateSpans.length; i++) { const span = node.templateSpans[i]; - let value = this.visit(span.expression, context); - if (value instanceof EnumValue) { - value = value.resolved; - } - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || - value == null) { - pieces.push(`${value}`); - } else if (value instanceof DynamicValue) { + const value = literal( + this.visit(span.expression, context), + () => DynamicValue.fromDynamicString(span.expression)); + if (value instanceof DynamicValue) { return DynamicValue.fromDynamicInput(node, value); - } else { - return DynamicValue.fromDynamicInput(node, DynamicValue.fromDynamicString(span.expression)); } - pieces.push(span.literal.text); + pieces.push(`${value}`, span.literal.text); } return pieces.join(''); } @@ -520,8 +514,12 @@ export class StaticInterpreter { const opRecord = BINARY_OPERATORS.get(tokenKind)!; let lhs: ResolvedValue, rhs: ResolvedValue; if (opRecord.literal) { - lhs = literal(this.visitExpression(node.left, context), node.left); - rhs = literal(this.visitExpression(node.right, context), node.right); + lhs = literal( + this.visitExpression(node.left, context), + value => DynamicValue.fromInvalidExpressionType(node.left, value)); + rhs = literal( + this.visitExpression(node.right, context), + value => DynamicValue.fromInvalidExpressionType(node.right, value)); } else { lhs = this.visitExpression(node.left, context); rhs = this.visitExpression(node.right, context); @@ -585,12 +583,16 @@ function isFunctionOrMethodReference(ref: Reference<ts.Node>): ts.isFunctionExpression(ref.node); } -function literal(value: ResolvedValue, node: ts.Node): any { +function literal( + value: ResolvedValue, reject: (value: ResolvedValue) => ResolvedValue): ResolvedValue { + if (value instanceof EnumValue) { + value = value.resolved; + } if (value instanceof DynamicValue || value === null || value === undefined || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { return value; } - return DynamicValue.fromInvalidExpressionType(node, value); + return reject(value); } function isVariableDeclarationDeclared(node: ts.VariableDeclaration): boolean { diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index 8d2d773cbe8f6..7c3dcd3ae0b50 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -448,6 +448,31 @@ runInEachFileSystem(() => { expect(evaluate('const a = 2, b = 4;', '`1${a}3${b}5`')).toEqual('12345'); }); + it('template expressions should resolve enums', () => { + expect(evaluate('enum Test { VALUE = "test" };', '`a.${Test.VALUE}.b`')).toBe('a.test.b'); + }); + + it('string concatenation should resolve enums', () => { + expect(evaluate('enum Test { VALUE = "test" };', '"a." + Test.VALUE + ".b"')) + .toBe('a.test.b'); + }); + + it('should resolve non-literals as dynamic string', () => { + const value = evaluate(`const a: any = [];`, '`a.${a}.b`'); + + if (!(value instanceof DynamicValue)) { + return fail(`Should have resolved to a DynamicValue`); + } + expect(value.node.getText()).toEqual('`a.${a}.b`'); + + if (!value.isFromDynamicInput()) { + return fail('Should originate from dynamic input'); + } else if (!value.reason.isFromDynamicString()) { + return fail('Should refer to a dynamic string part'); + } + expect(value.reason.node.getText()).toEqual('a'); + }); + it('enum resolution works', () => { const result = evaluate( ` @@ -512,12 +537,6 @@ runInEachFileSystem(() => { expect(value.node).toBe(prop.initializer); }); - it('should resolve enums in template expressions', () => { - const value = - evaluate(`enum Test { VALUE = 'test', } const value = \`a.\${Test.VALUE}.b\`;`, 'value'); - expect(value).toBe('a.test.b'); - }); - it('should not attach identifiers to FFR-resolved values', () => { const value = evaluate( ` From 4374931b0ed331450c77ca19cf90a5c0c39b2230 Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Thu, 12 Mar 2020 01:41:19 +0900 Subject: [PATCH 145/262] fix(zone.js): zone.js patch jest should handle done correctly (#36022) `zone.js` supports jest `test.each()` methods, but it introduces a bug, which is the `done()` function will not be handled correctly. ``` it('should work with done', done => { // done will be undefined. }); ``` The reason is the logic of monkey patching `test` method is different from `jasmine` patch // jasmine patch ``` return testBody.length === 0 ? () => testProxyZone.run(testBody, null) : done => testProxyZone.run(testBody, null, [done]); ``` // jest patch ``` return function(...args) { return testProxyZone.run(testBody, null, args); }; ``` the purpose of this change is to handle the following cases. ``` test.each([1, 2])('test.each', (arg1, arg2) => { expect(arg1).toBe(1); expect(arg2).toBe(2); }); ``` so in jest, it is a little complex, because the `testBody`'s parameter may be bigger than 1, so the logic in `jasmine` ``` return testBody.length === 0 ? () => testProxyZone.run(testBody, null) : done => testProxyZone.run(testBody, null, [done]); ``` will not work for `test.each` in jest. So in this PR, I created a dynamic `Function` to return the correct length of paramters (which is required by jest core), to handle 1. normal `test` with or without `done`. 2. each with parameters with or without done. PR Close #36022 --- packages/zone.js/lib/jest/jest.ts | 18 ++++-- packages/zone.js/test/jest/jest.spec.js | 85 +++++++++++++++++++++---- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/packages/zone.js/lib/jest/jest.ts b/packages/zone.js/lib/jest/jest.ts index 28e989c0d4dc8..7ced7e9a788b8 100644 --- a/packages/zone.js/lib/jest/jest.ts +++ b/packages/zone.js/lib/jest/jest.ts @@ -43,10 +43,9 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => { function wrapTestFactoryInZone(originalJestFn: Function) { return function(this: unknown, ...tableArgs: any[]) { - const testFn = originalJestFn.apply(this, tableArgs); return function(this: unknown, ...args: any[]) { args[1] = wrapTestInZone(args[1]); - return testFn.apply(this, args); + return originalJestFn.apply(this, tableArgs).apply(this, args); }; }; } @@ -64,16 +63,21 @@ Zone.__load_patch('jest', (context: any, Zone: ZoneType) => { /** * Gets a function wrapping the body of a jest `it/beforeEach/afterEach` block to * execute in a ProxyZone zone. - * This will run in the `testProxyZone`. + * This will run in the `proxyZone`. */ function wrapTestInZone(testBody: Function): Function { if (typeof testBody !== 'function') { return testBody; } - // The `done` callback is only passed through if the function expects at least one argument. - // Note we have to make a function with correct number of arguments, otherwise jest will - // think that all functions are sync or async. - return function(this: unknown, ...args: any[]) { return proxyZone.run(testBody, this, args); }; + const wrappedFunc = function() { + return proxyZone.run(testBody, null, arguments as any); + }; + // Update the length of wrappedFunc to be the same as the length of the testBody + // So jest core can handle whether the test function has `done()` or not correctly + Object.defineProperty( + wrappedFunc, 'length', {configurable: true, writable: true, enumerable: false}); + wrappedFunc.length = testBody.length; + return wrappedFunc; } ['describe', 'xdescribe', 'fdescribe'].forEach(methodName => { diff --git a/packages/zone.js/test/jest/jest.spec.js b/packages/zone.js/test/jest/jest.spec.js index 13e38412795d6..35fa8df264eb6 100644 --- a/packages/zone.js/test/jest/jest.spec.js +++ b/packages/zone.js/test/jest/jest.spec.js @@ -6,10 +6,18 @@ function assertInsideSyncDescribeZone() { } describe('describe', () => { assertInsideSyncDescribeZone(); - beforeEach(() => { assertInsideProxyZone(); }); - beforeAll(() => { assertInsideProxyZone(); }); - afterEach(() => { assertInsideProxyZone(); }); - afterAll(() => { assertInsideProxyZone(); }); + beforeEach(() => { + assertInsideProxyZone(); + }); + beforeAll(() => { + assertInsideProxyZone(); + }); + afterEach(() => { + assertInsideProxyZone(); + }); + afterAll(() => { + assertInsideProxyZone(); + }); }); describe.each([[1, 2]])('describe.each', (arg1, arg2) => { assertInsideSyncDescribeZone(); @@ -17,23 +25,78 @@ describe.each([[1, 2]])('describe.each', (arg1, arg2) => { expect(arg2).toBe(2); }); describe('test', () => { - it('it', () => { assertInsideProxyZone(); }); + it('it', () => { + assertInsideProxyZone(); + }); it.each([[1, 2]])('it.each', (arg1, arg2) => { assertInsideProxyZone(); expect(arg1).toBe(1); expect(arg2).toBe(2); }); - test('test', () => { assertInsideProxyZone(); }); - test.each([[]])('test.each', () => { assertInsideProxyZone(); }); + test('test', () => { + assertInsideProxyZone(); + }); + test.each([[]])('test.each', () => { + assertInsideProxyZone(); + }); +}); + +it('it', () => { + assertInsideProxyZone(); +}); +it('it with done', done => { + assertInsideProxyZone(); + done(); }); -it('it', () => { assertInsideProxyZone(); }); -it.each([[1, 2]])('it.each', (arg1, arg2) => { +it.each([[1, 2]])('it.each', (arg1, arg2, done) => { assertInsideProxyZone(); expect(arg1).toBe(1); expect(arg2).toBe(2); + done(); +}); + +it.each([2])('it.each with 1D array', arg1 => { + assertInsideProxyZone(); + expect(arg1).toBe(2); +}); + +it.each([2])('it.each with 1D array and done', (arg1, done) => { + assertInsideProxyZone(); + expect(arg1).toBe(2); + done(); +}); + +it.each` + foo | bar + ${1} | ${2} + `('it.each should work with table as a tagged template literal', ({foo, bar}) => { + expect(foo).toBe(1); + expect(bar).toBe(2); +}); + +it.each` + foo | bar + ${1} | ${2} + `('it.each should work with table as a tagged template literal with done', ({foo, bar}, done) => { + expect(foo).toBe(1); + expect(bar).toBe(2); + done(); +}); + +it.each` + foo | bar + ${1} | ${2} + `('(async) it.each should work with table as a tagged template literal', async ({foo, bar}) => { + expect(foo).toBe(1); + expect(bar).toBe(2); +}); + +test('test', () => { + assertInsideProxyZone(); +}); +test.each([[]])('test.each', () => { + assertInsideProxyZone(); }); -test('test', () => { assertInsideProxyZone(); }); -test.each([[]])('test.each', () => { assertInsideProxyZone(); }); test.todo('todo'); From 0075017b43a37d06780cc245c3326212d15fd6bd Mon Sep 17 00:00:00 2001 From: Judy Bogart <jbogart@gmail.com> Date: Wed, 4 Mar 2020 16:40:56 -0800 Subject: [PATCH 146/262] docs: update reactive forms page (#35969) PR Close #35969 --- aio/content/guide/deprecations.md | 68 +++++- aio/content/guide/reactive-forms.md | 194 ++++++++++++------ .../form_control_directive.ts | 79 +------ .../reactive_directives/form_control_name.ts | 72 +------ packages/forms/src/form_providers.ts | 7 +- packages/forms/src/model.ts | 3 +- 6 files changed, 210 insertions(+), 213 deletions(-) diff --git a/aio/content/guide/deprecations.md b/aio/content/guide/deprecations.md index 6d28414fd0002..880affa372286 100644 --- a/aio/content/guide/deprecations.md +++ b/aio/content/guide/deprecations.md @@ -117,7 +117,7 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i | API | Replacement | Deprecation announced | Notes | | --- | ----------- | --------------------- | ----- | -| [`ngModel` with reactive forms](#ngmodel-reactive) | See [FormControlDirective usage notes](api/forms/FormControlDirective#use-with-ngmodel) | v6 | none | +| [`ngModel` with reactive forms](#ngmodel-reactive) | [`FormControlDirective`](api/forms/FormControlDirective) | v6 | none | {@a router} ### @angular/router @@ -189,9 +189,71 @@ The `<template>` tag was deprecated in v4 to avoid colliding with the DOM's elem {@a ngmodel-reactive} ### ngModel with reactive forms -Support for using the `ngModel` input property and `ngModelChange` event with reactive form directives was deprecated in version 6. +Support for using the `ngModel` input property and `ngModelChange` event with reactive +form directives has been deprecated in Angular v6 and will be removed in a future version +of Angular. -For more information, see the usage notes for [`FormControlDirective`](api/forms/FormControlDirective#use-with-ngmodel) and [`FormControlName`](api/forms/FormControlName#use-with-ngmodel). +Now deprecated: + +```html +<input [formControl]="control" [(ngModel)]="value"> +``` + +```ts +this.value = 'some value'; +``` + +This has been deprecated for several reasons. First, developers have found this pattern +confusing. It seems like the actual `ngModel` directive is being used, but in fact it's +an input/output property named `ngModel` on the reactive form directive that +approximates some, but not all, of the directive's behavior. +It allows getting and setting a value and intercepting value events, but +some of `ngModel`'s other features, such as +delaying updates with`ngModelOptions` or exporting the directive, don't work. + +In addition, this pattern mixes template-driven and reactive forms strategies, which +prevents taking advantage of the full benefits of either strategy. +Setting the value in the template violates the template-agnostic +principles behind reactive forms, whereas adding a `FormControl`/`FormGroup` layer in +the class removes the convenience of defining forms in the template. + +To update your code before support is removed, you'll want to decide whether to stick +with reactive form directives (and get/set values using reactive forms patterns) or +switch over to template-driven directives. + +After (choice 1 - use reactive forms): + +```html +<input [formControl]="control"> +``` + +```ts +this.control.setValue('some value'); +``` + +After (choice 2 - use template-driven forms): + +```html +<input [(ngModel)]="value"> +``` + +```ts +this.value = 'some value'; +``` + +By default, when you use this pattern, you will see a deprecation warning once in dev +mode. You can choose to silence this warning by providing a config for +`ReactiveFormsModule` at import time: + +```ts +imports: [ + ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'}); +] +``` + +Alternatively, you can choose to surface a separate warning for each instance of this +pattern with a config value of `"always"`. This may help to track down where in the code +the pattern is being used as the code is being updated. {@a reflectiveinjector} diff --git a/aio/content/guide/reactive-forms.md b/aio/content/guide/reactive-forms.md index 4e21778e2ccb1..ca73e5fad4657 100644 --- a/aio/content/guide/reactive-forms.md +++ b/aio/content/guide/reactive-forms.md @@ -1,36 +1,54 @@ # Reactive forms -*Reactive forms* provide a model-driven approach to handling form inputs whose values change over time. This guide shows you how to create and update a simple form control, progress to using multiple controls in a group, validate form values, and implement more advanced forms. +Reactive forms provide a model-driven approach to handling form inputs whose values change over time. This guide shows you how to create and update a basic form control, progress to using multiple controls in a group, validate form values, and create dynamic forms where you can add or remove controls at run time. +<div class="alert is-helpful"> + +Try this <live-example title="Reactive Forms in Stackblitz">Reactive Forms live-example</live-example>. +</div> -{@a toc} +**Prerequisites** -Try the <live-example title="Reactive Forms in Stackblitz">Reactive Forms live-example</live-example>. +Before going further into reactive forms, you should have a basic understanding of the following: + +* TypeScript programming. +* Angular app-design fundamentals, as described in [Angular Concepts](guide/architecture "Introduction to Angular concepts."). +* The form-design concepts that are presented in [Introduction to Forms](guide/forms-overview "Overview of Angular forms."). {@a intro} -## Introduction to reactive forms +## Overview of reactive forms -Reactive forms use an explicit and immutable approach to managing the state of a form at a given point in time. Each change to the form state returns a new state, which maintains the integrity of the model between changes. Reactive forms are built around observable streams, where form inputs and values are provided as streams of input values, which can be accessed synchronously. +Reactive forms use an explicit and immutable approach to managing the state of a form at a given point in time. Each change to the form state returns a new state, which maintains the integrity of the model between changes. Reactive forms are built around [observable](guide/glossary#observable "Observable definition.") streams, where form inputs and values are provided as streams of input values, which can be accessed synchronously. Reactive forms also provide a straightforward path to testing because you are assured that your data is consistent and predictable when requested. Any consumers of the streams have access to manipulate that data safely. -Reactive forms differ from template-driven forms in distinct ways. Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams. If you prefer direct access to modify data in your template, template-driven forms are less explicit because they rely on directives embedded in the template, along with mutable data to track changes asynchronously. See the [Forms Overview](guide/forms-overview) for detailed comparisons between the two paradigms. +Reactive forms differ from [template-driven forms](guide/forms "Template-driven forms guide") in distinct ways. Reactive forms provide more predictability with synchronous access to the data model, immutability with observable operators, and change tracking through observable streams. + +Template-driven forms allow direct access to modify data in your template, but are less explicit than reactive forms because they rely on directives embedded in the template, along with mutable data to track changes asynchronously. See the [Forms Overview](guide/forms-overview "Overview of Angular forms.") for detailed comparisons between the two paradigms. -## Getting started +## Adding a basic form control -This section describes how to add a single form control. In the example, the user enters their name into an input field, captures that input value, and displays the current value of the form control element. +There are three steps to using form controls. -### Step 1: Registering the reactive forms module +1. Register the reactive forms module in your app. This module declares the reactive-form directives that you need to use reactive forms. +2. Generate a new `FormControl` instance and save it in the component. +3. Register the `FormControl` in the template. -To use reactive forms, import `ReactiveFormsModule` from the `@angular/forms` package and add it to your NgModule's `imports` array. +You can then display the form by adding the component to the template. + +The following examples show how to add a single form control. In the example, the user enters their name into an input field, captures that input value, and displays the current value of the form control element. + +**Register the reactive forms module** + +To use reactive form controls, import `ReactiveFormsModule` from the `@angular/forms` package and add it to your NgModule's `imports` array. <code-example path="reactive-forms/src/app/app.module.ts" region="imports" header="src/app/app.module.ts (excerpt)"></code-example> -### Step 2: Generating and importing a new form control +**Generate a new `FormControl`** -Generate a component for the control. +Use the [CLI command](cli "Using the Angular command-line interface.") `ng generate` to generate a component in your project to host the control. <code-example language="sh" class="code-shell"> @@ -38,27 +56,29 @@ Generate a component for the control. </code-example> -The `FormControl` class is the basic building block when using reactive forms. To register a single form control, import the `FormControl` class into your component and create a new instance of the form control to save as a class property. +To register a single form control, import the `FormControl` class and create a new instance of `FormControl` to save as a class property. <code-example path="reactive-forms/src/app/name-editor/name-editor.component.ts" region="create-control" header="src/app/name-editor/name-editor.component.ts"></code-example> Use the constructor of `FormControl` to set its initial value, which in this case is an empty string. By creating these controls in your component class, you get immediate access to listen for, update, and validate the state of the form input. -### Step 3: Registering the control in the template +**Register the control in the template** -After you create the control in the component class, you must associate it with a form control element in the template. Update the template with the form control using the `formControl` binding provided by `FormControlDirective` included in `ReactiveFormsModule`. +After you create the control in the component class, you must associate it with a form control element in the template. Update the template with the form control using the `formControl` binding provided by `FormControlDirective`, which is also included in the `ReactiveFormsModule`. <code-example path="reactive-forms/src/app/name-editor/name-editor.component.html" region="control-binding" header="src/app/name-editor/name-editor.component.html"></code-example> <div class="alert is-helpful"> -**Note:** For a more detailed list of classes and directives provided by `ReactiveFormsModule`, see the [Reactive forms API](#reactive-forms-api) section. +* For a summary of the classes and directives provided by `ReactiveFormsModule`, see the [Reactive forms API](#reactive-forms-api "API summary.") section below. + +* For complete syntax details of these classes and directives, see the API reference documentation for the [Forms package](api/forms "API reference."). </div> Using the template binding syntax, the form control is now registered to the `name` input element in the template. The form control and DOM element communicate with each other: the view reflects changes in the model, and the model reflects changes in the view. -#### Displaying the component +**Display the component** The form control assigned to `name` is displayed when the component is added to a template. @@ -68,18 +88,14 @@ The form control assigned to `name` is displayed when the component is added to <img src="generated/images/guide/reactive-forms/name-editor-1.png" alt="Name Editor"> </div> -## Managing control values - -Reactive forms give you access to the form control state and value at a point in time. You can manipulate -the current state and value through the component class or the component template. The following examples display the value of the form control instance and change it. - {@a display-value} ### Displaying a form control value -You can display the value in these ways: +You can display the value in the following ways. * Through the `valueChanges` observable where you can listen for changes in the form's value in the template using `AsyncPipe` or in the component class using the `subscribe()` method. + * With the `value` property, which gives you a snapshot of the current value. The following example shows you how to display the current value using interpolation in the template. @@ -88,9 +104,10 @@ The following example shows you how to display the current value using interpola The displayed value changes as you update the form control element. -Reactive forms provide access to information about a given control through properties and methods provided with each instance. These properties and methods of the underlying [AbstractControl](api/forms/AbstractControl) class are used to control form state and determine when to display messages when handling validation. For more information, see [Simple form validation](#simple-form-validation) later in this guide. +Reactive forms provide access to information about a given control through properties and methods provided with each instance. +These properties and methods of the underlying [AbstractControl](api/forms/AbstractControl "API reference.") class are used to control form state and determine when to display messages when handling [input validation](#basic-form-validation "Learn more about validating form input."). -Read about other `FormControl` properties and methods in the [Reactive forms API](#reactive-forms-api) section. +Read about other `FormControl` properties and methods in the [API Reference](api/forms/FormControl "Detailed syntax reference."). ### Replacing a form control value @@ -114,12 +131,17 @@ The form model is the source of truth for the control, so when you click the but <div class="alert is-helpful"> -**Note:** In this example, you're using a single control. When using the `setValue()` method with a form group or form array instance, the value needs to match the structure of the group or array. +**Note:** In this example, you're using a single control. When using the `setValue()` method with a [form group](#grouping-form-controls "Learn more about form groups.") or [form array](#creating-dynamic-forms "Learn more about dynamic forms.") instance, the value needs to match the structure of the group or array. </div> ## Grouping form controls +Forms typically contain several related controls. Reactive forms provide two ways of grouping multiple related controls into a single input form. + +* A form *group* defines a form with a fixed set of controls that you can manage together. Form group basics are discussed in this section. You can also [nest form groups](#nested-groups "See more about nesting groups.") to create more complex forms. +* A form *array* defines a dynamic form, where you can add and remove controls at run time. You can also nest form arrays to create more complex forms. For more about this option, see [Creating dynamic forms](#dynamic-forms "See more about form arrays.") below. + Just as a form control instance gives you control over a single input field, a form group instance tracks the form state of a group of form control instances (for example, a form). Each control in a form group instance is tracked by name when creating the form group. The following example shows how to manage multiple form control instances in a single group. Generate a `ProfileEditor` component and import the `FormGroup` and `FormControl` classes from the `@angular/forms` package. @@ -134,7 +156,13 @@ Generate a `ProfileEditor` component and import the `FormGroup` and `FormControl </code-example> -### Step 1: Creating a FormGroup instance +To add a form group to this component, take the following steps. + +1. Create a `FormGroup` instance. +2. Associate the `FormGroup` model and view. +3. Save the form data. + +**Create a FormGroup instance** Create a property in the component class named `profileForm` and set the property to a new form group instance. To initialize the form group, provide the constructor with an object of named keys mapped to their control. @@ -146,7 +174,7 @@ For the profile form, add two form control instances with the names `firstName` The individual form controls are now collected within a group. A `FormGroup` instance provides its model value as an object reduced from the values of each control in the group. A form group instance has the same properties (such as `value` and `untouched`) and methods (such as `setValue()`) as a form control instance. -### Step 2: Associating the FormGroup model and view +**Associate the FormGroup model and view** A form group tracks the status and changes for each of its controls, so if one of the controls changes, the parent control also emits a new status or value change. The model for the group is maintained from its members. After you define the model, you must update the template to reflect the model in the view. @@ -154,7 +182,7 @@ A form group tracks the status and changes for each of its controls, so if one o Note that just as a form group contains a group of controls, the *profile form* `FormGroup` is bound to the `form` element with the `FormGroup` directive, creating a communication layer between the model and the form containing the inputs. The `formControlName` input provided by the `FormControlName` directive binds each individual input to the form control defined in `FormGroup`. The form controls communicate with their respective elements. They also communicate changes to the form group instance, which provides the source of truth for the model value. -### Saving form data +**Save form data** The `ProfileEditor` component accepts input from the user, but in a real scenario you want to capture the form value and make available for further processing outside the component. The `FormGroup` directive listens for the `submit` event emitted by the `form` element and emits an `ngSubmit` event that you can bind to a callback function. @@ -176,11 +204,11 @@ Use a `button` element to add a button to the bottom of the form to trigger the <div class="alert is-helpful"> -**Note:** The button in the snippet above also has a `disabled` binding attached to it to disable the button when `profileForm` is invalid. You aren't performing any validation yet, so the button is always enabled. Simple form validation is covered in the [Simple form validation](#simple-form-validation) section. +**Note:** The button in the snippet above also has a `disabled` binding attached to it to disable the button when `profileForm` is invalid. You aren't performing any validation yet, so the button is always enabled. Basic form validation is covered in the [Validating form input](#basic-form-validation "Basic form validation.") section. </div> -#### Displaying the component +**Display the component** To display the `ProfileEditor` component that contains the form, add it to a component template. @@ -192,19 +220,30 @@ To display the `ProfileEditor` component that contains the form, add it to a com <img src="generated/images/guide/reactive-forms/profile-editor-1.png" alt="Profile Editor"> </div> -## Creating nested form groups +{@a nested-groups} + +### Creating nested form groups -When building complex forms, managing the different areas of information is easier in smaller sections, and some groups of information naturally fall into the same group. Using a nested form group instance allows you to break large forms groups into smaller, more manageable ones. +Form groups can accept both individual form control instances and other form group instances as children. This makes composing complex form models easier to maintain and logically group together. -### Step 1: Creating a nested group +When building complex forms, managing the different areas of information is easier in smaller sections. Using a nested form group instance allows you to break large forms groups into smaller, more manageable ones. -An address is a good example of information that can be grouped together. Form groups can accept both form control and form group instances as children. This makes composing complex form models easier to maintain and logically group together. To create a nested group in `profileForm`, add a nested `address` element to the form group instance. +To make more complex forms, use the following steps. + +1. Create a nested group. +2. Group the nested form in the template. + +Some types of information naturally fall into the same group. A name and address are typical examples of such nested groups, and are used in the following examples. + +**Create a nested group** + +To create a nested group in `profileForm`, add a nested `address` element to the form group instance. <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.1.ts" region="nested-formgroup" header="src/app/profile-editor/profile-editor.component.ts (nested form group)"></code-example> In this example, `address group` combines the current `firstName` and `lastName` controls with the new `street`, `city`, `state`, and `zip` controls. Even though the `address` element in the form group is a child of the overall `profileForm` element in the form group, the same rules apply with value and status changes. Changes in status and value from the nested form group propagate to the parent form group, maintaining consistency with the overall model. -### Step 2: Grouping the nested form in the template +**Group the nested form in the template** After you update the model in the component class, update the template to connect the form group instance and its input elements. @@ -220,16 +259,14 @@ The `ProfileEditor` form is displayed as one group, but the model is broken down <div class="alert is-helpful"> -**Note:** Display the value for the form group instance in the component template using the `value` property and `JsonPipe`. +**Tip** Display the value for the form group instance in the component template using the `value` property and `JsonPipe`. </div> -## Partial model updates +### Updating parts of the data model When updating the value for a form group instance that contains multiple controls, you may only want to update parts of the model. This section covers how to update specific parts of a form control data model. -### Patching the model value - There are two ways to update the model value: * Use the `setValue()` method to set a new value for an individual control. The `setValue()` method strictly adheres to the structure of the form group and replaces the entire value for the control. @@ -250,13 +287,19 @@ Simulate an update by adding a button to the template to update the user profile When a user clicks the button, the `profileForm` model is updated with new values for `firstName` and `street`. Notice that `street` is provided in an object inside the `address` property. This is necessary because the `patchValue()` method applies the update against the model structure. `PatchValue()` only updates properties that the form model defines. -## Generating form controls with FormBuilder +## Using the FormBuilder service to generate controls Creating form control instances manually can become repetitive when dealing with multiple forms. The `FormBuilder` service provides convenient methods for generating controls. -The following section refactors the `ProfileEditor` component to use the form builder service to create form control and form group instances. +Use the following steps to take advantage of this service. + +1. Import the `FormBuilder` class. +2. Inject the `FormBuilder` service. +3. Generate the form contents. -### Step 1: Importing the FormBuilder class +The following examples show how to refactor the `ProfileEditor` component to use the form builder service to create form control and form group instances. + +**Import the FormBuilder class** Import the `FormBuilder` class from the `@angular/forms` package. @@ -264,7 +307,7 @@ Import the `FormBuilder` class from the `@angular/forms` package. </code-example> -### Step 2: Injecting the FormBuilder service +**Inject the FormBuilder service** The `FormBuilder` service is an injectable provider that is provided with the reactive forms module. Inject this dependency by adding it to the component constructor. @@ -272,7 +315,7 @@ The `FormBuilder` service is an injectable provider that is provided with the re </code-example> -### Step 3: Generating form controls +**Generate form controls** The `FormBuilder` service has three methods: `control()`, `group()`, and `array()`. These are factory methods for generating instances in your component classes including form controls, form groups, and form arrays. @@ -286,7 +329,7 @@ In the example above, you use the `group()` method with the same object to defin <div class="alert is-helpful"> -**Note:** You can define the control with just the initial value, but if your controls need sync or async validation, add sync and async validators as the second and third items in the array. +**Tip** You can define the control with just the initial value, but if your controls need sync or async validation, add sync and async validators as the second and third items in the array. </div> @@ -304,11 +347,21 @@ Compare using the form builder to creating the instances manually. </code-tabs> -## Simple form validation +{@a basic-form-validation} + +## Validating form input -_Form validation_ is used to validate user input to ensure it's complete and correct. This section covers adding a single validator to a form control and displaying the overall form status. Form validation is covered more extensively in the [Form Validation](guide/form-validation) guide. +_Form validation_ is used to ensure that user input is complete and correct. This section covers adding a single validator to a form control and displaying the overall form status. Form validation is covered more extensively in the [Form Validation](guide/form-validation "All about form validation.") guide. -### Step 1: Importing a validator function +Use the following steps to add form validation. + +1. Import a validator function in your form component. +2. Add the validator to the field in the form. +3. Add logic to handle the validation status. + +The most common validation is making a field required. The following example shows how to add a required validation to the `firstName` control and display the result of validation. + +**Import a validator function** Reactive forms include a set of validator functions for common use cases. These functions receive a control to validate against and return an error object or a null value based on the validation check. @@ -318,9 +371,7 @@ Import the `Validators` class from the `@angular/forms` package. </code-example> -### Step 2: Making a field required - -The most common validation is making a field required. This section describes how to add a required validation to the `firstName` control. +**Make a field required** In the `ProfileEditor` component, add the `Validators.required` static method as the second item in the array for the `firstName` control. @@ -338,7 +389,7 @@ HTML5 has a set of built-in attributes that you can use for native validation, i </div> -### Displaying form status +**Display form status** When you add a required field to the form control, its initial status is invalid. This invalid status propagates to the parent form group element, making its status invalid. Access the current status of the form group instance through its `status` property. @@ -352,13 +403,24 @@ Display the current status of `profileForm` using interpolation. The **Submit** button is disabled because `profileForm` is invalid due to the required `firstName` form control. After you fill out the `firstName` input, the form becomes valid and the **Submit** button is enabled. -For more on form validation, visit the [Form Validation](guide/form-validation) guide. +For more on form validation, visit the [Form Validation](guide/form-validation "All about form validation.") guide. + +{@a dynamic-forms} + +## Creating dynamic forms + +`FormArray` is an alternative to `FormGroup` for managing any number of unnamed controls. As with form group instances, you can dynamically insert and remove controls from form array instances, and the form array instance value and validation status is calculated from its child controls. However, you don't need to define a key for each control by name, so this is a great option if you don't know the number of child values in advance. + +To define a dynamic form, take the following steps. -## Dynamic controls using form arrays +1. Import the `FormArray` class. +2. Define a `FormArray` control. +3. Access the `FormArray` control with a getter method. +4. Display the form array in a template. -`FormArray` is an alternative to `FormGroup` for managing any number of unnamed controls. As with form group instances, you can dynamically insert and remove controls from form array instances, and the form array instance value and validation status is calculated from its child controls. However, you don't need to define a key for each control by name, so this is a great option if you don't know the number of child values in advance. The following example shows you how to manage an array of *aliases* in `ProfileEditor`. +The following example shows you how to manage an array of *aliases* in `ProfileEditor`. -### Step 1: Importing the FormArray class +**Import the FormArray class** Import the `FormArray` class from `@angular/forms` to use for type information. The `FormBuilder` service is ready to create a `FormArray` instance. @@ -366,7 +428,7 @@ Import the `FormArray` class from `@angular/forms` to use for type information. </code-example> -### Step 2: Defining a FormArray control +**Define a FormArray control** You can initialize a form array with any number of controls, from zero to many, by defining them in an array. Add an `aliases` property to the form group instance for `profileForm` to define the form array. @@ -378,7 +440,7 @@ Use the `FormBuilder.array()` method to define the array, and the `FormBuilder.c The aliases control in the form group instance is now populated with a single control until more controls are added dynamically. -### Step 3: Accessing the FormArray control +**Access the FormArray control** A getter provides easy access to the aliases in the form array instance compared to repeating the `profileForm.get()` method to get each instance. The form array instance represents an undefined number of controls in an array. It's convenient to access a control through a getter, and this approach is easy to repeat for additional controls. @@ -394,7 +456,8 @@ Use the getter syntax to create an `aliases` class property to retrieve the alia </div> -Define a method to dynamically insert an alias control into the alias's form array. The `FormArray.push()` method inserts the control as a new item in the array. +Define a method to dynamically insert an alias control into the alias's form array. +The `FormArray.push()` method inserts the control as a new item in the array. <code-example path="reactive-forms/src/app/profile-editor/profile-editor.component.ts" region="add-alias" header="src/app/profile-editor/profile-editor.component.ts (add alias)"> @@ -402,7 +465,7 @@ Define a method to dynamically insert an alias control into the alias's form arr In the template, each control is displayed as a separate input field. -### Step 4: Displaying the form array in the template +**Display the form array in the template** To attach the aliases from your form model, you must add it to the template. Similar to the `formGroupName` input provided by `FormGroupNameDirective`, `formArrayName` binds communication from the form array instance to the template with `FormArrayNameDirective`. @@ -418,7 +481,7 @@ The `*ngFor` directive iterates over each form control instance provided by the Each time a new alias instance is added, the new form array instance is provided its control based on the index. This allows you to track each individual control when calculating the status and value of the root control. -#### Adding an alias +**Add an alias** Initially, the form contains one `Alias` field. To add another field, click the **Add Alias** button. You can also validate the array of aliases reported by the form model displayed by `Form Value` at the bottom of the template. @@ -428,15 +491,14 @@ Initially, the form contains one `Alias` field. To add another field, click the </div> -{@a appendix} -## Appendix {@a reactive-forms-api} -### Reactive forms API +## Reactive forms API summary -Listed below are the base classes and services used to create and manage form controls. +The following table lists the base classes and services used to create and manage reactive form controls. +For complete syntax details, see the API reference documentation for the [Forms package](api/forms "API reference."). #### Classes diff --git a/packages/forms/src/directives/reactive_directives/form_control_directive.ts b/packages/forms/src/directives/reactive_directives/form_control_directive.ts index 28d1957a94e13..0d9711fc03449 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_directive.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_directive.ts @@ -30,7 +30,12 @@ export const formControlBinding: any = { /** * @description - * * Syncs a standalone `FormControl` instance to a form control element. + * Synchronizes a standalone `FormControl` instance to a form control element. + * + * Note that support for using the `ngModel` input property and `ngModelChange` event with reactive + * form directives was deprecated in Angular v6 and is scheduled for removal in + * a future version of Angular. + * For details, see [Deprecated features](guide/deprecations#ngmodel-with-reactive-forms). * * @see [Reactive Forms Guide](guide/reactive-forms) * @see `FormControl` @@ -38,80 +43,10 @@ export const formControlBinding: any = { * * @usageNotes * - * ### Registering a single form control - * - * The following examples shows how to register a standalone control and set its value. + * The following example shows how to register a standalone control and set its value. * * {@example forms/ts/simpleFormControl/simple_form_control_example.ts region='Component'} * - * ### Use with ngModel - * - * Support for using the `ngModel` input property and `ngModelChange` event with reactive - * form directives has been deprecated in Angular v6 and will be removed in a future version - * of Angular. - * - * Now deprecated: - * - * ```html - * <input [formControl]="control" [(ngModel)]="value"> - * ``` - * - * ```ts - * this.value = 'some value'; - * ``` - * - * This has been deprecated for a few reasons. First, developers have found this pattern - * confusing. It seems like the actual `ngModel` directive is being used, but in fact it's - * an input/output property named `ngModel` on the reactive form directive that simply - * approximates (some of) its behavior. Specifically, it allows getting/setting the value - * and intercepting value events. However, some of `ngModel`'s other features - like - * delaying updates with`ngModelOptions` or exporting the directive - simply don't work, - * which has understandably caused some confusion. - * - * In addition, this pattern mixes template-driven and reactive forms strategies, which - * we generally don't recommend because it doesn't take advantage of the full benefits of - * either strategy. Setting the value in the template violates the template-agnostic - * principles behind reactive forms, whereas adding a `FormControl`/`FormGroup` layer in - * the class removes the convenience of defining forms in the template. - * - * To update your code before support is removed, you'll want to decide whether to stick - * with reactive form directives (and get/set values using reactive forms patterns) or - * switch over to template-driven directives. - * - * After (choice 1 - use reactive forms): - * - * ```html - * <input [formControl]="control"> - * ``` - * - * ```ts - * this.control.setValue('some value'); - * ``` - * - * After (choice 2 - use template-driven forms): - * - * ```html - * <input [(ngModel)]="value"> - * ``` - * - * ```ts - * this.value = 'some value'; - * ``` - * - * By default, when you use this pattern, you will see a deprecation warning once in dev - * mode. You can choose to silence this warning by providing a config for - * `ReactiveFormsModule` at import time: - * - * ```ts - * imports: [ - * ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'}); - * ] - * ``` - * - * Alternatively, you can choose to surface a separate warning for each instance of this - * pattern with a config value of `"always"`. This may help to track down where in the code - * the pattern is being used as the code is being updated. - * * @ngModule ReactiveFormsModule * @publicApi */ diff --git a/packages/forms/src/directives/reactive_directives/form_control_name.ts b/packages/forms/src/directives/reactive_directives/form_control_name.ts index 6a4e9da351a45..d425f8da5d29a 100644 --- a/packages/forms/src/directives/reactive_directives/form_control_name.ts +++ b/packages/forms/src/directives/reactive_directives/form_control_name.ts @@ -50,77 +50,13 @@ export const controlNameBinding: any = { * * Radio buttons: `RadioControlValueAccessor` * * Selects: `SelectControlValueAccessor` * - * ### Use with ngModel + * ### Use with ngModel is deprecated * * Support for using the `ngModel` input property and `ngModelChange` event with reactive - * form directives has been deprecated in Angular v6 and will be removed in a future - * version of Angular. + * form directives has been deprecated in Angular v6 and is scheduled for removal in + * a future version of Angular. * - * Now deprecated: - * - * ```html - * <form [formGroup]="form"> - * <input formControlName="first" [(ngModel)]="value"> - * </form> - * ``` - * - * ```ts - * this.value = 'some value'; - * ``` - * - * This has been deprecated for a few reasons. First, developers have found this pattern - * confusing. It seems like the actual `ngModel` directive is being used, but in fact it's - * an input/output property named `ngModel` on the reactive form directive that simply - * approximates (some of) its behavior. Specifically, it allows getting/setting the value - * and intercepting value events. However, some of `ngModel`'s other features - like - * delaying updates with `ngModelOptions` or exporting the directive - simply don't work, - * which has understandably caused some confusion. - * - * In addition, this pattern mixes template-driven and reactive forms strategies, which - * we generally don't recommend because it doesn't take advantage of the full benefits of - * either strategy. Setting the value in the template violates the template-agnostic - * principles behind reactive forms, whereas adding a `FormControl`/`FormGroup` layer in - * the class removes the convenience of defining forms in the template. - * - * To update your code before support is removed, you'll want to decide whether to stick with - * reactive form directives (and get/set values using reactive forms patterns) or switch over to - * template-driven directives. - * - * After (choice 1 - use reactive forms): - * - * ```html - * <form [formGroup]="form"> - * <input formControlName="first"> - * </form> - * ``` - * - * ```ts - * this.form.get('first').setValue('some value'); - * ``` - * - * After (choice 2 - use template-driven forms): - * - * ```html - * <input [(ngModel)]="value"> - * ``` - * - * ```ts - * this.value = 'some value'; - * ``` - * - * By default, when you use this pattern, you will see a deprecation warning once in dev - * mode. You can choose to silence this warning by providing a config for - * `ReactiveFormsModule` at import time: - * - * ```ts - * imports: [ - * ReactiveFormsModule.withConfig({warnOnNgModelWithFormControl: 'never'}) - * ] - * ``` - * - * Alternatively, you can choose to surface a separate warning for each instance of this - * pattern with a config value of `"always"`. This may help to track down where in the code - * the pattern is being used as the code is being updated. + * For details, see [Deprecated features](guide/deprecations#ngmodel-with-reactive-forms). * * @ngModule ReactiveFormsModule * @publicApi diff --git a/packages/forms/src/form_providers.ts b/packages/forms/src/form_providers.ts index 2fdd72b476078..5de31a70411ff 100644 --- a/packages/forms/src/form_providers.ts +++ b/packages/forms/src/form_providers.ts @@ -16,7 +16,8 @@ import {FormBuilder} from './form_builder'; * Exports the required providers and directives for template-driven forms, * making them available for import by NgModules that import this module. * - * @see [Forms Guide](/guide/forms) + * @see [Forms Overview](/guide/forms-overview) + * @see [Template-driven Forms Guide](/guide/forms) * * @publicApi */ @@ -31,9 +32,9 @@ export class FormsModule { /** * Exports the required infrastructure and directives for reactive forms, * making them available for import by NgModules that import this module. - * @see [Forms](guide/reactive-forms) * - * @see [Reactive Forms Guide](/guide/reactive-forms) + * @see [Forms Overview](guide/forms-overview) + * @see [Reactive Forms Guide](guide/reactive-forms) * * @publicApi */ diff --git a/packages/forms/src/model.ts b/packages/forms/src/model.ts index 169f9e7446ab1..dc49b050753a3 100644 --- a/packages/forms/src/model.ts +++ b/packages/forms/src/model.ts @@ -700,6 +700,7 @@ export abstract class AbstractControl { * Calling `setErrors` also updates the validity of the parent control. * * @usageNotes + * * ### Manually set the errors for a control * * ``` @@ -935,7 +936,7 @@ export abstract class AbstractControl { * This is one of the three fundamental building blocks of Angular forms, along with * `FormGroup` and `FormArray`. It extends the `AbstractControl` class that * implements most of the base functionality for accessing the value, validation status, - * user interactions and events. + * user interactions and events. See [usage examples below](#usage-notes). * * @see `AbstractControl` * @see [Reactive Forms Guide](guide/reactive-forms) From 1beccc1a6c01ede758bf22f703508ba51f1f464e Mon Sep 17 00:00:00 2001 From: Kara Erickson <karakara@google.com> Date: Tue, 7 Apr 2020 16:37:55 -0700 Subject: [PATCH 147/262] docs: release notes for the v9.1.1 release --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3e1f514dcfcd..e9bc58786413e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +<a name="9.1.1"></a> +## [9.1.1](https://github.com/angular/angular/compare/9.1.0...9.1.1) (2020-04-07) + + +### Bug Fixes + +* **compiler:** avoid undefined expressions in holey array ([#36343](https://github.com/angular/angular/issues/36343)) ([90cae34](https://github.com/angular/angular/commit/90cae34)) +* **compiler:** resolve enum values in binary operations ([#36461](https://github.com/angular/angular/issues/36461)) ([cbc25bb](https://github.com/angular/angular/commit/cbc25bb)), closes [#35584](https://github.com/angular/angular/issues/35584) +* **compiler-cli:** pass real source spans where they are empty ([#31805](https://github.com/angular/angular/issues/31805)) ([4894220](https://github.com/angular/angular/commit/4894220)) +* **core:** avoid migration error when non-existent symbol is imported ([#36367](https://github.com/angular/angular/issues/36367)) ([dff52ec](https://github.com/angular/angular/commit/dff52ec)), closes [#36346](https://github.com/angular/angular/issues/36346) +* **core:** ngOnDestroy on multi providers called with incorrect context ([#35840](https://github.com/angular/angular/issues/35840)) ([af42694](https://github.com/angular/angular/commit/af42694)), closes [#35231](https://github.com/angular/angular/issues/35231) +* **core:** run `APP_INITIALIZER`s before accessing `LOCALE_ID` token in Ivy TestBed ([#36237](https://github.com/angular/angular/issues/36237)) ([5c28af0](https://github.com/angular/angular/commit/5c28af0)), closes [#36230](https://github.com/angular/angular/issues/36230) +* **core:** undecorated-classes-with-decorated-fields migration does not decorate derived classes ([#35339](https://github.com/angular/angular/issues/35339)) ([5ff5a11](https://github.com/angular/angular/commit/5ff5a11)), closes [#34376](https://github.com/angular/angular/issues/34376) +* **core:** undecorated-classes migration should handle derived abstract classes ([#35339](https://github.com/angular/angular/issues/35339)) ([a631b99](https://github.com/angular/angular/commit/a631b99)) +* **language-service:** infer type of elements of array-like objects ([#36312](https://github.com/angular/angular/issues/36312)) ([ff523c9](https://github.com/angular/angular/commit/ff523c9)), closes [#36191](https://github.com/angular/angular/issues/36191) +* **language-service:** use the `HtmlAst` to get the span of HTML tag ([#36371](https://github.com/angular/angular/issues/36371)) ([ffa4e11](https://github.com/angular/angular/commit/ffa4e11)) +* **ngcc:** add process title ([#36448](https://github.com/angular/angular/issues/36448)) ([136596d](https://github.com/angular/angular/commit/136596d)), closes [/github.com/angular/angular/issues/36414#issuecomment-609644282](https://github.com//github.com/angular/angular/issues/36414/issues/issuecomment-609644282) +* **ngcc:** allow ngcc configuration to match pre-release versions of packages ([#36370](https://github.com/angular/angular/issues/36370)) ([cb0a2a0](https://github.com/angular/angular/commit/cb0a2a0)) +* **ngcc:** correctly detect imported TypeScript helpers ([#36284](https://github.com/angular/angular/issues/36284)) ([879457c](https://github.com/angular/angular/commit/879457c)), closes [#36089](https://github.com/angular/angular/issues/36089) +* **ngcc:** correctly identify relative Windows-style import paths ([#36372](https://github.com/angular/angular/issues/36372)) ([0daa488](https://github.com/angular/angular/commit/0daa488)) +* **ngcc:** correctly identify the package path of secondary entry-points ([#36249](https://github.com/angular/angular/issues/36249)) ([e53b686](https://github.com/angular/angular/commit/e53b686)), closes [#35747](https://github.com/angular/angular/issues/35747) +* **ngcc:** detect non-emitted, non-imported TypeScript helpers ([#36418](https://github.com/angular/angular/issues/36418)) ([93b32d3](https://github.com/angular/angular/commit/93b32d3)) +* **ngcc:** do not spawn more processes than intended in parallel mode ([#36280](https://github.com/angular/angular/issues/36280)) ([6ea232e](https://github.com/angular/angular/commit/6ea232e)), closes [#35719](https://github.com/angular/angular/issues/35719) [#36278](https://github.com/angular/angular/issues/36278) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/main.ts#L429](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/main.ts/issues/L429) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L108](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts/issues/L108) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L110](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts/issues/L110) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L199](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts/issues/L199) +* **ngcc:** do not write entry-point manifest outside node_modules ([#36299](https://github.com/angular/angular/issues/36299)) ([bb8744d](https://github.com/angular/angular/commit/bb8744d)), closes [#36296](https://github.com/angular/angular/issues/36296) +* **ngcc:** don't crash on cyclic source-map references ([#36452](https://github.com/angular/angular/issues/36452)) ([56af303](https://github.com/angular/angular/commit/56af303)), closes [#35727](https://github.com/angular/angular/issues/35727) [#35757](https://github.com/angular/angular/issues/35757) +* **ngcc:** handle bad path mappings when finding entry-points ([#36331](https://github.com/angular/angular/issues/36331)) ([7bb3588](https://github.com/angular/angular/commit/7bb3588)), closes [#36313](https://github.com/angular/angular/issues/36313) [#36283](https://github.com/angular/angular/issues/36283) +* **ngcc:** handle entry-points within container folders ([#36305](https://github.com/angular/angular/issues/36305)) ([392ef93](https://github.com/angular/angular/commit/392ef93)), closes [#35756](https://github.com/angular/angular/issues/35756) [#36216](https://github.com/angular/angular/issues/36216) +* **ngcc:** sniff `main` property for ESM5 format ([#36396](https://github.com/angular/angular/issues/36396)) ([93cbef2](https://github.com/angular/angular/commit/93cbef2)), closes [#35788](https://github.com/angular/angular/issues/35788) +* **ngcc:** support ignoring deep-imports via package config ([#36423](https://github.com/angular/angular/issues/36423)) ([31eaf78](https://github.com/angular/angular/commit/31eaf78)), closes [#35750](https://github.com/angular/angular/issues/35750) +* **ngcc:** support simple `browser` property in entry-points ([#36396](https://github.com/angular/angular/issues/36396)) ([b0d680d](https://github.com/angular/angular/commit/b0d680d)), closes [#36062](https://github.com/angular/angular/issues/36062) +* **platform-server:** update `xhr2` dependency ([#36366](https://github.com/angular/angular/issues/36366)) ([14ae3c0](https://github.com/angular/angular/commit/14ae3c0)), closes [#36358](https://github.com/angular/angular/issues/36358) +* **router:** state data missing in routerLink ([#36462](https://github.com/angular/angular/issues/36462)) ([0e7a89a](https://github.com/angular/angular/commit/0e7a89a)), closes [#33173](https://github.com/angular/angular/issues/33173) + + <a name="9.1.0"></a> # [9.1.0](https://github.com/angular/angular/compare/9.0.0...9.1.0) (2020-03-25) From 7549c65502e26efdde0e695de863601c6971d586 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Wed, 8 Apr 2020 10:38:51 -0700 Subject: [PATCH 148/262] build: update matching regex for bazel stamping (#36523) Previously, the bazel stamping regex only matched on versions 0-9 for major and minor numbers, this update allows for matching on any number for major, minor or patch. PR Close #36523 --- tools/bazel_stamp_vars.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/bazel_stamp_vars.js b/tools/bazel_stamp_vars.js index 6d29b9d512138..7368c57bfb176 100644 --- a/tools/bazel_stamp_vars.js +++ b/tools/bazel_stamp_vars.js @@ -43,7 +43,7 @@ console.log(`BUILD_SCM_LOCAL_CHANGES ${LOCAL_CHANGES}`); // This will ignore non-version tags which would break unit tests expecting a valid version // number in the package headers const BUILD_SCM_VERSION_RAW = - _exec(`git describe --match [0-9].[0-9].[0-9]* --abbrev=7 --tags HEAD`); + _exec(`git describe --match [0-9]*.[0-9]*.[0-9]* --abbrev=7 --tags HEAD`); // Reformat `git describe` version string into a more semver-ish string // From: 5.2.0-rc.0-57-g757f886 From db4a4484398ce8b4e1186a82fe8dd6a7cff4f373 Mon Sep 17 00:00:00 2001 From: Kara Erickson <karakara@google.com> Date: Wed, 8 Apr 2020 11:08:01 -0700 Subject: [PATCH 149/262] release: cut the v10.0.0-next.0 release --- CHANGELOG.md | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9bc58786413e..621ce88083b2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,65 @@ +<a name="10.0.0-next.0"></a> +# [10.0.0-next.0](https://github.com/angular/angular/compare/9.1.0-rc.0...10.0.0-next.0) (2020-04-08) + + +### Bug Fixes + +* **common:** let `KeyValuePipe` accept type unions with `null` ([#36093](https://github.com/angular/angular/issues/36093)) ([d783519](https://github.com/angular/angular/commit/d783519)), closes [#35743](https://github.com/angular/angular/issues/35743) +* **compiler:** avoid undefined expressions in holey array ([#36343](https://github.com/angular/angular/issues/36343)) ([5516802](https://github.com/angular/angular/commit/5516802)) +* **compiler:** record correct end of expression ([#34690](https://github.com/angular/angular/issues/34690)) ([df890d7](https://github.com/angular/angular/commit/df890d7)), closes [#33477](https://github.com/angular/angular/issues/33477) +* **compiler:** resolve enum values in binary operations ([#36461](https://github.com/angular/angular/issues/36461)) ([64022f5](https://github.com/angular/angular/commit/64022f5)), closes [#35584](https://github.com/angular/angular/issues/35584) +* **compiler-cli:** pass real source spans where they are empty ([#31805](https://github.com/angular/angular/issues/31805)) ([e893c5a](https://github.com/angular/angular/commit/e893c5a)) +* **core:** avoid migration error when non-existent symbol is imported ([#36367](https://github.com/angular/angular/issues/36367)) ([d43c306](https://github.com/angular/angular/commit/d43c306)), closes [#36346](https://github.com/angular/angular/issues/36346) +* **core:** ngOnDestroy on multi providers called with incorrect context ([#35840](https://github.com/angular/angular/issues/35840)) ([95fc3d4](https://github.com/angular/angular/commit/95fc3d4)), closes [#35231](https://github.com/angular/angular/issues/35231) +* **core:** run `APP_INITIALIZER`s before accessing `LOCALE_ID` token in Ivy TestBed ([#36237](https://github.com/angular/angular/issues/36237)) ([1649743](https://github.com/angular/angular/commit/1649743)), closes [#36230](https://github.com/angular/angular/issues/36230) +* **core:** undecorated-classes-with-decorated-fields migration does not decorate derived classes ([#35339](https://github.com/angular/angular/issues/35339)) ([32eafef](https://github.com/angular/angular/commit/32eafef)), closes [#34376](https://github.com/angular/angular/issues/34376) +* **core:** workaround Terser inlining bug ([#36200](https://github.com/angular/angular/issues/36200)) ([0ce8ad3](https://github.com/angular/angular/commit/0ce8ad3)) +* **elements:** correctly handle setting inputs to `undefined` ([#36140](https://github.com/angular/angular/issues/36140)) ([9ba46d9](https://github.com/angular/angular/commit/9ba46d9)) +* **elements:** correctly set `SimpleChange#firstChange` for pre-existing inputs ([#36140](https://github.com/angular/angular/issues/36140)) ([b14ac96](https://github.com/angular/angular/commit/b14ac96)), closes [#36130](https://github.com/angular/angular/issues/36130) +* **language-service:** infer type of elements of array-like objects ([#36312](https://github.com/angular/angular/issues/36312)) ([fe2b692](https://github.com/angular/angular/commit/fe2b692)), closes [#36191](https://github.com/angular/angular/issues/36191) +* **language-service:** use the `HtmlAst` to get the span of HTML tag ([#36371](https://github.com/angular/angular/issues/36371)) ([81195a2](https://github.com/angular/angular/commit/81195a2)) +* **localize:** allow ICU expansion case to start with any character except `}` ([#36123](https://github.com/angular/angular/issues/36123)) ([fced8ee](https://github.com/angular/angular/commit/fced8ee)), closes [#31586](https://github.com/angular/angular/issues/31586) +* **ngcc:** add process title ([#36448](https://github.com/angular/angular/issues/36448)) ([76a8cd5](https://github.com/angular/angular/commit/76a8cd5)), closes [/github.com/angular/angular/issues/36414#issuecomment-609644282](https://github.com//github.com/angular/angular/issues/36414/issues/issuecomment-609644282) +* **ngcc:** allow ngcc configuration to match pre-release versions of packages ([#36370](https://github.com/angular/angular/issues/36370)) ([326240e](https://github.com/angular/angular/commit/326240e)) +* **ngcc:** correctly detect imported TypeScript helpers ([#36284](https://github.com/angular/angular/issues/36284)) ([ca25c95](https://github.com/angular/angular/commit/ca25c95)), closes [#36089](https://github.com/angular/angular/issues/36089) +* **ngcc:** correctly identify relative Windows-style import paths ([#36372](https://github.com/angular/angular/issues/36372)) ([aecf9de](https://github.com/angular/angular/commit/aecf9de)) +* **ngcc:** correctly identify the package path of secondary entry-points ([#36249](https://github.com/angular/angular/issues/36249)) ([995cd15](https://github.com/angular/angular/commit/995cd15)), closes [#35747](https://github.com/angular/angular/issues/35747) +* **ngcc:** detect non-emitted, non-imported TypeScript helpers ([#36418](https://github.com/angular/angular/issues/36418)) ([5fa7b8b](https://github.com/angular/angular/commit/5fa7b8b)) +* **ngcc:** do not spawn more processes than intended in parallel mode ([#36280](https://github.com/angular/angular/issues/36280)) ([5cee709](https://github.com/angular/angular/commit/5cee709)), closes [#35719](https://github.com/angular/angular/issues/35719) [#36278](https://github.com/angular/angular/issues/36278) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/main.ts#L429](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/main.ts/issues/L429) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L108](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts/issues/L108) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L110](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts/issues/L110) [/github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts#L199](https://github.com//github.com/angular/angular/blob/b8e9a30d3b6/packages/compiler-cli/ngcc/src/execution/cluster/master.ts/issues/L199) +* **ngcc:** do not write entry-point manifest outside node_modules ([#36299](https://github.com/angular/angular/issues/36299)) ([c6dd900](https://github.com/angular/angular/commit/c6dd900)), closes [#36296](https://github.com/angular/angular/issues/36296) +* **ngcc:** don't crash on cyclic source-map references ([#36452](https://github.com/angular/angular/issues/36452)) ([ee70a18](https://github.com/angular/angular/commit/ee70a18)), closes [#35727](https://github.com/angular/angular/issues/35727) [#35757](https://github.com/angular/angular/issues/35757) +* **ngcc:** handle bad path mappings when finding entry-points ([#36331](https://github.com/angular/angular/issues/36331)) ([cc4b813](https://github.com/angular/angular/commit/cc4b813)), closes [#36313](https://github.com/angular/angular/issues/36313) [#36283](https://github.com/angular/angular/issues/36283) +* **ngcc:** handle entry-points within container folders ([#36305](https://github.com/angular/angular/issues/36305)) ([38ad1d9](https://github.com/angular/angular/commit/38ad1d9)), closes [#35756](https://github.com/angular/angular/issues/35756) [#36216](https://github.com/angular/angular/issues/36216) +* **ngcc:** sniff `main` property for ESM5 format ([#36396](https://github.com/angular/angular/issues/36396)) ([2463548](https://github.com/angular/angular/commit/2463548)), closes [#35788](https://github.com/angular/angular/issues/35788) +* **ngcc:** support ignoring deep-imports via package config ([#36423](https://github.com/angular/angular/issues/36423)) ([f9fb833](https://github.com/angular/angular/commit/f9fb833)), closes [#35750](https://github.com/angular/angular/issues/35750) +* **ngcc:** support simple `browser` property in entry-points ([#36396](https://github.com/angular/angular/issues/36396)) ([6b3aa60](https://github.com/angular/angular/commit/6b3aa60)), closes [#36062](https://github.com/angular/angular/issues/36062) +* **ngcc:** use path-mappings from tsconfig in dependency resolution ([#36180](https://github.com/angular/angular/issues/36180)) ([380de1e](https://github.com/angular/angular/commit/380de1e)), closes [#36119](https://github.com/angular/angular/issues/36119) +* **ngcc:** use preserve whitespaces from tsconfig if provided ([#36189](https://github.com/angular/angular/issues/36189)) ([b8e9a30](https://github.com/angular/angular/commit/b8e9a30)), closes [#35871](https://github.com/angular/angular/issues/35871) +* **platform-server:** update `xhr2` dependency ([#36366](https://github.com/angular/angular/issues/36366)) ([b59bc0e](https://github.com/angular/angular/commit/b59bc0e)), closes [#36358](https://github.com/angular/angular/issues/36358) +* **router:** allow UrlMatcher to return null ([#36402](https://github.com/angular/angular/issues/36402)) ([568e9df](https://github.com/angular/angular/commit/568e9df)), closes [#29824](https://github.com/angular/angular/issues/29824) +* **router:** state data missing in routerLink ([#36462](https://github.com/angular/angular/issues/36462)) ([e0415db](https://github.com/angular/angular/commit/e0415db)), closes [#33173](https://github.com/angular/angular/issues/33173) +* **service-worker:** by default register the SW after 30s even the app never stabilizes ([#35870](https://github.com/angular/angular/issues/35870)) ([29e8a64](https://github.com/angular/angular/commit/29e8a64)), closes [#34464](https://github.com/angular/angular/issues/34464) +* **service-worker:** prevent SW registration strategies from affecting app stabilization ([#35870](https://github.com/angular/angular/issues/35870)) ([2d7c95f](https://github.com/angular/angular/commit/2d7c95f)) + + +### Features + +* **compiler:** add dependency info and ng-content selectors to metadata ([#35695](https://github.com/angular/angular/issues/35695)) ([32ce8b1](https://github.com/angular/angular/commit/32ce8b1)) +* **compiler:** Propagate value span of ExpressionBinding to ParsedProperty ([#36133](https://github.com/angular/angular/issues/36133)) ([d714b95](https://github.com/angular/angular/commit/d714b95)) +* **core:** undecorated-classes migration should handle derived abstract classes ([#35339](https://github.com/angular/angular/issues/35339)) ([c24ad56](https://github.com/angular/angular/commit/c24ad56)) +* **service-worker:** support timeout in `registerWhenStable` SW registration strategy ([#35870](https://github.com/angular/angular/issues/35870)) ([00efacf](https://github.com/angular/angular/commit/00efacf)), closes [#34464](https://github.com/angular/angular/issues/34464) + + +### BREAKING CHANGES + +* **router:** UrlMatcher's type now reflects that it could always return + null. + + If you implemented your own Router or Recognizer class, please update it to + handle matcher returning null. + + + <a name="9.1.1"></a> ## [9.1.1](https://github.com/angular/angular/compare/9.1.0...9.1.1) (2020-04-07) diff --git a/package.json b/package.json index 80271bf367b77..07777e3e9c845 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-srcs", - "version": "9.1.0-rc.0", + "version": "10.0.0-next.0", "private": true, "description": "Angular - a web framework for modern web apps", "homepage": "https://github.com/angular/angular", From ef4736d052a2c8ae5ec35bd4ea5c6c765b16b834 Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Fri, 3 Jan 2020 14:28:06 +0900 Subject: [PATCH 150/262] build: update jasmine to 3.5 (#34625) 1. update jasmine to 3.5 2. update @types/jasmine to 3.5 3. update @types/jasminewd2 to 2.0.8 Also fix several cases, the new jasmine 3 will help to create test cases correctly, such as in the `jasmine 2.x` version, the following case will pass ``` expect(1 == 2); ``` But in jsamine 3, the case will need to be ``` expect(1 == 2).toBeTrue(); ``` PR Close #34625 --- package.json | 8 +++--- packages/common/http/test/xhr_spec.ts | 2 +- .../test/analysis/decoration_analyzer_spec.ts | 4 +-- .../test/execution/cluster/executor_spec.ts | 4 +-- .../ngcc/test/integration/ngcc_spec.ts | 5 ++-- .../ngcc/test/locking/async_locker_spec.ts | 11 +++++++- .../unlocker_spec.ts | 3 ++- .../ngcc/test/packages/entry_point_spec.ts | 14 ++++++---- .../test/cached_file_system_spec.ts | 6 ++--- .../test/node_js_file_system_spec.ts | 26 ++++++++++--------- .../partial_evaluator/test/evaluator_spec.ts | 21 ++++++++++----- packages/compiler-cli/test/ngc_spec.ts | 12 +++++---- .../animation_query_integration_spec.ts | 16 ++++++------ .../change_detection_integration_spec.ts | 6 +++-- .../core/test/render3/global_utils_spec.ts | 2 +- .../render3/node_selector_matcher_spec.ts | 10 ++++--- packages/elements/test/utils_spec.ts | 4 ++- .../di/ts/forward_ref/forward_ref_spec.ts | 2 +- .../language-service/test/html_info_spec.ts | 4 +-- .../test/dom/events/hammer_gestures_spec.ts | 2 +- .../test/dom/events/key_events_spec.ts | 2 +- packages/router/test/integration.spec.ts | 3 ++- packages/service-worker/test/comm_spec.ts | 6 ++--- packages/service-worker/test/module_spec.ts | 2 +- .../service-worker/worker/test/happy_spec.ts | 5 ++-- .../upgrade/src/dynamic/test/upgrade_spec.ts | 6 ++--- packages/zone.js/test/extra/bluebird.spec.ts | 8 ++++++ packages/zone.js/test/node/crypto.spec.ts | 2 +- yarn.lock | 13 +++------- 29 files changed, 124 insertions(+), 85 deletions(-) diff --git a/package.json b/package.json index 07777e3e9c845..717e1c28b77b1 100644 --- a/package.json +++ b/package.json @@ -72,8 +72,8 @@ "@types/fs-extra": "4.0.2", "@types/hammerjs": "2.0.35", "@types/inquirer": "^0.0.44", - "@types/jasmine": "^2.8.8", - "@types/jasminewd2": "^2.0.6", + "@types/jasmine": "3.5.10", + "@types/jasminewd2": "^2.0.8", "@types/minimist": "^1.2.0", "@types/node": "^12.11.1", "@types/selenium-webdriver": "3.0.7", @@ -105,8 +105,8 @@ "hammerjs": "2.0.8", "http-server": "^0.11.1", "incremental-dom": "0.4.1", - "jasmine": "^3.1.0", - "jasmine-core": "^3.1.0", + "jasmine": "^3.5.0", + "jasmine-core": "^3.5.0", "jquery": "3.0.0", "karma": "~4.1.0", "karma-chrome-launcher": "^2.2.0", diff --git a/packages/common/http/test/xhr_spec.ts b/packages/common/http/test/xhr_spec.ts index 88e608d484b3f..0d08c3a91ea62 100644 --- a/packages/common/http/test/xhr_spec.ts +++ b/packages/common/http/test/xhr_spec.ts @@ -141,7 +141,7 @@ const XSSI_PREFIX = ')]}\'\n'; it('emits real errors via the error path', done => { backend.handle(TEST_POST).subscribe(undefined, (err: HttpErrorResponse) => { expect(err instanceof HttpErrorResponse).toBe(true); - expect(err.error instanceof Error); + expect(err.error instanceof Error).toBeTrue(); expect(err.url).toBe('/test'); done(); }); diff --git a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts index 42e932da7dc67..8ec0130a959ec 100644 --- a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -95,7 +95,7 @@ runInEachFileSystem(() => { }); // The "test" compilation result is just the name of the decorator being compiled // (suffixed with `(compiled)`) - handler.compile.and.callFake((decl: ts.Declaration, analysis: any) => { + (handler.compile as any).and.callFake((decl: ts.Declaration, analysis: any) => { logs.push(`compile: ${(decl as any).name.text}@${analysis.decoratorName} (resolved: ${ analysis.resolved})`); return `@${analysis.decoratorName} (compiled)`; @@ -183,7 +183,7 @@ runInEachFileSystem(() => { it('should call detect on the decorator handlers with each class from the parsed file', () => { expect(testHandler.detect).toHaveBeenCalledTimes(5); - expect(testHandler.detect.calls.allArgs().map(args => args[1])).toEqual([ + expect(testHandler.detect.calls.allArgs().map((args: any[]) => args[1])).toEqual([ null, jasmine.arrayContaining([jasmine.objectContaining({name: 'Component'})]), jasmine.arrayContaining([jasmine.objectContaining({name: 'Directive'})]), diff --git a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts index 87d264ab5a545..c5f7f64fe717d 100644 --- a/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts +++ b/packages/compiler-cli/ngcc/test/execution/cluster/executor_spec.ts @@ -34,9 +34,9 @@ describe('ClusterExecutor', () => { beforeEach(() => { masterRunSpy = spyOn(ClusterMaster.prototype, 'run') - .and.returnValue(Promise.resolve('CusterMaster#run()')); + .and.returnValue(Promise.resolve('CusterMaster#run()' as any)); workerRunSpy = spyOn(ClusterWorker.prototype, 'run') - .and.returnValue(Promise.resolve('CusterWorker#run()')); + .and.returnValue(Promise.resolve('CusterWorker#run()' as any)); createTaskCompletedCallback = jasmine.createSpy('createTaskCompletedCallback'); mockLogger = new MockLogger(); diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 9e9ff8ea91e9d..be342392a50d1 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -38,7 +38,7 @@ runInEachFileSystem(() => { initMockFileSystem(fs, testFiles); // Force single-process execution in unit tests by mocking available CPUs to 1. - spyOn(os, 'cpus').and.returnValue([{model: 'Mock CPU'}]); + spyOn(os, 'cpus').and.returnValue([{ model: 'Mock CPU' } as any]); }); it('should run ngcc without errors for esm2015', () => { @@ -962,7 +962,8 @@ runInEachFileSystem(() => { .toMatch(ANGULAR_CORE_IMPORT_REGEX); // Copies over files (unchanged) that did not need compiling - expect(fs.exists(_(`/node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js`))); + expect(fs.exists(_(`/node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js`))) + .toBeTrue(); expect(fs.readFile(_(`/node_modules/@angular/common/__ivy_ngcc__/esm5/src/version.js`))) .toEqual(fs.readFile(_(`/node_modules/@angular/common/esm5/src/version.js`))); diff --git a/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts b/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts index d9a045758a206..a77b34c5d823f 100644 --- a/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/async_locker_spec.ts @@ -66,6 +66,9 @@ runInEachFileSystem(() => { }); spyOn(lockFile, 'read').and.callFake(() => { log.push('read() => ' + lockFileContents); + if (lockFileContents === null) { + throw {code: 'ENOENT'}; + } return lockFileContents; }); @@ -99,6 +102,9 @@ runInEachFileSystem(() => { }); spyOn(lockFile, 'read').and.callFake(() => { log.push('read() => ' + lockFileContents); + if (lockFileContents === null) { + throw {code: 'ENOENT'}; + } return lockFileContents; }); @@ -148,6 +154,9 @@ runInEachFileSystem(() => { }); spyOn(lockFile, 'read').and.callFake(() => { log.push('read() => ' + lockFileContents); + if (lockFileContents === null) { + throw {code: 'ENOENT'}; + } return lockFileContents; }); @@ -167,4 +176,4 @@ runInEachFileSystem(() => { }); }); }); -}); \ No newline at end of file +}); diff --git a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts index d6d5d697ce7af..0e99ed74172b2 100644 --- a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts @@ -12,6 +12,7 @@ describe('unlocker', () => { it('should attach a handler to the `disconnect` event', () => { spyOn(process, 'on'); require('../../../src/locking/lock_file_with_child_process/unlocker'); - expect(process.on).toHaveBeenCalledWith('disconnect', jasmine.any(Function)); + // TODO: @JiaLiPassion, need to wait for @types/jasmine to handle the override case + expect(process.on).toHaveBeenCalledWith('disconnect' as any, jasmine.any(Function)); }); }); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index f07c779942b0c..4fed2fcd40fe5 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -70,7 +70,7 @@ runInEachFileSystem(() => { const config = new NgccConfiguration(fs, _('/project')); spyOn(config, 'getConfig').and.returnValue({ entryPoints: {[_('/project/node_modules/some_package/valid_entry_point')]: {ignore: true}} - }); + } as any); const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, _('/project/node_modules/some_package/valid_entry_point')); @@ -95,7 +95,8 @@ runInEachFileSystem(() => { esm2015: './some_other.js', }; spyOn(config, 'getConfig').and.returnValue({ - entryPoints: {[_('/project/node_modules/some_package/valid_entry_point')]: {override}} + entryPoints: {[_('/project/node_modules/some_package/valid_entry_point')]: {override}}, + versionRange: '*' }); const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, @@ -145,7 +146,9 @@ runInEachFileSystem(() => { const override = JSON.parse(createPackageJson('missing_package_json', {excludes: ['name']})); spyOn(config, 'getConfig').and.returnValue({ - entryPoints: {[_('/project/node_modules/some_package/missing_package_json')]: {override}} + entryPoints: + {[_('/project/node_modules/some_package/missing_package_json')]: {override}}, + versionRange: '*' }); const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, @@ -279,7 +282,8 @@ runInEachFileSystem(() => { ]); const config = new NgccConfiguration(fs, _('/project')); spyOn(config, 'getConfig').and.returnValue({ - entryPoints: {[_('/project/node_modules/some_package/missing_metadata')]: {}} + entryPoints: {[_('/project/node_modules/some_package/missing_metadata')]: {}}, + versionRange: '*' }); const entryPoint = getEntryPointInfo( fs, config, new MockLogger(), SOME_PACKAGE, @@ -398,7 +402,7 @@ runInEachFileSystem(() => { if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { return fail(`Expected an entry point but got ${result}`); } - entryPoint = result; + entryPoint = result as any; }); it('should return `esm2015` format for `fesm2015` property', () => { diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts index cea871856e9f6..bcba05ed8f265 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts @@ -47,7 +47,7 @@ describe('CachedFileSystem', () => { let lstatSpy: jasmine.Spy; beforeEach(() => { // For most of the tests the files are not symbolic links. - lstatSpy = spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false}); + lstatSpy = spyOn(delegate, 'lstat').and.returnValue({ isSymbolicLink: () => false } as any); }); it('should call delegate if not in cache', () => { @@ -93,7 +93,7 @@ describe('CachedFileSystem', () => { describe('invalidateCaches()', () => { it('should call the delegate `readFile()` if the path for the cached file has been invalidated', () => { - spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false}); + spyOn(delegate, 'lstat').and.returnValue({ isSymbolicLink: () => false } as any); const spy = spyOn(delegate, 'readFile').and.returnValue('Some contents'); fs.readFile(abcPath); // Call once to fill the cache spy.calls.reset(); @@ -230,7 +230,7 @@ describe('CachedFileSystem', () => { describe('moveFile()', () => { beforeEach(() => { // `moveFile()` relies upon `readFile` which calls through to `lstat()`, so stub it out. - spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false}); + spyOn(delegate, 'lstat').and.returnValue({ isSymbolicLink: () => false } as any); }); it('should call delegate', () => { diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts index a2c0adc236a1f..71babf1878459 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts @@ -65,10 +65,11 @@ describe('NodeJSFileSystem', () => { describe('readdir()', () => { it('should delegate to fs.readdirSync()', () => { - const spy = spyOn(realFs, 'readdirSync').and.returnValue(['x', 'y/z']); + const spy = spyOn(realFs, 'readdirSync').and.returnValue(['x', 'y/z'] as any); const result = fs.readdir(abcPath); expect(result).toEqual([relativeFrom('x'), relativeFrom('y/z')]); - expect(spy).toHaveBeenCalledWith(abcPath); + // TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters. + expect(spy as any).toHaveBeenCalledWith(abcPath); }); }); @@ -88,7 +89,8 @@ describe('NodeJSFileSystem', () => { const spy = spyOn(realFs, 'statSync').and.returnValue(stats); const result = fs.stat(abcPath); expect(result).toBe(stats); - expect(spy).toHaveBeenCalledWith(abcPath); + // TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters. + expect(spy as any).toHaveBeenCalledWith(abcPath); }); }); @@ -125,7 +127,7 @@ describe('NodeJSFileSystem', () => { const xyPath = absoluteFrom('/x/y'); const mkdirCalls: string[] = []; const existsCalls: string[] = []; - spyOn(realFs, 'mkdirSync').and.callFake((path: string) => mkdirCalls.push(path)); + spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => mkdirCalls.push(path)) as any); spyOn(fs, 'exists').and.callFake((path: AbsoluteFsPath) => { existsCalls.push(path); switch (path) { @@ -171,12 +173,12 @@ describe('NodeJSFileSystem', () => { } return false; }); - spyOn(fs, 'stat').and.returnValue({isDirectory: () => true}); - const mkdirSyncSpy = spyOn(realFs, 'mkdirSync').and.callFake((path: string) => { + spyOn(fs, 'stat').and.returnValue({ isDirectory: () => true } as any); + const mkdirSyncSpy = spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { if (path === abcPath) { throw new Error('It exists already. Supposedly.'); } - }); + }) as any); fs.ensureDir(abcPath); expect(mkdirSyncSpy).toHaveBeenCalledTimes(3); @@ -186,11 +188,11 @@ describe('NodeJSFileSystem', () => { it('should fail if creating the directory throws and the directory does not exist', () => { spyOn(fs, 'exists').and.returnValue(false); - spyOn(realFs, 'mkdirSync').and.callFake((path: string) => { + spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { if (path === abcPath) { throw new Error('Unable to create directory (for whatever reason).'); } - }); + }) as any); expect(() => fs.ensureDir(abcPath)) .toThrowError('Unable to create directory (for whatever reason).'); @@ -210,12 +212,12 @@ describe('NodeJSFileSystem', () => { } return false; }); - spyOn(fs, 'stat').and.returnValue({isDirectory: isDirectorySpy}); - spyOn(realFs, 'mkdirSync').and.callFake((path: string) => { + spyOn(fs, 'stat').and.returnValue({ isDirectory: isDirectorySpy } as any); + spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { if (path === abcPath) { throw new Error('It exists already. Supposedly.'); } - }); + }) as any); expect(() => fs.ensureDir(abcPath)).toThrowError('It exists already. Supposedly.'); expect(isDirectorySpy).toHaveBeenCalledTimes(1); diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index 7c3dcd3ae0b50..33e38e91a8b7b 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -775,18 +775,22 @@ runInEachFileSystem(() => { describe('(visited file tracking)', () => { it('should track each time a source file is visited', () => { - const addDependency = jasmine.createSpy('DependencyTracker'); + const addDependency = + jasmine.createSpy<DependencyTracker['addDependency']>('DependencyTracker'); const {expression, checker} = makeExpression( `class A { static foo = 42; } function bar() { return A.foo; }`, 'bar()'); const evaluator = makeEvaluator(checker, {...fakeDepTracker, addDependency}); evaluator.evaluate(expression); expect(addDependency).toHaveBeenCalledTimes(2); // two declaration visited - expect(addDependency.calls.allArgs().map(args => [args[0].fileName, args[1].fileName])) + expect( + addDependency.calls.allArgs().map( + (args: Parameters<typeof addDependency>) => [args[0].fileName, args[1].fileName])) .toEqual([[_('/entry.ts'), _('/entry.ts')], [_('/entry.ts'), _('/entry.ts')]]); }); it('should track imported source files', () => { - const addDependency = jasmine.createSpy('DependencyTracker'); + const addDependency = + jasmine.createSpy<DependencyTracker['addDependency']>('DependencyTracker'); const {expression, checker} = makeExpression(`import {Y} from './other'; const A = Y;`, 'A', [ {name: _('/other.ts'), contents: `export const Y = 'test';`}, @@ -795,7 +799,9 @@ runInEachFileSystem(() => { const evaluator = makeEvaluator(checker, {...fakeDepTracker, addDependency}); evaluator.evaluate(expression); expect(addDependency).toHaveBeenCalledTimes(2); - expect(addDependency.calls.allArgs().map(args => [args[0].fileName, args[1].fileName])) + expect( + addDependency.calls.allArgs().map( + (args: Parameters<typeof addDependency>) => [args[0].fileName, args[1].fileName])) .toEqual([ [_('/entry.ts'), _('/entry.ts')], [_('/entry.ts'), _('/other.ts')], @@ -803,7 +809,8 @@ runInEachFileSystem(() => { }); it('should track files passed through during re-exports', () => { - const addDependency = jasmine.createSpy('DependencyTracker'); + const addDependency = + jasmine.createSpy<DependencyTracker['addDependency']>('DependencyTracker'); const {expression, checker} = makeExpression(`import * as mod from './direct-reexport';`, 'mod.value.property', [ {name: _('/const.ts'), contents: 'export const value = {property: "test"};'}, @@ -823,7 +830,9 @@ runInEachFileSystem(() => { const evaluator = makeEvaluator(checker, {...fakeDepTracker, addDependency}); evaluator.evaluate(expression); expect(addDependency).toHaveBeenCalledTimes(2); - expect(addDependency.calls.allArgs().map(args => [args[0].fileName, args[1].fileName])) + expect( + addDependency.calls.allArgs().map( + (args: Parameters<typeof addDependency>) => [args[0].fileName, args[1].fileName])) .toEqual([ [_('/entry.ts'), _('/direct-reexport.ts')], // Not '/indirect-reexport.ts' or '/def.ts'. diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index d972374208b27..93ccda8f6ccdc 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -1559,11 +1559,13 @@ describe('ngc transformer command-line', () => { originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; const timerToken = 100; - spyOn(ts.sys, 'setTimeout').and.callFake((callback: () => void) => { + // TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case + spyOn(ts.sys as any, 'setTimeout').and.callFake((callback: () => void) => { timer = callback; return timerToken; }); - spyOn(ts.sys, 'clearTimeout').and.callFake((token: number) => { + // TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case + spyOn(ts.sys as any, 'clearTimeout').and.callFake((token: number) => { if (token == timerToken) { timer = undefined; } @@ -2323,17 +2325,17 @@ describe('ngc transformer command-line', () => { })); write('lib1/index.ts', ` import {Directive} from '@angular/core'; - + @Directive() export class BaseClass {} `); write('index.ts', ` import {NgModule, Directive} from '@angular/core'; import {BaseClass} from 'lib1_built'; - + @Directive({selector: 'my-dir'}) export class MyDirective extends BaseClass {} - + @NgModule({declarations: [MyDirective]}) export class AppModule {} `); diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index 37be2f2718994..4917316870bd5 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -2496,8 +2496,8 @@ import {HostListener} from '../../src/metadata/directives'; expect(players.length).toEqual(2); const [p1, p2] = players; - expect(p1.element.classList.contains('a')); - expect(p2.element.classList.contains('d')); + expect(p1.element.classList.contains('a')).toBeTrue(); + expect(p2.element.classList.contains('d')).toBeTrue(); cmp.exp = false; fixture.detectChanges(); @@ -2508,8 +2508,8 @@ import {HostListener} from '../../src/metadata/directives'; expect(players.length).toEqual(2); const [p3, p4] = players; - expect(p3.element.classList.contains('a')); - expect(p4.element.classList.contains('d')); + expect(p3.element.classList.contains('a')).toBeTrue(); + expect(p4.element.classList.contains('d')).toBeTrue(); }); it('should collect multiple root levels of :enter and :leave nodes', () => { @@ -3248,9 +3248,9 @@ import {HostListener} from '../../src/metadata/directives'; const [p1, p2] = players; expect(p1.duration).toEqual(750); - expect(p1.element.classList.contains('header')); + expect(p1.element.classList.contains('header')).toBeTrue(); expect(p2.duration).toEqual(250); - expect(p2.element.classList.contains('footer')); + expect(p2.element.classList.contains('footer')).toBeTrue(); }); it('should allow a parent animation to query and animate sub animations that are in a disabled region', @@ -3303,9 +3303,9 @@ import {HostListener} from '../../src/metadata/directives'; const [p1, p2] = players; expect(p1.duration).toEqual(500); - expect(p1.element.classList.contains('child')); + expect(p1.element.classList.contains('child')).toBeTrue(); expect(p2.duration).toEqual(1000); - expect(p2.element.classList.contains('parent')); + expect(p2.element.classList.contains('parent')).toBeTrue(); }); }); }); diff --git a/packages/core/test/linker/change_detection_integration_spec.ts b/packages/core/test/linker/change_detection_integration_spec.ts index 5d365cf9efb78..ed67524610949 100644 --- a/packages/core/test/linker/change_detection_integration_spec.ts +++ b/packages/core/test/linker/change_detection_integration_spec.ts @@ -683,8 +683,10 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ fakeAsync(() => { const ctx = createCompFixture('<div testDirective [a]="42"></div>'); const rf = TestBed.inject(RendererFactory2); - spyOn(rf, 'begin'); - spyOn(rf, 'end'); + // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the + // optional method infer issue. + spyOn(rf as any, 'begin'); + spyOn(rf as any, 'end'); expect(rf.begin).not.toHaveBeenCalled(); expect(rf.end).not.toHaveBeenCalled(); diff --git a/packages/core/test/render3/global_utils_spec.ts b/packages/core/test/render3/global_utils_spec.ts index a0923bb02f82f..c3df0032c0331 100644 --- a/packages/core/test/render3/global_utils_spec.ts +++ b/packages/core/test/render3/global_utils_spec.ts @@ -48,7 +48,7 @@ describe('global utils', () => { }); }); -function assertPublished(name: string, value: {}) { +function assertPublished(name: string, value: Function) { const w = global as any as GlobalDevModeContainer; expect(w[GLOBAL_PUBLISH_EXPANDO_KEY][name]).toBe(value); } diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index 17c8550a62e50..92abc30c09617 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -81,10 +81,12 @@ describe('css selector matching', () => { ])).toBeFalsy(`Selector '[other]' should NOT match <span title="">'`); }); - it('should match namespaced attributes', () => { + // TODO: Not sure how to fix this cases. + xit('should match namespaced attributes', () => { expect(isMatching( - 'span', [AttributeMarker.NamespaceURI, 'http://some/uri', 'title', 'name'], - ['', 'title', ''])); + 'span', [AttributeMarker.NamespaceURI, 'http://some/uri', 'title', 'name'], + ['', 'title', ''])) + .toBeTruthy(); }); it('should match selector with one attribute without value when element has several attributes', @@ -616,4 +618,4 @@ describe('extractAttrsAndClassesFromSelector', () => { expect(extracted.classes).toEqual(classes as string[]); }); }); -}); \ No newline at end of file +}); diff --git a/packages/elements/test/utils_spec.ts b/packages/elements/test/utils_spec.ts index 930fcf086acf8..fb7a0a326e198 100644 --- a/packages/elements/test/utils_spec.ts +++ b/packages/elements/test/utils_spec.ts @@ -15,7 +15,9 @@ describe('utils', () => { let clearTimeoutSpy: jasmine.Spy; beforeEach(() => { - setTimeoutSpy = spyOn(window, 'setTimeout').and.returnValue(42); + // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the wrong return + // type infer issue. + setTimeoutSpy = spyOn(window, 'setTimeout').and.returnValue(42 as any); clearTimeoutSpy = spyOn(window, 'clearTimeout'); }); diff --git a/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts b/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts index 213c972222cbd..b16e869307e7d 100644 --- a/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts +++ b/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts @@ -42,7 +42,7 @@ import {Inject, ReflectiveInjector, forwardRef, resolveForwardRef} from '@angula it('can be unwrapped', () => { // #docregion resolve_forward_ref const ref = forwardRef(() => 'refValue'); - expect(resolveForwardRef(ref)).toEqual('refValue'); + expect(resolveForwardRef(ref as any)).toEqual('refValue'); expect(resolveForwardRef('regularValue')).toEqual('regularValue'); // #enddocregion }); diff --git a/packages/language-service/test/html_info_spec.ts b/packages/language-service/test/html_info_spec.ts index 3781eb3f73670..9007a3f49365a 100644 --- a/packages/language-service/test/html_info_spec.ts +++ b/packages/language-service/test/html_info_spec.ts @@ -28,7 +28,7 @@ describe('html_info', () => { const elements = SchemaInformation.instance.allKnownElements(); for (const element of elements) { for (const prop of SchemaInformation.instance.propertiesOf(element)) { - expect(domRegistry.hasProperty(element, prop, [])); + expect(domRegistry.hasProperty(element, prop, [])).toBeTrue(); } } }); @@ -48,4 +48,4 @@ function uniqueElements<T>(a: T[], b: T[]): T[] { } } return result; -} \ No newline at end of file +} diff --git a/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts b/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts index cf82361a9bc0c..e631a7c7ab344 100644 --- a/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts +++ b/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts @@ -25,7 +25,7 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow }); it('should implement addGlobalEventListener', () => { - spyOn(plugin, 'addEventListener').and.callFake(() => {}); + spyOn(plugin, 'addEventListener').and.callFake(() => () => {}); expect(() => { plugin.addGlobalEventListener('document', 'swipe', () => {}); diff --git a/packages/platform-browser/test/dom/events/key_events_spec.ts b/packages/platform-browser/test/dom/events/key_events_spec.ts index 648852de64e97..0c9b14d19dff7 100644 --- a/packages/platform-browser/test/dom/events/key_events_spec.ts +++ b/packages/platform-browser/test/dom/events/key_events_spec.ts @@ -62,7 +62,7 @@ import {KeyEventsPlugin} from '@angular/platform-browser/src/dom/events/key_even it('should implement addGlobalEventListener', () => { const plugin = new KeyEventsPlugin(document); - spyOn(plugin, 'addEventListener').and.callFake(() => {}); + spyOn(plugin, 'addEventListener').and.callFake(() => () => {}); expect(() => plugin.addGlobalEventListener('window', 'keyup.control.esc', () => {})) .not.toThrowError(); diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 6d03da7b1e461..867f550bb579f 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -3708,7 +3708,8 @@ describe('Integration', () => { router.navigate(['/user/:fedor']); advance(fixture); - expect(navigateSpy.calls.mostRecent().args[1].queryParams); + expect(navigateSpy.calls.mostRecent().args[1] !.queryParams); + }))); }); diff --git a/packages/service-worker/test/comm_spec.ts b/packages/service-worker/test/comm_spec.ts index 5e5678a27017b..839deada200b7 100644 --- a/packages/service-worker/test/comm_spec.ts +++ b/packages/service-worker/test/comm_spec.ts @@ -179,12 +179,12 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS expect(pmSubscribeSpy).toHaveBeenCalledTimes(1); expect(pmSubscribeSpy).toHaveBeenCalledWith({ - applicationServerKey: jasmine.any(Uint8Array), + applicationServerKey: jasmine.any(Uint8Array) as any, userVisibleOnly: true, }); - const actualAppServerKey = pmSubscribeSpy.calls.first().args[0].applicationServerKey; - const actualAppServerKeyStr = decode(actualAppServerKey); + const actualAppServerKey = pmSubscribeSpy.calls.first().args[0] !.applicationServerKey; + const actualAppServerKeyStr = decode(actualAppServerKey as Uint8Array); expect(actualAppServerKeyStr).toBe(appServerKeyStr); }); diff --git a/packages/service-worker/test/module_spec.ts b/packages/service-worker/test/module_spec.ts index 2f6d8a3768225..480fe837f1550 100644 --- a/packages/service-worker/test/module_spec.ts +++ b/packages/service-worker/test/module_spec.ts @@ -30,7 +30,7 @@ describe('ServiceWorkerModule', () => { beforeEach( () => swRegisterSpy = - spyOn(navigator.serviceWorker, 'register').and.returnValue(Promise.resolve())); + spyOn(navigator.serviceWorker, 'register').and.returnValue(Promise.resolve(null as any))); describe('register()', () => { const configTestBed = async(opts: SwRegistrationOptions) => { diff --git a/packages/service-worker/worker/test/happy_spec.ts b/packages/service-worker/worker/test/happy_spec.ts index adc674bda9a2e..ba29e7dfbfd0b 100644 --- a/packages/service-worker/worker/test/happy_spec.ts +++ b/packages/service-worker/worker/test/happy_spec.ts @@ -876,7 +876,7 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope'; async() => { expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); await driver.initialized; - spyOn(server, 'fetch').and.callFake((req: Request) => new MockResponse(null, { + spyOn(server, 'fetch').and.callFake(async(req: Request) => new MockResponse(null, { status: 503, statusText: 'Service Unavailable' })); @@ -1432,7 +1432,8 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope'; it('ignores passive mixed content requests ', async() => { const scopeFetchSpy = spyOn(scope, 'fetch').and.callThrough(); - const getRequestUrls = () => scopeFetchSpy.calls.allArgs().map(args => args[0].url); + const getRequestUrls = () => + (scopeFetchSpy.calls.allArgs() as[Request][]).map(args => args[0].url); const httpScopeUrl = 'http://mock.origin.dev'; const httpsScopeUrl = 'https://mock.origin.dev'; diff --git a/packages/upgrade/src/dynamic/test/upgrade_spec.ts b/packages/upgrade/src/dynamic/test/upgrade_spec.ts index ed7fc7c206fc1..981690fe34c9a 100644 --- a/packages/upgrade/src/dynamic/test/upgrade_spec.ts +++ b/packages/upgrade/src/dynamic/test/upgrade_spec.ts @@ -14,7 +14,6 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import * as angular from '../../common/src/angular1'; import {$EXCEPTION_HANDLER, $ROOT_SCOPE} from '../../common/src/constants'; import {html, multiTrim, withEachNg1Version} from '../../common/test/helpers/common_test_helpers'; - import {UpgradeAdapter, UpgradeAdapterRef} from '../src/upgrade_adapter'; @@ -113,11 +112,12 @@ withEachNg1Version(() => { ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); adapter.bootstrap(element, ['ng1']).ready((ref) => { expect(platformRef.bootstrapModule).toHaveBeenCalledWith(jasmine.any(Function), [ - {providers: []}, jasmine.any(Object) + {providers: []}, jasmine.any(Object) as any ]); expect(platformRef.bootstrapModuleFactory) .toHaveBeenCalledWith( - jasmine.any(NgModuleFactory), {providers: [], ngZone: jasmine.any(NgZone)}); + jasmine.any(NgModuleFactory), + jasmine.objectContaining({ngZone: jasmine.any(NgZone), providers: []})); ref.dispose(); }); })); diff --git a/packages/zone.js/test/extra/bluebird.spec.ts b/packages/zone.js/test/extra/bluebird.spec.ts index a7db2845eece1..f88fcc9eceef4 100644 --- a/packages/zone.js/test/extra/bluebird.spec.ts +++ b/packages/zone.js/test/extra/bluebird.spec.ts @@ -284,7 +284,11 @@ describe('bluebird promise', () => { .each( BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), (r: number, idx: number) => { +<<<<<<< HEAD expect(r).toBe(arr[idx]); +======= + expect(r === arr[idx]).toBeTrue(); +>>>>>>> 253023848d... build: update jasmine to 3.5 expect(Zone.current.name).toEqual('bluebird'); }) .then((r: any) => { @@ -305,7 +309,11 @@ describe('bluebird promise', () => { .mapSeries( BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), (r: number, idx: number) => { +<<<<<<< HEAD expect(r).toBe(arr[idx]); +======= + expect(r === arr[idx]).toBeTrue(); +>>>>>>> 253023848d... build: update jasmine to 3.5 expect(Zone.current.name).toEqual('bluebird'); }) .then((r: any) => { diff --git a/packages/zone.js/test/node/crypto.spec.ts b/packages/zone.js/test/node/crypto.spec.ts index 086e1a4ea5327..3c38d484e73ed 100644 --- a/packages/zone.js/test/node/crypto.spec.ts +++ b/packages/zone.js/test/node/crypto.spec.ts @@ -41,7 +41,7 @@ describe('crypto test', () => { done(); return; } - const zoneASpec: ZoneSpec = { + const zoneASpec = { name: 'A', onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): Task => { return delegate.scheduleTask(targetZone, task); } diff --git a/yarn.lock b/yarn.lock index 959ad17be4342..69ef6520dda2d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1300,17 +1300,12 @@ "@types/rx" "*" "@types/through" "*" -"@types/jasmine@*": +"@types/jasmine@*", "@types/jasmine@3.5.10": version "3.5.10" resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.10.tgz#a1a41012012b5da9d4b205ba9eba58f6cce2ab7b" integrity sha512-3F8qpwBAiVc5+HPJeXJpbrl+XjawGmciN5LgiO7Gv1pl1RHtjoMNqZpqEksaPJW05ViKe8snYInRs6xB25Xdew== -"@types/jasmine@^2.8.8": - version "2.8.16" - resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-2.8.16.tgz#a6cb24b1149d65293bd616923500014838e14e7d" - integrity sha512-056oRlBBp7MDzr+HoU5su099s/s7wjZ3KcHxLfv+Byqb9MwdLUvsfLgw1VS97hsh3ddxSPyQu+olHMnoVTUY6g== - -"@types/jasminewd2@^2.0.6": +"@types/jasminewd2@^2.0.8": version "2.0.8" resolved "https://registry.yarnpkg.com/@types/jasminewd2/-/jasminewd2-2.0.8.tgz#67afe5098d5ef2386073a7b7384b69a840dfe93b" integrity sha512-d9p31r7Nxk0ZH0U39PTH0hiDlJ+qNVGjlt1ucOoTUptxb2v+Y5VMnsxfwN+i3hK4yQnqBi3FMmoMFcd1JHDxdg== @@ -8002,7 +7997,7 @@ istanbul-reports@^1.3.0: dependencies: handlebars "^4.0.3" -jasmine-core@^3.1.0, jasmine-core@^3.3, jasmine-core@~3.5.0: +jasmine-core@^3.3, jasmine-core@^3.5.0, jasmine-core@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.5.0.tgz#132c23e645af96d85c8bca13c8758b18429fc1e4" integrity sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA== @@ -8029,7 +8024,7 @@ jasmine@2.8.0: glob "^7.0.6" jasmine-core "~2.8.0" -jasmine@^3.1.0, jasmine@~3.5.0: +jasmine@^3.5.0, jasmine@~3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.5.0.tgz#7101eabfd043a1fc82ac24e0ab6ec56081357f9e" integrity sha512-DYypSryORqzsGoMazemIHUfMkXM7I7easFaxAvNM3Mr6Xz3Fy36TupTrAOxZWN8MVKEU5xECv22J4tUQf3uBzQ== From 41667de778322ac946ed9e8a1d6647a096f1b371 Mon Sep 17 00:00:00 2001 From: JiaLiPassion <JiaLi.Passion@gmail.com> Date: Tue, 31 Mar 2020 00:22:25 +0900 Subject: [PATCH 151/262] fix(zone.js): add issue numbers of `@types/jasmine` to the test cases (#34625) Some cases will still need to use `spy as any` cast, because `@types/jasmine` have some issues, 1. The issue jasmine doesn't handle optional method properties, https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 2. The issue jasmine doesn't handle overload method correctly, https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42455 PR Close #34625 --- packages/common/http/test/xhr_spec.ts | 12 +- .../ngcc/test/integration/ngcc_spec.ts | 2 +- .../unlocker_spec.ts | 1 + .../test/cached_file_system_spec.ts | 6 +- .../test/node_js_file_system_spec.ts | 37 +- packages/compiler-cli/test/ngc_spec.ts | 32 +- .../compiler/test/output/value_util_spec.ts | 4 +- .../animation_query_integration_spec.ts | 5347 ++++++++--------- .../change_detection_integration_spec.ts | 2818 ++++----- .../core/test/render3/global_utils_spec.ts | 39 +- .../render3/node_selector_matcher_spec.ts | 40 +- packages/elements/test/utils_spec.ts | 15 +- .../di/ts/forward_ref/forward_ref_spec.ts | 6 +- .../test/dom/events/hammer_gestures_spec.ts | 14 +- .../test/dom/events/key_events_spec.ts | 2 - packages/router/test/integration.spec.ts | 3 +- packages/service-worker/test/comm_spec.ts | 73 +- packages/service-worker/test/module_spec.ts | 22 +- .../service-worker/worker/test/happy_spec.ts | 2513 ++++---- .../upgrade/src/dynamic/test/upgrade_spec.ts | 412 +- packages/zone.js/test/extra/bluebird.spec.ts | 8 - packages/zone.js/test/node/crypto.spec.ts | 8 +- 22 files changed, 5831 insertions(+), 5583 deletions(-) diff --git a/packages/common/http/test/xhr_spec.ts b/packages/common/http/test/xhr_spec.ts index 0d08c3a91ea62..d7b4147a2b796 100644 --- a/packages/common/http/test/xhr_spec.ts +++ b/packages/common/http/test/xhr_spec.ts @@ -29,8 +29,8 @@ const XSSI_PREFIX = ')]}\'\n'; { describe('XhrBackend', () => { - let factory: MockXhrFactory = null !; - let backend: HttpXhrBackend = null !; + let factory: MockXhrFactory = null!; + let backend: HttpXhrBackend = null!; beforeEach(() => { factory = new MockXhrFactory(); backend = new HttpXhrBackend(factory); @@ -92,7 +92,7 @@ const XSSI_PREFIX = ')]}\'\n'; factory.mock.mockFlush(200, 'OK', JSON.stringify({data: 'some data'})); expect(events.length).toBe(2); const res = events[1] as HttpResponse<{data: string}>; - expect(res.body !.data).toBe('some data'); + expect(res.body!.data).toBe('some data'); }); it('handles a blank json response', () => { const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); @@ -106,14 +106,14 @@ const XSSI_PREFIX = ')]}\'\n'; factory.mock.mockFlush(500, 'Error', JSON.stringify({data: 'some data'})); expect(events.length).toBe(2); const res = events[1] as any as HttpErrorResponse; - expect(res.error !.data).toBe('some data'); + expect(res.error!.data).toBe('some data'); }); it('handles a json error response with XSSI prefix', () => { const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); factory.mock.mockFlush(500, 'Error', XSSI_PREFIX + JSON.stringify({data: 'some data'})); expect(events.length).toBe(2); const res = events[1] as any as HttpErrorResponse; - expect(res.error !.data).toBe('some data'); + expect(res.error!.data).toBe('some data'); }); it('handles a json string response', () => { const events = trackEvents(backend.handle(TEST_POST.clone({responseType: 'json'}))); @@ -128,7 +128,7 @@ const XSSI_PREFIX = ')]}\'\n'; factory.mock.mockFlush(200, 'OK', XSSI_PREFIX + JSON.stringify({data: 'some data'})); expect(events.length).toBe(2); const res = events[1] as HttpResponse<{data: string}>; - expect(res.body !.data).toBe('some data'); + expect(res.body!.data).toBe('some data'); }); it('emits unsuccessful responses via the error path', done => { backend.handle(TEST_POST).subscribe(undefined, (err: HttpErrorResponse) => { diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index be342392a50d1..cab8b9852d9a1 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -38,7 +38,7 @@ runInEachFileSystem(() => { initMockFileSystem(fs, testFiles); // Force single-process execution in unit tests by mocking available CPUs to 1. - spyOn(os, 'cpus').and.returnValue([{ model: 'Mock CPU' } as any]); + spyOn(os, 'cpus').and.returnValue([{model: 'Mock CPU'} as any]); }); it('should run ngcc without errors for esm2015', () => { diff --git a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts index 0e99ed74172b2..80ad758291e08 100644 --- a/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts +++ b/packages/compiler-cli/ngcc/test/locking/lockfile_with_child_process/unlocker_spec.ts @@ -13,6 +13,7 @@ describe('unlocker', () => { spyOn(process, 'on'); require('../../../src/locking/lock_file_with_child_process/unlocker'); // TODO: @JiaLiPassion, need to wait for @types/jasmine to handle the override case + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42455 expect(process.on).toHaveBeenCalledWith('disconnect' as any, jasmine.any(Function)); }); }); diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts index bcba05ed8f265..d8bc40dfd54f3 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/cached_file_system_spec.ts @@ -47,7 +47,7 @@ describe('CachedFileSystem', () => { let lstatSpy: jasmine.Spy; beforeEach(() => { // For most of the tests the files are not symbolic links. - lstatSpy = spyOn(delegate, 'lstat').and.returnValue({ isSymbolicLink: () => false } as any); + lstatSpy = spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false} as any); }); it('should call delegate if not in cache', () => { @@ -93,7 +93,7 @@ describe('CachedFileSystem', () => { describe('invalidateCaches()', () => { it('should call the delegate `readFile()` if the path for the cached file has been invalidated', () => { - spyOn(delegate, 'lstat').and.returnValue({ isSymbolicLink: () => false } as any); + spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false} as any); const spy = spyOn(delegate, 'readFile').and.returnValue('Some contents'); fs.readFile(abcPath); // Call once to fill the cache spy.calls.reset(); @@ -230,7 +230,7 @@ describe('CachedFileSystem', () => { describe('moveFile()', () => { beforeEach(() => { // `moveFile()` relies upon `readFile` which calls through to `lstat()`, so stub it out. - spyOn(delegate, 'lstat').and.returnValue({ isSymbolicLink: () => false } as any); + spyOn(delegate, 'lstat').and.returnValue({isSymbolicLink: () => false} as any); }); it('should call delegate', () => { diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts index 71babf1878459..eca3261239d1c 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/node_js_file_system_spec.ts @@ -69,6 +69,7 @@ describe('NodeJSFileSystem', () => { const result = fs.readdir(abcPath); expect(result).toEqual([relativeFrom('x'), relativeFrom('y/z')]); // TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters. + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 expect(spy as any).toHaveBeenCalledWith(abcPath); }); }); @@ -90,6 +91,7 @@ describe('NodeJSFileSystem', () => { const result = fs.stat(abcPath); expect(result).toBe(stats); // TODO: @JiaLiPassion need to wait for @types/jasmine update to handle optional parameters. + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 expect(spy as any).toHaveBeenCalledWith(abcPath); }); }); @@ -173,12 +175,14 @@ describe('NodeJSFileSystem', () => { } return false; }); - spyOn(fs, 'stat').and.returnValue({ isDirectory: () => true } as any); - const mkdirSyncSpy = spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { - if (path === abcPath) { - throw new Error('It exists already. Supposedly.'); - } - }) as any); + spyOn(fs, 'stat').and.returnValue({isDirectory: () => true} as any); + const mkdirSyncSpy = + spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { + if (path === abcPath) { + throw new Error( + 'It exists already. Supposedly.'); + } + }) as any); fs.ensureDir(abcPath); expect(mkdirSyncSpy).toHaveBeenCalledTimes(3); @@ -188,11 +192,12 @@ describe('NodeJSFileSystem', () => { it('should fail if creating the directory throws and the directory does not exist', () => { spyOn(fs, 'exists').and.returnValue(false); - spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { - if (path === abcPath) { - throw new Error('Unable to create directory (for whatever reason).'); - } - }) as any); + spyOn(realFs, 'mkdirSync') + .and.callFake(((path: string) => { + if (path === abcPath) { + throw new Error('Unable to create directory (for whatever reason).'); + } + }) as any); expect(() => fs.ensureDir(abcPath)) .toThrowError('Unable to create directory (for whatever reason).'); @@ -212,12 +217,12 @@ describe('NodeJSFileSystem', () => { } return false; }); - spyOn(fs, 'stat').and.returnValue({ isDirectory: isDirectorySpy } as any); + spyOn(fs, 'stat').and.returnValue({isDirectory: isDirectorySpy} as any); spyOn(realFs, 'mkdirSync').and.callFake(((path: string) => { - if (path === abcPath) { - throw new Error('It exists already. Supposedly.'); - } - }) as any); + if (path === abcPath) { + throw new Error('It exists already. Supposedly.'); + } + }) as any); expect(() => fs.ensureDir(abcPath)).toThrowError('It exists already. Supposedly.'); expect(isDirectorySpy).toHaveBeenCalledTimes(1); diff --git a/packages/compiler-cli/test/ngc_spec.ts b/packages/compiler-cli/test/ngc_spec.ts index 93ccda8f6ccdc..d2c783ad6c152 100644 --- a/packages/compiler-cli/test/ngc_spec.ts +++ b/packages/compiler-cli/test/ngc_spec.ts @@ -41,7 +41,9 @@ describe('ngc transformer command-line', () => { basePath = support.basePath; outDir = path.join(basePath, 'built'); process.chdir(basePath); - write = (fileName: string, content: string) => { support.write(fileName, content); }; + write = (fileName: string, content: string) => { + support.write(fileName, content); + }; write('tsconfig-base.json', `{ "compilerOptions": { @@ -96,8 +98,9 @@ describe('ngc transformer command-line', () => { }); describe('errors', () => { - - beforeEach(() => { errorSpy.and.stub(); }); + beforeEach(() => { + errorSpy.and.stub(); + }); it('should not print the stack trace if user input file does not exist', () => { writeConfig(`{ @@ -231,7 +234,6 @@ describe('ngc transformer command-line', () => { }); describe('compile ngfactory files', () => { - it('should compile ngfactory files that are not referenced by root files', () => { writeConfig(`{ "extends": "./tsconfig-base.json", @@ -1122,7 +1124,6 @@ describe('ngc transformer command-line', () => { }); describe('with external symbol re-exports enabled', () => { - it('should be able to compile multiple libraries with summaries', () => { // Note: we need to emit the generated code for the libraries // into the node_modules, as that is the only way that we @@ -1560,11 +1561,13 @@ describe('ngc transformer command-line', () => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000; const timerToken = 100; // TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 spyOn(ts.sys as any, 'setTimeout').and.callFake((callback: () => void) => { timer = callback; return timerToken; }); // TODO: @JiaLiPassion, need to wait @types/jasmine to handle optional method case + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 spyOn(ts.sys as any, 'clearTimeout').and.callFake((token: number) => { if (token == timerToken) { timer = undefined; @@ -1617,7 +1620,9 @@ describe('ngc transformer command-line', () => { `); }); - afterEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; }); + afterEach(() => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + }); function writeAppConfig(location: string) { writeConfig(`{ @@ -1672,11 +1677,13 @@ describe('ngc transformer command-line', () => { `); })); - it('should recompile when the html file changes', - expectRecompile(() => { write('greet.html', '<p> Hello {{name}} again!</p>'); })); + it('should recompile when the html file changes', expectRecompile(() => { + write('greet.html', '<p> Hello {{name}} again!</p>'); + })); - it('should recompile when the css file changes', - expectRecompile(() => { write('greet.css', `p.greeting { color: blue }`); })); + it('should recompile when the css file changes', expectRecompile(() => { + write('greet.css', `p.greeting { color: blue }`); + })); }); describe('regressions', () => { @@ -2041,8 +2048,8 @@ describe('ngc transformer command-line', () => { expect(exitCode).toBe(1, 'Compile was expected to fail'); const srcPathWithSep = `lib/`; expect(messages[0]) - .toEqual( - `${srcPathWithSep}test.component.ts(6,21): Error during template compile of 'TestComponent' + .toEqual(`${ + srcPathWithSep}test.component.ts(6,21): Error during template compile of 'TestComponent' Tagged template expressions are not supported in metadata in 't1' 't1' references 't2' at ${srcPathWithSep}indirect1.ts(3,27) 't2' contains the error at ${srcPathWithSep}indirect2.ts(4,27). @@ -2051,7 +2058,6 @@ describe('ngc transformer command-line', () => { }); describe('tree shakeable services', () => { - function compileService(source: string): string { write('service.ts', source); diff --git a/packages/compiler/test/output/value_util_spec.ts b/packages/compiler/test/output/value_util_spec.ts index 536cf81527e7c..0098608151542 100644 --- a/packages/compiler/test/output/value_util_spec.ts +++ b/packages/compiler/test/output/value_util_spec.ts @@ -13,8 +13,8 @@ describe('convertValueToOutputAst', () => { it('should convert all array elements, including undefined', () => { const ctx = null; const value = new Array(3).concat('foo'); - const expr = convertValueToOutputAst(ctx !, value) as o.LiteralArrayExpr; - expect(expr instanceof o.LiteralArrayExpr); + const expr = convertValueToOutputAst(ctx!, value) as o.LiteralArrayExpr; + expect(expr instanceof o.LiteralArrayExpr).toBe(true); expect(expr.entries.length).toBe(4); for (let i = 0; i < 4; ++i) { expect(expr.entries[i] instanceof o.Expression).toBe(true); diff --git a/packages/core/test/animation/animation_query_integration_spec.ts b/packages/core/test/animation/animation_query_integration_spec.ts index 4917316870bd5..ff17a0f9aa422 100644 --- a/packages/core/test/animation/animation_query_integration_spec.ts +++ b/packages/core/test/animation/animation_query_integration_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationPlayer, animate, animateChild, group, query, sequence, stagger, state, style, transition, trigger, ɵAnimationGroupPlayer as AnimationGroupPlayer} from '@angular/animations'; +import {animate, animateChild, AnimationPlayer, AUTO_STYLE, group, query, sequence, stagger, state, style, transition, trigger, ɵAnimationGroupPlayer as AnimationGroupPlayer} from '@angular/animations'; import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser'; import {matchesElement} from '@angular/animations/browser/src/render/shared'; import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine'; @@ -13,35 +13,37 @@ import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '@angular/animations/browser/src/ import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing'; import {CommonModule} from '@angular/common'; import {Component, HostBinding, ViewChild} from '@angular/core'; -import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {HostListener} from '../../src/metadata/directives'; (function() { - // these tests are only mean't to be run within the DOM (for now) - if (isNode) return; - - describe('animation query tests', function() { - function getLog(): MockAnimationPlayer[] { - return MockAnimationDriver.log as MockAnimationPlayer[]; - } - - function resetLog() { MockAnimationDriver.log = []; } - - beforeEach(() => { - resetLog(); - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}], - imports: [BrowserAnimationsModule, CommonModule] - }); +// these tests are only mean't to be run within the DOM (for now) +if (isNode) return; + +describe('animation query tests', function() { + function getLog(): MockAnimationPlayer[] { + return MockAnimationDriver.log as MockAnimationPlayer[]; + } + + function resetLog() { + MockAnimationDriver.log = []; + } + + beforeEach(() => { + resetLog(); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}], + imports: [BrowserAnimationsModule, CommonModule] }); + }); - describe('query()', () => { - it('should be able to query all elements that contain animation triggers via @*', () => { - @Component({ - selector: 'ani-cmp', - template: ` + describe('query()', () => { + it('should be able to query all elements that contain animation triggers via @*', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@parent]="exp0"> <div class="a" [@a]="exp1"></div> <div class="b" [@b]="exp2"></div> @@ -50,75 +52,71 @@ import {HostListener} from '../../src/metadata/directives'; </section> </div> `, - animations: [ - trigger( - 'parent', - [ - transition( - '* => go', - [ - query( - '@*', - [ - style({ backgroundColor: 'blue' }), - animate(1000, style({backgroundColor: 'red'})), - ]), - ]), - ]), - trigger( - 'a', - [ - transition('* => 1', [ - animate(1000, style({ opacity: 0 })) - ]), - ]), - trigger( - 'b', - [ - transition('* => 1', [ - animate(1000, style({ opacity: 0 })), - query('.b-inner', [ - animate(1000, style({ opacity: 0 })) + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + query( + '@*', + [ + style({backgroundColor: 'blue'}), + animate(1000, style({backgroundColor: 'red'})), + ]), ]), - ]), - ]), - trigger( - 'c', - [ - transition('* => 1', [ - animate(1000, style({ opacity: 0 })) - ]), - ]), - ] - }) - class Cmp { - public exp0: any; - public exp1: any; - public exp2: any; - } + ]), + trigger( + 'a', + [ + transition('* => 1', [animate(1000, style({opacity: 0}))]), + ]), + trigger( + 'b', + [ + transition( + '* => 1', + [ + animate(1000, style({opacity: 0})), + query('.b-inner', [animate(1000, style({opacity: 0}))]), + ]), + ]), + trigger( + 'c', + [ + transition('* => 1', [animate(1000, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + public exp0: any; + public exp1: any; + public exp2: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp0 = 'go'; - fixture.detectChanges(); + cmp.exp0 = 'go'; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(3); // a,b,c - resetLog(); + let players = getLog(); + expect(players.length).toEqual(3); // a,b,c + resetLog(); - const [p1, p2, p3] = players; - expect(p1.element.classList.contains('a')).toBeTruthy(); - expect(p2.element.classList.contains('b')).toBeTruthy(); - expect(p3.element.classList.contains('c')).toBeTruthy(); - }); + const [p1, p2, p3] = players; + expect(p1.element.classList.contains('a')).toBeTruthy(); + expect(p2.element.classList.contains('b')).toBeTruthy(); + expect(p3.element.classList.contains('c')).toBeTruthy(); + }); - it('should be able to query currently animating elements via :animating', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should be able to query currently animating elements via :animating', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@parent]="exp0"> <div class="a" [@a]="exp1"></div> <div class="b" [@b]="exp2"> @@ -127,95 +125,91 @@ import {HostListener} from '../../src/metadata/directives'; <div class="c" [@c]="exp3"></div> </div> `, - animations: [ - trigger( - 'parent', - [ - transition( - '* => go', - [ - query( - ':animating', - [ - style({ backgroundColor: 'blue' }), - animate(1000, style({backgroundColor: 'red'})), - ]), - ]), - ]), - trigger( - 'a', - [ - transition('* => 1', [ - animate(1000, style({ opacity: 0 })) - ]), - ]), - trigger( - 'b', - [ - transition('* => 1', [ - animate(1000, style({ opacity: 0 })), - query('.b-inner', [ - animate(1000, style({ opacity: 0 })) + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + query( + ':animating', + [ + style({backgroundColor: 'blue'}), + animate(1000, style({backgroundColor: 'red'})), + ]), ]), - ]), - ]), - trigger( - 'c', - [ - transition('* => 1', [ - animate(1000, style({ opacity: 0 })) - ]), - ]), - ] - }) - class Cmp { - public exp0: any; - public exp1: any; - public exp2: any; - public exp3: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp0 = ''; - cmp.exp1 = 1; - cmp.exp2 = 1; - // note that exp3 is skipped here - fixture.detectChanges(); - - let players = getLog(); - expect(players.length).toEqual(3); // a,b,b-inner and not c - resetLog(); + ]), + trigger( + 'a', + [ + transition('* => 1', [animate(1000, style({opacity: 0}))]), + ]), + trigger( + 'b', + [ + transition( + '* => 1', + [ + animate(1000, style({opacity: 0})), + query('.b-inner', [animate(1000, style({opacity: 0}))]), + ]), + ]), + trigger( + 'c', + [ + transition('* => 1', [animate(1000, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + public exp0: any; + public exp1: any; + public exp2: any; + public exp3: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp0 = ''; + cmp.exp1 = 1; + cmp.exp2 = 1; + // note that exp3 is skipped here + fixture.detectChanges(); + + let players = getLog(); + expect(players.length).toEqual(3); // a,b,b-inner and not c + resetLog(); - cmp.exp0 = 'go'; - fixture.detectChanges(); + cmp.exp0 = 'go'; + fixture.detectChanges(); - const expectedKeyframes = [ - {backgroundColor: 'blue', offset: 0}, - {backgroundColor: 'red', offset: 1}, - ]; + const expectedKeyframes = [ + {backgroundColor: 'blue', offset: 0}, + {backgroundColor: 'red', offset: 1}, + ]; - players = getLog(); - expect(players.length).toEqual(3); - const [p1, p2, p3] = players; + players = getLog(); + expect(players.length).toEqual(3); + const [p1, p2, p3] = players; - expect(p1.element.classList.contains('a')).toBeTruthy(); - expect(p1.keyframes).toEqual(expectedKeyframes); + expect(p1.element.classList.contains('a')).toBeTruthy(); + expect(p1.keyframes).toEqual(expectedKeyframes); - expect(p2.element.classList.contains('b')).toBeTruthy(); - expect(p2.keyframes).toEqual(expectedKeyframes); + expect(p2.element.classList.contains('b')).toBeTruthy(); + expect(p2.keyframes).toEqual(expectedKeyframes); - expect(p3.element.classList.contains('b-inner')).toBeTruthy(); - expect(p3.keyframes).toEqual(expectedKeyframes); - }); + expect(p3.element.classList.contains('b-inner')).toBeTruthy(); + expect(p3.keyframes).toEqual(expectedKeyframes); + }); - it('should be able to query triggers directly by name', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should be able to query triggers directly by name', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp0"> <div class="f1" @foo></div> <div class="f2" [@foo]></div> @@ -225,147 +219,146 @@ import {HostListener} from '../../src/metadata/directives'; <div class="b3" [@bar]="exp2"></div> </div> `, - animations: [ - trigger('foo', []), - trigger('bar', []), - trigger( - 'myAnimation', - [ - transition( - '* => foo', - [ - query( - '@foo', - [ - animate(1000, style({color: 'red'})), - ]), - ]), - transition( - '* => bar', - [ - query( - '@bar', - [ - animate(1000, style({color: 'blue'})), - ]), - ]) - ]), - ] - }) - class Cmp { - public exp0: any; - public exp1: any; - public exp2: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - fixture.detectChanges(); - engine.flush(); - resetLog(); + animations: [ + trigger('foo', []), + trigger('bar', []), + trigger( + 'myAnimation', + [ + transition( + '* => foo', + [ + query( + '@foo', + [ + animate(1000, style({color: 'red'})), + ]), + ]), + transition( + '* => bar', + [ + query( + '@bar', + [ + animate(1000, style({color: 'blue'})), + ]), + ]) + ]), + ] + }) + class Cmp { + public exp0: any; + public exp1: any; + public exp2: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp0 = 'foo'; - fixture.detectChanges(); - engine.flush(); + cmp.exp0 = 'foo'; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - expect(players.length).toEqual(3); - const [p1, p2, p3] = players; - resetLog(); + let players = getLog(); + expect(players.length).toEqual(3); + const [p1, p2, p3] = players; + resetLog(); - expect(p1.element.classList.contains('f1')).toBeTruthy(); - expect(p2.element.classList.contains('f2')).toBeTruthy(); - expect(p3.element.classList.contains('f3')).toBeTruthy(); + expect(p1.element.classList.contains('f1')).toBeTruthy(); + expect(p2.element.classList.contains('f2')).toBeTruthy(); + expect(p3.element.classList.contains('f3')).toBeTruthy(); - cmp.exp0 = 'bar'; - fixture.detectChanges(); - engine.flush(); + cmp.exp0 = 'bar'; + fixture.detectChanges(); + engine.flush(); - players = getLog(); - expect(players.length).toEqual(3); - const [p4, p5, p6] = players; - resetLog(); + players = getLog(); + expect(players.length).toEqual(3); + const [p4, p5, p6] = players; + resetLog(); - expect(p4.element.classList.contains('b1')).toBeTruthy(); - expect(p5.element.classList.contains('b2')).toBeTruthy(); - expect(p6.element.classList.contains('b3')).toBeTruthy(); - }); + expect(p4.element.classList.contains('b1')).toBeTruthy(); + expect(p5.element.classList.contains('b2')).toBeTruthy(); + expect(p6.element.classList.contains('b3')).toBeTruthy(); + }); - it('should be able to query all active animations using :animating in a query', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should be able to query all active animations using :animating in a query', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" #parent> <div *ngFor="let item of items" class="item e-{{ item }}"> </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => a', - [ - query( - '.item:nth-child(odd)', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - transition( - '* => b', - [ - query( - '.item:animating', - [ - style({opacity: 1}), - animate(1000, style({opacity: 0})), - ]), - ]), - ]), - ] - }) - class Cmp { - public exp: any; - public items: number[] = [0, 1, 2, 3, 4]; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => a', + [ + query( + '.item:nth-child(odd)', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + transition( + '* => b', + [ + query( + '.item:animating', + [ + style({opacity: 1}), + animate(1000, style({opacity: 0})), + ]), + ]), + ]), + ] + }) + class Cmp { + public exp: any; + public items: number[] = [0, 1, 2, 3, 4]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'a'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'a'; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - expect(players.length).toEqual(3); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(3); + resetLog(); - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - players = getLog(); - expect(players.length).toEqual(3); - expect(players[0].element.classList.contains('e-0')).toBeTruthy(); - expect(players[1].element.classList.contains('e-2')).toBeTruthy(); - expect(players[2].element.classList.contains('e-4')).toBeTruthy(); - }); + players = getLog(); + expect(players.length).toEqual(3); + expect(players[0].element.classList.contains('e-0')).toBeTruthy(); + expect(players[1].element.classList.contains('e-2')).toBeTruthy(); + expect(players[2].element.classList.contains('e-4')).toBeTruthy(); + }); - it('should be able to query all actively queued animation triggers via `@*:animating`', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should be able to query all actively queued animation triggers via `@*:animating`', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@parent]="exp0"> <div class="c1" [@child]="exp1"></div> <div class="c2" [@child]="exp2"></div> @@ -374,88 +367,89 @@ import {HostListener} from '../../src/metadata/directives'; <div class="c5" [@child]="exp5"></div> </div> `, - animations: [ - trigger( - 'parent', - [ - transition( - '* => *', - [ - query( - '@*:animating', [animate(1000, style({background: 'red'}))], - {optional: true}), - ]), - ]), - trigger( - 'child', - [ - transition('* => *', []), - ]) - ] - }) - class Cmp { - public exp0: any; - public exp1: any; - public exp2: any; - public exp3: any; - public exp4: any; - public exp5: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp1 = 0; - cmp.exp2 = 0; - cmp.exp3 = 0; - cmp.exp4 = 0; - cmp.exp5 = 0; - fixture.detectChanges(); - - cmp.exp0 = 0; - fixture.detectChanges(); - - let players = engine.players; - cancelAllPlayers(players); - - cmp.exp2 = 1; - cmp.exp4 = 1; - fixture.detectChanges(); - - cmp.exp0 = 1; - fixture.detectChanges(); + animations: [ + trigger( + 'parent', + [ + transition( + '* => *', + [ + query( + '@*:animating', [animate(1000, style({background: 'red'}))], + {optional: true}), + ]), + ]), + trigger( + 'child', + [ + transition('* => *', []), + ]) + ] + }) + class Cmp { + public exp0: any; + public exp1: any; + public exp2: any; + public exp3: any; + public exp4: any; + public exp5: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp1 = 0; + cmp.exp2 = 0; + cmp.exp3 = 0; + cmp.exp4 = 0; + cmp.exp5 = 0; + fixture.detectChanges(); + + cmp.exp0 = 0; + fixture.detectChanges(); + + let players = engine.players; + cancelAllPlayers(players); + + cmp.exp2 = 1; + cmp.exp4 = 1; + fixture.detectChanges(); + + cmp.exp0 = 1; + fixture.detectChanges(); + + players = engine.players; + cancelAllPlayers(players); + expect(players.length).toEqual(3); + + cmp.exp1 = 2; + cmp.exp2 = 2; + cmp.exp3 = 2; + cmp.exp4 = 2; + cmp.exp5 = 2; + fixture.detectChanges(); + + cmp.exp0 = 2; + fixture.detectChanges(); + + players = engine.players; + cancelAllPlayers(players); + expect(players.length).toEqual(6); + + cmp.exp0 = 3; + fixture.detectChanges(); + + players = engine.players; + cancelAllPlayers(players); + expect(players.length).toEqual(1); + }); - players = engine.players; - cancelAllPlayers(players); - expect(players.length).toEqual(3); - - cmp.exp1 = 2; - cmp.exp2 = 2; - cmp.exp3 = 2; - cmp.exp4 = 2; - cmp.exp5 = 2; - fixture.detectChanges(); - - cmp.exp0 = 2; - fixture.detectChanges(); - - players = engine.players; - cancelAllPlayers(players); - expect(players.length).toEqual(6); - - cmp.exp0 = 3; - fixture.detectChanges(); - - players = engine.players; - cancelAllPlayers(players); - expect(players.length).toEqual(1); - }); - - it('should collect styles for the same elements between queries', () => { - @Component({ + it( + 'should collect styles for the same elements between queries', () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="exp"> @@ -478,110 +472,109 @@ import {HostListener} from '../../src/metadata/directives'; ] }) class Cmp { - public exp: any; - public items: any[] = [0, 1, 2]; - } + public exp: any; + public items: any[] = [0, 1, 2]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(6); + const players = getLog(); + expect(players.length).toEqual(6); - const [p1, p2, p3, p4, p5, p6] = players; + const [p1, p2, p3, p4, p5, p6] = players; - expect(p1.delay).toEqual(0); - expect(p1.duration).toEqual(0); - expect(p1.keyframes).toEqual([ - {opacity: '0.01', offset: 0}, - {opacity: '0.01', offset: 1}, - ]); + expect(p1.delay).toEqual(0); + expect(p1.duration).toEqual(0); + expect(p1.keyframes).toEqual([ + {opacity: '0.01', offset: 0}, + {opacity: '0.01', offset: 1}, + ]); - expect(p2.delay).toEqual(0); - expect(p2.duration).toEqual(0); - expect(p2.keyframes).toEqual([ - {opacity: '0.01', offset: 0}, - {opacity: '0.01', offset: 1}, - ]); + expect(p2.delay).toEqual(0); + expect(p2.duration).toEqual(0); + expect(p2.keyframes).toEqual([ + {opacity: '0.01', offset: 0}, + {opacity: '0.01', offset: 1}, + ]); - expect(p3.delay).toEqual(0); - expect(p3.duration).toEqual(0); - expect(p3.keyframes).toEqual([ - {opacity: '0.01', offset: 0}, - {opacity: '0.01', offset: 1}, - ]); + expect(p3.delay).toEqual(0); + expect(p3.duration).toEqual(0); + expect(p3.keyframes).toEqual([ + {opacity: '0.01', offset: 0}, + {opacity: '0.01', offset: 1}, + ]); - expect(p4.delay).toEqual(0); - expect(p4.duration).toEqual(1000); - expect(p4.keyframes).toEqual([ - {opacity: '0.01', offset: 0}, - {opacity: '1', offset: 1}, - ]); + expect(p4.delay).toEqual(0); + expect(p4.duration).toEqual(1000); + expect(p4.keyframes).toEqual([ + {opacity: '0.01', offset: 0}, + {opacity: '1', offset: 1}, + ]); - expect(p5.delay).toEqual(1000); - expect(p5.duration).toEqual(1000); - expect(p5.keyframes).toEqual([ - {opacity: '0.01', offset: 0}, - {opacity: '1', offset: 1}, - ]); + expect(p5.delay).toEqual(1000); + expect(p5.duration).toEqual(1000); + expect(p5.keyframes).toEqual([ + {opacity: '0.01', offset: 0}, + {opacity: '1', offset: 1}, + ]); - expect(p6.delay).toEqual(1500); - expect(p6.duration).toEqual(1000); - expect(p6.keyframes).toEqual([ - {opacity: '0.01', offset: 0}, - {opacity: '1', offset: 1}, - ]); - }); + expect(p6.delay).toEqual(1500); + expect(p6.duration).toEqual(1000); + expect(p6.keyframes).toEqual([ + {opacity: '0.01', offset: 0}, + {opacity: '1', offset: 1}, + ]); + }); - it('should retain style values when :self is used inside of a query', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should retain style values when :self is used inside of a query', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [trigger('myAnimation', [transition( - '* => go', - [ - query(':self', style({opacity: '0.5'})), - animate(1000, style({opacity: '1'})) - ])])] - }) - class Cmp { - public exp: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(2); - - const [p1, p2] = players; - expect(p1.delay).toEqual(0); - expect(p1.duration).toEqual(0); - expect(p1.keyframes).toEqual([{opacity: '0.5', offset: 0}, {opacity: '0.5', offset: 1}]); - - expect(p2.delay).toEqual(0); - expect(p2.duration).toEqual(1000); - expect(p2.keyframes).toEqual([{opacity: '0.5', offset: 0}, {opacity: '1', offset: 1}]); - }); + animations: [trigger( + 'myAnimation', + [transition( + '* => go', + [query(':self', style({opacity: '0.5'})), animate(1000, style({opacity: '1'}))])])] + }) + class Cmp { + public exp: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(2); + + const [p1, p2] = players; + expect(p1.delay).toEqual(0); + expect(p1.duration).toEqual(0); + expect(p1.keyframes).toEqual([{opacity: '0.5', offset: 0}, {opacity: '0.5', offset: 1}]); + + expect(p2.delay).toEqual(0); + expect(p2.duration).toEqual(1000); + expect(p2.keyframes).toEqual([{opacity: '0.5', offset: 0}, {opacity: '1', offset: 1}]); + }); - it('should properly apply stagger after various other steps within a query', () => { - @Component({ + it('should properly apply stagger after various other steps within a query', () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="exp"> @@ -605,101 +598,101 @@ import {HostListener} from '../../src/metadata/directives'; ] }) class Cmp { - public exp: any; - public items: any[] = [0, 1, 2]; - } + public exp: any; + public items: any[] = [0, 1, 2]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(3); + const players = getLog(); + expect(players.length).toEqual(3); - const [p1, p2, p3] = players; + const [p1, p2, p3] = players; - expect(p1.delay).toEqual(0); - expect(p1.duration).toEqual(3000); - expect(p2.delay).toEqual(0); - expect(p2.duration).toEqual(3500); - expect(p3.delay).toEqual(0); - expect(p3.duration).toEqual(4000); - }); + expect(p1.delay).toEqual(0); + expect(p1.duration).toEqual(3000); + expect(p2.delay).toEqual(0); + expect(p2.duration).toEqual(3500); + expect(p3.delay).toEqual(0); + expect(p3.duration).toEqual(4000); + }); - it('should properly apply pre styling before a stagger is issued', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should properly apply pre styling before a stagger is issued', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp"> <div *ngFor="let item of items" class="item"> {{ item }} </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - query( - ':enter', - [ - style({opacity: 0}), - stagger( - 100, - [ - animate(1000, style({opacity: 1})), - ]), - ]), - ]), - ]), - ] - }) - class Cmp { - public exp: any; - public items: any[] = [0, 1, 2, 3, 4]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(5); - - for (let i = 0; i < players.length; i++) { - const player = players[i]; - const kf = player.keyframes; - const limit = kf.length - 1; - const staggerDelay = 100 * i; - const duration = 1000 + staggerDelay; - - expect(kf[0]).toEqual({opacity: '0', offset: 0}); - if (limit > 1) { - const offsetAtStaggerDelay = staggerDelay / duration; - expect(kf[1]).toEqual({opacity: '0', offset: offsetAtStaggerDelay}); - } - expect(kf[limit]).toEqual({opacity: '1', offset: 1}); - expect(player.duration).toEqual(duration); + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + query( + ':enter', + [ + style({opacity: 0}), + stagger( + 100, + [ + animate(1000, style({opacity: 1})), + ]), + ]), + ]), + ]), + ] + }) + class Cmp { + public exp: any; + public items: any[] = [0, 1, 2, 3, 4]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(5); + + for (let i = 0; i < players.length; i++) { + const player = players[i]; + const kf = player.keyframes; + const limit = kf.length - 1; + const staggerDelay = 100 * i; + const duration = 1000 + staggerDelay; + + expect(kf[0]).toEqual({opacity: '0', offset: 0}); + if (limit > 1) { + const offsetAtStaggerDelay = staggerDelay / duration; + expect(kf[1]).toEqual({opacity: '0', offset: offsetAtStaggerDelay}); } - }); + expect(kf[limit]).toEqual({opacity: '1', offset: 1}); + expect(player.duration).toEqual(duration); + } + }); - it('should apply a full stagger step delay if the timing data is left undefined', () => { - @Component({ + it('should apply a full stagger step delay if the timing data is left undefined', () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="exp"> @@ -717,146 +710,144 @@ import {HostListener} from '../../src/metadata/directives'; ])])])])] }) class Cmp { - public exp: any; - public items: any[] = [0, 1, 2, 3, 4]; - } + public exp: any; + public items: any[] = [0, 1, 2, 3, 4]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(5); + const players = getLog(); + expect(players.length).toEqual(5); - const [p1, p2, p3, p4, p5] = players; - expect(p1.delay).toEqual(0); - expect(p2.delay).toEqual(1500); - expect(p3.delay).toEqual(3000); - expect(p4.delay).toEqual(4500); - expect(p5.delay).toEqual(6000); - }); + const [p1, p2, p3, p4, p5] = players; + expect(p1.delay).toEqual(0); + expect(p2.delay).toEqual(1500); + expect(p3.delay).toEqual(3000); + expect(p4.delay).toEqual(4500); + expect(p5.delay).toEqual(6000); + }); - it('should persist inner sub trigger styles once their animation is complete', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should persist inner sub trigger styles once their animation is complete', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @parent *ngIf="exp1"> <div class="child" [@child]="exp2"></div> </div> `, - animations: [ - trigger( - 'parent', - [ - transition( - ':enter', - [ - query( - '.child', - [ - animateChild(), - ]), - ]), - ]), - trigger( - 'child', - [ - state('*, void', style({height: '0px'})), - state('b', style({height: '444px'})), - transition('* => *', animate(500)), - ]), - ] - }) - class Cmp { - public exp1: any; - public exp2: any; - } + animations: [ + trigger( + 'parent', + [ + transition( + ':enter', + [ + query( + '.child', + [ + animateChild(), + ]), + ]), + ]), + trigger( + 'child', + [ + state('*, void', style({height: '0px'})), + state('b', style({height: '444px'})), + transition('* => *', animate(500)), + ]), + ] + }) + class Cmp { + public exp1: any; + public exp2: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = true; - cmp.exp2 = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = true; + cmp.exp2 = 'b'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(1); - const player = players[0]; + const players = getLog(); + expect(players.length).toEqual(1); + const player = players[0]; - expect(player.keyframes).toEqual([ - {height: '0px', offset: 0}, {height: '444px', offset: 1} - ]); - player.finish(); + expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '444px', offset: 1}]); + player.finish(); - expect(player.element.style.height).toEqual('444px'); - }); + expect(player.element.style.height).toEqual('444px'); + }); - it('should find newly inserted items in the component via :enter', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should find newly inserted items in the component via :enter', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @myAnimation> <div *ngFor="let item of items" class="child"> {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - ':enter', - [ - query( - ':enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: .5})), - ]), - ]), - ])] - }) - class Cmp { - public items: any[] = [0, 1, 2]; - } + animations: [trigger( + 'myAnimation', + [ + transition( + ':enter', + [ + query( + ':enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: .5})), + ]), + ]), + ])] + }) + class Cmp { + public items: any[] = [0, 1, 2]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(3); + const players = getLog(); + expect(players.length).toEqual(3); - const [p1, p2, p3] = players; - expect(p1.element.innerText.trim()).toEqual('0'); - expect(p2.element.innerText.trim()).toEqual('1'); - expect(p3.element.innerText.trim()).toEqual('2'); + const [p1, p2, p3] = players; + expect(p1.element.innerText.trim()).toEqual('0'); + expect(p2.element.innerText.trim()).toEqual('1'); + expect(p3.element.innerText.trim()).toEqual('2'); - players.forEach(p => { - expect(p.keyframes).toEqual([{opacity: '0', offset: 0}, {opacity: '0.5', offset: 1}]); - }); + players.forEach(p => { + expect(p.keyframes).toEqual([{opacity: '0', offset: 0}, {opacity: '0.5', offset: 1}]); }); + }); - it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="items.length" class="parent" #container> <div *ngFor="let item of items" class="child"> {{ item }} @@ -864,161 +855,163 @@ import {HostListener} from '../../src/metadata/directives'; <div *ngIf="items.length == 0" class="child">Leave!</div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => 0', []), - transition( - '* => *', - [ - query( - '.child:enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - query( - '.incorrect-child:leave', - [ - animate(1000, style({opacity: 0})), - ]), - ]), - ]), - ] - }) - class Cmp { - @ViewChild('container') public container: any; - public items: any[] = []; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.items = []; + animations: [ + trigger( + 'myAnimation', + [ + transition('* => 0', []), + transition( + '* => *', + [ + query( + '.child:enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + query( + '.incorrect-child:leave', + [ + animate(1000, style({opacity: 0})), + ]), + ]), + ]), + ] + }) + class Cmp { + @ViewChild('container') public container: any; + public items: any[] = []; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.items = []; + fixture.detectChanges(); + + cmp.items = [0, 1, 2, 3, 4]; + + expect(() => { fixture.detectChanges(); - - cmp.items = [0, 1, 2, 3, 4]; - - expect(() => { fixture.detectChanges(); }).toThrow(); - - const children = cmp.container.nativeElement.querySelectorAll('.child'); - expect(children.length).toEqual(5); - - for (let i = 0; i < children.length; i++) { - let child = children[i]; - expect(child.classList.contains(ENTER_CLASSNAME)).toBe(false); - expect(child.classList.contains(LEAVE_CLASSNAME)).toBe(false); - } - }); - - it('should find elements that have been removed via :leave', () => { - @Component({ - selector: 'ani-cmp', - template: ` + }).toThrow(); + + const children = cmp.container.nativeElement.querySelectorAll('.child'); + expect(children.length).toEqual(5); + + for (let i = 0; i < children.length; i++) { + let child = children[i]; + expect(child.classList.contains(ENTER_CLASSNAME)).toBe(false); + expect(child.classList.contains(LEAVE_CLASSNAME)).toBe(false); + } + }); + + it('should find elements that have been removed via :leave', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" class="parent"> <div *ngFor="let item of items" class="child"> {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - 'a => b', - [query(':leave', [style({opacity: 1}), animate(1000, style({opacity: .5}))])]), - ])] - }) - class Cmp { - public exp: any; - public items: any[] = [4, 2, 0]; - } + animations: [trigger( + 'myAnimation', + [ + transition( + 'a => b', + [query(':leave', [style({opacity: 1}), animate(1000, style({opacity: .5}))])]), + ])] + }) + class Cmp { + public exp: any; + public items: any[] = [4, 2, 0]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'a'; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp = 'a'; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp = 'b'; - cmp.items = []; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + cmp.items = []; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(3); + const players = getLog(); + expect(players.length).toEqual(3); - const [p1, p2, p3] = players; - expect(p1.element.innerText.trim()).toEqual('4'); - expect(p2.element.innerText.trim()).toEqual('2'); - expect(p3.element.innerText.trim()).toEqual('0'); + const [p1, p2, p3] = players; + expect(p1.element.innerText.trim()).toEqual('4'); + expect(p2.element.innerText.trim()).toEqual('2'); + expect(p3.element.innerText.trim()).toEqual('0'); - players.forEach(p => { - expect(p.keyframes).toEqual([{opacity: '1', offset: 0}, {opacity: '0.5', offset: 1}]); - }); + players.forEach(p => { + expect(p.keyframes).toEqual([{opacity: '1', offset: 0}, {opacity: '0.5', offset: 1}]); }); + }); - it('should find :enter nodes that have been inserted around non enter nodes', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should find :enter nodes that have been inserted around non enter nodes', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" class="parent"> <div *ngFor="let item of items" class="child"> {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - '* => go', - [query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]), - ])] - }) - class Cmp { - public exp: any; - public items: any[] = []; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'no'; - cmp.items = [2]; - fixture.detectChanges(); - engine.flush(); - resetLog(); + animations: [trigger( + 'myAnimation', + [ + transition( + '* => go', + [query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]), + ])] + }) + class Cmp { + public exp: any; + public items: any[] = []; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'no'; + cmp.items = [2]; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp = 'go'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'go'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(4); + const players = getLog(); + expect(players.length).toEqual(4); - const [p1, p2, p3, p4] = players; - expect(p1.element.innerText.trim()).toEqual('0'); - expect(p2.element.innerText.trim()).toEqual('1'); - expect(p3.element.innerText.trim()).toEqual('3'); - expect(p4.element.innerText.trim()).toEqual('4'); - }); + const [p1, p2, p3, p4] = players; + expect(p1.element.innerText.trim()).toEqual('0'); + expect(p2.element.innerText.trim()).toEqual('1'); + expect(p3.element.innerText.trim()).toEqual('3'); + expect(p4.element.innerText.trim()).toEqual('4'); + }); - it('should find :enter/:leave nodes that are nested inside of ng-container elements', () => { - @Component({ + it('should find :enter/:leave nodes that are nested inside of ng-container elements', () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="items.length" class="parent"> @@ -1048,64 +1041,64 @@ import {HostListener} from '../../src/metadata/directives'; ])] }) class Cmp { - // TODO(issue/24571): remove '!'. - public items !: any[]; - } + // TODO(issue/24571): remove '!'. + public items!: any[]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.items = []; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.items = []; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - expect(players.length).toEqual(5); + let players = getLog(); + expect(players.length).toEqual(5); - for (let i = 0; i < 5; i++) { - let player = players[i] !; - expect(player.keyframes).toEqual([ - {opacity: '0', offset: 0}, - {opacity: '1', offset: 1}, - ]); + for (let i = 0; i < 5; i++) { + let player = players[i]!; + expect(player.keyframes).toEqual([ + {opacity: '0', offset: 0}, + {opacity: '1', offset: 1}, + ]); - let elm = player.element; - let text = i % 2 == 0 ? `even ${i}` : `odd ${i}`; - expect(elm.innerText.trim()).toEqual(text); - } + let elm = player.element; + let text = i % 2 == 0 ? `even ${i}` : `odd ${i}`; + expect(elm.innerText.trim()).toEqual(text); + } - resetLog(); - cmp.items = []; - fixture.detectChanges(); - engine.flush(); + resetLog(); + cmp.items = []; + fixture.detectChanges(); + engine.flush(); - players = getLog(); - expect(players.length).toEqual(5); + players = getLog(); + expect(players.length).toEqual(5); - for (let i = 0; i < 5; i++) { - let player = players[i] !; - expect(player.keyframes).toEqual([ - {opacity: '1', offset: 0}, - {opacity: '0', offset: 1}, - ]); + for (let i = 0; i < 5; i++) { + let player = players[i]!; + expect(player.keyframes).toEqual([ + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, + ]); - let elm = player.element; - let text = i % 2 == 0 ? `even ${i}` : `odd ${i}`; - expect(elm.innerText.trim()).toEqual(text); - } - }); + let elm = player.element; + let text = i % 2 == 0 ? `even ${i}` : `odd ${i}`; + expect(elm.innerText.trim()).toEqual(text); + } + }); - it('should properly cancel items that were queried into a former animation and pass in the associated styles into the follow-up players per element', - () => { - @Component({ + it('should properly cancel items that were queried into a former animation and pass in the associated styles into the follow-up players per element', + () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="exp" class="parent"> @@ -1128,52 +1121,52 @@ import {HostListener} from '../../src/metadata/directives'; ])] }) class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public items !: any[]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'on'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); - - const previousPlayers = getLog(); - expect(previousPlayers.length).toEqual(10); - resetLog(); - - cmp.exp = 'off'; - cmp.items = [0, 1, 2]; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(4); - - const [p1, p2, p3, p4] = players; - - // p1 && p2 are the starting players for item3 and item4 - expect(p1.previousStyles) - .toEqual({opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE}); - expect(p2.previousStyles) - .toEqual({opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE}); - - // p3 && p4 are the following players for item3 and item4 - expect(p3.previousStyles).toEqual({}); - expect(p4.previousStyles).toEqual({}); - }); - - it('should not remove a parent container if its contents are queried into by an ancestor element', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + public exp: any; + // TODO(issue/24571): remove '!'. + public items!: any[]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'on'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); + + const previousPlayers = getLog(); + expect(previousPlayers.length).toEqual(10); + resetLog(); + + cmp.exp = 'off'; + cmp.items = [0, 1, 2]; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(4); + + const [p1, p2, p3, p4] = players; + + // p1 && p2 are the starting players for item3 and item4 + expect(p1.previousStyles) + .toEqual({opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE}); + expect(p2.previousStyles) + .toEqual({opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE}); + + // p3 && p4 are the following players for item3 and item4 + expect(p3.previousStyles).toEqual({}); + expect(p4.previousStyles).toEqual({}); + }); + + it('should not remove a parent container if its contents are queried into by an ancestor element', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp1" class="ancestor" #ancestor> <div class="parent" *ngIf="exp2" #parent> <div class="child"></div> @@ -1181,67 +1174,67 @@ import {HostListener} from '../../src/metadata/directives'; </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - query( - '.child', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - ]), - ] - }) - class Cmp { - public exp1: any = ''; - public exp2: any = true; - - @ViewChild('ancestor') public ancestorElm: any; - - @ViewChild('parent') public parentElm: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - resetLog(); - - const ancestorElm = cmp.ancestorElm.nativeElement; - const parentElm = cmp.parentElm.nativeElement; - - cmp.exp1 = 'go'; - cmp.exp2 = false; - fixture.detectChanges(); - engine.flush(); - - expect(ancestorElm.contains(parentElm)).toBe(true); - - const players = getLog(); - expect(players.length).toEqual(2); - const [p1, p2] = players; - expect(parentElm.contains(p1.element)).toBe(true); - expect(parentElm.contains(p2.element)).toBe(true); - - cancelAllPlayers(players); - - expect(ancestorElm.contains(parentElm)).toBe(false); - }); - - it('should only retain a to-be-removed node if the inner queried items are apart of an animation issued by an ancestor', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + query( + '.child', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + ]), + ] + }) + class Cmp { + public exp1: any = ''; + public exp2: any = true; + + @ViewChild('ancestor') public ancestorElm: any; + + @ViewChild('parent') public parentElm: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + resetLog(); + + const ancestorElm = cmp.ancestorElm.nativeElement; + const parentElm = cmp.parentElm.nativeElement; + + cmp.exp1 = 'go'; + cmp.exp2 = false; + fixture.detectChanges(); + engine.flush(); + + expect(ancestorElm.contains(parentElm)).toBe(true); + + const players = getLog(); + expect(players.length).toEqual(2); + const [p1, p2] = players; + expect(parentElm.contains(p1.element)).toBe(true); + expect(parentElm.contains(p2.element)).toBe(true); + + cancelAllPlayers(players); + + expect(ancestorElm.contains(parentElm)).toBe(false); + }); + + it('should only retain a to-be-removed node if the inner queried items are apart of an animation issued by an ancestor', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@one]="exp1" [@two]="exp2" class="ancestor" #ancestor> <header>hello</header> <div class="parent" *ngIf="parentExp" #parent> @@ -1249,191 +1242,195 @@ import {HostListener} from '../../src/metadata/directives'; </div> </div> `, - animations: [ - trigger( - 'one', - [ - transition( - '* => go', - [ - query( - '.child', - [ - style({height: '100px'}), - animate(1000, style({height: '0px'})), - ]), - ]), - ]), - trigger( - 'two', - [ - transition('* => go', [query( - 'header', - [ - style({width: '100px'}), - animate(1000, style({width: '0px'})), - ])]), - ]), - ] - }) - class Cmp { - public exp1: any = ''; - public exp2: any = ''; - public parentExp: any = true; - - @ViewChild('ancestor') public ancestorElm: any; - - @ViewChild('parent') public parentElm: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - resetLog(); - - const ancestorElm = cmp.ancestorElm.nativeElement; - const parentElm = cmp.parentElm.nativeElement; - expect(ancestorElm.contains(parentElm)).toBe(true); - - cmp.exp1 = 'go'; - fixture.detectChanges(); - engine.flush(); - - expect(ancestorElm.contains(parentElm)).toBe(true); - - const onePlayers = getLog(); - expect(onePlayers.length).toEqual(1); // element.child - const [childPlayer] = onePlayers; - - let childPlayerComplete = false; - childPlayer.onDone(() => childPlayerComplete = true); - resetLog(); - flushMicrotasks(); - - expect(childPlayerComplete).toBe(false); - - cmp.exp2 = 'go'; - cmp.parentExp = false; - fixture.detectChanges(); - engine.flush(); - - const twoPlayers = getLog(); - expect(twoPlayers.length).toEqual(1); // the header element - expect(ancestorElm.contains(parentElm)).toBe(false); - expect(childPlayerComplete).toBe(true); - })); - - it('should finish queried players in an animation when the next animation takes over', () => { - @Component({ - selector: 'ani-cmp', - template: ` + animations: [ + trigger( + 'one', + [ + transition( + '* => go', + [ + query( + '.child', + [ + style({height: '100px'}), + animate(1000, style({height: '0px'})), + ]), + ]), + ]), + trigger( + 'two', + [ + transition('* => go', [query( + 'header', + [ + style({width: '100px'}), + animate(1000, style({width: '0px'})), + ])]), + ]), + ] + }) + class Cmp { + public exp1: any = ''; + public exp2: any = ''; + public parentExp: any = true; + + @ViewChild('ancestor') public ancestorElm: any; + + @ViewChild('parent') public parentElm: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + resetLog(); + + const ancestorElm = cmp.ancestorElm.nativeElement; + const parentElm = cmp.parentElm.nativeElement; + expect(ancestorElm.contains(parentElm)).toBe(true); + + cmp.exp1 = 'go'; + fixture.detectChanges(); + engine.flush(); + + expect(ancestorElm.contains(parentElm)).toBe(true); + + const onePlayers = getLog(); + expect(onePlayers.length).toEqual(1); // element.child + const [childPlayer] = onePlayers; + + let childPlayerComplete = false; + childPlayer.onDone(() => childPlayerComplete = true); + resetLog(); + flushMicrotasks(); + + expect(childPlayerComplete).toBe(false); + + cmp.exp2 = 'go'; + cmp.parentExp = false; + fixture.detectChanges(); + engine.flush(); + + const twoPlayers = getLog(); + expect(twoPlayers.length).toEqual(1); // the header element + expect(ancestorElm.contains(parentElm)).toBe(false); + expect(childPlayerComplete).toBe(true); + })); + + it('should finish queried players in an animation when the next animation takes over', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" class="parent"> <div *ngFor="let item of items" class="child"> {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - '* => on', - [ - query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), - ]), - transition('* => off', []) - ])] - }) - class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public items !: any[]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'on'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(5); - - let count = 0; - players.forEach(p => { p.onDone(() => count++); }); + animations: [trigger( + 'myAnimation', + [ + transition( + '* => on', + [ + query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + ]), + transition('* => off', []) + ])] + }) + class Cmp { + public exp: any; + // TODO(issue/24571): remove '!'. + public items!: any[]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'on'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(5); + + let count = 0; + players.forEach(p => { + p.onDone(() => count++); + }); - expect(count).toEqual(0); + expect(count).toEqual(0); - cmp.exp = 'off'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'off'; + fixture.detectChanges(); + engine.flush(); - expect(count).toEqual(5); - }); + expect(count).toEqual(5); + }); - it('should finish queried players when the previous player is finished', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should finish queried players when the previous player is finished', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" class="parent"> <div *ngFor="let item of items" class="child"> {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - '* => on', - [ - query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), - ]), - transition('* => off', []) - ])] - }) - class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public items !: any[]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'on'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(5); - - let count = 0; - players.forEach(p => { p.onDone(() => count++); }); + animations: [trigger( + 'myAnimation', + [ + transition( + '* => on', + [ + query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + ]), + transition('* => off', []) + ])] + }) + class Cmp { + public exp: any; + // TODO(issue/24571): remove '!'. + public items!: any[]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'on'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(5); + + let count = 0; + players.forEach(p => { + p.onDone(() => count++); + }); - expect(count).toEqual(0); + expect(count).toEqual(0); - expect(engine.players.length).toEqual(1); - engine.players[0].finish(); + expect(engine.players.length).toEqual(1); + engine.players[0].finish(); - expect(count).toEqual(5); - }); + expect(count).toEqual(5); + }); - it('should allow multiple triggers to animate on queried elements at the same time', () => { - @Component({ + it('should allow multiple triggers to animate on queried elements at the same time', () => { + @Component({ selector: 'ani-cmp', template: ` <div [@one]="exp1" [@two]="exp2" class="parent"> @@ -1464,111 +1461,117 @@ import {HostListener} from '../../src/metadata/directives'; ] }) class Cmp { - public exp1: any; - public exp2: any; - // TODO(issue/24571): remove '!'. - public items !: any[]; - } + public exp1: any; + public exp2: any; + // TODO(issue/24571): remove '!'. + public items!: any[]; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = 'on'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = 'on'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - expect(players.length).toEqual(5); + let players = getLog(); + expect(players.length).toEqual(5); - let count = 0; - players.forEach(p => { p.onDone(() => count++); }); + let count = 0; + players.forEach(p => { + p.onDone(() => count++); + }); - resetLog(); + resetLog(); - expect(count).toEqual(0); + expect(count).toEqual(0); - cmp.exp2 = 'on'; - fixture.detectChanges(); - engine.flush(); + cmp.exp2 = 'on'; + fixture.detectChanges(); + engine.flush(); - expect(count).toEqual(0); + expect(count).toEqual(0); - players = getLog(); - expect(players.length).toEqual(3); + players = getLog(); + expect(players.length).toEqual(3); - players.forEach(p => { p.onDone(() => count++); }); + players.forEach(p => { + p.onDone(() => count++); + }); - cmp.exp1 = 'off'; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = 'off'; + fixture.detectChanges(); + engine.flush(); - expect(count).toEqual(5); + expect(count).toEqual(5); - cmp.exp2 = 'off'; - fixture.detectChanges(); - engine.flush(); + cmp.exp2 = 'off'; + fixture.detectChanges(); + engine.flush(); - expect(count).toEqual(8); - }); + expect(count).toEqual(8); + }); - it('should cancel inner queried animations if a trigger state value changes, but isn\'t detected as a valid transition', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should cancel inner queried animations if a trigger state value changes, but isn\'t detected as a valid transition', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" class="parent"> <div *ngFor="let item of items" class="child"> {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [transition( - '* => on', - [ - query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), - ])])] - }) - class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public items !: any[]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'on'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(5); + animations: [trigger( + 'myAnimation', + [transition( + '* => on', + [ + query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + ])])] + }) + class Cmp { + public exp: any; + // TODO(issue/24571): remove '!'. + public items!: any[]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'on'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(5); + + let count = 0; + players.forEach(p => { + p.onDone(() => count++); + }); - let count = 0; - players.forEach(p => { p.onDone(() => count++); }); + expect(count).toEqual(0); - expect(count).toEqual(0); + cmp.exp = 'off'; + fixture.detectChanges(); + engine.flush(); - cmp.exp = 'off'; - fixture.detectChanges(); - engine.flush(); + expect(count).toEqual(5); + }); - expect(count).toEqual(5); - }); - - it('should allow for queried items to restore their styling back to the original state via animate(time, "*")', - () => { - @Component({ + it('should allow for queried items to restore their styling back to the original state via animate(time, "*")', + () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="exp" class="parent"> @@ -1590,301 +1593,299 @@ import {HostListener} from '../../src/metadata/directives'; ] }) class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public items !: any[]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'on'; - cmp.items = [0, 1, 2]; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(3); - - players.forEach(p => { - expect(p.keyframes).toEqual([ - {opacity: '0', width: '0px', height: '0px', offset: 0}, - {opacity: '1', width: '0px', height: '0px', offset: .5}, - {opacity: AUTO_STYLE, width: AUTO_STYLE, height: '200px', offset: 1} - ]); - }); + public exp: any; + // TODO(issue/24571): remove '!'. + public items!: any[]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'on'; + cmp.items = [0, 1, 2]; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(3); + + players.forEach(p => { + expect(p.keyframes).toEqual([ + {opacity: '0', width: '0px', height: '0px', offset: 0}, + {opacity: '1', width: '0px', height: '0px', offset: .5}, + {opacity: AUTO_STYLE, width: AUTO_STYLE, height: '200px', offset: 1} + ]); }); + }); - it('should query elements in sub components that do not contain animations using the :enter selector', - () => { - @Component({ - selector: 'parent-cmp', - template: ` + it('should query elements in sub components that do not contain animations using the :enter selector', + () => { + @Component({ + selector: 'parent-cmp', + template: ` <div [@myAnimation]="exp"> <child-cmp #child></child-cmp> </div> `, - animations: [trigger( - 'myAnimation', - [transition( - '* => on', - [query( - ':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])])] - }) - class ParentCmp { - public exp: any; - - @ViewChild('child') public child: any; - } - - @Component({ - selector: 'child-cmp', - template: ` + animations: [trigger( + 'myAnimation', + [transition( + '* => on', + [query(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])])] + }) + class ParentCmp { + public exp: any; + + @ViewChild('child') public child: any; + } + + @Component({ + selector: 'child-cmp', + template: ` <div *ngFor="let item of items"> {{ item }} </div> ` - }) - class ChildCmp { - public items: any[] = []; - } - - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - - cmp.exp = 'on'; - cmp.child.items = [1, 2, 3]; - fixture.detectChanges(); - - const players = getLog() as any[]; - expect(players.length).toEqual(3); - - expect(players[0].element.innerText.trim()).toEqual('1'); - expect(players[1].element.innerText.trim()).toEqual('2'); - expect(players[2].element.innerText.trim()).toEqual('3'); - }); - - it('should query elements in sub components that do not contain animations using the :leave selector', - () => { - @Component({ - selector: 'parent-cmp', - template: ` + }) + class ChildCmp { + public items: any[] = []; + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + + cmp.exp = 'on'; + cmp.child.items = [1, 2, 3]; + fixture.detectChanges(); + + const players = getLog() as any[]; + expect(players.length).toEqual(3); + + expect(players[0].element.innerText.trim()).toEqual('1'); + expect(players[1].element.innerText.trim()).toEqual('2'); + expect(players[2].element.innerText.trim()).toEqual('3'); + }); + + it('should query elements in sub components that do not contain animations using the :leave selector', + () => { + @Component({ + selector: 'parent-cmp', + template: ` <div [@myAnimation]="exp"> <child-cmp #child></child-cmp> </div> `, - animations: [trigger( - 'myAnimation', - [transition( - '* => on', [query(':leave', [animate(1000, style({opacity: 0}))])])])] - }) - class ParentCmp { - public exp: any; - - @ViewChild('child', {static: true}) public child: any; - } - - @Component({ - selector: 'child-cmp', - template: ` + animations: [trigger( + 'myAnimation', + [transition('* => on', [query(':leave', [animate(1000, style({opacity: 0}))])])])] + }) + class ParentCmp { + public exp: any; + + @ViewChild('child', {static: true}) public child: any; + } + + @Component({ + selector: 'child-cmp', + template: ` <div *ngFor="let item of items"> {{ item }} </div> ` - }) - class ChildCmp { - public items: any[] = []; - } + }) + class ChildCmp { + public items: any[] = []; + } - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; - cmp.child.items = [4, 5, 6]; - fixture.detectChanges(); + cmp.child.items = [4, 5, 6]; + fixture.detectChanges(); - cmp.exp = 'on'; - cmp.child.items = []; - fixture.detectChanges(); + cmp.exp = 'on'; + cmp.child.items = []; + fixture.detectChanges(); - const players = getLog() as any[]; - expect(players.length).toEqual(3); + const players = getLog() as any[]; + expect(players.length).toEqual(3); - expect(players[0].element.innerText.trim()).toEqual('4'); - expect(players[1].element.innerText.trim()).toEqual('5'); - expect(players[2].element.innerText.trim()).toEqual('6'); - }); + expect(players[0].element.innerText.trim()).toEqual('4'); + expect(players[1].element.innerText.trim()).toEqual('5'); + expect(players[2].element.innerText.trim()).toEqual('6'); + }); - describe('options.limit', () => { - it('should limit results when a limit value is passed into the query options', () => { - @Component({ - selector: 'cmp', - template: ` + describe('options.limit', () => { + it('should limit results when a limit value is passed into the query options', () => { + @Component({ + selector: 'cmp', + template: ` <div [@myAnimation]="exp"> <div *ngFor="let item of items" class="item"> {{ item }} </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - query( - '.item', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ], - {limit: 2}), - ]), - ]), - ] - }) - class Cmp { - public exp: any; - public items: any[] = []; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + query( + '.item', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ], + {limit: 2}), + ]), + ]), + ] + }) + class Cmp { + public exp: any; + public items: any[] = []; + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.items = ['a', 'b', 'c', 'd', 'e']; - fixture.detectChanges(); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.items = ['a', 'b', 'c', 'd', 'e']; + fixture.detectChanges(); - cmp.exp = 'go'; - fixture.detectChanges(); + cmp.exp = 'go'; + fixture.detectChanges(); - const players = getLog() as any[]; - expect(players.length).toEqual(2); - expect(players[0].element.innerText.trim()).toEqual('a'); - expect(players[1].element.innerText.trim()).toEqual('b'); - }); + const players = getLog() as any[]; + expect(players.length).toEqual(2); + expect(players[0].element.innerText.trim()).toEqual('a'); + expect(players[1].element.innerText.trim()).toEqual('b'); + }); - it('should support negative limit values by pulling in elements from the end of the query', - () => { - @Component({ - selector: 'cmp', - template: ` + it('should support negative limit values by pulling in elements from the end of the query', + () => { + @Component({ + selector: 'cmp', + template: ` <div [@myAnimation]="exp"> <div *ngFor="let item of items" class="item"> {{ item }} </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - query( - '.item', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ], - {limit: -3}), - ]), - ]), - ] - }) - class Cmp { - public exp: any; - public items: any[] = []; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + query( + '.item', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ], + {limit: -3}), + ]), + ]), + ] + }) + class Cmp { + public exp: any; + public items: any[] = []; + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.items = ['a', 'b', 'c', 'd', 'e']; - fixture.detectChanges(); - - cmp.exp = 'go'; - fixture.detectChanges(); - - const players = getLog() as any[]; - expect(players.length).toEqual(3); - expect(players[0].element.innerText.trim()).toEqual('c'); - expect(players[1].element.innerText.trim()).toEqual('d'); - expect(players[2].element.innerText.trim()).toEqual('e'); - }); - }); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.items = ['a', 'b', 'c', 'd', 'e']; + fixture.detectChanges(); + + cmp.exp = 'go'; + fixture.detectChanges(); + + const players = getLog() as any[]; + expect(players.length).toEqual(3); + expect(players[0].element.innerText.trim()).toEqual('c'); + expect(players[1].element.innerText.trim()).toEqual('d'); + expect(players[2].element.innerText.trim()).toEqual('e'); + }); }); + }); - describe('sub triggers', () => { - it('should animate a sub trigger that exists in an inner element in the template', () => { - @Component({ - selector: 'ani-cmp', - template: ` + describe('sub triggers', () => { + it('should animate a sub trigger that exists in an inner element in the template', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #parent class="parent" [@parent]="exp1"> <div #child class="child" [@child]="exp2"></div> </div> `, - animations: [ - trigger('parent', [transition( - '* => go1', - [ - style({width: '0px'}), animate(1000, style({width: '100px'})), - query('.child', [animateChild()]) - ])]), - trigger('child', [transition( - '* => go2', - [ - style({height: '0px'}), - animate(1000, style({height: '100px'})), - ])]) - ] - }) - class Cmp { - public exp1: any; - public exp2: any; - - @ViewChild('parent') public elm1: any; - - @ViewChild('child') public elm2: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp1 = 'go1'; - cmp.exp2 = 'go2'; - fixture.detectChanges(); - engine.flush(); - - const elm1 = cmp.elm1; - const elm2 = cmp.elm2; - - const [p1, p2] = getLog(); - expect(p1.delay).toEqual(0); - expect(p1.element).toEqual(elm1.nativeElement); - expect(p1.duration).toEqual(1000); - expect(p1.keyframes).toEqual([{width: '0px', offset: 0}, {width: '100px', offset: 1}]); - - expect(p2.delay).toEqual(0); - expect(p2.element).toEqual(elm2.nativeElement); - expect(p2.duration).toEqual(2000); - expect(p2.keyframes).toEqual([ - {height: '0px', offset: 0}, {height: '0px', offset: .5}, {height: '100px', offset: 1} - ]); - }); + animations: [ + trigger('parent', [transition( + '* => go1', + [ + style({width: '0px'}), animate(1000, style({width: '100px'})), + query('.child', [animateChild()]) + ])]), + trigger('child', [transition( + '* => go2', + [ + style({height: '0px'}), + animate(1000, style({height: '100px'})), + ])]) + ] + }) + class Cmp { + public exp1: any; + public exp2: any; + + @ViewChild('parent') public elm1: any; + + @ViewChild('child') public elm2: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp1 = 'go1'; + cmp.exp2 = 'go2'; + fixture.detectChanges(); + engine.flush(); + + const elm1 = cmp.elm1; + const elm2 = cmp.elm2; + + const [p1, p2] = getLog(); + expect(p1.delay).toEqual(0); + expect(p1.element).toEqual(elm1.nativeElement); + expect(p1.duration).toEqual(1000); + expect(p1.keyframes).toEqual([{width: '0px', offset: 0}, {width: '100px', offset: 1}]); + + expect(p2.delay).toEqual(0); + expect(p2.element).toEqual(elm2.nativeElement); + expect(p2.duration).toEqual(2000); + expect(p2.keyframes).toEqual([ + {height: '0px', offset: 0}, {height: '0px', offset: .5}, {height: '100px', offset: 1} + ]); + }); - it('should run and operate a series of triggers on a list of elements with overridden timing data', - () => { - @Component({ + it('should run and operate a series of triggers on a list of elements with overridden timing data', + () => { + @Component({ selector: 'ani-cmp', template: ` <div #parent class="parent" [@parent]="exp"> @@ -1908,557 +1909,548 @@ import {HostListener} from '../../src/metadata/directives'; ] }) class Cmp { - public exp: any; - public items: any[] = [0, 1, 2, 3, 4]; + public exp: any; + public items: any[] = [0, 1, 2, 3, 4]; - @ViewChild('parent') public elm: any; - } + @ViewChild('parent') public elm: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); - const parent = cmp.elm.nativeElement; - const elements = parent.querySelectorAll('.item'); + const parent = cmp.elm.nativeElement; + const elements = parent.querySelectorAll('.item'); - const players = getLog(); - expect(players.length).toEqual(7); - const [pA, pc1, pc2, pc3, pc4, pc5, pZ] = players; + const players = getLog(); + expect(players.length).toEqual(7); + const [pA, pc1, pc2, pc3, pc4, pc5, pZ] = players; - expect(pA.element).toEqual(parent); - expect(pA.delay).toEqual(0); - expect(pA.duration).toEqual(1000); + expect(pA.element).toEqual(parent); + expect(pA.delay).toEqual(0); + expect(pA.duration).toEqual(1000); - expect(pc1.element).toEqual(elements[0]); - expect(pc1.delay).toEqual(0); - expect(pc1.duration).toEqual(4000); + expect(pc1.element).toEqual(elements[0]); + expect(pc1.delay).toEqual(0); + expect(pc1.duration).toEqual(4000); - expect(pc2.element).toEqual(elements[1]); - expect(pc2.delay).toEqual(0); - expect(pc2.duration).toEqual(4000); + expect(pc2.element).toEqual(elements[1]); + expect(pc2.delay).toEqual(0); + expect(pc2.duration).toEqual(4000); - expect(pc3.element).toEqual(elements[2]); - expect(pc3.delay).toEqual(0); - expect(pc3.duration).toEqual(4000); + expect(pc3.element).toEqual(elements[2]); + expect(pc3.delay).toEqual(0); + expect(pc3.duration).toEqual(4000); - expect(pc4.element).toEqual(elements[3]); - expect(pc4.delay).toEqual(0); - expect(pc4.duration).toEqual(4000); + expect(pc4.element).toEqual(elements[3]); + expect(pc4.delay).toEqual(0); + expect(pc4.duration).toEqual(4000); - expect(pc5.element).toEqual(elements[4]); - expect(pc5.delay).toEqual(0); - expect(pc5.duration).toEqual(4000); + expect(pc5.element).toEqual(elements[4]); + expect(pc5.delay).toEqual(0); + expect(pc5.duration).toEqual(4000); - expect(pZ.element).toEqual(parent); - expect(pZ.delay).toEqual(4000); - expect(pZ.duration).toEqual(1000); - }); + expect(pZ.element).toEqual(parent); + expect(pZ.delay).toEqual(4000); + expect(pZ.duration).toEqual(1000); + }); - it('should silently continue if a sub trigger is animated that doesn\'t exist', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should silently continue if a sub trigger is animated that doesn\'t exist', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #parent class="parent" [@parent]="exp"> <div class="child"></div> </div> `, - animations: - [trigger('parent', [transition( - '* => go', - [ - style({opacity: 0}), animate(1000, style({opacity: 1})), - query('.child', [animateChild({duration: '1s'})]), - animate(1000, style({opacity: 0})) - ])])] - }) - class Cmp { - public exp: any; - public items: any[] = [0, 1, 2, 3, 4]; + animations: + [trigger('parent', [transition( + '* => go', + [ + style({opacity: 0}), animate(1000, style({opacity: 1})), + query('.child', [animateChild({duration: '1s'})]), + animate(1000, style({opacity: 0})) + ])])] + }) + class Cmp { + public exp: any; + public items: any[] = [0, 1, 2, 3, 4]; + + @ViewChild('parent') public elm: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); + + const parent = cmp.elm.nativeElement; + const players = getLog(); + expect(players.length).toEqual(2); + + const [pA, pZ] = players; + expect(pA.element).toEqual(parent); + expect(pA.delay).toEqual(0); + expect(pA.duration).toEqual(1000); + + expect(pZ.element).toEqual(parent); + expect(pZ.delay).toEqual(1000); + expect(pZ.duration).toEqual(1000); + }); - @ViewChild('parent') public elm: any; - } + it('should silently continue if a sub trigger is animated that doesn\'t contain a trigger that is setup for animation', + () => { + @Component({ + selector: 'ani-cmp', + template: ` + <div #parent class="parent" [@parent]="exp1"> + <div [@child]="exp2" class="child"></div> + </div> + `, + animations: [ + trigger( + 'child', + [transition('a => z', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]), + trigger('parent', [transition( + 'a => z', + [ + style({opacity: 0}), animate(1000, style({opacity: 1})), + query('.child', [animateChild({duration: '1s'})]), + animate(1000, style({opacity: 0})) + ])]) + ] + }) + class Cmp { + public exp1: any; + public exp2: any; + + @ViewChild('parent') public elm: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp1 = 'a'; + cmp.exp2 = 'a'; + fixture.detectChanges(); + engine.flush(); + resetLog(); + + cmp.exp1 = 'z'; + fixture.detectChanges(); + engine.flush(); + + const parent = cmp.elm.nativeElement; + const players = getLog(); + expect(players.length).toEqual(2); + + const [pA, pZ] = players; + expect(pA.element).toEqual(parent); + expect(pA.delay).toEqual(0); + expect(pA.duration).toEqual(1000); + + expect(pZ.element).toEqual(parent); + expect(pZ.delay).toEqual(1000); + expect(pZ.duration).toEqual(1000); + }); + + it('should animate all sub triggers on the element at the same time', () => { + @Component({ + selector: 'ani-cmp', + template: ` + <div #parent class="parent" [@parent]="exp1"> + <div [@w]="exp2" [@h]="exp2" class="child"></div> + </div> + `, + animations: [ + trigger( + 'w', + [transition('* => go', [style({width: 0}), animate(1800, style({width: '100px'}))])]), + trigger( + 'h', [transition( + '* => go', [style({height: 0}), animate(1500, style({height: '100px'}))])]), + trigger( + 'parent', [transition( + '* => go', + [ + style({opacity: 0}), animate(1000, style({opacity: 1})), + query('.child', [animateChild()]), animate(1000, style({opacity: 0})) + ])]) + ] + }) + class Cmp { + public exp1: any; + public exp2: any; - TestBed.configureTestingModule({declarations: [Cmp]}); + @ViewChild('parent') public elm: any; + } - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + TestBed.configureTestingModule({declarations: [Cmp]}); - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - const parent = cmp.elm.nativeElement; - const players = getLog(); - expect(players.length).toEqual(2); + cmp.exp1 = 'go'; + cmp.exp2 = 'go'; + fixture.detectChanges(); + engine.flush(); - const [pA, pZ] = players; - expect(pA.element).toEqual(parent); - expect(pA.delay).toEqual(0); - expect(pA.duration).toEqual(1000); + const players = getLog(); + expect(players.length).toEqual(4); + const [pA, pc1, pc2, pZ] = players; - expect(pZ.element).toEqual(parent); - expect(pZ.delay).toEqual(1000); - expect(pZ.duration).toEqual(1000); - }); + expect(pc1.delay).toEqual(0); + expect(pc1.duration).toEqual(2800); - it('should silently continue if a sub trigger is animated that doesn\'t contain a trigger that is setup for animation', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + expect(pc2.delay).toEqual(0); + expect(pc2.duration).toEqual(2500); + + expect(pZ.delay).toEqual(2800); + expect(pZ.duration).toEqual(1000); + }); + + it('should skip a sub animation when a zero duration value is passed in', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #parent class="parent" [@parent]="exp1"> <div [@child]="exp2" class="child"></div> </div> `, - animations: [ - trigger('child', [transition( - 'a => z', - [style({opacity: 0}), animate(1000, style({opacity: 1}))])]), - trigger('parent', [transition( - 'a => z', - [ - style({opacity: 0}), animate(1000, style({opacity: 1})), - query('.child', [animateChild({duration: '1s'})]), - animate(1000, style({opacity: 0})) - ])]) - ] - }) - class Cmp { - public exp1: any; - public exp2: any; + animations: [ + trigger( + 'child', + [transition('* => go', [style({width: 0}), animate(1800, style({width: '100px'}))])]), + trigger('parent', [transition( + '* => go', + [ + style({opacity: 0}), animate(1000, style({opacity: 1})), + query('.child', [animateChild({duration: '0'})]), + animate(1000, style({opacity: 0})) + ])]) + ] + }) + class Cmp { + public exp1: any; + public exp2: any; + + @ViewChild('parent') public elm: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp1 = 'go'; + cmp.exp2 = 'go'; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(2); + const [pA, pZ] = players; + + expect(pA.delay).toEqual(0); + expect(pA.duration).toEqual(1000); + + expect(pZ.delay).toEqual(1000); + expect(pZ.duration).toEqual(1000); + }); - @ViewChild('parent') public elm: any; - } + it('should only allow a sub animation to be used up by a parent trigger once', () => { + @Component({ + selector: 'ani-cmp', + template: ` + <div [@parent]="exp1" class="parent1" #parent> + <div [@parent]="exp1" class="parent2"> + <div [@child]="exp2" class="child"> + </div> + </div> + </div> + `, + animations: [ + trigger('parent', [transition( + '* => go', + [ + style({opacity: 0}), animate(1000, style({opacity: 1})), + query('.child', animateChild()) + ])]), + trigger( + 'child', + [transition('* => go', [style({opacity: 0}), animate(1800, style({opacity: 1}))])]) + ] + }) + class Cmp { + public exp1: any; + public exp2: any; + + @ViewChild('parent') public elm: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp1 = 'go'; + cmp.exp2 = 'go'; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(3); + + const [p1, p2, p3] = players; + + // parent2 is evaluated first because it is inside of parent1 + expect(p1.element.classList.contains('parent2')).toBeTruthy(); + expect(p2.element.classList.contains('child')).toBeTruthy(); + expect(p3.element.classList.contains('parent1')).toBeTruthy(); + }); - TestBed.configureTestingModule({declarations: [Cmp]}); + it('should emulate a leave animation on the nearest sub host elements when a parent is removed', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: ` + <div @parent *ngIf="exp" class="parent1" #parent> + <child-cmp #child @leave (@leave.start)="animateStart($event)"></child-cmp> + </div> + `, + animations: [ + trigger( + 'leave', + [ + transition(':leave', [animate(1000, style({color: 'gold'}))]), + ]), + trigger( + 'parent', + [ + transition(':leave', [query(':leave', animateChild())]), + ]), + ] + }) + class ParentCmp { + public exp: boolean = true; + @ViewChild('child') public childElm: any; + + public childEvent: any; + + animateStart(event: any) { + if (event.toState == 'void') { + this.childEvent = event; + } + } + } - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + @Component({ + selector: 'child-cmp', + template: '...', + animations: [ + trigger( + 'child', + [ + transition(':leave', [animate(1000, style({color: 'gold'}))]), + ]), + ] + }) + class ChildCmp { + public childEvent: any; + + @HostBinding('@child') public animate = true; + + @HostListener('@child.start', ['$event']) + animateStart(event: any) { + if (event.toState == 'void') { + this.childEvent = event; + } + } + } - cmp.exp1 = 'a'; - cmp.exp2 = 'a'; - fixture.detectChanges(); - engine.flush(); - resetLog(); + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; - cmp.exp1 = 'z'; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); - const parent = cmp.elm.nativeElement; - const players = getLog(); - expect(players.length).toEqual(2); + const childCmp = cmp.childElm; - const [pA, pZ] = players; - expect(pA.element).toEqual(parent); - expect(pA.delay).toEqual(0); - expect(pA.duration).toEqual(1000); + cmp.exp = false; + fixture.detectChanges(); + flushMicrotasks(); - expect(pZ.element).toEqual(parent); - expect(pZ.delay).toEqual(1000); - expect(pZ.duration).toEqual(1000); - }); + expect(cmp.childEvent.toState).toEqual('void'); + expect(cmp.childEvent.totalTime).toEqual(1000); + expect(childCmp.childEvent.toState).toEqual('void'); + expect(childCmp.childEvent.totalTime).toEqual(1000); + })); - it('should animate all sub triggers on the element at the same time', () => { - @Component({ - selector: 'ani-cmp', - template: ` - <div #parent class="parent" [@parent]="exp1"> - <div [@w]="exp2" [@h]="exp2" class="child"></div> + it('should emulate a leave animation on a sub component\'s inner elements when a parent leave animation occurs with animateChild', + () => { + @Component({ + selector: 'ani-cmp', + template: ` + <div @myAnimation *ngIf="exp" class="parent"> + <child-cmp></child-cmp> </div> `, - animations: [ - trigger('w', [ - transition('* => go', [ - style({ width: 0 }), - animate(1800, style({ width: '100px' })) - ]) - ]), - trigger('h', [ - transition('* => go', [ - style({ height: 0 }), - animate(1500, style({ height: '100px' })) - ]) - ]), - trigger('parent', [ - transition('* => go', [ - style({ opacity: 0 }), - animate(1000, style({ opacity: 1 })), - query('.child', [ - animateChild() - ]), - animate(1000, style({ opacity: 0 })) - ]) - ]) - ] - }) - class Cmp { - public exp1: any; - public exp2: any; - - @ViewChild('parent') public elm: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp1 = 'go'; - cmp.exp2 = 'go'; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(4); - const [pA, pc1, pc2, pZ] = players; - - expect(pc1.delay).toEqual(0); - expect(pc1.duration).toEqual(2800); - - expect(pc2.delay).toEqual(0); - expect(pc2.duration).toEqual(2500); - - expect(pZ.delay).toEqual(2800); - expect(pZ.duration).toEqual(1000); - }); - - it('should skip a sub animation when a zero duration value is passed in', () => { - @Component({ - selector: 'ani-cmp', - template: ` - <div #parent class="parent" [@parent]="exp1"> - <div [@child]="exp2" class="child"></div> - </div> - `, - animations: [ - trigger('child', [transition( - '* => go', - [style({width: 0}), animate(1800, style({width: '100px'}))])]), - trigger('parent', [transition( - '* => go', - [ - style({opacity: 0}), animate(1000, style({opacity: 1})), - query('.child', [animateChild({duration: '0'})]), - animate(1000, style({opacity: 0})) - ])]) - ] - }) - class Cmp { - public exp1: any; - public exp2: any; - - @ViewChild('parent') public elm: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp1 = 'go'; - cmp.exp2 = 'go'; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(2); - const [pA, pZ] = players; - - expect(pA.delay).toEqual(0); - expect(pA.duration).toEqual(1000); - - expect(pZ.delay).toEqual(1000); - expect(pZ.duration).toEqual(1000); - }); - - it('should only allow a sub animation to be used up by a parent trigger once', () => { - @Component({ - selector: 'ani-cmp', - template: ` - <div [@parent]="exp1" class="parent1" #parent> - <div [@parent]="exp1" class="parent2"> - <div [@child]="exp2" class="child"> - </div> - </div> - </div> - `, - animations: [ - trigger('parent', [transition( - '* => go', - [ - style({opacity: 0}), animate(1000, style({opacity: 1})), - query('.child', animateChild()) - ])]), - trigger('child', [transition( - '* => go', - [style({opacity: 0}), animate(1800, style({opacity: 1}))])]) - ] - }) - class Cmp { - public exp1: any; - public exp2: any; - - @ViewChild('parent') public elm: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp1 = 'go'; - cmp.exp2 = 'go'; - fixture.detectChanges(); - engine.flush(); - - const players = getLog(); - expect(players.length).toEqual(3); - - const [p1, p2, p3] = players; - - // parent2 is evaluated first because it is inside of parent1 - expect(p1.element.classList.contains('parent2')).toBeTruthy(); - expect(p2.element.classList.contains('child')).toBeTruthy(); - expect(p3.element.classList.contains('parent1')).toBeTruthy(); - }); - - it('should emulate a leave animation on the nearest sub host elements when a parent is removed', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` - <div @parent *ngIf="exp" class="parent1" #parent> - <child-cmp #child @leave (@leave.start)="animateStart($event)"></child-cmp> - </div> - `, - animations: [ - trigger( - 'leave', - [ - transition(':leave', [animate(1000, style({color: 'gold'}))]), - ]), - trigger( - 'parent', - [ - transition(':leave', [query(':leave', animateChild())]), - ]), - ] - }) - class ParentCmp { - public exp: boolean = true; - @ViewChild('child') public childElm: any; - - public childEvent: any; - - animateStart(event: any) { - if (event.toState == 'void') { - this.childEvent = event; - } - } - } - - @Component({ - selector: 'child-cmp', - template: '...', - animations: [ - trigger( - 'child', - [ - transition(':leave', [animate(1000, style({color: 'gold'}))]), - ]), - ] - }) - class ChildCmp { - public childEvent: any; - - @HostBinding('@child') public animate = true; - - @HostListener('@child.start', ['$event']) - animateStart(event: any) { - if (event.toState == 'void') { - this.childEvent = event; - } - } - } - - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - - fixture.detectChanges(); - - const childCmp = cmp.childElm; - - cmp.exp = false; - fixture.detectChanges(); - flushMicrotasks(); - - expect(cmp.childEvent.toState).toEqual('void'); - expect(cmp.childEvent.totalTime).toEqual(1000); - expect(childCmp.childEvent.toState).toEqual('void'); - expect(childCmp.childEvent.totalTime).toEqual(1000); - })); - - it('should emulate a leave animation on a sub component\'s inner elements when a parent leave animation occurs with animateChild', - () => { - @Component({ - selector: 'ani-cmp', - template: ` - <div @myAnimation *ngIf="exp" class="parent"> - <child-cmp></child-cmp> - </div> - `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - ':leave', - [ - query('@*', animateChild()), - ]), - ]), - ] - }) - class ParentCmp { - public exp: boolean = true; - } - - @Component({ - selector: 'child-cmp', - template: ` + animations: [ + trigger( + 'myAnimation', + [ + transition( + ':leave', + [ + query('@*', animateChild()), + ]), + ]), + ] + }) + class ParentCmp { + public exp: boolean = true; + } + + @Component({ + selector: 'child-cmp', + template: ` <section> <div class="inner-div" @myChildAnimation></div> </section> `, - animations: [ - trigger( - 'myChildAnimation', - [ - transition( - ':leave', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ]), - ]), - ] - }) - class ChildCmp { - } - - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - - cmp.exp = true; - fixture.detectChanges(); - - cmp.exp = false; - fixture.detectChanges(); - - let players = getLog(); - expect(players.length).toEqual(1); - const [player] = players; - - expect(player.element.classList.contains('inner-div')).toBeTruthy(); - expect(player.keyframes).toEqual([ - {opacity: '0', offset: 0}, - {opacity: '1', offset: 1}, - ]); - }); - - it('should not cause a removal of inner @trigger DOM nodes when a parent animation occurs', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + animations: [ + trigger( + 'myChildAnimation', + [ + transition( + ':leave', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ]), + ]), + ] + }) + class ChildCmp { + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); + + cmp.exp = false; + fixture.detectChanges(); + + let players = getLog(); + expect(players.length).toEqual(1); + const [player] = players; + + expect(player.element.classList.contains('inner-div')).toBeTruthy(); + expect(player.keyframes).toEqual([ + {opacity: '0', offset: 0}, + {opacity: '1', offset: 1}, + ]); + }); + + it('should not cause a removal of inner @trigger DOM nodes when a parent animation occurs', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: ` <div @parent *ngIf="exp" class="parent"> this <div @child>child</div> </div> `, - animations: [ - trigger( - 'parent', - [ - transition( - ':leave', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ]), - ]), - trigger( - 'child', - [ - transition( - '* => something', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ]), - ]), - ] - }) - class Cmp { - public exp: boolean = true; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = true; - fixture.detectChanges(); - flushMicrotasks(); - - cmp.exp = false; - fixture.detectChanges(); - flushMicrotasks(); - - const players = getLog(); - expect(players.length).toEqual(1); - - const element = players[0] !.element; - expect(element.innerText.trim()).toMatch(/this\s+child/mg); - })); - - it('should only mark outermost *directive nodes :enter and :leave when inserts and removals occur', - () => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger( - 'anim', - [ - transition( - '* => enter', - [ - query(':enter', [animate(1000, style({color: 'red'}))]), - ]), - transition( - '* => leave', - [ - query(':leave', [animate(1000, style({color: 'blue'}))]), - ]), - ]), - ], - template: ` + animations: [ + trigger( + 'parent', + [ + transition( + ':leave', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ]), + ]), + trigger( + 'child', + [ + transition( + '* => something', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ]), + ]), + ] + }) + class Cmp { + public exp: boolean = true; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); + flushMicrotasks(); + + cmp.exp = false; + fixture.detectChanges(); + flushMicrotasks(); + + const players = getLog(); + expect(players.length).toEqual(1); + + const element = players[0]!.element; + expect(element.innerText.trim()).toMatch(/this\s+child/mg); + })); + + it('should only mark outermost *directive nodes :enter and :leave when inserts and removals occur', + () => { + @Component({ + selector: 'ani-cmp', + animations: [ + trigger( + 'anim', + [ + transition( + '* => enter', + [ + query(':enter', [animate(1000, style({color: 'red'}))]), + ]), + transition( + '* => leave', + [ + query(':leave', [animate(1000, style({color: 'blue'}))]), + ]), + ]), + ], + template: ` <section class="container" [@anim]="exp ? 'enter' : 'leave'"> <div class="a" *ngIf="exp"> <div class="b" *ngIf="exp"> @@ -2474,629 +2466,632 @@ import {HostListener} from '../../src/metadata/directives'; </div> </section> ` - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: boolean; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - const container = fixture.elementRef.nativeElement; - - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); - - let players = getLog(); - resetLog(); - expect(players.length).toEqual(2); - const [p1, p2] = players; - - expect(p1.element.classList.contains('a')).toBeTrue(); - expect(p2.element.classList.contains('d')).toBeTrue(); - - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); - - players = getLog(); - resetLog(); - expect(players.length).toEqual(2); - const [p3, p4] = players; - - expect(p3.element.classList.contains('a')).toBeTrue(); - expect(p4.element.classList.contains('d')).toBeTrue(); - }); - - it('should collect multiple root levels of :enter and :leave nodes', () => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger('pageAnimation', [ + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp!: boolean; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + const container = fixture.elementRef.nativeElement; + + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); + + let players = getLog(); + resetLog(); + expect(players.length).toEqual(2); + const [p1, p2] = players; + + expect(p1.element.classList.contains('a')).toBeTrue(); + expect(p2.element.classList.contains('d')).toBeTrue(); + + cmp.exp = false; + fixture.detectChanges(); + engine.flush(); + + players = getLog(); + resetLog(); + expect(players.length).toEqual(2); + const [p3, p4] = players; + + expect(p3.element.classList.contains('a')).toBeTrue(); + expect(p4.element.classList.contains('d')).toBeTrue(); + }); + + it('should collect multiple root levels of :enter and :leave nodes', () => { + @Component({ + selector: 'ani-cmp', + animations: [trigger( + 'pageAnimation', + [ transition(':enter', []), - transition('* => *', [ - query(':leave', [ - animate('1s', style({ opacity: 0 })) - ], { optional: true }), - query(':enter', [ - animate('1s', style({ opacity: 1 })) - ], { optional: true }) - ]) - ]) - ], - template: ` - <div [@pageAnimation]="status"> - <header> - <div *ngIf="!loading" class="title">{{ title }}</div> - <div *ngIf="loading" class="loading">loading...</div> - </header> - <section> - <div class="page"> - <div *ngIf="page1" class="page1"> - <div *ngIf="true">page 1</div> - </div> - <div *ngIf="page2" class="page2"> - <div *ngIf="true">page 2</div> - </div> - </div> - </section> - </div> - ` - }) - class Cmp { - get title() { - if (this.page1) { - return 'hello from page1'; - } - return 'greetings from page2'; - } - - page1 = false; - page2 = false; - loading = false; - - get status() { - if (this.loading) return 'loading'; - if (this.page1) return 'page1'; - if (this.page2) return 'page2'; - return ''; - } - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.loading = true; - fixture.detectChanges(); - engine.flush(); - - let players = getLog(); - resetLog(); - cancelAllPlayers(players); - - cmp.page1 = true; - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); - - let p1: MockAnimationPlayer; - let p2: MockAnimationPlayer; - let p3: MockAnimationPlayer; - - players = getLog(); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; - - expect(p1.element.classList.contains('loading')).toBe(true); - expect(p2.element.classList.contains('title')).toBe(true); - expect(p3.element.classList.contains('page1')).toBe(true); - - resetLog(); - cancelAllPlayers(players); - - cmp.page1 = false; - cmp.loading = true; - fixture.detectChanges(); - - players = getLog(); - cancelAllPlayers(players); - - expect(players.length).toEqual(3); - [p1, p2, p3] = players; - - expect(p1.element.classList.contains('title')).toBe(true); - expect(p2.element.classList.contains('page1')).toBe(true); - expect(p3.element.classList.contains('loading')).toBe(true); - - resetLog(); - cancelAllPlayers(players); - - cmp.page2 = true; - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); - - players = getLog(); - expect(players.length).toEqual(3); - [p1, p2, p3] = players; - - expect(p1.element.classList.contains('loading')).toBe(true); - expect(p2.element.classList.contains('title')).toBe(true); - expect(p3.element.classList.contains('page2')).toBe(true); - }); - - it('should emulate leave animation callbacks for all sub elements that have leave triggers within the component', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger('parent', []), trigger('child', []), - trigger( - 'childWithAnimation', - [ - transition( - ':leave', - [ - animate(1000, style({background: 'red'})), - ]), - ]) - ], - template: ` - <div data-name="p" class="parent" @parent *ngIf="exp" (@parent.start)="callback($event)" (@parent.done)="callback($event)"> - <div data-name="c1" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div> - <div data-name="c2" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div> - <div data-name="c3" @childWithAnimation (@childWithAnimation.start)="callback($event)" (@childWithAnimation.done)="callback($event)"></div> - </div> - ` - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: boolean; - public log: string[] = []; - callback(event: any) { - this.log.push(event.element.getAttribute('data-name') + '-' + event.phaseName); - } - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = true; - fixture.detectChanges(); - flushMicrotasks(); - cmp.log = []; - - cmp.exp = false; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.log).toEqual([ - 'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done', - 'p-done' - ]); - })); - - it('should build, but not run sub triggers when a parent animation is scheduled', () => { - @Component({ - selector: 'parent-cmp', - animations: - [trigger('parent', [transition('* => *', [animate(1000, style({opacity: 0}))])])], - template: '<div [@parent]="exp"><child-cmp #child></child-cmp></div>' - }) - class ParentCmp { - public exp: any; - - @ViewChild('child') public childCmp: any; - } - - @Component({ - selector: 'child-cmp', - animations: - [trigger('child', [transition('* => *', [animate(1000, style({color: 'red'}))])])], - template: '<div [@child]="exp"></div>' - }) - class ChildCmp { - public exp: any; - } - - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - fixture.detectChanges(); - engine.flush(); - resetLog(); - - const cmp = fixture.componentInstance; - const childCmp = cmp.childCmp; - - cmp.exp = 1; - childCmp.exp = 1; - fixture.detectChanges(); - engine.flush(); - - // we have 2 players, but the child is not used even though - // it is created. - const players = getLog(); - expect(players.length).toEqual(2); - expect(engine.players.length).toEqual(1); - - expect((engine.players[0] as TransitionAnimationPlayer).getRealPlayer()).toBe(players[1]); - }); - - it('should fire and synchronize the start/done callbacks on sub triggers even if they are not allowed to animate within the animation', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - animations: [ - trigger( - 'parent', - [ - transition( - '* => go', - [ - style({height: '0px'}), - animate(1000, style({height: '100px'})), - ]), - ]), - ], - template: ` - <div *ngIf="!remove" - [@parent]="exp" - (@parent.start)="track($event)" - (@parent.done)="track($event)"> - <child-cmp #child></child-cmp> - </div> - ` - }) - class ParentCmp { - @ViewChild('child') public childCmp: any; - - public exp: any; - public log: string[] = []; - public remove = false; - - track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } - } - - @Component({ - selector: 'child-cmp', - animations: [ - trigger( - 'child', - [ - transition( - '* => go', - [ - style({width: '0px'}), - animate(1000, style({width: '100px'})), - ]), - ]), - ], - template: ` - <div [@child]="exp" - (@child.start)="track($event)" - (@child.done)="track($event)"></div> - ` - }) - class ChildCmp { - public exp: any; - public log: string[] = []; - track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } - } - - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - fixture.detectChanges(); - flushMicrotasks(); - - const cmp = fixture.componentInstance; - const child = cmp.childCmp; - - expect(cmp.log).toEqual(['parent-start', 'parent-done']); - expect(child.log).toEqual(['child-start', 'child-done']); - - cmp.log = []; - child.log = []; - cmp.exp = 'go'; - cmp.childCmp.exp = 'go'; - fixture.detectChanges(); - flushMicrotasks(); - - expect(cmp.log).toEqual(['parent-start']); - expect(child.log).toEqual(['child-start']); - - const players = engine.players; - expect(players.length).toEqual(1); - players[0].finish(); - - expect(cmp.log).toEqual(['parent-start', 'parent-done']); - expect(child.log).toEqual(['child-start', 'child-done']); - - cmp.log = []; - child.log = []; - cmp.remove = true; - fixture.detectChanges(); - flushMicrotasks(); - - expect(cmp.log).toEqual(['parent-start', 'parent-done']); - expect(child.log).toEqual(['child-start', 'child-done']); - })); - - it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers', - fakeAsync(() => { - @Component({ - selector: 'cmp', - animations: [ - trigger( - 'parent1', - [ - transition( - '* => go, * => go-again', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ]), - ]), - trigger( - 'parent2', - [ - transition( - '* => go, * => go-again', - [ - style({lineHeight: '0px'}), - animate('1s', style({lineHeight: '10px'})), - ]), - ]), - trigger( - 'child1', - [ - transition( - '* => go, * => go-again', - [ - style({width: '0px'}), - animate('1s', style({width: '100px'})), - ]), - ]), - trigger( - 'child2', - [ - transition( - '* => go, * => go-again', - [ - style({height: '0px'}), - animate('1s', style({height: '100px'})), - ]), - ]), - ], - template: ` - <div [@parent1]="parent1Exp" (@parent1.start)="track($event)" - [@parent2]="parent2Exp" (@parent2.start)="track($event)"> - <div [@child1]="child1Exp" (@child1.start)="track($event)" - [@child2]="child2Exp" (@child2.start)="track($event)"></div> - </div> + transition( + '* => *', + [ + query(':leave', [animate('1s', style({opacity: 0}))], {optional: true}), + query(':enter', [animate('1s', style({opacity: 1}))], {optional: true}) + ]) + ])], + template: ` + <div [@pageAnimation]="status"> + <header> + <div *ngIf="!loading" class="title">{{ title }}</div> + <div *ngIf="loading" class="loading">loading...</div> + </header> + <section> + <div class="page"> + <div *ngIf="page1" class="page1"> + <div *ngIf="true">page 1</div> + </div> + <div *ngIf="page2" class="page2"> + <div *ngIf="true">page 2</div> + </div> + </div> + </section> + </div> ` - }) - class Cmp { - public parent1Exp = ''; - public parent2Exp = ''; - public child1Exp = ''; - public child2Exp = ''; - public log: string[] = []; + }) + class Cmp { + get title() { + if (this.page1) { + return 'hello from page1'; + } + return 'greetings from page2'; + } - track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } - } + page1 = false; + page2 = false; + loading = false; - TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - fixture.detectChanges(); - flushMicrotasks(); + get status() { + if (this.loading) return 'loading'; + if (this.page1) return 'page1'; + if (this.page2) return 'page2'; + return ''; + } + } - const cmp = fixture.componentInstance; - cmp.log = []; - cmp.parent1Exp = 'go'; - cmp.parent2Exp = 'go'; - cmp.child1Exp = 'go'; - cmp.child2Exp = 'go'; - fixture.detectChanges(); - flushMicrotasks(); + TestBed.configureTestingModule({declarations: [Cmp]}); - expect(cmp.log).toEqual( - ['parent1-start', 'parent2-start', 'child1-start', 'child2-start']); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.loading = true; + fixture.detectChanges(); + engine.flush(); - cmp.parent1Exp = 'go-again'; - cmp.parent2Exp = 'go-again'; - cmp.child1Exp = 'go-again'; - cmp.child2Exp = 'go-again'; - fixture.detectChanges(); - flushMicrotasks(); - })); + let players = getLog(); + resetLog(); + cancelAllPlayers(players); - it('should stretch the starting keyframe of a child animation queries are issued by the parent', - () => { - @Component({ - selector: 'parent-cmp', - animations: [trigger( - 'parent', - [transition( - '* => *', - [animate(1000, style({color: 'red'})), query('@child', animateChild())])])], - template: '<div [@parent]="exp"><child-cmp #child></child-cmp></div>' - }) - class ParentCmp { - public exp: any; + cmp.page1 = true; + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); - @ViewChild('child') public childCmp: any; - } + let p1: MockAnimationPlayer; + let p2: MockAnimationPlayer; + let p3: MockAnimationPlayer; - @Component({ - selector: 'child-cmp', - animations: [trigger( - 'child', - [transition( - '* => *', [style({color: 'blue'}), animate(1000, style({color: 'red'}))])])], - template: '<div [@child]="exp" class="child"></div>' - }) - class ChildCmp { - public exp: any; - } + players = getLog(); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + expect(p1.element.classList.contains('loading')).toBe(true); + expect(p2.element.classList.contains('title')).toBe(true); + expect(p3.element.classList.contains('page1')).toBe(true); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - fixture.detectChanges(); - engine.flush(); - resetLog(); + resetLog(); + cancelAllPlayers(players); - const cmp = fixture.componentInstance; - const childCmp = cmp.childCmp; + cmp.page1 = false; + cmp.loading = true; + fixture.detectChanges(); - cmp.exp = 1; - childCmp.exp = 1; - fixture.detectChanges(); - engine.flush(); - - expect(engine.players.length).toEqual(1); // child player, parent cover, parent player - const groupPlayer = (engine.players[0] as TransitionAnimationPlayer) - .getRealPlayer() as AnimationGroupPlayer; - const childPlayer = groupPlayer.players.find(player => { - if (player instanceof MockAnimationPlayer) { - return matchesElement(player.element, '.child'); - } - return false; - }) as MockAnimationPlayer; + players = getLog(); + cancelAllPlayers(players); - const keyframes = childPlayer.keyframes.map(kf => { - delete kf['offset']; - return kf; - }); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - expect(keyframes.length).toEqual(3); + expect(p1.element.classList.contains('title')).toBe(true); + expect(p2.element.classList.contains('page1')).toBe(true); + expect(p3.element.classList.contains('loading')).toBe(true); - const [k1, k2, k3] = keyframes; - expect(k1).toEqual(k2); - }); + resetLog(); + cancelAllPlayers(players); - it('should allow a parent trigger to control child triggers across multiple template boundaries even if there are no animations in between', - () => { - @Component({ - selector: 'parent-cmp', - animations: [ - trigger( - 'parentAnimation', - [ - transition( - '* => go', - [ - query(':self, @grandChildAnimation', style({opacity: 0})), - animate(1000, style({opacity: 1})), - query( - '@grandChildAnimation', - [ - animate(1000, style({opacity: 1})), - animateChild(), - ]), - ]), - ]), - ], - template: '<div [@parentAnimation]="exp"><child-cmp #child></child-cmp></div>' - }) - class ParentCmp { - public exp: any; + cmp.page2 = true; + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); - @ViewChild('child') public innerCmp: any; - } + players = getLog(); + expect(players.length).toEqual(3); + [p1, p2, p3] = players; - @Component( - {selector: 'child-cmp', template: '<grandchild-cmp #grandchild></grandchild-cmp>'}) - class ChildCmp { - @ViewChild('grandchild') public innerCmp: any; - } + expect(p1.element.classList.contains('loading')).toBe(true); + expect(p2.element.classList.contains('title')).toBe(true); + expect(p3.element.classList.contains('page2')).toBe(true); + }); - @Component({ - selector: 'grandchild-cmp', - animations: [ - trigger( - 'grandChildAnimation', - [ - transition( - '* => go', - [ - style({width: '0px'}), - animate(1000, style({width: '200px'})), - ]), - ]), - ], - template: '<div [@grandChildAnimation]="exp"></div>' - }) - class GrandChildCmp { - public exp: any; + it('should emulate leave animation callbacks for all sub elements that have leave triggers within the component', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + animations: [ + trigger('parent', []), trigger('child', []), + trigger( + 'childWithAnimation', + [ + transition( + ':leave', + [ + animate(1000, style({background: 'red'})), + ]), + ]) + ], + template: ` + <div data-name="p" class="parent" @parent *ngIf="exp" (@parent.start)="callback($event)" (@parent.done)="callback($event)"> + <div data-name="c1" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div> + <div data-name="c2" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div> + <div data-name="c3" @childWithAnimation (@childWithAnimation.start)="callback($event)" (@childWithAnimation.done)="callback($event)"></div> + </div> + ` + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp!: boolean; + public log: string[] = []; + callback(event: any) { + this.log.push(event.element.getAttribute('data-name') + '-' + event.phaseName); } + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); + flushMicrotasks(); + cmp.log = []; + + cmp.exp = false; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.log).toEqual([ + 'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done', 'p-done' + ]); + })); + + it('should build, but not run sub triggers when a parent animation is scheduled', () => { + @Component({ + selector: 'parent-cmp', + animations: + [trigger('parent', [transition('* => *', [animate(1000, style({opacity: 0}))])])], + template: '<div [@parent]="exp"><child-cmp #child></child-cmp></div>' + }) + class ParentCmp { + public exp: any; + + @ViewChild('child') public childCmp: any; + } + + @Component({ + selector: 'child-cmp', + animations: + [trigger('child', [transition('* => *', [animate(1000, style({color: 'red'}))])])], + template: '<div [@child]="exp"></div>' + }) + class ChildCmp { + public exp: any; + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + fixture.detectChanges(); + engine.flush(); + resetLog(); - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp, GrandChildCmp]}); + const cmp = fixture.componentInstance; + const childCmp = cmp.childCmp; - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp = 1; + childCmp.exp = 1; + fixture.detectChanges(); + engine.flush(); - const cmp = fixture.componentInstance; - const grandChildCmp = cmp.innerCmp.innerCmp; + // we have 2 players, but the child is not used even though + // it is created. + const players = getLog(); + expect(players.length).toEqual(2); + expect(engine.players.length).toEqual(1); - cmp.exp = 'go'; - grandChildCmp.exp = 'go'; + expect((engine.players[0] as TransitionAnimationPlayer).getRealPlayer()).toBe(players[1]); + }); - fixture.detectChanges(); - engine.flush(); - const players = getLog(); - expect(players.length).toEqual(5); - const [p1, p2, p3, p4, p5] = players; + it('should fire and synchronize the start/done callbacks on sub triggers even if they are not allowed to animate within the animation', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + style({height: '0px'}), + animate(1000, style({height: '100px'})), + ]), + ]), + ], + template: ` + <div *ngIf="!remove" + [@parent]="exp" + (@parent.start)="track($event)" + (@parent.done)="track($event)"> + <child-cmp #child></child-cmp> + </div> + ` + }) + class ParentCmp { + @ViewChild('child') public childCmp: any; - expect(p5.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: .67, width: '0px'}, {offset: 1, width: '200px'} - ]); + public exp: any; + public log: string[] = []; + public remove = false; + + track(event: any) { + this.log.push(`${event.triggerName}-${event.phaseName}`); + } + } + + @Component({ + selector: 'child-cmp', + animations: [ + trigger( + 'child', + [ + transition( + '* => go', + [ + style({width: '0px'}), + animate(1000, style({width: '100px'})), + ]), + ]), + ], + template: ` + <div [@child]="exp" + (@child.start)="track($event)" + (@child.done)="track($event)"></div> + ` + }) + class ChildCmp { + public exp: any; + public log: string[] = []; + track(event: any) { + this.log.push(`${event.triggerName}-${event.phaseName}`); + } + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + fixture.detectChanges(); + flushMicrotasks(); + + const cmp = fixture.componentInstance; + const child = cmp.childCmp; + + expect(cmp.log).toEqual(['parent-start', 'parent-done']); + expect(child.log).toEqual(['child-start', 'child-done']); + + cmp.log = []; + child.log = []; + cmp.exp = 'go'; + cmp.childCmp.exp = 'go'; + fixture.detectChanges(); + flushMicrotasks(); + + expect(cmp.log).toEqual(['parent-start']); + expect(child.log).toEqual(['child-start']); + + const players = engine.players; + expect(players.length).toEqual(1); + players[0].finish(); + + expect(cmp.log).toEqual(['parent-start', 'parent-done']); + expect(child.log).toEqual(['child-start', 'child-done']); + + cmp.log = []; + child.log = []; + cmp.remove = true; + fixture.detectChanges(); + flushMicrotasks(); + + expect(cmp.log).toEqual(['parent-start', 'parent-done']); + expect(child.log).toEqual(['child-start', 'child-done']); + })); + + it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers', + fakeAsync(() => { + @Component({ + selector: 'cmp', + animations: [ + trigger( + 'parent1', + [ + transition( + '* => go, * => go-again', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ]), + ]), + trigger( + 'parent2', + [ + transition( + '* => go, * => go-again', + [ + style({lineHeight: '0px'}), + animate('1s', style({lineHeight: '10px'})), + ]), + ]), + trigger( + 'child1', + [ + transition( + '* => go, * => go-again', + [ + style({width: '0px'}), + animate('1s', style({width: '100px'})), + ]), + ]), + trigger( + 'child2', + [ + transition( + '* => go, * => go-again', + [ + style({height: '0px'}), + animate('1s', style({height: '100px'})), + ]), + ]), + ], + template: ` + <div [@parent1]="parent1Exp" (@parent1.start)="track($event)" + [@parent2]="parent2Exp" (@parent2.start)="track($event)"> + <div [@child1]="child1Exp" (@child1.start)="track($event)" + [@child2]="child2Exp" (@child2.start)="track($event)"></div> + </div> + ` + }) + class Cmp { + public parent1Exp = ''; + public parent2Exp = ''; + public child1Exp = ''; + public child2Exp = ''; + public log: string[] = []; + + track(event: any) { + this.log.push(`${event.triggerName}-${event.phaseName}`); + } + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + flushMicrotasks(); + + const cmp = fixture.componentInstance; + cmp.log = []; + cmp.parent1Exp = 'go'; + cmp.parent2Exp = 'go'; + cmp.child1Exp = 'go'; + cmp.child2Exp = 'go'; + fixture.detectChanges(); + flushMicrotasks(); + + expect(cmp.log).toEqual( + ['parent1-start', 'parent2-start', 'child1-start', 'child2-start']); + + cmp.parent1Exp = 'go-again'; + cmp.parent2Exp = 'go-again'; + cmp.child1Exp = 'go-again'; + cmp.child2Exp = 'go-again'; + fixture.detectChanges(); + flushMicrotasks(); + })); + + it('should stretch the starting keyframe of a child animation queries are issued by the parent', + () => { + @Component({ + selector: 'parent-cmp', + animations: [trigger( + 'parent', + [transition( + '* => *', + [animate(1000, style({color: 'red'})), query('@child', animateChild())])])], + template: '<div [@parent]="exp"><child-cmp #child></child-cmp></div>' + }) + class ParentCmp { + public exp: any; + + @ViewChild('child') public childCmp: any; + } + + @Component({ + selector: 'child-cmp', + animations: [trigger( + 'child', + [transition( + '* => *', [style({color: 'blue'}), animate(1000, style({color: 'red'}))])])], + template: '<div [@child]="exp" class="child"></div>' + }) + class ChildCmp { + public exp: any; + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + fixture.detectChanges(); + engine.flush(); + resetLog(); + + const cmp = fixture.componentInstance; + const childCmp = cmp.childCmp; + + cmp.exp = 1; + childCmp.exp = 1; + fixture.detectChanges(); + engine.flush(); + + expect(engine.players.length).toEqual(1); // child player, parent cover, parent player + const groupPlayer = (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as + AnimationGroupPlayer; + const childPlayer = groupPlayer.players.find(player => { + if (player instanceof MockAnimationPlayer) { + return matchesElement(player.element, '.child'); + } + return false; + }) as MockAnimationPlayer; + + const keyframes = childPlayer.keyframes.map(kf => { + delete kf['offset']; + return kf; }); - it('should scope :enter queries between sub animations', () => { - @Component({ - selector: 'cmp', - animations: [ - trigger( - 'parent', - [ - transition(':enter', group([ - sequence([ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - query(':enter @child', animateChild()), - ])), - ]), - trigger( - 'child', - [ - transition( - ':enter', - [ - query( - ':enter .item', - [style({opacity: 0}), animate(1000, style({opacity: 1}))]), - ]), - ]), - ], - template: ` + expect(keyframes.length).toEqual(3); + + const [k1, k2, k3] = keyframes; + expect(k1).toEqual(k2); + }); + + it('should allow a parent trigger to control child triggers across multiple template boundaries even if there are no animations in between', + () => { + @Component({ + selector: 'parent-cmp', + animations: [ + trigger( + 'parentAnimation', + [ + transition( + '* => go', + [ + query(':self, @grandChildAnimation', style({opacity: 0})), + animate(1000, style({opacity: 1})), + query( + '@grandChildAnimation', + [ + animate(1000, style({opacity: 1})), + animateChild(), + ]), + ]), + ]), + ], + template: '<div [@parentAnimation]="exp"><child-cmp #child></child-cmp></div>' + }) + class ParentCmp { + public exp: any; + + @ViewChild('child') public innerCmp: any; + } + + @Component( + {selector: 'child-cmp', template: '<grandchild-cmp #grandchild></grandchild-cmp>'}) + class ChildCmp { + @ViewChild('grandchild') public innerCmp: any; + } + + @Component({ + selector: 'grandchild-cmp', + animations: [ + trigger( + 'grandChildAnimation', + [ + transition( + '* => go', + [ + style({width: '0px'}), + animate(1000, style({width: '200px'})), + ]), + ]), + ], + template: '<div [@grandChildAnimation]="exp"></div>' + }) + class GrandChildCmp { + public exp: any; + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp, GrandChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + fixture.detectChanges(); + engine.flush(); + resetLog(); + + const cmp = fixture.componentInstance; + const grandChildCmp = cmp.innerCmp.innerCmp; + + cmp.exp = 'go'; + grandChildCmp.exp = 'go'; + + fixture.detectChanges(); + engine.flush(); + const players = getLog(); + expect(players.length).toEqual(5); + const [p1, p2, p3, p4, p5] = players; + + expect(p5.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: .67, width: '0px'}, {offset: 1, width: '200px'} + ]); + }); + + it('should scope :enter queries between sub animations', () => { + @Component({ + selector: 'cmp', + animations: [ + trigger( + 'parent', + [ + transition(':enter', group([ + sequence([ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + query(':enter @child', animateChild()), + ])), + ]), + trigger( + 'child', + [ + transition( + ':enter', + [ + query( + ':enter .item', + [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + ]), + ]), + ], + template: ` <div @parent *ngIf="exp1" class="container"> <div *ngIf="exp2"> <div @child> @@ -3107,61 +3102,61 @@ import {HostListener} from '../../src/metadata/directives'; </div> </div> ` - }) - class Cmp { - public exp1: any; - public exp2: any; - public exp3: any; - } + }) + class Cmp { + public exp1: any; + public exp2: any; + public exp3: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + resetLog(); - const cmp = fixture.componentInstance; - cmp.exp1 = true; - cmp.exp2 = true; - cmp.exp3 = true; - fixture.detectChanges(); + const cmp = fixture.componentInstance; + cmp.exp1 = true; + cmp.exp2 = true; + cmp.exp3 = true; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); + const players = getLog(); + expect(players.length).toEqual(2); - const [p1, p2] = players; - expect(p1.element.classList.contains('container')).toBeTruthy(); - expect(p2.element.classList.contains('item')).toBeTruthy(); - }); + const [p1, p2] = players; + expect(p1.element.classList.contains('container')).toBeTruthy(); + expect(p2.element.classList.contains('item')).toBeTruthy(); + }); - it('should scope :leave queries between sub animations', () => { - @Component({ - selector: 'cmp', - animations: [ - trigger( - 'parent', - [ - transition(':leave', group([ - sequence([ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - query(':leave @child', animateChild()), - ])), - ]), - trigger( - 'child', - [ - transition( - ':leave', - [ - query( - ':leave .item', - [style({opacity: 0}), animate(1000, style({opacity: 1}))]), - ]), - ]), - ], - template: ` + it('should scope :leave queries between sub animations', () => { + @Component({ + selector: 'cmp', + animations: [ + trigger( + 'parent', + [ + transition(':leave', group([ + sequence([ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + query(':leave @child', animateChild()), + ])), + ]), + trigger( + 'child', + [ + transition( + ':leave', + [ + query( + ':leave .item', + [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + ]), + ]), + ], + template: ` <div @parent *ngIf="exp1" class="container"> <div *ngIf="exp2"> <div @child> @@ -3172,42 +3167,42 @@ import {HostListener} from '../../src/metadata/directives'; </div> </div> ` - }) - class Cmp { - public exp1: any; - public exp2: any; - public exp3: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp1 = true; - cmp.exp2 = true; - cmp.exp3 = true; - fixture.detectChanges(); - resetLog(); + }) + class Cmp { + public exp1: any; + public exp2: any; + public exp3: any; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp1 = true; + cmp.exp2 = true; + cmp.exp3 = true; + fixture.detectChanges(); + resetLog(); - cmp.exp1 = false; - fixture.detectChanges(); + cmp.exp1 = false; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); + const players = getLog(); + expect(players.length).toEqual(2); - const [p1, p2] = players; - expect(p1.element.classList.contains('container')).toBeTruthy(); - expect(p2.element.classList.contains('item')).toBeTruthy(); - }); + const [p1, p2] = players; + expect(p1.element.classList.contains('container')).toBeTruthy(); + expect(p2.element.classList.contains('item')).toBeTruthy(); }); + }); - describe('animation control flags', () => { - describe('[@.disabled]', () => { - it('should allow a parent animation to query and animate inner nodes that are in a disabled region', - () => { - @Component({ - selector: 'some-cmp', - template: ` + describe('animation control flags', () => { + describe('[@.disabled]', () => { + it('should allow a parent animation to query and animate inner nodes that are in a disabled region', + () => { + @Component({ + selector: 'some-cmp', + template: ` <div [@myAnimation]="exp"> <div [@.disabled]="disabledExp"> <div class="header"></div> @@ -3215,101 +3210,101 @@ import {HostListener} from '../../src/metadata/directives'; </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - query('.header', animate(750, style({opacity: 0}))), - query('.footer', animate(250, style({opacity: 0}))), - ]), - ]), - ] - }) - class Cmp { - exp: any = ''; - disableExp = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + query('.header', animate(750, style({opacity: 0}))), + query('.footer', animate(250, style({opacity: 0}))), + ]), + ]), + ] + }) + class Cmp { + exp: any = ''; + disableExp = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.disableExp = true; + fixture.detectChanges(); + resetLog(); + + cmp.exp = 'go'; + fixture.detectChanges(); + const players = getLog(); + expect(players.length).toEqual(2); + + const [p1, p2] = players; + expect(p1.duration).toEqual(750); + expect(p1.element.classList.contains('header')).toBeTrue(); + expect(p2.duration).toEqual(250); + expect(p2.element.classList.contains('footer')).toBeTrue(); + }); - TestBed.configureTestingModule({declarations: [Cmp]}); - - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.disableExp = true; - fixture.detectChanges(); - resetLog(); - - cmp.exp = 'go'; - fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); - - const [p1, p2] = players; - expect(p1.duration).toEqual(750); - expect(p1.element.classList.contains('header')).toBeTrue(); - expect(p2.duration).toEqual(250); - expect(p2.element.classList.contains('footer')).toBeTrue(); - }); - - it('should allow a parent animation to query and animate sub animations that are in a disabled region', - () => { - @Component({ - selector: 'some-cmp', - template: ` + it('should allow a parent animation to query and animate sub animations that are in a disabled region', + () => { + @Component({ + selector: 'some-cmp', + template: ` <div class="parent" [@parentAnimation]="exp"> <div [@.disabled]="disabledExp"> <div class="child" [@childAnimation]="exp"></div> </div> </div> `, - animations: [ - trigger( - 'parentAnimation', - [ - transition( - '* => go', - [ - query('@childAnimation', animateChild()), - animate(1000, style({opacity: 0})) - ]), - ]), - trigger( - 'childAnimation', - [ - transition('* => go', [animate(500, style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - exp: any = ''; - disableExp = false; - } + animations: [ + trigger( + 'parentAnimation', + [ + transition( + '* => go', + [ + query('@childAnimation', animateChild()), + animate(1000, style({opacity: 0})) + ]), + ]), + trigger( + 'childAnimation', + [ + transition('* => go', [animate(500, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + exp: any = ''; + disableExp = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.disableExp = true; - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.disableExp = true; + fixture.detectChanges(); + resetLog(); - cmp.exp = 'go'; - fixture.detectChanges(); + cmp.exp = 'go'; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); + const players = getLog(); + expect(players.length).toEqual(2); - const [p1, p2] = players; - expect(p1.duration).toEqual(500); - expect(p1.element.classList.contains('child')).toBeTrue(); - expect(p2.duration).toEqual(1000); - expect(p2.element.classList.contains('parent')).toBeTrue(); - }); - }); + const [p1, p2] = players; + expect(p1.duration).toEqual(500); + expect(p1.element.classList.contains('child')).toBeTrue(); + expect(p2.duration).toEqual(1000); + expect(p2.element.classList.contains('parent')).toBeTrue(); + }); }); }); +}); })(); function cancelAllPlayers(players: AnimationPlayer[]) { diff --git a/packages/core/test/linker/change_detection_integration_spec.ts b/packages/core/test/linker/change_detection_integration_spec.ts index ed67524610949..e9bd1f37fa0b7 100644 --- a/packages/core/test/linker/change_detection_integration_spec.ts +++ b/packages/core/test/linker/change_detection_integration_spec.ts @@ -9,7 +9,7 @@ import {ResourceLoader, UrlResolver} from '@angular/compiler'; import {MockResourceLoader} from '@angular/compiler/testing'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, DebugElement, Directive, DoCheck, EventEmitter, HostBinding, Inject, Injectable, Input, OnChanges, OnDestroy, OnInit, Output, Pipe, PipeTransform, Provider, RendererFactory2, RendererType2, SimpleChange, SimpleChanges, TemplateRef, Type, ViewChild, ViewContainerRef, WrappedValue} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; +import {ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -26,1667 +26,1697 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [ (function() { - let renderLog: RenderLog; - let directiveLog: DirectiveLog; +let renderLog: RenderLog; +let directiveLog: DirectiveLog; - function createCompFixture<T>(template: string): ComponentFixture<TestComponent>; - function createCompFixture<T>(template: string, compType: Type<T>): ComponentFixture<T>; - function createCompFixture<T>( - template: string, compType: Type<T> = <any>TestComponent): ComponentFixture<T> { - TestBed.overrideComponent(compType, {set: new Component({template})}); +function createCompFixture<T>(template: string): ComponentFixture<TestComponent>; +function createCompFixture<T>(template: string, compType: Type<T>): ComponentFixture<T>; +function createCompFixture<T>( + template: string, compType: Type<T> = <any>TestComponent): ComponentFixture<T> { + TestBed.overrideComponent(compType, {set: new Component({template})}); - initHelpers(); + initHelpers(); - return TestBed.createComponent(compType); - } - - function initHelpers(): void { - renderLog = TestBed.inject(RenderLog); - directiveLog = TestBed.inject(DirectiveLog); - patchLoggingRenderer2(TestBed.inject(RendererFactory2), renderLog); - } + return TestBed.createComponent(compType); +} - function queryDirs(el: DebugElement, dirType: Type<any>): any { - const nodes = el.queryAllNodes(By.directive(dirType)); - return nodes.map(node => node.injector.get(dirType)); - } +function initHelpers(): void { + renderLog = TestBed.inject(RenderLog); + directiveLog = TestBed.inject(DirectiveLog); + patchLoggingRenderer2(TestBed.inject(RendererFactory2), renderLog); +} - function _bindSimpleProp<T>(bindAttr: string): ComponentFixture<TestComponent>; - function _bindSimpleProp<T>(bindAttr: string, compType: Type<T>): ComponentFixture<T>; - function _bindSimpleProp<T>( - bindAttr: string, compType: Type<T> = <any>TestComponent): ComponentFixture<T> { - const template = `<div ${bindAttr}></div>`; - return createCompFixture(template, compType); - } +function queryDirs(el: DebugElement, dirType: Type<any>): any { + const nodes = el.queryAllNodes(By.directive(dirType)); + return nodes.map(node => node.injector.get(dirType)); +} - function _bindSimpleValue(expression: any): ComponentFixture<TestComponent>; - function _bindSimpleValue<T>(expression: any, compType: Type<T>): ComponentFixture<T>; - function _bindSimpleValue<T>( - expression: any, compType: Type<T> = <any>TestComponent): ComponentFixture<T> { - return _bindSimpleProp(`[id]='${expression}'`, compType); - } +function _bindSimpleProp<T>(bindAttr: string): ComponentFixture<TestComponent>; +function _bindSimpleProp<T>(bindAttr: string, compType: Type<T>): ComponentFixture<T>; +function _bindSimpleProp<T>( + bindAttr: string, compType: Type<T> = <any>TestComponent): ComponentFixture<T> { + const template = `<div ${bindAttr}></div>`; + return createCompFixture(template, compType); +} - function _bindAndCheckSimpleValue( - expression: any, compType: Type<any> = TestComponent): string[] { - const ctx = _bindSimpleValue(expression, compType); - ctx.detectChanges(false); - return renderLog.log; - } +function _bindSimpleValue(expression: any): ComponentFixture<TestComponent>; +function _bindSimpleValue<T>(expression: any, compType: Type<T>): ComponentFixture<T>; +function _bindSimpleValue<T>( + expression: any, compType: Type<T> = <any>TestComponent): ComponentFixture<T> { + return _bindSimpleProp(`[id]='${expression}'`, compType); +} - describe(`ChangeDetection`, () => { +function _bindAndCheckSimpleValue(expression: any, compType: Type<any> = TestComponent): string[] { + const ctx = _bindSimpleValue(expression, compType); + ctx.detectChanges(false); + return renderLog.log; +} - beforeEach(() => { - TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); - TestBed.configureTestingModule({ - declarations: [ - TestData, - TestDirective, - TestComponent, - AnotherComponent, - TestLocals, - CompWithRef, - WrapCompWithRef, - EmitterDirective, - PushComp, - OnDestroyDirective, - OrderCheckDirective2, - OrderCheckDirective0, - OrderCheckDirective1, - Gh9882, - Uninitialized, - Person, - PersonHolder, - PersonHolderHolder, - CountingPipe, - CountingImpurePipe, - MultiArgPipe, - PipeWithOnDestroy, - IdentityPipe, - WrappedPipe, - ], - providers: [ - RenderLog, - DirectiveLog, - ], - }); +describe(`ChangeDetection`, () => { + beforeEach(() => { + TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); + TestBed.configureTestingModule({ + declarations: [ + TestData, + TestDirective, + TestComponent, + AnotherComponent, + TestLocals, + CompWithRef, + WrapCompWithRef, + EmitterDirective, + PushComp, + OnDestroyDirective, + OrderCheckDirective2, + OrderCheckDirective0, + OrderCheckDirective1, + Gh9882, + Uninitialized, + Person, + PersonHolder, + PersonHolderHolder, + CountingPipe, + CountingImpurePipe, + MultiArgPipe, + PipeWithOnDestroy, + IdentityPipe, + WrappedPipe, + ], + providers: [ + RenderLog, + DirectiveLog, + ], }); + }); - describe('expressions', () => { - it('should support literals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']); })); - - it('should strip quotes from literals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']); })); - - it('should support newlines in literals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']); })); - - it('should support + operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']); })); - - it('should support - operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']); })); - - it('should support * operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']); })); - - it('should support / operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`id=${5.0}`]); - })); // dart exp=5.0, js exp=5 - - it('should support % operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']); })); - - it('should support == operations on identical', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']); })); - - it('should support != operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']); })); - - it('should support == operations on coerceible', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]); })); - - it('should support === operations on identical', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']); })); - - it('should support !== operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']); })); - - it('should support === operations on coerceible', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['id=false']); - })); + describe('expressions', () => { + it('should support literals', fakeAsync(() => { + expect(_bindAndCheckSimpleValue(10)).toEqual(['id=10']); + })); - it('should support true < operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']); })); + it('should strip quotes from literals', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('"str"')).toEqual(['id=str']); + })); - it('should support false < operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']); })); + it('should support newlines in literals', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('"a\n\nb"')).toEqual(['id=a\n\nb']); + })); - it('should support false > operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']); })); + it('should support + operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('10 + 2')).toEqual(['id=12']); + })); - it('should support true > operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']); })); + it('should support - operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('10 - 2')).toEqual(['id=8']); + })); - it('should support true <= operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']); })); + it('should support * operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('10 * 2')).toEqual(['id=20']); + })); - it('should support equal <= operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']); })); + it('should support / operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('10 / 2')).toEqual([`id=${5.0}`]); + })); // dart exp=5.0, js exp=5 - it('should support false <= operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']); })); + it('should support % operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('11 % 2')).toEqual(['id=1']); + })); - it('should support true >= operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']); })); + it('should support == operations on identical', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 == 1')).toEqual(['id=true']); + })); - it('should support equal >= operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']); })); + it('should support != operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 != 1')).toEqual(['id=false']); + })); - it('should support false >= operations', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']); })); + it('should support == operations on coerceible', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 == true')).toEqual([`id=true`]); + })); - it('should support true && operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('true && true')).toEqual(['id=true']); - })); + it('should support === operations on identical', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 === 1')).toEqual(['id=true']); + })); - it('should support false && operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('true && false')).toEqual(['id=false']); + it('should support !== operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 !== 1')).toEqual(['id=false']); + })); + + it('should support === operations on coerceible', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 === true')).toEqual(['id=false']); + })); + + it('should support true < operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 < 2')).toEqual(['id=true']); + })); + + it('should support false < operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('2 < 1')).toEqual(['id=false']); + })); + + it('should support false > operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 > 2')).toEqual(['id=false']); + })); + + it('should support true > operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('2 > 1')).toEqual(['id=true']); + })); + + it('should support true <= operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 <= 2')).toEqual(['id=true']); + })); + + it('should support equal <= operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('2 <= 2')).toEqual(['id=true']); + })); + + it('should support false <= operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('2 <= 1')).toEqual(['id=false']); + })); + + it('should support true >= operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('2 >= 1')).toEqual(['id=true']); + })); + + it('should support equal >= operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('2 >= 2')).toEqual(['id=true']); + })); + + it('should support false >= operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 >= 2')).toEqual(['id=false']); + })); + + it('should support true && operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('true && true')).toEqual(['id=true']); + })); + + it('should support false && operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('true && false')).toEqual(['id=false']); + })); + + it('should support true || operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('true || false')).toEqual(['id=true']); + })); + + it('should support false || operations', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('false || false')).toEqual(['id=false']); + })); + + it('should support negate', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']); + })); + + it('should support double negate', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']); + })); + + it('should support true conditionals', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']); + })); + + it('should support false conditionals', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']); + })); + + it('should support keyed access to a list item', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['id=foo']); + })); + + it('should support keyed access to a map item', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('{"foo": "bar"}["foo"]')).toEqual(['id=bar']); + })); + + it('should report all changes on the first run including uninitialized values', + fakeAsync(() => { + expect(_bindAndCheckSimpleValue('value', Uninitialized)).toEqual(['id=null']); + })); + + it('should report all changes on the first run including null values', fakeAsync(() => { + const ctx = _bindSimpleValue('a', TestData); + ctx.componentInstance.a = null; + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=null']); + })); + + it('should support simple chained property access', fakeAsync(() => { + const ctx = _bindSimpleValue('address.city', Person); + ctx.componentInstance.name = 'Victor'; + ctx.componentInstance.address = new Address('Grenoble'); + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=Grenoble']); + })); + + describe('safe navigation operator', () => { + it('should support reading properties of nulls', fakeAsync(() => { + const ctx = _bindSimpleValue('address?.city', Person); + ctx.componentInstance.address = null!; + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=null']); })); - it('should support true || operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('true || false')).toEqual(['id=true']); + it('should support calling methods on nulls', fakeAsync(() => { + const ctx = _bindSimpleValue('address?.toString()', Person); + ctx.componentInstance.address = null!; + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=null']); })); - it('should support false || operations', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('false || false')).toEqual(['id=false']); + it('should support reading properties on non nulls', fakeAsync(() => { + const ctx = _bindSimpleValue('address?.city', Person); + ctx.componentInstance.address = new Address('MTV'); + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=MTV']); })); - it('should support negate', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('!true')).toEqual(['id=false']); })); - - it('should support double negate', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('!!true')).toEqual(['id=true']); })); - - it('should support true conditionals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 < 2 ? 1 : 2')).toEqual(['id=1']); })); - - it('should support false conditionals', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('1 > 2 ? 1 : 2')).toEqual(['id=2']); })); - - it('should support keyed access to a list item', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('["foo", "bar"][0]')).toEqual(['id=foo']); + it('should support calling methods on non nulls', fakeAsync(() => { + const ctx = _bindSimpleValue('address?.toString()', Person); + ctx.componentInstance.address = new Address('MTV'); + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=MTV']); })); - it('should support keyed access to a map item', fakeAsync(() => { - expect(_bindAndCheckSimpleValue('{"foo": "bar"}["foo"]')).toEqual(['id=bar']); + it('should support short-circuting safe navigation', fakeAsync(() => { + const ctx = _bindSimpleValue('value?.address.city', PersonHolder); + ctx.componentInstance.value = null!; + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=null']); })); - it('should report all changes on the first run including uninitialized values', - fakeAsync(() => { - expect(_bindAndCheckSimpleValue('value', Uninitialized)).toEqual(['id=null']); + it('should support nested short-circuting safe navigation', fakeAsync(() => { + const ctx = _bindSimpleValue('value.value?.address.city', PersonHolderHolder); + ctx.componentInstance.value = new PersonHolder(); + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=null']); })); - it('should report all changes on the first run including null values', fakeAsync(() => { - const ctx = _bindSimpleValue('a', TestData); - ctx.componentInstance.a = null; + it('should support chained short-circuting safe navigation', fakeAsync(() => { + const ctx = _bindSimpleValue('value?.value?.address.city', PersonHolderHolder); ctx.detectChanges(false); expect(renderLog.log).toEqual(['id=null']); })); - it('should support simple chained property access', fakeAsync(() => { - const ctx = _bindSimpleValue('address.city', Person); - ctx.componentInstance.name = 'Victor'; - ctx.componentInstance.address = new Address('Grenoble'); + it('should support short-circuting array index operations', fakeAsync(() => { + const ctx = _bindSimpleValue('value?.phones[0]', PersonHolder); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=Grenoble']); + expect(renderLog.log).toEqual(['id=null']); })); - describe('safe navigation operator', () => { - it('should support reading properties of nulls', fakeAsync(() => { - const ctx = _bindSimpleValue('address?.city', Person); - ctx.componentInstance.address = null !; - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=null']); - })); - - it('should support calling methods on nulls', fakeAsync(() => { - const ctx = _bindSimpleValue('address?.toString()', Person); - ctx.componentInstance.address = null !; - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=null']); - })); - - it('should support reading properties on non nulls', fakeAsync(() => { - const ctx = _bindSimpleValue('address?.city', Person); - ctx.componentInstance.address = new Address('MTV'); - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=MTV']); - })); - - it('should support calling methods on non nulls', fakeAsync(() => { - const ctx = _bindSimpleValue('address?.toString()', Person); - ctx.componentInstance.address = new Address('MTV'); - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=MTV']); - })); - - it('should support short-circuting safe navigation', fakeAsync(() => { + it('should still throw if right-side would throw', fakeAsync(() => { + expect(() => { const ctx = _bindSimpleValue('value?.address.city', PersonHolder); - ctx.componentInstance.value = null !; - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=null']); - })); - - it('should support nested short-circuting safe navigation', fakeAsync(() => { - const ctx = _bindSimpleValue('value.value?.address.city', PersonHolderHolder); - ctx.componentInstance.value = new PersonHolder(); - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=null']); - })); - - it('should support chained short-circuting safe navigation', fakeAsync(() => { - const ctx = _bindSimpleValue('value?.value?.address.city', PersonHolderHolder); + const person = new Person(); + person.address = null!; + ctx.componentInstance.value = person; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=null']); - })); - - it('should support short-circuting array index operations', fakeAsync(() => { - const ctx = _bindSimpleValue('value?.phones[0]', PersonHolder); - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=null']); - })); - - it('should still throw if right-side would throw', fakeAsync(() => { - expect(() => { - const ctx = _bindSimpleValue('value?.address.city', PersonHolder); - const person = new Person(); - person.address = null !; - ctx.componentInstance.value = person; - ctx.detectChanges(false); - }).toThrow(); - })); - }); + }).toThrow(); + })); + }); - it('should support method calls', fakeAsync(() => { - const ctx = _bindSimpleValue('sayHi("Jim")', Person); + it('should support method calls', fakeAsync(() => { + const ctx = _bindSimpleValue('sayHi("Jim")', Person); + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=Hi, Jim']); + })); + + it('should support function calls', fakeAsync(() => { + const ctx = _bindSimpleValue('a()(99)', TestData); + ctx.componentInstance.a = () => (a: any) => a; + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=99']); + })); + + it('should support chained method calls', fakeAsync(() => { + const ctx = _bindSimpleValue('address.toString()', Person); + ctx.componentInstance.address = new Address('MTV'); + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=MTV']); + })); + + it('should support NaN', fakeAsync(() => { + const ctx = _bindSimpleValue('age', Person); + ctx.componentInstance.age = NaN; + ctx.detectChanges(false); + + expect(renderLog.log).toEqual(['id=NaN']); + renderLog.clear(); + + ctx.detectChanges(false); + expect(renderLog.log).toEqual([]); + })); + + it('should do simple watching', fakeAsync(() => { + const ctx = _bindSimpleValue('name', Person); + ctx.componentInstance.name = 'misko'; + + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=misko']); + renderLog.clear(); + + ctx.detectChanges(false); + expect(renderLog.log).toEqual([]); + renderLog.clear(); + + ctx.componentInstance.name = 'Misko'; + ctx.detectChanges(false); + expect(renderLog.log).toEqual(['id=Misko']); + })); + + it('should support literal array made of literals', fakeAsync(() => { + const ctx = _bindSimpleValue('[1, 2]'); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([[1, 2]]); + })); + + it('should support empty literal array', fakeAsync(() => { + const ctx = _bindSimpleValue('[]'); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([[]]); + })); + + it('should support literal array made of expressions', fakeAsync(() => { + const ctx = _bindSimpleValue('[1, a]', TestData); + ctx.componentInstance.a = 2; + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([[1, 2]]); + })); + + it('should not recreate literal arrays unless their content changed', fakeAsync(() => { + const ctx = _bindSimpleValue('[1, a]', TestData); + ctx.componentInstance.a = 2; + ctx.detectChanges(false); + ctx.detectChanges(false); + ctx.componentInstance.a = 3; + ctx.detectChanges(false); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([[1, 2], [1, 3]]); + })); + + it('should support literal maps made of literals', fakeAsync(() => { + const ctx = _bindSimpleValue('{z: 1}'); + ctx.detectChanges(false); + expect(renderLog.loggedValues[0]['z']).toEqual(1); + })); + + it('should support empty literal map', fakeAsync(() => { + const ctx = _bindSimpleValue('{}'); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([{}]); + })); + + it('should support literal maps made of expressions', fakeAsync(() => { + const ctx = _bindSimpleValue('{z: a}'); + ctx.componentInstance.a = 1; + ctx.detectChanges(false); + expect(renderLog.loggedValues[0]['z']).toEqual(1); + })); + + it('should not recreate literal maps unless their content changed', fakeAsync(() => { + const ctx = _bindSimpleValue('{z: a}'); + ctx.componentInstance.a = 1; + ctx.detectChanges(false); + ctx.detectChanges(false); + ctx.componentInstance.a = 2; + ctx.detectChanges(false); + ctx.detectChanges(false); + expect(renderLog.loggedValues.length).toBe(2); + expect(renderLog.loggedValues[0]['z']).toEqual(1); + expect(renderLog.loggedValues[1]['z']).toEqual(2); + })); + + + it('should ignore empty bindings', fakeAsync(() => { + const ctx = _bindSimpleProp('[id]', TestData); + ctx.componentInstance.a = 'value'; + ctx.detectChanges(false); + + expect(renderLog.log).toEqual([]); + })); + + it('should support interpolation', fakeAsync(() => { + const ctx = _bindSimpleProp('id="B{{a}}A"', TestData); + ctx.componentInstance.a = 'value'; + ctx.detectChanges(false); + + expect(renderLog.log).toEqual(['id=BvalueA']); + })); + + it('should output empty strings for null values in interpolation', fakeAsync(() => { + const ctx = _bindSimpleProp('id="B{{a}}A"', TestData); + ctx.componentInstance.a = null; + ctx.detectChanges(false); + + expect(renderLog.log).toEqual(['id=BA']); + })); + + it('should escape values in literals that indicate interpolation', fakeAsync(() => { + expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']); + })); + + it('should read locals', fakeAsync(() => { + const ctx = createCompFixture( + '<ng-template testLocals let-local="someLocal">{{local}}</ng-template>'); + ctx.detectChanges(false); + + expect(renderLog.log).toEqual(['{{someLocalValue}}']); + })); + + describe('pipes', () => { + it('should use the return value of the pipe', fakeAsync(() => { + const ctx = _bindSimpleValue('name | countingPipe', Person); + ctx.componentInstance.name = 'bob'; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=Hi, Jim']); + expect(renderLog.loggedValues).toEqual(['bob state:0']); })); - it('should support function calls', fakeAsync(() => { - const ctx = _bindSimpleValue('a()(99)', TestData); - ctx.componentInstance.a = () => (a: any) => a; + it('should support arguments in pipes', fakeAsync(() => { + const ctx = _bindSimpleValue('name | multiArgPipe:"one":address.city', Person); + ctx.componentInstance.name = 'value'; + ctx.componentInstance.address = new Address('two'); ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=99']); + expect(renderLog.loggedValues).toEqual(['value one two default']); })); - it('should support chained method calls', fakeAsync(() => { - const ctx = _bindSimpleValue('address.toString()', Person); - ctx.componentInstance.address = new Address('MTV'); + it('should associate pipes right-to-left', fakeAsync(() => { + const ctx = _bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1', Person); + ctx.componentInstance.name = 'value'; ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=MTV']); + expect(renderLog.loggedValues).toEqual(['value a b default 0 1 default']); })); - it('should support NaN', fakeAsync(() => { - const ctx = _bindSimpleValue('age', Person); - ctx.componentInstance.age = NaN; + it('should support calling pure pipes with different number of arguments', fakeAsync(() => { + const ctx = _bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1:2', Person); + ctx.componentInstance.name = 'value'; ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual(['value a b default 0 1 2']); + })); - expect(renderLog.log).toEqual(['id=NaN']); - renderLog.clear(); + it('should do nothing when no change', fakeAsync(() => { + const ctx = _bindSimpleValue('"Megatron" | identityPipe', Person); ctx.detectChanges(false); - expect(renderLog.log).toEqual([]); - })); - it('should do simple watching', fakeAsync(() => { - const ctx = _bindSimpleValue('name', Person); - ctx.componentInstance.name = 'misko'; + expect(renderLog.log).toEqual(['id=Megatron']); - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=misko']); renderLog.clear(); - ctx.detectChanges(false); - expect(renderLog.log).toEqual([]); - renderLog.clear(); - ctx.componentInstance.name = 'Misko'; - ctx.detectChanges(false); - expect(renderLog.log).toEqual(['id=Misko']); + expect(renderLog.log).toEqual([]); })); - it('should support literal array made of literals', fakeAsync(() => { - const ctx = _bindSimpleValue('[1, 2]'); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([[1, 2]]); - })); + it('should unwrap the wrapped value and force a change', fakeAsync(() => { + const ctx = _bindSimpleValue('"Megatron" | wrappedPipe', Person); - it('should support empty literal array', fakeAsync(() => { - const ctx = _bindSimpleValue('[]'); ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([[]]); - })); - it('should support literal array made of expressions', fakeAsync(() => { - const ctx = _bindSimpleValue('[1, a]', TestData); - ctx.componentInstance.a = 2; + expect(renderLog.log).toEqual(['id=Megatron']); + + renderLog.clear(); ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([[1, 2]]); + + expect(renderLog.log).toEqual(['id=Megatron']); })); - it('should not recreate literal arrays unless their content changed', fakeAsync(() => { - const ctx = _bindSimpleValue('[1, a]', TestData); - ctx.componentInstance.a = 2; - ctx.detectChanges(false); - ctx.detectChanges(false); - ctx.componentInstance.a = 3; + it('should record unwrapped values via ngOnChanges', fakeAsync(() => { + const ctx = createCompFixture( + '<div [testDirective]="\'aName\' | wrappedPipe" [a]="1" [b]="2 | wrappedPipe"></div>'); + const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0]; ctx.detectChanges(false); + dir.changes = {}; ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([[1, 2], [1, 3]]); - })); - it('should support literal maps made of literals', fakeAsync(() => { - const ctx = _bindSimpleValue('{z: 1}'); - ctx.detectChanges(false); - expect(renderLog.loggedValues[0]['z']).toEqual(1); - })); + // Note: the binding for `a` did not change and has no ValueWrapper, + // and should therefore stay unchanged. + expect(dir.changes).toEqual({ + 'name': new SimpleChange('aName', 'aName', false), + 'b': new SimpleChange(2, 2, false) + }); - it('should support empty literal map', fakeAsync(() => { - const ctx = _bindSimpleValue('{}'); ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([{}]); + expect(dir.changes).toEqual({ + 'name': new SimpleChange('aName', 'aName', false), + 'b': new SimpleChange(2, 2, false) + }); })); - it('should support literal maps made of expressions', fakeAsync(() => { - const ctx = _bindSimpleValue('{z: a}'); - ctx.componentInstance.a = 1; + it('should call pure pipes only if the arguments change', fakeAsync(() => { + const ctx = _bindSimpleValue('name | countingPipe', Person); + // change from undefined -> null + ctx.componentInstance.name = null!; ctx.detectChanges(false); - expect(renderLog.loggedValues[0]['z']).toEqual(1); - })); + expect(renderLog.loggedValues).toEqual(['null state:0']); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual(['null state:0']); - it('should not recreate literal maps unless their content changed', fakeAsync(() => { - const ctx = _bindSimpleValue('{z: a}'); - ctx.componentInstance.a = 1; + // change from null -> some value + ctx.componentInstance.name = 'bob'; ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1']); ctx.detectChanges(false); - ctx.componentInstance.a = 2; + expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1']); + + // change from some value -> some other value + ctx.componentInstance.name = 'bart'; ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1', 'bart state:2']); ctx.detectChanges(false); - expect(renderLog.loggedValues.length).toBe(2); - expect(renderLog.loggedValues[0]['z']).toEqual(1); - expect(renderLog.loggedValues[1]['z']).toEqual(2); + expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1', 'bart state:2']); })); + modifiedInIvy('Pure pipes are instantiated differently in view engine and ivy') + .it('should call pure pipes that are used multiple times only when the arguments change and share state between pipe instances', + fakeAsync(() => { + const ctx = createCompFixture( + `<div [id]="name | countingPipe"></div><div [id]="age | countingPipe"></div>` + + '<div *ngFor="let x of [1,2]" [id]="address.city | countingPipe"></div>', + Person); + ctx.componentInstance.name = 'a'; + ctx.componentInstance.age = 10; + ctx.componentInstance.address = new Address('mtv'); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([ + 'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3' + ]); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([ + 'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3' + ]); + ctx.componentInstance.age = 11; + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([ + 'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3', '11 state:4' + ]); + })); - it('should ignore empty bindings', fakeAsync(() => { - const ctx = _bindSimpleProp('[id]', TestData); - ctx.componentInstance.a = 'value'; + // this is the ivy version of the above tests - the difference is in pure pipe instantiation + // logic and binding execution order + ivyEnabled && + it('should call pure pipes that are used multiple times only when the arguments change', + fakeAsync(() => { + const ctx = createCompFixture( + `<div [id]="name | countingPipe"></div><div [id]="age | countingPipe"></div>` + + '<div *ngFor="let x of [1,2]" [id]="address.city | countingPipe"></div>', + Person); + ctx.componentInstance.name = 'a'; + ctx.componentInstance.age = 10; + ctx.componentInstance.address = new Address('mtv'); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([ + 'a state:0', '10 state:0', 'mtv state:0', 'mtv state:0' + ]); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([ + 'a state:0', '10 state:0', 'mtv state:0', 'mtv state:0' + ]); + ctx.componentInstance.age = 11; + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([ + 'a state:0', '10 state:0', 'mtv state:0', 'mtv state:0', '11 state:1' + ]); + })); + + it('should call impure pipes on each change detection run', fakeAsync(() => { + const ctx = _bindSimpleValue('name | countingImpurePipe', Person); + ctx.componentInstance.name = 'bob'; ctx.detectChanges(false); - - expect(renderLog.log).toEqual([]); - })); - - it('should support interpolation', fakeAsync(() => { - const ctx = _bindSimpleProp('id="B{{a}}A"', TestData); - ctx.componentInstance.a = 'value'; + expect(renderLog.loggedValues).toEqual(['bob state:0']); ctx.detectChanges(false); - - expect(renderLog.log).toEqual(['id=BvalueA']); + expect(renderLog.loggedValues).toEqual(['bob state:0', 'bob state:1']); })); + }); - it('should output empty strings for null values in interpolation', fakeAsync(() => { - const ctx = _bindSimpleProp('id="B{{a}}A"', TestData); - ctx.componentInstance.a = null; - ctx.detectChanges(false); + describe('event expressions', () => { + it('should support field assignments', fakeAsync(() => { + const ctx = _bindSimpleProp('(event)="b=a=$event"'); + const childEl = ctx.debugElement.children[0]; + const evt = 'EVENT'; + childEl.triggerEventHandler('event', evt); - expect(renderLog.log).toEqual(['id=BA']); + expect(ctx.componentInstance.a).toEqual(evt); + expect(ctx.componentInstance.b).toEqual(evt); })); - it('should escape values in literals that indicate interpolation', - fakeAsync(() => { expect(_bindAndCheckSimpleValue('"$"')).toEqual(['id=$']); })); - - it('should read locals', fakeAsync(() => { - const ctx = createCompFixture( - '<ng-template testLocals let-local="someLocal">{{local}}</ng-template>'); - ctx.detectChanges(false); - - expect(renderLog.log).toEqual(['{{someLocalValue}}']); + it('should support keyed assignments', fakeAsync(() => { + const ctx = _bindSimpleProp('(event)="a[0]=$event"'); + const childEl = ctx.debugElement.children[0]; + ctx.componentInstance.a = ['OLD']; + const evt = 'EVENT'; + childEl.triggerEventHandler('event', evt); + expect(ctx.componentInstance.a).toEqual([evt]); })); - describe('pipes', () => { - it('should use the return value of the pipe', fakeAsync(() => { - const ctx = _bindSimpleValue('name | countingPipe', Person); - ctx.componentInstance.name = 'bob'; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['bob state:0']); - })); - - it('should support arguments in pipes', fakeAsync(() => { - const ctx = _bindSimpleValue('name | multiArgPipe:"one":address.city', Person); - ctx.componentInstance.name = 'value'; - ctx.componentInstance.address = new Address('two'); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['value one two default']); - })); - - it('should associate pipes right-to-left', fakeAsync(() => { - const ctx = _bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1', Person); - ctx.componentInstance.name = 'value'; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['value a b default 0 1 default']); - })); - - it('should support calling pure pipes with different number of arguments', fakeAsync(() => { - const ctx = - _bindSimpleValue('name | multiArgPipe:"a":"b" | multiArgPipe:0:1:2', Person); - ctx.componentInstance.name = 'value'; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['value a b default 0 1 2']); - })); - - it('should do nothing when no change', fakeAsync(() => { - const ctx = _bindSimpleValue('"Megatron" | identityPipe', Person); - - ctx.detectChanges(false); - - expect(renderLog.log).toEqual(['id=Megatron']); - - renderLog.clear(); - ctx.detectChanges(false); - - expect(renderLog.log).toEqual([]); - })); - - it('should unwrap the wrapped value and force a change', fakeAsync(() => { - const ctx = _bindSimpleValue('"Megatron" | wrappedPipe', Person); - - ctx.detectChanges(false); - - expect(renderLog.log).toEqual(['id=Megatron']); - - renderLog.clear(); - ctx.detectChanges(false); - - expect(renderLog.log).toEqual(['id=Megatron']); - })); - - it('should record unwrapped values via ngOnChanges', fakeAsync(() => { - const ctx = createCompFixture( - '<div [testDirective]="\'aName\' | wrappedPipe" [a]="1" [b]="2 | wrappedPipe"></div>'); - const dir: TestDirective = queryDirs(ctx.debugElement, TestDirective)[0]; - ctx.detectChanges(false); - dir.changes = {}; - ctx.detectChanges(false); - - // Note: the binding for `a` did not change and has no ValueWrapper, - // and should therefore stay unchanged. - expect(dir.changes).toEqual({ - 'name': new SimpleChange('aName', 'aName', false), - 'b': new SimpleChange(2, 2, false) - }); - - ctx.detectChanges(false); - expect(dir.changes).toEqual({ - 'name': new SimpleChange('aName', 'aName', false), - 'b': new SimpleChange(2, 2, false) - }); - })); - - it('should call pure pipes only if the arguments change', fakeAsync(() => { - const ctx = _bindSimpleValue('name | countingPipe', Person); - // change from undefined -> null - ctx.componentInstance.name = null !; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['null state:0']); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['null state:0']); + it('should support chains', fakeAsync(() => { + const ctx = _bindSimpleProp('(event)="a=a+1; a=a+1;"'); + const childEl = ctx.debugElement.children[0]; + ctx.componentInstance.a = 0; + childEl.triggerEventHandler('event', 'EVENT'); + expect(ctx.componentInstance.a).toEqual(2); + })); - // change from null -> some value - ctx.componentInstance.name = 'bob'; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1']); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['null state:0', 'bob state:1']); + it('should support empty literals', fakeAsync(() => { + const ctx = _bindSimpleProp('(event)="a=[{},[]]"'); + const childEl = ctx.debugElement.children[0]; + childEl.triggerEventHandler('event', 'EVENT'); - // change from some value -> some other value - ctx.componentInstance.name = 'bart'; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'null state:0', 'bob state:1', 'bart state:2' - ]); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'null state:0', 'bob state:1', 'bart state:2' - ]); - - })); - - modifiedInIvy('Pure pipes are instantiated differently in view engine and ivy') - .it('should call pure pipes that are used multiple times only when the arguments change and share state between pipe instances', - fakeAsync(() => { - const ctx = createCompFixture( - `<div [id]="name | countingPipe"></div><div [id]="age | countingPipe"></div>` + - '<div *ngFor="let x of [1,2]" [id]="address.city | countingPipe"></div>', - Person); - ctx.componentInstance.name = 'a'; - ctx.componentInstance.age = 10; - ctx.componentInstance.address = new Address('mtv'); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3' - ]); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3' - ]); - ctx.componentInstance.age = 11; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'mtv state:0', 'mtv state:1', 'a state:2', '10 state:3', '11 state:4' - ]); - })); - - // this is the ivy version of the above tests - the difference is in pure pipe instantiation - // logic and binding execution order - ivyEnabled && - it('should call pure pipes that are used multiple times only when the arguments change', - fakeAsync(() => { - const ctx = createCompFixture( - `<div [id]="name | countingPipe"></div><div [id]="age | countingPipe"></div>` + - '<div *ngFor="let x of [1,2]" [id]="address.city | countingPipe"></div>', - Person); - ctx.componentInstance.name = 'a'; - ctx.componentInstance.age = 10; - ctx.componentInstance.address = new Address('mtv'); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'a state:0', '10 state:0', 'mtv state:0', 'mtv state:0' - ]); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'a state:0', '10 state:0', 'mtv state:0', 'mtv state:0' - ]); - ctx.componentInstance.age = 11; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([ - 'a state:0', '10 state:0', 'mtv state:0', 'mtv state:0', '11 state:1' - ]); - })); - - it('should call impure pipes on each change detection run', fakeAsync(() => { - const ctx = _bindSimpleValue('name | countingImpurePipe', Person); - ctx.componentInstance.name = 'bob'; - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['bob state:0']); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual(['bob state:0', 'bob state:1']); - })); - }); + expect(ctx.componentInstance.a).toEqual([{}, []]); + })); - describe('event expressions', () => { - it('should support field assignments', fakeAsync(() => { - const ctx = _bindSimpleProp('(event)="b=a=$event"'); - const childEl = ctx.debugElement.children[0]; - const evt = 'EVENT'; - childEl.triggerEventHandler('event', evt); - - expect(ctx.componentInstance.a).toEqual(evt); - expect(ctx.componentInstance.b).toEqual(evt); - })); - - it('should support keyed assignments', fakeAsync(() => { - const ctx = _bindSimpleProp('(event)="a[0]=$event"'); - const childEl = ctx.debugElement.children[0]; - ctx.componentInstance.a = ['OLD']; - const evt = 'EVENT'; - childEl.triggerEventHandler('event', evt); - expect(ctx.componentInstance.a).toEqual([evt]); - })); - - it('should support chains', fakeAsync(() => { - const ctx = _bindSimpleProp('(event)="a=a+1; a=a+1;"'); - const childEl = ctx.debugElement.children[0]; - ctx.componentInstance.a = 0; - childEl.triggerEventHandler('event', 'EVENT'); - expect(ctx.componentInstance.a).toEqual(2); - })); - - it('should support empty literals', fakeAsync(() => { - const ctx = _bindSimpleProp('(event)="a=[{},[]]"'); - const childEl = ctx.debugElement.children[0]; - childEl.triggerEventHandler('event', 'EVENT'); - - expect(ctx.componentInstance.a).toEqual([{}, []]); - })); - - it('should throw when trying to assign to a local', fakeAsync(() => { - expect(() => { _bindSimpleProp('(event)="$event=1"'); }) - .toThrowError(new RegExp( - 'Cannot assign value (.*) to template variable (.*). Template variables are read-only.')); - })); - - it('should support short-circuiting', fakeAsync(() => { - const ctx = _bindSimpleProp('(event)="true ? a = a + 1 : a = a + 1"'); - const childEl = ctx.debugElement.children[0]; - ctx.componentInstance.a = 0; - childEl.triggerEventHandler('event', 'EVENT'); - expect(ctx.componentInstance.a).toEqual(1); - })); - }); + it('should throw when trying to assign to a local', fakeAsync(() => { + expect(() => { + _bindSimpleProp('(event)="$event=1"'); + }) + .toThrowError(new RegExp( + 'Cannot assign value (.*) to template variable (.*). Template variables are read-only.')); + })); + it('should support short-circuiting', fakeAsync(() => { + const ctx = _bindSimpleProp('(event)="true ? a = a + 1 : a = a + 1"'); + const childEl = ctx.debugElement.children[0]; + ctx.componentInstance.a = 0; + childEl.triggerEventHandler('event', 'EVENT'); + expect(ctx.componentInstance.a).toEqual(1); + })); }); + }); - describe('RendererFactory', () => { - it('should call the begin and end methods on the renderer factory when change detection is called', - fakeAsync(() => { - const ctx = createCompFixture('<div testDirective [a]="42"></div>'); - const rf = TestBed.inject(RendererFactory2); - // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the - // optional method infer issue. - spyOn(rf as any, 'begin'); - spyOn(rf as any, 'end'); - expect(rf.begin).not.toHaveBeenCalled(); - expect(rf.end).not.toHaveBeenCalled(); + describe('RendererFactory', () => { + it('should call the begin and end methods on the renderer factory when change detection is called', + fakeAsync(() => { + const ctx = createCompFixture('<div testDirective [a]="42"></div>'); + const rf = TestBed.inject(RendererFactory2); + // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the + // optional method infer issue. + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 + spyOn(rf as any, 'begin'); + spyOn(rf as any, 'end'); + expect(rf.begin).not.toHaveBeenCalled(); + expect(rf.end).not.toHaveBeenCalled(); + + ctx.detectChanges(false); + expect(rf.begin).toHaveBeenCalled(); + expect(rf.end).toHaveBeenCalled(); + })); + }); + describe('change notification', () => { + describe('updating directives', () => { + it('should happen without invoking the renderer', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective [a]="42"></div>'); ctx.detectChanges(false); - expect(rf.begin).toHaveBeenCalled(); - expect(rf.end).toHaveBeenCalled(); + expect(renderLog.log).toEqual([]); + expect(queryDirs(ctx.debugElement, TestDirective)[0].a).toEqual(42); })); }); - describe('change notification', () => { - describe('updating directives', () => { - it('should happen without invoking the renderer', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective [a]="42"></div>'); - ctx.detectChanges(false); - expect(renderLog.log).toEqual([]); - expect(queryDirs(ctx.debugElement, TestDirective)[0].a).toEqual(42); - })); - }); - - describe('reading directives', () => { - it('should read directive properties', fakeAsync(() => { - const ctx = createCompFixture( - '<div testDirective [a]="42" ref-dir="testDirective" [id]="dir.a"></div>'); - ctx.detectChanges(false); - expect(renderLog.loggedValues).toEqual([42]); - })); - }); - - describe('ngOnChanges', () => { - it('should notify the directive when a group of records changes', fakeAsync(() => { - const ctx = createCompFixture( - '<div [testDirective]="\'aName\'" [a]="1" [b]="2"></div><div [testDirective]="\'bName\'" [a]="4"></div>'); - ctx.detectChanges(false); - - const dirs = <TestDirective[]>queryDirs(ctx.debugElement, TestDirective); - expect(dirs[0].changes).toEqual({ - 'a': new SimpleChange(undefined, 1, true), - 'b': new SimpleChange(undefined, 2, true), - 'name': new SimpleChange(undefined, 'aName', true) - }); - expect(dirs[1].changes).toEqual({ - 'a': new SimpleChange(undefined, 4, true), - 'name': new SimpleChange(undefined, 'bName', true) - }); - })); - }); + describe('reading directives', () => { + it('should read directive properties', fakeAsync(() => { + const ctx = createCompFixture( + '<div testDirective [a]="42" ref-dir="testDirective" [id]="dir.a"></div>'); + ctx.detectChanges(false); + expect(renderLog.loggedValues).toEqual([42]); + })); }); - describe('lifecycle', () => { - function createCompWithContentAndViewChild(): ComponentFixture<any> { - TestBed.overrideComponent(AnotherComponent, { - set: new Component({ - selector: 'other-cmp', - template: '<div testDirective="viewChild"></div>', - }) - }); - - return createCompFixture( - '<div testDirective="parent"><div *ngIf="true" testDirective="contentChild"></div><other-cmp></other-cmp></div>', - TestComponent); - } + describe('ngOnChanges', () => { + it('should notify the directive when a group of records changes', fakeAsync(() => { + const ctx = createCompFixture( + '<div [testDirective]="\'aName\'" [a]="1" [b]="2"></div><div [testDirective]="\'bName\'" [a]="4"></div>'); + ctx.detectChanges(false); - describe('ngOnInit', () => { - it('should be called after ngOnChanges', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); - expect(directiveLog.filter(['ngOnInit', 'ngOnChanges'])).toEqual([]); + const dirs = <TestDirective[]>queryDirs(ctx.debugElement, TestDirective); + expect(dirs[0].changes).toEqual({ + 'a': new SimpleChange(undefined, 1, true), + 'b': new SimpleChange(undefined, 2, true), + 'name': new SimpleChange(undefined, 'aName', true) + }); + expect(dirs[1].changes).toEqual({ + 'a': new SimpleChange(undefined, 4, true), + 'name': new SimpleChange(undefined, 'bName', true) + }); + })); + }); + }); - ctx.detectChanges(false); + describe('lifecycle', () => { + function createCompWithContentAndViewChild(): ComponentFixture<any> { + TestBed.overrideComponent(AnotherComponent, { + set: new Component({ + selector: 'other-cmp', + template: '<div testDirective="viewChild"></div>', + }) + }); - expect(directiveLog.filter(['ngOnInit', 'ngOnChanges'])).toEqual([ - 'dir.ngOnChanges', 'dir.ngOnInit' - ]); - directiveLog.clear(); + return createCompFixture( + '<div testDirective="parent"><div *ngIf="true" testDirective="contentChild"></div><other-cmp></other-cmp></div>', + TestComponent); + } - ctx.detectChanges(false); + describe('ngOnInit', () => { + it('should be called after ngOnChanges', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); + expect(directiveLog.filter(['ngOnInit', 'ngOnChanges'])).toEqual([]); - expect(directiveLog.filter(['ngOnInit'])).toEqual([]); - })); + ctx.detectChanges(false); - it('should only be called only once', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + expect(directiveLog.filter(['ngOnInit', 'ngOnChanges'])).toEqual([ + 'dir.ngOnChanges', 'dir.ngOnInit' + ]); + directiveLog.clear(); - ctx.detectChanges(false); + ctx.detectChanges(false); - expect(directiveLog.filter(['ngOnInit'])).toEqual(['dir.ngOnInit']); + expect(directiveLog.filter(['ngOnInit'])).toEqual([]); + })); - // reset directives - directiveLog.clear(); + it('should only be called only once', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - // Verify that checking should not call them. - ctx.checkNoChanges(); + ctx.detectChanges(false); - expect(directiveLog.filter(['ngOnInit'])).toEqual([]); + expect(directiveLog.filter(['ngOnInit'])).toEqual(['dir.ngOnInit']); - // re-verify that changes should not call them - ctx.detectChanges(false); + // reset directives + directiveLog.clear(); - expect(directiveLog.filter(['ngOnInit'])).toEqual([]); - })); + // Verify that checking should not call them. + ctx.checkNoChanges(); - it('should not call ngOnInit again if it throws', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir" throwOn="ngOnInit"></div>'); + expect(directiveLog.filter(['ngOnInit'])).toEqual([]); - let errored = false; - // First pass fails, but ngOnInit should be called. - try { - ctx.detectChanges(false); - } catch (e) { - expect(e.message).toBe('Boom!'); - errored = true; - } - expect(errored).toBe(true); - - expect(directiveLog.filter(['ngOnInit'])).toEqual(['dir.ngOnInit']); - directiveLog.clear(); + // re-verify that changes should not call them + ctx.detectChanges(false); - // Second change detection also fails, but this time ngOnInit should not be called. - try { - ctx.detectChanges(false); - } catch (e) { - expect(e.message).toBe('Boom!'); - throw new Error('Second detectChanges() should not have called ngOnInit.'); - } - expect(directiveLog.filter(['ngOnInit'])).toEqual([]); - })); - }); + expect(directiveLog.filter(['ngOnInit'])).toEqual([]); + })); - describe('ngDoCheck', () => { - it('should be called after ngOnInit', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + it('should not call ngOnInit again if it throws', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir" throwOn="ngOnInit"></div>'); + let errored = false; + // First pass fails, but ngOnInit should be called. + try { ctx.detectChanges(false); - expect(directiveLog.filter(['ngDoCheck', 'ngOnInit'])).toEqual([ - 'dir.ngOnInit', 'dir.ngDoCheck' - ]); - })); + } catch (e) { + expect(e.message).toBe('Boom!'); + errored = true; + } + expect(errored).toBe(true); - it('should be called on every detectChanges run, except for checkNoChanges', - fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + expect(directiveLog.filter(['ngOnInit'])).toEqual(['dir.ngOnInit']); + directiveLog.clear(); + // Second change detection also fails, but this time ngOnInit should not be called. + try { ctx.detectChanges(false); + } catch (e) { + expect(e.message).toBe('Boom!'); + throw new Error('Second detectChanges() should not have called ngOnInit.'); + } + expect(directiveLog.filter(['ngOnInit'])).toEqual([]); + })); + }); - expect(directiveLog.filter(['ngDoCheck'])).toEqual(['dir.ngDoCheck']); + describe('ngDoCheck', () => { + it('should be called after ngOnInit', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - // reset directives - directiveLog.clear(); + ctx.detectChanges(false); + expect(directiveLog.filter(['ngDoCheck', 'ngOnInit'])).toEqual([ + 'dir.ngOnInit', 'dir.ngDoCheck' + ]); + })); - // Verify that checking should not call them. - ctx.checkNoChanges(); + it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - expect(directiveLog.filter(['ngDoCheck'])).toEqual([]); + ctx.detectChanges(false); - // re-verify that changes are still detected - ctx.detectChanges(false); + expect(directiveLog.filter(['ngDoCheck'])).toEqual(['dir.ngDoCheck']); - expect(directiveLog.filter(['ngDoCheck'])).toEqual(['dir.ngDoCheck']); - })); - }); + // reset directives + directiveLog.clear(); - describe('ngAfterContentInit', () => { - it('should be called after processing the content children but before the view children', - fakeAsync(() => { - const ctx = createCompWithContentAndViewChild(); - ctx.detectChanges(false); - - expect(directiveLog.filter(['ngDoCheck', 'ngAfterContentInit'])).toEqual([ - 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterContentInit', - 'parent.ngAfterContentInit', 'viewChild.ngDoCheck', 'viewChild.ngAfterContentInit' - ]); - })); + // Verify that checking should not call them. + ctx.checkNoChanges(); - it('should only be called only once', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + expect(directiveLog.filter(['ngDoCheck'])).toEqual([]); - ctx.detectChanges(false); + // re-verify that changes are still detected + ctx.detectChanges(false); - expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([ - 'dir.ngAfterContentInit' - ]); + expect(directiveLog.filter(['ngDoCheck'])).toEqual(['dir.ngDoCheck']); + })); + }); - // reset directives - directiveLog.clear(); + describe('ngAfterContentInit', () => { + it('should be called after processing the content children but before the view children', + fakeAsync(() => { + const ctx = createCompWithContentAndViewChild(); + ctx.detectChanges(false); - // Verify that checking should not call them. - ctx.checkNoChanges(); + expect(directiveLog.filter(['ngDoCheck', 'ngAfterContentInit'])).toEqual([ + 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterContentInit', + 'parent.ngAfterContentInit', 'viewChild.ngDoCheck', 'viewChild.ngAfterContentInit' + ]); + })); - expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([]); + it('should only be called only once', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - // re-verify that changes should not call them - ctx.detectChanges(false); + ctx.detectChanges(false); - expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([]); - })); + expect(directiveLog.filter(['ngAfterContentInit'])).toEqual(['dir.ngAfterContentInit']); - it('should not call ngAfterContentInit again if it throws', fakeAsync(() => { - const ctx = - createCompFixture('<div testDirective="dir" throwOn="ngAfterContentInit"></div>'); + // reset directives + directiveLog.clear(); - let errored = false; - // First pass fails, but ngAfterContentInit should be called. - try { - ctx.detectChanges(false); - } catch (e) { - errored = true; - } - expect(errored).toBe(true); - - expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([ - 'dir.ngAfterContentInit' - ]); - directiveLog.clear(); - - // Second change detection also fails, but this time ngAfterContentInit should not be - // called. - try { - ctx.detectChanges(false); - } catch (e) { - throw new Error('Second detectChanges() should not have run detection.'); - } - expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([]); - })); - }); + // Verify that checking should not call them. + ctx.checkNoChanges(); - describe('ngAfterContentChecked', () => { - it('should be called after the content children but before the view children', - fakeAsync(() => { - const ctx = createCompWithContentAndViewChild(); + expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([]); - ctx.detectChanges(false); + // re-verify that changes should not call them + ctx.detectChanges(false); - expect(directiveLog.filter(['ngDoCheck', 'ngAfterContentChecked'])).toEqual([ - 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterContentChecked', - 'parent.ngAfterContentChecked', 'viewChild.ngDoCheck', - 'viewChild.ngAfterContentChecked' - ]); - })); + expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([]); + })); - it('should be called on every detectChanges run, except for checkNoChanges', - fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + it('should not call ngAfterContentInit again if it throws', fakeAsync(() => { + const ctx = + createCompFixture('<div testDirective="dir" throwOn="ngAfterContentInit"></div>'); + let errored = false; + // First pass fails, but ngAfterContentInit should be called. + try { ctx.detectChanges(false); + } catch (e) { + errored = true; + } + expect(errored).toBe(true); - expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([ - 'dir.ngAfterContentChecked' - ]); - - // reset directives - directiveLog.clear(); - - // Verify that checking should not call them. - ctx.checkNoChanges(); - - expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([]); + expect(directiveLog.filter(['ngAfterContentInit'])).toEqual(['dir.ngAfterContentInit']); + directiveLog.clear(); - // re-verify that changes are still detected + // Second change detection also fails, but this time ngAfterContentInit should not be + // called. + try { ctx.detectChanges(false); + } catch (e) { + throw new Error('Second detectChanges() should not have run detection.'); + } + expect(directiveLog.filter(['ngAfterContentInit'])).toEqual([]); + })); + }); - expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([ - 'dir.ngAfterContentChecked' - ]); - })); - - it('should be called in reverse order so the child is always notified before the parent', - fakeAsync(() => { - const ctx = createCompFixture( - '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); - - ctx.detectChanges(false); + describe('ngAfterContentChecked', () => { + it('should be called after the content children but before the view children', + fakeAsync(() => { + const ctx = createCompWithContentAndViewChild(); - expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([ - 'child.ngAfterContentChecked', 'parent.ngAfterContentChecked', - 'sibling.ngAfterContentChecked' - ]); - })); - }); + ctx.detectChanges(false); + expect(directiveLog.filter(['ngDoCheck', 'ngAfterContentChecked'])).toEqual([ + 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterContentChecked', + 'parent.ngAfterContentChecked', 'viewChild.ngDoCheck', + 'viewChild.ngAfterContentChecked' + ]); + })); - describe('ngAfterViewInit', () => { - it('should be called after processing the view children', fakeAsync(() => { - const ctx = createCompWithContentAndViewChild(); + it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - ctx.detectChanges(false); + ctx.detectChanges(false); - expect(directiveLog.filter(['ngDoCheck', 'ngAfterViewInit'])).toEqual([ - 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterViewInit', - 'viewChild.ngDoCheck', 'viewChild.ngAfterViewInit', 'parent.ngAfterViewInit' - ]); - })); + expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([ + 'dir.ngAfterContentChecked' + ]); - it('should only be called only once', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + // reset directives + directiveLog.clear(); - ctx.detectChanges(false); + // Verify that checking should not call them. + ctx.checkNoChanges(); - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); + expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([]); - // reset directives - directiveLog.clear(); + // re-verify that changes are still detected + ctx.detectChanges(false); - // Verify that checking should not call them. - ctx.checkNoChanges(); + expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([ + 'dir.ngAfterContentChecked' + ]); + })); - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); + it('should be called in reverse order so the child is always notified before the parent', + fakeAsync(() => { + const ctx = createCompFixture( + '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); - // re-verify that changes should not call them - ctx.detectChanges(false); + ctx.detectChanges(false); - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); - })); + expect(directiveLog.filter(['ngAfterContentChecked'])).toEqual([ + 'child.ngAfterContentChecked', 'parent.ngAfterContentChecked', + 'sibling.ngAfterContentChecked' + ]); + })); + }); - it('should not call ngAfterViewInit again if it throws', fakeAsync(() => { - const ctx = - createCompFixture('<div testDirective="dir" throwOn="ngAfterViewInit"></div>'); - let errored = false; - // First pass fails, but ngAfterViewInit should be called. - try { - ctx.detectChanges(false); - } catch (e) { - errored = true; - } - expect(errored).toBe(true); + describe('ngAfterViewInit', () => { + it('should be called after processing the view children', fakeAsync(() => { + const ctx = createCompWithContentAndViewChild(); - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); - directiveLog.clear(); + ctx.detectChanges(false); - // Second change detection also fails, but this time ngAfterViewInit should not be - // called. - try { - ctx.detectChanges(false); - } catch (e) { - throw new Error('Second detectChanges() should not have run detection.'); - } - expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); - })); - }); + expect(directiveLog.filter(['ngDoCheck', 'ngAfterViewInit'])).toEqual([ + 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterViewInit', + 'viewChild.ngDoCheck', 'viewChild.ngAfterViewInit', 'parent.ngAfterViewInit' + ]); + })); - describe('ngAfterViewChecked', () => { - it('should be called after processing the view children', fakeAsync(() => { - const ctx = createCompWithContentAndViewChild(); + it('should only be called only once', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - ctx.detectChanges(false); + ctx.detectChanges(false); - expect(directiveLog.filter(['ngDoCheck', 'ngAfterViewChecked'])).toEqual([ - 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterViewChecked', - 'viewChild.ngDoCheck', 'viewChild.ngAfterViewChecked', 'parent.ngAfterViewChecked' - ]); - })); + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); - it('should be called on every detectChanges run, except for checkNoChanges', - fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); + // reset directives + directiveLog.clear(); - ctx.detectChanges(false); + // Verify that checking should not call them. + ctx.checkNoChanges(); - expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([ - 'dir.ngAfterViewChecked' - ]); + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); - // reset directives - directiveLog.clear(); + // re-verify that changes should not call them + ctx.detectChanges(false); - // Verify that checking should not call them. - ctx.checkNoChanges(); + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); + })); - expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([]); + it('should not call ngAfterViewInit again if it throws', fakeAsync(() => { + const ctx = + createCompFixture('<div testDirective="dir" throwOn="ngAfterViewInit"></div>'); - // re-verify that changes are still detected + let errored = false; + // First pass fails, but ngAfterViewInit should be called. + try { ctx.detectChanges(false); + } catch (e) { + errored = true; + } + expect(errored).toBe(true); - expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([ - 'dir.ngAfterViewChecked' - ]); - })); - - it('should be called in reverse order so the child is always notified before the parent', - fakeAsync(() => { - const ctx = createCompFixture( - '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual(['dir.ngAfterViewInit']); + directiveLog.clear(); + // Second change detection also fails, but this time ngAfterViewInit should not be + // called. + try { ctx.detectChanges(false); + } catch (e) { + throw new Error('Second detectChanges() should not have run detection.'); + } + expect(directiveLog.filter(['ngAfterViewInit'])).toEqual([]); + })); + }); - expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([ - 'child.ngAfterViewChecked', 'parent.ngAfterViewChecked', 'sibling.ngAfterViewChecked' - ]); - })); - }); + describe('ngAfterViewChecked', () => { + it('should be called after processing the view children', fakeAsync(() => { + const ctx = createCompWithContentAndViewChild(); - describe('ngOnDestroy', () => { - it('should be called on view destruction', fakeAsync(() => { - const ctx = createCompFixture('<div testDirective="dir"></div>'); - ctx.detectChanges(false); + ctx.detectChanges(false); - ctx.destroy(); + expect(directiveLog.filter(['ngDoCheck', 'ngAfterViewChecked'])).toEqual([ + 'parent.ngDoCheck', 'contentChild.ngDoCheck', 'contentChild.ngAfterViewChecked', + 'viewChild.ngDoCheck', 'viewChild.ngAfterViewChecked', 'parent.ngAfterViewChecked' + ]); + })); - expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['dir.ngOnDestroy']); - })); + it('should be called on every detectChanges run, except for checkNoChanges', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); - it('should be called after processing the content and view children', fakeAsync(() => { - TestBed.overrideComponent(AnotherComponent, { - set: new Component( - {selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'}) - }); + ctx.detectChanges(false); - const ctx = createCompFixture( - '<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' + - '<other-cmp></other-cmp></div>', - TestComponent); + expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual(['dir.ngAfterViewChecked']); - ctx.detectChanges(false); - ctx.destroy(); + // reset directives + directiveLog.clear(); - expect(directiveLog.filter(['ngOnDestroy'])).toEqual([ - 'contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy', 'viewChild.ngOnDestroy', - 'parent.ngOnDestroy' - ]); - })); + // Verify that checking should not call them. + ctx.checkNoChanges(); - it('should be called in reverse order so the child is always notified before the parent', - fakeAsync(() => { - const ctx = createCompFixture( - '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); + expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([]); - ctx.detectChanges(false); - ctx.destroy(); + // re-verify that changes are still detected + ctx.detectChanges(false); - expect(directiveLog.filter(['ngOnDestroy'])).toEqual([ - 'child.ngOnDestroy', 'parent.ngOnDestroy', 'sibling.ngOnDestroy' - ]); - })); + expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual(['dir.ngAfterViewChecked']); + })); - it('should deliver synchronous events to parent', fakeAsync(() => { - const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>'); + it('should be called in reverse order so the child is always notified before the parent', + fakeAsync(() => { + const ctx = createCompFixture( + '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); - ctx.detectChanges(false); - ctx.destroy(); + ctx.detectChanges(false); - expect(ctx.componentInstance.a).toEqual('destroyed'); - })); + expect(directiveLog.filter(['ngAfterViewChecked'])).toEqual([ + 'child.ngAfterViewChecked', 'parent.ngAfterViewChecked', 'sibling.ngAfterViewChecked' + ]); + })); + }); + describe('ngOnDestroy', () => { + it('should be called on view destruction', fakeAsync(() => { + const ctx = createCompFixture('<div testDirective="dir"></div>'); + ctx.detectChanges(false); - it('should call ngOnDestroy on pipes', fakeAsync(() => { - const ctx = createCompFixture('{{true | pipeWithOnDestroy }}'); + ctx.destroy(); - ctx.detectChanges(false); - ctx.destroy(); + expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['dir.ngOnDestroy']); + })); - expect(directiveLog.filter(['ngOnDestroy'])).toEqual([ - 'pipeWithOnDestroy.ngOnDestroy' - ]); - })); + it('should be called after processing the content and view children', fakeAsync(() => { + TestBed.overrideComponent(AnotherComponent, { + set: new Component( + {selector: 'other-cmp', template: '<div testDirective="viewChild"></div>'}) + }); - it('should call ngOnDestroy on an injectable class', fakeAsync(() => { - TestBed.overrideDirective( - TestDirective, {set: {providers: [InjectableWithLifecycle]}}); + const ctx = createCompFixture( + '<div testDirective="parent"><div *ngFor="let x of [0,1]" testDirective="contentChild{{x}}"></div>' + + '<other-cmp></other-cmp></div>', + TestComponent); - const ctx = createCompFixture('<div testDirective="dir"></div>', TestComponent); + ctx.detectChanges(false); + ctx.destroy(); - ctx.debugElement.children[0].injector.get(InjectableWithLifecycle); - ctx.detectChanges(false); + expect(directiveLog.filter(['ngOnDestroy'])).toEqual([ + 'contentChild0.ngOnDestroy', 'contentChild1.ngOnDestroy', 'viewChild.ngOnDestroy', + 'parent.ngOnDestroy' + ]); + })); - ctx.destroy(); + it('should be called in reverse order so the child is always notified before the parent', + fakeAsync(() => { + const ctx = createCompFixture( + '<div testDirective="parent"><div testDirective="child"></div></div><div testDirective="sibling"></div>'); - // We don't care about the exact order in this test. - expect(directiveLog.filter(['ngOnDestroy']).sort()).toEqual([ - 'dir.ngOnDestroy', 'injectable.ngOnDestroy' - ]); - })); - }); - }); + ctx.detectChanges(false); + ctx.destroy(); - describe('enforce no new changes', () => { - it('should throw when a record gets changed after it has been checked', fakeAsync(() => { - @Directive({selector: '[changed]'}) - class ChangingDirective { - @Input() changed: any; - } + expect(directiveLog.filter(['ngOnDestroy'])).toEqual([ + 'child.ngOnDestroy', 'parent.ngOnDestroy', 'sibling.ngOnDestroy' + ]); + })); - TestBed.configureTestingModule({declarations: [ChangingDirective]}); + it('should deliver synchronous events to parent', fakeAsync(() => { + const ctx = createCompFixture('<div (destroy)="a=$event" onDestroyDirective></div>'); - const ctx = createCompFixture('<div [id]="a" [changed]="b"></div>', TestData); + ctx.detectChanges(false); + ctx.destroy(); - ctx.componentInstance.b = 1; - const errMsgRegExp = ivyEnabled ? - /Previous value: 'undefined'\. Current value: '1'/g : - /Previous value: 'changed: undefined'\. Current value: 'changed: 1'/g; - expect(() => ctx.checkNoChanges()).toThrowError(errMsgRegExp); + expect(ctx.componentInstance.a).toEqual('destroyed'); })); - it('should throw when a record gets changed after the first change detection pass', - fakeAsync(() => { - @Directive({selector: '[changed]'}) - class ChangingDirective { - @Input() changed: any; - } - - TestBed.configureTestingModule({declarations: [ChangingDirective]}); - - const ctx = createCompFixture('<div [id]="a" [changed]="b"></div>', TestData); + it('should call ngOnDestroy on pipes', fakeAsync(() => { + const ctx = createCompFixture('{{true | pipeWithOnDestroy }}'); - ctx.componentInstance.b = 1; - ctx.detectChanges(); + ctx.detectChanges(false); + ctx.destroy(); - ctx.componentInstance.b = 2; - const errMsgRegExp = ivyEnabled ? - /Previous value: '1'\. Current value: '2'/g : - /Previous value: 'changed: 1'\. Current value: 'changed: 2'/g; - expect(() => ctx.checkNoChanges()).toThrowError(errMsgRegExp); + expect(directiveLog.filter(['ngOnDestroy'])).toEqual(['pipeWithOnDestroy.ngOnDestroy']); })); - it('should warn when the view has been created in a cd hook', fakeAsync(() => { - const ctx = createCompFixture('<div *gh9882>{{ a }}</div>', TestData); - ctx.componentInstance.a = 1; - expect(() => ctx.detectChanges()) - .toThrowError( - /It seems like the view has been created after its parent and its children have been dirty checked/); + it('should call ngOnDestroy on an injectable class', fakeAsync(() => { + TestBed.overrideDirective(TestDirective, {set: {providers: [InjectableWithLifecycle]}}); - // subsequent change detection should run without issues - ctx.detectChanges(); - })); + const ctx = createCompFixture('<div testDirective="dir"></div>', TestComponent); - it('should not throw when two arrays are structurally the same', fakeAsync(() => { - const ctx = _bindSimpleValue('a', TestData); - ctx.componentInstance.a = ['value']; + ctx.debugElement.children[0].injector.get(InjectableWithLifecycle); ctx.detectChanges(false); - ctx.componentInstance.a = ['value']; - expect(() => ctx.checkNoChanges()).not.toThrow(); - })); - it('should not break the next run', fakeAsync(() => { - const ctx = _bindSimpleValue('a', TestData); - ctx.componentInstance.a = 'value'; - expect(() => ctx.checkNoChanges()).toThrow(); + ctx.destroy(); - ctx.detectChanges(); - expect(renderLog.loggedValues).toEqual(['value']); + // We don't care about the exact order in this test. + expect(directiveLog.filter(['ngOnDestroy']).sort()).toEqual([ + 'dir.ngOnDestroy', 'injectable.ngOnDestroy' + ]); })); + }); + }); - it('should not break the next run (view engine and ivy)', fakeAsync(() => { - const ctx = _bindSimpleValue('a', TestData); - - ctx.detectChanges(); - renderLog.clear(); + describe('enforce no new changes', () => { + it('should throw when a record gets changed after it has been checked', fakeAsync(() => { + @Directive({selector: '[changed]'}) + class ChangingDirective { + @Input() changed: any; + } + + TestBed.configureTestingModule({declarations: [ChangingDirective]}); + + const ctx = createCompFixture('<div [id]="a" [changed]="b"></div>', TestData); + + ctx.componentInstance.b = 1; + const errMsgRegExp = ivyEnabled ? + /Previous value: 'undefined'\. Current value: '1'/g : + /Previous value: 'changed: undefined'\. Current value: 'changed: 1'/g; + expect(() => ctx.checkNoChanges()).toThrowError(errMsgRegExp); + })); + + + it('should throw when a record gets changed after the first change detection pass', + fakeAsync(() => { + @Directive({selector: '[changed]'}) + class ChangingDirective { + @Input() changed: any; + } + + TestBed.configureTestingModule({declarations: [ChangingDirective]}); + + const ctx = createCompFixture('<div [id]="a" [changed]="b"></div>', TestData); + + ctx.componentInstance.b = 1; + ctx.detectChanges(); + + ctx.componentInstance.b = 2; + const errMsgRegExp = ivyEnabled ? + /Previous value: '1'\. Current value: '2'/g : + /Previous value: 'changed: 1'\. Current value: 'changed: 2'/g; + expect(() => ctx.checkNoChanges()).toThrowError(errMsgRegExp); + })); + + it('should warn when the view has been created in a cd hook', fakeAsync(() => { + const ctx = createCompFixture('<div *gh9882>{{ a }}</div>', TestData); + ctx.componentInstance.a = 1; + expect(() => ctx.detectChanges()) + .toThrowError( + /It seems like the view has been created after its parent and its children have been dirty checked/); + + // subsequent change detection should run without issues + ctx.detectChanges(); + })); + + it('should not throw when two arrays are structurally the same', fakeAsync(() => { + const ctx = _bindSimpleValue('a', TestData); + ctx.componentInstance.a = ['value']; + ctx.detectChanges(false); + ctx.componentInstance.a = ['value']; + expect(() => ctx.checkNoChanges()).not.toThrow(); + })); + + it('should not break the next run', fakeAsync(() => { + const ctx = _bindSimpleValue('a', TestData); + ctx.componentInstance.a = 'value'; + expect(() => ctx.checkNoChanges()).toThrow(); + + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual(['value']); + })); + + it('should not break the next run (view engine and ivy)', fakeAsync(() => { + const ctx = _bindSimpleValue('a', TestData); + + ctx.detectChanges(); + renderLog.clear(); + + ctx.componentInstance.a = 'value'; + expect(() => ctx.checkNoChanges()).toThrow(); + + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual(['value']); + })); + }); - ctx.componentInstance.a = 'value'; - expect(() => ctx.checkNoChanges()).toThrow(); + describe('mode', () => { + it('Detached', fakeAsync(() => { + const ctx = createCompFixture('<comp-with-ref></comp-with-ref>'); + const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; + cmp.value = 'hello'; + cmp.changeDetectorRef.detach(); - ctx.detectChanges(); - expect(renderLog.loggedValues).toEqual(['value']); - })); - }); + ctx.detectChanges(); - describe('mode', () => { - it('Detached', fakeAsync(() => { - const ctx = createCompFixture('<comp-with-ref></comp-with-ref>'); - const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; - cmp.value = 'hello'; - cmp.changeDetectorRef.detach(); + expect(renderLog.log).toEqual([]); + })); - ctx.detectChanges(); + it('Detached should disable OnPush', fakeAsync(() => { + const ctx = createCompFixture('<push-cmp [value]="value"></push-cmp>'); + ctx.componentInstance.value = 0; + ctx.detectChanges(); + renderLog.clear(); - expect(renderLog.log).toEqual([]); - })); + const cmp: CompWithRef = queryDirs(ctx.debugElement, PushComp)[0]; + cmp.changeDetectorRef.detach(); - it('Detached should disable OnPush', fakeAsync(() => { - const ctx = createCompFixture('<push-cmp [value]="value"></push-cmp>'); - ctx.componentInstance.value = 0; - ctx.detectChanges(); - renderLog.clear(); + ctx.componentInstance.value = 1; + ctx.detectChanges(); - const cmp: CompWithRef = queryDirs(ctx.debugElement, PushComp)[0]; - cmp.changeDetectorRef.detach(); + expect(renderLog.log).toEqual([]); + })); - ctx.componentInstance.value = 1; - ctx.detectChanges(); + it('Detached view can be checked locally', fakeAsync(() => { + const ctx = createCompFixture('<wrap-comp-with-ref></wrap-comp-with-ref>'); + const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; + cmp.value = 'hello'; + cmp.changeDetectorRef.detach(); + expect(renderLog.log).toEqual([]); - expect(renderLog.log).toEqual([]); - })); + ctx.detectChanges(); - it('Detached view can be checked locally', fakeAsync(() => { - const ctx = createCompFixture('<wrap-comp-with-ref></wrap-comp-with-ref>'); - const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; - cmp.value = 'hello'; - cmp.changeDetectorRef.detach(); - expect(renderLog.log).toEqual([]); + expect(renderLog.log).toEqual([]); - ctx.detectChanges(); + cmp.changeDetectorRef.detectChanges(); - expect(renderLog.log).toEqual([]); + expect(renderLog.log).toEqual(['{{hello}}']); + })); - cmp.changeDetectorRef.detectChanges(); - expect(renderLog.log).toEqual(['{{hello}}']); - })); + it('Reattaches', fakeAsync(() => { + const ctx = createCompFixture('<comp-with-ref></comp-with-ref>'); + const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; + cmp.value = 'hello'; + cmp.changeDetectorRef.detach(); - it('Reattaches', fakeAsync(() => { - const ctx = createCompFixture('<comp-with-ref></comp-with-ref>'); - const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; + ctx.detectChanges(); - cmp.value = 'hello'; - cmp.changeDetectorRef.detach(); + expect(renderLog.log).toEqual([]); - ctx.detectChanges(); + cmp.changeDetectorRef.reattach(); - expect(renderLog.log).toEqual([]); + ctx.detectChanges(); - cmp.changeDetectorRef.reattach(); + expect(renderLog.log).toEqual(['{{hello}}']); + })); - ctx.detectChanges(); + it('Reattaches in the original cd mode', fakeAsync(() => { + const ctx = createCompFixture('<push-cmp></push-cmp>'); + const cmp: PushComp = queryDirs(ctx.debugElement, PushComp)[0]; + cmp.changeDetectorRef.detach(); + cmp.changeDetectorRef.reattach(); - expect(renderLog.log).toEqual(['{{hello}}']); + // renderCount should NOT be incremented with each CD as CD mode + // should be resetted to + // on-push + ctx.detectChanges(); + expect(cmp.renderCount).toBeGreaterThan(0); + const count = cmp.renderCount; - })); + ctx.detectChanges(); + expect(cmp.renderCount).toBe(count); + })); + }); - it('Reattaches in the original cd mode', fakeAsync(() => { - const ctx = createCompFixture('<push-cmp></push-cmp>'); - const cmp: PushComp = queryDirs(ctx.debugElement, PushComp)[0]; - cmp.changeDetectorRef.detach(); - cmp.changeDetectorRef.reattach(); - - // renderCount should NOT be incremented with each CD as CD mode - // should be resetted to - // on-push - ctx.detectChanges(); - expect(cmp.renderCount).toBeGreaterThan(0); - const count = cmp.renderCount; - - ctx.detectChanges(); - expect(cmp.renderCount).toBe(count); - })); + describe('multi directive order', () => { + modifiedInIvy('order of bindings to directive inputs is different in ivy') + .it('should follow the DI order for the same element', fakeAsync(() => { + const ctx = + createCompFixture('<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>'); - }); + ctx.detectChanges(false); + ctx.destroy(); - describe('multi directive order', () => { - modifiedInIvy('order of bindings to directive inputs is different in ivy') - .it('should follow the DI order for the same element', fakeAsync(() => { - const ctx = createCompFixture( - '<div orderCheck2="2" orderCheck0="0" orderCheck1="1"></div>'); + expect(directiveLog.filter(['set'])).toEqual(['0.set', '1.set', '2.set']); + })); + }); - ctx.detectChanges(false); - ctx.destroy(); + describe('nested view recursion', () => { + it('should recurse into nested components even if there are no bindings in the component view', + () => { + @Component({selector: 'nested', template: '{{name}}'}) + class Nested { + name = 'Tom'; + } + + TestBed.configureTestingModule({declarations: [Nested]}); + + const ctx = createCompFixture('<nested></nested>'); + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual(['Tom']); + }); + + it('should recurse into nested view containers even if there are no bindings in the component view', + () => { + @Component({template: '<ng-template #vc>{{name}}</ng-template>'}) + class Comp { + name = 'Tom'; + // TODO(issue/24571): remove '!'. + @ViewChild('vc', {read: ViewContainerRef, static: true}) vc!: ViewContainerRef; + // TODO(issue/24571): remove '!'. + @ViewChild(TemplateRef, {static: true}) template !: TemplateRef<any>; + } + + TestBed.configureTestingModule({declarations: [Comp]}); + initHelpers(); + + const ctx = TestBed.createComponent(Comp); + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual([]); + + ctx.componentInstance.vc.createEmbeddedView(ctx.componentInstance.template); + ctx.detectChanges(); + expect(renderLog.loggedValues).toEqual(['Tom']); + }); + + describe('projected views', () => { + let log: string[]; + + @Directive({selector: '[i]'}) + class DummyDirective { + @Input() i: any; + } - expect(directiveLog.filter(['set'])).toEqual(['0.set', '1.set', '2.set']); - })); - }); + @Component({ + selector: 'main-cmp', + template: + `<span [i]="log('start')"></span><outer-cmp><ng-template><span [i]="log('tpl')"></span></ng-template></outer-cmp>` + }) + class MainComp { + constructor(public cdRef: ChangeDetectorRef) {} + log(id: string) { + log.push(`main-${id}`); + } + } - describe('nested view recursion', () => { - it('should recurse into nested components even if there are no bindings in the component view', - () => { - @Component({selector: 'nested', template: '{{name}}'}) - class Nested { - name = 'Tom'; - } + @Component({ + selector: 'outer-cmp', + template: + `<span [i]="log('start')"></span><inner-cmp [outerTpl]="tpl"><ng-template><span [i]="log('tpl')"></span></ng-template></inner-cmp>` + }) + class OuterComp { + // TODO(issue/24571): remove '!'. + @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>; + + constructor(public cdRef: ChangeDetectorRef) {} + log(id: string) { + log.push(`outer-${id}`); + } + } - TestBed.configureTestingModule({declarations: [Nested]}); + @Component({ + selector: 'inner-cmp', + template: + `<span [i]="log('start')"></span>><ng-container [ngTemplateOutlet]="outerTpl"></ng-container><ng-container [ngTemplateOutlet]="tpl"></ng-container>` + }) + class InnerComp { + // TODO(issue/24571): remove '!'. + @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>; + + // TODO(issue/24571): remove '!'. + @Input() outerTpl!: TemplateRef<any>; + + constructor(public cdRef: ChangeDetectorRef) {} + log(id: string) { + log.push(`inner-${id}`); + } + } - const ctx = createCompFixture('<nested></nested>'); - ctx.detectChanges(); - expect(renderLog.loggedValues).toEqual(['Tom']); - }); + let ctx: ComponentFixture<MainComp>; + let mainComp: MainComp; + let outerComp: OuterComp; + let innerComp: InnerComp; + + beforeEach(() => { + log = []; + ctx = TestBed + .configureTestingModule( + {declarations: [MainComp, OuterComp, InnerComp, DummyDirective]}) + .createComponent(MainComp); + mainComp = ctx.componentInstance; + outerComp = ctx.debugElement.query(By.directive(OuterComp)).injector.get(OuterComp); + innerComp = ctx.debugElement.query(By.directive(InnerComp)).injector.get(InnerComp); + }); - it('should recurse into nested view containers even if there are no bindings in the component view', - () => { - @Component({template: '<ng-template #vc>{{name}}</ng-template>'}) - class Comp { - name = 'Tom'; - // TODO(issue/24571): remove '!'. - @ViewChild('vc', {read: ViewContainerRef, static: true}) vc !: ViewContainerRef; - // TODO(issue/24571): remove '!'. - @ViewChild(TemplateRef, {static: true}) template !: TemplateRef<any>; - } + it('should dirty check projected views in regular order', () => { + ctx.detectChanges(false); + expect(log).toEqual(['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']); - TestBed.configureTestingModule({declarations: [Comp]}); - initHelpers(); + log = []; + ctx.detectChanges(false); + expect(log).toEqual(['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']); + }); - const ctx = TestBed.createComponent(Comp); - ctx.detectChanges(); - expect(renderLog.loggedValues).toEqual([]); + it('should not dirty check projected views if neither the declaration nor the insertion place is dirty checked', + () => { + ctx.detectChanges(false); + log = []; + mainComp.cdRef.detach(); + ctx.detectChanges(false); - ctx.componentInstance.vc.createEmbeddedView(ctx.componentInstance.template); - ctx.detectChanges(); - expect(renderLog.loggedValues).toEqual(['Tom']); + expect(log).toEqual([]); }); - describe('projected views', () => { - let log: string[]; - - @Directive({selector: '[i]'}) - class DummyDirective { - @Input() - i: any; - } + it('should dirty check projected views if the insertion place is dirty checked', () => { + ctx.detectChanges(false); + log = []; - @Component({ - selector: 'main-cmp', - template: - `<span [i]="log('start')"></span><outer-cmp><ng-template><span [i]="log('tpl')"></span></ng-template></outer-cmp>` - }) - class MainComp { - constructor(public cdRef: ChangeDetectorRef) {} - log(id: string) { log.push(`main-${id}`); } - } + innerComp.cdRef.detectChanges(); + expect(log).toEqual(['inner-start', 'main-tpl', 'outer-tpl']); + }); - @Component({ - selector: 'outer-cmp', - template: - `<span [i]="log('start')"></span><inner-cmp [outerTpl]="tpl"><ng-template><span [i]="log('tpl')"></span></ng-template></inner-cmp>` - }) - class OuterComp { - // TODO(issue/24571): remove '!'. - @ContentChild(TemplateRef, {static: true}) - tpl !: TemplateRef<any>; + modifiedInIvy('Views should not be dirty checked if inserted into CD-detached view tree') + .it('should dirty check projected views if the declaration place is dirty checked', + () => { + ctx.detectChanges(false); + log = []; + innerComp.cdRef.detach(); + mainComp.cdRef.detectChanges(); - constructor(public cdRef: ChangeDetectorRef) {} - log(id: string) { log.push(`outer-${id}`); } - } + expect(log).toEqual(['main-start', 'outer-start', 'main-tpl', 'outer-tpl']); - @Component({ - selector: 'inner-cmp', - template: - `<span [i]="log('start')"></span>><ng-container [ngTemplateOutlet]="outerTpl"></ng-container><ng-container [ngTemplateOutlet]="tpl"></ng-container>` - }) - class InnerComp { - // TODO(issue/24571): remove '!'. - @ContentChild(TemplateRef, {static: true}) - tpl !: TemplateRef<any>; + log = []; + outerComp.cdRef.detectChanges(); - // TODO(issue/24571): remove '!'. - @Input() - outerTpl !: TemplateRef<any>; + expect(log).toEqual(['outer-start', 'outer-tpl']); - constructor(public cdRef: ChangeDetectorRef) {} - log(id: string) { log.push(`inner-${id}`); } - } + log = []; + outerComp.cdRef.detach(); + mainComp.cdRef.detectChanges(); - let ctx: ComponentFixture<MainComp>; - let mainComp: MainComp; - let outerComp: OuterComp; - let innerComp: InnerComp; - - beforeEach(() => { - log = []; - ctx = TestBed - .configureTestingModule( - {declarations: [MainComp, OuterComp, InnerComp, DummyDirective]}) - .createComponent(MainComp); - mainComp = ctx.componentInstance; - outerComp = ctx.debugElement.query(By.directive(OuterComp)).injector.get(OuterComp); - innerComp = ctx.debugElement.query(By.directive(InnerComp)).injector.get(InnerComp); - }); - - it('should dirty check projected views in regular order', () => { - ctx.detectChanges(false); - expect(log).toEqual( - ['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']); - - log = []; - ctx.detectChanges(false); - expect(log).toEqual( - ['main-start', 'outer-start', 'inner-start', 'main-tpl', 'outer-tpl']); - }); - - it('should not dirty check projected views if neither the declaration nor the insertion place is dirty checked', - () => { - ctx.detectChanges(false); - log = []; - mainComp.cdRef.detach(); - ctx.detectChanges(false); + expect(log).toEqual(['main-start', 'main-tpl']); + }); - expect(log).toEqual([]); - }); + onlyInIvy('Views should not be dirty checked if inserted into CD-detached view tree') + .it('should not dirty check views that are inserted into a detached tree, even if the declaration place is dirty checked', + () => { + ctx.detectChanges(false); + log = []; + innerComp.cdRef.detach(); + mainComp.cdRef.detectChanges(); - it('should dirty check projected views if the insertion place is dirty checked', () => { - ctx.detectChanges(false); - log = []; + expect(log).toEqual(['main-start', 'outer-start']); - innerComp.cdRef.detectChanges(); - expect(log).toEqual(['inner-start', 'main-tpl', 'outer-tpl']); - }); + log = []; + outerComp.cdRef.detectChanges(); - modifiedInIvy('Views should not be dirty checked if inserted into CD-detached view tree') - .it('should dirty check projected views if the declaration place is dirty checked', - () => { - ctx.detectChanges(false); - log = []; - innerComp.cdRef.detach(); - mainComp.cdRef.detectChanges(); + expect(log).toEqual(['outer-start']); - expect(log).toEqual(['main-start', 'outer-start', 'main-tpl', 'outer-tpl']); + log = []; + outerComp.cdRef.detach(); + mainComp.cdRef.detectChanges(); - log = []; - outerComp.cdRef.detectChanges(); + expect(log).toEqual(['main-start']); + }); + }); + }); - expect(log).toEqual(['outer-start', 'outer-tpl']); + describe('class binding', () => { + it('should coordinate class attribute and class host binding', () => { + @Component({template: `<div class="{{initClasses}}" someDir></div>`}) + class Comp { + initClasses = 'init'; + } - log = []; - outerComp.cdRef.detach(); - mainComp.cdRef.detectChanges(); + @Directive({selector: '[someDir]'}) + class SomeDir { + @HostBinding('class.foo') fooClass = true; + } - expect(log).toEqual(['main-start', 'main-tpl']); - }); + const ctx = + TestBed.configureTestingModule({declarations: [Comp, SomeDir]}).createComponent(Comp); - onlyInIvy('Views should not be dirty checked if inserted into CD-detached view tree') - .it('should not dirty check views that are inserted into a detached tree, even if the declaration place is dirty checked', - () => { - ctx.detectChanges(false); - log = []; - innerComp.cdRef.detach(); - mainComp.cdRef.detectChanges(); + ctx.detectChanges(); - expect(log).toEqual(['main-start', 'outer-start']); + const divEl = ctx.debugElement.children[0]; + expect(divEl.nativeElement).toHaveCssClass('init'); + expect(divEl.nativeElement).toHaveCssClass('foo'); + }); + }); - log = []; - outerComp.cdRef.detectChanges(); + describe('lifecycle asserts', () => { + let logged: string[]; - expect(log).toEqual(['outer-start']); + function log(value: string) { + logged.push(value); + } + function clearLog() { + logged = []; + } - log = []; - outerComp.cdRef.detach(); - mainComp.cdRef.detectChanges(); + function expectOnceAndOnlyOnce(log: string) { + expect(logged.indexOf(log) >= 0) + .toBeTruthy(`'${log}' not logged. Log was ${JSON.stringify(logged)}`); + expect(logged.lastIndexOf(log) === logged.indexOf(log)) + .toBeTruthy(`'${log}' logged more than once. Log was ${JSON.stringify(logged)}`); + } - expect(log).toEqual(['main-start']); - }); - }); + beforeEach(() => { + clearLog(); }); - describe('class binding', () => { - it('should coordinate class attribute and class host binding', () => { - @Component({template: `<div class="{{initClasses}}" someDir></div>`}) - class Comp { - initClasses = 'init'; - } - - @Directive({selector: '[someDir]'}) - class SomeDir { - @HostBinding('class.foo') - fooClass = true; - } - - const ctx = - TestBed.configureTestingModule({declarations: [Comp, SomeDir]}).createComponent(Comp); - - ctx.detectChanges(); + enum LifetimeMethods { + None = 0, + ngOnInit = 1 << 0, + ngOnChanges = 1 << 1, + ngAfterViewInit = 1 << 2, + ngAfterContentInit = 1 << 3, + ngDoCheck = 1 << 4, + InitMethods = ngOnInit | ngAfterViewInit | ngAfterContentInit, + InitMethodsAndChanges = InitMethods | ngOnChanges, + All = InitMethodsAndChanges | ngDoCheck, + } - const divEl = ctx.debugElement.children[0]; - expect(divEl.nativeElement).toHaveCssClass('init'); - expect(divEl.nativeElement).toHaveCssClass('foo'); - }); - }); + function forEachMethod(methods: LifetimeMethods, cb: (method: LifetimeMethods) => void) { + if (methods & LifetimeMethods.ngOnInit) cb(LifetimeMethods.ngOnInit); + if (methods & LifetimeMethods.ngOnChanges) cb(LifetimeMethods.ngOnChanges); + if (methods & LifetimeMethods.ngAfterContentInit) cb(LifetimeMethods.ngAfterContentInit); + if (methods & LifetimeMethods.ngAfterViewInit) cb(LifetimeMethods.ngAfterViewInit); + if (methods & LifetimeMethods.ngDoCheck) cb(LifetimeMethods.ngDoCheck); + } - describe('lifecycle asserts', () => { - let logged: string[]; + interface Options { + childRecursion: LifetimeMethods; + childThrows: LifetimeMethods; + } - function log(value: string) { logged.push(value); } - function clearLog() { logged = []; } + describe('calling init', () => { + function initialize(options: Options) { + @Component({selector: 'my-child', template: ''}) + class MyChild { + private thrown = LifetimeMethods.None; - function expectOnceAndOnlyOnce(log: string) { - expect(logged.indexOf(log) >= 0) - .toBeTruthy(`'${log}' not logged. Log was ${JSON.stringify(logged)}`); - expect(logged.lastIndexOf(log) === logged.indexOf(log)) - .toBeTruthy(`'${log}' logged more than once. Log was ${JSON.stringify(logged)}`); - } + // TODO(issue/24571): remove '!'. + @Input() inp!: boolean; + @Output() outp = new EventEmitter<any>(); - beforeEach(() => { clearLog(); }); - - enum LifetimeMethods { - None = 0, - ngOnInit = 1 << 0, - ngOnChanges = 1 << 1, - ngAfterViewInit = 1 << 2, - ngAfterContentInit = 1 << 3, - ngDoCheck = 1 << 4, - InitMethods = ngOnInit | ngAfterViewInit | ngAfterContentInit, - InitMethodsAndChanges = InitMethods | ngOnChanges, - All = InitMethodsAndChanges | ngDoCheck, - } + constructor() {} - function forEachMethod(methods: LifetimeMethods, cb: (method: LifetimeMethods) => void) { - if (methods & LifetimeMethods.ngOnInit) cb(LifetimeMethods.ngOnInit); - if (methods & LifetimeMethods.ngOnChanges) cb(LifetimeMethods.ngOnChanges); - if (methods & LifetimeMethods.ngAfterContentInit) cb(LifetimeMethods.ngAfterContentInit); - if (methods & LifetimeMethods.ngAfterViewInit) cb(LifetimeMethods.ngAfterViewInit); - if (methods & LifetimeMethods.ngDoCheck) cb(LifetimeMethods.ngDoCheck); - } + ngDoCheck() { + this.check(LifetimeMethods.ngDoCheck); + } + ngOnInit() { + this.check(LifetimeMethods.ngOnInit); + } + ngOnChanges() { + this.check(LifetimeMethods.ngOnChanges); + } + ngAfterViewInit() { + this.check(LifetimeMethods.ngAfterViewInit); + } + ngAfterContentInit() { + this.check(LifetimeMethods.ngAfterContentInit); + } - interface Options { - childRecursion: LifetimeMethods; - childThrows: LifetimeMethods; - } + private check(method: LifetimeMethods) { + log(`MyChild::${LifetimeMethods[method]}()`); - describe('calling init', () => { - function initialize(options: Options) { - @Component({selector: 'my-child', template: ''}) - class MyChild { - private thrown = LifetimeMethods.None; - - // TODO(issue/24571): remove '!'. - @Input() inp !: boolean; - @Output() outp = new EventEmitter<any>(); - - constructor() {} - - ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } - ngOnInit() { this.check(LifetimeMethods.ngOnInit); } - ngOnChanges() { this.check(LifetimeMethods.ngOnChanges); } - ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } - ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } - - private check(method: LifetimeMethods) { - log(`MyChild::${LifetimeMethods[method]}()`); - - if ((options.childRecursion & method) !== 0) { - if (logged.length < 20) { - this.outp.emit(null); - } else { - fail(`Unexpected MyChild::${LifetimeMethods[method]} recursion`); - } + if ((options.childRecursion & method) !== 0) { + if (logged.length < 20) { + this.outp.emit(null); + } else { + fail(`Unexpected MyChild::${LifetimeMethods[method]} recursion`); } - if ((options.childThrows & method) !== 0) { - if ((this.thrown & method) === 0) { - this.thrown |= method; - log(`<THROW from MyChild::${LifetimeMethods[method]}>()`); - throw new Error(`Throw from MyChild::${LifetimeMethods[method]}`); - } + } + if ((options.childThrows & method) !== 0) { + if ((this.thrown & method) === 0) { + this.thrown |= method; + log(`<THROW from MyChild::${LifetimeMethods[method]}>()`); + throw new Error(`Throw from MyChild::${LifetimeMethods[method]}`); } } } + } - @Component({ - selector: 'my-component', - template: `<my-child [inp]='true' (outp)='onOutp()'></my-child>` - }) - class MyComponent { - constructor(private changeDetectionRef: ChangeDetectorRef) {} - ngDoCheck() { this.check(LifetimeMethods.ngDoCheck); } - ngOnInit() { this.check(LifetimeMethods.ngOnInit); } - ngAfterViewInit() { this.check(LifetimeMethods.ngAfterViewInit); } - ngAfterContentInit() { this.check(LifetimeMethods.ngAfterContentInit); } - onOutp() { - log('<RECURSION START>'); - this.changeDetectionRef.detectChanges(); - log('<RECURSION DONE>'); - } + @Component({ + selector: 'my-component', + template: `<my-child [inp]='true' (outp)='onOutp()'></my-child>` + }) + class MyComponent { + constructor(private changeDetectionRef: ChangeDetectorRef) {} + ngDoCheck() { + this.check(LifetimeMethods.ngDoCheck); + } + ngOnInit() { + this.check(LifetimeMethods.ngOnInit); + } + ngAfterViewInit() { + this.check(LifetimeMethods.ngAfterViewInit); + } + ngAfterContentInit() { + this.check(LifetimeMethods.ngAfterContentInit); + } + onOutp() { + log('<RECURSION START>'); + this.changeDetectionRef.detectChanges(); + log('<RECURSION DONE>'); + } - private check(method: LifetimeMethods) { - log(`MyComponent::${LifetimeMethods[method]}()`); - } + private check(method: LifetimeMethods) { + log(`MyComponent::${LifetimeMethods[method]}()`); } + } - TestBed.configureTestingModule({declarations: [MyChild, MyComponent]}); + TestBed.configureTestingModule({declarations: [MyChild, MyComponent]}); - return createCompFixture(`<my-component></my-component>`); - } + return createCompFixture(`<my-component></my-component>`); + } - function ensureOneInit(options: Options) { - const ctx = initialize(options); + function ensureOneInit(options: Options) { + const ctx = initialize(options); - const throws = options.childThrows != LifetimeMethods.None; - if (throws) { - log(`<CYCLE 0 START>`); - expect(() => { - // Expect child to throw. - ctx.detectChanges(); - }).toThrow(); - log(`<CYCLE 0 END>`); - log(`<CYCLE 1 START>`); - } - ctx.detectChanges(); - if (throws) log(`<CYCLE 1 DONE>`); - expectOnceAndOnlyOnce('MyComponent::ngOnInit()'); - expectOnceAndOnlyOnce('MyChild::ngOnInit()'); - expectOnceAndOnlyOnce('MyComponent::ngAfterViewInit()'); - expectOnceAndOnlyOnce('MyComponent::ngAfterContentInit()'); - expectOnceAndOnlyOnce('MyChild::ngAfterViewInit()'); - expectOnceAndOnlyOnce('MyChild::ngAfterContentInit()'); + const throws = options.childThrows != LifetimeMethods.None; + if (throws) { + log(`<CYCLE 0 START>`); + expect(() => { + // Expect child to throw. + ctx.detectChanges(); + }).toThrow(); + log(`<CYCLE 0 END>`); + log(`<CYCLE 1 START>`); } + ctx.detectChanges(); + if (throws) log(`<CYCLE 1 DONE>`); + expectOnceAndOnlyOnce('MyComponent::ngOnInit()'); + expectOnceAndOnlyOnce('MyChild::ngOnInit()'); + expectOnceAndOnlyOnce('MyComponent::ngAfterViewInit()'); + expectOnceAndOnlyOnce('MyComponent::ngAfterContentInit()'); + expectOnceAndOnlyOnce('MyChild::ngAfterViewInit()'); + expectOnceAndOnlyOnce('MyChild::ngAfterContentInit()'); + } - forEachMethod(LifetimeMethods.InitMethodsAndChanges, method => { - it(`should ensure that init hooks are called once an only once with recursion in ${LifetimeMethods[method]} `, - () => { - // Ensure all the init methods are called once. - ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None}); - }); - }); - forEachMethod(LifetimeMethods.All, method => { - it(`should ensure that init hooks are called once an only once with a throw in ${LifetimeMethods[method]} `, - () => { - // Ensure all the init methods are called once. - // the first cycle throws but the next cycle should complete the inits. - ensureOneInit({childRecursion: LifetimeMethods.None, childThrows: method}); - }); - }); + forEachMethod(LifetimeMethods.InitMethodsAndChanges, method => { + it(`should ensure that init hooks are called once an only once with recursion in ${ + LifetimeMethods[method]} `, + () => { + // Ensure all the init methods are called once. + ensureOneInit({childRecursion: method, childThrows: LifetimeMethods.None}); + }); + }); + forEachMethod(LifetimeMethods.All, method => { + it(`should ensure that init hooks are called once an only once with a throw in ${ + LifetimeMethods[method]} `, + () => { + // Ensure all the init methods are called once. + // the first cycle throws but the next cycle should complete the inits. + ensureOneInit({childRecursion: LifetimeMethods.None, childThrows: method}); + }); }); }); }); +}); })(); @Injectable() @@ -1750,7 +1780,9 @@ class DirectiveLog { this.entries.push(new DirectiveLogEntry(directiveName, method)); } - clear() { this.entries = []; } + clear() { + this.entries = []; + } filter(methods: string[]): string[] { return this.entries.filter((entry) => methods.indexOf(entry.method) !== -1) @@ -1762,32 +1794,44 @@ class DirectiveLog { @Pipe({name: 'countingPipe'}) class CountingPipe implements PipeTransform { state: number = 0; - transform(value: any) { return `${value} state:${this.state++}`; } + transform(value: any) { + return `${value} state:${this.state++}`; + } } @Pipe({name: 'countingImpurePipe', pure: false}) class CountingImpurePipe implements PipeTransform { state: number = 0; - transform(value: any) { return `${value} state:${this.state++}`; } + transform(value: any) { + return `${value} state:${this.state++}`; + } } @Pipe({name: 'pipeWithOnDestroy'}) class PipeWithOnDestroy implements PipeTransform, OnDestroy { constructor(private directiveLog: DirectiveLog) {} - ngOnDestroy() { this.directiveLog.add('pipeWithOnDestroy', 'ngOnDestroy'); } + ngOnDestroy() { + this.directiveLog.add('pipeWithOnDestroy', 'ngOnDestroy'); + } - transform(value: any): any { return null; } + transform(value: any): any { + return null; + } } @Pipe({name: 'identityPipe'}) class IdentityPipe implements PipeTransform { - transform(value: any) { return value; } + transform(value: any) { + return value; + } } @Pipe({name: 'wrappedPipe'}) class WrappedPipe implements PipeTransform { - transform(value: any) { return WrappedValue.wrap(value); } + transform(value: any) { + return WrappedValue.wrap(value); + } } @Pipe({name: 'multiArgPipe'}) @@ -1856,30 +1900,36 @@ class Gh9882 implements AfterContentInit { constructor(private _viewContainer: ViewContainerRef, private _templateRef: TemplateRef<Object>) { } - ngAfterContentInit(): any { this._viewContainer.createEmbeddedView(this._templateRef); } + ngAfterContentInit(): any { + this._viewContainer.createEmbeddedView(this._templateRef); + } } @Directive({selector: '[testDirective]', exportAs: 'testDirective'}) class TestDirective implements OnInit, DoCheck, OnChanges, AfterContentInit, AfterContentChecked, - AfterViewInit, AfterViewChecked, OnDestroy { + AfterViewInit, AfterViewChecked, OnDestroy { @Input() a: any; @Input() b: any; // TODO(issue/24571): remove '!'. - changes !: SimpleChanges; + changes!: SimpleChanges; event: any; eventEmitter: EventEmitter<string> = new EventEmitter<string>(); // TODO(issue/24571): remove '!'. - @Input('testDirective') name !: string; + @Input('testDirective') name!: string; // TODO(issue/24571): remove '!'. - @Input() throwOn !: string; + @Input() throwOn!: string; constructor(public log: DirectiveLog) {} - onEvent(event: any) { this.event = event; } + onEvent(event: any) { + this.event = event; + } - ngDoCheck() { this.log.add(this.name, 'ngDoCheck'); } + ngDoCheck() { + this.log.add(this.name, 'ngDoCheck'); + } ngOnInit() { this.log.add(this.name, 'ngOnInit'); @@ -1937,20 +1987,24 @@ class InjectableWithLifecycle { name = 'injectable'; constructor(public log: DirectiveLog) {} - ngOnDestroy() { this.log.add(this.name, 'ngOnDestroy'); } + ngOnDestroy() { + this.log.add(this.name, 'ngOnDestroy'); + } } @Directive({selector: '[onDestroyDirective]'}) class OnDestroyDirective implements OnDestroy { @Output('destroy') emitter = new EventEmitter<string>(false); - ngOnDestroy() { this.emitter.emit('destroyed'); } + ngOnDestroy() { + this.emitter.emit('destroyed'); + } } @Directive({selector: '[orderCheck0]'}) class OrderCheckDirective0 { // TODO(issue/24571): remove '!'. - private _name !: string; + private _name!: string; @Input('orderCheck0') set name(value: string) { @@ -1964,7 +2018,7 @@ class OrderCheckDirective0 { @Directive({selector: '[orderCheck1]'}) class OrderCheckDirective1 { // TODO(issue/24571): remove '!'. - private _name !: string; + private _name!: string; @Input('orderCheck1') set name(value: string) { @@ -1978,7 +2032,7 @@ class OrderCheckDirective1 { @Directive({selector: '[orderCheck2]'}) class OrderCheckDirective2 { // TODO(issue/24571): remove '!'. - private _name !: string; + private _name!: string; @Input('orderCheck2') set name(value: string) { @@ -2003,21 +2057,25 @@ class TestLocals { @Component({selector: 'root', template: 'empty'}) class Person { // TODO(issue/24571): remove '!'. - age !: number; + age!: number; // TODO(issue/24571): remove '!'. - name !: string; + name!: string; address: Address|null = null; // TODO(issue/24571): remove '!'. - phones !: number[]; + phones!: number[]; init(name: string, address: Address|null = null) { this.name = name; this.address = address; } - sayHi(m: any): string { return `Hi, ${m}`; } + sayHi(m: any): string { + return `Hi, ${m}`; + } - passThrough(val: any): any { return val; } + passThrough(val: any): any { + return val; + } toString(): string { const address = this.address == null ? '' : ' address=' + this.address.toString(); @@ -2042,11 +2100,17 @@ class Address { return this._zipcode; } - set city(v) { this._city = v; } + set city(v) { + this._city = v; + } - set zipcode(v) { this._zipcode = v; } + set zipcode(v) { + this._zipcode = v; + } - toString(): string { return this.city || '-'; } + toString(): string { + return this.city || '-'; + } } @Component({selector: 'root', template: 'empty'}) @@ -2063,14 +2127,16 @@ class TestData { @Component({selector: 'root', template: 'empty'}) class TestDataWithGetter { // TODO(issue/24571): remove '!'. - public fn !: Function; + public fn!: Function; - get a() { return this.fn(); } + get a() { + return this.fn(); + } } class Holder<T> { // TODO(issue/24571): remove '!'. - value !: T; + value!: T; } @Component({selector: 'root', template: 'empty'}) diff --git a/packages/core/test/render3/global_utils_spec.ts b/packages/core/test/render3/global_utils_spec.ts index c3df0032c0331..a95cb61d22f5b 100644 --- a/packages/core/test/render3/global_utils_spec.ts +++ b/packages/core/test/render3/global_utils_spec.ts @@ -25,26 +25,41 @@ describe('global utils', () => { describe('publishDefaultGlobalUtils', () => { beforeEach(() => publishDefaultGlobalUtils()); - it('should publish getComponent', () => { assertPublished('getComponent', getComponent); }); + it('should publish getComponent', () => { + assertPublished('getComponent', getComponent); + }); - it('should publish getContext', () => { assertPublished('getContext', getContext); }); + it('should publish getContext', () => { + assertPublished('getContext', getContext); + }); - it('should publish getListeners', () => { assertPublished('getListeners', getListeners); }); + it('should publish getListeners', () => { + assertPublished('getListeners', getListeners); + }); - it('should publish getOwningComponent', - () => { assertPublished('getOwningComponent', getOwningComponent); }); + it('should publish getOwningComponent', () => { + assertPublished('getOwningComponent', getOwningComponent); + }); - it('should publish getRootComponents', - () => { assertPublished('getRootComponents', getRootComponents); }); + it('should publish getRootComponents', () => { + assertPublished('getRootComponents', getRootComponents); + }); - it('should publish getDirectives', () => { assertPublished('getDirectives', getDirectives); }); + it('should publish getDirectives', () => { + assertPublished('getDirectives', getDirectives); + }); - it('should publish getHostComponent', - () => { assertPublished('getHostElement', getHostElement); }); + it('should publish getHostComponent', () => { + assertPublished('getHostElement', getHostElement); + }); - it('should publish getInjector', () => { assertPublished('getInjector', getInjector); }); + it('should publish getInjector', () => { + assertPublished('getInjector', getInjector); + }); - it('should publish applyChanges', () => { assertPublished('applyChanges', applyChanges); }); + it('should publish applyChanges', () => { + assertPublished('applyChanges', applyChanges); + }); }); }); diff --git a/packages/core/test/render3/node_selector_matcher_spec.ts b/packages/core/test/render3/node_selector_matcher_spec.ts index 92abc30c09617..5565f8a867b2d 100644 --- a/packages/core/test/render3/node_selector_matcher_spec.ts +++ b/packages/core/test/render3/node_selector_matcher_spec.ts @@ -12,24 +12,21 @@ import {AttributeMarker, TAttributes, TNode, TNodeType} from '../../src/render3/ import {CssSelector, CssSelectorList, SelectorFlags} from '../../src/render3/interfaces/projection'; import {extractAttrsAndClassesFromSelector, getProjectAsAttrValue, isNodeMatchingSelector, isNodeMatchingSelectorList, stringifyCSSSelectorList} from '../../src/render3/node_selector_matcher'; -function testLStaticData(tagName: string, attrs: TAttributes | null): TNode { - return createTNode(null !, null, TNodeType.Element, 0, tagName, attrs); +function testLStaticData(tagName: string, attrs: TAttributes|null): TNode { + return createTNode(null!, null, TNodeType.Element, 0, tagName, attrs); } describe('css selector matching', () => { function isMatching( - tagName: string, attrsOrTNode: TAttributes | TNode | null, selector: CssSelector): boolean { + tagName: string, attrsOrTNode: TAttributes|TNode|null, selector: CssSelector): boolean { const tNode = (!attrsOrTNode || Array.isArray(attrsOrTNode)) ? - createTNode(null !, null, TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes) : + createTNode(null!, null, TNodeType.Element, 0, tagName, attrsOrTNode as TAttributes) : (attrsOrTNode as TNode); return isNodeMatchingSelector(tNode, selector, true); } describe('isNodeMatchingSimpleSelector', () => { - - describe('element matching', () => { - it('should match element name only if names are the same', () => { expect(isMatching('span', null, ['span'])) .toBeTruthy(`Selector 'span' should match <span>`); @@ -55,11 +52,9 @@ describe('css selector matching', () => { }); describe('attributes matching', () => { - // TODO: do we need to differentiate no value and empty value? that is: title vs. title="" ? it('should match single attribute without value', () => { - expect(isMatching('span', ['title', ''], [ '', 'title', '' ])).toBeTruthy(`Selector '[title]' should match <span title>`); @@ -81,7 +76,8 @@ describe('css selector matching', () => { ])).toBeFalsy(`Selector '[other]' should NOT match <span title="">'`); }); - // TODO: Not sure how to fix this cases. + // TODO: this case will not work, need more discussion + // https://github.com/angular/angular/pull/34625#discussion_r401791275 xit('should match namespaced attributes', () => { expect(isMatching( 'span', [AttributeMarker.NamespaceURI, 'http://some/uri', 'title', 'name'], @@ -228,7 +224,6 @@ describe('css selector matching', () => { }); describe('class matching', () => { - it('should match with a class selector when an element has multiple classes', () => { expect(isMatching('span', ['class', 'foo bar'], [ '', SelectorFlags.CLASS, 'foo' @@ -328,7 +323,6 @@ describe('css selector matching', () => { }); describe('negations', () => { - it('should match when negation part is null', () => { expect(isMatching('span', null, ['span'])).toBeTruthy(`Selector 'span' should match <span>`); }); @@ -436,13 +430,11 @@ describe('css selector matching', () => { expect(isMatching('div', ['name', 'name', 'title', '', 'class', 'foo bar'], selector)) .toBeFalsy(); }); - }); describe('isNodeMatchingSelectorList', () => { - function isAnyMatching( - tagName: string, attrs: string[] | null, selector: CssSelectorList): boolean { + tagName: string, attrs: string[]|null, selector: CssSelectorList): boolean { return isNodeMatchingSelectorList(testLStaticData(tagName, attrs), selector, false); } @@ -468,16 +460,18 @@ describe('css selector matching', () => { }); describe('reading the ngProjectAs attribute value', function() { - - function testTNode(attrs: TAttributes | null) { return testLStaticData('tag', attrs); } + function testTNode(attrs: TAttributes|null) { + return testLStaticData('tag', attrs); + } it('should get ngProjectAs value if present', function() { expect(getProjectAsAttrValue(testTNode([AttributeMarker.ProjectAs, ['tag', 'foo', 'bar']]))) .toEqual(['tag', 'foo', 'bar']); }); - it('should return null if there are no attributes', - function() { expect(getProjectAsAttrValue(testTNode(null))).toBe(null); }); + it('should return null if there are no attributes', function() { + expect(getProjectAsAttrValue(testTNode(null))).toBe(null); + }); it('should return if ngProjectAs is not present', function() { expect(getProjectAsAttrValue(testTNode(['foo', 'bar']))).toBe(null); @@ -486,15 +480,13 @@ describe('css selector matching', () => { it('should not accidentally identify ngProjectAs in attribute values', function() { expect(getProjectAsAttrValue(testTNode(['foo', AttributeMarker.ProjectAs]))).toBe(null); }); - }); - }); describe('stringifyCSSSelectorList', () => { - - it('should stringify selector with a tag name only', - () => { expect(stringifyCSSSelectorList([['button']])).toBe('button'); }); + it('should stringify selector with a tag name only', () => { + expect(stringifyCSSSelectorList([['button']])).toBe('button'); + }); it('should stringify selector with attributes', () => { expect(stringifyCSSSelectorList([['', 'id', '']])).toBe('[id]'); diff --git a/packages/elements/test/utils_spec.ts b/packages/elements/test/utils_spec.ts index fb7a0a326e198..97cc62b7a545d 100644 --- a/packages/elements/test/utils_spec.ts +++ b/packages/elements/test/utils_spec.ts @@ -17,6 +17,7 @@ describe('utils', () => { beforeEach(() => { // TODO: @JiaLiPassion, need to wait @types/jasmine to fix the wrong return // type infer issue. + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/43486 setTimeoutSpy = spyOn(window, 'setTimeout').and.returnValue(42 as any); clearTimeoutSpy = spyOn(window, 'clearTimeout'); }); @@ -83,8 +84,9 @@ describe('utils', () => { expect(camelToDashCase('foo1Bar2Baz3Qux4')).toBe('foo1-bar2-baz3-qux4'); }); - it('should keep existing dashes', - () => { expect(camelToDashCase('fooBar-baz-Qux')).toBe('foo-bar-baz--qux'); }); + it('should keep existing dashes', () => { + expect(camelToDashCase('fooBar-baz-Qux')).toBe('foo-bar-baz--qux'); + }); }); describe('createCustomEvent()', () => { @@ -99,7 +101,6 @@ describe('utils', () => { expect(event.cancelable).toBe(false); expect(event.detail).toEqual(value); }); - }); describe('isElement()', () => { @@ -131,7 +132,7 @@ describe('utils', () => { it('should return true for functions', () => { const obj = {foo: function() {}, bar: () => null, baz() {}}; const fns = [ - function(){}, + function() {}, () => null, obj.foo, obj.bar, @@ -182,7 +183,7 @@ describe('utils', () => { </ul> </div> `; - li = div.querySelector('li') !; + li = div.querySelector('li')!; }); it('should return whether the element matches the selector', () => { @@ -218,7 +219,9 @@ describe('utils', () => { ]; values.forEach((v1, i) => { - values.forEach((v2, j) => { expect(strictEquals(v1, v2)).toBe(i === j); }); + values.forEach((v2, j) => { + expect(strictEquals(v1, v2)).toBe(i === j); + }); }); }); diff --git a/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts b/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts index b16e869307e7d..a9e9ad5d7eef9 100644 --- a/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts +++ b/packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, ReflectiveInjector, forwardRef, resolveForwardRef} from '@angular/core'; +import {forwardRef, Inject, ReflectiveInjector, resolveForwardRef} from '@angular/core'; { describe('forwardRef examples', () => { @@ -26,7 +26,9 @@ import {Inject, ReflectiveInjector, forwardRef, resolveForwardRef} from '@angula // Door attempts to inject Lock, despite it not being defined yet. // forwardRef makes this possible. - constructor(@Inject(forwardRef(() => Lock)) lock: Lock) { this.lock = lock; } + constructor(@Inject(forwardRef(() => Lock)) lock: Lock) { + this.lock = lock; + } } // Only at this point Lock is defined. diff --git a/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts b/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts index e631a7c7ab344..fd0c99c35e3ce 100644 --- a/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts +++ b/packages/platform-browser/test/dom/events/hammer_gestures_spec.ts @@ -17,7 +17,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow let fakeConsole: any; if (isNode) return; - beforeEach(() => { fakeConsole = {warn: jasmine.createSpy('console.warn')}; }); + beforeEach(() => { + fakeConsole = {warn: jasmine.createSpy('console.warn')}; + }); describe('with no custom loader', () => { beforeEach(() => { @@ -61,7 +63,9 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow // Inject the NgZone so that we can make it available to the plugin through a fake // EventManager. let ngZone: NgZone; - beforeEach(inject([NgZone], (z: NgZone) => { ngZone = z; })); + beforeEach(inject([NgZone], (z: NgZone) => { + ngZone = z; + })); beforeEach(() => { originalHammerGlobal = (window as any).Hammer; @@ -84,13 +88,15 @@ import {HammerGestureConfig, HammerGesturesPlugin,} from '@angular/platform-brow plugin = new HammerGesturesPlugin(document, hammerConfig, fakeConsole, loader); // Use a fake EventManager that has access to the NgZone. - plugin.manager = { getZone: () => ngZone } as EventManager; + plugin.manager = {getZone: () => ngZone} as EventManager; someElement = document.createElement('div'); someListener = () => {}; }); - afterEach(() => { (window as any).Hammer = originalHammerGlobal; }); + afterEach(() => { + (window as any).Hammer = originalHammerGlobal; + }); it('should not log a warning when HammerJS is not loaded', () => { plugin.addEventListener(someElement, 'swipe', () => {}); diff --git a/packages/platform-browser/test/dom/events/key_events_spec.ts b/packages/platform-browser/test/dom/events/key_events_spec.ts index 0c9b14d19dff7..ba97308756686 100644 --- a/packages/platform-browser/test/dom/events/key_events_spec.ts +++ b/packages/platform-browser/test/dom/events/key_events_spec.ts @@ -51,7 +51,6 @@ import {KeyEventsPlugin} from '@angular/platform-browser/src/dom/events/key_even .toEqual({'domEventName': 'keydown', 'fullKey': 'control.shift'}); expect(KeyEventsPlugin.parseEventName('keyup.control.shift')) .toEqual({'domEventName': 'keyup', 'fullKey': 'control.shift'}); - }); it('should alias esc to escape', () => { @@ -67,6 +66,5 @@ import {KeyEventsPlugin} from '@angular/platform-browser/src/dom/events/key_even expect(() => plugin.addGlobalEventListener('window', 'keyup.control.esc', () => {})) .not.toThrowError(); }); - }); } diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 867f550bb579f..358f4ccc46469 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -3708,8 +3708,7 @@ describe('Integration', () => { router.navigate(['/user/:fedor']); advance(fixture); - expect(navigateSpy.calls.mostRecent().args[1] !.queryParams); - + expect(navigateSpy.calls.mostRecent().args[1]!.queryParams); }))); }); diff --git a/packages/service-worker/test/comm_spec.ts b/packages/service-worker/test/comm_spec.ts index 839deada200b7..64f6e67601468 100644 --- a/packages/service-worker/test/comm_spec.ts +++ b/packages/service-worker/test/comm_spec.ts @@ -9,7 +9,7 @@ import {PLATFORM_ID} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {NgswCommChannel} from '@angular/service-worker/src/low_level'; -import {SwRegistrationOptions, ngswCommChannelFactory} from '@angular/service-worker/src/module'; +import {ngswCommChannelFactory, SwRegistrationOptions} from '@angular/service-worker/src/module'; import {SwPush} from '@angular/service-worker/src/push'; import {SwUpdate} from '@angular/service-worker/src/update'; import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockServiceWorkerRegistration, patchDecodeBase64} from '@angular/service-worker/testing/mock'; @@ -32,14 +32,18 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS mock.setupSw(); - (comm as any).registration.subscribe((reg: any) => { done(); }); + (comm as any).registration.subscribe((reg: any) => { + done(); + }); }); it('can access the registration when it comes after subscription', done => { const mock = new MockServiceWorkerContainer(); const comm = new NgswCommChannel(mock as any); const regPromise = mock.getRegistration() as any as MockServiceWorkerRegistration; - (comm as any).registration.subscribe((reg: any) => { done(); }); + (comm as any).registration.subscribe((reg: any) => { + done(); + }); mock.setupSw(); }); @@ -158,7 +162,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS }); describe('requestSubscription()', () => { - it('returns a promise that resolves to the subscription', async() => { + it('returns a promise that resolves to the subscription', async () => { const promise = push.requestSubscription({serverPublicKey: 'test'}); expect(promise).toEqual(jasmine.any(Promise)); @@ -166,7 +170,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS expect(sub).toEqual(jasmine.any(MockPushSubscription)); }); - it('calls `PushManager.subscribe()` (with appropriate options)', async() => { + it('calls `PushManager.subscribe()` (with appropriate options)', async () => { const decode = (charCodeArr: Uint8Array) => Array.from(charCodeArr).map(c => String.fromCharCode(c)).join(''); @@ -183,12 +187,12 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS userVisibleOnly: true, }); - const actualAppServerKey = pmSubscribeSpy.calls.first().args[0] !.applicationServerKey; + const actualAppServerKey = pmSubscribeSpy.calls.first().args[0]!.applicationServerKey; const actualAppServerKeyStr = decode(actualAppServerKey as Uint8Array); expect(actualAppServerKeyStr).toBe(appServerKeyStr); }); - it('emits the new `PushSubscription` on `SwPush.subscription`', async() => { + it('emits the new `PushSubscription` on `SwPush.subscription`', async () => { const subscriptionSpy = jasmine.createSpy('subscriptionSpy'); push.subscription.subscribe(subscriptionSpy); const sub = await push.requestSubscription({serverPublicKey: 'test'}); @@ -204,7 +208,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS psUnsubscribeSpy = spyOn(MockPushSubscription.prototype, 'unsubscribe').and.callThrough(); }); - it('rejects if currently not subscribed to push notifications', async() => { + it('rejects if currently not subscribed to push notifications', async () => { try { await push.unsubscribe(); throw new Error('`unsubscribe()` should fail'); @@ -213,15 +217,17 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS } }); - it('calls `PushSubscription.unsubscribe()`', async() => { + it('calls `PushSubscription.unsubscribe()`', async () => { await push.requestSubscription({serverPublicKey: 'test'}); await push.unsubscribe(); expect(psUnsubscribeSpy).toHaveBeenCalledTimes(1); }); - it('rejects if `PushSubscription.unsubscribe()` fails', async() => { - psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); }); + it('rejects if `PushSubscription.unsubscribe()` fails', async () => { + psUnsubscribeSpy.and.callFake(() => { + throw new Error('foo'); + }); try { await push.requestSubscription({serverPublicKey: 'test'}); @@ -232,7 +238,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS } }); - it('rejects if `PushSubscription.unsubscribe()` returns false', async() => { + it('rejects if `PushSubscription.unsubscribe()` returns false', async () => { psUnsubscribeSpy.and.returnValue(Promise.resolve(false)); try { @@ -244,7 +250,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS } }); - it('emits `null` on `SwPush.subscription`', async() => { + it('emits `null` on `SwPush.subscription`', async () => { const subscriptionSpy = jasmine.createSpy('subscriptionSpy'); push.subscription.subscribe(subscriptionSpy); @@ -254,7 +260,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS expect(subscriptionSpy).toHaveBeenCalledWith(null); }); - it('does not emit on `SwPush.subscription` on failure', async() => { + it('does not emit on `SwPush.subscription` on failure', async () => { const subscriptionSpy = jasmine.createSpy('subscriptionSpy'); const initialSubEmit = new Promise(resolve => subscriptionSpy.and.callFake(resolve)); @@ -271,7 +277,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS subscriptionSpy.calls.reset(); // Error due to `PushSubscription.unsubscribe()` error. - psUnsubscribeSpy.and.callFake(() => { throw new Error('foo'); }); + psUnsubscribeSpy.and.callFake(() => { + throw new Error('foo'); + }); await push.unsubscribe().catch(() => undefined); expect(subscriptionSpy).not.toHaveBeenCalled(); @@ -338,7 +346,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS push.subscription.subscribe(subscriptionSpy); }); - it('emits on worker-driven changes (i.e. when the controller changes)', async() => { + it('emits on worker-driven changes (i.e. when the controller changes)', async () => { // Initial emit for the current `ServiceWorkerController`. await nextSubEmitPromise; expect(subscriptionSpy).toHaveBeenCalledTimes(1); @@ -353,7 +361,7 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS expect(subscriptionSpy).toHaveBeenCalledWith(null); }); - it('emits on subscription changes (i.e. when subscribing/unsubscribing)', async() => { + it('emits on subscription changes (i.e. when subscribing/unsubscribing)', async () => { await nextSubEmitPromise; subscriptionSpy.calls.reset(); @@ -391,11 +399,16 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS }); it('gives an error when registering', done => { - push.requestSubscription({serverPublicKey: 'test'}).catch(err => { done(); }); + push.requestSubscription({serverPublicKey: 'test'}).catch(err => { + done(); + }); }); - it('gives an error when unsubscribing', - done => { push.unsubscribe().catch(err => { done(); }); }); + it('gives an error when unsubscribing', done => { + push.unsubscribe().catch(err => { + done(); + }); + }); }); }); @@ -461,7 +474,9 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS }); }); return update.activateUpdate() - .catch(err => { expect(err.message).toEqual('Failed to activate'); }) + .catch(err => { + expect(err.message).toEqual('Failed to activate'); + }) .then(() => done()) .catch(err => done.fail(err)); }); @@ -475,8 +490,12 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS expect(() => TestBed.inject(SwUpdate)).not.toThrow(); }); describe('with no SW', () => { - beforeEach(() => { comm = new NgswCommChannel(undefined); }); - it('can be instantiated', () => { update = new SwUpdate(comm); }); + beforeEach(() => { + comm = new NgswCommChannel(undefined); + }); + it('can be instantiated', () => { + update = new SwUpdate(comm); + }); it('does not crash on subscription to observables', () => { update = new SwUpdate(comm); update.available.toPromise().catch(err => fail(err)); @@ -484,11 +503,15 @@ import {MockPushManager, MockPushSubscription, MockServiceWorkerContainer, MockS }); it('gives an error when checking for updates', done => { update = new SwUpdate(comm); - update.checkForUpdate().catch(err => { done(); }); + update.checkForUpdate().catch(err => { + done(); + }); }); it('gives an error when activating updates', done => { update = new SwUpdate(comm); - update.activateUpdate().catch(err => { done(); }); + update.activateUpdate().catch(err => { + done(); + }); }); }); }); diff --git a/packages/service-worker/test/module_spec.ts b/packages/service-worker/test/module_spec.ts index 480fe837f1550..495debec5b087 100644 --- a/packages/service-worker/test/module_spec.ts +++ b/packages/service-worker/test/module_spec.ts @@ -7,7 +7,7 @@ */ import {ApplicationRef, PLATFORM_ID} from '@angular/core'; -import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing'; import {Subject} from 'rxjs'; import {filter, take} from 'rxjs/operators'; @@ -33,7 +33,7 @@ describe('ServiceWorkerModule', () => { spyOn(navigator.serviceWorker, 'register').and.returnValue(Promise.resolve(null as any))); describe('register()', () => { - const configTestBed = async(opts: SwRegistrationOptions) => { + const configTestBed = async (opts: SwRegistrationOptions) => { TestBed.configureTestingModule({ imports: [ServiceWorkerModule.register('sw.js', opts)], providers: [{provide: PLATFORM_ID, useValue: 'browser'}], @@ -42,35 +42,35 @@ describe('ServiceWorkerModule', () => { await untilStable(); }; - it('sets the registration options', async() => { + it('sets the registration options', async () => { await configTestBed({enabled: true, scope: 'foo'}); expect(TestBed.inject(SwRegistrationOptions)).toEqual({enabled: true, scope: 'foo'}); expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: 'foo'}); }); - it('can disable the SW', async() => { + it('can disable the SW', async () => { await configTestBed({enabled: false}); expect(TestBed.inject(SwUpdate).isEnabled).toBe(false); expect(swRegisterSpy).not.toHaveBeenCalled(); }); - it('can enable the SW', async() => { + it('can enable the SW', async () => { await configTestBed({enabled: true}); expect(TestBed.inject(SwUpdate).isEnabled).toBe(true); expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); }); - it('defaults to enabling the SW', async() => { + it('defaults to enabling the SW', async () => { await configTestBed({}); expect(TestBed.inject(SwUpdate).isEnabled).toBe(true); expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); }); - it('catches and a logs registration errors', async() => { + it('catches and a logs registration errors', async () => { const consoleErrorSpy = spyOn(console, 'error'); swRegisterSpy.and.returnValue(Promise.reject('no reason')); @@ -92,7 +92,7 @@ describe('ServiceWorkerModule', () => { }); }; - it('sets the registration options (and overwrites those set via `.register()`', async() => { + it('sets the registration options (and overwrites those set via `.register()`', async () => { configTestBed({enabled: true, scope: 'provider'}); await untilStable(); @@ -100,7 +100,7 @@ describe('ServiceWorkerModule', () => { expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: 'provider'}); }); - it('can disable the SW', async() => { + it('can disable the SW', async () => { configTestBed({enabled: false}, {enabled: true}); await untilStable(); @@ -108,7 +108,7 @@ describe('ServiceWorkerModule', () => { expect(swRegisterSpy).not.toHaveBeenCalled(); }); - it('can enable the SW', async() => { + it('can enable the SW', async () => { configTestBed({enabled: true}, {enabled: false}); await untilStable(); @@ -116,7 +116,7 @@ describe('ServiceWorkerModule', () => { expect(swRegisterSpy).toHaveBeenCalledWith('sw.js', {scope: undefined}); }); - it('defaults to enabling the SW', async() => { + it('defaults to enabling the SW', async () => { configTestBed({}, {enabled: false}); await untilStable(); diff --git a/packages/service-worker/worker/test/happy_spec.ts b/packages/service-worker/worker/test/happy_spec.ts index ba29e7dfbfd0b..320240c55574d 100644 --- a/packages/service-worker/worker/test/happy_spec.ts +++ b/packages/service-worker/worker/test/happy_spec.ts @@ -11,60 +11,77 @@ import {CacheDatabase} from '../src/db-cache'; import {Driver, DriverReadyState} from '../src/driver'; import {AssetGroupConfig, DataGroupConfig, Manifest} from '../src/manifest'; import {sha1} from '../src/sha1'; -import {MockCache, clearAllCaches} from '../testing/cache'; +import {clearAllCaches, MockCache} from '../testing/cache'; import {MockRequest, MockResponse} from '../testing/fetch'; import {MockFileSystemBuilder, MockServerStateBuilder, tmpHashTableForFs} from '../testing/mock'; import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope'; (function() { - // Skip environments that don't support the minimum APIs needed to run the SW tests. - if (!SwTestHarness.envIsSupported()) { - return; - } - - const dist = - new MockFileSystemBuilder() - .addFile('/foo.txt', 'this is foo') - .addFile('/bar.txt', 'this is bar') - .addFile('/baz.txt', 'this is baz') - .addFile('/qux.txt', 'this is qux') - .addFile('/quux.txt', 'this is quux') - .addFile('/quuux.txt', 'this is quuux') - .addFile('/lazy/unchanged1.txt', 'this is unchanged (1)') - .addFile('/lazy/unchanged2.txt', 'this is unchanged (2)') - .addUnhashedFile('/unhashed/a.txt', 'this is unhashed', {'Cache-Control': 'max-age=10'}) - .addUnhashedFile('/unhashed/b.txt', 'this is unhashed b', {'Cache-Control': 'no-cache'}) - .addUnhashedFile('/api/foo', 'this is api foo', {'Cache-Control': 'no-cache'}) - .addUnhashedFile( - '/api-static/bar', 'this is static api bar', {'Cache-Control': 'no-cache'}) - .build(); - - const distUpdate = - new MockFileSystemBuilder() - .addFile('/foo.txt', 'this is foo v2') - .addFile('/bar.txt', 'this is bar') - .addFile('/baz.txt', 'this is baz v2') - .addFile('/qux.txt', 'this is qux v2') - .addFile('/quux.txt', 'this is quux v2') - .addFile('/quuux.txt', 'this is quuux v2') - .addFile('/lazy/unchanged1.txt', 'this is unchanged (1)') - .addFile('/lazy/unchanged2.txt', 'this is unchanged (2)') - .addUnhashedFile( - '/unhashed/a.txt', 'this is unhashed v2', {'Cache-Control': 'max-age=10'}) - .addUnhashedFile('/ignored/file1', 'this is not handled by the SW') - .addUnhashedFile('/ignored/dir/file2', 'this is not handled by the SW either') - .build(); - - const brokenFs = new MockFileSystemBuilder() - .addFile('/foo.txt', 'this is foo (broken)') - .addFile('/bar.txt', 'this is bar (broken)') - .build(); - - const brokenManifest: Manifest = { - configVersion: 1, - timestamp: 1234567890123, - index: '/foo.txt', - assetGroups: [{ +// Skip environments that don't support the minimum APIs needed to run the SW tests. +if (!SwTestHarness.envIsSupported()) { + return; +} + +const dist = + new MockFileSystemBuilder() + .addFile('/foo.txt', 'this is foo') + .addFile('/bar.txt', 'this is bar') + .addFile('/baz.txt', 'this is baz') + .addFile('/qux.txt', 'this is qux') + .addFile('/quux.txt', 'this is quux') + .addFile('/quuux.txt', 'this is quuux') + .addFile('/lazy/unchanged1.txt', 'this is unchanged (1)') + .addFile('/lazy/unchanged2.txt', 'this is unchanged (2)') + .addUnhashedFile('/unhashed/a.txt', 'this is unhashed', {'Cache-Control': 'max-age=10'}) + .addUnhashedFile('/unhashed/b.txt', 'this is unhashed b', {'Cache-Control': 'no-cache'}) + .addUnhashedFile('/api/foo', 'this is api foo', {'Cache-Control': 'no-cache'}) + .addUnhashedFile('/api-static/bar', 'this is static api bar', {'Cache-Control': 'no-cache'}) + .build(); + +const distUpdate = + new MockFileSystemBuilder() + .addFile('/foo.txt', 'this is foo v2') + .addFile('/bar.txt', 'this is bar') + .addFile('/baz.txt', 'this is baz v2') + .addFile('/qux.txt', 'this is qux v2') + .addFile('/quux.txt', 'this is quux v2') + .addFile('/quuux.txt', 'this is quuux v2') + .addFile('/lazy/unchanged1.txt', 'this is unchanged (1)') + .addFile('/lazy/unchanged2.txt', 'this is unchanged (2)') + .addUnhashedFile('/unhashed/a.txt', 'this is unhashed v2', {'Cache-Control': 'max-age=10'}) + .addUnhashedFile('/ignored/file1', 'this is not handled by the SW') + .addUnhashedFile('/ignored/dir/file2', 'this is not handled by the SW either') + .build(); + +const brokenFs = new MockFileSystemBuilder() + .addFile('/foo.txt', 'this is foo (broken)') + .addFile('/bar.txt', 'this is bar (broken)') + .build(); + +const brokenManifest: Manifest = { + configVersion: 1, + timestamp: 1234567890123, + index: '/foo.txt', + assetGroups: [{ + name: 'assets', + installMode: 'prefetch', + updateMode: 'prefetch', + urls: [ + '/foo.txt', + ], + patterns: [], + }], + dataGroups: [], + navigationUrls: processNavigationUrls(''), + hashTable: tmpHashTableForFs(brokenFs, {'/foo.txt': true}), +}; + +const brokenLazyManifest: Manifest = { + configVersion: 1, + timestamp: 1234567890123, + index: '/foo.txt', + assetGroups: [ + { name: 'assets', installMode: 'prefetch', updateMode: 'prefetch', @@ -72,1441 +89,1419 @@ import {SwTestHarness, SwTestHarnessBuilder} from '../testing/scope'; '/foo.txt', ], patterns: [], - }], - dataGroups: [], - navigationUrls: processNavigationUrls(''), - hashTable: tmpHashTableForFs(brokenFs, {'/foo.txt': true}), - }; - - const brokenLazyManifest: Manifest = { - configVersion: 1, - timestamp: 1234567890123, - index: '/foo.txt', - assetGroups: [ - { - name: 'assets', - installMode: 'prefetch', - updateMode: 'prefetch', - urls: [ - '/foo.txt', - ], - patterns: [], - }, - { - name: 'lazy-assets', - installMode: 'lazy', - updateMode: 'lazy', - urls: [ - '/bar.txt', - ], - patterns: [], - }, - ], - dataGroups: [], - navigationUrls: processNavigationUrls(''), - hashTable: tmpHashTableForFs(brokenFs, {'/bar.txt': true}), - }; - - // Manifest without navigation urls to test backward compatibility with - // versions < 6.0.0. - interface ManifestV5 { - configVersion: number; - appData?: {[key: string]: string}; - index: string; - assetGroups?: AssetGroupConfig[]; - dataGroups?: DataGroupConfig[]; - hashTable: {[url: string]: string}; - } - - // To simulate versions < 6.0.0 - const manifestOld: ManifestV5 = { - configVersion: 1, - index: '/foo.txt', - hashTable: tmpHashTableForFs(dist), - }; - - const manifest: Manifest = { - configVersion: 1, - timestamp: 1234567890123, - appData: { - version: 'original', }, - index: '/foo.txt', - assetGroups: [ - { - name: 'assets', - installMode: 'prefetch', - updateMode: 'prefetch', - urls: [ - '/foo.txt', - '/bar.txt', - '/redirected.txt', - ], - patterns: [ - '/unhashed/.*', - ], - }, - { - name: 'other', - installMode: 'lazy', - updateMode: 'lazy', - urls: [ - '/baz.txt', - '/qux.txt', - ], - patterns: [], - }, - { - name: 'lazy_prefetch', - installMode: 'lazy', - updateMode: 'prefetch', - urls: [ - '/quux.txt', - '/quuux.txt', - '/lazy/unchanged1.txt', - '/lazy/unchanged2.txt', - ], - patterns: [], - } - ], - dataGroups: [ - { - name: 'api', - version: 42, - maxAge: 3600000, - maxSize: 100, - strategy: 'freshness', - patterns: [ - '/api/.*', - ], - }, - { - name: 'api-static', - version: 43, - maxAge: 3600000, - maxSize: 100, - strategy: 'performance', - patterns: [ - '/api-static/.*', - ], - }, - ], - navigationUrls: processNavigationUrls(''), - hashTable: tmpHashTableForFs(dist), - }; - - const manifestUpdate: Manifest = { - configVersion: 1, - timestamp: 1234567890123, - appData: { - version: 'update', + { + name: 'lazy-assets', + installMode: 'lazy', + updateMode: 'lazy', + urls: [ + '/bar.txt', + ], + patterns: [], }, - index: '/foo.txt', - assetGroups: [ - { - name: 'assets', - installMode: 'prefetch', - updateMode: 'prefetch', - urls: [ - '/foo.txt', - '/bar.txt', - '/redirected.txt', - ], - patterns: [ - '/unhashed/.*', - ], - }, - { - name: 'other', - installMode: 'lazy', - updateMode: 'lazy', - urls: [ - '/baz.txt', - '/qux.txt', - ], - patterns: [], - }, - { - name: 'lazy_prefetch', - installMode: 'lazy', - updateMode: 'prefetch', - urls: [ - '/quux.txt', - '/quuux.txt', - '/lazy/unchanged1.txt', - '/lazy/unchanged2.txt', - ], - patterns: [], - } - ], - navigationUrls: processNavigationUrls( - '', - [ - '/**/file1', - '/**/file2', - '!/ignored/file1', - '!/ignored/dir/**', - ]), - hashTable: tmpHashTableForFs(distUpdate), - }; - - const serverBuilderBase = - new MockServerStateBuilder() - .withStaticFiles(dist) - .withRedirect('/redirected.txt', '/redirect-target.txt', 'this was a redirect') - .withError('/error.txt'); - - const server = serverBuilderBase.withManifest(manifest).build(); - - const serverRollback = - serverBuilderBase.withManifest({...manifest, timestamp: manifest.timestamp + 1}).build(); - - const serverUpdate = - new MockServerStateBuilder() - .withStaticFiles(distUpdate) - .withManifest(manifestUpdate) - .withRedirect('/redirected.txt', '/redirect-target.txt', 'this was a redirect') - .build(); - - const brokenServer = - new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenManifest).build(); - - const brokenLazyServer = new MockServerStateBuilder() - .withStaticFiles(brokenFs) - .withManifest(brokenLazyManifest) - .build(); - - const server404 = new MockServerStateBuilder().withStaticFiles(dist).build(); - - const manifestHash = sha1(JSON.stringify(manifest)); - const manifestUpdateHash = sha1(JSON.stringify(manifestUpdate)); - - - describe('Driver', () => { - let scope: SwTestHarness; - let driver: Driver; - - beforeEach(() => { - server.reset(); - serverUpdate.reset(); - server404.reset(); - brokenServer.reset(); - - scope = new SwTestHarnessBuilder().withServerState(server).build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - }); + ], + dataGroups: [], + navigationUrls: processNavigationUrls(''), + hashTable: tmpHashTableForFs(brokenFs, {'/bar.txt': true}), +}; + +// Manifest without navigation urls to test backward compatibility with +// versions < 6.0.0. +interface ManifestV5 { + configVersion: number; + appData?: {[key: string]: string}; + index: string; + assetGroups?: AssetGroupConfig[]; + dataGroups?: DataGroupConfig[]; + hashTable: {[url: string]: string}; +} + +// To simulate versions < 6.0.0 +const manifestOld: ManifestV5 = { + configVersion: 1, + index: '/foo.txt', + hashTable: tmpHashTableForFs(dist), +}; + +const manifest: Manifest = { + configVersion: 1, + timestamp: 1234567890123, + appData: { + version: 'original', + }, + index: '/foo.txt', + assetGroups: [ + { + name: 'assets', + installMode: 'prefetch', + updateMode: 'prefetch', + urls: [ + '/foo.txt', + '/bar.txt', + '/redirected.txt', + ], + patterns: [ + '/unhashed/.*', + ], + }, + { + name: 'other', + installMode: 'lazy', + updateMode: 'lazy', + urls: [ + '/baz.txt', + '/qux.txt', + ], + patterns: [], + }, + { + name: 'lazy_prefetch', + installMode: 'lazy', + updateMode: 'prefetch', + urls: [ + '/quux.txt', + '/quuux.txt', + '/lazy/unchanged1.txt', + '/lazy/unchanged2.txt', + ], + patterns: [], + } + ], + dataGroups: [ + { + name: 'api', + version: 42, + maxAge: 3600000, + maxSize: 100, + strategy: 'freshness', + patterns: [ + '/api/.*', + ], + }, + { + name: 'api-static', + version: 43, + maxAge: 3600000, + maxSize: 100, + strategy: 'performance', + patterns: [ + '/api-static/.*', + ], + }, + ], + navigationUrls: processNavigationUrls(''), + hashTable: tmpHashTableForFs(dist), +}; + +const manifestUpdate: Manifest = { + configVersion: 1, + timestamp: 1234567890123, + appData: { + version: 'update', + }, + index: '/foo.txt', + assetGroups: [ + { + name: 'assets', + installMode: 'prefetch', + updateMode: 'prefetch', + urls: [ + '/foo.txt', + '/bar.txt', + '/redirected.txt', + ], + patterns: [ + '/unhashed/.*', + ], + }, + { + name: 'other', + installMode: 'lazy', + updateMode: 'lazy', + urls: [ + '/baz.txt', + '/qux.txt', + ], + patterns: [], + }, + { + name: 'lazy_prefetch', + installMode: 'lazy', + updateMode: 'prefetch', + urls: [ + '/quux.txt', + '/quuux.txt', + '/lazy/unchanged1.txt', + '/lazy/unchanged2.txt', + ], + patterns: [], + } + ], + navigationUrls: processNavigationUrls( + '', + [ + '/**/file1', + '/**/file2', + '!/ignored/file1', + '!/ignored/dir/**', + ]), + hashTable: tmpHashTableForFs(distUpdate), +}; + +const serverBuilderBase = + new MockServerStateBuilder() + .withStaticFiles(dist) + .withRedirect('/redirected.txt', '/redirect-target.txt', 'this was a redirect') + .withError('/error.txt'); + +const server = serverBuilderBase.withManifest(manifest).build(); + +const serverRollback = + serverBuilderBase.withManifest({...manifest, timestamp: manifest.timestamp + 1}).build(); + +const serverUpdate = + new MockServerStateBuilder() + .withStaticFiles(distUpdate) + .withManifest(manifestUpdate) + .withRedirect('/redirected.txt', '/redirect-target.txt', 'this was a redirect') + .build(); + +const brokenServer = + new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenManifest).build(); + +const brokenLazyServer = + new MockServerStateBuilder().withStaticFiles(brokenFs).withManifest(brokenLazyManifest).build(); + +const server404 = new MockServerStateBuilder().withStaticFiles(dist).build(); + +const manifestHash = sha1(JSON.stringify(manifest)); +const manifestUpdateHash = sha1(JSON.stringify(manifestUpdate)); + + +describe('Driver', () => { + let scope: SwTestHarness; + let driver: Driver; + + beforeEach(() => { + server.reset(); + serverUpdate.reset(); + server404.reset(); + brokenServer.reset(); + + scope = new SwTestHarnessBuilder().withServerState(server).build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + }); - it('activates without waiting', async() => { - const skippedWaiting = await scope.startup(true); - expect(skippedWaiting).toBe(true); - }); + it('activates without waiting', async () => { + const skippedWaiting = await scope.startup(true); + expect(skippedWaiting).toBe(true); + }); - it('claims all clients, after activation', async() => { - const claimSpy = spyOn(scope.clients, 'claim'); + it('claims all clients, after activation', async () => { + const claimSpy = spyOn(scope.clients, 'claim'); - await scope.startup(true); - expect(claimSpy).toHaveBeenCalledTimes(1); - }); + await scope.startup(true); + expect(claimSpy).toHaveBeenCalledTimes(1); + }); - it('cleans up old `@angular/service-worker` caches, after activation', async() => { - const claimSpy = spyOn(scope.clients, 'claim'); - const cleanupOldSwCachesSpy = spyOn(driver, 'cleanupOldSwCaches'); + it('cleans up old `@angular/service-worker` caches, after activation', async () => { + const claimSpy = spyOn(scope.clients, 'claim'); + const cleanupOldSwCachesSpy = spyOn(driver, 'cleanupOldSwCaches'); - // Automatically advance time to trigger idle tasks as they are added. - scope.autoAdvanceTime = true; - await scope.startup(true); - await scope.resolveSelfMessages(); - scope.autoAdvanceTime = false; + // Automatically advance time to trigger idle tasks as they are added. + scope.autoAdvanceTime = true; + await scope.startup(true); + await scope.resolveSelfMessages(); + scope.autoAdvanceTime = false; - expect(cleanupOldSwCachesSpy).toHaveBeenCalledTimes(1); - expect(claimSpy).toHaveBeenCalledBefore(cleanupOldSwCachesSpy); - }); + expect(cleanupOldSwCachesSpy).toHaveBeenCalledTimes(1); + expect(claimSpy).toHaveBeenCalledBefore(cleanupOldSwCachesSpy); + }); - it('does not blow up if cleaning up old `@angular/service-worker` caches fails', async() => { - spyOn(driver, 'cleanupOldSwCaches').and.callFake(() => Promise.reject('Ooops')); + it('does not blow up if cleaning up old `@angular/service-worker` caches fails', async () => { + spyOn(driver, 'cleanupOldSwCaches').and.callFake(() => Promise.reject('Ooops')); - // Automatically advance time to trigger idle tasks as they are added. - scope.autoAdvanceTime = true; - await scope.startup(true); - await scope.resolveSelfMessages(); - scope.autoAdvanceTime = false; + // Automatically advance time to trigger idle tasks as they are added. + scope.autoAdvanceTime = true; + await scope.startup(true); + await scope.resolveSelfMessages(); + scope.autoAdvanceTime = false; - server.clearRequests(); + server.clearRequests(); - expect(driver.state).toBe(DriverReadyState.NORMAL); - expect(await makeRequest(scope, '/foo.txt')).toBe('this is foo'); - server.assertNoOtherRequests(); - }); + expect(driver.state).toBe(DriverReadyState.NORMAL); + expect(await makeRequest(scope, '/foo.txt')).toBe('this is foo'); + server.assertNoOtherRequests(); + }); - it('initializes prefetched content correctly, after activation', async() => { - // Automatically advance time to trigger idle tasks as they are added. - scope.autoAdvanceTime = true; - await scope.startup(true); - await scope.resolveSelfMessages(); - scope.autoAdvanceTime = false; + it('initializes prefetched content correctly, after activation', async () => { + // Automatically advance time to trigger idle tasks as they are added. + scope.autoAdvanceTime = true; + await scope.startup(true); + await scope.resolveSelfMessages(); + scope.autoAdvanceTime = false; + + server.assertSawRequestFor('ngsw.json'); + server.assertSawRequestFor('/foo.txt'); + server.assertSawRequestFor('/bar.txt'); + server.assertSawRequestFor('/redirected.txt'); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); + server.assertNoOtherRequests(); + }); - server.assertSawRequestFor('ngsw.json'); - server.assertSawRequestFor('/foo.txt'); - server.assertSawRequestFor('/bar.txt'); - server.assertSawRequestFor('/redirected.txt'); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); - server.assertNoOtherRequests(); - }); + it('initializes prefetched content correctly, after a request kicks it off', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.assertSawRequestFor('ngsw.json'); + server.assertSawRequestFor('/foo.txt'); + server.assertSawRequestFor('/bar.txt'); + server.assertSawRequestFor('/redirected.txt'); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); + server.assertNoOtherRequests(); + }); - it('initializes prefetched content correctly, after a request kicks it off', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.assertSawRequestFor('ngsw.json'); - server.assertSawRequestFor('/foo.txt'); - server.assertSawRequestFor('/bar.txt'); - server.assertSawRequestFor('/redirected.txt'); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); - server.assertNoOtherRequests(); - }); + it('initializes the service worker on fetch if it has not yet been initialized', async () => { + // Driver is initially uninitialized. + expect(driver.initialized).toBeNull(); + expect(driver['latestHash']).toBeNull(); + + // Making a request initializes the driver (fetches assets). + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(driver['latestHash']).toEqual(jasmine.any(String)); + server.assertSawRequestFor('ngsw.json'); + server.assertSawRequestFor('/foo.txt'); + server.assertSawRequestFor('/bar.txt'); + server.assertSawRequestFor('/redirected.txt'); + + // Once initialized, cached resources are served without network requests. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); + server.assertNoOtherRequests(); + }); - it('initializes the service worker on fetch if it has not yet been initialized', async() => { - // Driver is initially uninitialized. - expect(driver.initialized).toBeNull(); - expect(driver['latestHash']).toBeNull(); + it('initializes the service worker on message if it has not yet been initialized', async () => { + // Driver is initially uninitialized. + expect(driver.initialized).toBeNull(); + expect(driver['latestHash']).toBeNull(); + + // Pushing a message initializes the driver (fetches assets). + await scope.handleMessage({action: 'foo'}, 'someClient'); + expect(driver['latestHash']).toEqual(jasmine.any(String)); + server.assertSawRequestFor('ngsw.json'); + server.assertSawRequestFor('/foo.txt'); + server.assertSawRequestFor('/bar.txt'); + server.assertSawRequestFor('/redirected.txt'); + + // Once initialized, pushed messages are handled without re-initializing. + await scope.handleMessage({action: 'bar'}, 'someClient'); + server.assertNoOtherRequests(); + + // Once initialized, cached resources are served without network requests. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); + server.assertNoOtherRequests(); + }); - // Making a request initializes the driver (fetches assets). - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(driver['latestHash']).toEqual(jasmine.any(String)); - server.assertSawRequestFor('ngsw.json'); - server.assertSawRequestFor('/foo.txt'); - server.assertSawRequestFor('/bar.txt'); - server.assertSawRequestFor('/redirected.txt'); + it('handles non-relative URLs', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + expect(await makeRequest(scope, 'http://localhost/foo.txt')).toEqual('this is foo'); + server.assertNoOtherRequests(); + }); - // Once initialized, cached resources are served without network requests. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); - server.assertNoOtherRequests(); - }); + it('handles actual errors from the browser', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); - it('initializes the service worker on message if it has not yet been initialized', async() => { - // Driver is initially uninitialized. - expect(driver.initialized).toBeNull(); - expect(driver['latestHash']).toBeNull(); + const [resPromise, done] = scope.handleFetch(new MockRequest('/error.txt'), 'default'); + await done; + const res = (await resPromise)!; + expect(res.status).toEqual(504); + expect(res.statusText).toEqual('Gateway Timeout'); + }); - // Pushing a message initializes the driver (fetches assets). - await scope.handleMessage({action: 'foo'}, 'someClient'); - expect(driver['latestHash']).toEqual(jasmine.any(String)); - server.assertSawRequestFor('ngsw.json'); - server.assertSawRequestFor('/foo.txt'); - server.assertSawRequestFor('/bar.txt'); - server.assertSawRequestFor('/redirected.txt'); + it('handles redirected responses', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + expect(await makeRequest(scope, '/redirected.txt')).toEqual('this was a redirect'); + server.assertNoOtherRequests(); + }); - // Once initialized, pushed messages are handled without re-initializing. - await scope.handleMessage({action: 'bar'}, 'someClient'); - server.assertNoOtherRequests(); + it('caches lazy content on-request', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + expect(await makeRequest(scope, '/baz.txt')).toEqual('this is baz'); + server.assertSawRequestFor('/baz.txt'); + server.assertNoOtherRequests(); + expect(await makeRequest(scope, '/baz.txt')).toEqual('this is baz'); + server.assertNoOtherRequests(); + expect(await makeRequest(scope, '/qux.txt')).toEqual('this is qux'); + server.assertSawRequestFor('/qux.txt'); + server.assertNoOtherRequests(); + }); - // Once initialized, cached resources are served without network requests. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); - server.assertNoOtherRequests(); - }); + it('updates to new content when requested', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - it('handles non-relative URLs', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - expect(await makeRequest(scope, 'http://localhost/foo.txt')).toEqual('this is foo'); - server.assertNoOtherRequests(); - }); + const client = scope.clients.getMock('default')!; + expect(client.messages).toEqual([]); - it('handles actual errors from the browser', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + serverUpdate.assertSawRequestFor('ngsw.json'); + serverUpdate.assertSawRequestFor('/foo.txt'); + serverUpdate.assertSawRequestFor('/redirected.txt'); + serverUpdate.assertNoOtherRequests(); - const [resPromise, done] = scope.handleFetch(new MockRequest('/error.txt'), 'default'); - await done; - const res = (await resPromise) !; - expect(res.status).toEqual(504); - expect(res.statusText).toEqual('Gateway Timeout'); - }); + expect(client.messages).toEqual([{ + type: 'UPDATE_AVAILABLE', + current: {hash: manifestHash, appData: {version: 'original'}}, + available: {hash: manifestUpdateHash, appData: {version: 'update'}}, + }]); - it('handles redirected responses', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - expect(await makeRequest(scope, '/redirected.txt')).toEqual('this was a redirect'); - server.assertNoOtherRequests(); - }); + // Default client is still on the old version of the app. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - it('caches lazy content on-request', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - expect(await makeRequest(scope, '/baz.txt')).toEqual('this is baz'); - server.assertSawRequestFor('/baz.txt'); - server.assertNoOtherRequests(); - expect(await makeRequest(scope, '/baz.txt')).toEqual('this is baz'); - server.assertNoOtherRequests(); - expect(await makeRequest(scope, '/qux.txt')).toEqual('this is qux'); - server.assertSawRequestFor('/qux.txt'); - server.assertNoOtherRequests(); - }); + // Sending a new client id should result in the updated version being returned. + expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); - it('updates to new content when requested', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + // Of course, the old version should still work. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - const client = scope.clients.getMock('default') !; - expect(client.messages).toEqual([]); + expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); + serverUpdate.assertNoOtherRequests(); + }); - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - serverUpdate.assertSawRequestFor('ngsw.json'); - serverUpdate.assertSawRequestFor('/foo.txt'); - serverUpdate.assertSawRequestFor('/redirected.txt'); - serverUpdate.assertNoOtherRequests(); + it('detects new version even if only `manifest.timestamp` is different', async () => { + expect(await makeRequest(scope, '/foo.txt', 'newClient')).toEqual('this is foo'); + await driver.initialized; + + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + expect(await makeRequest(scope, '/foo.txt', 'newerClient')).toEqual('this is foo v2'); + + scope.updateServerState(serverRollback); + expect(await driver.checkForUpdate()).toEqual(true); + expect(await makeRequest(scope, '/foo.txt', 'newestClient')).toEqual('this is foo'); + }); - expect(client.messages).toEqual([{ + it('updates a specific client to new content on request', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + + const client = scope.clients.getMock('default')!; + expect(client.messages).toEqual([]); + + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + serverUpdate.clearRequests(); + await driver.updateClient(client as any as Client); + + expect(client.messages).toEqual([ + { type: 'UPDATE_AVAILABLE', current: {hash: manifestHash, appData: {version: 'original'}}, available: {hash: manifestUpdateHash, appData: {version: 'update'}}, - }]); + }, + { + type: 'UPDATE_ACTIVATED', + previous: {hash: manifestHash, appData: {version: 'original'}}, + current: {hash: manifestUpdateHash, appData: {version: 'update'}}, + } + ]); - // Default client is still on the old version of the app. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo v2'); + }); - // Sending a new client id should result in the updated version being returned. - expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); + it('handles empty client ID', async () => { + // Initialize the SW. + expect(await makeNavigationRequest(scope, '/foo/file1', '')).toEqual('this is foo'); + expect(await makeNavigationRequest(scope, '/bar/file2', null)).toEqual('this is foo'); + await driver.initialized; - // Of course, the old version should still work. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + // Update to a new version. + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); - expect(await makeRequest(scope, '/bar.txt')).toEqual('this is bar'); - serverUpdate.assertNoOtherRequests(); - }); + // Correctly handle navigation requests, even if `clientId` is null/empty. + expect(await makeNavigationRequest(scope, '/foo/file1', '')).toEqual('this is foo v2'); + expect(await makeNavigationRequest(scope, '/bar/file2', null)).toEqual('this is foo v2'); + }); - it('detects new version even if only `manifest.timestamp` is different', async() => { - expect(await makeRequest(scope, '/foo.txt', 'newClient')).toEqual('this is foo'); - await driver.initialized; + it('checks for updates on restart', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + + scope = new SwTestHarnessBuilder() + .withCacheState(scope.caches.dehydrate()) + .withServerState(serverUpdate) + .build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + serverUpdate.assertNoOtherRequests(); + + scope.advance(12000); + await driver.idle.empty; + + serverUpdate.assertSawRequestFor('ngsw.json'); + serverUpdate.assertSawRequestFor('/foo.txt'); + serverUpdate.assertSawRequestFor('/redirected.txt'); + serverUpdate.assertNoOtherRequests(); + }); - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - expect(await makeRequest(scope, '/foo.txt', 'newerClient')).toEqual('this is foo v2'); + it('checks for updates on navigation', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); - scope.updateServerState(serverRollback); - expect(await driver.checkForUpdate()).toEqual(true); - expect(await makeRequest(scope, '/foo.txt', 'newestClient')).toEqual('this is foo'); - }); + expect(await makeNavigationRequest(scope, '/foo.txt')).toEqual('this is foo'); - it('updates a specific client to new content on request', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + scope.advance(12000); + await driver.idle.empty; - const client = scope.clients.getMock('default') !; - expect(client.messages).toEqual([]); + server.assertSawRequestFor('ngsw.json'); + }); - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - serverUpdate.clearRequests(); - await driver.updateClient(client as any as Client); + it('does not make concurrent checks for updates on navigation', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); - expect(client.messages).toEqual([ - { - type: 'UPDATE_AVAILABLE', - current: {hash: manifestHash, appData: {version: 'original'}}, - available: {hash: manifestUpdateHash, appData: {version: 'update'}}, - }, - { - type: 'UPDATE_ACTIVATED', - previous: {hash: manifestHash, appData: {version: 'original'}}, - current: {hash: manifestUpdateHash, appData: {version: 'update'}}, - } - ]); + expect(await makeNavigationRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo v2'); - }); + expect(await makeNavigationRequest(scope, '/foo.txt')).toEqual('this is foo'); - it('handles empty client ID', async() => { - // Initialize the SW. - expect(await makeNavigationRequest(scope, '/foo/file1', '')).toEqual('this is foo'); - expect(await makeNavigationRequest(scope, '/bar/file2', null)).toEqual('this is foo'); - await driver.initialized; + scope.advance(12000); + await driver.idle.empty; - // Update to a new version. - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); + server.assertSawRequestFor('ngsw.json'); + server.assertNoOtherRequests(); + }); - // Correctly handle navigation requests, even if `clientId` is null/empty. - expect(await makeNavigationRequest(scope, '/foo/file1', '')).toEqual('this is foo v2'); - expect(await makeNavigationRequest(scope, '/bar/file2', null)).toEqual('this is foo v2'); - }); + it('preserves multiple client assignments across restarts', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - it('checks for updates on restart', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); + serverUpdate.clearRequests(); - scope = new SwTestHarnessBuilder() - .withCacheState(scope.caches.dehydrate()) - .withServerState(serverUpdate) - .build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - serverUpdate.assertNoOtherRequests(); + scope = new SwTestHarnessBuilder() + .withCacheState(scope.caches.dehydrate()) + .withServerState(serverUpdate) + .build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - scope.advance(12000); - await driver.idle.empty; + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); + serverUpdate.assertNoOtherRequests(); + }); - serverUpdate.assertSawRequestFor('ngsw.json'); - serverUpdate.assertSawRequestFor('/foo.txt'); - serverUpdate.assertSawRequestFor('/redirected.txt'); - serverUpdate.assertNoOtherRequests(); - }); + it('updates when refreshed', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - it('checks for updates on navigation', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); + const client = scope.clients.getMock('default')!; - expect(await makeNavigationRequest(scope, '/foo.txt')).toEqual('this is foo'); + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + serverUpdate.clearRequests(); - scope.advance(12000); - await driver.idle.empty; + expect(await makeNavigationRequest(scope, '/file1')).toEqual('this is foo v2'); - server.assertSawRequestFor('ngsw.json'); - }); + expect(client.messages).toEqual([ + { + type: 'UPDATE_AVAILABLE', + current: {hash: manifestHash, appData: {version: 'original'}}, + available: {hash: manifestUpdateHash, appData: {version: 'update'}}, + }, + { + type: 'UPDATE_ACTIVATED', + previous: {hash: manifestHash, appData: {version: 'original'}}, + current: {hash: manifestUpdateHash, appData: {version: 'update'}}, + } + ]); + serverUpdate.assertNoOtherRequests(); + }); - it('does not make concurrent checks for updates on navigation', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); + it('cleans up properly when manually requested', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - expect(await makeNavigationRequest(scope, '/foo.txt')).toEqual('this is foo'); + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + serverUpdate.clearRequests(); - expect(await makeNavigationRequest(scope, '/foo.txt')).toEqual('this is foo'); + expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); - scope.advance(12000); - await driver.idle.empty; + // Delete the default client. + scope.clients.remove('default'); - server.assertSawRequestFor('ngsw.json'); - server.assertNoOtherRequests(); - }); + // After this, the old version should no longer be cached. + await driver.cleanupCaches(); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo v2'); - it('preserves multiple client assignments across restarts', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + serverUpdate.assertNoOtherRequests(); + }); - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); - serverUpdate.clearRequests(); + it('cleans up properly on restart', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - scope = new SwTestHarnessBuilder() - .withCacheState(scope.caches.dehydrate()) - .withServerState(serverUpdate) - .build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + scope = new SwTestHarnessBuilder() + .withCacheState(scope.caches.dehydrate()) + .withServerState(serverUpdate) + .build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + serverUpdate.assertNoOtherRequests(); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); - serverUpdate.assertNoOtherRequests(); - }); + let keys = await scope.caches.keys(); + let hasOriginalCaches = keys.some(name => name.startsWith(`ngsw:/:${manifestHash}:`)); + expect(hasOriginalCaches).toEqual(true); - it('updates when refreshed', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + scope.clients.remove('default'); - const client = scope.clients.getMock('default') !; + scope.advance(12000); + await driver.idle.empty; + serverUpdate.clearRequests(); - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - serverUpdate.clearRequests(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo v2'); - expect(await makeNavigationRequest(scope, '/file1')).toEqual('this is foo v2'); + keys = await scope.caches.keys(); + hasOriginalCaches = keys.some(name => name.startsWith(`ngsw:/:${manifestHash}:`)); + expect(hasOriginalCaches).toEqual(false); + }); - expect(client.messages).toEqual([ - { - type: 'UPDATE_AVAILABLE', - current: {hash: manifestHash, appData: {version: 'original'}}, - available: {hash: manifestUpdateHash, appData: {version: 'update'}}, - }, - { - type: 'UPDATE_ACTIVATED', - previous: {hash: manifestHash, appData: {version: 'original'}}, - current: {hash: manifestUpdateHash, appData: {version: 'update'}}, - } - ]); - serverUpdate.assertNoOtherRequests(); + it('shows notifications for push notifications', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + await scope.handlePush({ + notification: { + title: 'This is a test', + body: 'Test body', + } }); + expect(scope.notifications).toEqual([{ + title: 'This is a test', + options: {title: 'This is a test', body: 'Test body'}, + }]); + expect(scope.clients.getMock('default')!.messages).toEqual([{ + type: 'PUSH', + data: { + notification: { + title: 'This is a test', + body: 'Test body', + }, + }, + }]); + }); - it('cleans up properly when manually requested', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + it('broadcasts notification click events with action', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + await scope.handleClick( + {title: 'This is a test with action', body: 'Test body with action'}, 'button'); + const message: any = scope.clients.getMock('default')!.messages[0]; + + expect(message.type).toEqual('NOTIFICATION_CLICK'); + expect(message.data.action).toEqual('button'); + expect(message.data.notification.title).toEqual('This is a test with action'); + expect(message.data.notification.body).toEqual('Test body with action'); + }); - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - serverUpdate.clearRequests(); + it('broadcasts notification click events without action', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + await scope.handleClick( + {title: 'This is a test without action', body: 'Test body without action'}); + const message: any = scope.clients.getMock('default')!.messages[0]; + + expect(message.type).toEqual('NOTIFICATION_CLICK'); + expect(message.data.action).toBeUndefined(); + expect(message.data.notification.title).toEqual('This is a test without action'); + expect(message.data.notification.body).toEqual('Test body without action'); + }); - expect(await makeRequest(scope, '/foo.txt', 'new')).toEqual('this is foo v2'); + it('prefetches updates to lazy cache when set', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - // Delete the default client. - scope.clients.remove('default'); + // Fetch some files from the `lazy_prefetch` asset group. + expect(await makeRequest(scope, '/quux.txt')).toEqual('this is quux'); + expect(await makeRequest(scope, '/lazy/unchanged1.txt')).toEqual('this is unchanged (1)'); - // After this, the old version should no longer be cached. - await driver.cleanupCaches(); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo v2'); + // Install update. + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toBe(true); - serverUpdate.assertNoOtherRequests(); - }); + // Previously requested and changed: Fetch from network. + serverUpdate.assertSawRequestFor('/quux.txt'); + // Never requested and changed: Don't fetch. + serverUpdate.assertNoRequestFor('/quuux.txt'); + // Previously requested and unchanged: Fetch from cache. + serverUpdate.assertNoRequestFor('/lazy/unchanged1.txt'); + // Never requested and unchanged: Don't fetch. + serverUpdate.assertNoRequestFor('/lazy/unchanged2.txt'); - it('cleans up properly on restart', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + serverUpdate.clearRequests(); - scope = new SwTestHarnessBuilder() - .withCacheState(scope.caches.dehydrate()) - .withServerState(serverUpdate) - .build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - serverUpdate.assertNoOtherRequests(); + // Update client. + await driver.updateClient(await scope.clients.get('default')); - let keys = await scope.caches.keys(); - let hasOriginalCaches = keys.some(name => name.startsWith(`ngsw:/:${manifestHash}:`)); - expect(hasOriginalCaches).toEqual(true); + // Already cached. + expect(await makeRequest(scope, '/quux.txt')).toBe('this is quux v2'); + serverUpdate.assertNoOtherRequests(); - scope.clients.remove('default'); + // Not cached: Fetch from network. + expect(await makeRequest(scope, '/quuux.txt')).toBe('this is quuux v2'); + serverUpdate.assertSawRequestFor('/quuux.txt'); - scope.advance(12000); - await driver.idle.empty; - serverUpdate.clearRequests(); + // Already cached (copied from old cache). + expect(await makeRequest(scope, '/lazy/unchanged1.txt')).toBe('this is unchanged (1)'); + serverUpdate.assertNoOtherRequests(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo v2'); + // Not cached: Fetch from network. + expect(await makeRequest(scope, '/lazy/unchanged2.txt')).toBe('this is unchanged (2)'); + serverUpdate.assertSawRequestFor('/lazy/unchanged2.txt'); - keys = await scope.caches.keys(); - hasOriginalCaches = keys.some(name => name.startsWith(`ngsw:/:${manifestHash}:`)); - expect(hasOriginalCaches).toEqual(false); - }); + serverUpdate.assertNoOtherRequests(); + }); - it('shows notifications for push notifications', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - await scope.handlePush({ - notification: { - title: 'This is a test', - body: 'Test body', - } - }); - expect(scope.notifications).toEqual([{ - title: 'This is a test', - options: {title: 'This is a test', body: 'Test body'}, - }]); - expect(scope.clients.getMock('default') !.messages).toEqual([{ - type: 'PUSH', - data: { - notification: { - title: 'This is a test', - body: 'Test body', - }, - }, - }]); - }); + it('should bypass serviceworker on ngsw-bypass parameter', async () => { + await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypass': 'true'}}); + server.assertNoRequestFor('/foo.txt'); - it('broadcasts notification click events with action', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - await scope.handleClick( - {title: 'This is a test with action', body: 'Test body with action'}, 'button'); - const message: any = scope.clients.getMock('default') !.messages[0]; - - expect(message.type).toEqual('NOTIFICATION_CLICK'); - expect(message.data.action).toEqual('button'); - expect(message.data.notification.title).toEqual('This is a test with action'); - expect(message.data.notification.body).toEqual('Test body with action'); - }); + await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypass': 'anything'}}); + server.assertNoRequestFor('/foo.txt'); - it('broadcasts notification click events without action', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - await scope.handleClick( - {title: 'This is a test without action', body: 'Test body without action'}); - const message: any = scope.clients.getMock('default') !.messages[0]; - - expect(message.type).toEqual('NOTIFICATION_CLICK'); - expect(message.data.action).toBeUndefined(); - expect(message.data.notification.title).toEqual('This is a test without action'); - expect(message.data.notification.body).toEqual('Test body without action'); - }); + await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypass': null!}}); + server.assertNoRequestFor('/foo.txt'); - it('prefetches updates to lazy cache when set', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + await makeRequest(scope, '/foo.txt', undefined, {headers: {'NGSW-bypass': 'upperCASE'}}); + server.assertNoRequestFor('/foo.txt'); - // Fetch some files from the `lazy_prefetch` asset group. - expect(await makeRequest(scope, '/quux.txt')).toEqual('this is quux'); - expect(await makeRequest(scope, '/lazy/unchanged1.txt')).toEqual('this is unchanged (1)'); + await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypasss': 'anything'}}); + server.assertSawRequestFor('/foo.txt'); - // Install update. - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toBe(true); + server.clearRequests(); - // Previously requested and changed: Fetch from network. - serverUpdate.assertSawRequestFor('/quux.txt'); - // Never requested and changed: Don't fetch. - serverUpdate.assertNoRequestFor('/quuux.txt'); - // Previously requested and unchanged: Fetch from cache. - serverUpdate.assertNoRequestFor('/lazy/unchanged1.txt'); - // Never requested and unchanged: Don't fetch. - serverUpdate.assertNoRequestFor('/lazy/unchanged2.txt'); + await makeRequest(scope, '/bar.txt?ngsw-bypass=true'); + server.assertNoRequestFor('/bar.txt'); - serverUpdate.clearRequests(); + await makeRequest(scope, '/bar.txt?ngsw-bypasss=true'); + server.assertSawRequestFor('/bar.txt'); - // Update client. - await driver.updateClient(await scope.clients.get('default')); + server.clearRequests(); - // Already cached. - expect(await makeRequest(scope, '/quux.txt')).toBe('this is quux v2'); - serverUpdate.assertNoOtherRequests(); + await makeRequest(scope, '/bar.txt?ngsw-bypaSS=something'); + server.assertNoRequestFor('/bar.txt'); - // Not cached: Fetch from network. - expect(await makeRequest(scope, '/quuux.txt')).toBe('this is quuux v2'); - serverUpdate.assertSawRequestFor('/quuux.txt'); + await makeRequest(scope, '/bar.txt?testparam=test&ngsw-byPASS=anything'); + server.assertNoRequestFor('/bar.txt'); - // Already cached (copied from old cache). - expect(await makeRequest(scope, '/lazy/unchanged1.txt')).toBe('this is unchanged (1)'); - serverUpdate.assertNoOtherRequests(); + await makeRequest(scope, '/bar.txt?testparam=test&angsw-byPASS=anything'); + server.assertSawRequestFor('/bar.txt'); - // Not cached: Fetch from network. - expect(await makeRequest(scope, '/lazy/unchanged2.txt')).toBe('this is unchanged (2)'); - serverUpdate.assertSawRequestFor('/lazy/unchanged2.txt'); + server.clearRequests(); - serverUpdate.assertNoOtherRequests(); - }); + await makeRequest(scope, '/bar&ngsw-bypass=true.txt?testparam=test&angsw-byPASS=anything'); + server.assertSawRequestFor('/bar&ngsw-bypass=true.txt'); - it('should bypass serviceworker on ngsw-bypass parameter', async() => { - await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypass': 'true'}}); - server.assertNoRequestFor('/foo.txt'); + server.clearRequests(); - await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypass': 'anything'}}); - server.assertNoRequestFor('/foo.txt'); + await makeRequest(scope, '/bar&ngsw-bypass=true.txt'); + server.assertSawRequestFor('/bar&ngsw-bypass=true.txt'); - await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypass': null !}}); - server.assertNoRequestFor('/foo.txt'); + server.clearRequests(); - await makeRequest(scope, '/foo.txt', undefined, {headers: {'NGSW-bypass': 'upperCASE'}}); - server.assertNoRequestFor('/foo.txt'); + await makeRequest( + scope, '/bar&ngsw-bypass=true.txt?testparam=test&ngSW-BYPASS=SOMETHING&testparam2=test'); + server.assertNoRequestFor('/bar&ngsw-bypass=true.txt'); - await makeRequest(scope, '/foo.txt', undefined, {headers: {'ngsw-bypasss': 'anything'}}); - server.assertSawRequestFor('/foo.txt'); + await makeRequest(scope, '/bar?testparam=test&ngsw-bypass'); + server.assertNoRequestFor('/bar'); - server.clearRequests(); + await makeRequest(scope, '/bar?testparam=test&ngsw-bypass&testparam2'); + server.assertNoRequestFor('/bar'); - await makeRequest(scope, '/bar.txt?ngsw-bypass=true'); - server.assertNoRequestFor('/bar.txt'); + await makeRequest(scope, '/bar?ngsw-bypass&testparam2'); + server.assertNoRequestFor('/bar'); - await makeRequest(scope, '/bar.txt?ngsw-bypasss=true'); - server.assertSawRequestFor('/bar.txt'); + await makeRequest(scope, '/bar?ngsw-bypass=&foo=ngsw-bypass'); + server.assertNoRequestFor('/bar'); - server.clearRequests(); + await makeRequest(scope, '/bar?ngsw-byapass&testparam2'); + server.assertSawRequestFor('/bar'); + }); - await makeRequest(scope, '/bar.txt?ngsw-bypaSS=something'); - server.assertNoRequestFor('/bar.txt'); + it('unregisters when manifest 404s', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - await makeRequest(scope, '/bar.txt?testparam=test&ngsw-byPASS=anything'); - server.assertNoRequestFor('/bar.txt'); + scope.updateServerState(server404); + expect(await driver.checkForUpdate()).toEqual(false); + expect(scope.unregistered).toEqual(true); + expect(await scope.caches.keys()).toEqual([]); + }); - await makeRequest(scope, '/bar.txt?testparam=test&angsw-byPASS=anything'); - server.assertSawRequestFor('/bar.txt'); + it('does not unregister or change state when offline (i.e. manifest 504s)', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.online = false; - server.clearRequests(); + expect(await driver.checkForUpdate()).toEqual(false); + expect(driver.state).toEqual(DriverReadyState.NORMAL); + expect(scope.unregistered).toBeFalsy(); + expect(await scope.caches.keys()).not.toEqual([]); + }); - await makeRequest(scope, '/bar&ngsw-bypass=true.txt?testparam=test&angsw-byPASS=anything'); - server.assertSawRequestFor('/bar&ngsw-bypass=true.txt'); + it('does not unregister or change state when status code is 503 (service unavailable)', + async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + spyOn(server, 'fetch').and.callFake(async (req: Request) => new MockResponse(null, { + status: 503, + statusText: 'Service Unavailable' + })); + + expect(await driver.checkForUpdate()).toEqual(false); + expect(driver.state).toEqual(DriverReadyState.NORMAL); + expect(scope.unregistered).toBeFalsy(); + expect(await scope.caches.keys()).not.toEqual([]); + }); + + describe('cache naming', () => { + // Helpers + const cacheKeysFor = (baseHref: string) => + [`ngsw:${baseHref}:db:control`, + `ngsw:${baseHref}:${manifestHash}:assets:assets:cache`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:assets:meta`, + `ngsw:${baseHref}:${manifestHash}:assets:other:cache`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:other:meta`, + `ngsw:${baseHref}:${manifestHash}:assets:lazy_prefetch:cache`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:lazy_prefetch:meta`, + `ngsw:${baseHref}:42:data:dynamic:api:cache`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:42:data:dynamic:api:lru`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:42:data:dynamic:api:age`, + `ngsw:${baseHref}:43:data:dynamic:api-static:cache`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:43:data:dynamic:api-static:lru`, + `ngsw:${baseHref}:db:ngsw:${baseHref}:43:data:dynamic:api-static:age`, + ]; + + const getClientAssignments = async (sw: SwTestHarness, baseHref: string) => { + const cache = await sw.caches.open(`ngsw:${baseHref}:db:control`) as unknown as MockCache; + const dehydrated = cache.dehydrate(); + return JSON.parse(dehydrated['/assignments'].body!); + }; + + const initializeSwFor = + async (baseHref: string, initialCacheState = '{}', serverState = server) => { + const newScope = new SwTestHarnessBuilder(`http://localhost${baseHref}`) + .withCacheState(initialCacheState) + .withServerState(serverState) + .build(); + const newDriver = new Driver(newScope, newScope, new CacheDatabase(newScope, newScope)); + + await makeRequest(newScope, '/foo.txt', baseHref.replace(/\//g, '_')); + await newDriver.initialized; + + return newScope; + }; + + it('includes the SW scope in all cache names', async () => { + // Default SW with scope `/`. + await makeRequest(scope, '/foo.txt'); + await driver.initialized; + const cacheNames = await scope.caches.keys(); - server.clearRequests(); + expect(cacheNames).toEqual(cacheKeysFor('/')); + expect(cacheNames.every(name => name.includes('/'))).toBe(true); - await makeRequest(scope, '/bar&ngsw-bypass=true.txt'); - server.assertSawRequestFor('/bar&ngsw-bypass=true.txt'); + // SW with scope `/foo/`. + const fooScope = await initializeSwFor('/foo/'); + const fooCacheNames = await fooScope.caches.keys(); - server.clearRequests(); + expect(fooCacheNames).toEqual(cacheKeysFor('/foo/')); + expect(fooCacheNames.every(name => name.includes('/foo/'))).toBe(true); + }); - await makeRequest( - scope, '/bar&ngsw-bypass=true.txt?testparam=test&ngSW-BYPASS=SOMETHING&testparam2=test'); - server.assertNoRequestFor('/bar&ngsw-bypass=true.txt'); + it('does not affect caches from other scopes', async () => { + // Create SW with scope `/foo/`. + const fooScope = await initializeSwFor('/foo/'); + const fooAssignments = await getClientAssignments(fooScope, '/foo/'); - await makeRequest(scope, '/bar?testparam=test&ngsw-bypass'); - server.assertNoRequestFor('/bar'); + expect(fooAssignments).toEqual({_foo_: manifestHash}); - await makeRequest(scope, '/bar?testparam=test&ngsw-bypass&testparam2'); - server.assertNoRequestFor('/bar'); + // Add new SW with different scope. + const barScope = await initializeSwFor('/bar/', await fooScope.caches.dehydrate()); + const barCacheNames = await barScope.caches.keys(); + const barAssignments = await getClientAssignments(barScope, '/bar/'); - await makeRequest(scope, '/bar?ngsw-bypass&testparam2'); - server.assertNoRequestFor('/bar'); + expect(barAssignments).toEqual({_bar_: manifestHash}); + expect(barCacheNames).toEqual([ + ...cacheKeysFor('/foo/'), + ...cacheKeysFor('/bar/'), + ]); - await makeRequest(scope, '/bar?ngsw-bypass=&foo=ngsw-bypass'); - server.assertNoRequestFor('/bar'); + // The caches for `/foo/` should be intact. + const fooAssignments2 = await getClientAssignments(barScope, '/foo/'); + expect(fooAssignments2).toEqual({_foo_: manifestHash}); + }); - await makeRequest(scope, '/bar?ngsw-byapass&testparam2'); - server.assertSawRequestFor('/bar'); + it('updates existing caches for same scope', async () => { + // Create SW with scope `/foo/`. + const fooScope = await initializeSwFor('/foo/'); + await makeRequest(fooScope, '/foo.txt', '_bar_'); + const fooAssignments = await getClientAssignments(fooScope, '/foo/'); + expect(fooAssignments).toEqual({ + _foo_: manifestHash, + _bar_: manifestHash, + }); + + expect(await makeRequest(fooScope, '/baz.txt', '_foo_')).toBe('this is baz'); + expect(await makeRequest(fooScope, '/baz.txt', '_bar_')).toBe('this is baz'); + + // Add new SW with same scope. + const fooScope2 = + await initializeSwFor('/foo/', await fooScope.caches.dehydrate(), serverUpdate); + await fooScope2.handleMessage({action: 'CHECK_FOR_UPDATES'}, '_foo_'); + await fooScope2.handleMessage({action: 'ACTIVATE_UPDATE'}, '_foo_'); + const fooAssignments2 = await getClientAssignments(fooScope2, '/foo/'); + + expect(fooAssignments2).toEqual({ + _foo_: manifestUpdateHash, + _bar_: manifestHash, + }); + + // Everything should still work as expected. + expect(await makeRequest(fooScope2, '/foo.txt', '_foo_')).toBe('this is foo v2'); + expect(await makeRequest(fooScope2, '/foo.txt', '_bar_')).toBe('this is foo'); + + expect(await makeRequest(fooScope2, '/baz.txt', '_foo_')).toBe('this is baz v2'); + expect(await makeRequest(fooScope2, '/baz.txt', '_bar_')).toBe('this is baz'); }); + }); - it('unregisters when manifest 404s', async() => { + describe('unhashed requests', () => { + beforeEach(async () => { expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); await driver.initialized; + server.clearRequests(); + }); - scope.updateServerState(server404); - expect(await driver.checkForUpdate()).toEqual(false); - expect(scope.unregistered).toEqual(true); - expect(await scope.caches.keys()).toEqual([]); + it('are cached appropriately', async () => { + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.assertSawRequestFor('/unhashed/a.txt'); + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.assertNoOtherRequests(); }); - it('does not unregister or change state when offline (i.e. manifest 504s)', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.online = false; + it(`doesn't error when 'Cache-Control' is 'no-cache'`, async () => { + expect(await makeRequest(scope, '/unhashed/b.txt')).toEqual('this is unhashed b'); + server.assertSawRequestFor('/unhashed/b.txt'); + expect(await makeRequest(scope, '/unhashed/b.txt')).toEqual('this is unhashed b'); + server.assertNoOtherRequests(); + }); - expect(await driver.checkForUpdate()).toEqual(false); - expect(driver.state).toEqual(DriverReadyState.NORMAL); - expect(scope.unregistered).toBeFalsy(); - expect(await scope.caches.keys()).not.toEqual([]); + it('avoid opaque responses', async () => { + expect(await makeRequest(scope, '/unhashed/a.txt', 'default', { + credentials: 'include' + })).toEqual('this is unhashed'); + server.assertSawRequestFor('/unhashed/a.txt'); + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.assertNoOtherRequests(); }); - it('does not unregister or change state when status code is 503 (service unavailable)', - async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - spyOn(server, 'fetch').and.callFake(async(req: Request) => new MockResponse(null, { - status: 503, - statusText: 'Service Unavailable' - })); - - expect(await driver.checkForUpdate()).toEqual(false); - expect(driver.state).toEqual(DriverReadyState.NORMAL); - expect(scope.unregistered).toBeFalsy(); - expect(await scope.caches.keys()).not.toEqual([]); - }); + it('expire according to Cache-Control headers', async () => { + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.clearRequests(); - describe('cache naming', () => { - // Helpers - const cacheKeysFor = (baseHref: string) => - [`ngsw:${baseHref}:db:control`, `ngsw:${baseHref}:${manifestHash}:assets:assets:cache`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:assets:meta`, - `ngsw:${baseHref}:${manifestHash}:assets:other:cache`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:other:meta`, - `ngsw:${baseHref}:${manifestHash}:assets:lazy_prefetch:cache`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:${manifestHash}:assets:lazy_prefetch:meta`, - `ngsw:${baseHref}:42:data:dynamic:api:cache`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:42:data:dynamic:api:lru`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:42:data:dynamic:api:age`, - `ngsw:${baseHref}:43:data:dynamic:api-static:cache`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:43:data:dynamic:api-static:lru`, - `ngsw:${baseHref}:db:ngsw:${baseHref}:43:data:dynamic:api-static:age`, - ]; + // Update the resource on the server. + scope.updateServerState(serverUpdate); - const getClientAssignments = async(sw: SwTestHarness, baseHref: string) => { - const cache = await sw.caches.open(`ngsw:${baseHref}:db:control`) as unknown as MockCache; - const dehydrated = cache.dehydrate(); - return JSON.parse(dehydrated['/assignments'].body !); - }; - - const initializeSwFor = - async(baseHref: string, initialCacheState = '{}', serverState = server) => { - const newScope = new SwTestHarnessBuilder(`http://localhost${baseHref}`) - .withCacheState(initialCacheState) - .withServerState(serverState) - .build(); - const newDriver = new Driver(newScope, newScope, new CacheDatabase(newScope, newScope)); + // Move ahead by 15 seconds. + scope.advance(15000); - await makeRequest(newScope, '/foo.txt', baseHref.replace(/\//g, '_')); - await newDriver.initialized; + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + serverUpdate.assertNoOtherRequests(); - return newScope; - }; + // Another 6 seconds. + scope.advance(6000); + await driver.idle.empty; + serverUpdate.assertSawRequestFor('/unhashed/a.txt'); - it('includes the SW scope in all cache names', async() => { - // Default SW with scope `/`. - await makeRequest(scope, '/foo.txt'); - await driver.initialized; - const cacheNames = await scope.caches.keys(); + // Now the new version of the resource should be served. + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed v2'); + server.assertNoOtherRequests(); + }); - expect(cacheNames).toEqual(cacheKeysFor('/')); - expect(cacheNames.every(name => name.includes('/'))).toBe(true); + it('survive serialization', async () => { + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.clearRequests(); - // SW with scope `/foo/`. - const fooScope = await initializeSwFor('/foo/'); - const fooCacheNames = await fooScope.caches.keys(); + const state = scope.caches.dehydrate(); + scope = new SwTestHarnessBuilder().withCacheState(state).withServerState(server).build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.assertNoRequestFor('/unhashed/a.txt'); + server.clearRequests(); - expect(fooCacheNames).toEqual(cacheKeysFor('/foo/')); - expect(fooCacheNames.every(name => name.includes('/foo/'))).toBe(true); - }); + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.assertNoOtherRequests(); - it('does not affect caches from other scopes', async() => { - // Create SW with scope `/foo/`. - const fooScope = await initializeSwFor('/foo/'); - const fooAssignments = await getClientAssignments(fooScope, '/foo/'); + // Advance the clock by 6 seconds, triggering the idle tasks. If an idle task + // was scheduled from the request above, it means that the metadata was not + // properly saved. + scope.advance(6000); + await driver.idle.empty; + server.assertNoRequestFor('/unhashed/a.txt'); + }); - expect(fooAssignments).toEqual({_foo_: manifestHash}); + it('get carried over during updates', async () => { + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + server.clearRequests(); - // Add new SW with different scope. - const barScope = await initializeSwFor('/bar/', await fooScope.caches.dehydrate()); - const barCacheNames = await barScope.caches.keys(); - const barAssignments = await getClientAssignments(barScope, '/bar/'); + scope = new SwTestHarnessBuilder() + .withCacheState(scope.caches.dehydrate()) + .withServerState(serverUpdate) + .build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; - expect(barAssignments).toEqual({_bar_: manifestHash}); - expect(barCacheNames).toEqual([ - ...cacheKeysFor('/foo/'), - ...cacheKeysFor('/bar/'), - ]); + scope.advance(15000); + await driver.idle.empty; + serverUpdate.assertNoRequestFor('/unhashed/a.txt'); + serverUpdate.clearRequests(); - // The caches for `/foo/` should be intact. - const fooAssignments2 = await getClientAssignments(barScope, '/foo/'); - expect(fooAssignments2).toEqual({_foo_: manifestHash}); - }); + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); + serverUpdate.assertNoOtherRequests(); - it('updates existing caches for same scope', async() => { - // Create SW with scope `/foo/`. - const fooScope = await initializeSwFor('/foo/'); - await makeRequest(fooScope, '/foo.txt', '_bar_'); - const fooAssignments = await getClientAssignments(fooScope, '/foo/'); - - expect(fooAssignments).toEqual({ - _foo_: manifestHash, - _bar_: manifestHash, - }); - - expect(await makeRequest(fooScope, '/baz.txt', '_foo_')).toBe('this is baz'); - expect(await makeRequest(fooScope, '/baz.txt', '_bar_')).toBe('this is baz'); - - // Add new SW with same scope. - const fooScope2 = - await initializeSwFor('/foo/', await fooScope.caches.dehydrate(), serverUpdate); - await fooScope2.handleMessage({action: 'CHECK_FOR_UPDATES'}, '_foo_'); - await fooScope2.handleMessage({action: 'ACTIVATE_UPDATE'}, '_foo_'); - const fooAssignments2 = await getClientAssignments(fooScope2, '/foo/'); - - expect(fooAssignments2).toEqual({ - _foo_: manifestUpdateHash, - _bar_: manifestHash, - }); - - // Everything should still work as expected. - expect(await makeRequest(fooScope2, '/foo.txt', '_foo_')).toBe('this is foo v2'); - expect(await makeRequest(fooScope2, '/foo.txt', '_bar_')).toBe('this is foo'); - - expect(await makeRequest(fooScope2, '/baz.txt', '_foo_')).toBe('this is baz v2'); - expect(await makeRequest(fooScope2, '/baz.txt', '_bar_')).toBe('this is baz'); - }); - }); + scope.advance(15000); + await driver.idle.empty; + serverUpdate.assertSawRequestFor('/unhashed/a.txt'); - describe('unhashed requests', () => { - beforeEach(async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - }); + expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed v2'); + serverUpdate.assertNoOtherRequests(); + }); + }); - it('are cached appropriately', async() => { - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.assertSawRequestFor('/unhashed/a.txt'); - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.assertNoOtherRequests(); - }); + describe('routing', () => { + const navRequest = (url: string, init = {}) => + makeNavigationRequest(scope, url, undefined, init); - it(`doesn't error when 'Cache-Control' is 'no-cache'`, async() => { - expect(await makeRequest(scope, '/unhashed/b.txt')).toEqual('this is unhashed b'); - server.assertSawRequestFor('/unhashed/b.txt'); - expect(await makeRequest(scope, '/unhashed/b.txt')).toEqual('this is unhashed b'); - server.assertNoOtherRequests(); - }); + beforeEach(async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + }); - it('avoid opaque responses', async() => { - expect(await makeRequest(scope, '/unhashed/a.txt', 'default', { - credentials: 'include' - })).toEqual('this is unhashed'); - server.assertSawRequestFor('/unhashed/a.txt'); - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.assertNoOtherRequests(); - }); + it('redirects to index on a route-like request', async () => { + expect(await navRequest('/baz')).toEqual('this is foo'); + server.assertNoOtherRequests(); + }); - it('expire according to Cache-Control headers', async() => { - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.clearRequests(); + it('redirects to index on a request to the origin URL request', async () => { + expect(await navRequest('http://localhost/')).toEqual('this is foo'); + server.assertNoOtherRequests(); + }); - // Update the resource on the server. - scope.updateServerState(serverUpdate); + it('does not redirect to index on a non-navigation request', async () => { + expect(await navRequest('/baz', {mode: undefined})).toBeNull(); + server.assertSawRequestFor('/baz'); + }); - // Move ahead by 15 seconds. - scope.advance(15000); + it('does not redirect to index on a request that does not accept HTML', async () => { + expect(await navRequest('/baz', {headers: {}})).toBeNull(); + server.assertSawRequestFor('/baz'); - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - serverUpdate.assertNoOtherRequests(); + expect(await navRequest('/qux', {headers: {'Accept': 'text/plain'}})).toBeNull(); + server.assertSawRequestFor('/qux'); + }); - // Another 6 seconds. - scope.advance(6000); - await driver.idle.empty; - serverUpdate.assertSawRequestFor('/unhashed/a.txt'); + it('does not redirect to index on a request with an extension', async () => { + expect(await navRequest('/baz.html')).toBeNull(); + server.assertSawRequestFor('/baz.html'); - // Now the new version of the resource should be served. - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed v2'); - server.assertNoOtherRequests(); - }); + // Only considers the last path segment when checking for a file extension. + expect(await navRequest('/baz.html/qux')).toBe('this is foo'); + server.assertNoOtherRequests(); + }); - it('survive serialization', async() => { - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.clearRequests(); + it('does not redirect to index if the URL contains `__`', async () => { + expect(await navRequest('/baz/x__x')).toBeNull(); + server.assertSawRequestFor('/baz/x__x'); - const state = scope.caches.dehydrate(); - scope = new SwTestHarnessBuilder().withCacheState(state).withServerState(server).build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.assertNoRequestFor('/unhashed/a.txt'); - server.clearRequests(); - - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.assertNoOtherRequests(); - - // Advance the clock by 6 seconds, triggering the idle tasks. If an idle task - // was scheduled from the request above, it means that the metadata was not - // properly saved. - scope.advance(6000); - await driver.idle.empty; - server.assertNoRequestFor('/unhashed/a.txt'); - }); + expect(await navRequest('/baz/x__x/qux')).toBeNull(); + server.assertSawRequestFor('/baz/x__x/qux'); - it('get carried over during updates', async() => { - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - server.clearRequests(); + expect(await navRequest('/baz/__')).toBeNull(); + server.assertSawRequestFor('/baz/__'); - scope = new SwTestHarnessBuilder() - .withCacheState(scope.caches.dehydrate()) - .withServerState(serverUpdate) - .build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; + expect(await navRequest('/baz/__/qux')).toBeNull(); + server.assertSawRequestFor('/baz/__/qux'); + }); - scope.advance(15000); - await driver.idle.empty; - serverUpdate.assertNoRequestFor('/unhashed/a.txt'); + describe('(with custom `navigationUrls`)', () => { + beforeEach(async () => { + scope.updateServerState(serverUpdate); + await driver.checkForUpdate(); serverUpdate.clearRequests(); + }); - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed'); - serverUpdate.assertNoOtherRequests(); + it('redirects to index on a request that matches any positive pattern', async () => { + expect(await navRequest('/foo/file0')).toBeNull(); + serverUpdate.assertSawRequestFor('/foo/file0'); - scope.advance(15000); - await driver.idle.empty; - serverUpdate.assertSawRequestFor('/unhashed/a.txt'); + expect(await navRequest('/foo/file1')).toBe('this is foo v2'); + serverUpdate.assertNoOtherRequests(); - expect(await makeRequest(scope, '/unhashed/a.txt')).toEqual('this is unhashed v2'); + expect(await navRequest('/bar/file2')).toBe('this is foo v2'); serverUpdate.assertNoOtherRequests(); }); - }); - describe('routing', () => { - const navRequest = (url: string, init = {}) => - makeNavigationRequest(scope, url, undefined, init); + it('does not redirect to index on a request that matches any negative pattern', async () => { + expect(await navRequest('/ignored/file1')).toBe('this is not handled by the SW'); + serverUpdate.assertSawRequestFor('/ignored/file1'); - beforeEach(async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - }); - - it('redirects to index on a route-like request', async() => { - expect(await navRequest('/baz')).toEqual('this is foo'); - server.assertNoOtherRequests(); - }); + expect(await navRequest('/ignored/dir/file2')).toBe('this is not handled by the SW either'); + serverUpdate.assertSawRequestFor('/ignored/dir/file2'); - it('redirects to index on a request to the origin URL request', async() => { - expect(await navRequest('http://localhost/')).toEqual('this is foo'); - server.assertNoOtherRequests(); + expect(await navRequest('/ignored/directory/file2')).toBe('this is foo v2'); + serverUpdate.assertNoOtherRequests(); }); - it('does not redirect to index on a non-navigation request', async() => { - expect(await navRequest('/baz', {mode: undefined})).toBeNull(); - server.assertSawRequestFor('/baz'); - }); + it('strips URL query before checking `navigationUrls`', async () => { + expect(await navRequest('/foo/file1?query=/a/b')).toBe('this is foo v2'); + serverUpdate.assertNoOtherRequests(); - it('does not redirect to index on a request that does not accept HTML', async() => { - expect(await navRequest('/baz', {headers: {}})).toBeNull(); - server.assertSawRequestFor('/baz'); + expect(await navRequest('/ignored/file1?query=/a/b')).toBe('this is not handled by the SW'); + serverUpdate.assertSawRequestFor('/ignored/file1'); - expect(await navRequest('/qux', {headers: {'Accept': 'text/plain'}})).toBeNull(); - server.assertSawRequestFor('/qux'); + expect(await navRequest('/ignored/dir/file2?query=/a/b')) + .toBe('this is not handled by the SW either'); + serverUpdate.assertSawRequestFor('/ignored/dir/file2'); }); - it('does not redirect to index on a request with an extension', async() => { - expect(await navRequest('/baz.html')).toBeNull(); - server.assertSawRequestFor('/baz.html'); - - // Only considers the last path segment when checking for a file extension. - expect(await navRequest('/baz.html/qux')).toBe('this is foo'); - server.assertNoOtherRequests(); + it('strips registration scope before checking `navigationUrls`', async () => { + expect(await navRequest('http://localhost/ignored/file1')) + .toBe('this is not handled by the SW'); + serverUpdate.assertSawRequestFor('/ignored/file1'); }); + }); + }); - it('does not redirect to index if the URL contains `__`', async() => { - expect(await navRequest('/baz/x__x')).toBeNull(); - server.assertSawRequestFor('/baz/x__x'); - - expect(await navRequest('/baz/x__x/qux')).toBeNull(); - server.assertSawRequestFor('/baz/x__x/qux'); - - expect(await navRequest('/baz/__')).toBeNull(); - server.assertSawRequestFor('/baz/__'); + describe('cleanupOldSwCaches()', () => { + it('should delete the correct caches', async () => { + const oldSwCacheNames = [ + // Example cache names from the beta versions of `@angular/service-worker`. + 'ngsw:active', + 'ngsw:staged', + 'ngsw:manifest:a1b2c3:super:duper', + // Example cache names from the beta versions of `@angular/service-worker`. + 'ngsw:a1b2c3:assets:foo', + 'ngsw:db:a1b2c3:assets:bar', + ]; + const otherCacheNames = [ + 'ngsuu:active', + 'not:ngsw:active', + 'NgSw:StAgEd', + 'ngsw:/:active', + 'ngsw:/foo/:staged', + ]; + const allCacheNames = oldSwCacheNames.concat(otherCacheNames); - expect(await navRequest('/baz/__/qux')).toBeNull(); - server.assertSawRequestFor('/baz/__/qux'); - }); + await Promise.all(allCacheNames.map(name => scope.caches.open(name))); + expect(await scope.caches.keys()).toEqual(allCacheNames); - describe('(with custom `navigationUrls`)', () => { - beforeEach(async() => { - scope.updateServerState(serverUpdate); - await driver.checkForUpdate(); - serverUpdate.clearRequests(); - }); - - it('redirects to index on a request that matches any positive pattern', async() => { - expect(await navRequest('/foo/file0')).toBeNull(); - serverUpdate.assertSawRequestFor('/foo/file0'); - - expect(await navRequest('/foo/file1')).toBe('this is foo v2'); - serverUpdate.assertNoOtherRequests(); - - expect(await navRequest('/bar/file2')).toBe('this is foo v2'); - serverUpdate.assertNoOtherRequests(); - }); - - it('does not redirect to index on a request that matches any negative pattern', async() => { - expect(await navRequest('/ignored/file1')).toBe('this is not handled by the SW'); - serverUpdate.assertSawRequestFor('/ignored/file1'); - - expect(await navRequest('/ignored/dir/file2')) - .toBe('this is not handled by the SW either'); - serverUpdate.assertSawRequestFor('/ignored/dir/file2'); - - expect(await navRequest('/ignored/directory/file2')).toBe('this is foo v2'); - serverUpdate.assertNoOtherRequests(); - }); - - it('strips URL query before checking `navigationUrls`', async() => { - expect(await navRequest('/foo/file1?query=/a/b')).toBe('this is foo v2'); - serverUpdate.assertNoOtherRequests(); - - expect(await navRequest('/ignored/file1?query=/a/b')) - .toBe('this is not handled by the SW'); - serverUpdate.assertSawRequestFor('/ignored/file1'); - - expect(await navRequest('/ignored/dir/file2?query=/a/b')) - .toBe('this is not handled by the SW either'); - serverUpdate.assertSawRequestFor('/ignored/dir/file2'); - }); - - it('strips registration scope before checking `navigationUrls`', async() => { - expect(await navRequest('http://localhost/ignored/file1')) - .toBe('this is not handled by the SW'); - serverUpdate.assertSawRequestFor('/ignored/file1'); - }); - }); + await driver.cleanupOldSwCaches(); + expect(await scope.caches.keys()).toEqual(otherCacheNames); }); - describe('cleanupOldSwCaches()', () => { - it('should delete the correct caches', async() => { - const oldSwCacheNames = [ - // Example cache names from the beta versions of `@angular/service-worker`. - 'ngsw:active', - 'ngsw:staged', - 'ngsw:manifest:a1b2c3:super:duper', - // Example cache names from the beta versions of `@angular/service-worker`. - 'ngsw:a1b2c3:assets:foo', - 'ngsw:db:a1b2c3:assets:bar', - ]; - const otherCacheNames = [ - 'ngsuu:active', - 'not:ngsw:active', - 'NgSw:StAgEd', - 'ngsw:/:active', - 'ngsw:/foo/:staged', - ]; - const allCacheNames = oldSwCacheNames.concat(otherCacheNames); - - await Promise.all(allCacheNames.map(name => scope.caches.open(name))); - expect(await scope.caches.keys()).toEqual(allCacheNames); - - await driver.cleanupOldSwCaches(); - expect(await scope.caches.keys()).toEqual(otherCacheNames); - }); + it('should delete other caches even if deleting one of them fails', async () => { + const oldSwCacheNames = ['ngsw:active', 'ngsw:staged', 'ngsw:manifest:a1b2c3:super:duper']; + const deleteSpy = + spyOn(scope.caches, 'delete') + .and.callFake( + (cacheName: string) => Promise.reject(`Failed to delete cache '${cacheName}'.`)); - it('should delete other caches even if deleting one of them fails', async() => { - const oldSwCacheNames = ['ngsw:active', 'ngsw:staged', 'ngsw:manifest:a1b2c3:super:duper']; - const deleteSpy = spyOn(scope.caches, 'delete') - .and.callFake( - (cacheName: string) => - Promise.reject(`Failed to delete cache '${cacheName}'.`)); + await Promise.all(oldSwCacheNames.map(name => scope.caches.open(name))); + const error = await driver.cleanupOldSwCaches().catch(err => err); - await Promise.all(oldSwCacheNames.map(name => scope.caches.open(name))); - const error = await driver.cleanupOldSwCaches().catch(err => err); + expect(error).toBe('Failed to delete cache \'ngsw:active\'.'); + expect(deleteSpy).toHaveBeenCalledTimes(3); + oldSwCacheNames.forEach(name => expect(deleteSpy).toHaveBeenCalledWith(name)); + }); + }); - expect(error).toBe('Failed to delete cache \'ngsw:active\'.'); - expect(deleteSpy).toHaveBeenCalledTimes(3); - oldSwCacheNames.forEach(name => expect(deleteSpy).toHaveBeenCalledWith(name)); - }); + describe('bugs', () => { + it('does not crash with bad index hash', async () => { + scope = new SwTestHarnessBuilder().withServerState(brokenServer).build(); + (scope.registration as any).scope = 'http://site.com'; + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo (broken)'); }); - describe('bugs', () => { - it('does not crash with bad index hash', async() => { - scope = new SwTestHarnessBuilder().withServerState(brokenServer).build(); - (scope.registration as any).scope = 'http://site.com'; - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + it('enters degraded mode when update has a bad index', async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo (broken)'); - }); + scope = new SwTestHarnessBuilder() + .withCacheState(scope.caches.dehydrate()) + .withServerState(brokenServer) + .build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); + await driver.checkForUpdate(); - it('enters degraded mode when update has a bad index', async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); + scope.advance(12000); + await driver.idle.empty; - scope = new SwTestHarnessBuilder() - .withCacheState(scope.caches.dehydrate()) - .withServerState(brokenServer) - .build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - await driver.checkForUpdate(); + expect(driver.state).toEqual(DriverReadyState.EXISTING_CLIENTS_ONLY); + }); + + it('enters degraded mode when failing to write to cache', async () => { + // Initialize the SW. + await makeRequest(scope, '/foo.txt'); + await driver.initialized; + expect(driver.state).toBe(DriverReadyState.NORMAL); - scope.advance(12000); - await driver.idle.empty; + server.clearRequests(); - expect(driver.state).toEqual(DriverReadyState.EXISTING_CLIENTS_ONLY); - }); + // Operate normally. + expect(await makeRequest(scope, '/foo.txt')).toBe('this is foo'); + server.assertNoOtherRequests(); - it('enters degraded mode when failing to write to cache', async() => { - // Initialize the SW. - await makeRequest(scope, '/foo.txt'); - await driver.initialized; - expect(driver.state).toBe(DriverReadyState.NORMAL); + // Clear the caches and make them unwritable. + await clearAllCaches(scope.caches); + spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); - server.clearRequests(); + // Enter degraded mode and serve from network. + expect(await makeRequest(scope, '/foo.txt')).toBe('this is foo'); + expect(driver.state).toBe(DriverReadyState.EXISTING_CLIENTS_ONLY); + server.assertSawRequestFor('/foo.txt'); + }); - // Operate normally. - expect(await makeRequest(scope, '/foo.txt')).toBe('this is foo'); - server.assertNoOtherRequests(); + it('keeps serving api requests with freshness strategy when failing to write to cache', + async () => { + // Initialize the SW. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + + // Make the caches unwritable. + spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); + spyOn(driver.debugger, 'log'); + + expect(await makeRequest(scope, '/api/foo')).toEqual('this is api foo'); + expect(driver.state).toBe(DriverReadyState.NORMAL); + // Since we are swallowing an error here, make sure it is at least properly logged + expect(driver.debugger.log) + .toHaveBeenCalledWith( + new Error('Can\'t touch this'), + 'DataGroup(api@42).safeCacheResponse(/api/foo, status: 200)'); + server.assertSawRequestFor('/api/foo'); + }); - // Clear the caches and make them unwritable. - await clearAllCaches(scope.caches); - spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); + it('keeps serving api requests with performance strategy when failing to write to cache', + async () => { + // Initialize the SW. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + + // Make the caches unwritable. + spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); + spyOn(driver.debugger, 'log'); + + expect(await makeRequest(scope, '/api-static/bar')).toEqual('this is static api bar'); + expect(driver.state).toBe(DriverReadyState.NORMAL); + // Since we are swallowing an error here, make sure it is at least properly logged + expect(driver.debugger.log) + .toHaveBeenCalledWith( + new Error('Can\'t touch this'), + 'DataGroup(api-static@43).safeCacheResponse(/api-static/bar, status: 200)'); + server.assertSawRequestFor('/api-static/bar'); + }); - // Enter degraded mode and serve from network. - expect(await makeRequest(scope, '/foo.txt')).toBe('this is foo'); - expect(driver.state).toBe(DriverReadyState.EXISTING_CLIENTS_ONLY); - server.assertSawRequestFor('/foo.txt'); - }); + it('keeps serving mutating api requests when failing to write to cache', + // sw can invalidate LRU cache entry and try to write to cache storage on mutating request + async () => { + // Initialize the SW. + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + server.clearRequests(); + + // Make the caches unwritable. + spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); + spyOn(driver.debugger, 'log'); + expect(await makeRequest(scope, '/api/foo', 'default', { + method: 'post' + })).toEqual('this is api foo'); + expect(driver.state).toBe(DriverReadyState.NORMAL); + // Since we are swallowing an error here, make sure it is at least properly logged + expect(driver.debugger.log) + .toHaveBeenCalledWith(new Error('Can\'t touch this'), 'DataGroup(api@42).syncLru()'); + server.assertSawRequestFor('/api/foo'); + }); - it('keeps serving api requests with freshness strategy when failing to write to cache', - async() => { - // Initialize the SW. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - - // Make the caches unwritable. - spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); - spyOn(driver.debugger, 'log'); - - expect(await makeRequest(scope, '/api/foo')).toEqual('this is api foo'); - expect(driver.state).toBe(DriverReadyState.NORMAL); - // Since we are swallowing an error here, make sure it is at least properly logged - expect(driver.debugger.log) - .toHaveBeenCalledWith( - new Error('Can\'t touch this'), - 'DataGroup(api@42).safeCacheResponse(/api/foo, status: 200)'); - server.assertSawRequestFor('/api/foo'); - }); + it('enters degraded mode when something goes wrong with the latest version', async () => { + await driver.initialized; - it('keeps serving api requests with performance strategy when failing to write to cache', - async() => { - // Initialize the SW. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - - // Make the caches unwritable. - spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); - spyOn(driver.debugger, 'log'); - - expect(await makeRequest(scope, '/api-static/bar')).toEqual('this is static api bar'); - expect(driver.state).toBe(DriverReadyState.NORMAL); - // Since we are swallowing an error here, make sure it is at least properly logged - expect(driver.debugger.log) - .toHaveBeenCalledWith( - new Error('Can\'t touch this'), - 'DataGroup(api-static@43).safeCacheResponse(/api-static/bar, status: 200)'); - server.assertSawRequestFor('/api-static/bar'); - }); + // Two clients on initial version. + expect(await makeRequest(scope, '/foo.txt', 'client1')).toBe('this is foo'); + expect(await makeRequest(scope, '/foo.txt', 'client2')).toBe('this is foo'); - it('keeps serving mutating api requests when failing to write to cache', - // sw can invalidate LRU cache entry and try to write to cache storage on mutating request - async() => { - // Initialize the SW. - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - server.clearRequests(); - - // Make the caches unwritable. - spyOn(MockCache.prototype, 'put').and.throwError('Can\'t touch this'); - spyOn(driver.debugger, 'log'); - expect(await makeRequest(scope, '/api/foo', 'default', { - method: 'post' - })).toEqual('this is api foo'); - expect(driver.state).toBe(DriverReadyState.NORMAL); - // Since we are swallowing an error here, make sure it is at least properly logged - expect(driver.debugger.log) - .toHaveBeenCalledWith(new Error('Can\'t touch this'), 'DataGroup(api@42).syncLru()'); - server.assertSawRequestFor('/api/foo'); - }); + // Install a broken version (`bar.txt` has invalid hash). + scope.updateServerState(brokenLazyServer); + await driver.checkForUpdate(); - it('enters degraded mode when something goes wrong with the latest version', async() => { - await driver.initialized; + // Update `client1` but not `client2`. + await makeNavigationRequest(scope, '/', 'client1'); + server.clearRequests(); + brokenLazyServer.clearRequests(); - // Two clients on initial version. - expect(await makeRequest(scope, '/foo.txt', 'client1')).toBe('this is foo'); - expect(await makeRequest(scope, '/foo.txt', 'client2')).toBe('this is foo'); + expect(await makeRequest(scope, '/foo.txt', 'client1')).toBe('this is foo (broken)'); + expect(await makeRequest(scope, '/foo.txt', 'client2')).toBe('this is foo'); + server.assertNoOtherRequests(); + brokenLazyServer.assertNoOtherRequests(); + + // Trying to fetch `bar.txt` (which has an invalid hash) should invalidate the latest + // version, enter degraded mode and "forget" clients that are on that version (i.e. + // `client1`). + expect(await makeRequest(scope, '/bar.txt', 'client1')).toBe('this is bar (broken)'); + expect(driver.state).toBe(DriverReadyState.EXISTING_CLIENTS_ONLY); + brokenLazyServer.sawRequestFor('/bar.txt'); + brokenLazyServer.clearRequests(); + + // `client1` should not be served from the network. + expect(await makeRequest(scope, '/foo.txt', 'client1')).toBe('this is foo (broken)'); + brokenLazyServer.sawRequestFor('/foo.txt'); + + // `client2` should still be served from the old version (since it never updated). + expect(await makeRequest(scope, '/foo.txt', 'client2')).toBe('this is foo'); + server.assertNoOtherRequests(); + brokenLazyServer.assertNoOtherRequests(); + }); - // Install a broken version (`bar.txt` has invalid hash). - scope.updateServerState(brokenLazyServer); - await driver.checkForUpdate(); + it('recovers from degraded `EXISTING_CLIENTS_ONLY` mode as soon as there is a valid update', + async () => { + await driver.initialized; + expect(driver.state).toBe(DriverReadyState.NORMAL); - // Update `client1` but not `client2`. - await makeNavigationRequest(scope, '/', 'client1'); - server.clearRequests(); - brokenLazyServer.clearRequests(); - - expect(await makeRequest(scope, '/foo.txt', 'client1')).toBe('this is foo (broken)'); - expect(await makeRequest(scope, '/foo.txt', 'client2')).toBe('this is foo'); - server.assertNoOtherRequests(); - brokenLazyServer.assertNoOtherRequests(); - - // Trying to fetch `bar.txt` (which has an invalid hash) should invalidate the latest - // version, enter degraded mode and "forget" clients that are on that version (i.e. - // `client1`). - expect(await makeRequest(scope, '/bar.txt', 'client1')).toBe('this is bar (broken)'); - expect(driver.state).toBe(DriverReadyState.EXISTING_CLIENTS_ONLY); - brokenLazyServer.sawRequestFor('/bar.txt'); - brokenLazyServer.clearRequests(); - - // `client1` should not be served from the network. - expect(await makeRequest(scope, '/foo.txt', 'client1')).toBe('this is foo (broken)'); - brokenLazyServer.sawRequestFor('/foo.txt'); - - // `client2` should still be served from the old version (since it never updated). - expect(await makeRequest(scope, '/foo.txt', 'client2')).toBe('this is foo'); - server.assertNoOtherRequests(); - brokenLazyServer.assertNoOtherRequests(); - }); + // Install a broken version. + scope.updateServerState(brokenServer); + await driver.checkForUpdate(); + expect(driver.state).toBe(DriverReadyState.EXISTING_CLIENTS_ONLY); - it('recovers from degraded `EXISTING_CLIENTS_ONLY` mode as soon as there is a valid update', - async() => { - await driver.initialized; - expect(driver.state).toBe(DriverReadyState.NORMAL); + // Install a good version. + scope.updateServerState(serverUpdate); + await driver.checkForUpdate(); + expect(driver.state).toBe(DriverReadyState.NORMAL); + }); - // Install a broken version. - scope.updateServerState(brokenServer); - await driver.checkForUpdate(); - expect(driver.state).toBe(DriverReadyState.EXISTING_CLIENTS_ONLY); + it('ignores invalid `only-if-cached` requests ', async () => { + const requestFoo = (cache: RequestCache|'only-if-cached', mode: RequestMode) => + makeRequest(scope, '/foo.txt', undefined, {cache, mode}); - // Install a good version. - scope.updateServerState(serverUpdate); - await driver.checkForUpdate(); - expect(driver.state).toBe(DriverReadyState.NORMAL); - }); + expect(await requestFoo('default', 'no-cors')).toBe('this is foo'); + expect(await requestFoo('only-if-cached', 'same-origin')).toBe('this is foo'); + expect(await requestFoo('only-if-cached', 'no-cors')).toBeNull(); + }); - it('ignores invalid `only-if-cached` requests ', async() => { - const requestFoo = (cache: RequestCache | 'only-if-cached', mode: RequestMode) => - makeRequest(scope, '/foo.txt', undefined, {cache, mode}); + it('ignores passive mixed content requests ', async () => { + const scopeFetchSpy = spyOn(scope, 'fetch').and.callThrough(); + const getRequestUrls = () => + (scopeFetchSpy.calls.allArgs() as [Request][]).map(args => args[0].url); - expect(await requestFoo('default', 'no-cors')).toBe('this is foo'); - expect(await requestFoo('only-if-cached', 'same-origin')).toBe('this is foo'); - expect(await requestFoo('only-if-cached', 'no-cors')).toBeNull(); - }); + const httpScopeUrl = 'http://mock.origin.dev'; + const httpsScopeUrl = 'https://mock.origin.dev'; + const httpRequestUrl = 'http://other.origin.sh/unknown.png'; + const httpsRequestUrl = 'https://other.origin.sh/unknown.pnp'; - it('ignores passive mixed content requests ', async() => { - const scopeFetchSpy = spyOn(scope, 'fetch').and.callThrough(); - const getRequestUrls = () => - (scopeFetchSpy.calls.allArgs() as[Request][]).map(args => args[0].url); + // Registration scope: `http:` + (scope.registration.scope as string) = httpScopeUrl; - const httpScopeUrl = 'http://mock.origin.dev'; - const httpsScopeUrl = 'https://mock.origin.dev'; - const httpRequestUrl = 'http://other.origin.sh/unknown.png'; - const httpsRequestUrl = 'https://other.origin.sh/unknown.pnp'; + await makeRequest(scope, httpRequestUrl); + await makeRequest(scope, httpsRequestUrl); + const requestUrls1 = getRequestUrls(); - // Registration scope: `http:` - (scope.registration.scope as string) = httpScopeUrl; + expect(requestUrls1).toContain(httpRequestUrl); + expect(requestUrls1).toContain(httpsRequestUrl); - await makeRequest(scope, httpRequestUrl); - await makeRequest(scope, httpsRequestUrl); - const requestUrls1 = getRequestUrls(); + scopeFetchSpy.calls.reset(); - expect(requestUrls1).toContain(httpRequestUrl); - expect(requestUrls1).toContain(httpsRequestUrl); + // Registration scope: `https:` + (scope.registration.scope as string) = httpsScopeUrl; - scopeFetchSpy.calls.reset(); + await makeRequest(scope, httpRequestUrl); + await makeRequest(scope, httpsRequestUrl); + const requestUrls2 = getRequestUrls(); - // Registration scope: `https:` - (scope.registration.scope as string) = httpsScopeUrl; + expect(requestUrls2).not.toContain(httpRequestUrl); + expect(requestUrls2).toContain(httpsRequestUrl); + }); - await makeRequest(scope, httpRequestUrl); - await makeRequest(scope, httpsRequestUrl); - const requestUrls2 = getRequestUrls(); + describe('backwards compatibility with v5', () => { + beforeEach(() => { + const serverV5 = new MockServerStateBuilder() + .withStaticFiles(dist) + .withManifest(<Manifest>manifestOld) + .build(); - expect(requestUrls2).not.toContain(httpRequestUrl); - expect(requestUrls2).toContain(httpsRequestUrl); + scope = new SwTestHarnessBuilder().withServerState(serverV5).build(); + driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); }); - describe('backwards compatibility with v5', () => { - beforeEach(() => { - const serverV5 = new MockServerStateBuilder() - .withStaticFiles(dist) - .withManifest(<Manifest>manifestOld) - .build(); - - scope = new SwTestHarnessBuilder().withServerState(serverV5).build(); - driver = new Driver(scope, scope, new CacheDatabase(scope, scope)); - }); - - // Test this bug: https://github.com/angular/angular/issues/27209 - it('fills previous versions of manifests with default navigation urls for backwards compatibility', - async() => { - expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); - await driver.initialized; - scope.updateServerState(serverUpdate); - expect(await driver.checkForUpdate()).toEqual(true); - }); - }); + // Test this bug: https://github.com/angular/angular/issues/27209 + it('fills previous versions of manifests with default navigation urls for backwards compatibility', + async () => { + expect(await makeRequest(scope, '/foo.txt')).toEqual('this is foo'); + await driver.initialized; + scope.updateServerState(serverUpdate); + expect(await driver.checkForUpdate()).toEqual(true); + }); }); }); +}); })(); async function makeRequest( - scope: SwTestHarness, url: string, clientId: string | null = 'default', init?: Object): - Promise<string|null> { - const [resPromise, done] = scope.handleFetch(new MockRequest(url, init), clientId); - await done; - const res = await resPromise; - if (res !== undefined && res.ok) { - return res.text(); - } - return null; - } + scope: SwTestHarness, url: string, clientId: string|null = 'default', + init?: Object): Promise<string|null> { + const [resPromise, done] = scope.handleFetch(new MockRequest(url, init), clientId); + await done; + const res = await resPromise; + if (res !== undefined && res.ok) { + return res.text(); + } + return null; +} function makeNavigationRequest( - scope: SwTestHarness, url: string, clientId?: string | null, init: Object = {}): - Promise<string|null> { - return makeRequest(scope, url, clientId, { - headers: { - Accept: 'text/plain, text/html, text/css', - ...(init as any).headers, - }, - mode: 'navigate', ...init, - }); - } + scope: SwTestHarness, url: string, clientId?: string|null, + init: Object = {}): Promise<string|null> { + return makeRequest(scope, url, clientId, { + headers: { + Accept: 'text/plain, text/html, text/css', + ...(init as any).headers, + }, + mode: 'navigate', + ...init, + }); +} diff --git a/packages/upgrade/src/dynamic/test/upgrade_spec.ts b/packages/upgrade/src/dynamic/test/upgrade_spec.ts index 981690fe34c9a..71f6ed9fece6c 100644 --- a/packages/upgrade/src/dynamic/test/upgrade_spec.ts +++ b/packages/upgrade/src/dynamic/test/upgrade_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, Component, EventEmitter, Input, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory, NgZone, OnChanges, OnDestroy, Output, SimpleChange, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core'; +import {ChangeDetectorRef, Component, destroyPlatform, EventEmitter, forwardRef, Input, NgModule, NgModuleFactory, NgZone, NO_ERRORS_SCHEMA, OnChanges, OnDestroy, Output, SimpleChange, SimpleChanges, Testability} from '@angular/core'; import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; @@ -23,7 +23,6 @@ declare global { withEachNg1Version(() => { describe('adapter: ng1 to ng2', () => { - beforeEach(() => destroyPlatform()); afterEach(() => destroyPlatform()); @@ -232,7 +231,9 @@ withEachNg1Version(() => { }) class Ng2 { l: any; - constructor() { this.l = l; } + constructor() { + this.l = l; + } } @NgModule({ @@ -262,7 +263,9 @@ withEachNg1Version(() => { @Component({selector: 'my-app', template: '<my-child [value]="value"></my-child>'}) class AppComponent { value?: number; - constructor() { appComponent = this; } + constructor() { + appComponent = this; + } } @Component({ @@ -272,7 +275,9 @@ withEachNg1Version(() => { class ChildComponent { valueFromPromise?: number; @Input() - set value(v: number) { expect(NgZone.isInAngularZone()).toBe(true); } + set value(v: number) { + expect(NgZone.isInAngularZone()).toBe(true); + } constructor(private zone: NgZone) {} @@ -352,14 +357,15 @@ withEachNg1Version(() => { const element = html('<ng2></ng2>'); adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent !)).toBe('It works'); + expect(multiTrim(document.body.textContent!)).toBe('It works'); }); })); it('should bind properties, events', async(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); - const ng1Module = - angular.module_('ng1', []).value($EXCEPTION_HANDLER, (err: any) => { throw err; }); + const ng1Module = angular.module_('ng1', []).value($EXCEPTION_HANDLER, (err: any) => { + throw err; + }); ng1Module.run(($rootScope: any) => { $rootScope.name = 'world'; @@ -409,8 +415,8 @@ withEachNg1Version(() => { } const actValue = changes[prop].currentValue; if (actValue != value) { - throw new Error( - `Expected changes record for'${prop}' to be '${value}' but was '${actValue}'`); + throw new Error(`Expected changes record for'${prop}' to be '${ + value}' but was '${actValue}'`); } }; @@ -458,7 +464,7 @@ withEachNg1Version(() => { | modelA: {{modelA}}; modelB: {{modelB}}; eventA: {{eventA}}; eventB: {{eventB}}; </div>`); adapter.bootstrap(element, ['ng1']).ready((ref) => { - expect(multiTrim(document.body.textContent !)) + expect(multiTrim(document.body.textContent!)) .toEqual( 'ignore: -; ' + 'literal: Text; interpolate: Hello world; ' + @@ -466,7 +472,7 @@ withEachNg1Version(() => { 'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;'); ref.ng1RootScope.$apply('name = "everyone"'); - expect(multiTrim(document.body.textContent !)) + expect(multiTrim(document.body.textContent!)) .toEqual( 'ignore: -; ' + 'literal: Text; interpolate: Hello everyone; ' + @@ -475,7 +481,6 @@ withEachNg1Version(() => { ref.dispose(); }); - })); it('should support two-way binding and event listener', async(() => { @@ -541,9 +546,9 @@ withEachNg1Version(() => { ngOnChangesCount = 0; firstChangesCount = 0; // TODO(issue/24571): remove '!'. - initialValue !: string; + initialValue!: string; // TODO(issue/24571): remove '!'. - @Input() foo !: string; + @Input() foo!: string; ngOnChanges(changes: SimpleChanges) { this.ngOnChangesCount++; @@ -590,7 +595,9 @@ withEachNg1Version(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module_('ng1', []); - ng1Module.run(($rootScope: any /** TODO #9100 */) => { $rootScope.modelA = 'A'; }); + ng1Module.run(($rootScope: any /** TODO #9100 */) => { + $rootScope.modelA = 'A'; + }); let ng2Instance: Ng2; @Component({selector: 'ng2', template: '{{_value}}'}) @@ -598,11 +605,21 @@ withEachNg1Version(() => { private _value: any = ''; private _onChangeCallback: (_: any) => void = () => {}; private _onTouchedCallback: () => void = () => {}; - constructor() { ng2Instance = this; } - writeValue(value: any) { this._value = value; } - registerOnChange(fn: any) { this._onChangeCallback = fn; } - registerOnTouched(fn: any) { this._onTouchedCallback = fn; } - doTouch() { this._onTouchedCallback(); } + constructor() { + ng2Instance = this; + } + writeValue(value: any) { + this._value = value; + } + registerOnChange(fn: any) { + this._onChangeCallback = fn; + } + registerOnTouched(fn: any) { + this._onTouchedCallback = fn; + } + doTouch() { + this._onTouchedCallback(); + } doChange(newValue: string) { this._value = newValue; this._onChangeCallback(newValue); @@ -653,14 +670,18 @@ withEachNg1Version(() => { return { template: '<div ng-if="!destroyIt"><ng2></ng2></div>', controller: function($rootScope: any, $timeout: Function) { - $timeout(() => { $rootScope.destroyIt = true; }); + $timeout(() => { + $rootScope.destroyIt = true; + }); } }; }); @Component({selector: 'ng2', template: 'test'}) class Ng2 { - ngOnDestroy() { onDestroyed.emit('destroyed'); } + ngOnDestroy() { + onDestroyed.emit('destroyed'); + } } @NgModule({ @@ -673,7 +694,9 @@ withEachNg1Version(() => { ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2)); const element = html('<ng1></ng1>'); adapter.bootstrap(element, ['ng1']).ready((ref) => { - onDestroyed.subscribe(() => { ref.dispose(); }); + onDestroyed.subscribe(() => { + ref.dispose(); + }); }); })); @@ -689,7 +712,9 @@ withEachNg1Version(() => { @Component({selector: 'ng2-inner', template: 'test'}) class Ng2InnerComponent implements OnDestroy { - ngOnDestroy() { destroyed = true; } + ngOnDestroy() { + destroyed = true; + } } @NgModule({ @@ -789,7 +814,7 @@ withEachNg1Version(() => { @Component({selector: 'ng2', template: 'ng2-{{ itemId }}(<ng-content></ng-content>)'}) class Ng2Component { // TODO(issue/24571): remove '!'. - @Input() itemId !: string; + @Input() itemId!: string; } @NgModule({imports: [BrowserModule], declarations: [Ng2Component]}) @@ -838,7 +863,7 @@ withEachNg1Version(() => { ng1Module.directive('rootComponent', adapter.downgradeNg2Component(RootComponent)); document.body.innerHTML = '<root-component></root-component>'; - adapter.bootstrap(document.body.firstElementChild !, ['myExample']).ready((ref) => { + adapter.bootstrap(document.body.firstElementChild!, ['myExample']).ready((ref) => { expect(multiTrim(document.body.textContent)).toEqual('It works!'); ref.dispose(); }); @@ -868,7 +893,9 @@ withEachNg1Version(() => { dataA = 'foo'; dataB = 'bar'; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -888,8 +915,8 @@ withEachNg1Version(() => { const element = html(`<ng2></ng2>`); adapter.bootstrap(element, ['ng1Module']).ready(ref => { - const ng1 = element.querySelector('ng1') !; - const ng1Controller = angular.element(ng1).controller !('ng1'); + const ng1 = element.querySelector('ng1')!; + const ng1Controller = angular.element(ng1).controller!('ng1'); expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); @@ -932,7 +959,9 @@ withEachNg1Version(() => { dataA = {value: 'foo'}; dataB = {value: 'bar'}; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -952,8 +981,8 @@ withEachNg1Version(() => { const element = html(`<ng2></ng2>`); adapter.bootstrap(element, ['ng1Module']).ready(ref => { - const ng1 = element.querySelector('ng1') !; - const ng1Controller = angular.element(ng1).controller !('ng1'); + const ng1 = element.querySelector('ng1')!; + const ng1Controller = angular.element(ng1).controller!('ng1'); expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); @@ -996,7 +1025,9 @@ withEachNg1Version(() => { dataA = {value: 'foo'}; dataB = {value: 'bar'}; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -1016,8 +1047,8 @@ withEachNg1Version(() => { const element = html(`<ng2></ng2>`); adapter.bootstrap(element, ['ng1Module']).ready(ref => { - const ng1 = element.querySelector('ng1') !; - const ng1Controller = angular.element(ng1).controller !('ng1'); + const ng1 = element.querySelector('ng1')!; + const ng1Controller = angular.element(ng1).controller!('ng1'); expect(multiTrim(element.textContent)).toBe('Inside: foo, bar | Outside: foo, bar'); @@ -1077,8 +1108,8 @@ withEachNg1Version(() => { const element = html(`<ng2></ng2>`); adapter.bootstrap(element, ['ng1Module']).ready(ref => { - const ng1 = element.querySelector('ng1') !; - const ng1Controller = angular.element(ng1).controller !('ng1'); + const ng1 = element.querySelector('ng1')!; + const ng1Controller = angular.element(ng1).controller!('ng1'); expect(multiTrim(element.textContent)).toBe('Inside: - | Outside: foo, bar'); @@ -1204,7 +1235,9 @@ withEachNg1Version(() => { restrict: 'E', template: '{{someText}} - Length: {{data.length}}', scope: {data: '='}, - controller: function($scope: any) { $scope.someText = 'ng1 - Data: ' + $scope.data; } + controller: function($scope: any) { + $scope.someText = 'ng1 - Data: ' + $scope.data; + } }; }; @@ -1248,7 +1281,9 @@ withEachNg1Version(() => { restrict: 'E', template: '{{someText}} - Length: {{data.length}}', scope: {data: '='}, - link: function($scope: any) { $scope.someText = 'ng1 - Data: ' + $scope.data; } + link: function($scope: any) { + $scope.someText = 'ng1 - Data: ' + $scope.data; + } }; }; @@ -1291,7 +1326,9 @@ withEachNg1Version(() => { cbFn(200, `${method}:${url}`); }); - const ng1 = () => { return {templateUrl: 'url.html'}; }; + const ng1 = () => { + return {templateUrl: 'url.html'}; + }; ng1Module.directive('ng1', ng1); @Component({selector: 'ng2', template: '<ng1></ng1>'}) class Ng2 { @@ -1320,7 +1357,13 @@ withEachNg1Version(() => { cbFn(200, `${method}:${url}`); }); - const ng1 = () => { return {templateUrl() { return 'url.html'; }}; }; + const ng1 = () => { + return { + templateUrl() { + return 'url.html'; + } + }; + }; ng1Module.directive('ng1', ng1); @Component({selector: 'ng2', template: '<ng1></ng1>'}) class Ng2 { @@ -1345,7 +1388,9 @@ withEachNg1Version(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module_('ng1', []); - const ng1 = () => { return {template: ''}; }; + const ng1 = () => { + return {template: ''}; + }; ng1Module.directive('ng1', ng1); @Component({selector: 'ng2', template: '<ng1></ng1>'}) @@ -1371,7 +1416,13 @@ withEachNg1Version(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module_('ng1', []); - const ng1 = () => { return {template() { return ''; }}; }; + const ng1 = () => { + return { + template() { + return ''; + } + }; + }; ng1Module.directive('ng1', ng1); @Component({selector: 'ng2', template: '<ng1></ng1>'}) @@ -1398,7 +1449,9 @@ withEachNg1Version(() => { const ng1Module = angular.module_('ng1', []); ng1Module.run(($templateCache: any) => $templateCache.put('url.html', 'WORKS')); - const ng1 = () => { return {templateUrl: 'url.html'}; }; + const ng1 = () => { + return {templateUrl: 'url.html'}; + }; ng1Module.directive('ng1', ng1); @Component({selector: 'ng2', template: '<ng1></ng1>'}) @@ -1431,13 +1484,20 @@ withEachNg1Version(() => { '{{ctl.scope}}; {{ctl.isClass}}; {{ctl.hasElement}}; {{ctl.isPublished()}}', controllerAs: 'ctl', controller: class { - scope: any; hasElement: string; $element: any; isClass: any; + scope: any; + hasElement: string; + $element: any; + isClass: any; constructor($scope: any, $element: any) { this.verifyIAmAClass(); this.scope = $scope.$parent.$parent == $scope.$root ? 'scope' : 'wrong-scope'; this.hasElement = $element[0].nodeName; this.$element = $element; - } verifyIAmAClass() { this.isClass = 'isClass'; } isPublished() { + } + verifyIAmAClass() { + this.isClass = 'isClass'; + } + isPublished() { return this.$element.controller('ng1') == this ? 'published' : 'not-published'; } } @@ -1543,7 +1603,9 @@ withEachNg1Version(() => { template: '{{ctl.status}}', require: 'ng1', controllerAs: 'ctrl', - controller: class {status = 'WORKS';}, + controller: class { + status = 'WORKS'; + }, link: function(scope: any, element: any, attrs: any, linkController: any) { expect(scope.$root).toEqual($rootScope); expect(element[0].nodeName).toEqual('NG1'); @@ -1577,7 +1639,13 @@ withEachNg1Version(() => { const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module)); const ng1Module = angular.module_('ng1', []); - const parent = () => { return {controller: class {parent = 'PARENT';}}; }; + const parent = () => { + return { + controller: class { + parent = 'PARENT'; + } + }; + }; const ng1 = () => { return { scope: {title: '@'}, @@ -1585,7 +1653,9 @@ withEachNg1Version(() => { template: '{{parent.parent}}:{{ng1.status}}', require: ['ng1', '^parent', '?^^notFound'], controllerAs: 'ctrl', - controller: class {status = 'WORKS';}, + controller: class { + status = 'WORKS'; + }, link: function(scope: any, element: any, attrs: any, linkControllers: any) { expect(linkControllers[0].status).toEqual('WORKS'); expect(linkControllers[1].parent).toEqual('PARENT'); @@ -1633,16 +1703,21 @@ withEachNg1Version(() => { scope: {}, bindToController: true, controllerAs: '$ctrl', - controller: class {$onInit() { $onInitSpyA(); }} + controller: class { + $onInit() { + $onInitSpyA(); + } + } + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function(this: any) { + this.$onInit = $onInitSpyB; + } })) - .directive( - 'ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function(this: any) { this.$onInit = $onInitSpyB; } - })) .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); @NgModule({ @@ -1718,7 +1793,9 @@ withEachNg1Version(() => { @Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'}) class Ng2Component { - constructor(cd: ChangeDetectorRef) { changeDetector = cd; } + constructor(cd: ChangeDetectorRef) { + changeDetector = cd; + } } angular.module_('ng1', []) @@ -1727,16 +1804,21 @@ withEachNg1Version(() => { scope: {}, bindToController: true, controllerAs: '$ctrl', - controller: class {$doCheck() { $doCheckSpyA(); }} + controller: class { + $doCheck() { + $doCheckSpyA(); + } + } + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function(this: any) { + this.$doCheck = $doCheckSpyB; + } })) - .directive( - 'ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function(this: any) { this.$doCheck = $doCheckSpyB; } - })) .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); @NgModule({ @@ -1773,7 +1855,9 @@ withEachNg1Version(() => { @Component({selector: 'ng2', template: '<ng1-a></ng1-a> | <ng1-b></ng1-b>'}) class Ng2Component { - constructor(cd: ChangeDetectorRef) { changeDetector = cd; } + constructor(cd: ChangeDetectorRef) { + changeDetector = cd; + } } angular.module_('ng1', []) @@ -1835,16 +1919,21 @@ withEachNg1Version(() => { scope: {}, bindToController: true, controllerAs: '$ctrl', - controller: class {$postLink() { $postLinkSpyA(); }} + controller: class { + $postLink() { + $postLinkSpyA(); + } + } + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function(this: any) { + this.$postLink = $postLinkSpyB; + } })) - .directive( - 'ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function(this: any) { this.$postLink = $postLinkSpyB; } - })) .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); @NgModule({ @@ -1924,7 +2013,9 @@ withEachNg1Version(() => { template: '<ng1-a [valA]="val"></ng1-a> | <ng1-b [valB]="val"></ng1-b>' }) class Ng2Component { - constructor() { ng2Instance = this; } + constructor() { + ng2Instance = this; + } } angular.module_('ng1', []) @@ -1937,17 +2028,17 @@ withEachNg1Version(() => { this.$onChanges = $onChangesControllerSpyA; } })) - .directive( - 'ng1B', - () => ({ - template: '', - scope: {valB: '<'}, - bindToController: false, - controllerAs: '$ctrl', - controller: class { - $onChanges(changes: SimpleChanges) { $onChangesControllerSpyB(changes); } - } - })) + .directive('ng1B', () => ({ + template: '', + scope: {valB: '<'}, + bindToController: false, + controllerAs: '$ctrl', + controller: class { + $onChanges(changes: SimpleChanges) { + $onChangesControllerSpyB(changes); + } + } + })) .directive('ng2', adapter.downgradeNg2Component(Ng2Component)) .run(($rootScope: angular.IRootScopeService) => { Object.getPrototypeOf($rootScope).$onChanges = $onChangesScopeSpy; @@ -2022,7 +2113,9 @@ withEachNg1Version(() => { }) class Ng2Component { ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), @@ -2036,16 +2129,21 @@ withEachNg1Version(() => { scope: {}, bindToController: true, controllerAs: '$ctrl', - controller: class {$onDestroy() { $onDestroySpyA(); }} + controller: class { + $onDestroy() { + $onDestroySpyA(); + } + } + })) + .directive('ng1B', () => ({ + template: '', + scope: {}, + bindToController: false, + controllerAs: '$ctrl', + controller: function(this: any) { + this.$onDestroy = $onDestroySpyB; + } })) - .directive( - 'ng1B', () => ({ - template: '', - scope: {}, - bindToController: false, - controllerAs: '$ctrl', - controller: function(this: any) { this.$onDestroy = $onDestroySpyB; } - })) .directive('ng2', adapter.downgradeNg2Component(Ng2Component)); @NgModule({ @@ -2112,7 +2210,9 @@ withEachNg1Version(() => { }) class Ng2Component { ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), @@ -2187,7 +2287,9 @@ withEachNg1Version(() => { @Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'}) class Ng2Component { ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), @@ -2233,7 +2335,9 @@ withEachNg1Version(() => { @Component({selector: 'ng2', template: '<div *ngIf="!ng2Destroy"><ng1></ng1></div>'}) class Ng2Component { ng2Destroy: boolean = false; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // On browsers that don't support `requestAnimationFrame` (IE 9, Android <= 4.3), @@ -2245,8 +2349,8 @@ withEachNg1Version(() => { .component('ng1', { controller: class { constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { - this.$element.on !('$destroy', elementDestroyListener); - this.$element.contents !().on !('$destroy', descendantDestroyListener); + this.$element.on!('$destroy', elementDestroyListener); + this.$element.contents!().on!('$destroy', descendantDestroyListener); } }, template: '<div></div>' @@ -2287,8 +2391,8 @@ withEachNg1Version(() => { const ng1Component: angular.IComponent = { controller: class { constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { - this.$element.data !('test', 1); - this.$element.contents !().data !('test', 2); + this.$element.data!('test', 1); + this.$element.contents!().data!('test', 2); ng1ComponentElement = this.$element; } @@ -2301,7 +2405,9 @@ withEachNg1Version(() => { class Ng2ComponentA { destroyIt = false; - constructor() { ng2ComponentAInstance = this; } + constructor() { + ng2ComponentAInstance = this; + } } @Component({selector: 'ng2B', template: '<ng1></ng1>'}) @@ -2330,15 +2436,15 @@ withEachNg1Version(() => { const $rootScope = ref.ng1RootScope as any; tick(); $rootScope.$digest(); - expect(ng1ComponentElement.data !('test')).toBe(1); - expect(ng1ComponentElement.contents !().data !('test')).toBe(2); + expect(ng1ComponentElement.data!('test')).toBe(1); + expect(ng1ComponentElement.contents!().data!('test')).toBe(2); ng2ComponentAInstance.destroyIt = true; tick(); $rootScope.$digest(); - expect(ng1ComponentElement.data !('test')).toBeUndefined(); - expect(ng1ComponentElement.contents !().data !('test')).toBeUndefined(); + expect(ng1ComponentElement.data!('test')).toBeUndefined(); + expect(ng1ComponentElement.contents!().data!('test')).toBeUndefined(); }); })); @@ -2353,10 +2459,10 @@ withEachNg1Version(() => { const ng1Component: angular.IComponent = { controller: class { constructor(private $element: angular.IAugmentedJQuery) {} $onInit() { - ng1DescendantElement = this.$element.contents !(); + ng1DescendantElement = this.$element.contents!(); - this.$element.on !('click', elementClickListener); - ng1DescendantElement.on !('click', descendantClickListener); + this.$element.on!('click', elementClickListener); + ng1DescendantElement.on!('click', descendantClickListener); } }, template: '<div></div>' @@ -2367,7 +2473,9 @@ withEachNg1Version(() => { class Ng2ComponentA { destroyIt = false; - constructor() { ng2ComponentAInstance = this; } + constructor() { + ng2ComponentAInstance = this; + } } @Component({selector: 'ng2B', template: '<ng1></ng1>'}) @@ -2420,7 +2528,11 @@ withEachNg1Version(() => { const ng1Directive: angular.IDirective = { template: '', link: {pre: () => log.push('ng1-pre')}, - controller: class {constructor() { log.push('ng1-ctrl'); }} + controller: class { + constructor() { + log.push('ng1-ctrl'); + } + } }; // Define `Ng2Component` @@ -2577,7 +2689,11 @@ withEachNg1Version(() => { const ng1Directive: angular.IDirective = { template: '', link: () => log.push('ng1-post'), - controller: class {$postLink() { log.push('ng1-$post'); }} + controller: class { + $postLink() { + log.push('ng1-$post'); + } + } }; // Define `Ng2Component` @@ -2627,13 +2743,17 @@ withEachNg1Version(() => { class Ng2ComponentA { value = 'foo'; showB = false; - constructor() { ng2ComponentAInstance = this; } + constructor() { + ng2ComponentAInstance = this; + } } @Component({selector: 'ng2B', template: 'ng2B({{ value }})'}) class Ng2ComponentB { value = 'bar'; - constructor() { ng2ComponentBInstance = this; } + constructor() { + ng2ComponentBInstance = this; + } } // Define `ng1Module` @@ -2678,7 +2798,10 @@ withEachNg1Version(() => { template: 'ng1(<div ng-transclude>{{ $ctrl.value }}</div>)', transclude: true, controller: class { - value = 'from-ng1'; constructor() { ng1ControllerInstances.push(this); } + value = 'from-ng1'; + constructor() { + ng1ControllerInstances.push(this); + } } }; @@ -2697,7 +2820,9 @@ withEachNg1Version(() => { }) class Ng2Component { value = 'from-ng2'; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -2756,7 +2881,9 @@ withEachNg1Version(() => { class Ng2Component { x = 'foo'; y = 'bar'; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -2798,8 +2925,12 @@ withEachNg1Version(() => { const ng1Component: angular.IComponent = { template: 'ng1(default(<div ng-transclude="">fallback-{{ $ctrl.value }}</div>))', transclude: {slotX: 'contentX', slotY: 'contentY'}, - controller: - class {value = 'ng1'; constructor() { ng1ControllerInstances.push(this); }} + controller: class { + value = 'ng1'; + constructor() { + ng1ControllerInstances.push(this); + } + } }; // Define `Ng2Component` @@ -2830,7 +2961,9 @@ withEachNg1Version(() => { class Ng2Component { x = 'foo'; y = 'bar'; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -2880,7 +3013,11 @@ withEachNg1Version(() => { )`, transclude: {slotX: '?contentX', slotY: '?contentY'}, controller: class { - x = 'ng1X'; y = 'ng1Y'; constructor() { ng1ControllerInstances.push(this); } + x = 'ng1X'; + y = 'ng1Y'; + constructor() { + ng1ControllerInstances.push(this); + } } }; @@ -2896,7 +3033,9 @@ withEachNg1Version(() => { class Ng2Component { x = 'ng2X'; y = 'ng2Y'; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -3000,7 +3139,9 @@ withEachNg1Version(() => { x = 'foo'; y = 'bar'; show = true; - constructor() { ng2ComponentInstance = this; } + constructor() { + ng2ComponentInstance = this; + } } // Define `ng1Module` @@ -3202,13 +3343,18 @@ withEachNg1Version(() => { const ng1Module = angular.module_('ng1', []); let a1Injector: angular.IInjectorService|undefined; ng1Module.run([ - '$injector', function($injector: angular.IInjectorService) { a1Injector = $injector; } + '$injector', + function($injector: angular.IInjectorService) { + a1Injector = $injector; + } ]); const element = html('<div></div>'); window.name = 'NG_DEFER_BOOTSTRAP!' + window.name; - adapter.bootstrap(element, [ng1Module.name]).ready((ref) => { ref.dispose(); }); + adapter.bootstrap(element, [ng1Module.name]).ready((ref) => { + ref.dispose(); + }); tick(100); @@ -3275,7 +3421,7 @@ withEachNg1Version(() => { document.body.innerHTML = '<ng2 name="World">project</ng2>'; - adapter.bootstrap(document.body.firstElementChild !, ['myExample']).ready((ref) => { + adapter.bootstrap(document.body.firstElementChild!, ['myExample']).ready((ref) => { expect(multiTrim(document.body.textContent)) .toEqual('ng2[ng1[Hello World!](transclude)](project)'); ref.dispose(); diff --git a/packages/zone.js/test/extra/bluebird.spec.ts b/packages/zone.js/test/extra/bluebird.spec.ts index f88fcc9eceef4..a7db2845eece1 100644 --- a/packages/zone.js/test/extra/bluebird.spec.ts +++ b/packages/zone.js/test/extra/bluebird.spec.ts @@ -284,11 +284,7 @@ describe('bluebird promise', () => { .each( BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), (r: number, idx: number) => { -<<<<<<< HEAD expect(r).toBe(arr[idx]); -======= - expect(r === arr[idx]).toBeTrue(); ->>>>>>> 253023848d... build: update jasmine to 3.5 expect(Zone.current.name).toEqual('bluebird'); }) .then((r: any) => { @@ -309,11 +305,7 @@ describe('bluebird promise', () => { .mapSeries( BluebirdPromise.map(arr, (item: number) => BluebirdPromise.resolve(item)), (r: number, idx: number) => { -<<<<<<< HEAD expect(r).toBe(arr[idx]); -======= - expect(r === arr[idx]).toBeTrue(); ->>>>>>> 253023848d... build: update jasmine to 3.5 expect(Zone.current.name).toEqual('bluebird'); }) .then((r: any) => { diff --git a/packages/zone.js/test/node/crypto.spec.ts b/packages/zone.js/test/node/crypto.spec.ts index 3c38d484e73ed..c09205049fd8f 100644 --- a/packages/zone.js/test/node/crypto.spec.ts +++ b/packages/zone.js/test/node/crypto.spec.ts @@ -21,7 +21,9 @@ describe('crypto test', () => { const zoneASpec = { name: 'A', onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): - Task => { return delegate.scheduleTask(targetZone, task); } + Task => { + return delegate.scheduleTask(targetZone, task); + } }; const zoneA = Zone.current.fork(zoneASpec); spyOn(zoneASpec, 'onScheduleTask').and.callThrough(); @@ -44,7 +46,9 @@ describe('crypto test', () => { const zoneASpec = { name: 'A', onScheduleTask: (delegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task): - Task => { return delegate.scheduleTask(targetZone, task); } + Task => { + return delegate.scheduleTask(targetZone, task); + } }; const zoneA = Zone.current.fork(zoneASpec); spyOn(zoneASpec, 'onScheduleTask').and.callThrough(); From e4852365027be76f9fd9d590ab8c32bb4eb9cb96 Mon Sep 17 00:00:00 2001 From: Keen Yee Liau <kyliau@google.com> Date: Tue, 7 Apr 2020 14:58:39 -0700 Subject: [PATCH 152/262] test(language-service): Inline test cases in parsing-cases.ts (#36495) This commit removes individual components from parsing-cases.ts and colocate them with the actual tests. This makes the tests more readable. PR Close #36495 --- .../language-service/test/completions_spec.ts | 52 +++++++++++++----- .../language-service/test/diagnostics_spec.ts | 4 +- .../language-service/test/project/app/main.ts | 3 -- .../test/project/app/parsing-cases.ts | 53 ++----------------- .../test/typescript_host_spec.ts | 2 +- 5 files changed, 45 insertions(+), 69 deletions(-) diff --git a/packages/language-service/test/completions_spec.ts b/packages/language-service/test/completions_spec.ts index 96f6c52c13b01..ea44326f69fd4 100644 --- a/packages/language-service/test/completions_spec.ts +++ b/packages/language-service/test/completions_spec.ts @@ -168,9 +168,10 @@ describe('completions', () => { }); it('should be able to get completions in an empty interpolation', () => { - const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'empty-interpolation'); - const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); - expectContain(completions, CompletionKind.PROPERTY, ['title', 'subTitle']); + mockHost.override(TEST_TEMPLATE, `{{ ~{cursor} }}`); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.PROPERTY, ['title', 'hero']); }); it('should suggest $any() type cast function in an interpolation', () => { @@ -282,9 +283,14 @@ describe('completions', () => { describe('with a *ngIf', () => { it('should be able to get completions for exported *ngIf variable', () => { - const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'promised-person-name'); - const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); - expectContain(completions, CompletionKind.PROPERTY, ['name', 'age', 'street']); + mockHost.override(TEST_TEMPLATE, ` + <div *ngIf="heroP | async as h"> + {{ h.~{cursor} }} + </div> + `); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); }); @@ -368,9 +374,14 @@ describe('completions', () => { }); it('should be able to infer the type of a ngForOf with an async pipe', () => { - const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'async-person-name'); - const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); - expectContain(completions, CompletionKind.PROPERTY, ['name', 'age', 'street']); + mockHost.override(TEST_TEMPLATE, ` + <div *ngFor="let h of heroesP | async"> + {{ h.~{cursor} }} + </div> + `); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.PROPERTY, ['id', 'name']); }); it('should be able to resolve variable in nested loop', () => { @@ -498,14 +509,27 @@ describe('completions', () => { describe('with references', () => { it('should list references', () => { - const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'test-comp-content'); - const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); - expectContain(completions, CompletionKind.REFERENCE, ['div', 'test1', 'test2']); + mockHost.override(TEST_TEMPLATE, ` + <div #myDiv> + <test-comp #test1> + {{ ~{cursor} }} + </test-comp> + </div> + <test-comp #test2></test-comp> + `); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); + expectContain(completions, CompletionKind.REFERENCE, ['myDiv', 'test1', 'test2']); }); it('should reference the component', () => { - const marker = mockHost.getLocationMarkerFor(PARSING_CASES, 'test-comp-after-test'); - const completions = ngLS.getCompletionsAtPosition(PARSING_CASES, marker.start); + mockHost.override(TEST_TEMPLATE, ` + <test-comp #test1> + {{ test1.~{cursor} }} + </test-comp> + `); + const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor'); + const completions = ngLS.getCompletionsAtPosition(TEST_TEMPLATE, marker.start); expectContain(completions, CompletionKind.PROPERTY, ['name', 'testEvent']); }); diff --git a/packages/language-service/test/diagnostics_spec.ts b/packages/language-service/test/diagnostics_spec.ts index d8e0218954494..3beb06c819947 100644 --- a/packages/language-service/test/diagnostics_spec.ts +++ b/packages/language-service/test/diagnostics_spec.ts @@ -342,7 +342,7 @@ describe('diagnostics', () => { expect(category).toBe(ts.DiagnosticCategory.Error); expect(messageText) .toBe( - `Identifier 'missingField' is not defined. '{ implicitPerson: Person; }' does not contain such a member`, + `Identifier 'missingField' is not defined. '{ implicitPerson: Hero; }' does not contain such a member`, ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); @@ -361,7 +361,7 @@ describe('diagnostics', () => { expect(category).toBe(ts.DiagnosticCategory.Error); expect(messageText) .toBe( - `Identifier 'missingField' is not defined. 'Person' does not contain such a member`, + `Identifier 'missingField' is not defined. 'Hero' does not contain such a member`, ); const span = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'emb'); expect(start).toBe(span.start); diff --git a/packages/language-service/test/project/app/main.ts b/packages/language-service/test/project/app/main.ts index 85d2b7a440b34..20b18045287ce 100644 --- a/packages/language-service/test/project/app/main.ts +++ b/packages/language-service/test/project/app/main.ts @@ -16,16 +16,13 @@ import * as ParsingCases from './parsing-cases'; imports: [CommonModule, FormsModule], declarations: [ AppComponent, - ParsingCases.AsyncForUsingComponent, ParsingCases.CaseIncompleteOpen, ParsingCases.CaseMissingClosing, ParsingCases.CaseUnknown, ParsingCases.CounterDirective, - ParsingCases.EmptyInterpolation, ParsingCases.HintModel, ParsingCases.NoValueAttribute, ParsingCases.NumberModel, - ParsingCases.References, ParsingCases.StringModel, ParsingCases.TemplateReference, ParsingCases.TestComponent, diff --git a/packages/language-service/test/project/app/parsing-cases.ts b/packages/language-service/test/project/app/parsing-cases.ts index da5c203034d45..69b6c5b8fee3e 100644 --- a/packages/language-service/test/project/app/parsing-cases.ts +++ b/packages/language-service/test/project/app/parsing-cases.ts @@ -63,45 +63,6 @@ export class HintModel { hintChange: EventEmitter<string> = new EventEmitter(); } -interface Person { - name: string; - age: number; - street: string; -} - -@Component({ - template: ` - <div *ngFor="let person of people | async"> - {{person.~{async-person-name}name}} - </div> - <div *ngIf="promisedPerson | async as person"> - {{person.~{promised-person-name}name}} - </div> - `, -}) -export class AsyncForUsingComponent { - people: Promise<Person[]> = Promise.resolve([]); - promisedPerson: Promise<Person> = Promise.resolve({ - name: 'John Doe', - age: 42, - street: '123 Angular Ln', - }); -} - -@Component({ - template: ` - <div #div> - <test-comp #test1> - {{~{test-comp-content}}} - {{test1.~{test-comp-after-test}name}} - {{div.~{test-comp-after-div}.innerText}} - </test-comp> - </div> - <test-comp #test2></test-comp>`, -}) -export class References { -} - class CounterDirectiveContext<T> { constructor(public $implicit: T) {} } @@ -121,8 +82,8 @@ export class CounterDirective implements OnChanges { } interface WithContextDirectiveContext { - $implicit: {implicitPerson: Person;}; - nonImplicitPerson: Person; + $implicit: {implicitPerson: Hero;}; + nonImplicitPerson: Hero; } @Directive({selector: '[withContext]'}) @@ -156,7 +117,9 @@ export class TemplateReference { */ title = 'Some title'; hero: Hero = {id: 1, name: 'Windstorm'}; + heroP = Promise.resolve(this.hero); heroes: Hero[] = [this.hero]; + heroesP = Promise.resolve(this.heroes); tupleArray: [string, Hero] = ['test', this.hero]; league: Hero[][] = [this.heroes]; heroesByName: {[name: string]: Hero} = {}; @@ -171,11 +134,3 @@ export class TemplateReference { constNames = [{name: 'name'}] as const; private myField = 'My Field'; } - -@Component({ - template: '{{~{empty-interpolation}}}', -}) -export class EmptyInterpolation { - title = 'Some title'; - subTitle = 'Some sub title'; -} diff --git a/packages/language-service/test/typescript_host_spec.ts b/packages/language-service/test/typescript_host_spec.ts index 07a09575f9b26..a8a724aa535f4 100644 --- a/packages/language-service/test/typescript_host_spec.ts +++ b/packages/language-service/test/typescript_host_spec.ts @@ -94,7 +94,7 @@ describe('TypeScriptServiceHost', () => { const tsLS = ts.createLanguageService(tsLSHost); const ngLSHost = new TypeScriptServiceHost(tsLSHost, tsLS); const templates = ngLSHost.getTemplates('/app/parsing-cases.ts'); - expect(templates.length).toBe(8); + expect(templates.length).toBe(5); }); it('should be able to find external template', () => { From d47b318fee2a9fe2a7061f70903f58b7e83677ac Mon Sep 17 00:00:00 2001 From: Alan Agius <alan.agius4@gmail.com> Date: Wed, 8 Apr 2020 13:36:07 +0200 Subject: [PATCH 153/262] build: remove `fullTemplateTypeCheck` from aio tsconfig (#36502) `fullTemplateTypeCheck` is no longer required since we now use `strictTemplates` which is a superset of the former option. Follow-up on: https://github.com/angular/angular/commit/04f61c0c3ee9b3616b1719b4ae9c3eb097698218#r38354112 PR Close #36502 --- aio/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/aio/tsconfig.json b/aio/tsconfig.json index 2e5d77de7a625..bcb138ef772e5 100644 --- a/aio/tsconfig.json +++ b/aio/tsconfig.json @@ -37,7 +37,6 @@ ], "angularCompilerOptions": { "disableTypeScriptVersionCheck": true, - "fullTemplateTypeCheck": true, "strictInjectionParameters": true, "strictTemplates": true } From 4cf89d4bd7facdcf27cc890b3213915a9ccba16b Mon Sep 17 00:00:00 2001 From: Alan Agius <alan.agius4@gmail.com> Date: Wed, 8 Apr 2020 11:07:58 +0200 Subject: [PATCH 154/262] docs: replace `browserslist` with `.browserslistrc` (#36504) In version 10, this file has been changed. See: https://github.com/angular/angular-cli/pull/17367 PR Close #36504 --- aio/content/guide/file-structure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/file-structure.md b/aio/content/guide/file-structure.md index f816449900882..536fa7033bdee 100644 --- a/aio/content/guide/file-structure.md +++ b/aio/content/guide/file-structure.md @@ -99,7 +99,7 @@ Project-specific [TypeScript](https://www.typescriptlang.org/) configuration fil | APPLICATION-SPECIFIC CONFIG FILES | PURPOSE | | :--------------------- | :------------------------------------------| -| `browserslist` | Configures sharing of target browsers and Node.js versions among various front-end tools. See [Browserslist on GitHub](https://github.com/browserslist/browserslist) for more information. | +| `.browserslistrc` | Configures sharing of target browsers and Node.js versions among various front-end tools. See [Browserslist on GitHub](https://github.com/browserslist/browserslist) for more information. | | `karma.conf.js` | Application-specific [Karma](https://karma-runner.github.io/2.0/config/configuration-file.html) configuration. | | `tsconfig.app.json` | Application-specific [TypeScript](https://www.typescriptlang.org/) configuration, including TypeScript and Angular template compiler options. See [TypeScript Configuration](guide/typescript-configuration) and [Angular Compiler Options](guide/angular-compiler-options). | | `tsconfig.spec.json` | [TypeScript](https://www.typescriptlang.org/) configuration for the application tests. See [TypeScript Configuration](guide/typescript-configuration). | From 7d7b59efa5e8de85bd802e468f1f54f949963e76 Mon Sep 17 00:00:00 2001 From: Sachin Grover <sacgrover@gmail.com> Date: Wed, 12 Feb 2020 23:16:59 +0530 Subject: [PATCH 155/262] docs: update the Support policy and schedule (#35390) PR Close #35359 PR Close #35390 --- aio/content/guide/releases.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aio/content/guide/releases.md b/aio/content/guide/releases.md index 1a4d0318d1140..b1207f691c1d6 100644 --- a/aio/content/guide/releases.md +++ b/aio/content/guide/releases.md @@ -101,7 +101,8 @@ The following table provides the status for Angular versions under support. Version | Status | Released | Active Ends | LTS Ends ------- | ------ | ------------ | ------------ | ------------ -^8.0.0 | Active | May 28, 2019 | Nov 28, 2019 | Nov 28, 2020 +^9.0.0 | Active | Feb 06, 2020 | Aug 06, 2020 | Aug 06, 2021 +^8.0.0 | LTS | May 28, 2019 | Nov 28, 2019 | Nov 28, 2020 ^7.0.0 | LTS | Oct 18, 2018 | Apr 18, 2019 | Apr 18, 2020 Angular versions ^4.0.0, ^5.0.0 and ^6.0.0 are no longer under support. From a8978ebf8e7dc6d16da310f1d17598434b424f26 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Wed, 8 Apr 2020 14:50:10 +0200 Subject: [PATCH 156/262] build: ts-circular-deps tool should normalize golden (#36505) Currently the golden output of the circular-deps tool is purely based on the order of source files passed to the tool, and on the amount of imports inside source files. This is actually resulting in deterministic output as running the tool multiple times without any changes to source files, results in the same output. Though it seems like the tool is too strict and we can avoid unnecessary golden changes if: 1. A source file that is part of a cycle is imported earlier (in terms of how the analyzer visits them). This could result in the cycle path starting with a different source file. 2. Source files which are not part of a cycle are imported earlier (in terms of how the analyzer visits them). This could result in moved items in the golden if re-approved (even though the cycles remain the same) To fix this, we normalize the cycle path array that serves as serializable data structure for the text-based goldens. Since the paths represents a cycle, the path can be shifted in a deterministic way so that cycles don't change unnecessarily in the golden, and to simplify comparison of cycles. Additionally, we sort the cycles in a deterministic way so that the golden doesn't change unnecessarily (as explained above). PR Close #36505 --- dev-infra/ts-circular-dependencies/golden.ts | 77 +- goldens/packages-circular-deps.json | 2164 +++++++++--------- 2 files changed, 1157 insertions(+), 1084 deletions(-) diff --git a/dev-infra/ts-circular-dependencies/golden.ts b/dev-infra/ts-circular-dependencies/golden.ts index 769975b3b87ce..49c5840fbe90b 100644 --- a/dev-infra/ts-circular-dependencies/golden.ts +++ b/dev-infra/ts-circular-dependencies/golden.ts @@ -20,8 +20,17 @@ export type Golden = CircularDependency[]; * the source file objects are mapped to their relative file names. */ export function convertReferenceChainToGolden(refs: ReferenceChain[], baseDir: string): Golden { - return refs.map( - chain => chain.map(({fileName}) => convertPathToForwardSlash(relative(baseDir, fileName)))); + return refs + .map( + // Normalize cycles as the paths can vary based on which node in the cycle is visited + // first in the analyzer. The paths represent cycles. Hence we can shift nodes in a + // deterministic way so that the goldens don't change unnecessarily and cycle comparison + // is simpler. + chain => normalizeCircularDependency( + chain.map(({fileName}) => convertPathToForwardSlash(relative(baseDir, fileName))))) + // Sort cycles so that the golden doesn't change unnecessarily when cycles are detected + // in different order (e.g. new imports cause cycles to be detected earlier or later). + .sort(compareCircularDependency); } /** @@ -44,6 +53,53 @@ export function compareGoldens(actual: Golden, expected: Golden) { return {newCircularDeps, fixedCircularDeps}; } +/** + * Normalizes the a circular dependency by ensuring that the path starts with the first + * node in alphabetical order. Since the path array represents a cycle, we can make a + * specific node the first element in the path that represents the cycle. + * + * This method is helpful because the path of circular dependencies changes based on which + * file in the path has been visited first by the analyzer. e.g. Assume we have a circular + * dependency represented as: `A -> B -> C`. The analyzer will detect this cycle when it + * visits `A`. Though when a source file that is analyzed before `A` starts importing `B`, + * the cycle path will detected as `B -> C -> A`. This represents the same cycle, but is just + * different due to a limitation of using a data structure that can be written to a text-based + * golden file. + * + * To account for this non-deterministic behavior in goldens, we shift the circular + * dependency path to the first node based on alphabetical order. e.g. `A` will always + * be the first node in the path that represents the cycle. + */ +function normalizeCircularDependency(path: CircularDependency): CircularDependency { + if (path.length <= 1) { + return path; + } + + let indexFirstNode: number = 0; + let valueFirstNode: string = path[0]; + + // Find a node in the cycle path that precedes all other elements + // in terms of alphabetical order. + for (let i = 1; i < path.length; i++) { + const value = path[i]; + if (value.localeCompare(valueFirstNode, 'en') < 0) { + indexFirstNode = i; + valueFirstNode = value; + } + } + + // If the alphabetically first node is already at start of the path, just + // return the actual path as no changes need to be made. + if (indexFirstNode === 0) { + return path; + } + + // Move the determined first node (as of alphabetical order) to the start of a new + // path array. The nodes before the first node in the old path are then concatenated + // to the end of the new path. This is possible because the path represents a cycle. + return [...path.slice(indexFirstNode), ...path.slice(0, indexFirstNode)]; +} + /** Checks whether the specified circular dependencies are equal. */ function isSameCircularDependency(actual: CircularDependency, expected: CircularDependency) { if (actual.length !== expected.length) { @@ -56,3 +112,20 @@ function isSameCircularDependency(actual: CircularDependency, expected: Circular } return true; } + +/** + * Compares two circular dependencies by respecting the alphabetic order of nodes in the + * cycle paths. The first nodes which don't match in both paths are decisive on the order. + */ +function compareCircularDependency(a: CircularDependency, b: CircularDependency): number { + // Go through nodes in both cycle paths and determine whether `a` should be ordered + // before `b`. The first nodes which don't match decide on the order. + for (let i = 0; i < Math.min(a.length, b.length); i++) { + const compareValue = a[i].localeCompare(b[i], 'en'); + if (compareValue !== 0) { + return compareValue; + } + } + // If all nodes are equal in the cycles, the order is based on the length of both cycles. + return a.length - b.length; +} diff --git a/goldens/packages-circular-deps.json b/goldens/packages-circular-deps.json index c2bb283d29ec3..669637271dfd1 100644 --- a/goldens/packages-circular-deps.json +++ b/goldens/packages-circular-deps.json @@ -1,27 +1,123 @@ [ [ - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts" + "packages/animations/browser/src/render/animation_driver.ts", + "packages/animations/browser/src/render/shared.ts" ], [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts" + "packages/compiler-cli/ngcc/src/packages/configuration.ts", + "packages/compiler-cli/ngcc/src/packages/entry_point.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_init.ts" + "packages/compiler-cli/src/metadata/bundle_index_host.ts", + "packages/compiler-cli/src/transformers/metadata_cache.ts", + "packages/compiler-cli/src/metadata/index.ts" + ], + [ + "packages/compiler-cli/src/metadata/bundle_index_host.ts", + "packages/compiler-cli/src/transformers/metadata_cache.ts", + "packages/compiler-cli/src/transformers/compiler_host.ts", + "packages/compiler-cli/src/metadata/index.ts" + ], + [ + "packages/compiler-cli/src/metadata/bundle_index_host.ts", + "packages/compiler-cli/src/transformers/metadata_cache.ts", + "packages/compiler-cli/src/transformers/compiler_host.ts", + "packages/compiler-cli/src/transformers/metadata_reader.ts", + "packages/compiler-cli/src/metadata/index.ts" + ], + [ + "packages/compiler-cli/src/metadata/collector.ts", + "packages/compiler-cli/src/metadata/evaluator.ts" + ], + [ + "packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts", + "packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts" + ], + [ + "packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts", + "packages/compiler-cli/src/ngtsc/routing/src/lazy.ts" + ], + [ + "packages/compiler-cli/src/ngtsc/scope/src/component_scope.ts", + "packages/compiler-cli/src/ngtsc/scope/src/local.ts" + ], + [ + "packages/compiler-cli/src/ngtsc/typecheck/src/context.ts", + "packages/compiler-cli/src/ngtsc/typecheck/src/host.ts" + ], + [ + "packages/compiler-cli/test/helpers/index.ts", + "packages/compiler-cli/test/helpers/src/mock_file_loading.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/lifecycle_reflector.ts", + "packages/compiler/src/compile_reflector.ts", + "packages/compiler/src/output/output_ast.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/ml_parser/parser.ts", + "packages/compiler/src/ml_parser/ast.ts", + "packages/compiler/src/i18n/i18n_ast.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/ml_parser/parser.ts", + "packages/compiler/src/ml_parser/ast.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/ml_parser/parser.ts", + "packages/compiler/src/ml_parser/lexer.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/ml_parser/parser.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/util.ts", + "packages/compiler/src/constant_pool.ts", + "packages/compiler/src/output/output_ast.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/util.ts", + "packages/compiler/src/output/output_ast.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/compile_metadata.ts", + "packages/compiler/src/util.ts", + "packages/compiler/src/parse_util.ts" + ], + [ + "packages/compiler/src/output/output_ast.ts", + "packages/compiler/src/render3/view/i18n/meta.ts" + ], + [ + "packages/compiler/src/output/output_ast.ts", + "packages/compiler/src/render3/view/i18n/meta.ts", + "packages/compiler/src/render3/view/i18n/util.ts" + ], + [ + "packages/compiler/src/render3/r3_factory.ts", + "packages/compiler/src/render3/view/util.ts", + "packages/compiler/src/render3/view/api.ts" ], [ + "packages/compiler/src/render3/view/styling_builder.ts", + "packages/compiler/src/render3/view/template.ts" + ], + [ + "packages/core/src/application_init.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -32,14 +128,11 @@ "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts" - ], - [ - "packages/core/src/change_detection/differs/default_iterable_differ.ts", - "packages/core/src/change_detection/differs/iterable_differs.ts" + "packages/core/src/application_ref.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -49,62 +142,21 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/differs/default_keyvalue_differ.ts", - "packages/core/src/change_detection/differs/keyvalue_differs.ts" - ], - [ - "packages/core/src/change_detection/differs/default_keyvalue_differ.ts", - "packages/core/src/change_detection/differs/keyvalue_differs.ts" - ], - [ - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts" + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts" - ], - [ - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts" - ], - [ "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/element_ref.ts" - ], - [ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/ng_module_factory.ts" + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -112,23 +164,24 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/linker/ng_module_factory.ts", - "packages/core/src/linker/component_factory_resolver.ts" + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/linker/ng_module_factory.ts", - "packages/core/src/linker/component_factory_resolver.ts" - ], - [ - "packages/core/src/linker/ng_module_factory.ts", - "packages/core/src/linker/component_factory_resolver.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/template_ref.ts" + "packages/core/src/linker/component_factory_resolver.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ "packages/core/src/application_ref.ts", @@ -141,51 +194,40 @@ "packages/core/src/linker/view_ref.ts" ], [ - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/template_ref.ts", - "packages/core/src/linker/view_ref.ts" - ], - [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/view_container_ref.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/view_container_ref.ts" + "packages/core/src/linker/view_container_ref.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/linker/view_container_ref.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render/api.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts" - ], - [ + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/container.ts", + "packages/core/src/render3/interfaces/node.ts", + "packages/core/src/render3/interfaces/definition.ts", "packages/core/src/core.ts", "packages/core/src/metadata.ts", "packages/core/src/di.ts", @@ -197,7 +239,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -207,17 +251,14 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/container.ts", "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts" - ], - [ + "packages/core/src/render3/interfaces/definition.ts", + "packages/core/src/render3/interfaces/view.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -228,9 +269,7 @@ "packages/core/src/render3/interfaces/container.ts", "packages/core/src/render3/interfaces/node.ts", "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts" - ], - [ + "packages/core/src/render3/interfaces/view.ts", "packages/core/src/metadata.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", @@ -241,7 +280,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -249,37 +290,52 @@ "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts" - ], - [ - "packages/core/src/render3/interfaces/container.ts", - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts" + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component_ref.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component_ref.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts" - ], - [ - "packages/core/src/render3/interfaces/node.ts", - "packages/core/src/render3/interfaces/definition.ts", - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts" - ], - [ - "packages/core/src/render3/interfaces/view.ts", - "packages/core/src/render3/interfaces/query.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component_ref.ts", + "packages/core/src/render3/view_ref.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", "packages/core/src/core.ts", "packages/core/src/metadata.ts", "packages/core/src/di.ts", @@ -291,7 +347,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -301,13 +359,13 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" - ], - [ + "packages/core/src/render3/component.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -317,17 +375,11 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -337,13 +389,15 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts" - ], - [ + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -354,14 +408,13 @@ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" - ], - [ - "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/render3/di.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -372,18 +425,11 @@ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" + "packages/core/src/render3/di.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -394,51 +440,7 @@ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/render3/hooks.ts", - "packages/core/src/render3/state.ts", - "packages/core/src/render3/util/view_utils.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/di.ts" - ], - [ + "packages/core/src/render3/instructions/shared.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -448,7 +450,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -459,9 +463,12 @@ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" - ], - [ + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/element.ts", + "packages/core/src/view/types.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -471,7 +478,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -487,16 +496,16 @@ "packages/core/src/errors.ts", "packages/core/src/view/index.ts", "packages/core/src/view/element.ts", - "packages/core/src/view/types.ts" - ], - [ - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts", - "packages/core/src/view/types.ts" + "packages/core/src/view/util.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", @@ -509,10 +518,16 @@ "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts", - "packages/core/src/view/types.ts" + "packages/core/src/view/entrypoint.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", @@ -524,15 +539,21 @@ "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts", - "packages/core/src/view/util.ts" - ], - [ + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -547,21 +568,16 @@ "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts", - "packages/core/src/view/util.ts" - ], - [ - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/element.ts", - "packages/core/src/view/util.ts", - "packages/core/src/view/errors.ts" - ], - [ + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -576,9 +592,27 @@ "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts" + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/instructions/lview_debug.ts", + "packages/core/src/core.ts", + "packages/core/src/metadata.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", @@ -591,9 +625,8 @@ "packages/core/src/error_handler.ts", "packages/core/src/errors.ts", "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts" - ], - [ + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -603,7 +636,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -620,9 +655,26 @@ "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts" + "packages/core/src/view/provider.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", @@ -632,13 +684,10 @@ "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts" + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -655,10 +704,20 @@ "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts" + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", @@ -669,35 +728,16 @@ "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts" - ], - [ - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/core.ts", - "packages/core/src/metadata.ts", - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts", + "packages/core/src/view/ng_module.ts", "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -714,59 +754,43 @@ "packages/core/src/view/index.ts", "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts", - "packages/core/src/render3/instructions/lview_debug.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts" + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts", + "packages/core/src/view/ng_module.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts", - "packages/core/src/render3/util/view_traversal_utils.ts" + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts", - "packages/core/src/render3/util/discovery_utils.ts", - "packages/core/src/render3/util/view_traversal_utils.ts" - ], - [ - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/debug/debug_node.ts" - ], - [ + "packages/core/src/render3/node_manipulation.ts", + "packages/core/src/core.ts", + "packages/core/src/metadata.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -776,7 +800,9 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -787,21 +813,24 @@ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" - ], - [ - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/di.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", @@ -810,40 +839,30 @@ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts" + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/di.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts" + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -853,14 +872,11 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts" + "packages/core/src/render3/features/providers_feature.ts", + "packages/core/src/render3/di_setup.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ "packages/core/src/application_ref.ts", @@ -872,38 +888,30 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" - ], - [ + "packages/core/src/render3/ng_module_ref.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -913,17 +921,14 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", @@ -931,21 +936,12 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts" + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/linker/ng_module_factory_registration.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -955,23 +951,10 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts" + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -981,27 +964,11 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts", - "packages/core/src/error_handler.ts", - "packages/core/src/errors.ts", - "packages/core/src/view/index.ts", - "packages/core/src/view/entrypoint.ts", - "packages/core/src/view/services.ts", - "packages/core/src/view/provider.ts", - "packages/core/src/view/refs.ts", - "packages/core/src/view/ng_module.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/ng_module_ref.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", @@ -1011,18 +978,34 @@ "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/pipe.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/instructions/shared.ts" + "packages/core/src/render3/pipe.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/core.ts", - "packages/core/src/metadata.ts", + "packages/core/src/application_ref.ts", + "packages/core/src/application_tokens.ts", + "packages/core/src/linker/component_factory.ts", + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/differs/default_keyvalue_differ.ts", + "packages/core/src/change_detection/differs/keyvalue_differs.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -1032,59 +1015,81 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/console.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/node_manipulation.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/styling/static_styling.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/linker/compiler.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/linker/compiler.ts", + "packages/core/src/metadata.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/container.ts" + "packages/core/src/application_ref.ts", + "packages/core/src/linker/compiler.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/metadata/resource_loading.ts", + "packages/core/src/metadata/directives.ts", "packages/core/src/di.ts", "packages/core/src/di/index.ts", "packages/core/src/di/injectable.ts", @@ -1094,166 +1099,230 @@ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/di.ts" + "packages/core/src/metadata/resource_loading.ts", + "packages/core/src/metadata/directives.ts", + "packages/core/src/render3/jit/directive.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ + "packages/core/src/application_ref.ts", + "packages/core/src/metadata/resource_loading.ts", + "packages/core/src/metadata/directives.ts", + "packages/core/src/render3/jit/directive.ts", + "packages/core/src/render3/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" ], [ + "packages/core/src/application_ref.ts", + "packages/core/src/metadata/resource_loading.ts", + "packages/core/src/metadata/directives.ts", + "packages/core/src/render3/jit/directive.ts", + "packages/core/src/render3/jit/module.ts", + "packages/core/src/metadata.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", + "packages/core/src/metadata/resource_loading.ts", + "packages/core/src/metadata/directives.ts", + "packages/core/src/render3/jit/directive.ts", + "packages/core/src/render3/jit/module.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ + "packages/core/src/application_ref.ts", + "packages/core/src/metadata/resource_loading.ts", + "packages/core/src/metadata/directives.ts", + "packages/core/src/render3/jit/directive.ts", + "packages/core/src/render3/jit/module.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ + "packages/core/src/application_ref.ts", + "packages/core/src/testability/testability.ts", + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts", + "packages/core/src/render3/definition.ts", + "packages/core/src/metadata/ng_module.ts" + ], + [ "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/di.ts" + "packages/core/src/linker/component_factory.ts" + ], + [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/linker/ng_module_factory.ts", + "packages/core/src/linker/component_factory_resolver.ts", + "packages/core/src/linker/component_factory.ts" + ], + [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/linker/view_container_ref.ts", + "packages/core/src/linker/component_factory.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts" + "packages/core/src/render3/component_ref.ts", + "packages/core/src/linker/component_factory.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/element.ts", + "packages/core/src/view/types.ts", + "packages/core/src/linker/component_factory.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element_container.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/element.ts", + "packages/core/src/view/util.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/element_container.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/linker/component_factory.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/embedded_view.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/listener.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/linker/component_factory.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/view/provider.ts" ], [ + "packages/core/src/change_detection/change_detection.ts", + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", "packages/core/src/render3/component.ts", - "packages/core/src/render3/util/global_utils.ts", - "packages/core/src/render3/util/change_detection_utils.ts", - "packages/core/src/render3/instructions/all.ts", - "packages/core/src/render3/instructions/styling.ts", - "packages/core/src/render3/styling/style_binding_list.ts" + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts" - ], - [ "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts", + "packages/core/src/view/provider.ts", + "packages/core/src/view/refs.ts", + "packages/core/src/linker/component_factory.ts" ], [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/copy_definition_feature.ts", - "packages/core/src/render3/features/inherit_definition_feature.ts" + "packages/core/src/change_detection/change_detector_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" - ], - [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/features/providers_feature.ts", - "packages/core/src/render3/di_setup.ts" + "packages/core/src/linker/template_ref.ts", + "packages/core/src/linker/view_ref.ts" ], [ "packages/core/src/change_detection/change_detector_ref.ts", @@ -1264,106 +1333,129 @@ "packages/core/src/render3/component_ref.ts" ], [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/component_ref.ts", + "packages/core/src/render3/view_ref.ts" ], [ - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", "packages/core/src/change_detection/change_detector_ref.ts", "packages/core/src/render3/view_engine_compatibility.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/view_engine_compatibility_prebound.ts" ], [ - "packages/core/src/render3/assert.ts", + "packages/core/src/change_detection/differs/default_iterable_differ.ts", + "packages/core/src/change_detection/differs/iterable_differs.ts" + ], + [ + "packages/core/src/change_detection/differs/default_keyvalue_differ.ts", + "packages/core/src/change_detection/differs/keyvalue_differs.ts" + ], + [ + "packages/core/src/debug/debug_node.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/instructions/lview_debug.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/render3/view_ref.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/util/view_traversal_utils.ts", "packages/core/src/render3/assert.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/render3/view_ref.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ + "packages/core/src/debug/debug_node.ts", + "packages/core/src/render3/util/discovery_utils.ts", + "packages/core/src/render3/util/view_traversal_utils.ts", "packages/core/src/render3/interfaces/type_checks.ts", "packages/core/src/render3/index.ts", - "packages/core/src/render3/component_ref.ts", - "packages/core/src/render3/view_ref.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/i18n.ts" + "packages/core/src/debug/debug_node.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" + ], + [ + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts" + ], + [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts" ], [ + "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" + "packages/core/src/di/r3_injector.ts" ], [ "packages/core/src/di/injector_compatibility.ts", @@ -1371,512 +1463,362 @@ "packages/core/src/di/r3_injector.ts", "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" + "packages/core/src/di/util.ts" ], [ - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" + "packages/core/src/di/injector.ts", + "packages/core/src/di/r3_injector.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts", - "packages/core/src/linker/ng_module_factory_registration.ts" - ], - [ - "packages/core/src/render3/ng_module_ref.ts", - "packages/core/src/linker/ng_module_factory_registration.ts" - ], - [ - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/ng_module_ref.ts" - ], - [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts" - ], - [ - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/query.ts" - ], - [ - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/view_engine_compatibility_prebound.ts" - ], - [ - "packages/core/src/render3/view_engine_compatibility.ts", - "packages/core/src/render3/assert.ts", - "packages/core/src/render3/interfaces/type_checks.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/view_engine_compatibility_prebound.ts" - ], - [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts" + "packages/core/src/di/reflective_errors.ts", + "packages/core/src/di/reflective_injector.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/console.ts" + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/element.ts", + "packages/core/src/view/types.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts" + "packages/core/src/error_handler.ts", + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/entrypoint.ts", + "packages/core/src/view/services.ts" ], [ - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/linker/compiler.ts" + "packages/core/src/errors.ts", + "packages/core/src/view/index.ts", + "packages/core/src/view/element.ts", + "packages/core/src/view/util.ts", + "packages/core/src/view/errors.ts" ], [ - "packages/core/src/metadata.ts", - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/linker/compiler.ts" + "packages/core/src/linker/component_factory_resolver.ts", + "packages/core/src/linker/ng_module_factory.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/linker/compiler.ts" + "packages/core/src/linker/element_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", - "packages/core/src/metadata/directives.ts" + "packages/core/src/linker/ng_module_factory_registration.ts", + "packages/core/src/render3/ng_module_ref.ts" ], [ - "packages/core/src/metadata/directives.ts", - "packages/core/src/render3/jit/directive.ts" + "packages/core/src/linker/template_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/core/src/metadata/resource_loading.ts", - "packages/core/src/metadata/directives.ts", - "packages/core/src/render3/jit/directive.ts" + "packages/core/src/linker/view_container_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", "packages/core/src/metadata/directives.ts", "packages/core/src/render3/jit/directive.ts" ], [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", "packages/core/src/metadata/directives.ts", "packages/core/src/render3/jit/directive.ts", - "packages/core/src/render3/jit/environment.ts" - ], - [ - "packages/core/src/metadata.ts", - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", - "packages/core/src/metadata/directives.ts", - "packages/core/src/render3/jit/directive.ts", - "packages/core/src/render3/jit/module.ts" - ], - [ - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", - "packages/core/src/metadata/directives.ts", - "packages/core/src/render3/jit/directive.ts", - "packages/core/src/render3/jit/module.ts" - ], - [ - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", - "packages/core/src/metadata/directives.ts", - "packages/core/src/render3/jit/directive.ts", - "packages/core/src/render3/jit/module.ts" + "packages/core/src/metadata/resource_loading.ts" ], [ "packages/core/src/metadata/directives.ts", "packages/core/src/render3/jit/pipe.ts" ], [ - "packages/core/src/di.ts", - "packages/core/src/di/index.ts", - "packages/core/src/di/injectable.ts", - "packages/core/src/di/jit/injectable.ts", - "packages/core/src/di/jit/environment.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/application_ref.ts", - "packages/core/src/testability/testability.ts" - ], - [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts", - "packages/core/src/di/util.ts" - ], - [ - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts" + "packages/core/src/render/api.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component_ref.ts" ], [ - "packages/core/src/di/reflective_injector.ts", - "packages/core/src/di/reflective_errors.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component_ref.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/animations/browser/src/render/animation_driver.ts", - "packages/animations/browser/src/render/shared.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts" ], [ - "packages/core/testing/src/test_bed.ts", - "packages/core/testing/src/r3_test_bed.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts" ], [ - "packages/core/testing/src/test_bed.ts", - "packages/core/testing/src/r3_test_bed.ts", - "packages/core/testing/src/test_bed_common.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts" ], [ - "packages/compiler/src/output/output_ast.ts", - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/lifecycle_reflector.ts", - "packages/compiler/src/compile_reflector.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts", + "packages/core/src/render3/state.ts" ], [ - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/ml_parser/parser.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts", + "packages/core/src/render3/state.ts", + "packages/core/src/render3/util/view_utils.ts" ], [ - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/ml_parser/parser.ts", - "packages/compiler/src/ml_parser/ast.ts", - "packages/compiler/src/i18n/i18n_ast.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts" ], [ - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/ml_parser/parser.ts", - "packages/compiler/src/ml_parser/ast.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/node_manipulation.ts" ], [ - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/ml_parser/parser.ts", - "packages/compiler/src/ml_parser/lexer.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/styling/static_styling.ts" ], [ - "packages/compiler/src/constant_pool.ts", - "packages/compiler/src/output/output_ast.ts", - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/util.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/container.ts" ], [ - "packages/compiler/src/output/output_ast.ts", - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/util.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element_container.ts" ], [ - "packages/compiler/src/parse_util.ts", - "packages/compiler/src/compile_metadata.ts", - "packages/compiler/src/util.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element.ts" ], [ - "packages/compiler/src/output/output_ast.ts", - "packages/compiler/src/render3/view/i18n/meta.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/embedded_view.ts" ], [ - "packages/compiler/src/output/output_ast.ts", - "packages/compiler/src/render3/view/i18n/meta.ts", - "packages/compiler/src/render3/view/i18n/util.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/styling.ts" ], [ - "packages/compiler/src/render3/r3_factory.ts", - "packages/compiler/src/render3/view/util.ts", - "packages/compiler/src/render3/view/api.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/styling.ts", + "packages/core/src/render3/styling/style_binding_list.ts" ], [ - "packages/compiler/src/render3/view/styling_builder.ts", - "packages/compiler/src/render3/view/template.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/query.ts" ], [ - "packages/compiler-cli/src/metadata/collector.ts", - "packages/compiler-cli/src/metadata/evaluator.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/query.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/compiler-cli/src/metadata/index.ts", - "packages/compiler-cli/src/metadata/bundle_index_host.ts", - "packages/compiler-cli/src/transformers/metadata_cache.ts" + "packages/core/src/render3/assert.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/view_engine_compatibility_prebound.ts", + "packages/core/src/render3/view_engine_compatibility.ts" ], [ - "packages/compiler-cli/src/metadata/index.ts", - "packages/compiler-cli/src/metadata/bundle_index_host.ts", - "packages/compiler-cli/src/transformers/metadata_cache.ts", - "packages/compiler-cli/src/transformers/compiler_host.ts" + "packages/core/src/render3/component_ref.ts", + "packages/core/src/render3/view_ref.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/compiler-cli/src/metadata/index.ts", - "packages/compiler-cli/src/metadata/bundle_index_host.ts", - "packages/compiler-cli/src/transformers/metadata_cache.ts", - "packages/compiler-cli/src/transformers/compiler_host.ts", - "packages/compiler-cli/src/transformers/metadata_reader.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/hooks.ts", + "packages/core/src/render3/state.ts", + "packages/core/src/render3/util/view_utils.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/compiler-cli/src/ngtsc/partial_evaluator/src/interface.ts", - "packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/di.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/compiler-cli/src/ngtsc/scope/src/component_scope.ts", - "packages/compiler-cli/src/ngtsc/scope/src/local.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/instructions/shared.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/compiler-cli/src/ngtsc/typecheck/src/context.ts", - "packages/compiler-cli/src/ngtsc/typecheck/src/host.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/node_manipulation.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts", - "packages/compiler-cli/src/ngtsc/routing/src/lazy.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/container.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/config.ts", - "packages/router/src/router_state.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element_container.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/config.ts", - "packages/router/src/router_state.ts", - "packages/router/src/shared.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/element.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/shared.ts", - "packages/router/src/url_tree.ts" + "packages/core/src/render3/component.ts", + "packages/core/src/render3/util/global_utils.ts", + "packages/core/src/render3/util/change_detection_utils.ts", + "packages/core/src/render3/instructions/all.ts", + "packages/core/src/render3/instructions/listener.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/shared.ts", - "packages/router/src/url_tree.ts", - "packages/router/src/utils/collection.ts" + "packages/core/src/render3/di_setup.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts", + "packages/core/src/render3/features/providers_feature.ts" ], [ - "packages/router/src/router_outlet_context.ts", - "packages/router/src/directives/router_outlet.ts" + "packages/core/src/render3/features/copy_definition_feature.ts", + "packages/core/src/render3/features/inherit_definition_feature.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/router.ts", - "packages/router/src/operators/activate_routes.ts" + "packages/core/src/render3/features/copy_definition_feature.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/router.ts", - "packages/router/src/operators/apply_redirects.ts" + "packages/core/src/render3/i18n.ts", + "packages/core/src/render3/interfaces/type_checks.ts", + "packages/core/src/render3/index.ts" ], [ - "packages/router/src/router.ts", - "packages/router/src/operators/check_guards.ts" + "packages/core/src/render3/interfaces/container.ts", + "packages/core/src/render3/interfaces/node.ts", + "packages/core/src/render3/interfaces/definition.ts", + "packages/core/src/render3/interfaces/view.ts" ], [ - "packages/router/src/router.ts", - "packages/router/src/operators/recognize.ts" + "packages/core/src/render3/interfaces/definition.ts", + "packages/core/src/render3/interfaces/node.ts" ], [ - "packages/router/src/router.ts", - "packages/router/src/operators/resolve_data.ts" + "packages/core/src/render3/interfaces/definition.ts", + "packages/core/src/render3/interfaces/view.ts" ], [ - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts" + "packages/core/src/render3/interfaces/definition.ts", + "packages/core/src/render3/interfaces/view.ts", + "packages/core/src/render3/interfaces/node.ts" ], [ - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/validators.ts", - "packages/forms/src/directives/validators.ts" + "packages/core/src/render3/interfaces/definition.ts", + "packages/core/src/render3/interfaces/view.ts", + "packages/core/src/render3/interfaces/query.ts", + "packages/core/src/render3/interfaces/node.ts" ], [ - "packages/forms/src/validators.ts", - "packages/forms/src/directives/validators.ts" + "packages/core/src/render3/interfaces/query.ts", + "packages/core/src/render3/interfaces/view.ts" ], [ - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/validators.ts" + "packages/core/testing/src/r3_test_bed.ts", + "packages/core/testing/src/test_bed_common.ts", + "packages/core/testing/src/test_bed.ts" ], [ - "packages/forms/src/directives/abstract_control_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts" + "packages/core/testing/src/r3_test_bed.ts", + "packages/core/testing/src/test_bed.ts" ], [ + "packages/forms/src/directives/abstract_control_directive.ts", "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/abstract_form_group_directive.ts" + "packages/forms/src/directives/shared.ts" ], [ "packages/forms/src/directives/abstract_control_directive.ts", @@ -1886,11 +1828,13 @@ "packages/forms/src/directives/control_container.ts" ], [ + "packages/forms/src/directives/abstract_control_directive.ts", "packages/forms/src/model.ts", "packages/forms/src/directives/shared.ts", "packages/forms/src/directives/abstract_form_group_directive.ts", "packages/forms/src/directives/control_container.ts", - "packages/forms/src/directives/form_interface.ts" + "packages/forms/src/directives/form_interface.ts", + "packages/forms/src/directives/ng_control.ts" ], [ "packages/forms/src/directives/abstract_form_group_directive.ts", @@ -1898,13 +1842,20 @@ "packages/forms/src/directives/form_interface.ts" ], [ - "packages/forms/src/directives/abstract_control_directive.ts", - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", "packages/forms/src/directives/abstract_form_group_directive.ts", "packages/forms/src/directives/control_container.ts", "packages/forms/src/directives/form_interface.ts", - "packages/forms/src/directives/ng_control.ts" + "packages/forms/src/model.ts", + "packages/forms/src/directives/shared.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/directives/shared.ts" + ], + [ + "packages/forms/src/directives/abstract_form_group_directive.ts", + "packages/forms/src/model.ts", + "packages/forms/src/directives/shared.ts" ], [ "packages/forms/src/directives/control_container.ts", @@ -1912,108 +1863,157 @@ "packages/forms/src/directives/ng_control.ts" ], [ - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/abstract_form_group_directive.ts" + "packages/forms/src/directives/ng_form.ts", + "packages/forms/src/directives/ng_model.ts" ], [ - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/normalize_validator.ts" + "packages/forms/src/directives/ng_form.ts", + "packages/forms/src/directives/ng_model.ts", + "packages/forms/src/directives/ng_model_group.ts" ], [ + "packages/forms/src/directives/normalize_validator.ts", "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts" + "packages/forms/src/directives/shared.ts" ], [ + "packages/forms/src/directives/reactive_directives/form_control_directive.ts", "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts" + "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_group_directive.ts", + "packages/forms/src/directives/reactive_directives/form_control_name.ts" ], [ + "packages/forms/src/directives/reactive_directives/form_control_directive.ts", "packages/forms/src/model.ts", "packages/forms/src/directives/shared.ts", "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts" + "packages/forms/src/directives/reactive_directives/form_group_directive.ts", + "packages/forms/src/directives/reactive_directives/form_control_name.ts" ], [ - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_control_name.ts", "packages/forms/src/directives/reactive_directives/form_group_directive.ts" ], [ - "packages/forms/src/model.ts", - "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_control_name.ts", "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts" + "packages/forms/src/directives/reactive_directives/form_group_directive.ts" ], [ + "packages/forms/src/directives/reactive_directives/form_control_name.ts", "packages/forms/src/directives/shared.ts", "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts" + "packages/forms/src/directives/reactive_directives/form_group_directive.ts" ], [ + "packages/forms/src/directives/reactive_directives/form_control_name.ts", "packages/forms/src/model.ts", "packages/forms/src/directives/shared.ts", "packages/forms/src/directives/reactive_directives/form_group_name.ts", + "packages/forms/src/directives/reactive_directives/form_group_directive.ts" + ], + [ "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts", - "packages/forms/src/directives/reactive_directives/form_control_directive.ts" + "packages/forms/src/directives/reactive_directives/form_group_name.ts" ], [ - "packages/forms/src/directives/shared.ts", - "packages/forms/src/directives/reactive_directives/form_group_name.ts", "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts", - "packages/forms/src/directives/reactive_directives/form_control_directive.ts" + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts" ], [ "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts" + "packages/forms/src/model.ts", + "packages/forms/src/directives/shared.ts", + "packages/forms/src/directives/reactive_directives/form_group_name.ts" ], [ "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts", - "packages/forms/src/directives/reactive_directives/form_control_name.ts" + "packages/forms/src/directives/shared.ts" ], [ "packages/forms/src/directives/reactive_directives/form_group_name.ts", - "packages/forms/src/directives/reactive_directives/form_group_directive.ts" + "packages/forms/src/model.ts", + "packages/forms/src/directives/shared.ts" ], [ - "packages/forms/src/directives/ng_form.ts", - "packages/forms/src/directives/ng_model.ts" + "packages/forms/src/directives/shared.ts", + "packages/forms/src/model.ts" ], [ - "packages/forms/src/directives/ng_form.ts", - "packages/forms/src/directives/ng_model.ts", - "packages/forms/src/directives/ng_model_group.ts" + "packages/forms/src/directives/shared.ts", + "packages/forms/src/validators.ts", + "packages/forms/src/directives/validators.ts", + "packages/forms/src/model.ts" ], [ - "packages/compiler-cli/ngcc/src/packages/configuration.ts", - "packages/compiler-cli/ngcc/src/packages/entry_point.ts" + "packages/forms/src/directives/shared.ts", + "packages/forms/src/validators.ts", + "packages/forms/src/model.ts" ], [ - "packages/compiler-cli/test/helpers/index.ts", - "packages/compiler-cli/test/helpers/src/mock_file_loading.ts" + "packages/forms/src/directives/validators.ts", + "packages/forms/src/validators.ts" ], [ "packages/language-service/src/common.ts", "packages/language-service/src/types.ts" ], + [ + "packages/language-service/src/completions.ts", + "packages/language-service/src/template.ts", + "packages/language-service/src/typescript_host.ts", + "packages/language-service/src/language_service.ts" + ], [ "packages/language-service/src/expression_diagnostics.ts", "packages/language-service/src/utils.ts" ], [ - "packages/language-service/src/language_service.ts", - "packages/language-service/src/completions.ts", "packages/language-service/src/template.ts", "packages/language-service/src/typescript_host.ts" ], [ - "packages/language-service/src/template.ts", - "packages/language-service/src/typescript_host.ts" + "packages/router/src/config.ts", + "packages/router/src/router_state.ts" + ], + [ + "packages/router/src/config.ts", + "packages/router/src/router_state.ts", + "packages/router/src/shared.ts" + ], + [ + "packages/router/src/directives/router_outlet.ts", + "packages/router/src/router_outlet_context.ts" + ], + [ + "packages/router/src/operators/activate_routes.ts", + "packages/router/src/router.ts" + ], + [ + "packages/router/src/operators/apply_redirects.ts", + "packages/router/src/router.ts" + ], + [ + "packages/router/src/operators/check_guards.ts", + "packages/router/src/router.ts" + ], + [ + "packages/router/src/operators/recognize.ts", + "packages/router/src/router.ts" + ], + [ + "packages/router/src/operators/resolve_data.ts", + "packages/router/src/router.ts" + ], + [ + "packages/router/src/shared.ts", + "packages/router/src/url_tree.ts" + ], + [ + "packages/router/src/shared.ts", + "packages/router/src/url_tree.ts", + "packages/router/src/utils/collection.ts" ] ] \ No newline at end of file From 03f2f1ae47ef4df062a5af655027490b5b514885 Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Wed, 8 Apr 2020 08:28:03 -0700 Subject: [PATCH 157/262] build(bazel): fix runfiles resolve in karma-saucelabs.js after $location => $rootpath cleanup (#36511) This wasn't caught by CI on the PR as this binary is only run once daily via a monitor job. PR Close #36511 --- tools/saucelabs/karma-saucelabs.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/saucelabs/karma-saucelabs.js b/tools/saucelabs/karma-saucelabs.js index b5d832264497f..0ad9a9dba11de 100644 --- a/tools/saucelabs/karma-saucelabs.js +++ b/tools/saucelabs/karma-saucelabs.js @@ -10,7 +10,7 @@ const shell = require('shelljs'); const karmaBin = require.resolve('karma/bin/karma'); const runfiles = require(process.env['BAZEL_NODE_RUNFILES_HELPER']); -const sauceService = runfiles.resolve(process.argv[2]); +const sauceService = runfiles.resolveWorkspaceRelative(process.argv[2]); process.argv = [ process.argv[0], karmaBin, @@ -61,7 +61,7 @@ try { } console.error(`Launching karma ${karmaBin}...`); - module.constructor._load(karmaBin, this, /*isMain=*/true); + module.constructor._load(karmaBin, this, /*isMain=*/ true); } catch (e) { console.error(e.stack || e); process.exit(1); From b40b5576df83745c42a45c6379038a51a90f8ac0 Mon Sep 17 00:00:00 2001 From: Kara Erickson <karakara@google.com> Date: Wed, 8 Apr 2020 12:28:12 -0700 Subject: [PATCH 158/262] release: cut the v10.0.0-next.1 release --- CHANGELOG.md | 5 +++++ package.json | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 621ce88083b2c..8d1c79f97c0a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +<a name="10.0.0-next.1"></a> +# [10.0.0-next.1](https://github.com/angular/angular/compare/10.0.0-next.0...10.0.0-next.1) (2020-04-08) + +This release contains various API docs improvements. + <a name="10.0.0-next.0"></a> # [10.0.0-next.0](https://github.com/angular/angular/compare/9.1.0-rc.0...10.0.0-next.0) (2020-04-08) diff --git a/package.json b/package.json index 717e1c28b77b1..0f2589f78967f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "angular-srcs", - "version": "10.0.0-next.0", + "version": "10.0.0-next.1", "private": true, "description": "Angular - a web framework for modern web apps", "homepage": "https://github.com/angular/angular", From 717df132077d5bea378653f963cd613d6a15b987 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Wed, 8 Apr 2020 19:34:19 +0100 Subject: [PATCH 159/262] fix(ngcc): do not warn if `paths` mapping does not exist (#36525) In cc4b813e759f16fb0f4dfa92a0e6464ed768a629 the `getBasePaths()` function was changed to log a warning if a `basePath()` computed from the `paths` mappings did not exist. It turns out this is a common and accepted scenario, so we should not log warnings in this case. Fixes #36518 PR Close #36525 --- packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts | 2 +- .../compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts index 67f2a2f332217..ff0da04eddf36 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/utils.ts @@ -50,7 +50,7 @@ export function getBasePaths( if (fs.exists(basePath)) { basePaths.push(basePath); } else { - logger.warn( + logger.debug( `The basePath "${basePath}" computed from baseUrl "${baseUrl}" and path mapping "${ path}" does not exist in the file-system.\n` + `It will not be scanned for entry-points.`); diff --git a/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts b/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts index 840a3e1b45eb8..41b893c9e2d77 100644 --- a/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts +++ b/packages/compiler-cli/ngcc/test/entry_point_finder/utils_spec.ts @@ -115,7 +115,7 @@ runInEachFileSystem(() => { ]); }); - it('should discard basePaths that do not exists and log a warning', () => { + it('should discard basePaths that do not exists and log a debug message', () => { const projectDirectory = _('/path/to/project'); const fs = getFileSystem(); fs.ensureDir(fs.resolve(projectDirectory, 'dist-1')); @@ -131,7 +131,7 @@ runInEachFileSystem(() => { sourceDirectory, fs.resolve(projectDirectory, 'dist-1'), ]); - expect(logger.logs.warn).toEqual([ + expect(logger.logs.debug).toEqual([ [`The basePath "${ fs.resolve(projectDirectory, 'sub-folder/dist-2')}" computed from baseUrl "${ projectDirectory}" and path mapping "sub-folder/dist-2" does not exist in the file-system.\n` + From 0a69a2832b0d6d08ee4b301517e447dd3232339b Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh <alx+alxhub@alxandria.net> Date: Tue, 7 Apr 2020 12:43:43 -0700 Subject: [PATCH 160/262] style(compiler-cli): reformat of codebase with new clang-format version (#36520) This commit reformats the packages/compiler-cli tree using the new version of clang-format. PR Close #36520 --- .../bazel/injectable_def/app/src/dep.ts | 4 +- .../bazel/injectable_def/app/src/hierarchy.ts | 4 +- .../bazel/injectable_def/app/src/self.ts | 4 +- .../bazel/injectable_def/app/src/string.ts | 4 +- .../bazel/injectable_def/app/src/token.ts | 10 +- .../bazel/injectable_def/app/test/app_spec.ts | 7 +- .../ivy_build/app/test/module_spec.ts | 18 +- .../feature/lazy-feature.module.ts | 6 +- .../integrationtest/src/animate.ts | 18 +- .../integrationtest/src/custom_token.ts | 4 +- .../integrationtest/src/errors.ts | 4 +- .../integrationtest/src/features.ts | 9 +- .../integrationtest/src/jit_summaries.ts | 10 +- .../integrationtest/src/module.ts | 2 +- .../integrationtest/src/module_fixtures.ts | 18 +- .../test/jit_summaries_spec.ts | 8 +- .../integrationtest/test/ng_module_spec.ts | 2 +- .../integrationtest/test/query_spec.ts | 1 - .../integrationtest/test/source_map_spec.ts | 2 +- .../integrationtest/test/test_ngtools_api.ts | 16 +- .../compiler-cli/integrationtest/test/util.ts | 2 +- .../src/diagnostics/translate_diagnostics.ts | 5 +- .../compiler-cli/src/language_services.ts | 2 +- packages/compiler-cli/src/main.ts | 32 +- .../src/metadata/bundle_index_host.ts | 7 +- packages/compiler-cli/src/metadata/bundler.ts | 61 +-- .../compiler-cli/src/metadata/collector.ts | 89 ++-- .../compiler-cli/src/metadata/evaluator.ts | 15 +- packages/compiler-cli/src/metadata/schema.ts | 55 +-- packages/compiler-cli/src/metadata/symbols.ts | 10 +- .../src/ngtsc/annotations/src/component.ts | 63 +-- .../src/ngtsc/annotations/src/diagnostics.ts | 18 +- .../src/ngtsc/annotations/src/directive.ts | 180 +++++---- .../src/ngtsc/annotations/src/factory.ts | 2 +- .../src/ngtsc/annotations/src/injectable.ts | 21 +- .../src/ngtsc/annotations/src/metadata.ts | 4 +- .../src/ngtsc/annotations/src/ng_module.ts | 48 ++- .../src/ngtsc/annotations/src/pipe.ts | 9 +- .../src/ngtsc/annotations/src/util.ts | 34 +- .../ngtsc/annotations/test/component_spec.ts | 20 +- .../ngtsc/annotations/test/directive_spec.ts | 11 +- .../ngtsc/annotations/test/injectable_spec.ts | 5 +- .../ngtsc/annotations/test/metadata_spec.ts | 3 +- .../ngtsc/annotations/test/ng_module_spec.ts | 4 +- .../src/ngtsc/annotations/test/util_spec.ts | 5 +- .../src/ngtsc/core/api/src/interfaces.ts | 2 +- .../src/ngtsc/core/api/src/options.ts | 6 +- .../src/ngtsc/core/src/compiler.ts | 54 ++- .../compiler-cli/src/ngtsc/core/src/host.ts | 5 +- .../src/ngtsc/core/test/compiler_test.ts | 3 +- .../src/ngtsc/cycles/src/imports.ts | 6 +- .../src/ngtsc/diagnostics/src/error.ts | 3 +- .../src/ngtsc/entry_point/src/generator.ts | 4 +- .../entry_point/src/private_export_checker.ts | 8 +- .../ngtsc/entry_point/src/reference_graph.ts | 6 +- .../entry_point/test/entry_point_spec.ts | 6 +- .../entry_point/test/reference_graph_spec.ts | 10 +- .../file_system/src/cached_file_system.ts | 50 ++- .../ngtsc/file_system/src/compiler_host.ts | 12 +- .../file_system/src/invalid_file_system.ts | 104 +++-- .../src/ngtsc/file_system/src/logical.ts | 2 +- .../file_system/src/node_js_file_system.ts | 70 +++- .../src/ngtsc/file_system/src/types.ts | 4 +- .../src/ngtsc/file_system/src/util.ts | 4 +- .../ngtsc/file_system/test/helpers_spec.ts | 48 ++- .../src/ngtsc/file_system/testing/index.ts | 2 +- .../testing/src/mock_file_system.ts | 60 ++- .../testing/src/mock_file_system_native.ts | 16 +- .../testing/src/mock_file_system_posix.ts | 12 +- .../testing/src/mock_file_system_windows.ts | 12 +- .../file_system/testing/src/test_helper.ts | 14 +- .../compiler-cli/src/ngtsc/imports/index.ts | 2 +- .../src/ngtsc/imports/src/alias.ts | 6 +- .../src/ngtsc/imports/src/core.ts | 22 +- .../src/ngtsc/imports/src/default.ts | 26 +- .../src/ngtsc/imports/src/emitter.ts | 23 +- .../src/ngtsc/imports/src/references.ts | 12 +- .../src/ngtsc/imports/test/default_spec.ts | 8 +- .../src/ngtsc/imports/test/emitter_spec.ts | 20 +- .../compiler-cli/src/ngtsc/incremental/api.ts | 2 +- .../incremental/src/dependency_tracking.ts | 10 +- .../src/ngtsc/incremental/src/state.ts | 12 +- .../compiler-cli/src/ngtsc/indexer/src/api.ts | 22 +- .../src/ngtsc/indexer/src/context.ts | 4 +- .../src/ngtsc/indexer/src/template.ts | 40 +- .../src/ngtsc/indexer/test/context_spec.ts | 6 +- .../src/ngtsc/indexer/test/template_spec.ts | 70 ++-- .../src/ngtsc/indexer/test/transform_spec.ts | 8 +- .../src/ngtsc/indexer/test/util.ts | 5 +- .../src/ngtsc/metadata/src/dts.ts | 2 +- .../src/ngtsc/metadata/src/inheritance.ts | 2 +- .../src/ngtsc/metadata/src/registry.ts | 22 +- .../src/ngtsc/metadata/src/util.ts | 6 +- .../ngtsc/modulewithproviders/src/scanner.ts | 4 +- .../compiler-cli/src/ngtsc/perf/src/noop.ts | 12 +- .../src/ngtsc/perf/src/tracking.ts | 8 +- packages/compiler-cli/src/ngtsc/program.ts | 37 +- .../src/ngtsc/reflection/src/host.ts | 23 +- .../src/ngtsc/reflection/src/type_to_value.ts | 8 +- .../src/ngtsc/reflection/src/typescript.ts | 48 ++- .../src/ngtsc/reflection/test/ts_host_spec.ts | 47 ++- .../src/ngtsc/resource/src/loader.ts | 9 +- .../src/ngtsc/routing/src/analyzer.ts | 17 +- .../src/ngtsc/routing/src/lazy.ts | 52 +-- .../src/ngtsc/routing/src/route.ts | 10 +- .../src/ngtsc/scope/src/dependency.ts | 6 +- .../compiler-cli/src/ngtsc/scope/src/local.ts | 70 ++-- .../src/ngtsc/scope/test/dependency_spec.ts | 24 +- .../src/ngtsc/scope/test/local_spec.ts | 14 +- .../src/ngtsc/shims/src/factory_generator.ts | 24 +- .../src/ngtsc/shims/src/factory_tracker.ts | 2 +- .../src/ngtsc/shims/src/summary_generator.ts | 12 +- .../src/ngtsc/shims/src/typecheck_shim.ts | 4 +- .../src/ngtsc/switch/src/switch.ts | 4 +- .../src/ngtsc/testing/src/utils.ts | 7 +- .../src/ngtsc/transform/src/alias.ts | 2 +- .../src/ngtsc/transform/src/compilation.ts | 48 ++- .../src/ngtsc/transform/src/declaration.ts | 14 +- .../src/ngtsc/transform/src/trait.ts | 14 +- .../src/ngtsc/transform/src/transform.ts | 4 +- .../ngtsc/transform/test/compilation_spec.ts | 10 +- .../src/ngtsc/translator/src/translator.ts | 46 ++- packages/compiler-cli/src/ngtsc/tsc_plugin.ts | 18 +- .../src/ngtsc/typecheck/src/api.ts | 4 +- .../src/ngtsc/typecheck/src/context.ts | 16 +- .../src/ngtsc/typecheck/src/diagnostics.ts | 7 +- .../src/ngtsc/typecheck/src/dom.ts | 20 +- .../src/ngtsc/typecheck/src/environment.ts | 7 +- .../src/ngtsc/typecheck/src/expression.ts | 84 +++- .../src/ngtsc/typecheck/src/host.ts | 18 +- .../src/ngtsc/typecheck/src/oob.ts | 15 +- .../src/ngtsc/typecheck/src/source.ts | 4 +- .../ngtsc/typecheck/src/type_check_block.ts | 53 +-- .../ngtsc/typecheck/src/type_check_file.ts | 4 +- .../ngtsc/typecheck/src/type_constructor.ts | 17 +- .../src/ngtsc/typecheck/src/type_emitter.ts | 10 +- .../typecheck/src/type_parameter_emitter.ts | 4 +- .../ngtsc/typecheck/test/diagnostics_spec.ts | 8 +- .../typecheck/test/span_comments_spec.ts | 2 +- .../src/ngtsc/typecheck/test/test_utils.ts | 51 +-- .../typecheck/test/type_check_block_spec.ts | 10 +- .../typecheck/test/type_constructor_spec.ts | 14 +- .../test/type_parameter_emitter_spec.ts | 9 +- .../ngtsc/util/src/ts_source_map_bug_29300.ts | 42 +- .../src/ngtsc/util/src/typescript.ts | 6 +- .../src/ngtsc/util/src/visitor.ts | 15 +- .../src/ngtsc/util/test/visitor_spec.ts | 18 +- packages/compiler-cli/src/perform_compile.ts | 67 +-- packages/compiler-cli/src/perform_watch.ts | 15 +- packages/compiler-cli/src/transformers/api.ts | 24 +- .../src/transformers/compiler_host.ts | 59 +-- .../src/transformers/inline_resources.ts | 17 +- .../src/transformers/lower_expressions.ts | 43 +- .../src/transformers/node_emitter.ts | 193 +++++---- .../compiler-cli/src/transformers/program.ts | 150 ++++--- .../src/transformers/r3_metadata_transform.ts | 2 +- .../src/transformers/r3_strip_decorators.ts | 14 +- .../compiler-cli/src/transformers/util.ts | 15 +- .../compiler-cli/src/typescript_support.ts | 4 +- .../test/compliance/mock_compile.ts | 28 +- .../test/compliance/mock_compiler_spec.ts | 4 +- .../compliance/r3_compiler_compliance_spec.ts | 24 +- .../r3_view_compiler_binding_spec.ts | 15 +- .../compliance/r3_view_compiler_di_spec.ts | 5 +- .../r3_view_compiler_directives_spec.ts | 8 - .../compliance/r3_view_compiler_i18n_spec.ts | 371 +++++++++-------- .../r3_view_compiler_input_outputs_spec.ts | 1 - .../r3_view_compiler_listener_spec.ts | 8 +- .../r3_view_compiler_styling_spec.ts | 12 +- .../r3_view_compiler_template_spec.ts | 14 +- .../test/diagnostics/check_types_spec.ts | 71 ++-- .../diagnostics/typescript_version_spec.ts | 5 +- .../compiler-cli/test/extract_i18n_spec.ts | 4 +- .../test/helpers/src/mock_file_loading.ts | 2 +- .../test/helpers/src/runfile_helpers.ts | 2 +- .../test/metadata/bundler_spec.ts | 27 +- .../test/metadata/collector_spec.ts | 381 +++++++++--------- .../test/metadata/evaluator_spec.ts | 65 ++- .../test/metadata/symbols_spec.ts | 10 +- .../test/metadata/typescript.mocks.ts | 128 ++++-- packages/compiler-cli/test/mocks.ts | 65 ++- .../test/ngtsc/component_indexing_spec.ts | 8 +- packages/compiler-cli/test/ngtsc/env.ts | 41 +- .../test/ngtsc/fake_core/index.ts | 22 +- .../test/ngtsc/incremental_error_spec.ts | 10 +- .../test/ngtsc/incremental_spec.ts | 2 +- .../test/ngtsc/modulewithproviders_spec.ts | 2 +- .../compiler-cli/test/ngtsc/monorepo_spec.ts | 2 +- .../compiler-cli/test/ngtsc/ngtsc_spec.ts | 41 +- .../compiler-cli/test/ngtsc/scope_spec.ts | 18 +- .../test/ngtsc/sourcemap_utils.ts | 2 +- .../test/ngtsc/template_mapping_spec.ts | 7 +- .../test/ngtsc/template_typecheck_spec.ts | 27 +- .../compiler-cli/test/perform_compile_spec.ts | 2 +- .../compiler-cli/test/perform_watch_spec.ts | 50 ++- packages/compiler-cli/test/test_support.ts | 9 +- .../test/transformers/compiler_host_spec.ts | 19 +- .../transformers/inline_resources_spec.ts | 4 +- .../transformers/lower_expressions_spec.ts | 13 +- .../test/transformers/metadata_reader_spec.ts | 21 +- .../test/transformers/node_emitter_spec.ts | 90 +++-- .../test/transformers/program_spec.ts | 67 ++- .../r3_metadata_transform_spec.ts | 3 +- .../test/transformers/r3_transform_spec.ts | 11 +- .../test/typescript_support_spec.ts | 4 +- 205 files changed, 2950 insertions(+), 2123 deletions(-) diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts index 4cc1c02b7d985..2e3c21564bae7 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/dep.ts @@ -20,7 +20,9 @@ export class NormalService { }) export class AppComponent { found: boolean; - constructor(service: ShakeableService) { this.found = !!service.normal; } + constructor(service: ShakeableService) { + this.found = !!service.normal; + } } @NgModule({ diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts index 86daf887989b8..2465c74ad0385 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/hierarchy.ts @@ -29,7 +29,9 @@ export class AppComponent { export class ChildComponent { found: boolean; - constructor(@Optional() @Self() service: Service|null) { this.found = !!service; } + constructor(@Optional() @Self() service: Service|null) { + this.found = !!service; + } } @NgModule({ diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts index fb37c76e40657..324b05931541d 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/self.ts @@ -21,7 +21,9 @@ export class NormalService { }) export class AppComponent { found: boolean; - constructor(service: NormalService) { this.found = !!service.shakeable; } + constructor(service: NormalService) { + this.found = !!service.shakeable; + } } @NgModule({ diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts index fca98267bd6eb..3187a87e9b44a 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/string.ts @@ -17,7 +17,9 @@ import {ServerModule} from '@angular/platform-server'; }) export class AppComponent { data: string; - constructor(service: Service) { this.data = service.data; } + constructor(service: Service) { + this.data = service.data; + } } @NgModule({ diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts index 3b93c3e5d8591..e3ca53e5d465a 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/src/token.ts @@ -6,11 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, Inject, Injectable, InjectionToken, NgModule, forwardRef, inject} from '@angular/core'; +import {Component, forwardRef, Inject, inject, Injectable, InjectionToken, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {ServerModule} from '@angular/platform-server'; -export interface IService { readonly dep: {readonly data: string;}; } +export interface IService { + readonly dep: {readonly data: string;}; +} @NgModule({}) export class TokenModule { @@ -28,7 +30,9 @@ export const TOKEN = new InjectionToken('test', { }) export class AppComponent { data: string; - constructor(@Inject(TOKEN) service: IService) { this.data = service.dep.data; } + constructor(@Inject(TOKEN) service: IService) { + this.data = service.dep.data; + } } @NgModule({ diff --git a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts index 793a27c4d6891..5311662b1062b 100644 --- a/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts +++ b/packages/compiler-cli/integrationtest/bazel/injectable_def/app/test/app_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, INJECTOR, Injectable, NgModule} from '@angular/core'; +import {Component, Injectable, INJECTOR, NgModule} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {renderModuleFactory} from '@angular/platform-server'; import {BasicAppModuleNgFactory} from 'app_built/src/basic.ngfactory'; @@ -104,7 +104,6 @@ describe('ngInjectableDef Bazel Integration', () => { }); it('allows provider override in JIT for module-scoped @Injectables', () => { - @NgModule() class Module { } @@ -172,7 +171,9 @@ describe('ngInjectableDef Bazel Integration', () => { // ChildServices exteds ParentService but does not have @Injectable class ChildService extends ParentService { - constructor(value: string) { super(value); } + constructor(value: string) { + super(value); + } static ngInjectableDef = { providedIn: 'root', factory: () => new ChildService('child'), diff --git a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts index 2ff1d1364de26..ea3f99aaca41c 100644 --- a/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts +++ b/packages/compiler-cli/integrationtest/bazel/injector_def/ivy_build/app/test/module_spec.ts @@ -6,17 +6,23 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injectable, InjectionToken, Injector, NgModule, forwardRef, ɵcreateInjector as createInjector} from '@angular/core'; +import {forwardRef, Injectable, InjectionToken, Injector, NgModule, ɵcreateInjector as createInjector} from '@angular/core'; import {AOT_TOKEN, AotModule, AotService} from 'app_built/src/module'; describe('Ivy NgModule', () => { describe('AOT', () => { let injector: Injector; - beforeEach(() => { injector = createInjector(AotModule); }); - it('works', () => { expect(injector.get(AotService) instanceof AotService).toBeTruthy(); }); + beforeEach(() => { + injector = createInjector(AotModule); + }); + it('works', () => { + expect(injector.get(AotService) instanceof AotService).toBeTruthy(); + }); - it('merges imports and exports', () => { expect(injector.get(AOT_TOKEN)).toEqual('exports'); }); + it('merges imports and exports', () => { + expect(injector.get(AOT_TOKEN)).toEqual('exports'); + }); }); @@ -38,7 +44,9 @@ describe('Ivy NgModule', () => { class JitAppModule { } - it('works', () => { createInjector(JitAppModule); }); + it('works', () => { + createInjector(JitAppModule); + }); it('throws an error on circular module dependencies', () => { @NgModule({ diff --git a/packages/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts b/packages/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts index 64e9bc4488092..b57ecc46e54a1 100644 --- a/packages/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts +++ b/packages/compiler-cli/integrationtest/ngtools_src/feature/lazy-feature.module.ts @@ -16,10 +16,8 @@ export class LazyFeatureComponent { @NgModule({ imports: [RouterModule.forChild([ {path: '', component: LazyFeatureComponent, pathMatch: 'full'}, - {path: 'feature', loadChildren: './feature.module#FeatureModule'}, { - path: 'nested-feature', - loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule' - } + {path: 'feature', loadChildren: './feature.module#FeatureModule'}, + {path: 'nested-feature', loadChildren: './lazy-feature-nested.module#LazyFeatureNestedModule'} ])], declarations: [LazyFeatureComponent] }) diff --git a/packages/compiler-cli/integrationtest/src/animate.ts b/packages/compiler-cli/integrationtest/src/animate.ts index 0c746888bda40..3b187e9130bcd 100644 --- a/packages/compiler-cli/integrationtest/src/animate.ts +++ b/packages/compiler-cli/integrationtest/src/animate.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, animate, state, style, transition, trigger} from '@angular/animations'; +import {animate, AUTO_STYLE, state, style, transition, trigger} from '@angular/animations'; import {Component} from '@angular/core'; @Component({ @@ -30,8 +30,16 @@ import {Component} from '@angular/core'; }) export class AnimateCmp { stateExpression: string; - constructor() { this.setAsClosed(); } - setAsSomethingElse() { this.stateExpression = 'something'; } - setAsOpen() { this.stateExpression = 'open'; } - setAsClosed() { this.stateExpression = 'closed'; } + constructor() { + this.setAsClosed(); + } + setAsSomethingElse() { + this.stateExpression = 'something'; + } + setAsOpen() { + this.stateExpression = 'open'; + } + setAsClosed() { + this.stateExpression = 'closed'; + } } diff --git a/packages/compiler-cli/integrationtest/src/custom_token.ts b/packages/compiler-cli/integrationtest/src/custom_token.ts index 698b4dd5fe2e2..4db05e42320c4 100644 --- a/packages/compiler-cli/integrationtest/src/custom_token.ts +++ b/packages/compiler-cli/integrationtest/src/custom_token.ts @@ -8,6 +8,8 @@ import {InjectionToken} from '@angular/core'; -export interface Named { name: string; } +export interface Named { + name: string; +} export const CUSTOM = new InjectionToken<Named>('CUSTOM'); diff --git a/packages/compiler-cli/integrationtest/src/errors.ts b/packages/compiler-cli/integrationtest/src/errors.ts index fc25afe56e2ab..0165521d8cdd0 100644 --- a/packages/compiler-cli/integrationtest/src/errors.ts +++ b/packages/compiler-cli/integrationtest/src/errors.ts @@ -10,5 +10,7 @@ import {Component} from '@angular/core'; @Component({selector: 'comp-with-error', templateUrl: 'errors.html'}) export class BindingErrorComp { - createError() { throw new Error('Test'); } + createError() { + throw new Error('Test'); + } } diff --git a/packages/compiler-cli/integrationtest/src/features.ts b/packages/compiler-cli/integrationtest/src/features.ts index 756cbd0b79288..47cde6908b84a 100644 --- a/packages/compiler-cli/integrationtest/src/features.ts +++ b/packages/compiler-cli/integrationtest/src/features.ts @@ -7,7 +7,7 @@ */ import * as common from '@angular/common'; -import {CUSTOM_ELEMENTS_SCHEMA, Component, Directive, EventEmitter, Inject, InjectionToken, NgModule, Output, forwardRef} from '@angular/core'; +import {Component, CUSTOM_ELEMENTS_SCHEMA, Directive, EventEmitter, forwardRef, Inject, InjectionToken, NgModule, Output} from '@angular/core'; import {Observable} from 'rxjs'; import {wrapInArray} from './funcs'; @@ -62,7 +62,9 @@ export class CompUsingCustomElements { }) export class CompConsumingEvents { handleDomEventVoid(e: any): void {} - handleDomEventPreventDefault(e: any): boolean { return false; } + handleDomEventPreventDefault(e: any): boolean { + return false; + } handleDirEvent(e: any): void {} } @@ -70,8 +72,7 @@ export class CompConsumingEvents { selector: '[dirEvent]', }) export class DirPublishingEvents { - @Output('dirEvent') - dirEvent: Observable<string> = new EventEmitter(); + @Output('dirEvent') dirEvent: Observable<string> = new EventEmitter(); } @NgModule({schemas: [CUSTOM_ELEMENTS_SCHEMA], declarations: wrapInArray(CompUsingCustomElements)}) diff --git a/packages/compiler-cli/integrationtest/src/jit_summaries.ts b/packages/compiler-cli/integrationtest/src/jit_summaries.ts index 8d2bccf698645..9221608aa12a0 100644 --- a/packages/compiler-cli/integrationtest/src/jit_summaries.ts +++ b/packages/compiler-cli/integrationtest/src/jit_summaries.ts @@ -11,7 +11,7 @@ import {Component, Directive, Injectable, NgModule, Pipe} from '@angular/core'; const instances = new Map<any, Base>(); export function expectInstanceCreated(type: any) { - const instance = instances.get(type) !; + const instance = instances.get(type)!; expect(instance).toBeDefined(); expect(instance.dep instanceof SomeDep).toBe(true); } @@ -19,7 +19,9 @@ export function expectInstanceCreated(type: any) { export class SomeDep {} export class Base { - constructor(public dep: SomeDep) { instances.set(Object.getPrototypeOf(this).constructor, this); } + constructor(public dep: SomeDep) { + instances.set(Object.getPrototypeOf(this).constructor, this); + } } @Component({templateUrl: './jit_summaries.html'}) @@ -36,7 +38,9 @@ export class SomeDirective extends Base { @Pipe({name: 'somePipe'}) export class SomePipe extends Base { - transform(value: any) { return value; } + transform(value: any) { + return value; + } } @Injectable() diff --git a/packages/compiler-cli/integrationtest/src/module.ts b/packages/compiler-cli/integrationtest/src/module.ts index a3d8711a9387f..ead5e36920b1f 100644 --- a/packages/compiler-cli/integrationtest/src/module.ts +++ b/packages/compiler-cli/integrationtest/src/module.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ApplicationRef, NgModule, forwardRef} from '@angular/core'; +import {ApplicationRef, forwardRef, NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {ServerModule} from '@angular/platform-server'; import {FlatModule} from 'flat_module'; diff --git a/packages/compiler-cli/integrationtest/src/module_fixtures.ts b/packages/compiler-cli/integrationtest/src/module_fixtures.ts index 18fe662ac1d0f..0fd71d8c69110 100644 --- a/packages/compiler-cli/integrationtest/src/module_fixtures.ts +++ b/packages/compiler-cli/integrationtest/src/module_fixtures.ts @@ -19,24 +19,26 @@ export class ServiceUsingLibModule { @Directive({selector: '[someDir]', host: {'[title]': 'someDir'}}) export class SomeDirectiveInRootModule { - @Input() - someDir: string; + @Input() someDir: string; } @Directive({selector: '[someDir]', host: {'[title]': 'someDir'}}) export class SomeDirectiveInLibModule { - @Input() - someDir: string; + @Input() someDir: string; } @Pipe({name: 'somePipe'}) export class SomePipeInRootModule { - transform(value: string): any { return `transformed ${value}`; } + transform(value: string): any { + return `transformed ${value}`; + } } @Pipe({name: 'somePipe'}) export class SomePipeInLibModule { - transform(value: string): any { return `transformed ${value}`; } + transform(value: string): any { + return `transformed ${value}`; + } } @Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`}) @@ -66,8 +68,8 @@ export class SomeLibModule { return { ngModule: SomeLibModule, providers: [ - ServiceUsingLibModule, provideValueWithEntryComponents( - [{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}]) + ServiceUsingLibModule, + provideValueWithEntryComponents([{a: 'b', component: CompUsingLibModuleDirectiveAndPipe}]) ] }; } diff --git a/packages/compiler-cli/integrationtest/test/jit_summaries_spec.ts b/packages/compiler-cli/integrationtest/test/jit_summaries_spec.ts index e68db802e2717..66ee77a3ca966 100644 --- a/packages/compiler-cli/integrationtest/test/jit_summaries_spec.ts +++ b/packages/compiler-cli/integrationtest/test/jit_summaries_spec.ts @@ -8,9 +8,9 @@ import {Component} from '@angular/core'; import {TestBed} from '@angular/core/testing'; -import {ServerTestingModule, platformServerTesting} from '@angular/platform-server/testing'; +import {platformServerTesting, ServerTestingModule} from '@angular/platform-server/testing'; -import {SomeDep, SomeDirective, SomeModule, SomePipe, SomePrivateComponent, SomeService, expectInstanceCreated} from '../src/jit_summaries'; +import {expectInstanceCreated, SomeDep, SomeDirective, SomeModule, SomePipe, SomePrivateComponent, SomeService} from '../src/jit_summaries'; import {SomeModuleNgSummary} from '../src/jit_summaries.ngsummary'; describe('Jit Summaries', () => { @@ -18,7 +18,9 @@ describe('Jit Summaries', () => { TestBed.initTestEnvironment(ServerTestingModule, platformServerTesting(), SomeModuleNgSummary); }); - afterEach(() => { TestBed.resetTestEnvironment(); }); + afterEach(() => { + TestBed.resetTestEnvironment(); + }); it('should use directive metadata from summaries', () => { @Component({template: '<div someDir></div>'}) diff --git a/packages/compiler-cli/integrationtest/test/ng_module_spec.ts b/packages/compiler-cli/integrationtest/test/ng_module_spec.ts index 4e58a8f4ea998..151c64211c398 100644 --- a/packages/compiler-cli/integrationtest/test/ng_module_spec.ts +++ b/packages/compiler-cli/integrationtest/test/ng_module_spec.ts @@ -10,7 +10,7 @@ import './init'; import {ComponentUsingThirdParty} from '../src/comp_using_3rdp'; import {ComponentUsingFlatModule} from '../src/comp_using_flat_module'; import {MainModule} from '../src/module'; -import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, SOME_TOKEN, ServiceUsingLibModule, SomeLibModule, SomeService} from '../src/module_fixtures'; +import {CompUsingLibModuleDirectiveAndPipe, CompUsingRootModuleDirectiveAndPipe, ServiceUsingLibModule, SOME_TOKEN, SomeLibModule, SomeService} from '../src/module_fixtures'; import {createComponent, createModule} from './util'; diff --git a/packages/compiler-cli/integrationtest/test/query_spec.ts b/packages/compiler-cli/integrationtest/test/query_spec.ts index 1d66f58c89a79..a97c91f142f14 100644 --- a/packages/compiler-cli/integrationtest/test/query_spec.ts +++ b/packages/compiler-cli/integrationtest/test/query_spec.ts @@ -19,7 +19,6 @@ describe('child queries', () => { debugElement.query(By.directive(CompWithChildQuery)); expect(childQueryCompFixture.componentInstance.child).toBeDefined(); expect(childQueryCompFixture.componentInstance.child instanceof CompForChildQuery).toBe(true); - }); it('should support compiling children queries', () => { diff --git a/packages/compiler-cli/integrationtest/test/source_map_spec.ts b/packages/compiler-cli/integrationtest/test/source_map_spec.ts index 25b4dd7b1b384..2b4ad439797a1 100644 --- a/packages/compiler-cli/integrationtest/test/source_map_spec.ts +++ b/packages/compiler-cli/integrationtest/test/source_map_spec.ts @@ -31,7 +31,7 @@ function getSourcePositionForStack(stack: string): {source: string, line: number const htmlLocations = stack .split('\n') // e.g. at View_MyComp_0 (...html:153:40) - .map(line => /\((.*\.html):(\d+):(\d+)/.exec(line) !) + .map(line => /\((.*\.html):(\d+):(\d+)/.exec(line)!) .filter(match => !!match) .map(match => ({ source: match[1], diff --git a/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts b/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts index f98bb420517d1..bff1e6cbc7369 100644 --- a/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts +++ b/packages/compiler-cli/integrationtest/test/test_ngtools_api.ts @@ -22,10 +22,15 @@ import {createProgram, readConfiguration} from '@angular/compiler-cli'; * properly read and wrote. */ function main() { - Promise.resolve().then(() => lazyRoutesTest()).then(() => { process.exit(0); }).catch((err) => { - console.error(err.stack); - process.exit(1); - }); + Promise.resolve() + .then(() => lazyRoutesTest()) + .then(() => { + process.exit(0); + }) + .catch((err) => { + console.error(err.stack); + process.exit(1); + }); } function lazyRoutesTest() { @@ -36,7 +41,8 @@ function lazyRoutesTest() { const host = ts.createCompilerHost(config.options, true); const program = createProgram({ rootNames: config.rootNames, - options: config.options, host, + options: config.options, + host, }); config.options.basePath = basePath; diff --git a/packages/compiler-cli/integrationtest/test/util.ts b/packages/compiler-cli/integrationtest/test/util.ts index 0fe1ae64d17de..05f6943f86882 100644 --- a/packages/compiler-cli/integrationtest/test/util.ts +++ b/packages/compiler-cli/integrationtest/test/util.ts @@ -13,7 +13,7 @@ import {platformServerTesting} from '@angular/platform-server/testing'; import {MainModule} from '../src/module'; import {MainModuleNgFactory} from '../src/module.ngfactory'; -let mainModuleRef: NgModuleRef<MainModule> = null !; +let mainModuleRef: NgModuleRef<MainModule> = null!; beforeEach((done) => { platformServerTesting().bootstrapModuleFactory(MainModuleNgFactory).then((moduleRef: any) => { mainModuleRef = moduleRef; diff --git a/packages/compiler-cli/src/diagnostics/translate_diagnostics.ts b/packages/compiler-cli/src/diagnostics/translate_diagnostics.ts index 46d98c2177a6c..d44d1f88526f9 100644 --- a/packages/compiler-cli/src/diagnostics/translate_diagnostics.ts +++ b/packages/compiler-cli/src/diagnostics/translate_diagnostics.ts @@ -35,7 +35,8 @@ export function translateDiagnostics( const fileName = span.start.file.url; ng.push({ messageText: diagnosticMessageToString(diagnostic.messageText), - category: diagnostic.category, span, + category: diagnostic.category, + span, source: SOURCE, code: DEFAULT_ERROR_CODE }); @@ -53,6 +54,6 @@ function sourceSpanOf(host: TypeCheckHost, source: ts.SourceFile, start: number) return host.parseSourceSpanOf(source.fileName, line, character); } -function diagnosticMessageToString(message: ts.DiagnosticMessageChain | string): string { +function diagnosticMessageToString(message: ts.DiagnosticMessageChain|string): string { return ts.flattenDiagnosticMessageText(message, '\n'); } diff --git a/packages/compiler-cli/src/language_services.ts b/packages/compiler-cli/src/language_services.ts index a59c053dc0d7b..3a75c881daf33 100644 --- a/packages/compiler-cli/src/language_services.ts +++ b/packages/compiler-cli/src/language_services.ts @@ -16,4 +16,4 @@ to the language service. */ export {MetadataCollector, ModuleMetadata} from './metadata'; export {CompilerOptions} from './transformers/api'; -export {MetadataReaderCache, MetadataReaderHost, createMetadataReaderCache, readMetadata} from './transformers/metadata_reader'; +export {createMetadataReaderCache, MetadataReaderCache, MetadataReaderHost, readMetadata} from './transformers/metadata_reader'; diff --git a/packages/compiler-cli/src/main.ts b/packages/compiler-cli/src/main.ts index 88b2fc37b5475..c57f62fbd003c 100644 --- a/packages/compiler-cli/src/main.ts +++ b/packages/compiler-cli/src/main.ts @@ -24,9 +24,9 @@ import {NodeJSFileSystem, setFileSystem} from './ngtsc/file_system'; export function main( args: string[], consoleError: (s: string) => void = console.error, config?: NgcParsedConfiguration, customTransformers?: api.CustomTransformers, programReuse?: { - program: api.Program | undefined, + program: api.Program|undefined, }, - modifiedResourceFiles?: Set<string>| null): number { + modifiedResourceFiles?: Set<string>|null): number { let {project, rootNames, options, errors: configErrors, watch, emitFlags} = config || readNgcCommandLineAndConfiguration(args); if (configErrors.length) { @@ -47,7 +47,9 @@ export function main( options, emitFlags, oldProgram, - emitCallback: createEmitCallback(options), customTransformers, modifiedResourceFiles + emitCallback: createEmitCallback(options), + customTransformers, + modifiedResourceFiles }); if (programReuse !== undefined) { programReuse.program = program; @@ -57,8 +59,8 @@ export function main( export function mainDiagnosticsForTest( args: string[], config?: NgcParsedConfiguration, - programReuse?: {program: api.Program | undefined}, - modifiedResourceFiles?: Set<string>| null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> { + programReuse?: {program: api.Program|undefined}, + modifiedResourceFiles?: Set<string>|null): ReadonlyArray<ts.Diagnostic|api.Diagnostic> { let {project, rootNames, options, errors: configErrors, watch, emitFlags} = config || readNgcCommandLineAndConfiguration(args); if (configErrors.length) { @@ -100,9 +102,10 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un options.emitDecoratorMetadata = true; } const tsickleHost: Pick< - tsickle.TsickleHost, 'shouldSkipTsickleProcessing'|'pathToModuleName'| - 'shouldIgnoreWarningsForPath'|'fileNameToModuleId'|'googmodule'|'untyped'| - 'convertIndexImportShorthand'|'transformDecorators'|'transformTypesToClosure'> = { + tsickle.TsickleHost, + 'shouldSkipTsickleProcessing'|'pathToModuleName'|'shouldIgnoreWarningsForPath'| + 'fileNameToModuleId'|'googmodule'|'untyped'|'convertIndexImportShorthand'| + 'transformDecorators'|'transformTypesToClosure'> = { shouldSkipTsickleProcessing: (fileName) => /\.d\.ts$/.test(fileName) || // View Engine's generated files were never intended to be processed with tsickle. (!options.enableIvy && GENERATED_FILES.test(fileName)), @@ -111,7 +114,9 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un fileNameToModuleId: (fileName) => fileName, googmodule: false, untyped: true, - convertIndexImportShorthand: false, transformDecorators, transformTypesToClosure, + convertIndexImportShorthand: false, + transformDecorators, + transformTypesToClosure, }; if (options.annotateForClosureCompiler || options.annotationsAs === 'static fields') { @@ -147,7 +152,9 @@ function createEmitCallback(options: api.CompilerOptions): api.TsEmitCallback|un } } -export interface NgcParsedConfiguration extends ParsedConfiguration { watch?: boolean; } +export interface NgcParsedConfiguration extends ParsedConfiguration { + watch?: boolean; +} export function readNgcCommandLineAndConfiguration(args: string[]): NgcParsedConfiguration { const options: api.CompilerOptions = {}; @@ -194,7 +201,8 @@ export function readCommandLineAndConfiguration( } return { project, - rootNames: config.rootNames, options, + rootNames: config.rootNames, + options, errors: config.errors, emitFlags: config.emitFlags }; @@ -237,7 +245,7 @@ export function watchMode( function printDiagnostics( diagnostics: ReadonlyArray<ts.Diagnostic|api.Diagnostic>, - options: api.CompilerOptions | undefined, consoleError: (s: string) => void): void { + options: api.CompilerOptions|undefined, consoleError: (s: string) => void): void { if (diagnostics.length === 0) { return; } diff --git a/packages/compiler-cli/src/metadata/bundle_index_host.ts b/packages/compiler-cli/src/metadata/bundle_index_host.ts index 489c32c4dbd8f..74db9c89797bc 100644 --- a/packages/compiler-cli/src/metadata/bundle_index_host.ts +++ b/packages/compiler-cli/src/metadata/bundle_index_host.ts @@ -47,8 +47,7 @@ function createSyntheticIndexHost<H extends ts.CompilerHost>( newHost.writeFile = (fileName: string, data: string, writeByteOrderMark: boolean, - onError: ((message: string) => void) | undefined, - sourceFiles: Readonly<ts.SourceFile>[]) => { + onError: ((message: string) => void)|undefined, sourceFiles: Readonly<ts.SourceFile>[]) => { delegate.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles); if (fileName.match(DTS) && sourceFiles && sourceFiles.length == 1 && path.normalize(sourceFiles[0].fileName) === normalSyntheticIndexName) { @@ -103,7 +102,7 @@ export function createBundleIndexHost<H extends ts.CompilerHost>( // contents of the flat module index. The bundle produced during emit does use the metadata cache // with associated transforms, so the metadata will have lowered expressions, resource inlining, // etc. - const getMetadataBundle = (cache: MetadataCache | null) => { + const getMetadataBundle = (cache: MetadataCache|null) => { const bundler = new MetadataBundler( indexModule, ngOptions.flatModuleId, new CompilerHostAdapter(host, cache, ngOptions), ngOptions.flatModulePrivateSymbolPrefix); @@ -113,7 +112,7 @@ export function createBundleIndexHost<H extends ts.CompilerHost>( // First, produce the bundle with no MetadataCache. const metadataBundle = getMetadataBundle(/* MetadataCache */ null); const name = - path.join(path.dirname(indexModule), ngOptions.flatModuleOutFile !.replace(JS_EXT, '.ts')); + path.join(path.dirname(indexModule), ngOptions.flatModuleOutFile!.replace(JS_EXT, '.ts')); const libraryIndex = `./${path.basename(indexModule)}`; const content = privateEntriesToIndex(libraryIndex, metadataBundle.privates); diff --git a/packages/compiler-cli/src/metadata/bundler.ts b/packages/compiler-cli/src/metadata/bundler.ts index 5c07de49c0d98..e1d3ad407e9a5 100644 --- a/packages/compiler-cli/src/metadata/bundler.ts +++ b/packages/compiler-cli/src/metadata/bundler.ts @@ -11,7 +11,7 @@ import * as ts from 'typescript'; import {MetadataCache} from '../transformers/metadata_cache'; import {MetadataCollector} from './collector'; -import {ClassMetadata, ConstructorMetadata, FunctionMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isInterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicCallExpression, isMetadataSymbolicExpression, isMethodMetadata} from './schema'; +import {ClassMetadata, ConstructorMetadata, FunctionMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isInterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicCallExpression, isMetadataSymbolicExpression, isMethodMetadata, MemberMetadata, METADATA_VERSION, MetadataEntry, MetadataError, MetadataMap, MetadataObject, MetadataSymbolicExpression, MetadataSymbolicReferenceExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata} from './schema'; @@ -59,7 +59,9 @@ interface Symbol { privateName?: string; } -export interface BundleEntries { [name: string]: MetadataEntry; } +export interface BundleEntries { + [name: string]: MetadataEntry; +} export interface BundlePrivateEntry { privateName: string; @@ -77,7 +79,7 @@ export interface MetadataBundlerHost { } type StaticsMetadata = { - [name: string]: MetadataValue | FunctionMetadata; + [name: string]: MetadataValue|FunctionMetadata; }; export class MetadataBundler { @@ -87,7 +89,7 @@ export class MetadataBundler { private rootModule: string; private privateSymbolPrefix: string; // TODO(issue/24571): remove '!'. - private exported !: Set<Symbol>; + private exported!: Set<Symbol>; constructor( private root: string, private importAs: string|undefined, private host: MetadataBundlerHost, @@ -106,14 +108,14 @@ export class MetadataBundler { const privates = Array.from(this.symbolMap.values()) .filter(s => s.referenced && s.isPrivate) .map(s => ({ - privateName: s.privateName !, - name: s.declaration !.name, - module: s.declaration !.module + privateName: s.privateName!, + name: s.declaration!.name, + module: s.declaration!.module })); const origins = Array.from(this.symbolMap.values()) .filter(s => s.referenced && !s.reexport) .reduce<{[name: string]: string}>((p, s) => { - p[s.isPrivate ? s.privateName ! : s.name] = s.declaration !.module; + p[s.isPrivate ? s.privateName! : s.name] = s.declaration!.module; return p; }, {}); const exports = this.getReExports(exportedSymbols); @@ -121,8 +123,10 @@ export class MetadataBundler { metadata: { __symbolic: 'module', version: METADATA_VERSION, - exports: exports.length ? exports : undefined, metadata, origins, - importAs: this.importAs ! + exports: exports.length ? exports : undefined, + metadata, + origins, + importAs: this.importAs! }, privates }; @@ -156,7 +160,7 @@ export class MetadataBundler { const exportSymbol = (exportedSymbol: Symbol, exportAs: string) => { const symbol = this.symbolOf(moduleName, exportAs); - result !.push(symbol); + result!.push(symbol); exportedSymbol.reexportedAs = symbol; symbol.exports = exportedSymbol; }; @@ -276,18 +280,18 @@ export class MetadataBundler { Array.from(this.symbolMap.values()).forEach(symbol => { if (symbol.referenced && !symbol.reexport) { let name = symbol.name; - const identifier = `${symbol.declaration!.module}:${symbol.declaration !.name}`; + const identifier = `${symbol.declaration!.module}:${symbol.declaration!.name}`; if (symbol.isPrivate && !symbol.privateName) { name = newPrivateName(this.privateSymbolPrefix); symbol.privateName = name; } if (symbolsMap.has(identifier)) { const names = symbolsMap.get(identifier); - names !.push(name); + names!.push(name); } else { symbolsMap.set(identifier, [name]); } - result[name] = symbol.value !; + result[name] = symbol.value!; } }); @@ -320,9 +324,9 @@ export class MetadataBundler { for (const symbol of exportedSymbols) { if (symbol.reexport) { // symbol.declaration is guaranteed to be defined during the phase this method is called. - const declaration = symbol.declaration !; + const declaration = symbol.declaration!; const module = declaration.module; - if (declaration !.name == '*') { + if (declaration!.name == '*') { // Reexport all the symbols. exportAlls.add(declaration.module); } else { @@ -346,12 +350,12 @@ export class MetadataBundler { private convertSymbol(symbol: Symbol) { // canonicalSymbol is ensured to be defined before this is called. - const canonicalSymbol = symbol.canonicalSymbol !; + const canonicalSymbol = symbol.canonicalSymbol!; if (!canonicalSymbol.referenced) { canonicalSymbol.referenced = true; // declaration is ensured to be definded before this method is called. - const declaration = canonicalSymbol.declaration !; + const declaration = canonicalSymbol.declaration!; const module = this.getMetadata(declaration.module); if (module) { const value = module.metadata[declaration.name]; @@ -399,11 +403,11 @@ export class MetadataBundler { private convertMember(moduleName: string, member: MemberMetadata) { const result: MemberMetadata = {__symbolic: member.__symbolic}; result.decorators = - member.decorators && member.decorators.map(d => this.convertExpression(moduleName, d) !); + member.decorators && member.decorators.map(d => this.convertExpression(moduleName, d)!); if (isMethodMetadata(member)) { (result as MethodMetadata).parameterDecorators = member.parameterDecorators && member.parameterDecorators.map( - d => d && d.map(p => this.convertExpression(moduleName, p) !)); + d => d && d.map(p => this.convertExpression(moduleName, p)!)); if (isConstructorMetadata(member)) { if (member.parameters) { (result as ConstructorMetadata).parameters = @@ -450,7 +454,7 @@ export class MetadataBundler { return this.convertError(moduleName, value); } if (isMetadataSymbolicExpression(value)) { - return this.convertExpression(moduleName, value) !; + return this.convertExpression(moduleName, value)!; } if (Array.isArray(value)) { return value.map(v => this.convertValue(moduleName, v)); @@ -466,8 +470,8 @@ export class MetadataBundler { } private convertExpression( - moduleName: string, value: MetadataSymbolicExpression|MetadataError|null| - undefined): MetadataSymbolicExpression|MetadataError|undefined|null { + moduleName: string, value: MetadataSymbolicExpression|MetadataError|null|undefined): + MetadataSymbolicExpression|MetadataError|undefined|null { if (value) { switch (value.__symbolic) { case 'error': @@ -487,14 +491,15 @@ export class MetadataBundler { message: value.message, line: value.line, character: value.character, - context: value.context, module + context: value.context, + module }; } private convertReference(moduleName: string, value: MetadataSymbolicReferenceExpression): MetadataSymbolicReferenceExpression|MetadataError|undefined { const createReference = (symbol: Symbol): MetadataSymbolicReferenceExpression => { - const declaration = symbol.declaration !; + const declaration = symbol.declaration!; if (declaration.module.startsWith('.')) { // Reference to a symbol defined in the module. Ensure it is converted then return a // references to the final symbol. @@ -503,11 +508,11 @@ export class MetadataBundler { __symbolic: 'reference', get name() { // Resolved lazily because private names are assigned late. - const canonicalSymbol = symbol.canonicalSymbol !; + const canonicalSymbol = symbol.canonicalSymbol!; if (canonicalSymbol.isPrivate == null) { throw Error('Invalid state: isPrivate was not initialized'); } - return canonicalSymbol.isPrivate ? canonicalSymbol.privateName ! : canonicalSymbol.name; + return canonicalSymbol.isPrivate ? canonicalSymbol.privateName! : canonicalSymbol.name; } }; } else { @@ -584,7 +589,7 @@ export class MetadataBundler { private convertExpressionNode(moduleName: string, value: MetadataSymbolicExpression): MetadataSymbolicExpression { - const result: MetadataSymbolicExpression = { __symbolic: value.__symbolic } as any; + const result: MetadataSymbolicExpression = {__symbolic: value.__symbolic} as any; for (const key in value) { (result as any)[key] = this.convertValue(moduleName, (value as any)[key]); } diff --git a/packages/compiler-cli/src/metadata/collector.ts b/packages/compiler-cli/src/metadata/collector.ts index f54ba3def7223..577347181e45e 100644 --- a/packages/compiler-cli/src/metadata/collector.ts +++ b/packages/compiler-cli/src/metadata/collector.ts @@ -8,8 +8,8 @@ import * as ts from 'typescript'; -import {Evaluator, errorSymbol, recordMapEntry} from './evaluator'; -import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, METADATA_VERSION, MemberMetadata, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata} from './schema'; +import {errorSymbol, Evaluator, recordMapEntry} from './evaluator'; +import {ClassMetadata, ConstructorMetadata, FunctionMetadata, InterfaceMetadata, isClassMetadata, isConstructorMetadata, isFunctionMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSelectExpression, isMethodMetadata, MemberMetadata, METADATA_VERSION, MetadataEntry, MetadataError, MetadataMap, MetadataSymbolicBinaryExpression, MetadataSymbolicCallExpression, MetadataSymbolicExpression, MetadataSymbolicIfExpression, MetadataSymbolicIndexExpression, MetadataSymbolicPrefixExpression, MetadataSymbolicReferenceExpression, MetadataSymbolicSelectExpression, MetadataSymbolicSpreadExpression, MetadataValue, MethodMetadata, ModuleExportMetadata, ModuleMetadata} from './schema'; import {Symbols} from './symbols'; const isStatic = (node: ts.Declaration) => @@ -60,12 +60,12 @@ export class MetadataCollector { new Map<MetadataValue|ClassMetadata|InterfaceMetadata|FunctionMetadata, ts.Node>(); const composedSubstituter = substituteExpression && this.options.substituteExpression ? (value: MetadataValue, node: ts.Node) => - this.options.substituteExpression !(substituteExpression(value, node), node) : + this.options.substituteExpression!(substituteExpression(value, node), node) : substituteExpression; const evaluatorOptions = substituteExpression ? {...this.options, substituteExpression: composedSubstituter} : this.options; - let metadata: {[name: string]: MetadataValue | ClassMetadata | FunctionMetadata}|undefined; + let metadata: {[name: string]: MetadataValue|ClassMetadata|FunctionMetadata}|undefined; const evaluator = new Evaluator(locals, nodeMap, evaluatorOptions, (name, value) => { if (!metadata) metadata = {}; metadata[name] = value; @@ -88,9 +88,9 @@ export class MetadataCollector { return errorSymbol(message, node, context, sourceFile); } - function maybeGetSimpleFunction( - functionDeclaration: ts.FunctionDeclaration | - ts.MethodDeclaration): {func: FunctionMetadata, name: string}|undefined { + function maybeGetSimpleFunction(functionDeclaration: ts.FunctionDeclaration| + ts.MethodDeclaration): {func: FunctionMetadata, name: string}| + undefined { if (functionDeclaration.name && functionDeclaration.name.kind == ts.SyntaxKind.Identifier) { const nameNode = <ts.Identifier>functionDeclaration.name; const functionName = nameNode.text; @@ -119,8 +119,8 @@ export class MetadataCollector { function classMetadataOf(classDeclaration: ts.ClassDeclaration): ClassMetadata { const result: ClassMetadata = {__symbolic: 'class'}; - function getDecorators(decorators: ReadonlyArray<ts.Decorator>| undefined): - MetadataSymbolicExpression[]|undefined { + function getDecorators(decorators: ReadonlyArray<ts.Decorator>| + undefined): MetadataSymbolicExpression[]|undefined { if (decorators && decorators.length) return decorators.map(decorator => objFromDecorator(decorator)); return undefined; @@ -167,8 +167,8 @@ export class MetadataCollector { } // static member - let statics: {[name: string]: MetadataValue | FunctionMetadata}|null = null; - function recordStaticMember(name: string, value: MetadataValue | FunctionMetadata) { + let statics: {[name: string]: MetadataValue|FunctionMetadata}|null = null; + function recordStaticMember(name: string, value: MetadataValue|FunctionMetadata) { if (!statics) statics = {}; statics[name] = value; } @@ -189,11 +189,10 @@ export class MetadataCollector { } const methodDecorators = getDecorators(method.decorators); const parameters = method.parameters; - const parameterDecoratorData: - ((MetadataSymbolicExpression | MetadataError)[] | undefined)[] = []; - const parametersData: - (MetadataSymbolicReferenceExpression | MetadataError | - MetadataSymbolicSelectExpression | null)[] = []; + const parameterDecoratorData: ((MetadataSymbolicExpression | MetadataError)[]| + undefined)[] = []; + const parametersData: (MetadataSymbolicReferenceExpression|MetadataError| + MetadataSymbolicSelectExpression|null)[] = []; let hasDecoratorData: boolean = false; let hasParameterData: boolean = false; for (const parameter of parameters) { @@ -282,15 +281,14 @@ export class MetadataCollector { ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export; const isExportedIdentifier = (identifier?: ts.Identifier) => identifier && exportMap.has(identifier.text); - const isExported = - (node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | - ts.InterfaceDeclaration | ts.EnumDeclaration) => - isExport(node) || isExportedIdentifier(node.name); + const isExported = (node: ts.FunctionDeclaration|ts.ClassDeclaration|ts.TypeAliasDeclaration| + ts.InterfaceDeclaration|ts.EnumDeclaration) => + isExport(node) || isExportedIdentifier(node.name); const exportedIdentifierName = (identifier?: ts.Identifier) => identifier && (exportMap.get(identifier.text) || identifier.text); - const exportedName = - (node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.InterfaceDeclaration | - ts.TypeAliasDeclaration | ts.EnumDeclaration) => exportedIdentifierName(node.name); + const exportedName = (node: ts.FunctionDeclaration|ts.ClassDeclaration| + ts.InterfaceDeclaration|ts.TypeAliasDeclaration|ts.EnumDeclaration) => + exportedIdentifierName(node.name); // Pre-declare classes and functions @@ -419,8 +417,8 @@ export class MetadataCollector { if (name) { if (!metadata) metadata = {}; // TODO(alxhub): The literal here is not valid FunctionMetadata. - metadata[name] = maybeFunc ? recordEntry(maybeFunc.func, node) : - ({ __symbolic: 'function' } as any); + metadata[name] = + maybeFunc ? recordEntry(maybeFunc.func, node) : ({__symbolic: 'function'} as any); } } break; @@ -456,7 +454,8 @@ export class MetadataCollector { operator: '+', left: { __symbolic: 'select', - expression: recordEntry({__symbolic: 'reference', name: enumName}, node), name + expression: recordEntry({__symbolic: 'reference', name: enumName}, node), + name }, } as any; } else { @@ -555,7 +554,8 @@ export class MetadataCollector { } const result: ModuleMetadata = { __symbolic: 'module', - version: this.options.version || METADATA_VERSION, metadata + version: this.options.version || METADATA_VERSION, + metadata }; if (sourceFile.moduleName) result.importAs = sourceFile.moduleName; if (exports) result.exports = exports; @@ -570,8 +570,7 @@ function validateMetadata( metadata: {[name: string]: MetadataEntry}) { let locals: Set<string> = new Set(['Array', 'Object', 'Set', 'Map', 'string', 'number', 'any']); - function validateExpression( - expression: MetadataValue | MetadataSymbolicExpression | MetadataError) { + function validateExpression(expression: MetadataValue|MetadataSymbolicExpression|MetadataError) { if (!expression) { return; } else if (Array.isArray(expression)) { @@ -648,11 +647,11 @@ function validateMetadata( } if (classData.members) { Object.getOwnPropertyNames(classData.members) - .forEach(name => classData.members ![name].forEach((m) => validateMember(classData, m))); + .forEach(name => classData.members![name].forEach((m) => validateMember(classData, m))); } if (classData.statics) { Object.getOwnPropertyNames(classData.statics).forEach(name => { - const staticMember = classData.statics ![name]; + const staticMember = classData.statics![name]; if (isFunctionMetadata(staticMember)) { validateExpression(staticMember.value); } else { @@ -675,7 +674,7 @@ function validateMetadata( } } - function shouldReportNode(node: ts.Node | undefined) { + function shouldReportNode(node: ts.Node|undefined) { if (node) { const nodeStart = node.getStart(); return !( @@ -688,12 +687,13 @@ function validateMetadata( function reportError(error: MetadataError) { const node = nodeMap.get(error); if (shouldReportNode(node)) { - const lineInfo = error.line != undefined ? - error.character != undefined ? `:${error.line + 1}:${error.character + 1}` : - `:${error.line + 1}` : - ''; - throw new Error( - `${sourceFile.fileName}${lineInfo}: Metadata collected contains an error that will be reported at runtime: ${expandedMessage(error)}.\n ${JSON.stringify(error)}`); + const lineInfo = error.line != undefined ? error.character != undefined ? + `:${error.line + 1}:${error.character + 1}` : + `:${error.line + 1}` : + ''; + throw new Error(`${sourceFile.fileName}${ + lineInfo}: Metadata collected contains an error that will be reported at runtime: ${ + expandedMessage(error)}.\n ${JSON.stringify(error)}`); } } @@ -708,8 +708,9 @@ function validateMetadata( if (shouldReportNode(node)) { if (node) { const {line, character} = sourceFile.getLineAndCharacterOfPosition(node.getStart()); - throw new Error( - `${sourceFile.fileName}:${line + 1}:${character + 1}: Error encountered in metadata generated for exported symbol '${name}': \n ${e.message}`); + throw new Error(`${sourceFile.fileName}:${line + 1}:${ + character + 1}: Error encountered in metadata generated for exported symbol '${ + name}': \n ${e.message}`); } throw new Error( `Error encountered in metadata generated for exported symbol ${name}: \n ${e.message}`); @@ -722,7 +723,7 @@ function validateMetadata( function namesOf(parameters: ts.NodeArray<ts.ParameterDeclaration>): string[] { const result: string[] = []; - function addNamesOf(name: ts.Identifier | ts.BindingPattern) { + function addNamesOf(name: ts.Identifier|ts.BindingPattern) { if (name.kind == ts.SyntaxKind.Identifier) { const identifier = <ts.Identifier>name; result.push(identifier.text); @@ -752,7 +753,8 @@ function expandedMessage(error: any): string { switch (error.message) { case 'Reference to non-exported class': if (error.context && error.context.className) { - return `Reference to a non-exported class ${error.context.className}. Consider exporting the class`; + return `Reference to a non-exported class ${ + error.context.className}. Consider exporting the class`; } break; case 'Variable not initialized': @@ -771,7 +773,8 @@ function expandedMessage(error: any): string { 'unction calls are not supported. Consider replacing the function or lambda with a reference to an exported function'; case 'Reference to a local symbol': if (error.context && error.context.name) { - return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`; + return `Reference to a local (non-exported) symbol '${ + error.context.name}'. Consider exporting the symbol`; } } return error.message; diff --git a/packages/compiler-cli/src/metadata/evaluator.ts b/packages/compiler-cli/src/metadata/evaluator.ts index 9cf440cc71f08..4752d98211f04 100644 --- a/packages/compiler-cli/src/metadata/evaluator.ts +++ b/packages/compiler-cli/src/metadata/evaluator.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {CollectorOptions} from './collector'; -import {ClassMetadata, FunctionMetadata, InterfaceMetadata, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression} from './schema'; +import {ClassMetadata, FunctionMetadata, InterfaceMetadata, isMetadataError, isMetadataGlobalReferenceExpression, isMetadataImportDefaultReference, isMetadataImportedSymbolReferenceExpression, isMetadataModuleReferenceExpression, isMetadataSymbolicReferenceExpression, isMetadataSymbolicSpreadExpression, MetadataEntry, MetadataError, MetadataImportedSymbolReferenceExpression, MetadataSourceLocationInfo, MetadataSymbolicCallExpression, MetadataValue} from './schema'; import {Symbols} from './symbols'; @@ -46,8 +46,9 @@ export function recordMapEntry<T extends MetadataEntry>( sourceFile?: ts.SourceFile) { if (!nodeMap.has(entry)) { nodeMap.set(entry, node); - if (node && (isMetadataImportedSymbolReferenceExpression(entry) || - isMetadataImportDefaultReference(entry)) && + if (node && + (isMetadataImportedSymbolReferenceExpression(entry) || + isMetadataImportDefaultReference(entry)) && entry.line == null) { const info = sourceInfo(node, sourceFile); if (info.line != null) entry.line = info.line; @@ -88,7 +89,7 @@ export interface ImportMetadata { } -function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile { +function getSourceFileOfNode(node: ts.Node|undefined): ts.SourceFile { while (node && node.kind != ts.SyntaxKind.SourceFile) { node = node.parent; } @@ -97,7 +98,7 @@ function getSourceFileOfNode(node: ts.Node | undefined): ts.SourceFile { /* @internal */ export function sourceInfo( - node: ts.Node | undefined, sourceFile: ts.SourceFile | undefined): MetadataSourceLocationInfo { + node: ts.Node|undefined, sourceFile: ts.SourceFile|undefined): MetadataSourceLocationInfo { if (node) { sourceFile = sourceFile || getSourceFileOfNode(node); if (sourceFile) { @@ -435,7 +436,7 @@ export class Evaluator { case ts.SyntaxKind.TypeReference: const typeReferenceNode = <ts.TypeReferenceNode>node; const typeNameNode = typeReferenceNode.typeName; - const getReference: (typeNameNode: ts.Identifier | ts.QualifiedName) => MetadataValue = + const getReference: (typeNameNode: ts.Identifier|ts.QualifiedName) => MetadataValue = node => { if (typeNameNode.kind === ts.SyntaxKind.QualifiedName) { const qualifiedName = <ts.QualifiedName>node; @@ -691,6 +692,6 @@ function isPropertyAssignment(node: ts.Node): node is ts.PropertyAssignment { const empty = ts.createNodeArray<any>(); -function arrayOrEmpty<T extends ts.Node>(v: ts.NodeArray<T>| undefined): ts.NodeArray<T> { +function arrayOrEmpty<T extends ts.Node>(v: ts.NodeArray<T>|undefined): ts.NodeArray<T> { return v || empty; } \ No newline at end of file diff --git a/packages/compiler-cli/src/metadata/schema.ts b/packages/compiler-cli/src/metadata/schema.ts index ec2ed8ad1cf68..519a8c1fd6627 100644 --- a/packages/compiler-cli/src/metadata/schema.ts +++ b/packages/compiler-cli/src/metadata/schema.ts @@ -18,7 +18,7 @@ export const METADATA_VERSION = 4; -export type MetadataEntry = ClassMetadata | InterfaceMetadata | FunctionMetadata | MetadataValue; +export type MetadataEntry = ClassMetadata|InterfaceMetadata|FunctionMetadata|MetadataValue; export interface ModuleMetadata { __symbolic: 'module'; @@ -43,18 +43,22 @@ export interface ClassMetadata { arity?: number; decorators?: (MetadataSymbolicExpression|MetadataError)[]; members?: MetadataMap; - statics?: {[name: string]: MetadataValue | FunctionMetadata}; + statics?: {[name: string]: MetadataValue|FunctionMetadata}; } export function isClassMetadata(value: any): value is ClassMetadata { return value && value.__symbolic === 'class'; } -export interface InterfaceMetadata { __symbolic: 'interface'; } +export interface InterfaceMetadata { + __symbolic: 'interface'; +} export function isInterfaceMetadata(value: any): value is InterfaceMetadata { return value && value.__symbolic === 'interface'; } -export interface MetadataMap { [name: string]: MemberMetadata[]; } +export interface MetadataMap { + [name: string]: MemberMetadata[]; +} export interface MemberMetadata { __symbolic: 'constructor'|'method'|'property'; @@ -99,24 +103,26 @@ export function isFunctionMetadata(value: any): value is FunctionMetadata { return value && value.__symbolic === 'function'; } -export type MetadataValue = string | number | boolean | undefined | null | MetadataObject | - MetadataArray | MetadataSymbolicExpression | MetadataSymbolicReferenceExpression | - MetadataSymbolicBinaryExpression | MetadataSymbolicIndexExpression | - MetadataSymbolicCallExpression | MetadataSymbolicPrefixExpression | - MetadataSymbolicIfExpression | MetadataSymbolicSpreadExpression | - MetadataSymbolicSelectExpression | MetadataError; +export type MetadataValue = string|number|boolean|undefined|null|MetadataObject|MetadataArray| + MetadataSymbolicExpression|MetadataSymbolicReferenceExpression|MetadataSymbolicBinaryExpression| + MetadataSymbolicIndexExpression|MetadataSymbolicCallExpression|MetadataSymbolicPrefixExpression| + MetadataSymbolicIfExpression|MetadataSymbolicSpreadExpression|MetadataSymbolicSelectExpression| + MetadataError; -export interface MetadataObject { [name: string]: MetadataValue; } +export interface MetadataObject { + [name: string]: MetadataValue; +} -export interface MetadataArray { [name: number]: MetadataValue; } +export interface MetadataArray { + [name: number]: MetadataValue; +} -export type MetadataSymbolicExpression = MetadataSymbolicBinaryExpression | - MetadataSymbolicIndexExpression | MetadataSymbolicIndexExpression | - MetadataSymbolicCallExpression | MetadataSymbolicCallExpression | - MetadataSymbolicPrefixExpression | MetadataSymbolicIfExpression | - MetadataGlobalReferenceExpression | MetadataModuleReferenceExpression | - MetadataImportedSymbolReferenceExpression | MetadataImportedDefaultReferenceExpression | - MetadataSymbolicSelectExpression | MetadataSymbolicSpreadExpression; +export type MetadataSymbolicExpression = MetadataSymbolicBinaryExpression| + MetadataSymbolicIndexExpression|MetadataSymbolicIndexExpression|MetadataSymbolicCallExpression| + MetadataSymbolicCallExpression|MetadataSymbolicPrefixExpression|MetadataSymbolicIfExpression| + MetadataGlobalReferenceExpression|MetadataModuleReferenceExpression| + MetadataImportedSymbolReferenceExpression|MetadataImportedDefaultReferenceExpression| + MetadataSymbolicSelectExpression|MetadataSymbolicSpreadExpression; export function isMetadataSymbolicExpression(value: any): value is MetadataSymbolicExpression { if (value) { @@ -234,18 +240,17 @@ export function isMetadataImportedSymbolReferenceExpression(value: any): export interface MetadataImportedDefaultReferenceExpression extends MetadataSourceLocationInfo { __symbolic: 'reference'; module: string; - default: - boolean; - arguments?: MetadataValue[]; + default: boolean; + arguments?: MetadataValue[]; } export function isMetadataImportDefaultReference(value: any): value is MetadataImportedDefaultReferenceExpression { return value && value.module && value.default && isMetadataSymbolicReferenceExpression(value); } -export type MetadataSymbolicReferenceExpression = MetadataGlobalReferenceExpression | - MetadataModuleReferenceExpression | MetadataImportedSymbolReferenceExpression | - MetadataImportedDefaultReferenceExpression; +export type MetadataSymbolicReferenceExpression = + MetadataGlobalReferenceExpression|MetadataModuleReferenceExpression| + MetadataImportedSymbolReferenceExpression|MetadataImportedDefaultReferenceExpression; export function isMetadataSymbolicReferenceExpression(value: any): value is MetadataSymbolicReferenceExpression { return value && value.__symbolic === 'reference'; diff --git a/packages/compiler-cli/src/metadata/symbols.ts b/packages/compiler-cli/src/metadata/symbols.ts index afd7aff8271e3..e1f6563c76b42 100644 --- a/packages/compiler-cli/src/metadata/symbols.ts +++ b/packages/compiler-cli/src/metadata/symbols.ts @@ -12,7 +12,7 @@ import {MetadataSymbolicReferenceExpression, MetadataValue} from './schema'; export class Symbols { // TODO(issue/24571): remove '!'. - private _symbols !: Map<string, MetadataValue>; + private _symbols!: Map<string, MetadataValue>; private references = new Map<string, MetadataSymbolicReferenceExpression>(); constructor(private sourceFile: ts.SourceFile) {} @@ -21,12 +21,16 @@ export class Symbols { return (preferReference && this.references.get(name)) || this.symbols.get(name); } - define(name: string, value: MetadataValue) { this.symbols.set(name, value); } + define(name: string, value: MetadataValue) { + this.symbols.set(name, value); + } defineReference(name: string, value: MetadataSymbolicReferenceExpression) { this.references.set(name, value); } - has(name: string): boolean { return this.symbols.has(name); } + has(name: string): boolean { + return this.symbols.has(name); + } private get symbols(): Map<string, MetadataValue> { let result = this._symbols; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index 3568e4f20a8ab..1aa775a1ebed7 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, Identifiers, InterpolationConfig, LexerRange, ParseError, ParseSourceFile, ParseTemplateOptions, R3ComponentMetadata, R3FactoryTarget, R3TargetBinder, SchemaMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr, compileComponentFromMetadata, makeBindingParser, parseTemplate} from '@angular/compiler'; +import {compileComponentFromMetadata, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DomElementSchemaRegistry, Expression, ExternalExpr, Identifiers, InterpolationConfig, LexerRange, makeBindingParser, ParseError, ParseSourceFile, parseTemplate, ParseTemplateOptions, R3ComponentMetadata, R3FactoryTarget, R3TargetBinder, SchemaMetadata, SelectorMatcher, Statement, TmplAstNode, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {CycleAnalyzer} from '../../cycles'; @@ -15,7 +15,7 @@ import {absoluteFrom, relative} from '../../file_system'; import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from '../../imports'; import {DependencyTracker} from '../../incremental/api'; import {IndexingContext} from '../../indexer'; -import {DirectiveMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry, extractDirectiveGuards} from '../../metadata'; +import {DirectiveMeta, extractDirectiveGuards, InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata'; import {flattenInheritedDirectiveMetadata} from '../../metadata/src/inheritance'; import {EnumValue, PartialEvaluator} from '../../partial_evaluator'; import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; @@ -200,7 +200,7 @@ export class ComponentDecoratorHandler implements } else { return previous; } - }, undefined) !; + }, undefined)!; // Note that we could technically combine the `viewProvidersRequiringFactory` and @@ -211,7 +211,7 @@ export class ComponentDecoratorHandler implements let wrappedViewProviders: Expression|null = null; if (component.has('viewProviders')) { - const viewProviders = component.get('viewProviders') !; + const viewProviders = component.get('viewProviders')!; viewProvidersRequiringFactory = resolveProvidersRequiringFactory(viewProviders, this.reflector, this.evaluator); wrappedViewProviders = new WrappedNodeExpr( @@ -221,7 +221,7 @@ export class ComponentDecoratorHandler implements if (component.has('providers')) { providersRequiringFactory = resolveProvidersRequiringFactory( - component.get('providers') !, this.reflector, this.evaluator); + component.get('providers')!, this.reflector, this.evaluator); } // Parse the template. @@ -232,14 +232,14 @@ export class ComponentDecoratorHandler implements let template: ParsedTemplateWithSource; if (this.preanalyzeTemplateCache.has(node)) { // The template was parsed in preanalyze. Use it and delete it to save memory. - const preanalyzed = this.preanalyzeTemplateCache.get(node) !; + const preanalyzed = this.preanalyzeTemplateCache.get(node)!; this.preanalyzeTemplateCache.delete(node); template = preanalyzed; } else { // The template was not already parsed. Either there's a templateUrl, or an inline template. if (component.has('templateUrl')) { - const templateUrlExpr = component.get('templateUrl') !; + const templateUrlExpr = component.get('templateUrl')!; const templateUrl = this.evaluator.evaluate(templateUrlExpr); if (typeof templateUrl !== 'string') { throw new FatalDiagnosticError( @@ -303,7 +303,7 @@ export class ComponentDecoratorHandler implements let animations: Expression|null = null; if (component.has('animations')) { - animations = new WrappedNodeExpr(component.get('animations') !); + animations = new WrappedNodeExpr(component.get('animations')!); } const output: AnalysisOutput<ComponentAnalysisData> = { @@ -323,7 +323,8 @@ export class ComponentDecoratorHandler implements // analyzed and the full compilation scope for the component can be realized. animations, viewProviders: wrappedViewProviders, - i18nUseExternalIds: this.i18nUseExternalIds, relativeContextFilePath, + i18nUseExternalIds: this.i18nUseExternalIds, + relativeContextFilePath, }, guards: extractDirectiveGuards(node, this.reflector), metadataStmt: generateSetClassMetadataCall( @@ -335,7 +336,7 @@ export class ComponentDecoratorHandler implements }, }; if (changeDetection !== null) { - output.analysis !.meta.changeDetection = changeDetection; + output.analysis!.meta.changeDetection = changeDetection; } return output; } @@ -353,7 +354,8 @@ export class ComponentDecoratorHandler implements outputs: analysis.meta.outputs, queries: analysis.meta.queries.map(query => query.propertyName), isComponent: true, - baseClass: analysis.baseClass, ...analysis.guards, + baseClass: analysis.baseClass, + ...analysis.guards, }); this.injectableRegistry.registerInjectable(node); @@ -415,8 +417,8 @@ export class ComponentDecoratorHandler implements } for (const {name, ref} of scope.compilation.pipes) { if (!ts.isClassDeclaration(ref.node)) { - throw new Error( - `Unexpected non-class declaration ${ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`); + throw new Error(`Unexpected non-class declaration ${ + ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`); } pipes.set(name, ref as Reference<ClassDeclaration<ts.ClassDeclaration>>); } @@ -491,7 +493,7 @@ export class ComponentDecoratorHandler implements // The BoundTarget knows which directives and pipes matched the template. const usedDirectives = bound.getUsedDirectives(); - const usedPipes = bound.getUsedPipes().map(name => pipes.get(name) !); + const usedPipes = bound.getUsedPipes().map(name => pipes.get(name)!); // Scan through the directives/pipes actually used in the template and check whether any // import which needs to be generated would create a cycle. @@ -539,7 +541,7 @@ export class ComponentDecoratorHandler implements if (analysis.providersRequiringFactory !== null && analysis.meta.providers instanceof WrappedNodeExpr) { const providerDiagnostics = getProviderDiagnostics( - analysis.providersRequiringFactory, analysis.meta.providers !.node, + analysis.providersRequiringFactory, analysis.meta.providers!.node, this.injectableRegistry); diagnostics.push(...providerDiagnostics); } @@ -547,7 +549,7 @@ export class ComponentDecoratorHandler implements if (analysis.viewProvidersRequiringFactory !== null && analysis.meta.viewProviders instanceof WrappedNodeExpr) { const viewProviderDiagnostics = getProviderDiagnostics( - analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders !.node, + analysis.viewProvidersRequiringFactory, analysis.meta.viewProviders!.node, this.injectableRegistry); diagnostics.push(...viewProviderDiagnostics); } @@ -587,7 +589,7 @@ export class ComponentDecoratorHandler implements private _resolveLiteral(decorator: Decorator): ts.ObjectLiteralExpression { if (this.literalCache.has(decorator)) { - return this.literalCache.get(decorator) !; + return this.literalCache.get(decorator)!; } if (decorator.args === null || decorator.args.length !== 1) { throw new FatalDiagnosticError( @@ -609,7 +611,7 @@ export class ComponentDecoratorHandler implements component: Map<string, ts.Expression>, field: string, enumSymbolName: string): number|null { let resolved: number|null = null; if (component.has(field)) { - const expr = component.get(field) !; + const expr = component.get(field)!; const value = this.evaluator.evaluate(expr) as any; if (value instanceof EnumValue && isAngularCoreReference(value.enumRef, enumSymbolName)) { resolved = value.resolved as number; @@ -628,7 +630,7 @@ export class ComponentDecoratorHandler implements return extraUrls.length > 0 ? extraUrls : null; } - const styleUrlsExpr = component.get('styleUrls') !; + const styleUrlsExpr = component.get('styleUrls')!; const styleUrls = this.evaluator.evaluate(styleUrlsExpr); if (!Array.isArray(styleUrls) || !styleUrls.every(url => typeof url === 'string')) { throw new FatalDiagnosticError( @@ -643,7 +645,7 @@ export class ComponentDecoratorHandler implements containingFile: string): Promise<ParsedTemplate|null> { if (component.has('templateUrl')) { // Extract the templateUrl and preload it. - const templateUrlExpr = component.get('templateUrl') !; + const templateUrlExpr = component.get('templateUrl')!; const templateUrl = this.evaluator.evaluate(templateUrlExpr); if (typeof templateUrl !== 'string') { throw new FatalDiagnosticError( @@ -703,7 +705,7 @@ export class ComponentDecoratorHandler implements ErrorCode.COMPONENT_MISSING_TEMPLATE, Decorator.nodeForError(decorator), 'component is missing a template'); } - const templateExpr = component.get('template') !; + const templateExpr = component.get('template')!; let templateStr: string; let templateUrl: string = ''; @@ -721,7 +723,7 @@ export class ComponentDecoratorHandler implements escapedString = true; sourceMapping = { type: 'direct', - node: templateExpr as(ts.StringLiteral | ts.NoSubstitutionTemplateLiteral), + node: templateExpr as (ts.StringLiteral | ts.NoSubstitutionTemplateLiteral), }; } else { const resolvedTemplate = this.evaluator.evaluate(templateExpr); @@ -749,7 +751,7 @@ export class ComponentDecoratorHandler implements templateRange: LexerRange|undefined, escapedString: boolean): ParsedTemplate { let preserveWhitespaces: boolean = this.defaultPreserveWhitespaces; if (component.has('preserveWhitespaces')) { - const expr = component.get('preserveWhitespaces') !; + const expr = component.get('preserveWhitespaces')!; const value = this.evaluator.evaluate(expr); if (typeof value !== 'boolean') { throw new FatalDiagnosticError( @@ -760,7 +762,7 @@ export class ComponentDecoratorHandler implements let interpolation: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG; if (component.has('interpolation')) { - const expr = component.get('interpolation') !; + const expr = component.get('interpolation')!; const value = this.evaluator.evaluate(expr); if (!Array.isArray(value) || value.length !== 2 || !value.every(element => typeof element === 'string')) { @@ -768,14 +770,15 @@ export class ComponentDecoratorHandler implements ErrorCode.VALUE_HAS_WRONG_TYPE, expr, 'interpolation must be an array with 2 elements of string type'); } - interpolation = InterpolationConfig.fromArray(value as[string, string]); + interpolation = InterpolationConfig.fromArray(value as [string, string]); } const {errors, nodes: emitNodes, styleUrls, styles, ngContentSelectors} = parseTemplate(templateStr, templateUrl, { preserveWhitespaces, interpolationConfig: interpolation, - range: templateRange, escapedString, + range: templateRange, + escapedString, enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, }); @@ -795,7 +798,8 @@ export class ComponentDecoratorHandler implements const {nodes: diagNodes} = parseTemplate(templateStr, templateUrl, { preserveWhitespaces: true, interpolationConfig: interpolation, - range: templateRange, escapedString, + range: templateRange, + escapedString, enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, leadingTriviaChars: [], }); @@ -808,7 +812,8 @@ export class ComponentDecoratorHandler implements styles, ngContentSelectors, errors, - template: templateStr, templateUrl, + template: templateStr, + templateUrl, isInline: component.has('template'), file: new ParseSourceFile(templateStr, templateUrl), }; @@ -820,7 +825,7 @@ export class ComponentDecoratorHandler implements } // Figure out what file is being imported. - return this.moduleResolver.resolveModule(expr.value.moduleName !, origin.fileName); + return this.moduleResolver.resolveModule(expr.value.moduleName!, origin.fileName); } private _isCyclicImport(expr: Expression, origin: ts.SourceFile): boolean { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/diagnostics.ts b/packages/compiler-cli/src/ngtsc/annotations/src/diagnostics.ts index 8b2853eefb345..0b4c1da3c5ce7 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/diagnostics.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/diagnostics.ts @@ -36,9 +36,13 @@ export function getProviderDiagnostics( const contextNode = provider.getOriginForDiagnostics(providersDeclaration); diagnostics.push(makeDiagnostic( ErrorCode.UNDECORATED_PROVIDER, contextNode, - `The class '${provider.node.name.text}' cannot be created via dependency injection, as it does not have an Angular decorator. This will result in an error at runtime. + `The class '${ + provider.node.name + .text}' cannot be created via dependency injection, as it does not have an Angular decorator. This will result in an error at runtime. -Either add the @Injectable() decorator to '${provider.node.name.text}', or configure a different provider (such as a provider with 'useFactory'). +Either add the @Injectable() decorator to '${ + provider.node.name + .text}', or configure a different provider (such as a provider with 'useFactory'). `, [{node: provider.node, messageText: `'${provider.node.name.text}' is declared here.`}])); } @@ -52,7 +56,7 @@ export function getDirectiveDiagnostics( kind: string): ts.Diagnostic[]|null { let diagnostics: ts.Diagnostic[]|null = []; - const addDiagnostics = (more: ts.Diagnostic | ts.Diagnostic[] | null) => { + const addDiagnostics = (more: ts.Diagnostic|ts.Diagnostic[]|null) => { if (more === null) { return; } else if (diagnostics === null) { @@ -121,14 +125,16 @@ export function checkInheritanceOfDirective( function getInheritedUndecoratedCtorDiagnostic( node: ClassDeclaration, baseClass: Reference, reader: MetadataReader) { - const subclassMeta = reader.getDirectiveMetadata(new Reference(node)) !; + const subclassMeta = reader.getDirectiveMetadata(new Reference(node))!; const dirOrComp = subclassMeta.isComponent ? 'Component' : 'Directive'; const baseClassName = baseClass.debugName; return makeDiagnostic( ErrorCode.DIRECTIVE_INHERITS_UNDECORATED_CTOR, node.name, - `The ${dirOrComp.toLowerCase()} ${node.name.text} inherits its constructor from ${baseClassName}, ` + + `The ${dirOrComp.toLowerCase()} ${node.name.text} inherits its constructor from ${ + baseClassName}, ` + `but the latter does not have an Angular decorator of its own. Dependency injection will not be able to ` + - `resolve the parameters of ${baseClassName}'s constructor. Either add a @Directive decorator ` + + `resolve the parameters of ${ + baseClassName}'s constructor. Either add a @Directive decorator ` + `to ${baseClassName}, or add an explicit constructor to ${node.name.text}.`); } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts index 9a2007386502f..1c86f3d0b3def 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/directive.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ConstantPool, Expression, Identifiers, ParseError, ParsedHostBindings, R3DependencyMetadata, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, Statement, WrappedNodeExpr, compileDirectiveFromMetadata, makeBindingParser, parseHostBindings, verifyHostBindings} from '@angular/compiler'; +import {compileDirectiveFromMetadata, ConstantPool, Expression, Identifiers, makeBindingParser, ParsedHostBindings, ParseError, parseHostBindings, R3DependencyMetadata, R3DirectiveMetadata, R3FactoryTarget, R3QueryMetadata, Statement, verifyHostBindings, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -14,7 +14,7 @@ import {DefaultImportRecorder, Reference} from '../../imports'; import {InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata'; import {extractDirectiveGuards} from '../../metadata/src/util'; import {DynamicValue, EnumValue, PartialEvaluator} from '../../partial_evaluator'; -import {ClassDeclaration, ClassMember, ClassMemberKind, Decorator, ReflectionHost, filterToMembersWithDecorator, reflectObjectLiteral} from '../../reflection'; +import {ClassDeclaration, ClassMember, ClassMemberKind, Decorator, filterToMembersWithDecorator, ReflectionHost, reflectObjectLiteral} from '../../reflection'; import {LocalModuleScopeRegistry} from '../../scope'; import {AnalysisOutput, CompileResult, DecoratorHandler, DetectResult, HandlerFlags, HandlerPrecedence, ResolveResult} from '../../transform'; @@ -92,7 +92,7 @@ export class DirectiveDecoratorHandler implements let providersRequiringFactory: Set<Reference<ClassDeclaration>>|null = null; if (directiveResult !== undefined && directiveResult.decorator.has('providers')) { providersRequiringFactory = resolveProvidersRequiringFactory( - directiveResult.decorator.get('providers') !, this.reflector, this.evaluator); + directiveResult.decorator.get('providers')!, this.reflector, this.evaluator); } return { @@ -102,7 +102,8 @@ export class DirectiveDecoratorHandler implements node, this.reflector, this.defaultImportRecorder, this.isCore, this.annotateForClosureCompiler), baseClass: readBaseClass(node, this.reflector, this.evaluator), - guards: extractDirectiveGuards(node, this.reflector), providersRequiringFactory + guards: extractDirectiveGuards(node, this.reflector), + providersRequiringFactory } }; } @@ -120,7 +121,8 @@ export class DirectiveDecoratorHandler implements outputs: analysis.meta.outputs, queries: analysis.meta.queries.map(query => query.propertyName), isComponent: false, - baseClass: analysis.baseClass, ...analysis.guards, + baseClass: analysis.baseClass, + ...analysis.guards, }); this.injectableRegistry.registerInjectable(node); @@ -132,7 +134,7 @@ export class DirectiveDecoratorHandler implements if (analysis.providersRequiringFactory !== null && analysis.meta.providers instanceof WrappedNodeExpr) { const providerDiagnostics = getProviderDiagnostics( - analysis.providersRequiringFactory, analysis.meta.providers !.node, + analysis.providersRequiringFactory, analysis.meta.providers!.node, this.injectableRegistry); diagnostics.push(...providerDiagnostics); } @@ -176,9 +178,8 @@ export class DirectiveDecoratorHandler implements export function extractDirectiveMetadata( clazz: ClassDeclaration, decorator: Readonly<Decorator|null>, reflector: ReflectionHost, evaluator: PartialEvaluator, defaultImportRecorder: DefaultImportRecorder, isCore: boolean, - flags: HandlerFlags, annotateForClosureCompiler: boolean, - defaultSelector: string | null = - null): {decorator: Map<string, ts.Expression>, metadata: R3DirectiveMetadata}|undefined { + flags: HandlerFlags, annotateForClosureCompiler: boolean, defaultSelector: string|null = null): + {decorator: Map<string, ts.Expression>, metadata: R3DirectiveMetadata}|undefined { let directive: Map<string, ts.Expression>; if (decorator === null || decorator.args === null || decorator.args.length === 0) { directive = new Map<string, ts.Expression>(); @@ -220,9 +221,10 @@ export function extractDirectiveMetadata( // And outputs. const outputsFromMeta = parseFieldToPropertyMapping(directive, 'outputs', evaluator); - const outputsFromFields = parseDecoratedFields( - filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator, - resolveOutput) as{[field: string]: string}; + const outputsFromFields = + parseDecoratedFields( + filterToMembersWithDecorator(decoratedElements, 'Output', coreModule), evaluator, + resolveOutput) as {[field: string]: string}; // Construct the list of queries. const contentChildFromFields = queriesFromFields( filterToMembersWithDecorator(decoratedElements, 'ContentChild', coreModule), reflector, @@ -244,7 +246,7 @@ export function extractDirectiveMetadata( if (directive.has('queries')) { const queriesFromDecorator = - extractQueriesFromDecorator(directive.get('queries') !, reflector, evaluator, isCore); + extractQueriesFromDecorator(directive.get('queries')!, reflector, evaluator, isCore); queries.push(...queriesFromDecorator.content); viewQueries.push(...queriesFromDecorator.view); } @@ -252,7 +254,7 @@ export function extractDirectiveMetadata( // Parse the selector. let selector = defaultSelector; if (directive.has('selector')) { - const expr = directive.get('selector') !; + const expr = directive.get('selector')!; const resolved = evaluator.evaluate(expr); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( @@ -272,8 +274,8 @@ export function extractDirectiveMetadata( const providers: Expression|null = directive.has('providers') ? new WrappedNodeExpr( annotateForClosureCompiler ? - wrapFunctionExpressionsInParens(directive.get('providers') !) : - directive.get('providers') !) : + wrapFunctionExpressionsInParens(directive.get('providers')!) : + directive.get('providers')!) : null; // Determine if `ngOnChanges` is a lifecycle hook defined on the component. @@ -284,7 +286,7 @@ export function extractDirectiveMetadata( // Parse exportAs. let exportAs: string[]|null = null; if (directive.has('exportAs')) { - const expr = directive.get('exportAs') !; + const expr = directive.get('exportAs')!; const resolved = evaluator.evaluate(expr); if (typeof resolved !== 'string') { throw new FatalDiagnosticError( @@ -312,15 +314,24 @@ export function extractDirectiveMetadata( const metadata: R3DirectiveMetadata = { name: clazz.name.text, - deps: ctorDeps, host, + deps: ctorDeps, + host, lifecycle: { - usesOnChanges, + usesOnChanges, }, inputs: {...inputsFromMeta, ...inputsFromFields}, - outputs: {...outputsFromMeta, ...outputsFromFields}, queries, viewQueries, selector, - fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), type, internalType, + outputs: {...outputsFromMeta, ...outputsFromFields}, + queries, + viewQueries, + selector, + fullInheritance: !!(flags & HandlerFlags.FULL_INHERITANCE), + type, + internalType, typeArgumentCount: reflector.getGenericArityOfClass(clazz) || 0, - typeSourceSpan: createSourceSpan(clazz.name), usesInheritance, exportAs, providers + typeSourceSpan: createSourceSpan(clazz.name), + usesInheritance, + exportAs, + providers }; return {decorator: directive, metadata}; } @@ -366,11 +377,11 @@ export function extractQueryMetadata( } const options = reflectObjectLiteral(optionsExpr); if (options.has('read')) { - read = new WrappedNodeExpr(options.get('read') !); + read = new WrappedNodeExpr(options.get('read')!); } if (options.has('descendants')) { - const descendantsExpr = options.get('descendants') !; + const descendantsExpr = options.get('descendants')!; const descendantsValue = evaluator.evaluate(descendantsExpr); if (typeof descendantsValue !== 'boolean') { throw new FatalDiagnosticError( @@ -381,7 +392,7 @@ export function extractQueryMetadata( } if (options.has('static')) { - const staticValue = evaluator.evaluate(options.get('static') !); + const staticValue = evaluator.evaluate(options.get('static')!); if (typeof staticValue !== 'boolean') { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, node, `@${name} options.static must be a boolean`); @@ -466,7 +477,7 @@ export function parseFieldArrayValue( } // Resolve the field of interest from the directive metadata to a string[]. - const expression = directive.get(field) !; + const expression = directive.get(field)!; const value = evaluator.evaluate(expression); if (!isStringArrayOrDie(value, field, expression)) { throw new FatalDiagnosticError( @@ -489,15 +500,13 @@ function parseFieldToPropertyMapping( return EMPTY_OBJECT; } - return metaValues.reduce( - (results, value) => { - // Either the value is 'field' or 'field: property'. In the first case, `property` will - // be undefined, in which case the field name should also be used as the property name. - const [field, property] = value.split(':', 2).map(str => str.trim()); - results[field] = property || field; - return results; - }, - {} as{[field: string]: string}); + return metaValues.reduce((results, value) => { + // Either the value is 'field' or 'field: property'. In the first case, `property` will + // be undefined, in which case the field name should also be used as the property name. + const [field, property] = value.split(':', 2).map(str => str.trim()); + results[field] = property || field; + return results; + }, {} as {[field: string]: string}); } /** @@ -507,33 +516,32 @@ function parseFieldToPropertyMapping( function parseDecoratedFields( fields: {member: ClassMember, decorators: Decorator[]}[], evaluator: PartialEvaluator, mapValueResolver: (publicName: string, internalName: string) => - string | [string, string]): {[field: string]: string | [string, string]} { - return fields.reduce( - (results, field) => { - const fieldName = field.member.name; - field.decorators.forEach(decorator => { - // The decorator either doesn't have an argument (@Input()) in which case the property - // name is used, or it has one argument (@Output('named')). - if (decorator.args == null || decorator.args.length === 0) { - results[fieldName] = fieldName; - } else if (decorator.args.length === 1) { - const property = evaluator.evaluate(decorator.args[0]); - if (typeof property !== 'string') { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator), - `@${decorator.name} decorator argument must resolve to a string`); - } - results[fieldName] = mapValueResolver(property, fieldName); - } else { - // Too many arguments. - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), - `@${decorator.name} can have at most one argument, got ${decorator.args.length} argument(s)`); - } - }); - return results; - }, - {} as{[field: string]: string | [string, string]}); + string | [string, string]): {[field: string]: string|[string, string]} { + return fields.reduce((results, field) => { + const fieldName = field.member.name; + field.decorators.forEach(decorator => { + // The decorator either doesn't have an argument (@Input()) in which case the property + // name is used, or it has one argument (@Output('named')). + if (decorator.args == null || decorator.args.length === 0) { + results[fieldName] = fieldName; + } else if (decorator.args.length === 1) { + const property = evaluator.evaluate(decorator.args[0]); + if (typeof property !== 'string') { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator), + `@${decorator.name} decorator argument must resolve to a string`); + } + results[fieldName] = mapValueResolver(property, fieldName); + } else { + // Too many arguments. + throw new FatalDiagnosticError( + ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), + `@${decorator.name} can have at most one argument, got ${ + decorator.args.length} argument(s)`); + } + }); + return results; + }, {} as {[field: string]: string | [string, string]}); } function resolveInput(publicName: string, internalName: string): [string, string] { @@ -552,7 +560,7 @@ export function queriesFromFields( const node = member.node || Decorator.nodeForError(decorator); // Throw in case of `@Input() @ContentChild('foo') foo: any`, which is not supported in Ivy - if (member.decorators !.some(v => v.name === 'Input')) { + if (member.decorators!.some(v => v.name === 'Input')) { throw new FatalDiagnosticError( ErrorCode.DECORATOR_COLLISION, node, 'Cannot combine @Input decorators with query decorators'); @@ -626,38 +634,40 @@ function evaluateHostExpressionBindings( } export function extractHostBindings( - members: ClassMember[], evaluator: PartialEvaluator, coreModule: string | undefined, + members: ClassMember[], evaluator: PartialEvaluator, coreModule: string|undefined, metadata?: Map<string, ts.Expression>): ParsedHostBindings { let bindings: ParsedHostBindings; if (metadata && metadata.has('host')) { - bindings = evaluateHostExpressionBindings(metadata.get('host') !, evaluator); + bindings = evaluateHostExpressionBindings(metadata.get('host')!, evaluator); } else { bindings = parseHostBindings({}); } - filterToMembersWithDecorator(members, 'HostBinding', coreModule).forEach(({member, decorators}) => { - decorators.forEach(decorator => { - let hostPropertyName: string = member.name; - if (decorator.args !== null && decorator.args.length > 0) { - if (decorator.args.length !== 1) { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), - `@HostBinding can have at most one argument, got ${decorator.args.length} argument(s)`); - } + filterToMembersWithDecorator(members, 'HostBinding', coreModule) + .forEach(({member, decorators}) => { + decorators.forEach(decorator => { + let hostPropertyName: string = member.name; + if (decorator.args !== null && decorator.args.length > 0) { + if (decorator.args.length !== 1) { + throw new FatalDiagnosticError( + ErrorCode.DECORATOR_ARITY_WRONG, Decorator.nodeForError(decorator), + `@HostBinding can have at most one argument, got ${ + decorator.args.length} argument(s)`); + } - const resolved = evaluator.evaluate(decorator.args[0]); - if (typeof resolved !== 'string') { - throw new FatalDiagnosticError( - ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator), - `@HostBinding's argument must be a string`); - } + const resolved = evaluator.evaluate(decorator.args[0]); + if (typeof resolved !== 'string') { + throw new FatalDiagnosticError( + ErrorCode.VALUE_HAS_WRONG_TYPE, Decorator.nodeForError(decorator), + `@HostBinding's argument must be a string`); + } - hostPropertyName = resolved; - } + hostPropertyName = resolved; + } - bindings.properties[hostPropertyName] = member.name; - }); - }); + bindings.properties[hostPropertyName] = member.name; + }); + }); filterToMembersWithDecorator(members, 'HostListener', coreModule) .forEach(({member, decorators}) => { diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts b/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts index 0aa284ca7697b..e7a3308e99566 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/factory.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {R3FactoryMetadata, compileFactoryFunction} from '@angular/compiler'; +import {compileFactoryFunction, R3FactoryMetadata} from '@angular/compiler'; import {CompileResult} from '../../transform'; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index 98b81843f9767..6578c7aebf709 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, Identifiers, LiteralExpr, R3DependencyMetadata, R3FactoryTarget, R3InjectableMetadata, R3ResolvedDependencyType, Statement, WrappedNodeExpr, compileInjectable as compileIvyInjectable} from '@angular/compiler'; +import {compileInjectable as compileIvyInjectable, Expression, Identifiers, LiteralExpr, R3DependencyMetadata, R3FactoryTarget, R3InjectableMetadata, R3ResolvedDependencyType, Statement, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -83,7 +83,9 @@ export class InjectableDecoratorHandler implements }; } - register(node: ClassDeclaration): void { this.injectableRegistry.registerInjectable(node); } + register(node: ClassDeclaration): void { + this.injectableRegistry.registerInjectable(node); + } compile(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>): CompileResult[] { const res = compileIvyInjectable(analysis.meta); @@ -165,12 +167,12 @@ function extractInjectableMetadata( const meta = reflectObjectLiteral(metaNode); let providedIn: Expression = new LiteralExpr(null); if (meta.has('providedIn')) { - providedIn = new WrappedNodeExpr(meta.get('providedIn') !); + providedIn = new WrappedNodeExpr(meta.get('providedIn')!); } let userDeps: R3DependencyMetadata[]|undefined = undefined; if ((meta.has('useClass') || meta.has('useFactory')) && meta.has('deps')) { - const depsExpr = meta.get('deps') !; + const depsExpr = meta.get('deps')!; if (!ts.isArrayLiteralExpression(depsExpr)) { throw new FatalDiagnosticError( ErrorCode.VALUE_NOT_LITERAL, depsExpr, @@ -186,7 +188,7 @@ function extractInjectableMetadata( typeArgumentCount, internalType, providedIn, - useValue: new WrappedNodeExpr(unwrapForwardRef(meta.get('useValue') !, reflector)), + useValue: new WrappedNodeExpr(unwrapForwardRef(meta.get('useValue')!, reflector)), }; } else if (meta.has('useExisting')) { return { @@ -195,7 +197,7 @@ function extractInjectableMetadata( typeArgumentCount, internalType, providedIn, - useExisting: new WrappedNodeExpr(unwrapForwardRef(meta.get('useExisting') !, reflector)), + useExisting: new WrappedNodeExpr(unwrapForwardRef(meta.get('useExisting')!, reflector)), }; } else if (meta.has('useClass')) { return { @@ -204,19 +206,20 @@ function extractInjectableMetadata( typeArgumentCount, internalType, providedIn, - useClass: new WrappedNodeExpr(unwrapForwardRef(meta.get('useClass') !, reflector)), + useClass: new WrappedNodeExpr(unwrapForwardRef(meta.get('useClass')!, reflector)), userDeps, }; } else if (meta.has('useFactory')) { // useFactory is special - the 'deps' property must be analyzed. - const factory = new WrappedNodeExpr(meta.get('useFactory') !); + const factory = new WrappedNodeExpr(meta.get('useFactory')!); return { name, type, typeArgumentCount, internalType, providedIn, - useFactory: factory, userDeps, + useFactory: factory, + userDeps, }; } else { return {name, type, typeArgumentCount, internalType, providedIn}; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts b/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts index e779f8d8178fd..bca360ad5efa2 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/metadata.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, ExternalExpr, FunctionExpr, Identifiers, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NONE_TYPE, ReturnStatement, Statement, WrappedNodeExpr, literalMap} from '@angular/compiler'; +import {Expression, ExternalExpr, FunctionExpr, Identifiers, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, literalMap, NONE_TYPE, ReturnStatement, Statement, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {DefaultImportRecorder} from '../../imports'; @@ -71,7 +71,7 @@ export function generateSetClassMetadataCall( duplicateDecoratedMemberNames.join(', ')); } const decoratedMembers = - classMembers.map(member => classMemberToMetadata(member.name, member.decorators !, isCore)); + classMembers.map(member => classMemberToMetadata(member.name, member.decorators!, isCore)); if (decoratedMembers.length > 0) { metaPropDecorators = ts.createObjectLiteral(decoratedMembers); } diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts index 940ef2458c399..ad66da3d1b476 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/ng_module.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CUSTOM_ELEMENTS_SCHEMA, Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NO_ERRORS_SCHEMA, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, STRING_TYPE, SchemaMetadata, Statement, WrappedNodeExpr, compileInjector, compileNgModule} from '@angular/compiler'; +import {compileInjector, compileNgModule, CUSTOM_ELEMENTS_SCHEMA, Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, NO_ERRORS_SCHEMA, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, SchemaMetadata, Statement, STRING_TYPE, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics'; @@ -40,7 +40,9 @@ export interface NgModuleAnalysis { providers: ts.Expression|null; } -export interface NgModuleResolution { injectorImports: Expression[]; } +export interface NgModuleResolution { + injectorImports: Expression[]; +} /** * Compiles @NgModule annotations to ngModuleDef fields. @@ -116,7 +118,7 @@ export class NgModuleDecoratorHandler implements let declarationRefs: Reference<ClassDeclaration>[] = []; let rawDeclarations: ts.Expression|null = null; if (ngModule.has('declarations')) { - rawDeclarations = ngModule.get('declarations') !; + rawDeclarations = ngModule.get('declarations')!; const declarationMeta = this.evaluator.evaluate(rawDeclarations, forwardRefResolver); declarationRefs = this.resolveTypeList(rawDeclarations, declarationMeta, name, 'declarations'); @@ -128,7 +130,9 @@ export class NgModuleDecoratorHandler implements diagnostics.push(makeDiagnostic( ErrorCode.NGMODULE_INVALID_DECLARATION, errorNode, - `Cannot declare '${ref.node.name.text}' in an NgModule as it's not a part of the current compilation.`, + `Cannot declare '${ + ref.node.name + .text}' in an NgModule as it's not a part of the current compilation.`, [{ node: ref.node.name, messageText: `'${ref.node.name.text}' is declared here.`, @@ -144,28 +148,28 @@ export class NgModuleDecoratorHandler implements let importRefs: Reference<ClassDeclaration>[] = []; let rawImports: ts.Expression|null = null; if (ngModule.has('imports')) { - rawImports = ngModule.get('imports') !; + rawImports = ngModule.get('imports')!; const importsMeta = this.evaluator.evaluate(rawImports, moduleResolvers); importRefs = this.resolveTypeList(rawImports, importsMeta, name, 'imports'); } let exportRefs: Reference<ClassDeclaration>[] = []; let rawExports: ts.Expression|null = null; if (ngModule.has('exports')) { - rawExports = ngModule.get('exports') !; + rawExports = ngModule.get('exports')!; const exportsMeta = this.evaluator.evaluate(rawExports, moduleResolvers); exportRefs = this.resolveTypeList(rawExports, exportsMeta, name, 'exports'); this.referencesRegistry.add(node, ...exportRefs); } let bootstrapRefs: Reference<ClassDeclaration>[] = []; if (ngModule.has('bootstrap')) { - const expr = ngModule.get('bootstrap') !; + const expr = ngModule.get('bootstrap')!; const bootstrapMeta = this.evaluator.evaluate(expr, forwardRefResolver); bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap'); } const schemas: SchemaMetadata[] = []; if (ngModule.has('schemas')) { - const rawExpr = ngModule.get('schemas') !; + const rawExpr = ngModule.get('schemas')!; const result = this.evaluator.evaluate(rawExpr); if (!Array.isArray(result)) { throw new FatalDiagnosticError( @@ -203,7 +207,7 @@ export class NgModuleDecoratorHandler implements } const id: Expression|null = - ngModule.has('id') ? new WrappedNodeExpr(ngModule.get('id') !) : null; + ngModule.has('id') ? new WrappedNodeExpr(ngModule.get('id')!) : null; const valueContext = node.getSourceFile(); let typeContext = valueContext; @@ -220,7 +224,7 @@ export class NgModuleDecoratorHandler implements const exports = exportRefs.map(exp => this._toR3Reference(exp, valueContext, typeContext)); const isForwardReference = (ref: R3Reference) => - isExpressionForwardReference(ref.value, node.name !, valueContext); + isExpressionForwardReference(ref.value, node.name!, valueContext); const containsForwardDecls = bootstrap.some(isForwardReference) || declarations.some(isForwardReference) || imports.some(isForwardReference) || exports.some(isForwardReference); @@ -244,7 +248,7 @@ export class NgModuleDecoratorHandler implements schemas: [], }; - const rawProviders = ngModule.has('providers') ? ngModule.get('providers') ! : null; + const rawProviders = ngModule.has('providers') ? ngModule.get('providers')! : null; const wrapperProviders = rawProviders !== null ? new WrappedNodeExpr( this.annotateForClosureCompiler ? wrapFunctionExpressionsInParens(rawProviders) : @@ -256,7 +260,7 @@ export class NgModuleDecoratorHandler implements // and pipes from the module exports. const injectorImports: WrappedNodeExpr<ts.Expression>[] = []; if (ngModule.has('imports')) { - injectorImports.push(new WrappedNodeExpr(ngModule.get('imports') !)); + injectorImports.push(new WrappedNodeExpr(ngModule.get('imports')!)); } if (this.routeAnalyzer !== null) { @@ -279,7 +283,8 @@ export class NgModuleDecoratorHandler implements schemas: schemas, mod: ngModuleDef, inj: ngInjectorDef, - declarations: declarationRefs, rawDeclarations, + declarations: declarationRefs, + rawDeclarations, imports: importRefs, exports: exportRefs, providers: rawProviders, @@ -326,7 +331,7 @@ export class NgModuleDecoratorHandler implements if (analysis.providersRequiringFactory !== null) { const providerDiagnostics = getProviderDiagnostics( - analysis.providersRequiringFactory, analysis.providers !, this.injectableRegistry); + analysis.providersRequiringFactory, analysis.providers!, this.injectableRegistry); diagnostics.push(...providerDiagnostics); } @@ -396,7 +401,7 @@ export class NgModuleDecoratorHandler implements const pipes = scope.compilation.pipes.map(pipe => this.refEmitter.emit(pipe.ref, context)); const directiveArray = new LiteralArrayExpr(directives); const pipesArray = new LiteralArrayExpr(pipes); - const declExpr = this.refEmitter.emit(decl, context) !; + const declExpr = this.refEmitter.emit(decl, context)!; const setComponentScope = new ExternalExpr(R3Identifiers.setComponentScope); const callExpr = new InvokeFunctionExpr(setComponentScope, [declExpr, directiveArray, pipesArray]); @@ -472,8 +477,9 @@ export class NgModuleDecoratorHandler implements return null; } - const typeName = type && (ts.isIdentifier(type.typeName) && type.typeName || - ts.isQualifiedName(type.typeName) && type.typeName.right) || + const typeName = type && + (ts.isIdentifier(type.typeName) && type.typeName || + ts.isQualifiedName(type.typeName) && type.typeName.right) || null; if (typeName === null) { return null; @@ -559,7 +565,7 @@ export class NgModuleDecoratorHandler implements // Unwrap ModuleWithProviders for modules that are locally declared (and thus static // resolution was able to descend into the function and return an object literal, a Map). if (entry instanceof Map && entry.has('ngModule')) { - entry = entry.get('ngModule') !; + entry = entry.get('ngModule')!; } if (Array.isArray(entry)) { @@ -569,14 +575,16 @@ export class NgModuleDecoratorHandler implements if (!this.isClassDeclarationReference(entry)) { throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, entry.node, - `Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a class`); + `Value at position ${idx} in the NgModule.${arrayName} of ${ + className} is not a class`); } refList.push(entry); } else { // TODO(alxhub): Produce a better diagnostic here - the array index may be an inner array. throw new FatalDiagnosticError( ErrorCode.VALUE_HAS_WRONG_TYPE, expr, - `Value at position ${idx} in the NgModule.${arrayName} of ${className} is not a reference: ${entry}`); + `Value at position ${idx} in the NgModule.${arrayName} of ${ + className} is not a reference: ${entry}`); } }); diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index cc99211d165ba..60b0a058d6e34 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Identifiers, R3FactoryTarget, R3PipeMetadata, Statement, WrappedNodeExpr, compilePipeFromMetadata} from '@angular/compiler'; +import {compilePipeFromMetadata, Identifiers, R3FactoryTarget, R3PipeMetadata, Statement, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError} from '../../diagnostics'; @@ -79,7 +79,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan throw new FatalDiagnosticError( ErrorCode.PIPE_MISSING_NAME, meta, `@Pipe decorator is missing name field`); } - const pipeNameExpr = pipe.get('name') !; + const pipeNameExpr = pipe.get('name')!; const pipeName = this.evaluator.evaluate(pipeNameExpr); if (typeof pipeName !== 'string') { throw new FatalDiagnosticError( @@ -88,7 +88,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan let pure = true; if (pipe.has('pure')) { - const expr = pipe.get('pure') !; + const expr = pipe.get('pure')!; const pureValue = this.evaluator.evaluate(expr); if (typeof pureValue !== 'boolean') { throw new FatalDiagnosticError( @@ -103,7 +103,8 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan name, type, internalType, - typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0, pipeName, + typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0, + pipeName, deps: getValidConstructorDependencies( clazz, this.reflector, this.defaultImportRecorder, this.isCore), pure, diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts index c4a88684fc048..78cd8d995baae 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts @@ -12,7 +12,7 @@ import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics'; import {DefaultImportRecorder, ImportFlags, Reference, ReferenceEmitter} from '../../imports'; import {ForeignFunctionResolver, PartialEvaluator} from '../../partial_evaluator'; -import {ClassDeclaration, CtorParameter, Decorator, Import, ReflectionHost, TypeValueReference, isNamedClassDeclaration} from '../../reflection'; +import {ClassDeclaration, CtorParameter, Decorator, Import, isNamedClassDeclaration, ReflectionHost, TypeValueReference} from '../../reflection'; import {DeclarationData} from '../../scope'; export enum ConstructorDepErrorKind { @@ -21,8 +21,7 @@ export enum ConstructorDepErrorKind { export type ConstructorDeps = { deps: R3DependencyMetadata[]; -} | -{ +}|{ deps: null; errors: ConstructorDepError[]; }; @@ -53,7 +52,7 @@ export function getConstructorDependencies( let resolved = R3ResolvedDependencyType.Token; (param.decorators || []).filter(dec => isCore || isAngularCore(dec)).forEach(dec => { - const name = isCore || dec.import === null ? dec.name : dec.import !.name; + const name = isCore || dec.import === null ? dec.name : dec.import!.name; if (name === 'Inject') { if (dec.args === null || dec.args.length !== 1) { throw new FatalDiagnosticError( @@ -97,7 +96,8 @@ export function getConstructorDependencies( if (token === null) { errors.push({ index: idx, - kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN, param, + kind: ConstructorDepErrorKind.NO_SUITABLE_TOKEN, + param, }); } else { deps.push({token, attribute, optional, self, skipSelf, host, resolved}); @@ -122,10 +122,10 @@ export function valueReferenceToExpression( export function valueReferenceToExpression( valueRef: null, defaultImportRecorder: DefaultImportRecorder): null; export function valueReferenceToExpression( - valueRef: TypeValueReference | null, defaultImportRecorder: DefaultImportRecorder): Expression| + valueRef: TypeValueReference|null, defaultImportRecorder: DefaultImportRecorder): Expression| null; export function valueReferenceToExpression( - valueRef: TypeValueReference | null, defaultImportRecorder: DefaultImportRecorder): Expression| + valueRef: TypeValueReference|null, defaultImportRecorder: DefaultImportRecorder): Expression| null { if (valueRef === null) { return null; @@ -138,7 +138,7 @@ export function valueReferenceToExpression( return new WrappedNodeExpr(valueRef.expression); } else { // TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here. - return new ExternalExpr(valueRef as{moduleName: string, name: string}); + return new ExternalExpr(valueRef as {moduleName: string, name: string}); } } @@ -148,7 +148,7 @@ export function valueReferenceToExpression( * * This is a companion function to `validateConstructorDependencies` which accepts invalid deps. */ -export function unwrapConstructorDependencies(deps: ConstructorDeps | null): R3DependencyMetadata[]| +export function unwrapConstructorDependencies(deps: ConstructorDeps|null): R3DependencyMetadata[]| 'invalid'|null { if (deps === null) { return null; @@ -176,18 +176,19 @@ export function getValidConstructorDependencies( * deps. */ export function validateConstructorDependencies( - clazz: ClassDeclaration, deps: ConstructorDeps | null): R3DependencyMetadata[]|null { + clazz: ClassDeclaration, deps: ConstructorDeps|null): R3DependencyMetadata[]|null { if (deps === null) { return null; } else if (deps.deps !== null) { return deps.deps; } else { // TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here. - const {param, index} = (deps as{errors: ConstructorDepError[]}).errors[0]; + const {param, index} = (deps as {errors: ConstructorDepError[]}).errors[0]; // There is at least one error. throw new FatalDiagnosticError( ErrorCode.PARAM_MISSING_TOKEN, param.nameNode, - `No suitable injection token for parameter '${param.name || index}' of class '${clazz.name.text}'.\n` + + `No suitable injection token for parameter '${param.name || index}' of class '${ + clazz.name.text}'.\n` + (param.typeNode !== null ? `Found ${param.typeNode.getText()}` : 'no type or decorator')); } @@ -319,8 +320,7 @@ export function forwardRefResolver( */ export function combineResolvers(resolvers: ForeignFunctionResolver[]): ForeignFunctionResolver { return (ref: Reference<ts.FunctionDeclaration|ts.MethodDeclaration|ts.FunctionExpression>, - args: ReadonlyArray<ts.Expression>): ts.Expression | - null => { + args: ReadonlyArray<ts.Expression>): ts.Expression|null => { for (const resolver of resolvers) { const resolved = resolver(ref, args); if (resolved !== null) { @@ -406,8 +406,8 @@ export function makeDuplicateDeclarationError( const contextNode = decl.ref.getOriginForDiagnostics(decl.rawDeclarations, decl.ngModule.name); context.push({ node: contextNode, - messageText: - `'${node.name.text}' is listed in the declarations of the NgModule '${decl.ngModule.name.text}'.`, + messageText: `'${node.name.text}' is listed in the declarations of the NgModule '${ + decl.ngModule.name.text}'.`, }); } @@ -441,7 +441,7 @@ export function resolveProvidersRequiringFactory( } else if (provider instanceof Reference) { tokenClass = provider; } else if (provider instanceof Map && provider.has('useClass') && !provider.has('deps')) { - const useExisting = provider.get('useClass') !; + const useExisting = provider.get('useClass')!; if (useExisting instanceof Reference) { tokenClass = useExisting; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts index 02772389e3ac2..fa952d1a60ffe 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts @@ -12,17 +12,23 @@ import {runInEachFileSystem} from '../../file_system/testing'; import {ModuleResolver, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports'; import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata'; import {PartialEvaluator} from '../../partial_evaluator'; -import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope'; import {getDeclaration, makeProgram} from '../../testing'; import {ResourceLoader} from '../src/api'; import {ComponentDecoratorHandler} from '../src/component'; export class NoopResourceLoader implements ResourceLoader { - resolve(): string { throw new Error('Not implemented.'); } + resolve(): string { + throw new Error('Not implemented.'); + } canPreload = false; - load(): string { throw new Error('Not implemented'); } - preload(): Promise<void>|undefined { throw new Error('Not implemented'); } + load(): string { + throw new Error('Not implemented'); + } + preload(): Promise<void>|undefined { + throw new Error('Not implemented'); + } } runInEachFileSystem(() => { describe('ComponentDecoratorHandler', () => { @@ -83,10 +89,12 @@ runInEachFileSystem(() => { const diag = err.toDiagnostic(); expect(diag.code).toEqual(ivyCode(ErrorCode.DECORATOR_ARG_NOT_LITERAL)); expect(diag.file.fileName.endsWith('entry.ts')).toBe(true); - expect(diag.start).toBe(detected.metadata.args ![0].getStart()); + expect(diag.start).toBe(detected.metadata.args![0].getStart()); } }); }); - function ivyCode(code: ErrorCode): number { return Number('-99' + code.valueOf()); } + function ivyCode(code: ErrorCode): number { + return Number('-99' + code.valueOf()); + } }); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts index 62ecab624ef88..0cd61336f10ad 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/directive_spec.ts @@ -6,12 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; + import {absoluteFrom} from '../../file_system'; import {runInEachFileSystem} from '../../file_system/testing'; import {NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports'; import {DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata'; import {PartialEvaluator} from '../../partial_evaluator'; -import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {ClassDeclaration, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope'; import {getDeclaration, makeProgram} from '../../testing'; import {DirectiveDecoratorHandler} from '../src/directive'; @@ -77,9 +78,13 @@ runInEachFileSystem(() => { // Helpers function analyzeDirective(program: ts.Program, dirName: string, hasBaseClass: boolean = false) { class TestReflectionHost extends TypeScriptReflectionHost { - constructor(checker: ts.TypeChecker) { super(checker); } + constructor(checker: ts.TypeChecker) { + super(checker); + } - hasBaseClass(_class: ClassDeclaration): boolean { return hasBaseClass; } + hasBaseClass(_class: ClassDeclaration): boolean { + return hasBaseClass; + } } const checker = program.getTypeChecker(); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/injectable_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/injectable_spec.ts index fed17853d4e9e..104f9d48a0c2d 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/injectable_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/injectable_spec.ts @@ -10,7 +10,7 @@ import {absoluteFrom} from '../../file_system'; import {runInEachFileSystem} from '../../file_system/testing'; import {NOOP_DEFAULT_IMPORT_RECORDER} from '../../imports'; import {InjectableClassRegistry} from '../../metadata'; -import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; import {InjectableDecoratorHandler} from '../src/injectable'; @@ -31,7 +31,7 @@ runInEachFileSystem(() => { const diag = err.toDiagnostic(); expect(diag.code).toEqual(ngErrorCode(ErrorCode.INJECTABLE_DUPLICATE_PROV)); expect(diag.file.fileName.endsWith('entry.ts')).toBe(true); - expect(diag.start).toBe(ɵprov.nameNode !.getStart()); + expect(diag.start).toBe(ɵprov.nameNode!.getStart()); } }); @@ -43,7 +43,6 @@ runInEachFileSystem(() => { expect(res).not.toContain(jasmine.objectContaining({name: 'ɵprov'})); }); }); - }); }); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts index 536bb02c4df8b..5bf1fc82f9ba5 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/metadata_spec.ts @@ -6,8 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; + import {absoluteFrom, getSourceFileOrError} from '../../file_system'; -import {TestFile, runInEachFileSystem} from '../../file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../file_system/testing'; import {NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports'; import {TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/ng_module_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/ng_module_spec.ts index 2e89ddca33278..0495a5c03f86b 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/ng_module_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/ng_module_spec.ts @@ -14,7 +14,7 @@ import {runInEachFileSystem} from '../../file_system/testing'; import {LocalIdentifierStrategy, NOOP_DEFAULT_IMPORT_RECORDER, ReferenceEmitter} from '../../imports'; import {CompoundMetadataReader, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry} from '../../metadata'; import {PartialEvaluator} from '../../partial_evaluator'; -import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope'; import {getDeclaration, makeProgram} from '../../testing'; import {NgModuleDecoratorHandler} from '../src/ng_module'; @@ -79,7 +79,7 @@ runInEachFileSystem(() => { if (detected === undefined) { return fail('Failed to recognize @NgModule'); } - const moduleDef = handler.analyze(TestModule, detected.metadata).analysis !.mod; + const moduleDef = handler.analyze(TestModule, detected.metadata).analysis!.mod; expect(getReferenceIdentifierTexts(moduleDef.declarations)).toEqual(['TestComp']); expect(getReferenceIdentifierTexts(moduleDef.exports)).toEqual(['TestComp']); diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/util_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/util_spec.ts index 95fc30ef1ccb9..6318ea4fc8d0f 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/util_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/util_spec.ts @@ -13,8 +13,9 @@ import {unwrapExpression} from '../src/util'; describe('ngtsc annotation utilities', () => { describe('unwrapExpression', () => { const obj = ts.createObjectLiteral(); - it('should pass through an ObjectLiteralExpression', - () => { expect(unwrapExpression(obj)).toBe(obj); }); + it('should pass through an ObjectLiteralExpression', () => { + expect(unwrapExpression(obj)).toBe(obj); + }); it('should unwrap an ObjectLiteralExpression in parentheses', () => { const wrapped = ts.createParen(obj); diff --git a/packages/compiler-cli/src/ngtsc/core/api/src/interfaces.ts b/packages/compiler-cli/src/ngtsc/core/api/src/interfaces.ts index fb67d80a60652..fa84da22a06e0 100644 --- a/packages/compiler-cli/src/ngtsc/core/api/src/interfaces.ts +++ b/packages/compiler-cli/src/ngtsc/core/api/src/interfaces.ts @@ -56,7 +56,7 @@ export interface ResourceHost { * core interface. */ export interface ExtendedTsCompilerHost extends ts.CompilerHost, Partial<ResourceHost>, - Partial<UnifiedModulesHost> {} + Partial<UnifiedModulesHost> {} export interface LazyRoute { route: string; diff --git a/packages/compiler-cli/src/ngtsc/core/api/src/options.ts b/packages/compiler-cli/src/ngtsc/core/api/src/options.ts index 5bcbcc67b0dba..a27ceb3b04bf4 100644 --- a/packages/compiler-cli/src/ngtsc/core/api/src/options.ts +++ b/packages/compiler-cli/src/ngtsc/core/api/src/options.ts @@ -36,7 +36,8 @@ export interface TestOnlyOptions { */ ivyTemplateTypeCheck?: boolean; - /** An option to enable ngtsc's internal performance tracing. + /** + * An option to enable ngtsc's internal performance tracing. * * This should be a path to a JSON file where trace information will be written. An optional 'ts:' * prefix will cause the trace to be written via the TS host instead of directly to the filesystem @@ -54,4 +55,5 @@ export interface TestOnlyOptions { * Also includes a few miscellaneous options. */ export interface NgCompilerOptions extends ts.CompilerOptions, LegacyNgcOptions, BazelAndG3Options, - NgcCompatibilityOptions, StrictTemplateOptions, TestOnlyOptions, I18nOptions, MiscOptions {} \ No newline at end of file + NgcCompatibilityOptions, StrictTemplateOptions, + TestOnlyOptions, I18nOptions, MiscOptions {} \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts index 9f315059b9275..f932927066175 100644 --- a/packages/compiler-cli/src/ngtsc/core/src/compiler.ts +++ b/packages/compiler-cli/src/ngtsc/core/src/compiler.ts @@ -12,23 +12,23 @@ import * as ts from 'typescript'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, NoopReferencesRegistry, PipeDecoratorHandler, ReferencesRegistry} from '../../annotations'; import {CycleAnalyzer, ImportGraph} from '../../cycles'; import {ErrorCode, ngErrorCode} from '../../diagnostics'; -import {ReferenceGraph, checkForPrivateExports} from '../../entry_point'; -import {LogicalFileSystem, getSourceFileOrError} from '../../file_system'; -import {AbsoluteModuleStrategy, AliasStrategy, AliasingHost, DefaultImportTracker, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesAliasingHost, UnifiedModulesStrategy} from '../../imports'; +import {checkForPrivateExports, ReferenceGraph} from '../../entry_point'; +import {getSourceFileOrError, LogicalFileSystem} from '../../file_system'; +import {AbsoluteModuleStrategy, AliasingHost, AliasStrategy, DefaultImportTracker, ImportRewriter, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, NoopImportRewriter, PrivateExportAliasingHost, R3SymbolsImportRewriter, Reference, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesAliasingHost, UnifiedModulesStrategy} from '../../imports'; import {IncrementalDriver} from '../../incremental'; -import {IndexedComponent, IndexingContext, generateAnalysis} from '../../indexer'; +import {generateAnalysis, IndexedComponent, IndexingContext} from '../../indexer'; import {CompoundMetadataReader, CompoundMetadataRegistry, DtsMetadataReader, InjectableClassRegistry, LocalMetadataRegistry, MetadataReader} from '../../metadata'; import {ModuleWithProvidersScanner} from '../../modulewithproviders'; import {PartialEvaluator} from '../../partial_evaluator'; import {NOOP_PERF_RECORDER, PerfRecorder} from '../../perf'; import {TypeScriptReflectionHost} from '../../reflection'; import {HostResourceLoader} from '../../resource'; -import {NgModuleRouteAnalyzer, entryPointKeyFor} from '../../routing'; +import {entryPointKeyFor, NgModuleRouteAnalyzer} from '../../routing'; import {ComponentScopeReader, LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../scope'; import {generatedFactoryTransform} from '../../shims'; import {ivySwitchTransform} from '../../switch'; -import {DecoratorHandler, DtsTransformRegistry, TraitCompiler, aliasTransformFactory, declarationTransformFactory, ivyTransformFactory} from '../../transform'; -import {TypeCheckContext, TypeCheckingConfig, isTemplateDiagnostic} from '../../typecheck'; +import {aliasTransformFactory, declarationTransformFactory, DecoratorHandler, DtsTransformRegistry, ivyTransformFactory, TraitCompiler} from '../../transform'; +import {isTemplateDiagnostic, TypeCheckContext, TypeCheckingConfig} from '../../typecheck'; import {getSourceFileOrNull, isDtsPath, resolveModuleName} from '../../util/src/typescript'; import {LazyRoute, NgCompilerOptions} from '../api'; @@ -191,7 +191,9 @@ export class NgCompiler { /** * Get all setup-related diagnostics for this compilation. */ - getOptionDiagnostics(): ts.Diagnostic[] { return this.constructionDiagnostics; } + getOptionDiagnostics(): ts.Diagnostic[] { + return this.constructionDiagnostics; + } /** * Get the `ts.Program` to use as a starting point when spawning a subsequent incremental @@ -202,7 +204,9 @@ export class NgCompiler { * operation, the consumer's `ts.Program` is no longer usable for starting a new incremental * compilation. `getNextProgram` retrieves the `ts.Program` which can be used instead. */ - getNextProgram(): ts.Program { return this.nextProgram; } + getNextProgram(): ts.Program { + return this.nextProgram; + } /** * Perform Angular's analysis step (as a precursor to `getDiagnostics` or `prepareEmit`) @@ -262,8 +266,8 @@ export class NgCompiler { // Relative entry paths are disallowed. if (entryRoute.startsWith('.')) { - throw new Error( - `Failed to list lazy routes: Resolution of relative paths (${entryRoute}) is not supported.`); + throw new Error(`Failed to list lazy routes: Resolution of relative paths (${ + entryRoute}) is not supported.`); } // Non-relative entry paths fall into one of the following categories: @@ -349,7 +353,7 @@ export class NgCompiler { if (this.compilation === null) { this.analyzeSync(); } - return this.compilation !; + return this.compilation!; } private analyzeSync(): void { @@ -482,7 +486,7 @@ export class NgCompiler { // Execute the typeCheck phase of each decorator in the program. const prepSpan = this.perfRecorder.start('typeCheckPrep'); const ctx = new TypeCheckContext( - typeCheckingConfig, compilation.refEmitter !, compilation.reflector, host.typeCheckFile); + typeCheckingConfig, compilation.refEmitter!, compilation.reflector, host.typeCheckFile); compilation.traitCompiler.typeCheck(ctx); this.perfRecorder.stop(prepSpan); @@ -505,7 +509,7 @@ export class NgCompiler { const recordSpan = this.perfRecorder.start('recordDependencies'); const depGraph = this.incrementalDriver.depGraph; - for (const scope of this.compilation !.scopeRegistry !.getCompilationScopes()) { + for (const scope of this.compilation!.scopeRegistry!.getCompilationScopes()) { const file = scope.declaration.getSourceFile(); const ngModuleFile = scope.ngModule.getSourceFile(); @@ -517,7 +521,7 @@ export class NgCompiler { depGraph.addDependency(file, ngModuleFile); const meta = - this.compilation !.metaReader.getDirectiveMetadata(new Reference(scope.declaration)); + this.compilation!.metaReader.getDirectiveMetadata(new Reference(scope.declaration)); if (meta !== null && meta.isComponent) { // If a component's template changes, it might have affected the import graph, and thus the // remote scoping feature which is activated in the event of potential import cycles. Thus, @@ -543,12 +547,11 @@ export class NgCompiler { } private scanForMwp(sf: ts.SourceFile): void { - this.compilation !.mwpScanner.scan(sf, { + this.compilation!.mwpScanner.scan(sf, { addTypeReplacement: (node: ts.Declaration, type: Type): void => { // Only obtain the return type transform for the source file once there's a type to replace, // so that no transform is allocated when there's nothing to do. - this.compilation !.dtsTransforms !.getReturnTypeTransform(sf).addTypeReplacement( - node, type); + this.compilation!.dtsTransforms!.getReturnTypeTransform(sf).addTypeReplacement(node, type); } }); } @@ -686,9 +689,18 @@ export class NgCompiler { this.options.compileNonExportedClasses !== false, dtsTransforms); return { - isCore, traitCompiler, reflector, scopeRegistry, - dtsTransforms, exportReferenceGraph, routeAnalyzer, mwpScanner, - metaReader, defaultImportTracker, aliasingHost, refEmitter, + isCore, + traitCompiler, + reflector, + scopeRegistry, + dtsTransforms, + exportReferenceGraph, + routeAnalyzer, + mwpScanner, + metaReader, + defaultImportTracker, + aliasingHost, + refEmitter, }; } } diff --git a/packages/compiler-cli/src/ngtsc/core/src/host.ts b/packages/compiler-cli/src/ngtsc/core/src/host.ts index 90c684394c434..474e08c05fb6b 100644 --- a/packages/compiler-cli/src/ngtsc/core/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/core/src/host.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {ErrorCode, ngErrorCode} from '../../diagnostics'; -import {FlatIndexGenerator, findFlatIndexEntryPoint} from '../../entry_point'; +import {findFlatIndexEntryPoint, FlatIndexGenerator} from '../../entry_point'; import {AbsoluteFsPath, resolve} from '../../file_system'; import {FactoryGenerator, FactoryTracker, ShimGenerator, SummaryGenerator, TypeCheckShimGenerator} from '../../shims'; import {typeCheckFilePath} from '../../typecheck'; @@ -88,8 +88,7 @@ export class DelegatingCompilerHost implements * `ExtendedTsCompilerHost` methods whenever present. */ export class NgCompilerHost extends DelegatingCompilerHost implements - RequiredCompilerHostDelegations, - ExtendedTsCompilerHost { + RequiredCompilerHostDelegations, ExtendedTsCompilerHost { readonly factoryTracker: FactoryTracker|null = null; readonly entryPoint: AbsoluteFsPath|null = null; readonly diagnostics: ts.Diagnostic[]; diff --git a/packages/compiler-cli/src/ngtsc/core/test/compiler_test.ts b/packages/compiler-cli/src/ngtsc/core/test/compiler_test.ts index 493f0a8860e9b..eb8db2ed16fa2 100644 --- a/packages/compiler-cli/src/ngtsc/core/test/compiler_test.ts +++ b/packages/compiler-cli/src/ngtsc/core/test/compiler_test.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {FileSystem, NgtscCompilerHost, absoluteFrom as _, getFileSystem, getSourceFileOrError, setFileSystem} from '../../file_system'; +import {absoluteFrom as _, FileSystem, getFileSystem, getSourceFileOrError, NgtscCompilerHost, setFileSystem} from '../../file_system'; import {runInEachFileSystem} from '../../file_system/testing'; import {NgCompilerOptions} from '../api'; import {NgCompiler} from '../src/compiler'; @@ -16,7 +16,6 @@ import {NgCompilerHost} from '../src/host'; runInEachFileSystem(() => { - describe('NgCompiler', () => { let fs: FileSystem; diff --git a/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts b/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts index 37d876c1baa48..c14642c1f8834 100644 --- a/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts +++ b/packages/compiler-cli/src/ngtsc/cycles/src/imports.ts @@ -30,7 +30,7 @@ export class ImportGraph { if (!this.map.has(sf)) { this.map.set(sf, this.scanImports(sf)); } - return this.map.get(sf) !; + return this.map.get(sf)!; } /** @@ -47,7 +47,9 @@ export class ImportGraph { return; } results.add(sf); - this.importsOf(sf).forEach(imported => { this.transitiveImportsOfHelper(imported, results); }); + this.importsOf(sf).forEach(imported => { + this.transitiveImportsOfHelper(imported, results); + }); } /** diff --git a/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts b/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts index 2454c8641828a..54b03dd5d9963 100644 --- a/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts +++ b/packages/compiler-cli/src/ngtsc/diagnostics/src/error.ts @@ -33,7 +33,8 @@ export function makeDiagnostic(code: ErrorCode, node: ts.Node, messageText: stri code: Number('-99' + code.valueOf()), file: ts.getOriginalNode(node).getSourceFile(), start: node.getStart(undefined, false), - length: node.getWidth(), messageText, + length: node.getWidth(), + messageText, }; if (relatedInfo !== undefined) { diag.relatedInformation = relatedInfo.map(info => { diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts index fcf3b760d23a1..96d95677d3894 100644 --- a/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/generator.ts @@ -24,7 +24,9 @@ export class FlatIndexGenerator implements ShimGenerator { join(dirname(entryPoint), relativeFlatIndexPath).replace(/\.js$/, '') + '.ts'; } - recognize(fileName: string): boolean { return fileName === this.flatIndexPath; } + recognize(fileName: string): boolean { + return fileName === this.flatIndexPath; + } generate(): ts.SourceFile { const relativeEntryPoint = relativePathBetween(this.flatIndexPath, this.entryPoint); diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts index 06e04d4cd5baf..57ea95bcec6d6 100644 --- a/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/private_export_checker.ts @@ -95,9 +95,11 @@ export function checkForPrivateExports( const diagnostic: ts.Diagnostic = { category: ts.DiagnosticCategory.Error, code: ngErrorCode(ErrorCode.SYMBOL_NOT_EXPORTED), - file: transitiveReference.getSourceFile(), ...getPosOfDeclaration(transitiveReference), - messageText: - `Unsupported private ${descriptor} ${name}. This ${descriptor} is visible to consumers via ${visibleVia}, but is not exported from the top-level library entrypoint.`, + file: transitiveReference.getSourceFile(), + ...getPosOfDeclaration(transitiveReference), + messageText: `Unsupported private ${descriptor} ${name}. This ${ + descriptor} is visible to consumers via ${ + visibleVia}, but is not exported from the top-level library entrypoint.`, }; diagnostics.push(diagnostic); diff --git a/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts b/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts index 396e90c5e9593..7691df63c3f8a 100644 --- a/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts +++ b/packages/compiler-cli/src/ngtsc/entry_point/src/reference_graph.ts @@ -15,7 +15,7 @@ export class ReferenceGraph<T = ts.Declaration> { if (!this.references.has(from)) { this.references.set(from, new Set()); } - this.references.get(from) !.add(to); + this.references.get(from)!.add(to); } transitiveReferencesOf(target: T): Set<T> { @@ -47,7 +47,7 @@ export class ReferenceGraph<T = ts.Declaration> { // Look through the outgoing edges of `source`. // TODO(alxhub): use proper iteration when the legacy build is removed. (#27762) let candidatePath: T[]|null = null; - this.references.get(source) !.forEach(edge => { + this.references.get(source)!.forEach(edge => { // Early exit if a path has already been found. if (candidatePath !== null) { return; @@ -67,7 +67,7 @@ export class ReferenceGraph<T = ts.Declaration> { private collectTransitiveReferences(set: Set<T>, decl: T): void { if (this.references.has(decl)) { // TODO(alxhub): use proper iteration when the legacy build is removed. (#27762) - this.references.get(decl) !.forEach(ref => { + this.references.get(decl)!.forEach(ref => { if (!set.has(ref)) { set.add(ref); this.collectTransitiveReferences(set, ref); diff --git a/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts b/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts index 7099cb8cb64e0..ed77965149b54 100644 --- a/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts +++ b/packages/compiler-cli/src/ngtsc/entry_point/test/entry_point_spec.ts @@ -16,9 +16,9 @@ runInEachFileSystem(() => { beforeEach(() => _ = absoluteFrom); describe('findFlatIndexEntryPoint', () => { - - it('should use the only source file if only a single one is specified', - () => { expect(findFlatIndexEntryPoint([_('/src/index.ts')])).toBe(_('/src/index.ts')); }); + it('should use the only source file if only a single one is specified', () => { + expect(findFlatIndexEntryPoint([_('/src/index.ts')])).toBe(_('/src/index.ts')); + }); it('should use the shortest source file ending with "index.ts" for multiple files', () => { expect(findFlatIndexEntryPoint([ diff --git a/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts b/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts index 78be9e7e6b620..6ed312b9425eb 100644 --- a/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts +++ b/packages/compiler-cli/src/ngtsc/entry_point/test/reference_graph_spec.ts @@ -12,8 +12,9 @@ import {ReferenceGraph} from '../src/reference_graph'; describe('entry_point reference graph', () => { let graph: ReferenceGraph<string>; - const refs = - (target: string) => { return Array.from(graph.transitiveReferencesOf(target)).sort(); }; + const refs = (target: string) => { + return Array.from(graph.transitiveReferencesOf(target)).sort(); + }; beforeEach(() => { graph = new ReferenceGraph(); @@ -45,6 +46,7 @@ describe('entry_point reference graph', () => { expect(graph.pathFrom('beta', 'alpha')).toEqual(['beta', 'delta', 'alpha']); }); - it('should not report a path that doesn\'t exist', - () => { expect(graph.pathFrom('gamma', 'beta')).toBeNull(); }); + it('should not report a path that doesn\'t exist', () => { + expect(graph.pathFrom('gamma', 'beta')).toBeNull(); + }); }); diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts index 25e9ff81de18b..1f04bb2bab0f5 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/cached_file_system.ts @@ -25,7 +25,7 @@ export class CachedFileSystem implements FileSystem { if (!this.existsCache.has(path)) { this.existsCache.set(path, this.delegate.exists(path)); } - return this.existsCache.get(path) !; + return this.existsCache.get(path)!; } invalidateCaches(path: AbsoluteFsPath) { @@ -131,15 +131,33 @@ export class CachedFileSystem implements FileSystem { } // The following methods simply call through to the delegate. - readdir(path: AbsoluteFsPath): PathSegment[] { return this.delegate.readdir(path); } - pwd(): AbsoluteFsPath { return this.delegate.pwd(); } - chdir(path: AbsoluteFsPath): void { this.delegate.chdir(path); } - extname(path: AbsoluteFsPath|PathSegment): string { return this.delegate.extname(path); } - isCaseSensitive(): boolean { return this.delegate.isCaseSensitive(); } - isRoot(path: AbsoluteFsPath): boolean { return this.delegate.isRoot(path); } - isRooted(path: string): boolean { return this.delegate.isRooted(path); } - resolve(...paths: string[]): AbsoluteFsPath { return this.delegate.resolve(...paths); } - dirname<T extends PathString>(file: T): T { return this.delegate.dirname(file); } + readdir(path: AbsoluteFsPath): PathSegment[] { + return this.delegate.readdir(path); + } + pwd(): AbsoluteFsPath { + return this.delegate.pwd(); + } + chdir(path: AbsoluteFsPath): void { + this.delegate.chdir(path); + } + extname(path: AbsoluteFsPath|PathSegment): string { + return this.delegate.extname(path); + } + isCaseSensitive(): boolean { + return this.delegate.isCaseSensitive(); + } + isRoot(path: AbsoluteFsPath): boolean { + return this.delegate.isRoot(path); + } + isRooted(path: string): boolean { + return this.delegate.isRooted(path); + } + resolve(...paths: string[]): AbsoluteFsPath { + return this.delegate.resolve(...paths); + } + dirname<T extends PathString>(file: T): T { + return this.delegate.dirname(file); + } join<T extends PathString>(basePath: T, ...paths: string[]): T { return this.delegate.join(basePath, ...paths); } @@ -149,7 +167,13 @@ export class CachedFileSystem implements FileSystem { basename(filePath: string, extension?: string|undefined): PathSegment { return this.delegate.basename(filePath, extension); } - realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { return this.delegate.realpath(filePath); } - getDefaultLibLocation(): AbsoluteFsPath { return this.delegate.getDefaultLibLocation(); } - normalize<T extends PathString>(path: T): T { return this.delegate.normalize(path); } + realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { + return this.delegate.realpath(filePath); + } + getDefaultLibLocation(): AbsoluteFsPath { + return this.delegate.getDefaultLibLocation(); + } + normalize<T extends PathString>(path: T): T { + return this.delegate.normalize(path); + } } diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/compiler_host.ts b/packages/compiler-cli/src/ngtsc/file_system/src/compiler_host.ts index 3c7b62b26de90..40717c44f5388 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/compiler_host.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/compiler_host.ts @@ -26,7 +26,9 @@ export class NgtscCompilerHost implements ts.CompilerHost { return this.fs.join(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options)); } - getDefaultLibLocation(): string { return this.fs.getDefaultLibLocation(); } + getDefaultLibLocation(): string { + return this.fs.getDefaultLibLocation(); + } writeFile( fileName: string, data: string, writeByteOrderMark: boolean, @@ -37,13 +39,17 @@ export class NgtscCompilerHost implements ts.CompilerHost { this.fs.writeFile(path, data); } - getCurrentDirectory(): string { return this.fs.pwd(); } + getCurrentDirectory(): string { + return this.fs.pwd(); + } getCanonicalFileName(fileName: string): string { return this.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase(); } - useCaseSensitiveFileNames(): boolean { return this.fs.isCaseSensitive(); } + useCaseSensitiveFileNames(): boolean { + return this.fs.isCaseSensitive(); + } getNewLine(): string { switch (this.options.newLine) { diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts index 2fcf235afe9e0..b9a9c4af215ab 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/invalid_file_system.ts @@ -16,32 +16,84 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './ * the `FileSystem` under the hood. */ export class InvalidFileSystem implements FileSystem { - exists(path: AbsoluteFsPath): boolean { throw makeError(); } - readFile(path: AbsoluteFsPath): string { throw makeError(); } - writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { throw makeError(); } - removeFile(path: AbsoluteFsPath): void { throw makeError(); } - symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { throw makeError(); } - readdir(path: AbsoluteFsPath): PathSegment[] { throw makeError(); } - lstat(path: AbsoluteFsPath): FileStats { throw makeError(); } - stat(path: AbsoluteFsPath): FileStats { throw makeError(); } - pwd(): AbsoluteFsPath { throw makeError(); } - chdir(path: AbsoluteFsPath): void { throw makeError(); } - extname(path: AbsoluteFsPath|PathSegment): string { throw makeError(); } - copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); } - moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { throw makeError(); } - ensureDir(path: AbsoluteFsPath): void { throw makeError(); } - removeDeep(path: AbsoluteFsPath): void { throw makeError(); } - isCaseSensitive(): boolean { throw makeError(); } - resolve(...paths: string[]): AbsoluteFsPath { throw makeError(); } - dirname<T extends PathString>(file: T): T { throw makeError(); } - join<T extends PathString>(basePath: T, ...paths: string[]): T { throw makeError(); } - isRoot(path: AbsoluteFsPath): boolean { throw makeError(); } - isRooted(path: string): boolean { throw makeError(); } - relative<T extends PathString>(from: T, to: T): PathSegment { throw makeError(); } - basename(filePath: string, extension?: string): PathSegment { throw makeError(); } - realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { throw makeError(); } - getDefaultLibLocation(): AbsoluteFsPath { throw makeError(); } - normalize<T extends PathString>(path: T): T { throw makeError(); } + exists(path: AbsoluteFsPath): boolean { + throw makeError(); + } + readFile(path: AbsoluteFsPath): string { + throw makeError(); + } + writeFile(path: AbsoluteFsPath, data: string, exclusive?: boolean): void { + throw makeError(); + } + removeFile(path: AbsoluteFsPath): void { + throw makeError(); + } + symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { + throw makeError(); + } + readdir(path: AbsoluteFsPath): PathSegment[] { + throw makeError(); + } + lstat(path: AbsoluteFsPath): FileStats { + throw makeError(); + } + stat(path: AbsoluteFsPath): FileStats { + throw makeError(); + } + pwd(): AbsoluteFsPath { + throw makeError(); + } + chdir(path: AbsoluteFsPath): void { + throw makeError(); + } + extname(path: AbsoluteFsPath|PathSegment): string { + throw makeError(); + } + copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { + throw makeError(); + } + moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { + throw makeError(); + } + ensureDir(path: AbsoluteFsPath): void { + throw makeError(); + } + removeDeep(path: AbsoluteFsPath): void { + throw makeError(); + } + isCaseSensitive(): boolean { + throw makeError(); + } + resolve(...paths: string[]): AbsoluteFsPath { + throw makeError(); + } + dirname<T extends PathString>(file: T): T { + throw makeError(); + } + join<T extends PathString>(basePath: T, ...paths: string[]): T { + throw makeError(); + } + isRoot(path: AbsoluteFsPath): boolean { + throw makeError(); + } + isRooted(path: string): boolean { + throw makeError(); + } + relative<T extends PathString>(from: T, to: T): PathSegment { + throw makeError(); + } + basename(filePath: string, extension?: string): PathSegment { + throw makeError(); + } + realpath(filePath: AbsoluteFsPath): AbsoluteFsPath { + throw makeError(); + } + getDefaultLibLocation(): AbsoluteFsPath { + throw makeError(); + } + normalize<T extends PathString>(path: T): T { + throw makeError(); + } } function makeError() { diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/logical.ts b/packages/compiler-cli/src/ngtsc/file_system/src/logical.ts index 312cd0d6d4415..15b5c24ae7df1 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/logical.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/logical.ts @@ -91,7 +91,7 @@ export class LogicalFileSystem { } this.cache.set(physicalFile, logicalFile); } - return this.cache.get(physicalFile) !; + return this.cache.get(physicalFile)!; } private createLogicalProjectPath(file: AbsoluteFsPath, rootDir: AbsoluteFsPath): diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts index b373e8e567cd9..2a1a41a7b5d24 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/node_js_file_system.ts @@ -17,20 +17,42 @@ import {AbsoluteFsPath, FileStats, FileSystem, PathSegment, PathString} from './ */ export class NodeJSFileSystem implements FileSystem { private _caseSensitive: boolean|undefined = undefined; - exists(path: AbsoluteFsPath): boolean { return fs.existsSync(path); } - readFile(path: AbsoluteFsPath): string { return fs.readFileSync(path, 'utf8'); } + exists(path: AbsoluteFsPath): boolean { + return fs.existsSync(path); + } + readFile(path: AbsoluteFsPath): string { + return fs.readFileSync(path, 'utf8'); + } writeFile(path: AbsoluteFsPath, data: string, exclusive: boolean = false): void { fs.writeFileSync(path, data, exclusive ? {flag: 'wx'} : undefined); } - removeFile(path: AbsoluteFsPath): void { fs.unlinkSync(path); } - symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { fs.symlinkSync(target, path); } - readdir(path: AbsoluteFsPath): PathSegment[] { return fs.readdirSync(path) as PathSegment[]; } - lstat(path: AbsoluteFsPath): FileStats { return fs.lstatSync(path); } - stat(path: AbsoluteFsPath): FileStats { return fs.statSync(path); } - pwd(): AbsoluteFsPath { return this.normalize(process.cwd()) as AbsoluteFsPath; } - chdir(dir: AbsoluteFsPath): void { process.chdir(dir); } - copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { fs.copyFileSync(from, to); } - moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { fs.renameSync(from, to); } + removeFile(path: AbsoluteFsPath): void { + fs.unlinkSync(path); + } + symlink(target: AbsoluteFsPath, path: AbsoluteFsPath): void { + fs.symlinkSync(target, path); + } + readdir(path: AbsoluteFsPath): PathSegment[] { + return fs.readdirSync(path) as PathSegment[]; + } + lstat(path: AbsoluteFsPath): FileStats { + return fs.lstatSync(path); + } + stat(path: AbsoluteFsPath): FileStats { + return fs.statSync(path); + } + pwd(): AbsoluteFsPath { + return this.normalize(process.cwd()) as AbsoluteFsPath; + } + chdir(dir: AbsoluteFsPath): void { + process.chdir(dir); + } + copyFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { + fs.copyFileSync(from, to); + } + moveFile(from: AbsoluteFsPath, to: AbsoluteFsPath): void { + fs.renameSync(from, to); + } ensureDir(path: AbsoluteFsPath): void { const parents: AbsoluteFsPath[] = []; while (!this.isRoot(path) && !this.exists(path)) { @@ -38,10 +60,12 @@ export class NodeJSFileSystem implements FileSystem { path = this.dirname(path); } while (parents.length) { - this.safeMkdir(parents.pop() !); + this.safeMkdir(parents.pop()!); } } - removeDeep(path: AbsoluteFsPath): void { fsExtra.removeSync(path); } + removeDeep(path: AbsoluteFsPath): void { + fsExtra.removeSync(path); + } isCaseSensitive(): boolean { if (this._caseSensitive === undefined) { this._caseSensitive = this.exists(togglePathCase(__filename)); @@ -52,20 +76,30 @@ export class NodeJSFileSystem implements FileSystem { return this.normalize(p.resolve(...paths)) as AbsoluteFsPath; } - dirname<T extends string>(file: T): T { return this.normalize(p.dirname(file)) as T; } + dirname<T extends string>(file: T): T { + return this.normalize(p.dirname(file)) as T; + } join<T extends string>(basePath: T, ...paths: string[]): T { return this.normalize(p.join(basePath, ...paths)) as T; } - isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === this.normalize(path); } - isRooted(path: string): boolean { return p.isAbsolute(path); } + isRoot(path: AbsoluteFsPath): boolean { + return this.dirname(path) === this.normalize(path); + } + isRooted(path: string): boolean { + return p.isAbsolute(path); + } relative<T extends PathString>(from: T, to: T): PathSegment { return relativeFrom(this.normalize(p.relative(from, to))); } basename(filePath: string, extension?: string): PathSegment { return p.basename(filePath, extension) as PathSegment; } - extname(path: AbsoluteFsPath|PathSegment): string { return p.extname(path); } - realpath(path: AbsoluteFsPath): AbsoluteFsPath { return this.resolve(fs.realpathSync(path)); } + extname(path: AbsoluteFsPath|PathSegment): string { + return p.extname(path); + } + realpath(path: AbsoluteFsPath): AbsoluteFsPath { + return this.resolve(fs.realpathSync(path)); + } getDefaultLibLocation(): AbsoluteFsPath { return this.resolve(require.resolve('typescript'), '..'); } diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/types.ts b/packages/compiler-cli/src/ngtsc/file_system/src/types.ts index 520b41bead75d..365de3b851795 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/types.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/types.ts @@ -12,7 +12,7 @@ * A `string` is not assignable to a `BrandedPath`, but a `BrandedPath` is assignable to a `string`. * Two `BrandedPath`s with different brands are not mutually assignable. */ -export type BrandedPath<B extends string> = string & { +export type BrandedPath<B extends string> = string&{ _brand: B; }; @@ -63,7 +63,7 @@ export interface FileSystem { normalize<T extends PathString>(path: T): T; } -export type PathString = string | AbsoluteFsPath | PathSegment; +export type PathString = string|AbsoluteFsPath|PathSegment; /** * Information about an object in the FileSystem. diff --git a/packages/compiler-cli/src/ngtsc/file_system/src/util.ts b/packages/compiler-cli/src/ngtsc/file_system/src/util.ts index be2863e9ac146..41f6c2b391427 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/src/util.ts @@ -28,8 +28,8 @@ export function stripExtension(path: string): string { export function getSourceFileOrError(program: ts.Program, fileName: AbsoluteFsPath): ts.SourceFile { const sf = program.getSourceFile(fileName); if (sf === undefined) { - throw new Error( - `Program does not contain "${fileName}" - available files are ${program.getSourceFiles().map(sf => sf.fileName).join(', ')}`); + throw new Error(`Program does not contain "${fileName}" - available files are ${ + program.getSourceFiles().map(sf => sf.fileName).join(', ')}`); } return sf; } diff --git a/packages/compiler-cli/src/ngtsc/file_system/test/helpers_spec.ts b/packages/compiler-cli/src/ngtsc/file_system/test/helpers_spec.ts index b14d44cc70485..6cc36eee824d1 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/test/helpers_spec.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/test/helpers_spec.ts @@ -11,37 +11,49 @@ import {absoluteFrom, relativeFrom, setFileSystem} from '../src/helpers'; import {NodeJSFileSystem} from '../src/node_js_file_system'; describe('path types', () => { - beforeEach(() => { setFileSystem(new NodeJSFileSystem()); }); + beforeEach(() => { + setFileSystem(new NodeJSFileSystem()); + }); describe('absoluteFrom', () => { - it('should not throw when creating one from an absolute path', - () => { expect(() => absoluteFrom('/test.txt')).not.toThrow(); }); + it('should not throw when creating one from an absolute path', () => { + expect(() => absoluteFrom('/test.txt')).not.toThrow(); + }); if (os.platform() === 'win32') { - it('should not throw when creating one from a windows absolute path', - () => { expect(absoluteFrom('C:\\test.txt')).toEqual('C:/test.txt'); }); + it('should not throw when creating one from a windows absolute path', () => { + expect(absoluteFrom('C:\\test.txt')).toEqual('C:/test.txt'); + }); it('should not throw when creating one from a windows absolute path with POSIX separators', - () => { expect(absoluteFrom('C:/test.txt')).toEqual('C:/test.txt'); }); - it('should support windows drive letters', - () => { expect(absoluteFrom('D:\\foo\\test.txt')).toEqual('D:/foo/test.txt'); }); - it('should convert Windows path separators to POSIX separators', - () => { expect(absoluteFrom('C:\\foo\\test.txt')).toEqual('C:/foo/test.txt'); }); + () => { + expect(absoluteFrom('C:/test.txt')).toEqual('C:/test.txt'); + }); + it('should support windows drive letters', () => { + expect(absoluteFrom('D:\\foo\\test.txt')).toEqual('D:/foo/test.txt'); + }); + it('should convert Windows path separators to POSIX separators', () => { + expect(absoluteFrom('C:\\foo\\test.txt')).toEqual('C:/foo/test.txt'); + }); } - it('should throw when creating one from a non-absolute path', - () => { expect(() => absoluteFrom('test.txt')).toThrow(); }); + it('should throw when creating one from a non-absolute path', () => { + expect(() => absoluteFrom('test.txt')).toThrow(); + }); }); describe('relativeFrom', () => { - it('should not throw when creating one from a relative path', - () => { expect(() => relativeFrom('a/b/c.txt')).not.toThrow(); }); + it('should not throw when creating one from a relative path', () => { + expect(() => relativeFrom('a/b/c.txt')).not.toThrow(); + }); - it('should throw when creating one from an absolute path', - () => { expect(() => relativeFrom('/a/b/c.txt')).toThrow(); }); + it('should throw when creating one from an absolute path', () => { + expect(() => relativeFrom('/a/b/c.txt')).toThrow(); + }); if (os.platform() === 'win32') { - it('should throw when creating one from a Windows absolute path', - () => { expect(() => relativeFrom('C:/a/b/c.txt')).toThrow(); }); + it('should throw when creating one from a Windows absolute path', () => { + expect(() => relativeFrom('C:/a/b/c.txt')).toThrow(); + }); } }); }); diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/index.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/index.ts index c41ab26f7b929..b5fb9f1084865 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/index.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/index.ts @@ -10,4 +10,4 @@ export {Folder, MockFileSystem} from './src/mock_file_system'; export {MockFileSystemNative} from './src/mock_file_system_native'; export {MockFileSystemPosix} from './src/mock_file_system_posix'; export {MockFileSystemWindows} from './src/mock_file_system_windows'; -export {TestFile, initMockFileSystem, runInEachFileSystem} from './src/test_helper'; +export {initMockFileSystem, runInEachFileSystem, TestFile} from './src/test_helper'; diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts index cf3c6258782dd..7731f5fea6c4d 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system.ts @@ -21,9 +21,13 @@ export abstract class MockFileSystem implements FileSystem { this._cwd = this.normalize(cwd); } - isCaseSensitive() { return this._isCaseSensitive; } + isCaseSensitive() { + return this._isCaseSensitive; + } - exists(path: AbsoluteFsPath): boolean { return this.findFromPath(path).entity !== null; } + exists(path: AbsoluteFsPath): boolean { + return this.findFromPath(path).entity !== null; + } readFile(path: AbsoluteFsPath): string { const {entity} = this.findFromPath(path); @@ -142,7 +146,9 @@ export abstract class MockFileSystem implements FileSystem { delete entity[basename]; } - isRoot(path: AbsoluteFsPath): boolean { return this.dirname(path) === path; } + isRoot(path: AbsoluteFsPath): boolean { + return this.dirname(path) === path; + } extname(path: AbsoluteFsPath|PathSegment): string { const match = /.+(\.[^.]*)$/.exec(path); @@ -159,9 +165,13 @@ export abstract class MockFileSystem implements FileSystem { } } - pwd(): AbsoluteFsPath { return this._cwd; } + pwd(): AbsoluteFsPath { + return this._cwd; + } - chdir(path: AbsoluteFsPath): void { this._cwd = this.normalize(path); } + chdir(path: AbsoluteFsPath): void { + this._cwd = this.normalize(path); + } getDefaultLibLocation(): AbsoluteFsPath { // Mimic the node module resolution algorithm and start in the current directory, then look @@ -201,8 +211,12 @@ export abstract class MockFileSystem implements FileSystem { abstract normalize<T extends PathString>(path: T): T; protected abstract splitPath<T extends PathString>(path: T): string[]; - dump(): Folder { return cloneFolder(this._fileTree); } - init(folder: Folder): void { this._fileTree = cloneFolder(folder); } + dump(): Folder { + return cloneFolder(this._fileTree); + } + init(folder: Folder): void { + this._fileTree = cloneFolder(folder); + } protected findFromPath(path: AbsoluteFsPath, options?: {followSymLinks: boolean}): FindResult { const followSymLinks = !!options && options.followSymLinks; @@ -215,7 +229,7 @@ export abstract class MockFileSystem implements FileSystem { segments[0] = ''; let current: Entity|null = this._fileTree; while (segments.length) { - current = current[segments.shift() !]; + current = current[segments.shift()!]; if (current === undefined) { return {path, entity: null}; } @@ -239,7 +253,7 @@ export abstract class MockFileSystem implements FileSystem { protected splitIntoFolderAndFile(path: AbsoluteFsPath): [AbsoluteFsPath, string] { const segments = this.splitPath(path); - const file = segments.pop() !; + const file = segments.pop()!; return [path.substring(0, path.length - file.length - 1) as AbsoluteFsPath, file]; } } @@ -247,8 +261,10 @@ export interface FindResult { path: AbsoluteFsPath; entity: Entity|null; } -export type Entity = Folder | File | SymLink; -export interface Folder { [pathSegments: string]: Entity; } +export type Entity = Folder|File|SymLink; +export interface Folder { + [pathSegments: string]: Entity; +} export type File = string; export class SymLink { constructor(public path: AbsoluteFsPath) {} @@ -256,24 +272,32 @@ export class SymLink { class MockFileStats implements FileStats { constructor(private entity: Entity) {} - isFile(): boolean { return isFile(this.entity); } - isDirectory(): boolean { return isFolder(this.entity); } - isSymbolicLink(): boolean { return isSymLink(this.entity); } + isFile(): boolean { + return isFile(this.entity); + } + isDirectory(): boolean { + return isFolder(this.entity); + } + isSymbolicLink(): boolean { + return isSymLink(this.entity); + } } class MockFileSystemError extends Error { - constructor(public code: string, public path: string, message: string) { super(message); } + constructor(public code: string, public path: string, message: string) { + super(message); + } } -export function isFile(item: Entity | null): item is File { +export function isFile(item: Entity|null): item is File { return typeof item === 'string'; } -export function isSymLink(item: Entity | null): item is SymLink { +export function isSymLink(item: Entity|null): item is SymLink { return item instanceof SymLink; } -export function isFolder(item: Entity | null): item is Folder { +export function isFolder(item: Entity|null): item is Folder { return item !== null && !isFile(item) && !isSymLink(item); } diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_native.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_native.ts index f4539fb048fb8..da97516e24f63 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_native.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_native.ts @@ -15,7 +15,9 @@ import {MockFileSystem} from './mock_file_system'; const isWindows = os.platform() === 'win32'; export class MockFileSystemNative extends MockFileSystem { - constructor(cwd: AbsoluteFsPath = '/' as AbsoluteFsPath) { super(undefined, cwd); } + constructor(cwd: AbsoluteFsPath = '/' as AbsoluteFsPath) { + super(undefined, cwd); + } // Delegate to the real NodeJSFileSystem for these path related methods @@ -36,9 +38,13 @@ export class MockFileSystemNative extends MockFileSystem { return NodeJSFileSystem.prototype.basename.call(this, filePath, extension); } - isCaseSensitive() { return NodeJSFileSystem.prototype.isCaseSensitive.call(this); } + isCaseSensitive() { + return NodeJSFileSystem.prototype.isCaseSensitive.call(this); + } - isRooted(path: string): boolean { return NodeJSFileSystem.prototype.isRooted.call(this, path); } + isRooted(path: string): boolean { + return NodeJSFileSystem.prototype.isRooted.call(this, path); + } isRoot(path: AbsoluteFsPath): boolean { return NodeJSFileSystem.prototype.isRoot.call(this, path); @@ -57,5 +63,7 @@ export class MockFileSystemNative extends MockFileSystem { return NodeJSFileSystem.prototype.normalize.call(this, path) as T; } - protected splitPath<T>(path: string): string[] { return path.split(/[\\\/]/); } + protected splitPath<T>(path: string): string[] { + return path.split(/[\\\/]/); + } } diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_posix.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_posix.ts index 2778997240758..74c528cad2cf1 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_posix.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_posix.ts @@ -17,7 +17,9 @@ export class MockFileSystemPosix extends MockFileSystem { return this.normalize(resolved) as AbsoluteFsPath; } - dirname<T extends string>(file: T): T { return this.normalize(p.posix.dirname(file)) as T; } + dirname<T extends string>(file: T): T { + return this.normalize(p.posix.dirname(file)) as T; + } join<T extends string>(basePath: T, ...paths: string[]): T { return this.normalize(p.posix.join(basePath, ...paths)) as T; @@ -31,9 +33,13 @@ export class MockFileSystemPosix extends MockFileSystem { return p.posix.basename(filePath, extension) as PathSegment; } - isRooted(path: string): boolean { return path.startsWith('/'); } + isRooted(path: string): boolean { + return path.startsWith('/'); + } - protected splitPath<T extends PathString>(path: T): string[] { return path.split('/'); } + protected splitPath<T extends PathString>(path: T): string[] { + return path.split('/'); + } normalize<T extends PathString>(path: T): T { return path.replace(/^[a-z]:\//i, '/').replace(/\\/g, '/') as T; diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_windows.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_windows.ts index 3ec01f4ed82f3..9cabd0a2b9a43 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_windows.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/mock_file_system_windows.ts @@ -17,7 +17,9 @@ export class MockFileSystemWindows extends MockFileSystem { return this.normalize(resolved as AbsoluteFsPath); } - dirname<T extends string>(path: T): T { return this.normalize(p.win32.dirname(path) as T); } + dirname<T extends string>(path: T): T { + return this.normalize(p.win32.dirname(path) as T); + } join<T extends string>(basePath: T, ...paths: string[]): T { return this.normalize(p.win32.join(basePath, ...paths)) as T; @@ -31,9 +33,13 @@ export class MockFileSystemWindows extends MockFileSystem { return p.win32.basename(filePath, extension) as PathSegment; } - isRooted(path: string): boolean { return /^([A-Z]:)?([\\\/]|$)/i.test(path); } + isRooted(path: string): boolean { + return /^([A-Z]:)?([\\\/]|$)/i.test(path); + } - protected splitPath<T extends PathString>(path: T): string[] { return path.split(/[\\\/]/); } + protected splitPath<T extends PathString>(path: T): string[] { + return path.split(/[\\\/]/); + } normalize<T extends PathString>(path: T): T { return path.replace(/^[\/\\]/i, 'C:/').replace(/\\/g, '/') as T; diff --git a/packages/compiler-cli/src/ngtsc/file_system/testing/src/test_helper.ts b/packages/compiler-cli/src/ngtsc/file_system/testing/src/test_helper.ts index f9ff163cc9678..2272d55b3b4f6 100644 --- a/packages/compiler-cli/src/ngtsc/file_system/testing/src/test_helper.ts +++ b/packages/compiler-cli/src/ngtsc/file_system/testing/src/test_helper.ts @@ -47,7 +47,9 @@ function runInFileSystem(os: string, callback: (os: string) => void, error: bool afterEach(() => setFileSystem(new InvalidFileSystem())); callback(os); if (error) { - afterAll(() => { throw new Error(`runInFileSystem limited to ${os}, cannot pass`); }); + afterAll(() => { + throw new Error(`runInFileSystem limited to ${os}, cannot pass`); + }); } }); } @@ -125,14 +127,16 @@ function monkeyPatchTypeScript(os: string, fs: MockFileSystem) { return {files, directories}; } - function realPath(path: string): string { return fs.realpath(fs.resolve(path)); } + function realPath(path: string): string { + return fs.realpath(fs.resolve(path)); + } // Rather than completely re-implementing we are using the `ts.matchFiles` function, // which is internal to the `ts` namespace. const tsMatchFiles: ( - path: string, extensions: ReadonlyArray<string>| undefined, - excludes: ReadonlyArray<string>| undefined, includes: ReadonlyArray<string>| undefined, - useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number | undefined, + path: string, extensions: ReadonlyArray<string>|undefined, + excludes: ReadonlyArray<string>|undefined, includes: ReadonlyArray<string>|undefined, + useCaseSensitiveFileNames: boolean, currentDirectory: string, depth: number|undefined, getFileSystemEntries: (path: string) => FileSystemEntries, realpath: (path: string) => string) => string[] = (ts as any).matchFiles; diff --git a/packages/compiler-cli/src/ngtsc/imports/index.ts b/packages/compiler-cli/src/ngtsc/imports/index.ts index d43beaaa30803..858f77c7e3e89 100644 --- a/packages/compiler-cli/src/ngtsc/imports/index.ts +++ b/packages/compiler-cli/src/ngtsc/imports/index.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -export {AliasStrategy, AliasingHost, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias'; +export {AliasingHost, AliasStrategy, PrivateExportAliasingHost, UnifiedModulesAliasingHost} from './src/alias'; export {ImportRewriter, NoopImportRewriter, R3SymbolsImportRewriter, validateAndRewriteCoreSymbol} from './src/core'; export {DefaultImportRecorder, DefaultImportTracker, NOOP_DEFAULT_IMPORT_RECORDER} from './src/default'; export {AbsoluteModuleStrategy, ImportFlags, LocalIdentifierStrategy, LogicalProjectStrategy, ReferenceEmitStrategy, ReferenceEmitter, RelativePathStrategy, UnifiedModulesStrategy} from './src/emitter'; diff --git a/packages/compiler-cli/src/ngtsc/imports/src/alias.ts b/packages/compiler-cli/src/ngtsc/imports/src/alias.ts index 6795705e2f3a5..94b4a1144446c 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/alias.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/alias.ts @@ -10,7 +10,7 @@ import {Expression, ExternalExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {UnifiedModulesHost} from '../../core/api'; -import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection'; import {ImportFlags, ReferenceEmitStrategy} from './emitter'; import {Reference} from './references'; @@ -203,7 +203,9 @@ export class PrivateExportAliasingHost implements AliasingHost { * * Thus, `getAliasIn` always returns `null`. */ - getAliasIn(): null { return null; } + getAliasIn(): null { + return null; + } } /** diff --git a/packages/compiler-cli/src/ngtsc/imports/src/core.ts b/packages/compiler-cli/src/ngtsc/imports/src/core.ts index a20b0c3097b90..027f814978c53 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/core.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/core.ts @@ -36,11 +36,17 @@ export interface ImportRewriter { * `ImportRewriter` that does no rewriting. */ export class NoopImportRewriter implements ImportRewriter { - shouldImportSymbol(symbol: string, specifier: string): boolean { return true; } + shouldImportSymbol(symbol: string, specifier: string): boolean { + return true; + } - rewriteSymbol(symbol: string, specifier: string): string { return symbol; } + rewriteSymbol(symbol: string, specifier: string): string { + return symbol; + } - rewriteSpecifier(specifier: string, inContextOfFile: string): string { return specifier; } + rewriteSpecifier(specifier: string, inContextOfFile: string): string { + return specifier; + } } /** @@ -70,7 +76,9 @@ const CORE_MODULE = '@angular/core'; export class R3SymbolsImportRewriter implements ImportRewriter { constructor(private r3SymbolsPath: string) {} - shouldImportSymbol(symbol: string, specifier: string): boolean { return true; } + shouldImportSymbol(symbol: string, specifier: string): boolean { + return true; + } rewriteSymbol(symbol: string, specifier: string): string { if (specifier !== CORE_MODULE) { @@ -89,8 +97,8 @@ export class R3SymbolsImportRewriter implements ImportRewriter { const relativePathToR3Symbols = relativePathBetween(inContextOfFile, this.r3SymbolsPath); if (relativePathToR3Symbols === null) { - throw new Error( - `Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${this.r3SymbolsPath}`); + throw new Error(`Failed to rewrite import inside ${CORE_MODULE}: ${inContextOfFile} -> ${ + this.r3SymbolsPath}`); } return relativePathToR3Symbols; @@ -101,5 +109,5 @@ export function validateAndRewriteCoreSymbol(name: string): string { if (!CORE_SUPPORTED_SYMBOLS.has(name)) { throw new Error(`Importing unexpected symbol ${name} while compiling ${CORE_MODULE}`); } - return CORE_SUPPORTED_SYMBOLS.get(name) !; + return CORE_SUPPORTED_SYMBOLS.get(name)!; } diff --git a/packages/compiler-cli/src/ngtsc/imports/src/default.ts b/packages/compiler-cli/src/ngtsc/imports/src/default.ts index aa36af2eb78c8..ae92d05eb6fd2 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/default.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/default.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import * as ts from 'typescript'; @@ -96,7 +96,7 @@ export class DefaultImportTracker implements DefaultImportRecorder { if (!this.sourceFileToImportMap.has(sf)) { this.sourceFileToImportMap.set(sf, new Map<ts.Identifier, ts.ImportDeclaration>()); } - this.sourceFileToImportMap.get(sf) !.set(id, decl); + this.sourceFileToImportMap.get(sf)!.set(id, decl); } recordUsedIdentifier(id: ts.Identifier): void { @@ -105,18 +105,18 @@ export class DefaultImportTracker implements DefaultImportRecorder { // The identifier's source file has no registered default imports at all. return; } - const identiferToDeclaration = this.sourceFileToImportMap.get(sf) !; + const identiferToDeclaration = this.sourceFileToImportMap.get(sf)!; if (!identiferToDeclaration.has(id)) { // The identifier isn't from a registered default import. return; } - const decl = identiferToDeclaration.get(id) !; + const decl = identiferToDeclaration.get(id)!; // Add the default import declaration to the set of used import declarations for the file. if (!this.sourceFileToUsedImports.has(sf)) { this.sourceFileToUsedImports.set(sf, new Set<ts.ImportDeclaration>()); } - this.sourceFileToUsedImports.get(sf) !.add(decl); + this.sourceFileToUsedImports.get(sf)!.add(decl); } /** @@ -127,7 +127,9 @@ export class DefaultImportTracker implements DefaultImportRecorder { */ importPreservingTransformer(): ts.TransformerFactory<ts.SourceFile> { return (context: ts.TransformationContext) => { - return (sf: ts.SourceFile) => { return this.transformSourceFile(sf); }; + return (sf: ts.SourceFile) => { + return this.transformSourceFile(sf); + }; }; } @@ -142,7 +144,7 @@ export class DefaultImportTracker implements DefaultImportRecorder { } // There are declarations that need to be preserved. - const importsToPreserve = this.sourceFileToUsedImports.get(originalSf) !; + const importsToPreserve = this.sourceFileToUsedImports.get(originalSf)!; // Generate a new statement list which preserves any imports present in `importsToPreserve`. const statements = sf.statements.map(stmt => { diff --git a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts index 6515cf49aa428..23206dcc261fb 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/emitter.ts @@ -9,7 +9,7 @@ import {Expression, ExternalExpr, ExternalReference, WrappedNodeExpr} from '@ang import * as ts from 'typescript'; import {UnifiedModulesHost} from '../../core/api'; -import {LogicalFileSystem, LogicalProjectPath, PathSegment, absoluteFromSourceFile, dirname, relative} from '../../file_system'; +import {absoluteFromSourceFile, dirname, LogicalFileSystem, LogicalProjectPath, PathSegment, relative} from '../../file_system'; import {stripExtension} from '../../file_system/src/util'; import {ReflectionHost} from '../../reflection'; import {getSourceFile, isDeclaration, isTypeDeclaration, nodeNameForError} from '../../util/src/typescript'; @@ -93,8 +93,8 @@ export class ReferenceEmitter { return emitted; } } - throw new Error( - `Unable to write a reference to ${nodeNameForError(ref.node)} in ${ref.node.getSourceFile().fileName} from ${context.fileName}`); + throw new Error(`Unable to write a reference to ${nodeNameForError(ref.node)} in ${ + ref.node.getSourceFile().fileName} from ${context.fileName}`); } } @@ -149,11 +149,11 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { return null; } else if (!isDeclaration(ref.node)) { // It's not possible to import something which isn't a declaration. - throw new Error( - `Debug assert: unable to import a Reference to non-declaration of type ${ts.SyntaxKind[ref.node.kind]}.`); + throw new Error(`Debug assert: unable to import a Reference to non-declaration of type ${ + ts.SyntaxKind[ref.node.kind]}.`); } else if ((importFlags & ImportFlags.AllowTypeImports) === 0 && isTypeDeclaration(ref.node)) { - throw new Error( - `Importing a type-only declaration of type ${ts.SyntaxKind[ref.node.kind]} in a value position is not allowed.`); + throw new Error(`Importing a type-only declaration of type ${ + ts.SyntaxKind[ref.node.kind]} in a value position is not allowed.`); } // Try to find the exported name of the declaration, if one is available. @@ -162,8 +162,9 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { if (symbolName === null) { // TODO(alxhub): make this error a ts.Diagnostic pointing at whatever caused this import to be // triggered. - throw new Error( - `Symbol ${ref.debugName} declared in ${getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${context.fileName})`); + throw new Error(`Symbol ${ref.debugName} declared in ${ + getSourceFile(ref.node).fileName} is not exported from ${specifier} (import into ${ + context.fileName})`); } return new ExternalExpr(new ExternalReference(specifier, symbolName)); @@ -173,7 +174,7 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { |null { const exports = this.getExportsOfModule(moduleName, fromFile); if (exports !== null && exports.has(target)) { - return exports.get(target) !; + return exports.get(target)!; } else { return null; } @@ -184,7 +185,7 @@ export class AbsoluteModuleStrategy implements ReferenceEmitStrategy { if (!this.moduleExportsCache.has(moduleName)) { this.moduleExportsCache.set(moduleName, this.enumerateExportsOfModule(moduleName, fromFile)); } - return this.moduleExportsCache.get(moduleName) !; + return this.moduleExportsCache.get(moduleName)!; } protected enumerateExportsOfModule(specifier: string, fromFile: string): diff --git a/packages/compiler-cli/src/ngtsc/imports/src/references.ts b/packages/compiler-cli/src/ngtsc/imports/src/references.ts index 8b1df442ccd24..f6150394b3dd3 100644 --- a/packages/compiler-cli/src/ngtsc/imports/src/references.ts +++ b/packages/compiler-cli/src/ngtsc/imports/src/references.ts @@ -80,7 +80,9 @@ export class Reference<T extends ts.Node = ts.Node> { * * See `bestGuessOwningModule`. */ - get hasOwningModuleGuess(): boolean { return this.bestGuessOwningModule !== null; } + get hasOwningModuleGuess(): boolean { + return this.bestGuessOwningModule !== null; + } /** * A name for the node, if one is available. @@ -93,14 +95,18 @@ export class Reference<T extends ts.Node = ts.Node> { return id !== null ? id.text : null; } - get alias(): Expression|null { return this._alias; } + get alias(): Expression|null { + return this._alias; + } /** * Record a `ts.Identifier` by which it's valid to refer to this node, within the context of this * `Reference`. */ - addIdentifier(identifier: ts.Identifier): void { this.identifiers.push(identifier); } + addIdentifier(identifier: ts.Identifier): void { + this.identifiers.push(identifier); + } /** * Get a `ts.Identifier` within this `Reference` that can be used to refer within the context of a diff --git a/packages/compiler-cli/src/ngtsc/imports/test/default_spec.ts b/packages/compiler-cli/src/ngtsc/imports/test/default_spec.ts index defa93505a1a1..8cfc4bd1c7667 100644 --- a/packages/compiler-cli/src/ngtsc/imports/test/default_spec.ts +++ b/packages/compiler-cli/src/ngtsc/imports/test/default_spec.ts @@ -39,7 +39,7 @@ runInEachFileSystem(() => { module: ts.ModuleKind.ES2015, }); const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause); - const fooId = fooClause.name !; + const fooId = fooClause.name!; const fooDecl = fooClause.parent; const tracker = new DefaultImportTracker(); @@ -48,7 +48,7 @@ runInEachFileSystem(() => { program.emit(undefined, undefined, undefined, undefined, { before: [tracker.importPreservingTransformer()], }); - const testContents = host.readFile('/test.js') !; + const testContents = host.readFile('/test.js')!; expect(testContents).toContain(`import Foo from './dep';`); // The control should have the import elided. @@ -69,7 +69,7 @@ runInEachFileSystem(() => { module: ts.ModuleKind.CommonJS, }); const fooClause = getDeclaration(program, _('/test.ts'), 'Foo', ts.isImportClause); - const fooId = ts.updateIdentifier(fooClause.name !); + const fooId = ts.updateIdentifier(fooClause.name!); const fooDecl = fooClause.parent; const tracker = new DefaultImportTracker(); @@ -81,7 +81,7 @@ runInEachFileSystem(() => { tracker.importPreservingTransformer(), ], }); - const testContents = host.readFile('/test.js') !; + const testContents = host.readFile('/test.js')!; expect(testContents).toContain(`var dep_1 = require("./dep");`); expect(testContents).toContain(`var ref = dep_1["default"];`); }); diff --git a/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts b/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts index 567c6143fad95..eb6bc7ac53b1a 100644 --- a/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts +++ b/packages/compiler-cli/src/ngtsc/imports/test/emitter_spec.ts @@ -8,8 +8,8 @@ import {ExternalExpr} from '@angular/compiler'; import * as ts from 'typescript'; -import {LogicalFileSystem, absoluteFrom as _} from '../../file_system'; -import {TestFile, runInEachFileSystem} from '../../file_system/testing'; +import {absoluteFrom as _, LogicalFileSystem} from '../../file_system'; +import {runInEachFileSystem, TestFile} from '../../file_system/testing'; import {Declaration, TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; import {AbsoluteModuleStrategy, ImportFlags, LogicalProjectStrategy} from '../src/emitter'; @@ -42,7 +42,7 @@ runInEachFileSystem(() => { ]); const decl = getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration); - const context = program.getSourceFile(_('/context.ts')) !; + const context = program.getSourceFile(_('/context.ts'))!; const reference = new Reference(decl); const emitted = strategy.emit(reference, context, ImportFlags.None); @@ -65,7 +65,7 @@ runInEachFileSystem(() => { ]); const decl = getDeclaration(program, _('/node_modules/external.d.ts'), 'Foo', ts.isClassDeclaration); - const context = program.getSourceFile(_('/context.ts')) !; + const context = program.getSourceFile(_('/context.ts'))!; const reference = new Reference(decl, { specifier: 'external', @@ -92,7 +92,7 @@ runInEachFileSystem(() => { ]); const decl = getDeclaration( program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration); - const context = program.getSourceFile(_('/context.ts')) !; + const context = program.getSourceFile(_('/context.ts'))!; const reference = new Reference(decl, { specifier: 'external', @@ -116,7 +116,7 @@ runInEachFileSystem(() => { ]); const decl = getDeclaration( program, _('/node_modules/external.d.ts'), 'Foo', ts.isInterfaceDeclaration); - const context = program.getSourceFile(_('/context.ts')) !; + const context = program.getSourceFile(_('/context.ts'))!; const reference = new Reference(decl, {specifier: 'external', resolutionContext: context.fileName}); @@ -139,7 +139,9 @@ runInEachFileSystem(() => { return null; } const fakeExports = new Map<string, Declaration>(); - realExports.forEach((decl, name) => { fakeExports.set(`test${name}`, decl); }); + realExports.forEach((decl, name) => { + fakeExports.set(`test${name}`, decl); + }); return fakeExports; } } @@ -158,12 +160,12 @@ runInEachFileSystem(() => { const logicalFs = new LogicalFileSystem([_('/')]); const strategy = new LogicalProjectStrategy(new TestHost(checker), logicalFs); const decl = getDeclaration(program, _('/index.ts'), 'Foo', ts.isClassDeclaration); - const context = program.getSourceFile(_('/context.ts')) !; + const context = program.getSourceFile(_('/context.ts'))!; const ref = strategy.emit(new Reference(decl), context); expect(ref).not.toBeNull(); // Expect the prefixed name from the TestHost. - expect((ref !as ExternalExpr).value.name).toEqual('testFoo'); + expect((ref! as ExternalExpr).value.name).toEqual('testFoo'); }); }); }); diff --git a/packages/compiler-cli/src/ngtsc/incremental/api.ts b/packages/compiler-cli/src/ngtsc/incremental/api.ts index e987cd59ec0c6..41c3f61bbf67c 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/api.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/api.ts @@ -25,7 +25,7 @@ export interface IncrementalBuild<W> { /** * Tracks dependencies between source files or resources in the application. */ -export interface DependencyTracker<T extends{fileName: string} = ts.SourceFile> { +export interface DependencyTracker<T extends {fileName: string} = ts.SourceFile> { /** * Record that the file `from` depends on the file `on`. */ diff --git a/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts b/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts index fdd2f8ce1ca77..0c42a13824fe2 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/src/dependency_tracking.ts @@ -23,11 +23,13 @@ import {DependencyTracker} from '../api'; * 2. One of its dependencies has physically changed. * 3. One of its resource dependencies has physically changed. */ -export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> implements +export class FileDependencyGraph<T extends {fileName: string} = ts.SourceFile> implements DependencyTracker<T> { private nodes = new Map<T, FileNode>(); - addDependency(from: T, on: T): void { this.nodeFor(from).dependsOn.add(on.fileName); } + addDependency(from: T, on: T): void { + this.nodeFor(from).dependsOn.add(on.fileName); + } addResourceDependency(from: T, resource: AbsoluteFsPath): void { this.nodeFor(from).usesResources.add(resource); @@ -103,7 +105,7 @@ export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> im usesResources: new Set<AbsoluteFsPath>(), }); } - return this.nodes.get(sf) !; + return this.nodes.get(sf)!; } } @@ -111,7 +113,7 @@ export class FileDependencyGraph<T extends{fileName: string} = ts.SourceFile> im * Determine whether `sf` has logically changed, given its dependencies and the set of physically * changed files and resources. */ -function isLogicallyChanged<T extends{fileName: string}>( +function isLogicallyChanged<T extends {fileName: string}>( sf: T, node: FileNode, changedTsPaths: ReadonlySet<string>, deletedTsPaths: ReadonlySet<string>, changedResources: ReadonlySet<AbsoluteFsPath>): boolean { // A file is logically changed if it has physically changed itself (including being deleted). diff --git a/packages/compiler-cli/src/ngtsc/incremental/src/state.ts b/packages/compiler-cli/src/ngtsc/incremental/src/state.ts index 21f3ef680b366..f2497cbb87dab 100644 --- a/packages/compiler-cli/src/ngtsc/incremental/src/state.ts +++ b/packages/compiler-cli/src/ngtsc/incremental/src/state.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom} from '../../file_system'; +import {absoluteFrom, AbsoluteFsPath} from '../../file_system'; import {ClassRecord, TraitCompiler} from '../../transform'; import {IncrementalBuild} from '../api'; @@ -194,9 +194,13 @@ export class IncrementalDriver implements IncrementalBuild<ClassRecord> { }; } - recordSuccessfulEmit(sf: ts.SourceFile): void { this.state.pendingEmit.delete(sf.fileName); } + recordSuccessfulEmit(sf: ts.SourceFile): void { + this.state.pendingEmit.delete(sf.fileName); + } - safeToSkipEmit(sf: ts.SourceFile): boolean { return !this.state.pendingEmit.has(sf.fileName); } + safeToSkipEmit(sf: ts.SourceFile): boolean { + return !this.state.pendingEmit.has(sf.fileName); + } priorWorkFor(sf: ts.SourceFile): ClassRecord[]|null { if (this.state.lastGood === null || this.logicalChanges === null) { @@ -212,7 +216,7 @@ export class IncrementalDriver implements IncrementalBuild<ClassRecord> { } } -type BuildState = PendingBuildState | AnalyzedBuildState; +type BuildState = PendingBuildState|AnalyzedBuildState; enum BuildStateKind { Pending, diff --git a/packages/compiler-cli/src/ngtsc/indexer/src/api.ts b/packages/compiler-cli/src/ngtsc/indexer/src/api.ts index 2f6095d499216..0227717709c31 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/src/api.ts @@ -43,13 +43,19 @@ interface ExpressionIdentifier extends TemplateIdentifier { } /** Describes a property accessed in a template. */ -export interface PropertyIdentifier extends ExpressionIdentifier { kind: IdentifierKind.Property; } +export interface PropertyIdentifier extends ExpressionIdentifier { + kind: IdentifierKind.Property; +} /** Describes a method accessed in a template. */ -export interface MethodIdentifier extends ExpressionIdentifier { kind: IdentifierKind.Method; } +export interface MethodIdentifier extends ExpressionIdentifier { + kind: IdentifierKind.Method; +} /** Describes an element attribute in a template. */ -export interface AttributeIdentifier extends TemplateIdentifier { kind: IdentifierKind.Attribute; } +export interface AttributeIdentifier extends TemplateIdentifier { + kind: IdentifierKind.Attribute; +} /** A reference to a directive node and its selector. */ interface DirectiveReference { @@ -85,7 +91,7 @@ export interface ReferenceIdentifier extends TemplateIdentifier { /** The target of this reference. If the target is not known, this is `null`. */ target: { /** The template AST node that the reference targets. */ - node: ElementIdentifier | TemplateIdentifier; + node: ElementIdentifier|TemplateIdentifier; /** * The directive on `node` that the reference targets. If no directive is targeted, this is @@ -96,14 +102,16 @@ export interface ReferenceIdentifier extends TemplateIdentifier { } /** Describes a template variable like "foo" in `<div *ngFor="let foo of foos"></div>`. */ -export interface VariableIdentifier extends TemplateIdentifier { kind: IdentifierKind.Variable; } +export interface VariableIdentifier extends TemplateIdentifier { + kind: IdentifierKind.Variable; +} /** * Identifiers recorded at the top level of the template, without any context about the HTML nodes * they were discovered in. */ -export type TopLevelIdentifier = PropertyIdentifier | MethodIdentifier | ElementIdentifier | - TemplateNodeIdentifier | ReferenceIdentifier | VariableIdentifier; +export type TopLevelIdentifier = PropertyIdentifier|MethodIdentifier|ElementIdentifier| + TemplateNodeIdentifier|ReferenceIdentifier|VariableIdentifier; /** * Describes the absolute byte offsets of a text anchor in a source code. diff --git a/packages/compiler-cli/src/ngtsc/indexer/src/context.ts b/packages/compiler-cli/src/ngtsc/indexer/src/context.ts index 1881ec01f0ce4..c4c5801c65fc4 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/src/context.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/src/context.ts @@ -56,5 +56,7 @@ export class IndexingContext { /** * Adds a component to the context. */ - addComponent(info: ComponentInfo) { this.components.add(info); } + addComponent(info: ComponentInfo) { + this.components.add(info); + } } diff --git a/packages/compiler-cli/src/ngtsc/indexer/src/template.ts b/packages/compiler-cli/src/ngtsc/indexer/src/template.ts index 84d32411e983b..f0b2eacf187f5 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/src/template.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/src/template.ts @@ -18,9 +18,9 @@ interface HTMLNode extends TmplAstNode { name?: string; } -type ExpressionIdentifier = PropertyIdentifier | MethodIdentifier; -type TmplTarget = TmplAstReference | TmplAstVariable; -type TargetIdentifier = ReferenceIdentifier | VariableIdentifier; +type ExpressionIdentifier = PropertyIdentifier|MethodIdentifier; +type TmplTarget = TmplAstReference|TmplAstVariable; +type TargetIdentifier = ReferenceIdentifier|VariableIdentifier; type TargetIdentifierMap = Map<TmplTarget, TargetIdentifier>; /** @@ -62,7 +62,9 @@ class ExpressionVisitor extends RecursiveAstVisitor { return visitor.identifiers; } - visit(ast: AST) { ast.visit(this); } + visit(ast: AST) { + ast.visit(this); + } visitMethodCall(ast: MethodCall, context: {}) { this.visitIdentifier(ast, IdentifierKind.Method); @@ -144,16 +146,22 @@ class TemplateVisitor extends TmplAstRecursiveVisitor { * * @param boundTemplate bound template target */ - constructor(private boundTemplate: BoundTarget<ComponentMeta>) { super(); } + constructor(private boundTemplate: BoundTarget<ComponentMeta>) { + super(); + } /** * Visits a node in the template. * * @param node node to visit */ - visit(node: HTMLNode) { node.visit(this); } + visit(node: HTMLNode) { + node.visit(this); + } - visitAll(nodes: TmplAstNode[]) { nodes.forEach(node => this.visit(node)); } + visitAll(nodes: TmplAstNode[]) { + nodes.forEach(node => this.visit(node)); + } /** * Add an identifier for an HTML element and visit its children recursively. @@ -204,8 +212,12 @@ class TemplateVisitor extends TmplAstRecursiveVisitor { this.targetToIdentifier.bind(this)); identifiers.forEach(id => this.identifiers.add(id)); } - visitBoundEvent(attribute: TmplAstBoundEvent) { this.visitExpression(attribute.handler); } - visitBoundText(text: TmplAstBoundText) { this.visitExpression(text.value); } + visitBoundEvent(attribute: TmplAstBoundEvent) { + this.visitExpression(attribute.handler); + } + visitBoundText(text: TmplAstBoundText) { + this.visitExpression(text.value); + } visitReference(reference: TmplAstReference) { const referenceIdentifer = this.targetToIdentifier(reference); @@ -222,7 +234,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor { |TemplateNodeIdentifier { // If this node has already been seen, return the cached result. if (this.elementAndTemplateIdentifierCache.has(node)) { - return this.elementAndTemplateIdentifierCache.get(node) !; + return this.elementAndTemplateIdentifierCache.get(node)!; } let name: string; @@ -254,7 +266,8 @@ class TemplateVisitor extends TmplAstRecursiveVisitor { const identifier = { name, - span: absoluteSpan, kind, + span: absoluteSpan, + kind, attributes: new Set(attributes), usedDirectives: new Set(usedDirectives.map(dir => { return { @@ -274,7 +287,7 @@ class TemplateVisitor extends TmplAstRecursiveVisitor { private targetToIdentifier(node: TmplAstReference|TmplAstVariable): TargetIdentifier { // If this node has already been seen, return the cached result. if (this.targetIdentifierCache.has(node)) { - return this.targetIdentifierCache.get(node) !; + return this.targetIdentifierCache.get(node)!; } const {name, sourceSpan} = node; @@ -304,7 +317,8 @@ class TemplateVisitor extends TmplAstRecursiveVisitor { identifier = { name, span, - kind: IdentifierKind.Reference, target, + kind: IdentifierKind.Reference, + target, }; } else { identifier = { diff --git a/packages/compiler-cli/src/ngtsc/indexer/test/context_spec.ts b/packages/compiler-cli/src/ngtsc/indexer/test/context_spec.ts index 070234844b88c..b95fb7502ce59 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/test/context_spec.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/test/context_spec.ts @@ -19,7 +19,8 @@ runInEachFileSystem(() => { context.addComponent({ declaration, - selector: 'c-selector', boundTemplate, + selector: 'c-selector', + boundTemplate, templateMeta: { isInline: false, file: new ParseSourceFile('<div></div>', util.getTestFilePath()), @@ -29,7 +30,8 @@ runInEachFileSystem(() => { expect(context.components).toEqual(new Set([ { declaration, - selector: 'c-selector', boundTemplate, + selector: 'c-selector', + boundTemplate, templateMeta: { isInline: false, file: new ParseSourceFile('<div></div>', util.getTestFilePath()), diff --git a/packages/compiler-cli/src/ngtsc/indexer/test/template_spec.ts b/packages/compiler-cli/src/ngtsc/indexer/test/template_spec.ts index 831de6640fbe2..0f7b7e7aeb5cd 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/test/template_spec.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/test/template_spec.ts @@ -219,11 +219,11 @@ runInEachFileSystem(() => { const refArr = Array.from(refs); expect(refArr).toEqual(jasmine.arrayContaining([{ - name: 'foo', - kind: IdentifierKind.Property, - span: new AbsoluteSourceSpan(20, 23), - target: null, - }] as TopLevelIdentifier[])); + name: 'foo', + kind: IdentifierKind.Property, + span: new AbsoluteSourceSpan(20, 23), + target: null, + }] as TopLevelIdentifier[])); }); it('should ignore property writes that are not implicitly received by the template', () => { @@ -314,12 +314,13 @@ runInEachFileSystem(() => { }; const refArray = Array.from(refs); - expect(refArray).toEqual(jasmine.arrayContaining([{ - name: 'foo', - kind: IdentifierKind.Reference, - span: new AbsoluteSourceSpan(6, 9), - target: {node: elementReference, directive: null}, - }] as TopLevelIdentifier[])); + expect(refArray).toEqual( + jasmine.arrayContaining([{ + name: 'foo', + kind: IdentifierKind.Reference, + span: new AbsoluteSourceSpan(6, 9), + target: {node: elementReference, directive: null}, + }] as TopLevelIdentifier[])); }); it('should discover nested references', () => { @@ -334,12 +335,13 @@ runInEachFileSystem(() => { }; const refArray = Array.from(refs); - expect(refArray).toEqual(jasmine.arrayContaining([{ - name: 'foo', - kind: IdentifierKind.Reference, - span: new AbsoluteSourceSpan(12, 15), - target: {node: elementReference, directive: null}, - }] as TopLevelIdentifier[])); + expect(refArray).toEqual( + jasmine.arrayContaining([{ + name: 'foo', + kind: IdentifierKind.Reference, + span: new AbsoluteSourceSpan(12, 15), + target: {node: elementReference, directive: null}, + }] as TopLevelIdentifier[])); }); it('should discover references to references', () => { @@ -409,14 +411,14 @@ runInEachFileSystem(() => { const refArr = Array.from(refs); let fooRef = refArr.find(id => id.name === 'foo'); expect(fooRef).toBeDefined(); - expect(fooRef !.kind).toBe(IdentifierKind.Reference); + expect(fooRef!.kind).toBe(IdentifierKind.Reference); fooRef = fooRef as ReferenceIdentifier; expect(fooRef.target).toBeDefined(); - expect(fooRef.target !.node.kind).toBe(IdentifierKind.Element); - expect(fooRef.target !.node.name).toBe('div'); - expect(fooRef.target !.node.span).toEqual(new AbsoluteSourceSpan(1, 4)); - expect(fooRef.target !.directive).toEqual(declB); + expect(fooRef.target!.node.kind).toBe(IdentifierKind.Element); + expect(fooRef.target!.node.name).toBe('div'); + expect(fooRef.target!.node.span).toEqual(new AbsoluteSourceSpan(1, 4)); + expect(fooRef.target!.directive).toEqual(declB); }); it('should discover references to references', () => { @@ -455,10 +457,10 @@ runInEachFileSystem(() => { const refArray = Array.from(refs); expect(refArray).toEqual(jasmine.arrayContaining([{ - name: 'foo', - kind: IdentifierKind.Variable, - span: new AbsoluteSourceSpan(17, 20), - }] as TopLevelIdentifier[])); + name: 'foo', + kind: IdentifierKind.Variable, + span: new AbsoluteSourceSpan(17, 20), + }] as TopLevelIdentifier[])); }); it('should discover variables with let- syntax', () => { @@ -467,10 +469,10 @@ runInEachFileSystem(() => { const refArray = Array.from(refs); expect(refArray).toEqual(jasmine.arrayContaining([{ - name: 'var', - kind: IdentifierKind.Variable, - span: new AbsoluteSourceSpan(17, 20), - }] as TopLevelIdentifier[])); + name: 'var', + kind: IdentifierKind.Variable, + span: new AbsoluteSourceSpan(17, 20), + }] as TopLevelIdentifier[])); }); it('should discover nested variables', () => { @@ -479,10 +481,10 @@ runInEachFileSystem(() => { const refArray = Array.from(refs); expect(refArray).toEqual(jasmine.arrayContaining([{ - name: 'foo', - kind: IdentifierKind.Variable, - span: new AbsoluteSourceSpan(23, 26), - }] as TopLevelIdentifier[])); + name: 'foo', + kind: IdentifierKind.Variable, + span: new AbsoluteSourceSpan(23, 26), + }] as TopLevelIdentifier[])); }); it('should discover references to variables', () => { diff --git a/packages/compiler-cli/src/ngtsc/indexer/test/transform_spec.ts b/packages/compiler-cli/src/ngtsc/indexer/test/transform_spec.ts index e77763f7c7d71..8dac5ec4b5b3e 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/test/transform_spec.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/test/transform_spec.ts @@ -68,7 +68,7 @@ runInEachFileSystem(() => { const info = analysis.get(decl); expect(info).toBeDefined(); - expect(info !.template.file) + expect(info!.template.file) .toEqual(new ParseSourceFile('class C {}', util.getTestFilePath())); }); @@ -83,7 +83,7 @@ runInEachFileSystem(() => { const info = analysis.get(decl); expect(info).toBeDefined(); - expect(info !.template.file) + expect(info!.template.file) .toEqual(new ParseSourceFile('<div>{{foo}}</div>', util.getTestFilePath())); }); @@ -110,11 +110,11 @@ runInEachFileSystem(() => { const infoA = analysis.get(declA); expect(infoA).toBeDefined(); - expect(infoA !.template.usedComponents).toEqual(new Set([declB])); + expect(infoA!.template.usedComponents).toEqual(new Set([declB])); const infoB = analysis.get(declB); expect(infoB).toBeDefined(); - expect(infoB !.template.usedComponents).toEqual(new Set([declA])); + expect(infoB!.template.usedComponents).toEqual(new Set([declA])); }); }); }); diff --git a/packages/compiler-cli/src/ngtsc/indexer/test/util.ts b/packages/compiler-cli/src/ngtsc/indexer/test/util.ts index 55bf78fb19488..67b200f39fe33 100644 --- a/packages/compiler-cli/src/ngtsc/indexer/test/util.ts +++ b/packages/compiler-cli/src/ngtsc/indexer/test/util.ts @@ -6,9 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {BoundTarget, CssSelector, ParseTemplateOptions, R3TargetBinder, SelectorMatcher, parseTemplate} from '@angular/compiler'; +import {BoundTarget, CssSelector, parseTemplate, ParseTemplateOptions, R3TargetBinder, SelectorMatcher} from '@angular/compiler'; import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom} from '../../file_system'; + +import {absoluteFrom, AbsoluteFsPath} from '../../file_system'; import {Reference} from '../../imports'; import {ClassDeclaration} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts b/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts index 9e85145fd9d7c..1f72300077d44 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/dts.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {Reference} from '../../imports'; -import {ClassDeclaration, ReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {ClassDeclaration, isNamedClassDeclaration, ReflectionHost} from '../../reflection'; import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta} from './api'; import {extractDirectiveGuards, extractReferencesFromType, readStringArrayType, readStringMapType, readStringType} from './util'; diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts b/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts index c6265188d153b..86d5f9588b445 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts @@ -25,7 +25,7 @@ export function flattenInheritedDirectiveMetadata( throw new Error(`Metadata not found for directive: ${dir.debugName}`); } - let inputs: {[key: string]: string | [string, string]} = {}; + let inputs: {[key: string]: string|[string, string]} = {}; let outputs: {[key: string]: string} = {}; let coercedInputFields = new Set<string>(); let isDynamic = false; diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/registry.ts b/packages/compiler-cli/src/ngtsc/metadata/src/registry.ts index b1bd7a5ffb533..585af36c7bbf7 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/registry.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/registry.ts @@ -22,18 +22,24 @@ export class LocalMetadataRegistry implements MetadataRegistry, MetadataReader { private pipes = new Map<ClassDeclaration, PipeMeta>(); getDirectiveMetadata(ref: Reference<ClassDeclaration>): DirectiveMeta|null { - return this.directives.has(ref.node) ? this.directives.get(ref.node) ! : null; + return this.directives.has(ref.node) ? this.directives.get(ref.node)! : null; } getNgModuleMetadata(ref: Reference<ClassDeclaration>): NgModuleMeta|null { - return this.ngModules.has(ref.node) ? this.ngModules.get(ref.node) ! : null; + return this.ngModules.has(ref.node) ? this.ngModules.get(ref.node)! : null; } getPipeMetadata(ref: Reference<ClassDeclaration>): PipeMeta|null { - return this.pipes.has(ref.node) ? this.pipes.get(ref.node) ! : null; + return this.pipes.has(ref.node) ? this.pipes.get(ref.node)! : null; } - registerDirectiveMetadata(meta: DirectiveMeta): void { this.directives.set(meta.ref.node, meta); } - registerNgModuleMetadata(meta: NgModuleMeta): void { this.ngModules.set(meta.ref.node, meta); } - registerPipeMetadata(meta: PipeMeta): void { this.pipes.set(meta.ref.node, meta); } + registerDirectiveMetadata(meta: DirectiveMeta): void { + this.directives.set(meta.ref.node, meta); + } + registerNgModuleMetadata(meta: NgModuleMeta): void { + this.ngModules.set(meta.ref.node, meta); + } + registerPipeMetadata(meta: PipeMeta): void { + this.pipes.set(meta.ref.node, meta); + } } /** @@ -70,7 +76,9 @@ export class InjectableClassRegistry { constructor(private host: ReflectionHost) {} - registerInjectable(declaration: ClassDeclaration): void { this.classes.add(declaration); } + registerInjectable(declaration: ClassDeclaration): void { + this.classes.add(declaration); + } isInjectable(declaration: ClassDeclaration): boolean { // Figure out whether the class is injectable based on the registered classes, otherwise diff --git a/packages/compiler-cli/src/ngtsc/metadata/src/util.ts b/packages/compiler-cli/src/ngtsc/metadata/src/util.ts index 48b6a3a4a9423..c3fc520dd27d3 100644 --- a/packages/compiler-cli/src/ngtsc/metadata/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/metadata/src/util.ts @@ -9,13 +9,13 @@ import * as ts from 'typescript'; import {Reference} from '../../imports'; -import {ClassDeclaration, ClassMember, ClassMemberKind, ReflectionHost, isNamedClassDeclaration, reflectTypeEntityToDeclaration} from '../../reflection'; +import {ClassDeclaration, ClassMember, ClassMemberKind, isNamedClassDeclaration, ReflectionHost, reflectTypeEntityToDeclaration} from '../../reflection'; import {nodeDebugInfo} from '../../util/src/typescript'; import {DirectiveMeta, MetadataReader, NgModuleMeta, PipeMeta, TemplateGuardMeta} from './api'; export function extractReferencesFromType( - checker: ts.TypeChecker, def: ts.TypeNode, ngModuleImportedFrom: string | null, + checker: ts.TypeChecker, def: ts.TypeNode, ngModuleImportedFrom: string|null, resolutionContext: string): Reference<ClassDeclaration>[] { if (!ts.isTupleTypeNode(def)) { return []; @@ -122,7 +122,7 @@ function extractTemplateGuard(member: ClassMember): TemplateGuardMeta|null { function extractCoercedInput(member: ClassMember): string|null { if (member.kind !== ClassMemberKind.Property || !member.name.startsWith('ngAcceptInputType_')) { - return null !; + return null!; } return afterUnderscore(member.name); } diff --git a/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts b/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts index 137151ed5bccc..52320a87932ca 100644 --- a/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts +++ b/packages/compiler-cli/src/ngtsc/modulewithproviders/src/scanner.ts @@ -13,7 +13,9 @@ import {ImportFlags, Reference, ReferenceEmitter} from '../../imports'; import {PartialEvaluator, ResolvedValueMap} from '../../partial_evaluator'; import {ReflectionHost} from '../../reflection'; -export interface DtsHandler { addTypeReplacement(node: ts.Declaration, type: Type): void; } +export interface DtsHandler { + addTypeReplacement(node: ts.Declaration, type: Type): void; +} export class ModuleWithProvidersScanner { constructor( diff --git a/packages/compiler-cli/src/ngtsc/perf/src/noop.ts b/packages/compiler-cli/src/ngtsc/perf/src/noop.ts index 01e4c9c68063f..8cd7c799c53b3 100644 --- a/packages/compiler-cli/src/ngtsc/perf/src/noop.ts +++ b/packages/compiler-cli/src/ngtsc/perf/src/noop.ts @@ -12,9 +12,11 @@ import {PerfRecorder} from './api'; export const NOOP_PERF_RECORDER: PerfRecorder = { enabled: false, - mark: (name: string, node: ts.SourceFile | ts.Declaration, category?: string, detail?: string): - void => {}, - start: (name: string, node: ts.SourceFile | ts.Declaration, category?: string, detail?: string): - number => { return 0;}, - stop: (span: number | false): void => {}, + mark: (name: string, node: ts.SourceFile|ts.Declaration, category?: string, detail?: string): + void => {}, + start: (name: string, node: ts.SourceFile|ts.Declaration, category?: string, detail?: string): + number => { + return 0; + }, + stop: (span: number|false): void => {}, }; diff --git a/packages/compiler-cli/src/ngtsc/perf/src/tracking.ts b/packages/compiler-cli/src/ngtsc/perf/src/tracking.ts index 0eb6251b91077..80c4a8d32dc1c 100644 --- a/packages/compiler-cli/src/ngtsc/perf/src/tracking.ts +++ b/packages/compiler-cli/src/ngtsc/perf/src/tracking.ts @@ -20,7 +20,9 @@ export class PerfTracker implements PerfRecorder { private constructor(private zeroTime: HrTime) {} - static zeroedToNow(): PerfTracker { return new PerfTracker(mark()); } + static zeroedToNow(): PerfTracker { + return new PerfTracker(mark()); + } mark(name: string, node?: ts.SourceFile|ts.Declaration, category?: string, detail?: string): void { @@ -73,7 +75,9 @@ export class PerfTracker implements PerfRecorder { return msg; } - asJson(): unknown { return this.log; } + asJson(): unknown { + return this.log; + } serializeToFile(target: string, host: ts.CompilerHost): void { const json = JSON.stringify(this.log, null, 2); diff --git a/packages/compiler-cli/src/ngtsc/program.ts b/packages/compiler-cli/src/ngtsc/program.ts index 84a3f75397a53..5e250ddc7bd5e 100644 --- a/packages/compiler-cli/src/ngtsc/program.ts +++ b/packages/compiler-cli/src/ngtsc/program.ts @@ -77,7 +77,9 @@ export class NgtscProgram implements api.Program { new NgCompiler(this.host, options, this.tsProgram, reuseProgram, this.perfRecorder); } - getTsProgram(): ts.Program { return this.tsProgram; } + getTsProgram(): ts.Program { + return this.tsProgram; + } getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken| undefined): readonly ts.Diagnostic[] { @@ -137,8 +139,8 @@ export class NgtscProgram implements api.Program { } getNgSemanticDiagnostics( - fileName?: string|undefined, cancellationToken?: ts.CancellationToken| - undefined): readonly(ts.Diagnostic|api.Diagnostic)[] { + fileName?: string|undefined, cancellationToken?: ts.CancellationToken|undefined): + readonly(ts.Diagnostic|api.Diagnostic)[] { let sf: ts.SourceFile|undefined = undefined; if (fileName !== undefined) { sf = this.tsProgram.getSourceFile(fileName); @@ -161,14 +163,17 @@ export class NgtscProgram implements api.Program { * This is used by the Angular CLI to allow for spawning (async) child compilations for things * like SASS files used in `styleUrls`. */ - loadNgStructureAsync(): Promise<void> { return this.compiler.analyzeAsync(); } + loadNgStructureAsync(): Promise<void> { + return this.compiler.analyzeAsync(); + } listLazyRoutes(entryRoute?: string|undefined): api.LazyRoute[] { return this.compiler.listLazyRoutes(entryRoute); } emit(opts?: { - emitFlags?: api.EmitFlags | undefined; cancellationToken?: ts.CancellationToken | undefined; + emitFlags?: api.EmitFlags|undefined; + cancellationToken?: ts.CancellationToken | undefined; customTransformers?: api.CustomTransformers | undefined; emitCallback?: api.TsEmitCallback | undefined; mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback | undefined; @@ -179,8 +184,8 @@ export class NgtscProgram implements api.Program { const writeFile: ts.WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean, - onError: ((message: string) => void) | undefined, - sourceFiles: ReadonlyArray<ts.SourceFile>| undefined) => { + onError: ((message: string) => void)|undefined, + sourceFiles: ReadonlyArray<ts.SourceFile>|undefined) => { if (sourceFiles !== undefined) { // Record successful writes for any `ts.SourceFile` (that's not a declaration file) // that's an input to this write. @@ -221,7 +226,8 @@ export class NgtscProgram implements api.Program { program: this.tsProgram, host: this.host, options: this.options, - emitOnlyDtsFiles: false, writeFile, + emitOnlyDtsFiles: false, + writeFile, customTransformers: { before: beforeTransforms, after: customTransforms && customTransforms.afterTs, @@ -257,11 +263,16 @@ export class NgtscProgram implements api.Program { } } -const defaultEmitCallback: api.TsEmitCallback = - ({program, targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, - customTransformers}) => - program.emit( - targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); +const defaultEmitCallback: api.TsEmitCallback = ({ + program, + targetSourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers +}) => + program.emit( + targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult { const diagnostics: ts.Diagnostic[] = []; diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/host.ts b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts index 6879769e16255..6a5940d93c997 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts @@ -12,7 +12,7 @@ import * as ts from 'typescript'; * Metadata extracted from an instance of a decorator on another declaration, or synthesized from * other information about a class. */ -export type Decorator = ConcreteDecorator | SyntheticDecorator; +export type Decorator = ConcreteDecorator|SyntheticDecorator; export interface BaseDecorator { /** @@ -28,11 +28,11 @@ export interface BaseDecorator { */ identifier: DecoratorIdentifier|null; - /** - * `Import` by which the decorator was brought into the module in which it was invoked, or `null` - * if the decorator was declared in the same module and not imported. - */ - import : Import | null; +/** + * `Import` by which the decorator was brought into the module in which it was invoked, or `null` + * if the decorator was declared in the same module and not imported. + */ +import: Import|null; /** * TypeScript reference to the decorator itself, or `null` if the decorator is synthesized (e.g. @@ -87,8 +87,8 @@ export const Decorator = { * A decorator is identified by either a simple identifier (e.g. `Decorator`) or, in some cases, * a namespaced property access (e.g. `core.Decorator`). */ -export type DecoratorIdentifier = ts.Identifier | NamespacedIdentifier; -export type NamespacedIdentifier = ts.PropertyAccessExpression & { +export type DecoratorIdentifier = ts.Identifier|NamespacedIdentifier; +export type NamespacedIdentifier = ts.PropertyAccessExpression&{ expression: ts.Identifier; name: ts.Identifier }; @@ -113,7 +113,7 @@ export function isDecoratorIdentifier(exp: ts.Expression): exp is DecoratorIdent * For `ReflectionHost` purposes, a class declaration should always have a `name` identifier, * because we need to be able to reference it in other parts of the program. */ -export type ClassDeclaration<T extends ts.Declaration = ts.Declaration> = T & {name: ts.Identifier}; +export type ClassDeclaration<T extends ts.Declaration = ts.Declaration> = T&{name: ts.Identifier}; /** * An enumeration of possible kinds of class members. @@ -241,8 +241,7 @@ export interface ClassMember { */ export type TypeValueReference = { local: true; expression: ts.Expression; defaultImportStatement: ts.ImportDeclaration | null; -} | -{ +}|{ local: false; name: string; moduleName: string; @@ -447,7 +446,7 @@ export interface InlineDeclaration extends BaseDeclaration { * downlevelings to a `ts.Expression` instead. */ export type Declaration<T extends ts.Declaration = ts.Declaration> = - ConcreteDeclaration<T>| InlineDeclaration; + ConcreteDeclaration<T>|InlineDeclaration; /** * Abstracts reflection operations on a TypeScript AST. diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts b/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts index edcab882ab871..ca930904d0535 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts @@ -18,7 +18,7 @@ import {TypeValueReference} from './host'; * declaration, or if it is not possible to statically understand. */ export function typeToValue( - typeNode: ts.TypeNode | null, checker: ts.TypeChecker): TypeValueReference|null { + typeNode: ts.TypeNode|null, checker: ts.TypeChecker): TypeValueReference|null { // It's not possible to get a value expression if the parameter doesn't even have a type. if (typeNode === null || !ts.isTypeReferenceNode(typeNode)) { return null; @@ -95,7 +95,7 @@ export function typeNodeToValueExpr(node: ts.TypeNode): ts.Expression|null { * give the identifier name within the current file by which the import is known. */ function resolveTypeSymbols(typeRef: ts.TypeReferenceNode, checker: ts.TypeChecker): - {local: ts.Symbol, decl: ts.Symbol, importName: string | null}|null { + {local: ts.Symbol, decl: ts.Symbol, importName: string|null}|null { const typeName = typeRef.typeName; // typeRefSymbol is the ts.Symbol of the entire type reference. const typeRefSymbol: ts.Symbol|undefined = checker.getSymbolAtLocation(typeName); @@ -156,8 +156,8 @@ function isImportSource(node: ts.Declaration): node is(ts.ImportSpecifier | ts.N } function extractModuleAndNameFromImport( - node: ts.ImportSpecifier | ts.NamespaceImport | ts.ImportClause, - localName: string | null): {name: string, moduleName: string} { + node: ts.ImportSpecifier|ts.NamespaceImport|ts.ImportClause, + localName: string|null): {name: string, moduleName: string} { let name: string; let moduleSpecifier: ts.Expression; switch (node.kind) { diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts index c96ae69a09b63..ec66a14014c30 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/typescript.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, ReflectionHost, isDecoratorIdentifier} from './host'; +import {ClassDeclaration, ClassMember, ClassMemberKind, CtorParameter, Declaration, Decorator, FunctionDefinition, Import, isDecoratorIdentifier, ReflectionHost} from './host'; import {typeToValue} from './type_to_value'; /** @@ -76,8 +76,10 @@ export class TypeScriptReflectionHost implements ReflectionHost { return { name, - nameNode: node.name, typeValueReference, - typeNode: originalTypeNode, decorators, + nameNode: node.name, + typeValueReference, + typeNode: originalTypeNode, + decorators, }; }); } @@ -183,11 +185,17 @@ export class TypeScriptReflectionHost implements ReflectionHost { return declaration.initializer || null; } - getDtsDeclaration(_: ts.Declaration): ts.Declaration|null { return null; } + getDtsDeclaration(_: ts.Declaration): ts.Declaration|null { + return null; + } - getInternalNameOfClass(clazz: ClassDeclaration): ts.Identifier { return clazz.name; } + getInternalNameOfClass(clazz: ClassDeclaration): ts.Identifier { + return clazz.name; + } - getAdjacentNameOfClass(clazz: ClassDeclaration): ts.Identifier { return clazz.name; } + getAdjacentNameOfClass(clazz: ClassDeclaration): ts.Identifier { + return clazz.name; + } protected getDirectImportOfIdentifier(id: ts.Identifier): Import|null { const symbol = this.checker.getSymbolAtLocation(id); @@ -305,12 +313,14 @@ export class TypeScriptReflectionHost implements ReflectionHost { if (symbol.valueDeclaration !== undefined) { return { node: symbol.valueDeclaration, - known: null, viaModule, + known: null, + viaModule, }; } else if (symbol.declarations !== undefined && symbol.declarations.length > 0) { return { node: symbol.declarations[0], - known: null, viaModule, + known: null, + viaModule, }; } else { return null; @@ -342,7 +352,9 @@ export class TypeScriptReflectionHost implements ReflectionHost { return { name: decoratorIdentifier.text, identifier: decoratorExpr, - import: importDecl, node, args, + import: importDecl, + node, + args, }; } @@ -382,8 +394,14 @@ export class TypeScriptReflectionHost implements ReflectionHost { return { node, - implementation: node, kind, - type: node.type || null, name, nameNode, decorators, value, isStatic, + implementation: node, + kind, + type: node.type || null, + name, + nameNode, + decorators, + value, + isStatic, }; } } @@ -405,7 +423,7 @@ export function reflectIdentifierOfDeclaration(decl: ts.Declaration): ts.Identif } export function reflectTypeEntityToDeclaration( - type: ts.EntityName, checker: ts.TypeChecker): {node: ts.Declaration, from: string | null} { + type: ts.EntityName, checker: ts.TypeChecker): {node: ts.Declaration, from: string|null} { let realSymbol = checker.getSymbolAtLocation(type); if (realSymbol === undefined) { throw new Error(`Cannot resolve type entity ${type.getText()} to symbol`); @@ -434,8 +452,8 @@ export function reflectTypeEntityToDeclaration( } const decl = symbol.declarations[0]; if (ts.isNamespaceImport(decl)) { - const clause = decl.parent !; - const importDecl = clause.parent !; + const clause = decl.parent!; + const importDecl = clause.parent!; if (!ts.isStringLiteral(importDecl.moduleSpecifier)) { throw new Error(`Module specifier is not a string`); } @@ -552,7 +570,7 @@ function getFarLeftIdentifier(propertyAccess: ts.PropertyAccessExpression): ts.I * `NamespaceImport`. If not return `null`. */ function getContainingImportDeclaration(node: ts.Node): ts.ImportDeclaration|null { - return ts.isImportSpecifier(node) ? node.parent !.parent !.parent ! : + return ts.isImportSpecifier(node) ? node.parent!.parent!.parent! : ts.isNamespaceImport(node) ? node.parent.parent : null; } diff --git a/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts index 9427afb37613a..30eb1c551a235 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts @@ -34,7 +34,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(1); expectParameter(args[0], 'bar', 'Bar'); }); @@ -63,7 +63,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(1); expectParameter(args[0], 'bar', 'Bar', 'dec', './dec'); }); @@ -92,7 +92,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(1); expectParameter(args[0], 'bar', 'Bar', 'dec', './dec'); }); @@ -120,7 +120,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(2); expectParameter(args[0], 'bar', {moduleName: './bar', name: 'Bar'}); expectParameter(args[1], 'otherBar', {moduleName: './bar', name: 'Bar'}); @@ -148,7 +148,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(1); expectParameter(args[0], 'bar', {moduleName: './bar', name: 'Bar'}); }); @@ -175,7 +175,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(1); const param = args[0].typeValueReference; if (param === null || !param.local) { @@ -207,7 +207,7 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(1); expectParameter(args[0], 'bar', {moduleName: './bar', name: 'Bar'}); }); @@ -228,12 +228,11 @@ runInEachFileSystem(() => { const clazz = getDeclaration(program, _('/entry.ts'), 'Foo', isNamedClassDeclaration); const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); - const args = host.getConstructorParameters(clazz) !; + const args = host.getConstructorParameters(clazz)!; expect(args.length).toBe(2); expectParameter(args[0], 'bar', 'Bar'); expectParameter(args[1], 'baz', 'Baz'); }); - }); @@ -330,9 +329,9 @@ runInEachFileSystem(() => { } else if (directTargetDecl === null) { return fail('No declaration found for DirectTarget'); } - expect(targetDecl.node !.getSourceFile().fileName) + expect(targetDecl.node!.getSourceFile().fileName) .toBe(_('/node_modules/absolute/index.ts')); - expect(ts.isClassDeclaration(targetDecl.node !)).toBe(true); + expect(ts.isClassDeclaration(targetDecl.node!)).toBe(true); expect(directTargetDecl.viaModule).toBe('absolute'); expect(directTargetDecl.node).toBe(targetDecl.node); }); @@ -415,9 +414,9 @@ runInEachFileSystem(() => { const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); const exportedDeclarations = - host.getExportsOfModule(program.getSourceFile(_('/entry.ts')) !); - expect(Array.from(exportedDeclarations !.keys())).toEqual(['foo', 'x', 'T', 'I', 'E']); - expect(Array.from(exportedDeclarations !.values()).map(v => v.viaModule)).toEqual([ + host.getExportsOfModule(program.getSourceFile(_('/entry.ts'))!); + expect(Array.from(exportedDeclarations!.keys())).toEqual(['foo', 'x', 'T', 'I', 'E']); + expect(Array.from(exportedDeclarations!.values()).map(v => v.viaModule)).toEqual([ null, null, null, null, null ]); }); @@ -440,11 +439,11 @@ runInEachFileSystem(() => { const checker = program.getTypeChecker(); const host = new TypeScriptReflectionHost(checker); const exportedDeclarations = - host.getExportsOfModule(program.getSourceFile(_('/entry.ts')) !); - expect(Array.from(exportedDeclarations !.keys())).toEqual([ + host.getExportsOfModule(program.getSourceFile(_('/entry.ts'))!); + expect(Array.from(exportedDeclarations!.keys())).toEqual([ 'Target1', 'AliasTarget', 'AliasTarget2', 'Target' ]); - expect(Array.from(exportedDeclarations !.values()).map(v => v.viaModule)).toEqual([ + expect(Array.from(exportedDeclarations!.values()).map(v => v.viaModule)).toEqual([ null, null, null, null ]); }); @@ -452,9 +451,9 @@ runInEachFileSystem(() => { }); function expectParameter( - param: CtorParameter, name: string, type?: string | {name: string, moduleName: string}, + param: CtorParameter, name: string, type?: string|{name: string, moduleName: string}, decorator?: string, decoratorFrom?: string): void { - expect(param.name !).toEqual(name); + expect(param.name!).toEqual(name); if (type === undefined) { expect(param.typeValueReference).toBeNull(); } else { @@ -467,21 +466,21 @@ runInEachFileSystem(() => { expect(param.typeValueReference.moduleName).toEqual(type.moduleName); expect(param.typeValueReference.name).toEqual(type.name); } else { - return fail( - `Mismatch between typeValueReference and expected type: ${param.name} / ${param.typeValueReference.local}`); + return fail(`Mismatch between typeValueReference and expected type: ${param.name} / ${ + param.typeValueReference.local}`); } } if (decorator !== undefined) { expect(param.decorators).not.toBeNull(); - expect(param.decorators !.length).toBeGreaterThan(0); - expect(param.decorators !.some( + expect(param.decorators!.length).toBeGreaterThan(0); + expect(param.decorators!.some( dec => dec.name === decorator && dec.import !== null && dec.import.from === decoratorFrom)) .toBe(true); } } - function argExpressionToString(name: ts.Node | null): string { + function argExpressionToString(name: ts.Node|null): string { if (name == null) { throw new Error('\'name\' argument can\'t be null'); } diff --git a/packages/compiler-cli/src/ngtsc/resource/src/loader.ts b/packages/compiler-cli/src/ngtsc/resource/src/loader.ts index 041b8f0594e40..67a698b534724 100644 --- a/packages/compiler-cli/src/ngtsc/resource/src/loader.ts +++ b/packages/compiler-cli/src/ngtsc/resource/src/loader.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {ResourceLoader} from '../../annotations'; import {ExtendedTsCompilerHost} from '../../core/api'; -import {AbsoluteFsPath, PathSegment, join} from '../../file_system'; +import {AbsoluteFsPath, join, PathSegment} from '../../file_system'; import {getRootDirs} from '../../util/src/typescript'; const CSS_PREPROCESSOR_EXT = /(\.scss|\.sass|\.less|\.styl)$/; @@ -101,7 +101,7 @@ export class HostResourceLoader implements ResourceLoader { */ load(resolvedUrl: string): string { if (this.cache.has(resolvedUrl)) { - return this.cache.get(resolvedUrl) !; + return this.cache.get(resolvedUrl)!; } const result = this.host.readResource ? this.host.readResource(resolvedUrl) : @@ -169,14 +169,15 @@ export class HostResourceLoader implements ResourceLoader { // but is marked @internal in TypeScript. See // https://github.com/Microsoft/TypeScript/issues/28770. type ResolvedModuleWithFailedLookupLocations = - ts.ResolvedModuleWithFailedLookupLocations & {failedLookupLocations: ReadonlyArray<string>}; + ts.ResolvedModuleWithFailedLookupLocations&{failedLookupLocations: ReadonlyArray<string>}; // clang-format off const failedLookup = ts.resolveModuleName(url + '.$ngresource$', fromFile, this.options, this.host) as ResolvedModuleWithFailedLookupLocations; // clang-format on if (failedLookup.failedLookupLocations === undefined) { throw new Error( - `Internal error: expected to find failedLookupLocations during resolution of resource '${url}' in context of ${fromFile}`); + `Internal error: expected to find failedLookupLocations during resolution of resource '${ + url}' in context of ${fromFile}`); } return failedLookup.failedLookupLocations diff --git a/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts b/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts index d6ef4b4020c97..f51ffb6d0df3a 100644 --- a/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts +++ b/packages/compiler-cli/src/ngtsc/routing/src/analyzer.ts @@ -12,7 +12,7 @@ import {ModuleResolver} from '../../imports'; import {PartialEvaluator} from '../../partial_evaluator'; import {scanForCandidateTransitiveModules, scanForRouteEntryPoints} from './lazy'; -import {RouterEntryPointManager, entryPointKeyFor} from './route'; +import {entryPointKeyFor, RouterEntryPointManager} from './route'; export interface NgModuleRawRouteData { sourceFile: ts.SourceFile; @@ -42,10 +42,13 @@ export class NgModuleRouteAnalyzer { if (this.modules.has(key)) { throw new Error(`Double route analyzing for '${key}'.`); } - this.modules.set( - key, { - sourceFile, moduleName, imports, exports, providers, - }); + this.modules.set(key, { + sourceFile, + moduleName, + imports, + exports, + providers, + }); } listLazyRoutes(entryModuleKey?: string|undefined): LazyRoute[] { @@ -63,7 +66,7 @@ export class NgModuleRouteAnalyzer { const scanRecursively = entryModuleKey !== undefined; while (pendingModuleKeys.length > 0) { - const key = pendingModuleKeys.pop() !; + const key = pendingModuleKeys.pop()!; if (scannedModuleKeys.has(key)) { continue; @@ -71,7 +74,7 @@ export class NgModuleRouteAnalyzer { scannedModuleKeys.add(key); } - const data = this.modules.get(key) !; + const data = this.modules.get(key)!; const entryPoints = scanForRouteEntryPoints( data.sourceFile, data.moduleName, data, this.entryPointManager, this.evaluator); diff --git a/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts b/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts index 3e1eb580c30c5..39b4ba334cbd9 100644 --- a/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts +++ b/packages/compiler-cli/src/ngtsc/routing/src/lazy.ts @@ -12,7 +12,7 @@ import {Reference} from '../../imports'; import {ForeignFunctionResolver, PartialEvaluator, ResolvedValue} from '../../partial_evaluator'; import {NgModuleRawRouteData} from './analyzer'; -import {RouterEntryPoint, RouterEntryPointManager, entryPointKeyFor} from './route'; +import {entryPointKeyFor, RouterEntryPoint, RouterEntryPointManager} from './route'; const ROUTES_MARKER = '__ngRoutesMarker__'; @@ -23,7 +23,7 @@ export interface LazyRouteEntry { } export function scanForCandidateTransitiveModules( - expr: ts.Expression | null, evaluator: PartialEvaluator): string[] { + expr: ts.Expression|null, evaluator: PartialEvaluator): string[] { if (expr === null) { return []; } @@ -38,7 +38,7 @@ export function scanForCandidateTransitiveModules( } } else if (entry instanceof Map) { if (entry.has('ngModule')) { - recursivelyAddModules(entry.get('ngModule') !); + recursivelyAddModules(entry.get('ngModule')!); } } else if ((entry instanceof Reference) && hasIdentifier(entry.node)) { const filePath = entry.node.getSourceFile().fileName; @@ -70,7 +70,9 @@ export function scanForRouteEntryPoints( const resolvedTo = entryPointManager.resolveLoadChildrenIdentifier(loadChildren, ngModule); if (resolvedTo !== null) { routes.push({ - loadChildren, from, resolvedTo, + loadChildren, + from, + resolvedTo, }); } } @@ -159,29 +161,27 @@ function scanForLazyRoutes(routes: ResolvedValue[]): string[] { const routerModuleFFR: ForeignFunctionResolver = function routerModuleFFR( ref: Reference<ts.FunctionDeclaration|ts.MethodDeclaration|ts.FunctionExpression>, - args: ReadonlyArray<ts.Expression>): ts.Expression | - null { - if (!isMethodNodeReference(ref) || !ts.isClassDeclaration(ref.node.parent)) { - return null; - } else if ( - ref.bestGuessOwningModule === null || - ref.bestGuessOwningModule.specifier !== '@angular/router') { - return null; - } else if ( - ref.node.parent.name === undefined || ref.node.parent.name.text !== 'RouterModule') { - return null; - } else if ( - !ts.isIdentifier(ref.node.name) || - (ref.node.name.text !== 'forRoot' && ref.node.name.text !== 'forChild')) { - return null; - } + args: ReadonlyArray<ts.Expression>): ts.Expression|null { + if (!isMethodNodeReference(ref) || !ts.isClassDeclaration(ref.node.parent)) { + return null; + } else if ( + ref.bestGuessOwningModule === null || + ref.bestGuessOwningModule.specifier !== '@angular/router') { + return null; + } else if (ref.node.parent.name === undefined || ref.node.parent.name.text !== 'RouterModule') { + return null; + } else if ( + !ts.isIdentifier(ref.node.name) || + (ref.node.name.text !== 'forRoot' && ref.node.name.text !== 'forChild')) { + return null; + } - const routes = args[0]; - return ts.createObjectLiteral([ - ts.createPropertyAssignment(ROUTES_MARKER, ts.createTrue()), - ts.createPropertyAssignment('routes', routes), - ]); - }; + const routes = args[0]; + return ts.createObjectLiteral([ + ts.createPropertyAssignment(ROUTES_MARKER, ts.createTrue()), + ts.createPropertyAssignment('routes', routes), + ]); +}; function hasIdentifier(node: ts.Node): node is ts.Node&{name: ts.Identifier} { const node_ = node as ts.NamedDeclaration; diff --git a/packages/compiler-cli/src/ngtsc/routing/src/route.ts b/packages/compiler-cli/src/ngtsc/routing/src/route.ts index 2764b09de3855..d6f11b9a6e5b0 100644 --- a/packages/compiler-cli/src/ngtsc/routing/src/route.ts +++ b/packages/compiler-cli/src/ngtsc/routing/src/route.ts @@ -22,10 +22,14 @@ export abstract class RouterEntryPoint { class RouterEntryPointImpl implements RouterEntryPoint { constructor(readonly filePath: string, readonly moduleName: string) {} - get name(): string { return this.moduleName; } + get name(): string { + return this.moduleName; + } // For debugging purposes. - toString(): string { return `RouterEntryPoint(name: ${this.name}, filePath: ${this.filePath})`; } + toString(): string { + return `RouterEntryPoint(name: ${this.name}, filePath: ${this.filePath})`; + } } export class RouterEntryPointManager { @@ -51,7 +55,7 @@ export class RouterEntryPointManager { if (!this.map.has(key)) { this.map.set(key, new RouterEntryPointImpl(sf.fileName, moduleName)); } - return this.map.get(key) !; + return this.map.get(key)!; } } diff --git a/packages/compiler-cli/src/ngtsc/scope/src/dependency.ts b/packages/compiler-cli/src/ngtsc/scope/src/dependency.ts index ab441af285fb2..94479f97b96ed 100644 --- a/packages/compiler-cli/src/ngtsc/scope/src/dependency.ts +++ b/packages/compiler-cli/src/ngtsc/scope/src/dependency.ts @@ -47,12 +47,12 @@ export class MetadataDtsModuleScopeResolver implements DtsModuleScopeResolver { const clazz = ref.node; const sourceFile = clazz.getSourceFile(); if (!sourceFile.isDeclarationFile) { - throw new Error( - `Debug error: DtsModuleScopeResolver.read(${ref.debugName} from ${sourceFile.fileName}), but not a .d.ts file`); + throw new Error(`Debug error: DtsModuleScopeResolver.read(${ref.debugName} from ${ + sourceFile.fileName}), but not a .d.ts file`); } if (this.cache.has(clazz)) { - return this.cache.get(clazz) !; + return this.cache.get(clazz)!; } // Build up the export scope - those directives and pipes made visible by this module. diff --git a/packages/compiler-cli/src/ngtsc/scope/src/local.ts b/packages/compiler-cli/src/ngtsc/scope/src/local.ts index ad505ed1b64c5..5cc992b4e98b7 100644 --- a/packages/compiler-cli/src/ngtsc/scope/src/local.ts +++ b/packages/compiler-cli/src/ngtsc/scope/src/local.ts @@ -143,7 +143,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop getScopeForComponent(clazz: ClassDeclaration): LocalModuleScope|null|'error' { const scope = !this.declarationToModule.has(clazz) ? null : - this.getScopeOfModule(this.declarationToModule.get(clazz) !.ngModule); + this.getScopeOfModule(this.declarationToModule.get(clazz)!.ngModule); return scope; } @@ -159,7 +159,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop return null; } - return Array.from(this.duplicateDeclarations.get(node) !.values()); + return Array.from(this.duplicateDeclarations.get(node)!.values()); } /** @@ -172,7 +172,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop */ getScopeOfModule(clazz: ClassDeclaration): LocalModuleScope|'error'|null { const scope = this.moduleToRef.has(clazz) ? - this.getScopeOfModuleReference(this.moduleToRef.get(clazz) !) : + this.getScopeOfModuleReference(this.moduleToRef.get(clazz)!) : null; // If the NgModule class is marked as tainted, consider it an error. if (this.taintedModules.has(clazz)) { @@ -193,7 +193,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop this.getScopeOfModule(clazz); if (this.scopeErrors.has(clazz)) { - return this.scopeErrors.get(clazz) !; + return this.scopeErrors.get(clazz)!; } else { return null; } @@ -218,21 +218,22 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop rawDeclarations: ts.Expression|null): void { const declData: DeclarationData = { ngModule, - ref: decl, rawDeclarations, + ref: decl, + rawDeclarations, }; // First, check for duplicate declarations of the same directive/pipe. if (this.duplicateDeclarations.has(decl.node)) { // This directive/pipe has already been identified as being duplicated. Add this module to the // map of modules for which a duplicate declaration exists. - this.duplicateDeclarations.get(decl.node) !.set(ngModule, declData); + this.duplicateDeclarations.get(decl.node)!.set(ngModule, declData); } else if ( this.declarationToModule.has(decl.node) && - this.declarationToModule.get(decl.node) !.ngModule !== ngModule) { + this.declarationToModule.get(decl.node)!.ngModule !== ngModule) { // This directive/pipe is already registered as declared in another module. Mark it as a // duplicate instead. const duplicateDeclMap = new Map<ClassDeclaration, DeclarationData>(); - const firstDeclData = this.declarationToModule.get(decl.node) !; + const firstDeclData = this.declarationToModule.get(decl.node)!; // Mark both modules as tainted, since their declarations are missing a component. this.taintedModules.add(firstDeclData.ngModule); @@ -341,11 +342,13 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop } else { this.taintedModules.add(ngModule.ref.node); - const errorNode = decl.getOriginForDiagnostics(ngModule.rawDeclarations !); + const errorNode = decl.getOriginForDiagnostics(ngModule.rawDeclarations!); diagnostics.push(makeDiagnostic( ErrorCode.NGMODULE_INVALID_DECLARATION, errorNode, `The class '${decl.node.name.text}' is listed in the declarations ` + - `of the NgModule '${ngModule.ref.node.name.text}', but is not a directive, a component, or a pipe. ` + + `of the NgModule '${ + ngModule.ref.node.name + .text}', but is not a directive, a component, or a pipe. ` + `Either remove it from the NgModule's declarations, or add an appropriate Angular decorator.`, [{node: decl.node.name, messageText: `'${decl.node.name.text}' is declared here.`}])); continue; @@ -378,11 +381,11 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop } } else if (compilationDirectives.has(decl.node)) { // decl is a directive or component in the compilation scope of this NgModule. - const directive = compilationDirectives.get(decl.node) !; + const directive = compilationDirectives.get(decl.node)!; exportDirectives.set(decl.node, directive); } else if (compilationPipes.has(decl.node)) { // decl is a pipe in the compilation scope of this NgModule. - const pipe = compilationPipes.get(decl.node) !; + const pipe = compilationPipes.get(decl.node)!; exportPipes.set(decl.node, pipe); } else { // decl is an unknown export. @@ -433,7 +436,9 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop /** * Check whether a component requires remote scoping. */ - getRequiresRemoteScope(node: ClassDeclaration): boolean { return this.remoteScoping.has(node); } + getRequiresRemoteScope(node: ClassDeclaration): boolean { + return this.remoteScoping.has(node); + } /** * Set a component as requiring remote scoping. @@ -466,7 +471,8 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop ErrorCode.NGMODULE_INVALID_EXPORT; diagnostics.push(makeDiagnostic( code, identifierOfNode(ref.node) || ref.node, - `Appears in the NgModule.${type}s of ${nodeNameForError(ownerForErrors)}, but could not be resolved to an NgModule`)); + `Appears in the NgModule.${type}s of ${ + nodeNameForError(ownerForErrors)}, but could not be resolved to an NgModule`)); return undefined; } return this.dependencyScopeReader.resolve(ref); @@ -496,16 +502,16 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop return; } const isReExport = !declared.has(exportRef.node); - const exportName = this.aliasingHost !.maybeAliasSymbolAs( + const exportName = this.aliasingHost!.maybeAliasSymbolAs( exportRef, sourceFile, ngModule.ref.node.name.text, isReExport); if (exportName === null) { return; } if (!reexportMap.has(exportName)) { if (exportRef.alias && exportRef.alias instanceof ExternalExpr) { - reexports !.push({ - fromModule: exportRef.alias.value.moduleName !, - symbolName: exportRef.alias.value.name !, + reexports!.push({ + fromModule: exportRef.alias.value.moduleName!, + symbolName: exportRef.alias.value.name!, asAlias: exportName, }); } else { @@ -514,7 +520,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop expr.value.name === null) { throw new Error('Expected ExternalExpr'); } - reexports !.push({ + reexports!.push({ fromModule: expr.value.moduleName, symbolName: expr.value.name, asAlias: exportName, @@ -523,7 +529,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop reexportMap.set(exportName, exportRef); } else { // Another re-export already used this name. Produce a diagnostic. - const prevRef = reexportMap.get(exportName) !; + const prevRef = reexportMap.get(exportName)!; diagnostics.push(reexportCollision(ngModuleRef.node, prevRef, exportRef)); } }; @@ -548,12 +554,13 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop */ function invalidRef( clazz: ts.Declaration, decl: Reference<ts.Declaration>, - type: 'import' | 'export'): ts.Diagnostic { + type: 'import'|'export'): ts.Diagnostic { const code = type === 'import' ? ErrorCode.NGMODULE_INVALID_IMPORT : ErrorCode.NGMODULE_INVALID_EXPORT; const resolveTarget = type === 'import' ? 'NgModule' : 'NgModule, Component, Directive, or Pipe'; let message = - `Appears in the NgModule.${type}s of ${nodeNameForError(clazz)}, but could not be resolved to an ${resolveTarget} class.` + + `Appears in the NgModule.${type}s of ${ + nodeNameForError(clazz)}, but could not be resolved to an ${resolveTarget} class.` + '\n\n'; const library = decl.ownedByModuleGuess !== null ? ` (${decl.ownedByModuleGuess})` : ''; const sf = decl.node.getSourceFile(); @@ -573,8 +580,8 @@ function invalidRef( } else { // This is a monorepo style local dependency. Unfortunately these are too different to really // offer much more advice than this. - message += - `This likely means that the dependency${library} which declares ${decl.debugName} has not been processed correctly by ngcc.`; + message += `This likely means that the dependency${library} which declares ${ + decl.debugName} has not been processed correctly by ngcc.`; } return makeDiagnostic(code, identifierOfNode(decl.node) || decl.node, message); @@ -585,7 +592,7 @@ function invalidRef( */ function invalidTransitiveNgModuleRef( clazz: ts.Declaration, decl: Reference<ts.Declaration>, - type: 'import' | 'export'): ts.Diagnostic { + type: 'import'|'export'): ts.Diagnostic { const code = type === 'import' ? ErrorCode.NGMODULE_INVALID_IMPORT : ErrorCode.NGMODULE_INVALID_EXPORT; return makeDiagnostic( @@ -600,7 +607,8 @@ function invalidTransitiveNgModuleRef( function invalidReexport(clazz: ts.Declaration, decl: Reference<ts.Declaration>): ts.Diagnostic { return makeDiagnostic( ErrorCode.NGMODULE_INVALID_REEXPORT, identifierOfNode(decl.node) || decl.node, - `Present in the NgModule.exports of ${nodeNameForError(clazz)} but neither declared nor imported`); + `Present in the NgModule.exports of ${ + nodeNameForError(clazz)} but neither declared nor imported`); } /** @@ -609,11 +617,13 @@ function invalidReexport(clazz: ts.Declaration, decl: Reference<ts.Declaration>) function reexportCollision( module: ClassDeclaration, refA: Reference<ClassDeclaration>, refB: Reference<ClassDeclaration>): ts.Diagnostic { - const childMessageText = - `This directive/pipe is part of the exports of '${module.name.text}' and shares the same name as another exported directive/pipe.`; + const childMessageText = `This directive/pipe is part of the exports of '${ + module.name.text}' and shares the same name as another exported directive/pipe.`; return makeDiagnostic( - ErrorCode.NGMODULE_REEXPORT_NAME_COLLISION, module.name, ` - There was a name collision between two classes named '${refA.node.name.text}', which are both part of the exports of '${module.name.text}'. + ErrorCode.NGMODULE_REEXPORT_NAME_COLLISION, module.name, + ` + There was a name collision between two classes named '${ + refA.node.name.text}', which are both part of the exports of '${module.name.text}'. Angular generates re-exports of an NgModule's exported directives/pipes from the module's source file in certain cases, using the declared name of the class. If two classes of the same name are exported, this automatic naming does not work. diff --git a/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts b/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts index 5e5e36522a2b1..512d5bb966282 100644 --- a/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts +++ b/packages/compiler-cli/src/ngtsc/scope/test/dependency_spec.ts @@ -22,7 +22,7 @@ const MODULE_FROM_NODE_MODULES_PATH = /.*node_modules\/(\w+)\/index\.d\.ts$/; const testHost: UnifiedModulesHost = { fileNameToModuleName: function(imported: string): string { - const res = MODULE_FROM_NODE_MODULES_PATH.exec(imported) !; + const res = MODULE_FROM_NODE_MODULES_PATH.exec(imported)!; return 'root/' + res[1]; } }; @@ -44,7 +44,7 @@ export declare type PipeMeta<A, B> = never; * destructured to retrieve references to specific declared classes. */ function makeTestEnv( - modules: {[module: string]: string}, aliasGenerator: AliasingHost | null = null): { + modules: {[module: string]: string}, aliasGenerator: AliasingHost|null = null): { refs: {[name: string]: Reference<ClassDeclaration>}, resolver: MetadataDtsModuleScopeResolver, } { @@ -64,11 +64,11 @@ function makeTestEnv( // Resolver for the refs object. const get = (target: {}, name: string): Reference<ts.ClassDeclaration> => { for (const sf of program.getSourceFiles()) { - const symbol = checker.getSymbolAtLocation(sf) !; - const exportedSymbol = symbol.exports !.get(name as ts.__String); + const symbol = checker.getSymbolAtLocation(sf)!; + const exportedSymbol = symbol.exports!.get(name as ts.__String); if (exportedSymbol !== undefined) { const decl = exportedSymbol.valueDeclaration as ts.ClassDeclaration; - const specifier = MODULE_FROM_NODE_MODULES_PATH.exec(sf.fileName) ![1]; + const specifier = MODULE_FROM_NODE_MODULES_PATH.exec(sf.fileName)![1]; return new Reference(decl, {specifier, resolutionContext: sf.fileName}); } } @@ -97,7 +97,7 @@ runInEachFileSystem(() => { ` }); const {Dir, Module} = refs; - const scope = resolver.resolve(Module) !; + const scope = resolver.resolve(Module)!; expect(scopeToRefs(scope)).toEqual([Dir]); }); @@ -118,7 +118,7 @@ runInEachFileSystem(() => { ` }); const {Dir, ModuleB} = refs; - const scope = resolver.resolve(ModuleB) !; + const scope = resolver.resolve(ModuleB)!; expect(scopeToRefs(scope)).toEqual([Dir]); }); @@ -142,7 +142,7 @@ runInEachFileSystem(() => { ` }); const {Dir, ModuleB} = refs; - const scope = resolver.resolve(ModuleB) !; + const scope = resolver.resolve(ModuleB)!; expect(scopeToRefs(scope)).toEqual([Dir]); // Explicitly verify that the directive has the correct owning module. @@ -186,7 +186,7 @@ runInEachFileSystem(() => { }, new UnifiedModulesAliasingHost(testHost)); const {ShallowModule} = refs; - const scope = resolver.resolve(ShallowModule) !; + const scope = resolver.resolve(ShallowModule)!; const [DeepDir, MiddleDir, ShallowDir] = scopeToRefs(scope); expect(getAlias(DeepDir)).toEqual({ moduleName: 'root/shallow', @@ -236,7 +236,7 @@ runInEachFileSystem(() => { }, new UnifiedModulesAliasingHost(testHost)); const {ShallowModule} = refs; - const scope = resolver.resolve(ShallowModule) !; + const scope = resolver.resolve(ShallowModule)!; const [DeepDir, MiddleDir, ShallowDir] = scopeToRefs(scope); expect(getAlias(DeepDir)).toEqual({ moduleName: 'root/shallow', @@ -269,7 +269,7 @@ runInEachFileSystem(() => { }, new UnifiedModulesAliasingHost(testHost)); const {DeepExportModule} = refs; - const scope = resolver.resolve(DeepExportModule) !; + const scope = resolver.resolve(DeepExportModule)!; const [DeepDir] = scopeToRefs(scope); expect(getAlias(DeepDir)).toBeNull(); }); @@ -278,7 +278,7 @@ runInEachFileSystem(() => { function scopeToRefs(scope: ExportScope): Reference<ClassDeclaration>[] { const directives = scope.exported.directives.map(dir => dir.ref); const pipes = scope.exported.pipes.map(pipe => pipe.ref); - return [...directives, ...pipes].sort((a, b) => a.debugName !.localeCompare(b.debugName !)); + return [...directives, ...pipes].sort((a, b) => a.debugName!.localeCompare(b.debugName!)); } function getAlias(ref: Reference<ClassDeclaration>): ExternalReference|null { diff --git a/packages/compiler-cli/src/ngtsc/scope/test/local_spec.ts b/packages/compiler-cli/src/ngtsc/scope/test/local_spec.ts index 05d06dda5e91f..a496754060932 100644 --- a/packages/compiler-cli/src/ngtsc/scope/test/local_spec.ts +++ b/packages/compiler-cli/src/ngtsc/scope/test/local_spec.ts @@ -34,8 +34,8 @@ function registerFakeRefs(registry: MetadataRegistry): describe('LocalModuleScopeRegistry', () => { const refEmitter = new ReferenceEmitter([]); - let scopeRegistry !: LocalModuleScopeRegistry; - let metaRegistry !: MetadataRegistry; + let scopeRegistry!: LocalModuleScopeRegistry; + let metaRegistry!: MetadataRegistry; beforeEach(() => { const localRegistry = new LocalMetadataRegistry(); @@ -230,7 +230,7 @@ describe('LocalModuleScopeRegistry', () => { }); function fakeDirective(ref: Reference<ClassDeclaration>): DirectiveMeta { - const name = ref.debugName !; + const name = ref.debugName!; return { ref, name, @@ -248,16 +248,18 @@ function fakeDirective(ref: Reference<ClassDeclaration>): DirectiveMeta { } function fakePipe(ref: Reference<ClassDeclaration>): PipeMeta { - const name = ref.debugName !; + const name = ref.debugName!; return {ref, name}; } class MockDtsModuleScopeResolver implements DtsModuleScopeResolver { - resolve(ref: Reference<ClassDeclaration>): null { return null; } + resolve(ref: Reference<ClassDeclaration>): null { + return null; + } } function scopeToRefs(scopeData: ScopeData): Reference<ClassDeclaration>[] { const directives = scopeData.directives.map(dir => dir.ref); const pipes = scopeData.pipes.map(pipe => pipe.ref); - return [...directives, ...pipes].sort((a, b) => a.debugName !.localeCompare(b.debugName !)); + return [...directives, ...pipes].sort((a, b) => a.debugName!.localeCompare(b.debugName!)); } diff --git a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts index 426687636ca97..4bca52c413ce3 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/factory_generator.ts @@ -7,7 +7,7 @@ */ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom, basename} from '../../file_system'; +import {absoluteFrom, AbsoluteFsPath, basename} from '../../file_system'; import {ImportRewriter} from '../../imports'; import {isNonDeclarationTsPath} from '../../util/src/typescript'; @@ -24,15 +24,21 @@ const STRIP_NG_FACTORY = /(.*)NgFactory$/; export class FactoryGenerator implements ShimGenerator { private constructor(private map: Map<AbsoluteFsPath, AbsoluteFsPath>) {} - get factoryFileMap(): Map<AbsoluteFsPath, AbsoluteFsPath> { return this.map; } + get factoryFileMap(): Map<AbsoluteFsPath, AbsoluteFsPath> { + return this.map; + } - get factoryFileNames(): AbsoluteFsPath[] { return Array.from(this.map.keys()); } + get factoryFileNames(): AbsoluteFsPath[] { + return Array.from(this.map.keys()); + } - recognize(fileName: AbsoluteFsPath): boolean { return this.map.has(fileName); } + recognize(fileName: AbsoluteFsPath): boolean { + return this.map.has(fileName); + } generate(genFilePath: AbsoluteFsPath, readFile: (fileName: string) => ts.SourceFile | null): ts.SourceFile|null { - const originalPath = this.map.get(genFilePath) !; + const originalPath = this.map.get(genFilePath)!; const original = readFile(originalPath); if (original === null) { return null; @@ -53,7 +59,7 @@ export class FactoryGenerator implements ShimGenerator { decl => isExported(decl) && decl.decorators !== undefined && decl.name !== undefined) // Grab the symbol name. - .map(decl => decl.name !.text); + .map(decl => decl.name!.text); let sourceText = ''; @@ -71,8 +77,8 @@ export class FactoryGenerator implements ShimGenerator { // This will encompass a lot of symbols which don't need factories, but that's okay // because it won't miss any that do. const varLines = symbolNames.map( - name => - `export const ${name}NgFactory: i0.ɵNgModuleFactory<any> = new i0.ɵNgModuleFactory(${name});`); + name => `export const ${ + name}NgFactory: i0.ɵNgModuleFactory<any> = new i0.ɵNgModuleFactory(${name});`); sourceText += [ // This might be incorrect if the current package being compiled is Angular core, but it's // okay to leave in at type checking time. TypeScript can handle this reference via its path @@ -136,7 +142,7 @@ function transformFactorySourceFile( return file; } - const {moduleSymbolNames, sourceFilePath} = factoryMap.get(file.fileName) !; + const {moduleSymbolNames, sourceFilePath} = factoryMap.get(file.fileName)!; file = ts.getMutableClone(file); diff --git a/packages/compiler-cli/src/ngtsc/shims/src/factory_tracker.ts b/packages/compiler-cli/src/ngtsc/shims/src/factory_tracker.ts index a9b58b37e4593..a4ccb13302078 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/factory_tracker.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/factory_tracker.ts @@ -32,7 +32,7 @@ export class FactoryTracker { track(sf: ts.SourceFile, factorySymbolName: string): void { if (this.sourceToFactorySymbols.has(sf.fileName)) { - this.sourceToFactorySymbols.get(sf.fileName) !.add(factorySymbolName); + this.sourceToFactorySymbols.get(sf.fileName)!.add(factorySymbolName); } } } diff --git a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts index f3eb5c10c7a0d..ab6caddcdf887 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/summary_generator.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom} from '../../file_system'; +import {absoluteFrom, AbsoluteFsPath} from '../../file_system'; import {isNonDeclarationTsPath} from '../../util/src/typescript'; import {ShimGenerator} from './api'; @@ -17,13 +17,17 @@ import {generatedModuleName} from './util'; export class SummaryGenerator implements ShimGenerator { private constructor(private map: Map<AbsoluteFsPath, AbsoluteFsPath>) {} - getSummaryFileNames(): AbsoluteFsPath[] { return Array.from(this.map.keys()); } + getSummaryFileNames(): AbsoluteFsPath[] { + return Array.from(this.map.keys()); + } - recognize(fileName: AbsoluteFsPath): boolean { return this.map.has(fileName); } + recognize(fileName: AbsoluteFsPath): boolean { + return this.map.has(fileName); + } generate(genFilePath: AbsoluteFsPath, readFile: (fileName: string) => ts.SourceFile | null): ts.SourceFile|null { - const originalPath = this.map.get(genFilePath) !; + const originalPath = this.map.get(genFilePath)!; const original = readFile(originalPath); if (original === null) { return null; diff --git a/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts b/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts index 8f9d5247db2cc..57ebf91b54700 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/typecheck_shim.ts @@ -22,7 +22,9 @@ import {ShimGenerator} from './api'; export class TypeCheckShimGenerator implements ShimGenerator { constructor(private typeCheckFile: AbsoluteFsPath) {} - recognize(fileName: AbsoluteFsPath): boolean { return fileName === this.typeCheckFile; } + recognize(fileName: AbsoluteFsPath): boolean { + return fileName === this.typeCheckFile; + } generate(genFileName: AbsoluteFsPath, readFile: (fileName: string) => ts.SourceFile | null): ts.SourceFile|null { diff --git a/packages/compiler-cli/src/ngtsc/switch/src/switch.ts b/packages/compiler-cli/src/ngtsc/switch/src/switch.ts index 017458bcab9b5..ea1619c9e3380 100644 --- a/packages/compiler-cli/src/ngtsc/switch/src/switch.ts +++ b/packages/compiler-cli/src/ngtsc/switch/src/switch.ts @@ -107,8 +107,8 @@ function flipIvySwitchesInVariableStatement( // reported as a thrown error and not a diagnostic as transformers cannot output diagnostics. let newIdentifier = findPostSwitchIdentifier(statements, postSwitchName); if (newIdentifier === null) { - throw new Error( - `Unable to find identifier ${postSwitchName} in ${stmt.getSourceFile().fileName} for the Ivy switch.`); + throw new Error(`Unable to find identifier ${postSwitchName} in ${ + stmt.getSourceFile().fileName} for the Ivy switch.`); } // Copy the identifier with updateIdentifier(). This copies the internal information which diff --git a/packages/compiler-cli/src/ngtsc/testing/src/utils.ts b/packages/compiler-cli/src/ngtsc/testing/src/utils.ts index a71b7d21c3f54..b50751f088dd3 100644 --- a/packages/compiler-cli/src/ngtsc/testing/src/utils.ts +++ b/packages/compiler-cli/src/ngtsc/testing/src/utils.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; -import {AbsoluteFsPath, NgtscCompilerHost, dirname, getFileSystem, getSourceFileOrError} from '../../file_system'; +import {AbsoluteFsPath, dirname, getFileSystem, getSourceFileOrError, NgtscCompilerHost} from '../../file_system'; export function makeProgram( files: {name: AbsoluteFsPath, contents: string, isRoot?: boolean}[], @@ -25,7 +25,8 @@ export function makeProgram( const compilerOptions = { noLib: true, experimentalDecorators: true, - moduleResolution: ts.ModuleResolutionKind.NodeJs, ...options + moduleResolution: ts.ModuleResolutionKind.NodeJs, + ...options }; const compilerHost = new NgtscCompilerHost(fs, compilerOptions); const rootNames = files.filter(file => file.isRoot !== false) @@ -38,7 +39,7 @@ export function makeProgram( let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); if (diagnostic.file) { const {line, character} = - diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start !); + diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); message = `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`; } return `Error: ${message}`; diff --git a/packages/compiler-cli/src/ngtsc/transform/src/alias.ts b/packages/compiler-cli/src/ngtsc/transform/src/alias.ts index f7698f29e6cbe..5cba3e6d50b1a 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/alias.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/alias.ts @@ -17,7 +17,7 @@ export function aliasTransformFactory(exportStatements: Map<string, Map<string, } const statements = [...file.statements]; - exportStatements.get(file.fileName) !.forEach(([moduleName, symbolName], aliasName) => { + exportStatements.get(file.fileName)!.forEach(([moduleName, symbolName], aliasName) => { const stmt = ts.createExportDeclaration( /* decorators */ undefined, /* modifiers */ undefined, diff --git a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts index e103aadd316ae..250360d70e978 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts @@ -94,9 +94,13 @@ export class TraitCompiler { } } - analyzeSync(sf: ts.SourceFile): void { this.analyze(sf, false); } + analyzeSync(sf: ts.SourceFile): void { + this.analyze(sf, false); + } - analyzeAsync(sf: ts.SourceFile): Promise<void>|undefined { return this.analyze(sf, true); } + analyzeAsync(sf: ts.SourceFile): Promise<void>|undefined { + return this.analyze(sf, true); + } private analyze(sf: ts.SourceFile, preanalyze: false): void; private analyze(sf: ts.SourceFile, preanalyze: true): Promise<void>|undefined; @@ -138,7 +142,7 @@ export class TraitCompiler { recordFor(clazz: ClassDeclaration): ClassRecord|null { if (this.classes.has(clazz)) { - return this.classes.get(clazz) !; + return this.classes.get(clazz)!; } else { return null; } @@ -149,8 +153,8 @@ export class TraitCompiler { return null; } const records: ClassRecord[] = []; - for (const clazz of this.fileToClasses.get(sf) !) { - records.push(this.classes.get(clazz) !); + for (const clazz of this.fileToClasses.get(sf)!) { + records.push(this.classes.get(clazz)!); } return records; } @@ -173,7 +177,7 @@ export class TraitCompiler { }; for (const priorTrait of priorRecord.traits) { - const handler = this.handlersByName.get(priorTrait.handler.name) !; + const handler = this.handlersByName.get(priorTrait.handler.name)!; let trait: Trait<unknown, unknown, unknown> = Trait.pending(handler, priorTrait.detected); if (priorTrait.state === TraitState.ANALYZED || priorTrait.state === TraitState.RESOLVED) { @@ -195,7 +199,7 @@ export class TraitCompiler { if (!this.fileToClasses.has(sf)) { this.fileToClasses.set(sf, new Set<ClassDeclaration>()); } - this.fileToClasses.get(sf) !.add(record.node); + this.fileToClasses.get(sf)!.add(record.node); } private scanClassForTraits(clazz: ClassDeclaration): @@ -242,7 +246,7 @@ export class TraitCompiler { if (!this.fileToClasses.has(sf)) { this.fileToClasses.set(sf, new Set<ClassDeclaration>()); } - this.fileToClasses.get(sf) !.add(clazz); + this.fileToClasses.get(sf)!.add(clazz); } else { // This is at least the second handler to match this class. This is a slower path that some // classes will go through, which validates that the set of decorators applied to the class @@ -317,7 +321,7 @@ export class TraitCompiler { } } if (preanalysis !== null) { - preanalyzeQueue !.push(preanalysis.then(analyze)); + preanalyzeQueue!.push(preanalysis.then(analyze)); } else { analyze(); } @@ -328,8 +332,8 @@ export class TraitCompiler { clazz: ClassDeclaration, trait: Trait<unknown, unknown, unknown>, flags?: HandlerFlags): void { if (trait.state !== TraitState.PENDING) { - throw new Error( - `Attempt to analyze trait of ${clazz.name.text} in state ${TraitState[trait.state]} (expected DETECTED)`); + throw new Error(`Attempt to analyze trait of ${clazz.name.text} in state ${ + TraitState[trait.state]} (expected DETECTED)`); } // Attempt analysis. This could fail with a `FatalDiagnosticError`; catch it if it does. @@ -363,7 +367,7 @@ export class TraitCompiler { resolve(): void { const classes = Array.from(this.classes.keys()); for (const clazz of classes) { - const record = this.classes.get(clazz) !; + const record = this.classes.get(clazz)!; for (let trait of record.traits) { const handler = trait.handler; switch (trait.state) { @@ -371,8 +375,8 @@ export class TraitCompiler { case TraitState.ERRORED: continue; case TraitState.PENDING: - throw new Error( - `Resolving a trait that hasn't been analyzed: ${clazz.name.text} / ${Object.getPrototypeOf(trait.handler).constructor.name}`); + throw new Error(`Resolving a trait that hasn't been analyzed: ${clazz.name.text} / ${ + Object.getPrototypeOf(trait.handler).constructor.name}`); case TraitState.RESOLVED: throw new Error(`Resolving an already resolved trait`); } @@ -410,7 +414,7 @@ export class TraitCompiler { if (!this.reexportMap.has(fileName)) { this.reexportMap.set(fileName, new Map<string, [string, string]>()); } - const fileReexports = this.reexportMap.get(fileName) !; + const fileReexports = this.reexportMap.get(fileName)!; for (const reexport of result.reexports) { fileReexports.set(reexport.asAlias, [reexport.fromModule, reexport.symbolName]); } @@ -421,7 +425,7 @@ export class TraitCompiler { typeCheck(ctx: TypeCheckContext): void { for (const clazz of this.classes.keys()) { - const record = this.classes.get(clazz) !; + const record = this.classes.get(clazz)!; for (const trait of record.traits) { if (trait.state !== TraitState.RESOLVED) { continue; @@ -435,7 +439,7 @@ export class TraitCompiler { index(ctx: IndexingContext): void { for (const clazz of this.classes.keys()) { - const record = this.classes.get(clazz) !; + const record = this.classes.get(clazz)!; for (const trait of record.traits) { if (trait.state !== TraitState.RESOLVED) { // Skip traits that haven't been resolved successfully. @@ -457,7 +461,7 @@ export class TraitCompiler { return null; } - const record = this.classes.get(original) !; + const record = this.classes.get(original)!; let res: CompileResult[] = []; @@ -496,7 +500,7 @@ export class TraitCompiler { return []; } - const record = this.classes.get(original) !; + const record = this.classes.get(original)!; const decorators: ts.Decorator[] = []; for (const trait of record.traits) { @@ -515,7 +519,7 @@ export class TraitCompiler { get diagnostics(): ReadonlyArray<ts.Diagnostic> { const diagnostics: ts.Diagnostic[] = []; for (const clazz of this.classes.keys()) { - const record = this.classes.get(clazz) !; + const record = this.classes.get(clazz)!; if (record.metaDiagnostics !== null) { diagnostics.push(...record.metaDiagnostics); } @@ -528,5 +532,7 @@ export class TraitCompiler { return diagnostics; } - get exportStatements(): Map<string, Map<string, [string, string]>> { return this.reexportMap; } + get exportStatements(): Map<string, Map<string, [string, string]>> { + return this.reexportMap; + } } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts index 6e8c9abaedfbe..36cee9b39a46f 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/declaration.ts @@ -28,14 +28,14 @@ export class DtsTransformRegistry { if (!this.ivyDeclarationTransforms.has(sf)) { this.ivyDeclarationTransforms.set(sf, new IvyDeclarationDtsTransform()); } - return this.ivyDeclarationTransforms.get(sf) !; + return this.ivyDeclarationTransforms.get(sf)!; } getReturnTypeTransform(sf: ts.SourceFile): ReturnTypeTransform { if (!this.returnTypeTransforms.has(sf)) { this.returnTypeTransforms.set(sf, new ReturnTypeTransform()); } - return this.returnTypeTransforms.get(sf) !; + return this.returnTypeTransforms.get(sf)!; } /** @@ -55,11 +55,11 @@ export class DtsTransformRegistry { let transforms: DtsTransform[]|null = null; if (this.ivyDeclarationTransforms.has(originalSf)) { transforms = []; - transforms.push(this.ivyDeclarationTransforms.get(originalSf) !); + transforms.push(this.ivyDeclarationTransforms.get(originalSf)!); } if (this.returnTypeTransforms.has(originalSf)) { transforms = transforms || []; - transforms.push(this.returnTypeTransforms.get(originalSf) !); + transforms.push(this.returnTypeTransforms.get(originalSf)!); } return transforms; } @@ -200,7 +200,7 @@ export class IvyDeclarationDtsTransform implements DtsTransform { if (!this.declarationFields.has(original)) { return clazz; } - const fields = this.declarationFields.get(original) !; + const fields = this.declarationFields.get(original)!; const newMembers = fields.map(decl => { const modifiers = [ts.createModifier(ts.SyntaxKind.StaticKeyword)]; @@ -247,7 +247,7 @@ export class ReturnTypeTransform implements DtsTransform { if (!this.typeReplacements.has(original)) { return element; } - const returnType = this.typeReplacements.get(original) !; + const returnType = this.typeReplacements.get(original)!; const tsReturnType = translateType(returnType, imports); const methodSignature = ts.updateMethodSignature( @@ -273,7 +273,7 @@ export class ReturnTypeTransform implements DtsTransform { if (!this.typeReplacements.has(original)) { return element; } - const returnType = this.typeReplacements.get(original) !; + const returnType = this.typeReplacements.get(original)!; const tsReturnType = translateType(returnType, imports); return ts.updateFunctionDeclaration( diff --git a/packages/compiler-cli/src/ngtsc/transform/src/trait.ts b/packages/compiler-cli/src/ngtsc/transform/src/trait.ts index 1bdd897354a06..e6b5fb83d3830 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/trait.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/trait.ts @@ -50,8 +50,8 @@ export enum TraitState { * This not only simplifies the implementation, but ensures traits are monomorphic objects as * they're all just "views" in the type system of the same object (which never changes shape). */ -export type Trait<D, A, R> = PendingTrait<D, A, R>| SkippedTrait<D, A, R>| AnalyzedTrait<D, A, R>| - ResolvedTrait<D, A, R>| ErroredTrait<D, A, R>; +export type Trait<D, A, R> = PendingTrait<D, A, R>|SkippedTrait<D, A, R>|AnalyzedTrait<D, A, R>| + ResolvedTrait<D, A, R>|ErroredTrait<D, A, R>; /** * The value side of `Trait` exposes a helper to create a `Trait` in a pending state (by delegating @@ -59,7 +59,7 @@ export type Trait<D, A, R> = PendingTrait<D, A, R>| SkippedTrait<D, A, R>| Analy */ export const Trait = { pending: <D, A, R>(handler: DecoratorHandler<D, A, R>, detected: DetectResult<D>): - PendingTrait<D, A, R> => TraitImpl.pending(handler, detected), + PendingTrait<D, A, R> => TraitImpl.pending(handler, detected), }; /** @@ -137,7 +137,9 @@ export interface ErroredTrait<D, A, R> extends TraitBase<D, A, R> { * * This is a terminal state. */ -export interface SkippedTrait<D, A, R> extends TraitBase<D, A, R> { state: TraitState.SKIPPED; } +export interface SkippedTrait<D, A, R> extends TraitBase<D, A, R> { + state: TraitState.SKIPPED; +} /** * The part of the `Trait` interface for any trait which has been successfully analyzed. @@ -251,8 +253,8 @@ class TraitImpl<D, A, R> { */ private assertTransitionLegal(allowedState: TraitState, transitionTo: TraitState): void { if (!(this.state & allowedState)) { - throw new Error( - `Assertion failure: cannot transition from ${TraitState[this.state]} to ${TraitState[transitionTo]}.`); + throw new Error(`Assertion failure: cannot transition from ${TraitState[this.state]} to ${ + TraitState[transitionTo]}.`); } } diff --git a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts index 00ada93a58165..58704a13694e7 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/transform.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/transform.ts @@ -12,7 +12,7 @@ import * as ts from 'typescript'; import {DefaultImportRecorder, ImportRewriter} from '../../imports'; import {Decorator, ReflectionHost} from '../../reflection'; import {ImportManager, translateExpression, translateStatement} from '../../translator'; -import {VisitListEntryResult, Visitor, visit} from '../../util/src/visitor'; +import {visit, VisitListEntryResult, Visitor} from '../../util/src/visitor'; import {TraitCompiler} from './compilation'; import {addImports} from './utils'; @@ -285,7 +285,7 @@ function setFileOverviewComment(sf: ts.SourceFile, fileoverview: FileOverviewMet } function maybeFilterDecorator( - decorators: ts.NodeArray<ts.Decorator>| undefined, + decorators: ts.NodeArray<ts.Decorator>|undefined, toRemove: ts.Decorator[]): ts.NodeArray<ts.Decorator>|undefined { if (decorators === undefined) { return undefined; diff --git a/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts b/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts index 8608e4364fe32..e90f61659d641 100644 --- a/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts +++ b/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts @@ -24,11 +24,15 @@ runInEachFileSystem(() => { name = 'FakeDecoratorHandler'; precedence = HandlerPrecedence.PRIMARY; - detect(): undefined { throw new Error('detect should not have been called'); } + detect(): undefined { + throw new Error('detect should not have been called'); + } analyze(): AnalysisOutput<unknown> { throw new Error('analyze should not have been called'); } - compile(): CompileResult { throw new Error('compile should not have been called'); } + compile(): CompileResult { + throw new Error('compile should not have been called'); + } } const {program} = makeProgram([{ @@ -40,7 +44,7 @@ runInEachFileSystem(() => { const compiler = new TraitCompiler( [new FakeDecoratorHandler()], reflectionHost, NOOP_PERF_RECORDER, NOOP_INCREMENTAL_BUILD, true, new DtsTransformRegistry()); - const sourceFile = program.getSourceFile('lib.d.ts') !; + const sourceFile = program.getSourceFile('lib.d.ts')!; const analysis = compiler.analyzeSync(sourceFile); expect(sourceFile.isDeclarationFile).toBe(true); diff --git a/packages/compiler-cli/src/ngtsc/translator/src/translator.ts b/packages/compiler-cli/src/ngtsc/translator/src/translator.ts index a55348229d11a..aed4303eea96b 100644 --- a/packages/compiler-cli/src/ngtsc/translator/src/translator.ts +++ b/packages/compiler-cli/src/ngtsc/translator/src/translator.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeVisitor, TypeofExpr, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; +import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeofExpr, TypeVisitor, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler'; import {LocalizedString} from '@angular/compiler/src/output/output_ast'; import * as ts from 'typescript'; @@ -15,9 +15,13 @@ import {DefaultImportRecorder, ImportRewriter, NOOP_DEFAULT_IMPORT_RECORDER, Noo export class Context { constructor(readonly isStatement: boolean) {} - get withExpressionMode(): Context { return this.isStatement ? new Context(false) : this; } + get withExpressionMode(): Context { + return this.isStatement ? new Context(false) : this; + } - get withStatementMode(): Context { return !this.isStatement ? new Context(true) : this; } + get withStatementMode(): Context { + return !this.isStatement ? new Context(true) : this; + } } const BINARY_OPERATORS = new Map<BinaryOperator, ts.BinaryOperator>([ @@ -83,7 +87,7 @@ export class ImportManager { if (!this.specifierToIdentifier.has(moduleName)) { this.specifierToIdentifier.set(moduleName, `${this.prefix}${this.nextIndex++}`); } - const moduleImport = this.specifierToIdentifier.get(moduleName) !; + const moduleImport = this.specifierToIdentifier.get(moduleName)!; return {moduleImport, symbol}; } @@ -130,19 +134,21 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor ts.NodeFlags.Const : ts.NodeFlags.None; return ts.createVariableStatement( - undefined, ts.createVariableDeclarationList( - [ts.createVariableDeclaration( - stmt.name, undefined, stmt.value && - stmt.value.visitExpression(this, context.withExpressionMode))], - nodeFlags)); + undefined, + ts.createVariableDeclarationList( + [ts.createVariableDeclaration( + stmt.name, undefined, + stmt.value && stmt.value.visitExpression(this, context.withExpressionMode))], + nodeFlags)); } visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: Context): ts.FunctionDeclaration { return ts.createFunctionDeclaration( undefined, undefined, undefined, stmt.name, undefined, stmt.params.map(param => ts.createParameter(undefined, undefined, undefined, param.name)), - undefined, ts.createBlock(stmt.statements.map( - child => child.visitStatement(this, context.withStatementMode)))); + undefined, + ts.createBlock( + stmt.statements.map(child => child.visitStatement(this, context.withStatementMode)))); } visitExpressionStmt(stmt: ExpressionStatement, context: Context): ts.ExpressionStatement { @@ -194,7 +200,7 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor } visitReadVarExpr(ast: ReadVarExpr, context: Context): ts.Identifier { - const identifier = ts.createIdentifier(ast.name !); + const identifier = ts.createIdentifier(ast.name!); this.setSourceMapRange(identifier, ast); return identifier; } @@ -322,7 +328,7 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor return ts.createConditional( cond, ast.trueCase.visitExpression(this, context), - ast.falseCase !.visitExpression(this, context)); + ast.falseCase!.visitExpression(this, context)); } visitNotExpr(ast: NotExpr, context: Context): ts.PrefixUnaryExpression { @@ -352,7 +358,7 @@ class ExpressionTranslatorVisitor implements ExpressionVisitor, StatementVisitor throw new Error(`Unknown binary operator: ${BinaryOperator[ast.operator]}`); } return ts.createBinary( - ast.lhs.visitExpression(this, context), BINARY_OPERATORS.get(ast.operator) !, + ast.lhs.visitExpression(this, context), BINARY_OPERATORS.get(ast.operator)!, ast.rhs.visitExpression(this, context)); } @@ -537,13 +543,17 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { throw new Error('Method not implemented.'); } - visitNotExpr(ast: NotExpr, context: Context) { throw new Error('Method not implemented.'); } + visitNotExpr(ast: NotExpr, context: Context) { + throw new Error('Method not implemented.'); + } visitAssertNotNullExpr(ast: AssertNotNull, context: Context) { throw new Error('Method not implemented.'); } - visitCastExpr(ast: CastExpr, context: Context) { throw new Error('Method not implemented.'); } + visitCastExpr(ast: CastExpr, context: Context) { + throw new Error('Method not implemented.'); + } visitFunctionExpr(ast: FunctionExpr, context: Context) { throw new Error('Method not implemented.'); @@ -580,7 +590,9 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor { return ts.createTypeLiteralNode(entries); } - visitCommaExpr(ast: CommaExpr, context: Context) { throw new Error('Method not implemented.'); } + visitCommaExpr(ast: CommaExpr, context: Context) { + throw new Error('Method not implemented.'); + } visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: Context): ts.TypeNode { const node: ts.Node = ast.node; diff --git a/packages/compiler-cli/src/ngtsc/tsc_plugin.ts b/packages/compiler-cli/src/ngtsc/tsc_plugin.ts index d533b8a3ee3bf..660d48d132cd9 100644 --- a/packages/compiler-cli/src/ngtsc/tsc_plugin.ts +++ b/packages/compiler-cli/src/ngtsc/tsc_plugin.ts @@ -71,12 +71,14 @@ export class NgTscPlugin implements TscPlugin { return this._compiler; } - constructor(private ngOptions: {}) { setFileSystem(new NodeJSFileSystem()); } + constructor(private ngOptions: {}) { + setFileSystem(new NodeJSFileSystem()); + } wrapHost( host: ts.CompilerHost&UnifiedModulesHost, inputFiles: readonly string[], options: ts.CompilerOptions): PluginCompilerHost { - this.options = {...this.ngOptions, ...options } as NgCompilerOptions; + this.options = {...this.ngOptions, ...options} as NgCompilerOptions; this.host = NgCompilerHost.wrap(host, inputFiles, this.options); return this.host; } @@ -100,9 +102,15 @@ export class NgTscPlugin implements TscPlugin { return this.compiler.getDiagnostics(file); } - getOptionDiagnostics(): ts.Diagnostic[] { return this.compiler.getOptionDiagnostics(); } + getOptionDiagnostics(): ts.Diagnostic[] { + return this.compiler.getOptionDiagnostics(); + } - getNextProgram(): ts.Program { return this.compiler.getNextProgram(); } + getNextProgram(): ts.Program { + return this.compiler.getNextProgram(); + } - createTransformers(): ts.CustomTransformers { return this.compiler.prepareEmit().transformers; } + createTransformers(): ts.CustomTransformers { + return this.compiler.prepareEmit().transformers; + } } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts index 3134a3db8a189..f36f7983f0ab5 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/api.ts @@ -25,7 +25,7 @@ export interface TypeCheckableDirectiveMeta extends DirectiveMeta { hasNgTemplateContextGuard: boolean; } -export type TemplateId = string & {__brand: 'TemplateId'}; +export type TemplateId = string&{__brand: 'TemplateId'}; /** * Metadata required in addition to a component class in order to generate a type check block (TCB) @@ -233,7 +233,7 @@ export interface TypeCheckingConfig { export type TemplateSourceMapping = - DirectTemplateSourceMapping | IndirectTemplateSourceMapping | ExternalTemplateSourceMapping; + DirectTemplateSourceMapping|IndirectTemplateSourceMapping|ExternalTemplateSourceMapping; /** * A mapping to an inline template in a TS file. diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts index 1538b964a2aaa..58b866f0f9651 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts @@ -14,7 +14,7 @@ import {NoopImportRewriter, Reference, ReferenceEmitter} from '../../imports'; import {ClassDeclaration, ReflectionHost} from '../../reflection'; import {ImportManager} from '../../translator'; -import {TemplateSourceMapping, TypeCheckBlockMetadata, TypeCheckableDirectiveMeta, TypeCheckingConfig, TypeCtorMetadata} from './api'; +import {TemplateSourceMapping, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata, TypeCheckingConfig, TypeCtorMetadata} from './api'; import {shouldReportDiagnostic, translateDiagnostic} from './diagnostics'; import {DomSchemaChecker, RegistryDomSchemaChecker} from './dom'; import {Environment} from './environment'; @@ -125,7 +125,7 @@ export class TypeCheckContext { if (!this.opMap.has(sf)) { this.opMap.set(sf, []); } - const ops = this.opMap.get(sf) !; + const ops = this.opMap.get(sf)!; // Push a `TypeCtorOp` into the operation queue for the source file. ops.push(new TypeCtorOp(ref, ctorMeta)); @@ -152,7 +152,7 @@ export class TypeCheckContext { // Each Op has a splitPoint index into the text where it needs to be inserted. Split the // original source text into chunks at these split points, where code will be inserted between // the chunks. - const ops = this.opMap.get(sf) !.sort(orderOps); + const ops = this.opMap.get(sf)!.sort(orderOps); const textParts = splitStringAtPoints(sf.text, ops.map(op => op.splitPoint)); // Use a `ts.Printer` to generate source code. @@ -238,7 +238,7 @@ export class TypeCheckContext { if (!this.opMap.has(sf)) { this.opMap.set(sf, []); } - const ops = this.opMap.get(sf) !; + const ops = this.opMap.get(sf)!; ops.push(new TcbOp( ref, tcbMeta, this.config, this.reflector, this.domSchemaChecker, this.oobRecorder)); } @@ -278,7 +278,9 @@ class TcbOp implements Op { /** * Type check blocks are inserted immediately after the end of the component class. */ - get splitPoint(): number { return this.ref.node.end + 1; } + get splitPoint(): number { + return this.ref.node.end + 1; + } execute(im: ImportManager, sf: ts.SourceFile, refEmitter: ReferenceEmitter, printer: ts.Printer): string { @@ -301,7 +303,9 @@ class TypeCtorOp implements Op { /** * Type constructor operations are inserted immediately before the end of the directive class. */ - get splitPoint(): number { return this.ref.node.end - 1; } + get splitPoint(): number { + return this.ref.node.end - 1; + } execute(im: ImportManager, sf: ts.SourceFile, refEmitter: ReferenceEmitter, printer: ts.Printer): string { diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts index b65fa8d81810d..f5d847938e6d9 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts @@ -70,7 +70,7 @@ export function ignoreDiagnostics(node: ts.Node): void { * Adds a synthetic comment to the expression that represents the parse span of the provided node. * This comment can later be retrieved as trivia of a node to recover original source locations. */ -export function addParseSpanInfo(node: ts.Node, span: AbsoluteSourceSpan | ParseSourceSpan): void { +export function addParseSpanInfo(node: ts.Node, span: AbsoluteSourceSpan|ParseSourceSpan): void { let commentText: string; if (span instanceof AbsoluteSourceSpan) { commentText = `${span.start},${span.end}`; @@ -145,7 +145,7 @@ export function translateDiagnostic( */ export function makeTemplateDiagnostic( mapping: TemplateSourceMapping, span: ParseSourceSpan, category: ts.DiagnosticCategory, - code: number, messageText: string | ts.DiagnosticMessageChain, relatedMessage?: { + code: number, messageText: string|ts.DiagnosticMessageChain, relatedMessage?: { text: string, span: ParseSourceSpan, }): TemplateDiagnostic { @@ -172,7 +172,8 @@ export function makeTemplateDiagnostic( file: mapping.node.getSourceFile(), componentFile: mapping.node.getSourceFile(), start: span.start.offset, - length: span.end.offset - span.start.offset, relatedInformation, + length: span.end.offset - span.start.offset, + relatedInformation, }; } else if (mapping.type === 'indirect' || mapping.type === 'external') { // For indirect mappings (template was declared inline, but ngtsc couldn't map it directly diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts index 480577cbdc226..2e2bfe8631fce 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts @@ -12,7 +12,7 @@ import * as ts from 'typescript'; import {ErrorCode, ngErrorCode} from '../../diagnostics'; import {TemplateId} from './api'; -import {TemplateSourceResolver, makeTemplateDiagnostic} from './diagnostics'; +import {makeTemplateDiagnostic, TemplateSourceResolver} from './diagnostics'; const REGISTRY = new DomElementSchemaRegistry(); const REMOVE_XHTML_REGEX = /^:xhtml:/; @@ -66,7 +66,9 @@ export interface DomSchemaChecker { export class RegistryDomSchemaChecker implements DomSchemaChecker { private _diagnostics: ts.Diagnostic[] = []; - get diagnostics(): ReadonlyArray<ts.Diagnostic> { return this._diagnostics; } + get diagnostics(): ReadonlyArray<ts.Diagnostic> { + return this._diagnostics; + } constructor(private resolver: TemplateSourceResolver) {} @@ -83,8 +85,8 @@ export class RegistryDomSchemaChecker implements DomSchemaChecker { errorMsg += `1. If '${name}' is an Angular component, then verify that it is part of this module.\n`; if (name.indexOf('-') > -1) { - errorMsg += - `2. If '${name}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; + errorMsg += `2. If '${ + name}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; } else { errorMsg += `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; @@ -107,12 +109,16 @@ export class RegistryDomSchemaChecker implements DomSchemaChecker { `Can't bind to '${name}' since it isn't a known property of '${element.name}'.`; if (element.name.startsWith('ng-')) { errorMsg += - `\n1. If '${name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` + + `\n1. If '${ + name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` + `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; } else if (element.name.indexOf('-') > -1) { errorMsg += - `\n1. If '${element.name}' is an Angular component and it has '${name}' input, then verify that it is part of this module.` + - `\n2. If '${element.name}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` + + `\n1. If '${element.name}' is an Angular component and it has '${ + name}' input, then verify that it is part of this module.` + + `\n2. If '${ + element + .name}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` + `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts index 5f48a9c04b3c2..300616c47f17b 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/environment.ts @@ -59,7 +59,7 @@ export class Environment { const dirRef = dir.ref as Reference<ClassDeclaration<ts.ClassDeclaration>>; const node = dirRef.node; if (this.typeCtors.has(node)) { - return this.typeCtors.get(node) !; + return this.typeCtors.get(node)!; } if (requiresInlineTypeCtor(node, this.reflector)) { @@ -101,7 +101,7 @@ export class Environment { */ pipeInst(ref: Reference<ClassDeclaration<ts.ClassDeclaration>>): ts.Expression { if (this.pipeInsts.has(ref.node)) { - return this.pipeInsts.get(ref.node) !; + return this.pipeInsts.get(ref.node)!; } const pipeType = this.referenceType(ref); @@ -142,7 +142,8 @@ export class Environment { /* dotDotDotToken */ undefined, /* name */ 'cb', /* questionToken */ undefined, - /* type */ ts.createFunctionTypeNode( + /* type */ + ts.createFunctionTypeNode( /* typeParameters */ undefined, /* parameters */[ts.createParameter( /* decorators */ undefined, diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts index fd1fa179c77b3..0d7901332c090 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, ASTWithSource, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '@angular/compiler'; +import {AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, EmptyExpr, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralPrimitive, MethodCall, NonNullAssert, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead} from '@angular/compiler'; import * as ts from 'typescript'; import {TypeCheckingConfig} from './api'; @@ -103,7 +103,7 @@ class AstTranslator implements AstVisitor { } visitFunctionCall(ast: FunctionCall): ts.Expression { - const receiver = wrapForDiagnostics(this.translate(ast.target !)); + const receiver = wrapForDiagnostics(this.translate(ast.target!)); const args = ast.args.map(expr => this.translate(expr)); const node = ts.createCall(receiver, undefined, args); addParseSpanInfo(node, ast.sourceSpan); @@ -192,7 +192,9 @@ class AstTranslator implements AstVisitor { return node; } - visitPipe(ast: BindingPipe): never { throw new Error('Method not implemented.'); } + visitPipe(ast: BindingPipe): never { + throw new Error('Method not implemented.'); + } visitPrefixNot(ast: PrefixNot): ts.Expression { const expression = wrapForDiagnostics(this.translate(ast.expression)); @@ -221,7 +223,9 @@ class AstTranslator implements AstVisitor { return node; } - visitQuote(ast: Quote): never { throw new Error('Method not implemented.'); } + visitQuote(ast: Quote): never { + throw new Error('Method not implemented.'); + } visitSafeMethodCall(ast: SafeMethodCall): ts.Expression { // See the comments in SafePropertyRead above for an explanation of the cases here. @@ -296,28 +300,64 @@ class VeSafeLhsInferenceBugDetector implements AstVisitor { return ast.receiver.visit(VeSafeLhsInferenceBugDetector.SINGLETON); } - visitBinary(ast: Binary): boolean { return ast.left.visit(this) || ast.right.visit(this); } - visitChain(ast: Chain): boolean { return false; } + visitBinary(ast: Binary): boolean { + return ast.left.visit(this) || ast.right.visit(this); + } + visitChain(ast: Chain): boolean { + return false; + } visitConditional(ast: Conditional): boolean { return ast.condition.visit(this) || ast.trueExp.visit(this) || ast.falseExp.visit(this); } - visitFunctionCall(ast: FunctionCall): boolean { return true; } - visitImplicitReceiver(ast: ImplicitReceiver): boolean { return false; } + visitFunctionCall(ast: FunctionCall): boolean { + return true; + } + visitImplicitReceiver(ast: ImplicitReceiver): boolean { + return false; + } visitInterpolation(ast: Interpolation): boolean { return ast.expressions.some(exp => exp.visit(this)); } - visitKeyedRead(ast: KeyedRead): boolean { return false; } - visitKeyedWrite(ast: KeyedWrite): boolean { return false; } - visitLiteralArray(ast: LiteralArray): boolean { return true; } - visitLiteralMap(ast: LiteralMap): boolean { return true; } - visitLiteralPrimitive(ast: LiteralPrimitive): boolean { return false; } - visitMethodCall(ast: MethodCall): boolean { return true; } - visitPipe(ast: BindingPipe): boolean { return true; } - visitPrefixNot(ast: PrefixNot): boolean { return ast.expression.visit(this); } - visitNonNullAssert(ast: PrefixNot): boolean { return ast.expression.visit(this); } - visitPropertyRead(ast: PropertyRead): boolean { return false; } - visitPropertyWrite(ast: PropertyWrite): boolean { return false; } - visitQuote(ast: Quote): boolean { return false; } - visitSafeMethodCall(ast: SafeMethodCall): boolean { return true; } - visitSafePropertyRead(ast: SafePropertyRead): boolean { return false; } + visitKeyedRead(ast: KeyedRead): boolean { + return false; + } + visitKeyedWrite(ast: KeyedWrite): boolean { + return false; + } + visitLiteralArray(ast: LiteralArray): boolean { + return true; + } + visitLiteralMap(ast: LiteralMap): boolean { + return true; + } + visitLiteralPrimitive(ast: LiteralPrimitive): boolean { + return false; + } + visitMethodCall(ast: MethodCall): boolean { + return true; + } + visitPipe(ast: BindingPipe): boolean { + return true; + } + visitPrefixNot(ast: PrefixNot): boolean { + return ast.expression.visit(this); + } + visitNonNullAssert(ast: PrefixNot): boolean { + return ast.expression.visit(this); + } + visitPropertyRead(ast: PropertyRead): boolean { + return false; + } + visitPropertyWrite(ast: PropertyWrite): boolean { + return false; + } + visitQuote(ast: Quote): boolean { + return false; + } + visitSafeMethodCall(ast: SafeMethodCall): boolean { + return true; + } + visitSafePropertyRead(ast: SafePropertyRead): boolean { + return false; + } } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts index 8bbc0edd4c409..a1d68b541cc12 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/host.ts @@ -25,7 +25,7 @@ export class TypeCheckProgramHost implements ts.CompilerHost { this.sfMap = sfMap; if (delegate.getDirectories !== undefined) { - this.getDirectories = (path: string) => delegate.getDirectories !(path); + this.getDirectories = (path: string) => delegate.getDirectories!(path); } if (delegate.resolveModuleNames !== undefined) { @@ -69,7 +69,9 @@ export class TypeCheckProgramHost implements ts.CompilerHost { throw new Error(`TypeCheckProgramHost should never write files`); } - getCurrentDirectory(): string { return this.delegate.getCurrentDirectory(); } + getCurrentDirectory(): string { + return this.delegate.getCurrentDirectory(); + } getDirectories?: (path: string) => string[]; @@ -77,13 +79,19 @@ export class TypeCheckProgramHost implements ts.CompilerHost { return this.delegate.getCanonicalFileName(fileName); } - useCaseSensitiveFileNames(): boolean { return this.delegate.useCaseSensitiveFileNames(); } + useCaseSensitiveFileNames(): boolean { + return this.delegate.useCaseSensitiveFileNames(); + } - getNewLine(): string { return this.delegate.getNewLine(); } + getNewLine(): string { + return this.delegate.getNewLine(); + } fileExists(fileName: string): boolean { return this.sfMap.has(fileName) || this.delegate.fileExists(fileName); } - readFile(fileName: string): string|undefined { return this.delegate.readFile(fileName); } + readFile(fileName: string): string|undefined { + return this.delegate.readFile(fileName); + } } \ No newline at end of file diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts index 2f1a8b6e9c834..18ee794e6d96c 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts @@ -12,7 +12,7 @@ import * as ts from 'typescript'; import {ErrorCode, ngErrorCode} from '../../diagnostics'; import {TemplateId} from './api'; -import {TemplateSourceResolver, makeTemplateDiagnostic} from './diagnostics'; +import {makeTemplateDiagnostic, TemplateSourceResolver} from './diagnostics'; @@ -68,7 +68,9 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor constructor(private resolver: TemplateSourceResolver) {} - get diagnostics(): ReadonlyArray<ts.Diagnostic> { return this._diagnostics; } + get diagnostics(): ReadonlyArray<ts.Diagnostic> { + return this._diagnostics; + } missingReferenceTarget(templateId: TemplateId, ref: TmplAstReference): void { const mapping = this.resolver.getSourceMapping(templateId); @@ -97,8 +99,9 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor illegalAssignmentToTemplateVar( templateId: TemplateId, assignment: PropertyWrite, target: TmplAstVariable): void { const mapping = this.resolver.getSourceMapping(templateId); - const errorMsg = - `Cannot use variable '${assignment.name}' as the left-hand side of an assignment expression. Template variables are read-only.`; + const errorMsg = `Cannot use variable '${ + assignment + .name}' as the left-hand side of an assignment expression. Template variables are read-only.`; const sourceSpan = this.resolver.toParseSourceSpan(templateId, assignment.sourceSpan); if (sourceSpan === null) { @@ -115,8 +118,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor duplicateTemplateVar( templateId: TemplateId, variable: TmplAstVariable, firstDecl: TmplAstVariable): void { const mapping = this.resolver.getSourceMapping(templateId); - const errorMsg = - `Cannot redeclare variable '${variable.name}' as it was previously declared elsewhere for the same template.`; + const errorMsg = `Cannot redeclare variable '${ + variable.name}' as it was previously declared elsewhere for the same template.`; // The allocation of the error here is pretty useless for variables declared in microsyntax, // since the sourceSpan refers to the entire microsyntax property, not a span for the specific diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts index 22ea319fff4cc..9f37c36c19ceb 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts @@ -65,14 +65,14 @@ export class TemplateSourceManager implements TemplateSourceResolver { if (!this.templateSources.has(id)) { throw new Error(`Unexpected unknown template ID: ${id}`); } - return this.templateSources.get(id) !.mapping; + return this.templateSources.get(id)!.mapping; } toParseSourceSpan(id: TemplateId, span: AbsoluteSourceSpan): ParseSourceSpan|null { if (!this.templateSources.has(id)) { return null; } - const templateSource = this.templateSources.get(id) !; + const templateSource = this.templateSources.get(id)!; return templateSource.toParseSourceSpan(span.start, span.end); } } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts index 667957411a4ec..7911baacbdd87 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts @@ -6,17 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, BindingPipe, BindingType, BoundTarget, DYNAMIC_TYPE, ImplicitReceiver, MethodCall, ParseSourceSpan, ParsedEventType, PropertyRead, PropertyWrite, SchemaMetadata, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstReference, TmplAstTemplate, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler'; +import {AST, BindingPipe, BindingType, BoundTarget, DYNAMIC_TYPE, ImplicitReceiver, MethodCall, ParsedEventType, ParseSourceSpan, PropertyRead, PropertyWrite, SchemaMetadata, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstElement, TmplAstNode, TmplAstReference, TmplAstTemplate, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler'; import * as ts from 'typescript'; import {Reference} from '../../imports'; import {ClassDeclaration} from '../../reflection'; -import {TemplateId, TypeCheckBlockMetadata, TypeCheckableDirectiveMeta} from './api'; +import {TemplateId, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata} from './api'; import {addParseSpanInfo, addTemplateId, ignoreDiagnostics, wrapForDiagnostics} from './diagnostics'; import {DomSchemaChecker} from './dom'; import {Environment} from './environment'; -import {NULL_AS_ANY, astToTypescript} from './expression'; +import {astToTypescript, NULL_AS_ANY} from './expression'; import {OutOfBandDiagnosticRecorder} from './oob'; import {ExpressionSemanticVisitor} from './template_semantics'; import {checkIfClassIsExported, checkIfGenericTypesAreUnbound, tsCallMethod, tsCastToAny, tsCreateElement, tsCreateVariable, tsDeclareVariable} from './ts_util'; @@ -109,7 +109,9 @@ abstract class TcbOp { * `TcbOp` can be returned in cases where additional code generation is necessary to deal with * circular references. */ - circularFallback(): TcbOp|ts.Expression { return INFER_TYPE_FOR_CIRCULAR_OP_EXPR; } + circularFallback(): TcbOp|ts.Expression { + return INFER_TYPE_FOR_CIRCULAR_OP_EXPR; + } } /** @@ -170,7 +172,9 @@ class TcbVariableOp extends TcbOp { * Executing this operation returns a reference to the template's context variable. */ class TcbTemplateContextOp extends TcbOp { - constructor(private tcb: Context, private scope: Scope) { super(); } + constructor(private tcb: Context, private scope: Scope) { + super(); + } execute(): ts.Identifier { // Allocate a template ctx variable and declare it with an 'any' type. The type of this variable @@ -219,7 +223,7 @@ class TcbTemplateBodyOp extends TcbOp { // For each template guard function on the directive, look for a binding to that input. const boundInput = this.template.inputs.find(i => i.name === guard.inputName) || this.template.templateAttrs.find( - (i: TmplAstTextAttribute | TmplAstBoundAttribute): i is TmplAstBoundAttribute => + (i: TmplAstTextAttribute|TmplAstBoundAttribute): i is TmplAstBoundAttribute => i instanceof TmplAstBoundAttribute && i.name === guard.inputName); if (boundInput !== undefined) { // If there is such a binding, generate an expression for it. @@ -266,7 +270,7 @@ class TcbTemplateBodyOp extends TcbOp { guard = directiveGuards.reduce( (expr, dirGuard) => ts.createBinary(expr, ts.SyntaxKind.AmpersandAmpersandToken, dirGuard), - directiveGuards.pop() !); + directiveGuards.pop()!); } // Create a new Scope for the template. This constructs the list of operations for the template @@ -514,7 +518,7 @@ class TcbDirectiveOutputsOp extends TcbOp { if (output.type !== ParsedEventType.Regular || !fieldByEventName.has(output.name)) { continue; } - const field = fieldByEventName.get(output.name) !; + const field = fieldByEventName.get(output.name)!; if (this.tcb.env.config.checkTypeOfOutputEvents) { // For strict checking of directive events, generate a call to the `subscribe` method @@ -644,13 +648,15 @@ export class Context { * Currently this uses a monotonically increasing counter, but in the future the variable name * might change depending on the type of data being stored. */ - allocateId(): ts.Identifier { return ts.createIdentifier(`_t${this.nextId++}`); } + allocateId(): ts.Identifier { + return ts.createIdentifier(`_t${this.nextId++}`); + } getPipeByName(name: string): ts.Expression|null { if (!this.pipes.has(name)) { return null; } - return this.env.pipeInst(this.pipes.get(name) !); + return this.env.pipeInst(this.pipes.get(name)!); } } @@ -745,7 +751,7 @@ class Scope { if (!varMap.has(v.name)) { varMap.set(v.name, v); } else { - const firstDecl = varMap.get(v.name) !; + const firstDecl = varMap.get(v.name)!; tcb.oobRecorder.duplicateTemplateVar(tcb.id, v, firstDecl); } @@ -796,7 +802,9 @@ class Scope { /** * Add a statement to this scope. */ - addStatement(stmt: ts.Statement): void { this.statements.push(stmt); } + addStatement(stmt: ts.Statement): void { + this.statements.push(stmt); + } /** * Get the statements. @@ -840,26 +848,26 @@ class Scope { if (ref instanceof TmplAstVariable && this.varMap.has(ref)) { // Resolving a context variable for this template. // Execute the `TcbVariableOp` associated with the `TmplAstVariable`. - return this.resolveOp(this.varMap.get(ref) !); + return this.resolveOp(this.varMap.get(ref)!); } else if ( ref instanceof TmplAstTemplate && directive === undefined && this.templateCtxOpMap.has(ref)) { // Resolving the context of the given sub-template. // Execute the `TcbTemplateContextOp` for the template. - return this.resolveOp(this.templateCtxOpMap.get(ref) !); + return this.resolveOp(this.templateCtxOpMap.get(ref)!); } else if ( (ref instanceof TmplAstElement || ref instanceof TmplAstTemplate) && directive !== undefined && this.directiveOpMap.has(ref)) { // Resolving a directive on an element or sub-template. - const dirMap = this.directiveOpMap.get(ref) !; + const dirMap = this.directiveOpMap.get(ref)!; if (dirMap.has(directive)) { - return this.resolveOp(dirMap.get(directive) !); + return this.resolveOp(dirMap.get(directive)!); } else { return null; } } else if (ref instanceof TmplAstElement && this.elementOpMap.has(ref)) { // Resolving the DOM node of an element in this template. - return this.resolveOp(this.elementOpMap.get(ref) !); + return this.resolveOp(this.elementOpMap.get(ref)!); } else { return null; } @@ -1261,14 +1269,13 @@ function tcbCallTypeCtor( type TcbDirectiveInput = { type: 'binding'; field: string; expression: ts.Expression; sourceSpan: ParseSourceSpan; -} | -{ +}|{ type: 'unset'; field: string; }; function tcbGetDirectiveInputs( - el: TmplAstElement | TmplAstTemplate, dir: TypeCheckableDirectiveMeta, tcb: Context, + el: TmplAstElement|TmplAstTemplate, dir: TypeCheckableDirectiveMeta, tcb: Context, scope: Scope): TcbDirectiveInput[] { // Only the first binding to a property is written. // TODO(alxhub): produce an error for duplicate bindings to the same property, independently of @@ -1306,7 +1313,7 @@ function tcbGetDirectiveInputs( * Add a binding expression to the map for each input/template attribute of the directive that has * a matching binding. */ - function processAttribute(attr: TmplAstBoundAttribute | TmplAstTextAttribute): void { + function processAttribute(attr: TmplAstBoundAttribute|TmplAstTextAttribute): void { // Skip non-property bindings. if (attr instanceof TmplAstBoundAttribute && attr.type !== BindingType.Property) { return; @@ -1321,7 +1328,7 @@ function tcbGetDirectiveInputs( if (!propMatch.has(attr.name)) { return; } - const field = propMatch.get(attr.name) !; + const field = propMatch.get(attr.name)!; // Skip the attribute if a previous binding also wrote to it. if (directiveInputs.has(field)) { @@ -1369,7 +1376,7 @@ const enum EventParamType { */ function tcbCreateEventHandler( event: TmplAstBoundEvent, tcb: Context, scope: Scope, - eventType: EventParamType | ts.TypeNode): ts.Expression { + eventType: EventParamType|ts.TypeNode): ts.Expression { const handler = tcbEventHandlerExpression(event.handler, tcb, scope); let eventParamType: ts.TypeNode|undefined; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_file.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_file.ts index 5df3ab2fb8892..1b5f93f247408 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_file.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_file.ts @@ -78,7 +78,9 @@ export class TypeCheckFile extends Environment { this.fileName, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS); } - getPreludeStatements(): ts.Statement[] { return []; } + getPreludeStatements(): ts.Statement[] { + return []; + } } export function typeCheckFilePath(rootDirs: AbsoluteFsPath[]): AbsoluteFsPath { diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_constructor.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_constructor.ts index 55c559f6552ea..de5621bd2bf5f 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_constructor.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_constructor.ts @@ -15,8 +15,7 @@ import {TypeParameterEmitter} from './type_parameter_emitter'; export function generateTypeCtorDeclarationFn( node: ClassDeclaration<ts.ClassDeclaration>, meta: TypeCtorMetadata, nodeTypeRef: ts.EntityName, - typeParams: ts.TypeParameterDeclaration[] | undefined, - reflector: ReflectionHost): ts.Statement { + typeParams: ts.TypeParameterDeclaration[]|undefined, reflector: ReflectionHost): ts.Statement { if (requiresInlineTypeCtor(node, reflector)) { throw new Error(`${node.name.text} requires an inline type constructor`); } @@ -32,7 +31,8 @@ export function generateTypeCtorDeclarationFn( const fnType = ts.createFunctionTypeNode( /* typeParameters */ typeParameters, /* parameters */[initParam], - /* type */ rawType, ); + /* type */ rawType, + ); const decl = ts.createVariableDeclaration( /* name */ meta.fnName, @@ -121,7 +121,8 @@ export function generateInlineTypeCtor( /* typeParameters */ typeParametersWithDefaultTypes(node.typeParameters), /* parameters */[initParam], /* type */ rawType, - /* body */ body, ); + /* body */ body, + ); } function constructTypeCtorParameter( @@ -149,7 +150,8 @@ function constructTypeCtorParameter( /* modifiers */ undefined, /* name */ key, /* questionToken */ undefined, - /* type */ ts.createTypeQueryNode( + /* type */ + ts.createTypeQueryNode( ts.createQualifiedName(rawType.typeName, `ngAcceptInputType_${key}`)), /* initializer */ undefined)); } @@ -243,9 +245,8 @@ function checkIfGenericTypeBoundsAreContextFree( * * This correctly infers `T` as `any`, and therefore `_t3` as `NgFor<any>`. */ -function typeParametersWithDefaultTypes( - params: ReadonlyArray<ts.TypeParameterDeclaration>| undefined): ts.TypeParameterDeclaration[]| - undefined { +function typeParametersWithDefaultTypes(params: ReadonlyArray<ts.TypeParameterDeclaration>| + undefined): ts.TypeParameterDeclaration[]|undefined { if (params === undefined) { return undefined; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_emitter.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_emitter.ts index 877235ef4b160..a1befba5933d6 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_emitter.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_emitter.ts @@ -12,7 +12,7 @@ import {Reference} from '../../imports'; * A resolved type reference can either be a `Reference`, the original `ts.TypeReferenceNode` itself * or null to indicate the no reference could be resolved. */ -export type ResolvedTypeReference = Reference | ts.TypeReferenceNode | null; +export type ResolvedTypeReference = Reference|ts.TypeReferenceNode|null; /** * A type reference resolver function is responsible for finding the declaration of the type @@ -111,7 +111,9 @@ export class TypeEmitter { visitTypeReferenceNode: type => this.emitTypeReference(type), visitArrayTypeNode: type => ts.updateArrayTypeNode(type, this.emitType(type.elementType)), visitKeywordType: type => type, - visitOtherType: () => { throw new Error('Unable to emit a complex type'); }, + visitOtherType: () => { + throw new Error('Unable to emit a complex type'); + }, }); } @@ -137,8 +139,8 @@ export class TypeEmitter { const emittedType = this.emitReference(reference); if (!ts.isTypeReferenceNode(emittedType)) { - throw new Error( - `Expected TypeReferenceNode for emitted reference, got ${ts.SyntaxKind[emittedType.kind]}`); + throw new Error(`Expected TypeReferenceNode for emitted reference, got ${ + ts.SyntaxKind[emittedType.kind]}`); } typeName = emittedType.typeName; diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts index 20d6bf1b18b5d..bf57f7280378f 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {OwningModule, Reference} from '../../imports'; import {ReflectionHost} from '../../reflection'; -import {ResolvedTypeReference, TypeEmitter, canEmitType} from './type_emitter'; +import {canEmitType, ResolvedTypeReference, TypeEmitter} from './type_emitter'; /** @@ -92,6 +92,6 @@ export class TypeParameterEmitter { private isLocalTypeParameter(decl: ts.Declaration): boolean { // Checking for local type parameters only occurs during resolution of type parameters, so it is // guaranteed that type parameters are present. - return this.typeParameters !.some(param => param === decl); + return this.typeParameters!.some(param => param === decl); } } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/diagnostics_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/diagnostics_spec.ts index 1c281971de3d9..c691989bb98c5 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/diagnostics_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/diagnostics_spec.ts @@ -8,10 +8,10 @@ import * as ts from 'typescript'; -import {TestFile, runInEachFileSystem} from '../../file_system/testing'; +import {runInEachFileSystem, TestFile} from '../../file_system/testing'; import {TypeCheckingConfig} from '../src/api'; -import {TestDeclaration, ngForDeclaration, ngForDts, typecheck} from './test_utils'; +import {ngForDeclaration, ngForDts, TestDeclaration, typecheck} from './test_utils'; runInEachFileSystem(() => { describe('template diagnostics', () => { @@ -377,8 +377,8 @@ function diagnose( return diagnostics.map(diag => { const text = typeof diag.messageText === 'string' ? diag.messageText : diag.messageText.messageText; - const fileName = diag.file !.fileName; - const {line, character} = ts.getLineAndCharacterOfPosition(diag.file !, diag.start !); + const fileName = diag.file!.fileName; + const {line, character} = ts.getLineAndCharacterOfPosition(diag.file!, diag.start!); return `${fileName}(${line + 1}, ${character + 1}): ${text}`; }); } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/span_comments_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/span_comments_spec.ts index 1f1a35a0589a6..81279b37bb289 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/span_comments_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/span_comments_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {TestDeclaration, tcb} from './test_utils'; +import {tcb, TestDeclaration} from './test_utils'; describe('type check blocks diagnostics', () => { describe('parse spans', () => { diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts index da668db467468..89d7d5c0b26a8 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/test_utils.ts @@ -6,16 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ -import {CssSelector, ParseSourceFile, ParseSourceSpan, R3TargetBinder, SchemaMetadata, SelectorMatcher, TmplAstElement, TmplAstReference, Type, parseTemplate} from '@angular/compiler'; +import {CssSelector, ParseSourceFile, ParseSourceSpan, parseTemplate, R3TargetBinder, SchemaMetadata, SelectorMatcher, TmplAstElement, TmplAstReference, Type} from '@angular/compiler'; import * as ts from 'typescript'; -import {AbsoluteFsPath, LogicalFileSystem, absoluteFrom} from '../../file_system'; +import {absoluteFrom, AbsoluteFsPath, LogicalFileSystem} from '../../file_system'; import {TestFile} from '../../file_system/testing'; import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, Reference, ReferenceEmitter} from '../../imports'; -import {ClassDeclaration, TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {ClassDeclaration, isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {makeProgram} from '../../testing'; import {getRootDirs} from '../../util/src/typescript'; -import {TemplateId, TemplateSourceMapping, TypeCheckBlockMetadata, TypeCheckableDirectiveMeta, TypeCheckingConfig} from '../src/api'; +import {TemplateId, TemplateSourceMapping, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata, TypeCheckingConfig} from '../src/api'; import {TypeCheckContext} from '../src/context'; import {DomSchemaChecker} from '../src/dom'; import {Environment} from '../src/environment'; @@ -168,23 +168,20 @@ export const ALL_ENABLED_CONFIG: TypeCheckingConfig = { }; // Remove 'ref' from TypeCheckableDirectiveMeta and add a 'selector' instead. -export type TestDirective = - Partial<Pick< - TypeCheckableDirectiveMeta, - Exclude<keyof TypeCheckableDirectiveMeta, 'ref'|'coercedInputFields'>>>& - { - selector: string, - name: string, file?: AbsoluteFsPath, - type: 'directive', coercedInputFields?: string[], - }; +export type TestDirective = Partial<Pick< + TypeCheckableDirectiveMeta, + Exclude<keyof TypeCheckableDirectiveMeta, 'ref'|'coercedInputFields'>>>&{ + selector: string, + name: string, + file?: AbsoluteFsPath, type: 'directive', + coercedInputFields?: string[], +}; export type TestPipe = { name: string, - file?: AbsoluteFsPath, - pipeName: string, - type: 'pipe', + file?: AbsoluteFsPath, pipeName: string, type: 'pipe', }; -export type TestDeclaration = TestDirective | TestPipe; +export type TestDeclaration = TestDirective|TestPipe; export function tcb( template: string, declarations: TestDeclaration[] = [], config?: TypeCheckingConfig, @@ -252,7 +249,7 @@ export function typecheck( ]; const {program, host, options} = makeProgram(files, {strictNullChecks: true, noImplicitAny: true, ...opts}, undefined, false); - const sf = program.getSourceFile(absoluteFrom('/main.ts')) !; + const sf = program.getSourceFile(absoluteFrom('/main.ts'))!; const checker = program.getTypeChecker(); const logicalFs = new LogicalFileSystem(getRootDirs(host, options)); const reflectionHost = new TypeScriptReflectionHost(checker); @@ -277,7 +274,7 @@ export function typecheck( const {matcher, pipes} = prepareDeclarations(declarations, decl => { let declFile = sf; if (decl.file !== undefined) { - declFile = program.getSourceFile(decl.file) !; + declFile = program.getSourceFile(decl.file)!; if (declFile === undefined) { throw new Error(`Unable to locate ${decl.file} for ${decl.type} ${decl.name}`); } @@ -356,7 +353,9 @@ class FakeEnvironment /* implements Environment */ { return ts.createParen(ts.createAsExpression(ts.createNull(), this.referenceType(ref))); } - declareOutputHelper(): ts.Expression { return ts.createIdentifier('_outputHelper'); } + declareOutputHelper(): ts.Expression { + return ts.createIdentifier('_outputHelper'); + } reference(ref: Reference<ClassDeclaration<ts.ClassDeclaration>>): ts.Expression { return ref.node.name; @@ -379,7 +378,9 @@ class FakeEnvironment /* implements Environment */ { return ts.createTypeReferenceNode(qName, typeArgs.length > 0 ? typeArgs : undefined); } - getPreludeStatements(): ts.Statement[] { return []; } + getPreludeStatements(): ts.Statement[] { + return []; + } static newFake(config: TypeCheckingConfig): Environment { return new FakeEnvironment(config) as Environment; @@ -387,7 +388,9 @@ class FakeEnvironment /* implements Environment */ { } export class NoopSchemaChecker implements DomSchemaChecker { - get diagnostics(): ReadonlyArray<ts.Diagnostic> { return []; } + get diagnostics(): ReadonlyArray<ts.Diagnostic> { + return []; + } checkElement(id: string, element: TmplAstElement, schemas: SchemaMetadata[]): void {} checkProperty( @@ -396,7 +399,9 @@ export class NoopSchemaChecker implements DomSchemaChecker { } export class NoopOobRecorder implements OutOfBandDiagnosticRecorder { - get diagnostics(): ReadonlyArray<ts.Diagnostic> { return []; } + get diagnostics(): ReadonlyArray<ts.Diagnostic> { + return []; + } missingReferenceTarget(): void {} missingPipe(): void {} illegalAssignmentToTemplateVar(): void {} diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts index 05d9d4cbe4b9d..f69af3763b959 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_check_block_spec.ts @@ -8,12 +8,13 @@ import {TypeCheckingConfig} from '../src/api'; -import {ALL_ENABLED_CONFIG, TestDeclaration, TestDirective, tcb} from './test_utils'; +import {ALL_ENABLED_CONFIG, tcb, TestDeclaration, TestDirective} from './test_utils'; describe('type check blocks', () => { - it('should generate a basic block for a binding', - () => { expect(tcb('{{hello}} {{world}}')).toContain('"" + (ctx).hello + (ctx).world;'); }); + it('should generate a basic block for a binding', () => { + expect(tcb('{{hello}} {{world}}')).toContain('"" + (ctx).hello + (ctx).world;'); + }); it('should generate literal map expressions', () => { const TEMPLATE = '{{ method({foo: a, bar: b}) }}'; @@ -264,7 +265,6 @@ describe('type check blocks', () => { }); describe('outputs', () => { - it('should emit subscribe calls for directive outputs', () => { const DIRECTIVES: TestDeclaration[] = [{ type: 'directive', @@ -305,7 +305,6 @@ describe('type check blocks', () => { expect(block).toContain( '_t3.addEventListener("event", function ($event): any { (_t2 = 3); });'); }); - }); describe('config', () => { @@ -385,7 +384,6 @@ describe('type check blocks', () => { }); describe('config.checkTypeOfBindings', () => { - it('should check types of bindings when enabled', () => { const TEMPLATE = `<div dir [dirInput]="a" [nonDirInput]="b"></div>`; const block = tcb(TEMPLATE, DIRECTIVES); diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts index 0dbcd2f9bd238..9f9e1e141c075 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_constructor_spec.ts @@ -6,14 +6,16 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; -import {LogicalFileSystem, absoluteFrom, getSourceFileOrError} from '../../file_system'; -import {TestFile, runInEachFileSystem} from '../../file_system/testing'; + +import {absoluteFrom, getSourceFileOrError, LogicalFileSystem} from '../../file_system'; +import {runInEachFileSystem, TestFile} from '../../file_system/testing'; import {AbsoluteModuleStrategy, LocalIdentifierStrategy, LogicalProjectStrategy, ModuleResolver, Reference, ReferenceEmitter} from '../../imports'; -import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; import {getRootDirs} from '../../util/src/typescript'; import {TypeCheckContext} from '../src/context'; import {TypeCheckFile} from '../src/type_check_file'; + import {ALL_ENABLED_CONFIG} from './test_utils'; runInEachFileSystem(() => { @@ -42,7 +44,7 @@ runInEachFileSystem(() => { it('should not produce an empty SourceFile when there is nothing to typecheck', () => { const file = new TypeCheckFile( _('/_typecheck_.ts'), ALL_ENABLED_CONFIG, new ReferenceEmitter([]), - /* reflector */ null !); + /* reflector */ null!); const sf = file.render(); expect(sf.statements.length).toBe(1); }); @@ -126,7 +128,7 @@ TestClass.ngTypeCtor({value: 'test'}); const res = ctx.calculateTemplateDiagnostics(program, host, options); const TestClassWithCtor = getDeclaration(res.program, _('/main.ts'), 'TestClass', isNamedClassDeclaration); - const typeCtor = TestClassWithCtor.members.find(isTypeCtor) !; + const typeCtor = TestClassWithCtor.members.find(isTypeCtor)!; expect(typeCtor.getText()).not.toContain('queryField'); }); }); @@ -168,7 +170,7 @@ TestClass.ngTypeCtor({value: 'test'}); const res = ctx.calculateTemplateDiagnostics(program, host, options); const TestClassWithCtor = getDeclaration(res.program, _('/main.ts'), 'TestClass', isNamedClassDeclaration); - const typeCtor = TestClassWithCtor.members.find(isTypeCtor) !; + const typeCtor = TestClassWithCtor.members.find(isTypeCtor)!; const ctorText = typeCtor.getText().replace(/[ \r\n]+/g, ' '); expect(ctorText).toContain( 'init: Pick<TestClass, "foo"> | { bar: typeof TestClass.ngAcceptInputType_bar; }'); diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts index 099573ebb26ba..5d80d09a01b38 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts @@ -8,16 +8,16 @@ import * as ts from 'typescript'; import {absoluteFrom} from '../../file_system'; -import {TestFile, runInEachFileSystem} from '../../file_system/testing'; -import {TypeScriptReflectionHost, isNamedClassDeclaration} from '../../reflection'; +import {runInEachFileSystem, TestFile} from '../../file_system/testing'; +import {isNamedClassDeclaration, TypeScriptReflectionHost} from '../../reflection'; import {getDeclaration, makeProgram} from '../../testing'; import {TypeParameterEmitter} from '../src/type_parameter_emitter'; + import {angularCoreDts} from './test_utils'; runInEachFileSystem(() => { describe('type parameter emitter', () => { - function createEmitter(source: string, additionalFiles: TestFile[] = []) { const files: TestFile[] = [ angularCoreDts(), {name: absoluteFrom('/main.ts'), contents: source}, ...additionalFiles @@ -34,7 +34,7 @@ runInEachFileSystem(() => { function emit(emitter: TypeParameterEmitter) { const emitted = emitter.emit(ref => { - const typeName = ts.createQualifiedName(ts.createIdentifier('test'), ref.debugName !); + const typeName = ts.createQualifiedName(ts.createIdentifier('test'), ref.debugName!); return ts.createTypeReferenceNode(typeName, /* typeArguments */ undefined); }); @@ -209,6 +209,5 @@ runInEachFileSystem(() => { expect(emitter.canEmit()).toBe(true); expect(emit(emitter)).toEqual('<T extends test.MyType>'); }); - }); }); diff --git a/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts b/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts index ede59091e10a2..83148904e72d3 100644 --- a/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts +++ b/packages/compiler-cli/src/ngtsc/util/src/ts_source_map_bug_29300.ts @@ -29,16 +29,38 @@ export function tsSourceMapBug29300Fixed() { const sourceFile = ts.createSourceFile('test.ts', 'a;', ts.ScriptTarget.ES2015, true, ts.ScriptKind.TS); const host = { - getSourceFile(): ts.SourceFile | undefined{return sourceFile;}, - fileExists(): boolean{return true;}, - readFile(): string | undefined{return '';}, - writeFile(fileName: string, data: string) { writtenFiles[fileName] = data; }, - getDefaultLibFileName(): string{return '';}, - getCurrentDirectory(): string{return '';}, - getDirectories(): string[]{return [];}, - getCanonicalFileName(): string{return '';}, - useCaseSensitiveFileNames(): boolean{return true;}, - getNewLine(): string{return '\n';}, + getSourceFile(): ts.SourceFile | + undefined { + return sourceFile; + }, + fileExists(): boolean { + return true; + }, + readFile(): string | + undefined { + return ''; + }, + writeFile(fileName: string, data: string) { + writtenFiles[fileName] = data; + }, + getDefaultLibFileName(): string { + return ''; + }, + getCurrentDirectory(): string { + return ''; + }, + getDirectories(): string[] { + return []; + }, + getCanonicalFileName(): string { + return ''; + }, + useCaseSensitiveFileNames(): boolean { + return true; + }, + getNewLine(): string { + return '\n'; + }, }; const transform = (context: ts.TransformationContext) => { diff --git a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts index 68e71b5673748..dc38c2a96c6c2 100644 --- a/packages/compiler-cli/src/ngtsc/util/src/typescript.ts +++ b/packages/compiler-cli/src/ngtsc/util/src/typescript.ts @@ -28,7 +28,7 @@ export function isFromDtsFile(node: ts.Node): boolean { return sf !== undefined && sf.isDeclarationFile; } -export function nodeNameForError(node: ts.Node & {name?: ts.Node}): string { +export function nodeNameForError(node: ts.Node&{name?: ts.Node}): string { if (node.name !== undefined && ts.isIdentifier(node.name)) { return node.name.text; } else { @@ -58,7 +58,7 @@ export function getTokenAtPosition(sf: ts.SourceFile, pos: number): ts.Node { return (ts as any).getTokenAtPosition(sf, pos); } -export function identifierOfNode(decl: ts.Node & {name?: ts.Node}): ts.Identifier|null { +export function identifierOfNode(decl: ts.Node&{name?: ts.Node}): ts.Identifier|null { if (decl.name !== undefined && ts.isIdentifier(decl.name)) { return decl.name; } else { @@ -123,7 +123,7 @@ export function nodeDebugInfo(node: ts.Node): string { export function resolveModuleName( moduleName: string, containingFile: string, compilerOptions: ts.CompilerOptions, compilerHost: ts.CompilerHost, - moduleResolutionCache: ts.ModuleResolutionCache | null): ts.ResolvedModule|undefined { + moduleResolutionCache: ts.ModuleResolutionCache|null): ts.ResolvedModule|undefined { if (compilerHost.resolveModuleNames) { // FIXME: Additional parameters are required in TS3.6, but ignored in 3.5. // Remove the any cast once google3 is fully on TS3.6. diff --git a/packages/compiler-cli/src/ngtsc/util/src/visitor.ts b/packages/compiler-cli/src/ngtsc/util/src/visitor.ts index 2c96f9304c968..fe2ac3377c792 100644 --- a/packages/compiler-cli/src/ngtsc/util/src/visitor.ts +++ b/packages/compiler-cli/src/ngtsc/util/src/visitor.ts @@ -68,7 +68,9 @@ export abstract class Visitor { /** * Visit types of nodes which don't have their own explicit visitor. */ - visitOtherNode<T extends ts.Node>(node: T): T { return node; } + visitOtherNode<T extends ts.Node>(node: T): T { + return node; + } /** * @internal @@ -81,8 +83,9 @@ export abstract class Visitor { node = ts.visitEachChild(node, child => this._visit(child, context), context) as T; if (ts.isClassDeclaration(node)) { - visitedNode = this._visitListEntryNode( - node, (node: ts.ClassDeclaration) => this.visitClassDeclaration(node)) as typeof node; + visitedNode = + this._visitListEntryNode( + node, (node: ts.ClassDeclaration) => this.visitClassDeclaration(node)) as typeof node; } else { visitedNode = this.visitOtherNode(node); } @@ -111,12 +114,12 @@ export abstract class Visitor { const newStatements: ts.Statement[] = []; clone.statements.forEach(stmt => { if (this._before.has(stmt)) { - newStatements.push(...(this._before.get(stmt) !as ts.Statement[])); + newStatements.push(...(this._before.get(stmt)! as ts.Statement[])); this._before.delete(stmt); } newStatements.push(stmt); if (this._after.has(stmt)) { - newStatements.push(...(this._after.get(stmt) !as ts.Statement[])); + newStatements.push(...(this._after.get(stmt)! as ts.Statement[])); this._after.delete(stmt); } }); @@ -126,6 +129,6 @@ export abstract class Visitor { } function hasStatements(node: ts.Node): node is ts.Node&{statements: ts.NodeArray<ts.Statement>} { - const block = node as{statements?: any}; + const block = node as {statements?: any}; return block.statements !== undefined && Array.isArray(block.statements); } diff --git a/packages/compiler-cli/src/ngtsc/util/test/visitor_spec.ts b/packages/compiler-cli/src/ngtsc/util/test/visitor_spec.ts index 7ecbc89aa2f2d..c875cc8ddb200 100644 --- a/packages/compiler-cli/src/ngtsc/util/test/visitor_spec.ts +++ b/packages/compiler-cli/src/ngtsc/util/test/visitor_spec.ts @@ -6,22 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ import * as ts from 'typescript'; + import {absoluteFrom, getSourceFileOrError} from '../../file_system'; import {runInEachFileSystem} from '../../file_system/testing'; import {makeProgram} from '../../testing'; -import {VisitListEntryResult, Visitor, visit} from '../src/visitor'; +import {visit, VisitListEntryResult, Visitor} from '../src/visitor'; class TestAstVisitor extends Visitor { visitClassDeclaration(node: ts.ClassDeclaration): VisitListEntryResult<ts.Statement, ts.ClassDeclaration> { - const name = node.name !.text; - const statics = - node.members.filter(member => (member.modifiers as ReadonlyArray<ts.Modifier>|| [ - ]).some(mod => mod.kind === ts.SyntaxKind.StaticKeyword)); - const idStatic = statics - .find( - el => ts.isPropertyDeclaration(el) && ts.isIdentifier(el.name) && - el.name.text === 'id') as ts.PropertyDeclaration | + const name = node.name!.text; + const statics = node.members.filter( + member => (member.modifiers as ReadonlyArray<ts.Modifier>|| + []).some(mod => mod.kind === ts.SyntaxKind.StaticKeyword)); + const idStatic = statics.find( + el => ts.isPropertyDeclaration(el) && ts.isIdentifier(el.name) && + el.name.text === 'id') as ts.PropertyDeclaration | undefined; if (idStatic !== undefined) { return { diff --git a/packages/compiler-cli/src/perform_compile.ts b/packages/compiler-cli/src/perform_compile.ts index b746e6ced5d9d..5456d2f0e4bad 100644 --- a/packages/compiler-cli/src/perform_compile.ts +++ b/packages/compiler-cli/src/perform_compile.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Position, isSyntaxError} from '@angular/compiler'; +import {isSyntaxError, Position} from '@angular/compiler'; import * as ts from 'typescript'; -import {AbsoluteFsPath, absoluteFrom, getFileSystem, relative, resolve} from '../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, getFileSystem, relative, resolve} from '../src/ngtsc/file_system'; import {replaceTsWithNgInErrors} from './ngtsc/diagnostics'; import * as api from './transformers/api'; @@ -35,7 +35,7 @@ function displayFileName(fileName: string, host: ts.FormatDiagnosticsHost): stri export function formatDiagnosticPosition( position: Position, host: ts.FormatDiagnosticsHost = defaultFormatHost): string { - return `${displayFileName(position.fileName, host)}(${position.line + 1},${position.column+1})`; + return `${displayFileName(position.fileName, host)}(${position.line + 1},${position.column + 1})`; } export function flattenDiagnosticMessageChain( @@ -73,11 +73,10 @@ export function formatDiagnostic( const newLine = host.getNewLine(); const span = diagnostic.span; if (span) { - result += `${formatDiagnosticPosition({ - fileName: span.start.file.url, - line: span.start.line, - column: span.start.col - }, host)}: `; + result += `${ + formatDiagnosticPosition( + {fileName: span.start.file.url, line: span.start.line, column: span.start.col}, + host)}: `; } else if (diagnostic.position) { result += `${formatDiagnosticPosition(diagnostic.position, host)}: `; } @@ -156,8 +155,10 @@ export function readConfiguration( // other options like 'compilerOptions' are merged by TS const baseConfig = existingConfig || config; if (existingConfig) { - baseConfig.angularCompilerOptions = {...config.angularCompilerOptions, - ...baseConfig.angularCompilerOptions}; + baseConfig.angularCompilerOptions = { + ...config.angularCompilerOptions, + ...baseConfig.angularCompilerOptions + }; } if (config.extends) { @@ -223,7 +224,7 @@ export interface PerformCompilationResult { emitResult?: ts.EmitResult; } -export function exitCodeFromResult(diags: Diagnostics | undefined): number { +export function exitCodeFromResult(diags: Diagnostics|undefined): number { if (!diags || filterErrorsAndWarnings(diags).length === 0) { // If we have a result and didn't get any errors, we succeeded. return 0; @@ -233,21 +234,29 @@ export function exitCodeFromResult(diags: Diagnostics | undefined): number { return diags.some(d => d.source === 'angular' && d.code === api.UNKNOWN_ERROR_CODE) ? 2 : 1; } -export function performCompilation( - {rootNames, options, host, oldProgram, emitCallback, mergeEmitResultsCallback, - gatherDiagnostics = defaultGatherDiagnostics, customTransformers, - emitFlags = api.EmitFlags.Default, modifiedResourceFiles = null}: { - rootNames: string[], - options: api.CompilerOptions, - host?: api.CompilerHost, - oldProgram?: api.Program, - emitCallback?: api.TsEmitCallback, - mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback, - gatherDiagnostics?: (program: api.Program) => Diagnostics, - customTransformers?: api.CustomTransformers, - emitFlags?: api.EmitFlags, - modifiedResourceFiles?: Set<string>| null, - }): PerformCompilationResult { +export function performCompilation({ + rootNames, + options, + host, + oldProgram, + emitCallback, + mergeEmitResultsCallback, + gatherDiagnostics = defaultGatherDiagnostics, + customTransformers, + emitFlags = api.EmitFlags.Default, + modifiedResourceFiles = null +}: { + rootNames: string[], + options: api.CompilerOptions, + host?: api.CompilerHost, + oldProgram?: api.Program, + emitCallback?: api.TsEmitCallback, + mergeEmitResultsCallback?: api.TsMergeEmitResultsCallback, + gatherDiagnostics?: (program: api.Program) => Diagnostics, + customTransformers?: api.CustomTransformers, + emitFlags?: api.EmitFlags, + modifiedResourceFiles?: Set<string>| null, +}): PerformCompilationResult { let program: api.Program|undefined; let emitResult: ts.EmitResult|undefined; let allDiagnostics: Array<ts.Diagnostic|api.Diagnostic> = []; @@ -262,7 +271,7 @@ export function performCompilation( program = ng.createProgram({rootNames, host, options, oldProgram}); const beforeDiags = Date.now(); - allDiagnostics.push(...gatherDiagnostics(program !)); + allDiagnostics.push(...gatherDiagnostics(program!)); if (options.diagnostics) { const afterDiags = Date.now(); allDiagnostics.push( @@ -271,7 +280,7 @@ export function performCompilation( if (!hasErrors(allDiagnostics)) { emitResult = - program !.emit({emitCallback, mergeEmitResultsCallback, customTransformers, emitFlags}); + program!.emit({emitCallback, mergeEmitResultsCallback, customTransformers, emitFlags}); allDiagnostics.push(...emitResult.diagnostics); return {diagnostics: allDiagnostics, program, emitResult}; } @@ -297,7 +306,7 @@ export function performCompilation( export function defaultGatherDiagnostics(program: api.Program): Diagnostics { const allDiagnostics: Array<ts.Diagnostic|api.Diagnostic> = []; - function checkDiagnostics(diags: Diagnostics | undefined) { + function checkDiagnostics(diags: Diagnostics|undefined) { if (diags) { allDiagnostics.push(...diags); return !hasErrors(diags); diff --git a/packages/compiler-cli/src/perform_watch.ts b/packages/compiler-cli/src/perform_watch.ts index 2d406686ace5d..36aa3e6a664f8 100644 --- a/packages/compiler-cli/src/perform_watch.ts +++ b/packages/compiler-cli/src/perform_watch.ts @@ -10,7 +10,7 @@ import * as chokidar from 'chokidar'; import * as path from 'path'; import * as ts from 'typescript'; -import {Diagnostics, ParsedConfiguration, PerformCompilationResult, exitCodeFromResult, performCompilation, readConfiguration} from './perform_compile'; +import {Diagnostics, exitCodeFromResult, ParsedConfiguration, performCompilation, PerformCompilationResult, readConfiguration} from './perform_compile'; import * as api from './transformers/api'; import {createCompilerHost} from './transformers/entry_points'; import {createMessageDiagnostic} from './transformers/util'; @@ -50,8 +50,9 @@ export interface PerformWatchHost { export function createPerformWatchHost( configFileName: string, reportDiagnostics: (diagnostics: Diagnostics) => void, - existingOptions?: ts.CompilerOptions, createEmitCallback?: (options: api.CompilerOptions) => - api.TsEmitCallback | undefined): PerformWatchHost { + existingOptions?: ts.CompilerOptions, + createEmitCallback?: (options: api.CompilerOptions) => + api.TsEmitCallback | undefined): PerformWatchHost { return { reportDiagnostics: reportDiagnostics, createCompilerHost: options => createCompilerHost({options}), @@ -130,7 +131,7 @@ export function performWatchCompilation(host: PerformWatchHost): // Note: ! is ok as options are filled after the first compilation // Note: ! is ok as resolvedReadyPromise is filled by the previous call const fileWatcher = - host.onFileChange(cachedOptions !.options, watchedFileChanged, resolveReadyPromise !); + host.onFileChange(cachedOptions!.options, watchedFileChanged, resolveReadyPromise!); return {close, ready: cb => readyPromise.then(cb), firstCompileResult}; @@ -177,7 +178,7 @@ export function performWatchCompilation(host: PerformWatchHost): if (ce.exists == null) { ce.exists = originalFileExists.call(this, fileName); } - return ce.exists !; + return ce.exists!; }; const originalGetSourceFile = cachedCompilerHost.getSourceFile; cachedCompilerHost.getSourceFile = function( @@ -186,7 +187,7 @@ export function performWatchCompilation(host: PerformWatchHost): if (!ce.sf) { ce.sf = originalGetSourceFile.call(this, fileName, languageVersion); } - return ce.sf !; + return ce.sf!; }; const originalReadFile = cachedCompilerHost.readFile; cachedCompilerHost.readFile = function(fileName: string) { @@ -194,7 +195,7 @@ export function performWatchCompilation(host: PerformWatchHost): if (ce.content == null) { ce.content = originalReadFile.call(this, fileName); } - return ce.content !; + return ce.content!; }; // Provide access to the file paths that triggered this rebuild cachedCompilerHost.getModifiedResourceFiles = function() { diff --git a/packages/compiler-cli/src/transformers/api.ts b/packages/compiler-cli/src/transformers/api.ts index 17da6f47d3739..bde02a1a289f4 100644 --- a/packages/compiler-cli/src/transformers/api.ts +++ b/packages/compiler-cli/src/transformers/api.ts @@ -190,8 +190,12 @@ export interface TsEmitArguments { customTransformers?: ts.CustomTransformers; } -export interface TsEmitCallback { (args: TsEmitArguments): ts.EmitResult; } -export interface TsMergeEmitResultsCallback { (results: ts.EmitResult[]): ts.EmitResult; } +export interface TsEmitCallback { + (args: TsEmitArguments): ts.EmitResult; +} +export interface TsMergeEmitResultsCallback { + (results: ts.EmitResult[]): ts.EmitResult; +} export interface LibrarySummary { fileName: string; @@ -283,14 +287,14 @@ export interface Program { * * Angular structural information is required to emit files. */ - emit({emitFlags, cancellationToken, customTransformers, emitCallback, - mergeEmitResultsCallback}?: { - emitFlags?: EmitFlags, - cancellationToken?: ts.CancellationToken, - customTransformers?: CustomTransformers, - emitCallback?: TsEmitCallback, - mergeEmitResultsCallback?: TsMergeEmitResultsCallback - }): ts.EmitResult; + emit({emitFlags, cancellationToken, customTransformers, emitCallback, mergeEmitResultsCallback}?: + { + emitFlags?: EmitFlags, + cancellationToken?: ts.CancellationToken, + customTransformers?: CustomTransformers, + emitCallback?: TsEmitCallback, + mergeEmitResultsCallback?: TsMergeEmitResultsCallback + }): ts.EmitResult; /** * Returns the .d.ts / .ngsummary.json / .ngfactory.d.ts files of libraries that have been emitted diff --git a/packages/compiler-cli/src/transformers/compiler_host.ts b/packages/compiler-cli/src/transformers/compiler_host.ts index 353b1884d8d59..5efb487d2d258 100644 --- a/packages/compiler-cli/src/transformers/compiler_host.ts +++ b/packages/compiler-cli/src/transformers/compiler_host.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotCompilerHost, EmitterVisitorContext, GeneratedFile, ParseSourceSpan, TypeScriptEmitter, collectExternalReferences, syntaxError} from '@angular/compiler'; +import {AotCompilerHost, collectExternalReferences, EmitterVisitorContext, GeneratedFile, ParseSourceSpan, syntaxError, TypeScriptEmitter} from '@angular/compiler'; import * as path from 'path'; import * as ts from 'typescript'; @@ -15,7 +15,7 @@ import {ModuleMetadata} from '../metadata/index'; import {join} from '../ngtsc/file_system'; import {CompilerHost, CompilerOptions, LibrarySummary} from './api'; -import {MetadataReaderHost, createMetadataReaderCache, readMetadata} from './metadata_reader'; +import {createMetadataReaderCache, MetadataReaderHost, readMetadata} from './metadata_reader'; import {DTS, GENERATED_FILES, isInRootDir, relativeToRootDirs} from './util'; const NODE_MODULES_PACKAGE_NAME = /node_modules\/((\w|-|\.)+|(@(\w|-|\.)+\/(\w|-|\.)+))/; @@ -24,8 +24,8 @@ const CSS_PREPROCESSOR_EXT = /(\.scss|\.sass|\.less|\.styl)$/; let wrapHostForTest: ((host: ts.CompilerHost) => ts.CompilerHost)|null = null; -export function setWrapHostForTest(wrapFn: ((host: ts.CompilerHost) => ts.CompilerHost) | null): - void { +export function setWrapHostForTest(wrapFn: ((host: ts.CompilerHost) => ts.CompilerHost)| + null): void { wrapHostForTest = wrapFn; } @@ -53,11 +53,11 @@ export interface CodeGenerator { findGeneratedFileNames(fileName: string): string[]; } -function assert<T>(condition: T | null | undefined) { +function assert<T>(condition: T|null|undefined) { if (!condition) { // TODO(chuckjaz): do the right thing } - return condition !; + return condition!; } /** @@ -67,7 +67,7 @@ function assert<T>(condition: T | null | undefined) { * - TypeCheckHost for mapping ts errors to ng errors (via translateDiagnostics) */ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHost, AotCompilerHost, - TypeCheckHost { + TypeCheckHost { private metadataReaderCache = createMetadataReaderCache(); private fileNameToModuleNameCache = new Map<string, string>(); private flatModuleIndexCache = new Map<string, boolean>(); @@ -83,13 +83,13 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos private metadataReaderHost: MetadataReaderHost; // TODO(issue/24571): remove '!'. - getCancellationToken !: () => ts.CancellationToken; + getCancellationToken!: () => ts.CancellationToken; // TODO(issue/24571): remove '!'. - getDefaultLibLocation !: () => string; + getDefaultLibLocation!: () => string; // TODO(issue/24571): remove '!'. - trace !: (s: string) => void; + trace!: (s: string) => void; // TODO(issue/24571): remove '!'. - getDirectories !: (path: string) => string[]; + getDirectories!: (path: string) => string[]; resolveTypeReferenceDirectives?: (names: string[], containingFile: string) => ts.ResolvedTypeReferenceDirective[]; directoryExists?: (directoryName: string) => boolean; @@ -100,21 +100,21 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos private codeGenerator: CodeGenerator, private librarySummaries = new Map<string, LibrarySummary>()) { this.moduleResolutionCache = ts.createModuleResolutionCache( - this.context.getCurrentDirectory !(), this.context.getCanonicalFileName.bind(this.context)); - const basePath = this.options.basePath !; + this.context.getCurrentDirectory!(), this.context.getCanonicalFileName.bind(this.context)); + const basePath = this.options.basePath!; this.rootDirs = - (this.options.rootDirs || [this.options.basePath !]).map(p => path.resolve(basePath, p)); + (this.options.rootDirs || [this.options.basePath!]).map(p => path.resolve(basePath, p)); if (context.getDirectories) { - this.getDirectories = path => context.getDirectories !(path); + this.getDirectories = path => context.getDirectories!(path); } if (context.directoryExists) { - this.directoryExists = directoryName => context.directoryExists !(directoryName); + this.directoryExists = directoryName => context.directoryExists!(directoryName); } if (context.getCancellationToken) { - this.getCancellationToken = () => context.getCancellationToken !(); + this.getCancellationToken = () => context.getCancellationToken!(); } if (context.getDefaultLibLocation) { - this.getDefaultLibLocation = () => context.getDefaultLibLocation !(); + this.getDefaultLibLocation = () => context.getDefaultLibLocation!(); } if (context.resolveTypeReferenceDirectives) { // Backward compatibility with TypeScript 2.9 and older since return @@ -123,11 +123,11 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos type ts3ResolveTypeReferenceDirectives = (names: string[], containingFile: string) => ts.ResolvedTypeReferenceDirective[]; this.resolveTypeReferenceDirectives = (names: string[], containingFile: string) => - (context.resolveTypeReferenceDirectives as ts3ResolveTypeReferenceDirectives) !( - names, containingFile); + (context.resolveTypeReferenceDirectives as ts3ResolveTypeReferenceDirectives)! + (names, containingFile); } if (context.trace) { - this.trace = s => context.trace !(s); + this.trace = s => context.trace!(s); } if (context.fileNameToModuleName) { this.fileNameToModuleName = context.fileNameToModuleName.bind(context); @@ -265,8 +265,8 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos } } } else { - throw new Error( - `Trying to import a source file from a node_modules package: import ${originalImportedFile} from ${containingFile}`); + throw new Error(`Trying to import a source file from a node_modules package: import ${ + originalImportedFile} from ${containingFile}`); } this.fileNameToModuleNameCache.set(cacheKey, moduleName); @@ -325,7 +325,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos // Note: we need the explicit check via `has` as we also cache results // that were null / undefined. if (this.originalSourceFiles.has(filePath)) { - return this.originalSourceFiles.get(filePath) !; + return this.originalSourceFiles.get(filePath)!; } if (!languageVersion) { languageVersion = this.options.target || ts.ScriptTarget.Latest; @@ -353,8 +353,8 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos newRefs.forEach(r => refsAreEqual = refsAreEqual && oldRefs.has(r)); } if (!refsAreEqual) { - throw new Error( - `Illegal State: external references changed in ${genFile.genFileUrl}.\nOld: ${Array.from(oldRefs)}.\nNew: ${Array.from(newRefs)}`); + throw new Error(`Illegal State: external references changed in ${genFile.genFileUrl}.\nOld: ${ + Array.from(oldRefs)}.\nNew: ${Array.from(newRefs)}`); } return this.addGeneratedFile(genFile, newRefs); } @@ -381,7 +381,8 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos } this.generatedSourceFiles.set(genFile.genFileUrl, { sourceFile: sf, - emitCtx: context, externalReferences, + emitCtx: context, + externalReferences, }); return sf; } @@ -468,7 +469,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos } // TODO(tbosch): TypeScript's typings for getSourceFile are incorrect, // as it can very well return undefined. - return sf !; + return sf!; } private getGeneratedFile(fileName: string): ts.SourceFile|null { @@ -638,7 +639,7 @@ export class TsCompilerAotCompilerTypeCheckHostAdapter implements ts.CompilerHos } function genFileExternalReferences(genFile: GeneratedFile): Set<string> { - return new Set(collectExternalReferences(genFile.stmts !).map(er => er.moduleName !)); + return new Set(collectExternalReferences(genFile.stmts!).map(er => er.moduleName!)); } function addReferencesToSourceFile(sf: ts.SourceFile, genFileNames: string[]) { diff --git a/packages/compiler-cli/src/transformers/inline_resources.ts b/packages/compiler-cli/src/transformers/inline_resources.ts index 25e4d6108f1d2..015fad0353800 100644 --- a/packages/compiler-cli/src/transformers/inline_resources.ts +++ b/packages/compiler-cli/src/transformers/inline_resources.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {MetadataObject, MetadataValue, isClassMetadata, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicCallExpression} from '../metadata/index'; +import {isClassMetadata, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicCallExpression, MetadataObject, MetadataValue} from '../metadata/index'; import {MetadataTransformer, ValueTransform} from './metadata_cache'; @@ -17,27 +17,29 @@ const PRECONDITIONS_TEXT = /** A subset of members from AotCompilerHost */ export type ResourcesHost = { - resourceNameToFileName(resourceName: string, containingFileName: string): string | null; + resourceNameToFileName(resourceName: string, containingFileName: string): string|null; loadResource(path: string): Promise<string>| string; }; export type StaticResourceLoader = { - get(url: string | MetadataValue): string; + get(url: string|MetadataValue): string; }; function getResourceLoader(host: ResourcesHost, containingFileName: string): StaticResourceLoader { return { - get(url: string | MetadataValue): string{ + get(url: string|MetadataValue): string { if (typeof url !== 'string') { throw new Error('templateUrl and stylesUrl must be string literals. ' + PRECONDITIONS_TEXT); - } const fileName = host.resourceNameToFileName(url, containingFileName); + } + const fileName = host.resourceNameToFileName(url, containingFileName); if (fileName) { const content = host.loadResource(fileName); if (typeof content !== 'string') { throw new Error('Cannot handle async resource. ' + PRECONDITIONS_TEXT); } return content; - } throw new Error(`Failed to resolve ${url} from ${containingFileName}. ${PRECONDITIONS_TEXT}`); + } + throw new Error(`Failed to resolve ${url} from ${containingFileName}. ${PRECONDITIONS_TEXT}`); } }; } @@ -249,8 +251,7 @@ function isComponentSymbol(identifier: ts.Node, typeChecker: ts.TypeChecker) { const name = (declaration.propertyName || declaration.name).text; // We know that parent pointers are set because we created the SourceFile ourselves. // The number of parent references here match the recursion depth at this point. - const moduleId = - (declaration.parent !.parent !.parent !.moduleSpecifier as ts.StringLiteral).text; + const moduleId = (declaration.parent!.parent!.parent!.moduleSpecifier as ts.StringLiteral).text; return moduleId === '@angular/core' && name === 'Component'; } diff --git a/packages/compiler-cli/src/transformers/lower_expressions.ts b/packages/compiler-cli/src/transformers/lower_expressions.ts index 3f2bc92c7830b..7ded3d5198ad2 100644 --- a/packages/compiler-cli/src/transformers/lower_expressions.ts +++ b/packages/compiler-cli/src/transformers/lower_expressions.ts @@ -9,7 +9,8 @@ import {createLoweredSymbol, isLoweredSymbol} from '@angular/compiler'; import * as ts from 'typescript'; -import {CollectorOptions, MetadataCollector, MetadataValue, ModuleMetadata, isMetadataGlobalReferenceExpression} from '../metadata/index'; +import {CollectorOptions, isMetadataGlobalReferenceExpression, MetadataCollector, MetadataValue, ModuleMetadata} from '../metadata/index'; + import {MetadataCache, MetadataTransformer, ValueTransform} from './metadata_cache'; export interface LoweringRequest { @@ -21,7 +22,10 @@ export interface LoweringRequest { export type RequestLocationMap = Map<number, LoweringRequest>; -const enum DeclarationOrder { BeforeStmt, AfterStmt } +const enum DeclarationOrder { + BeforeStmt, + AfterStmt +} interface Declaration { name: string; @@ -201,14 +205,16 @@ export function getExpressionLoweringTransformFactory( }; } -export interface RequestsMap { getRequests(sourceFile: ts.SourceFile): RequestLocationMap; } +export interface RequestsMap { + getRequests(sourceFile: ts.SourceFile): RequestLocationMap; +} interface MetadataAndLoweringRequests { metadata: ModuleMetadata|undefined; requests: RequestLocationMap; } -function isEligibleForLowering(node: ts.Node | undefined): boolean { +function isEligibleForLowering(node: ts.Node|undefined): boolean { if (node) { switch (node.kind) { case ts.SyntaxKind.SourceFile: @@ -232,10 +238,11 @@ function isEligibleForLowering(node: ts.Node | undefined): boolean { // example) might also require lowering even if the top-level declaration is already // properly exported. const varNode = node as ts.VariableDeclaration; - return isExported || (varNode.initializer !== undefined && - (ts.isObjectLiteralExpression(varNode.initializer) || - ts.isArrayLiteralExpression(varNode.initializer) || - ts.isCallExpression(varNode.initializer))); + return isExported || + (varNode.initializer !== undefined && + (ts.isObjectLiteralExpression(varNode.initializer) || + ts.isArrayLiteralExpression(varNode.initializer) || + ts.isCallExpression(varNode.initializer))); } return isEligibleForLowering(node.parent); } @@ -264,7 +271,7 @@ function isLiteralFieldNamed(node: ts.Node, names: Set<string>): boolean { export class LowerMetadataTransform implements RequestsMap, MetadataTransformer { // TODO(issue/24571): remove '!'. - private cache !: MetadataCache; + private cache!: MetadataCache; private requests = new Map<string, RequestLocationMap>(); private lowerableFieldNames: Set<string>; @@ -288,7 +295,9 @@ export class LowerMetadataTransform implements RequestsMap, MetadataTransformer } // MetadataTransformer - connect(cache: MetadataCache): void { this.cache = cache; } + connect(cache: MetadataCache): void { + this.cache = cache; + } start(sourceFile: ts.SourceFile): ValueTransform|undefined { let identNumber = 0; @@ -329,7 +338,7 @@ export class LowerMetadataTransform implements RequestsMap, MetadataTransformer const hasLowerableParentCache = new Map<ts.Node, boolean>(); - const shouldBeLowered = (node: ts.Node | undefined): boolean => { + const shouldBeLowered = (node: ts.Node|undefined): boolean => { if (node === undefined) { return false; } @@ -346,7 +355,7 @@ export class LowerMetadataTransform implements RequestsMap, MetadataTransformer return lowerable; }; - const hasLowerableParent = (node: ts.Node | undefined): boolean => { + const hasLowerableParent = (node: ts.Node|undefined): boolean => { if (node === undefined) { return false; } @@ -354,10 +363,10 @@ export class LowerMetadataTransform implements RequestsMap, MetadataTransformer hasLowerableParentCache.set( node, shouldBeLowered(node.parent) || hasLowerableParent(node.parent)); } - return hasLowerableParentCache.get(node) !; + return hasLowerableParentCache.get(node)!; }; - const isLowerable = (node: ts.Node | undefined): boolean => { + const isLowerable = (node: ts.Node|undefined): boolean => { if (node === undefined) { return false; } @@ -383,7 +392,7 @@ function createExportTableFor(sourceFile: ts.SourceFile): Set<string> { case ts.SyntaxKind.InterfaceDeclaration: if ((ts.getCombinedModifierFlags(node as ts.Declaration) & ts.ModifierFlags.Export) != 0) { const classDeclaration = - node as(ts.ClassDeclaration | ts.FunctionDeclaration | ts.InterfaceDeclaration); + node as (ts.ClassDeclaration | ts.FunctionDeclaration | ts.InterfaceDeclaration); const name = classDeclaration.name; if (name) exportTable.add(name.text); } @@ -406,7 +415,9 @@ function createExportTableFor(sourceFile: ts.SourceFile): Set<string> { const exportDeclaration = node as ts.ExportDeclaration; const {moduleSpecifier, exportClause} = exportDeclaration; if (!moduleSpecifier && exportClause && ts.isNamedExports(exportClause)) { - exportClause.elements.forEach(spec => { exportTable.add(spec.name.text); }); + exportClause.elements.forEach(spec => { + exportTable.add(spec.name.text); + }); } } }); diff --git a/packages/compiler-cli/src/transformers/node_emitter.ts b/packages/compiler-cli/src/transformers/node_emitter.ts index 9171982655197..a557669d453ea 100644 --- a/packages/compiler-cli/src/transformers/node_emitter.ts +++ b/packages/compiler-cli/src/transformers/node_emitter.ts @@ -12,7 +12,9 @@ import * as ts from 'typescript'; import {error} from './util'; -export interface Node { sourceSpan: ParseSourceSpan|null; } +export interface Node { + sourceSpan: ParseSourceSpan|null; +} const METHOD_THIS_NAME = 'this'; const CATCH_ERROR_NAME = 'error'; @@ -110,15 +112,16 @@ export function updateSourceFile( // Validate that all the classes have been generated classNames.size == 0 || - error( - `${classNames.size == 1 ? 'Class' : 'Classes'} "${Array.from(classNames.keys()).join(', ')}" not generated`); + error(`${classNames.size == 1 ? 'Class' : 'Classes'} "${ + Array.from(classNames.keys()).join(', ')}" not generated`); // Add imports to the module required by the new methods const imports = converter.getImports(); if (imports && imports.length) { // Find where the new imports should go const index = firstAfter( - newStatements, statement => statement.kind === ts.SyntaxKind.ImportDeclaration || + newStatements, + statement => statement.kind === ts.SyntaxKind.ImportDeclaration || statement.kind === ts.SyntaxKind.ImportEqualsDeclaration); newStatements = [...newStatements.slice(0, index), ...imports, ...prefix, ...newStatements.slice(index)]; @@ -152,7 +155,9 @@ function firstAfter<T>(a: T[], predicate: (value: T) => boolean) { // A recorded node is a subtype of the node that is marked as being recorded. This is used // to ensure that NodeEmitterVisitor.record has been called on all nodes returned by the // NodeEmitterVisitor -export type RecordedNode<T extends ts.Node = ts.Node> = (T & { __recorded: any;}) | null; +export type RecordedNode<T extends ts.Node = ts.Node> = (T&{ + __recorded: any; +})|null; function escapeLiteral(value: string): string { return value.replace(/(\"|\\)/g, '\\$1').replace(/(\n)|(\r)/g, function(v, n, r) { @@ -220,8 +225,9 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { .map( ([exportedFilePath, reexports]) => ts.createExportDeclaration( /* decorators */ undefined, - /* modifiers */ undefined, ts.createNamedExports(reexports.map( - ({name, as}) => ts.createExportSpecifier(name, as))), + /* modifiers */ undefined, + ts.createNamedExports( + reexports.map(({name, as}) => ts.createExportSpecifier(name, as))), /* moduleSpecifier */ createLiteral(exportedFilePath))); } @@ -231,13 +237,16 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { ([namespace, prefix]) => ts.createImportDeclaration( /* decorators */ undefined, /* modifiers */ undefined, - /* importClause */ ts.createImportClause( + /* importClause */ + ts.createImportClause( /* name */<ts.Identifier>(undefined as any), ts.createNamespaceImport(ts.createIdentifier(prefix))), /* moduleSpecifier */ createLiteral(namespace))); } - getNodeMap() { return this._nodeMap; } + getNodeMap() { + return this._nodeMap; + } updateSourceMap(statements: ts.Statement[]) { let lastRangeStartNode: ts.Node|undefined = undefined; @@ -324,7 +333,7 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { reexports = []; this._reexports.set(moduleName, reexports); } - reexports.push({name: name !, as: stmt.name}); + reexports.push({name: name!, as: stmt.name}); return null; } } @@ -340,9 +349,10 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { const tsVarStmt = this.record(stmt, ts.createVariableStatement(/* modifiers */[], varDeclList)); const exportStmt = this.record( - stmt, ts.createExportDeclaration( - /*decorators*/ undefined, /*modifiers*/ undefined, - ts.createNamedExports([ts.createExportSpecifier(stmt.name, stmt.name)]))); + stmt, + ts.createExportDeclaration( + /*decorators*/ undefined, /*modifiers*/ undefined, + ts.createNamedExports([ts.createExportSpecifier(stmt.name, stmt.name)]))); return [tsVarStmt, exportStmt]; } return this.record(stmt, ts.createVariableStatement(this.getModifiers(stmt), varDeclList)); @@ -350,14 +360,15 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitDeclareFunctionStmt(stmt: DeclareFunctionStmt) { return this.record( - stmt, ts.createFunctionDeclaration( - /* decorators */ undefined, this.getModifiers(stmt), - /* asteriskToken */ undefined, stmt.name, /* typeParameters */ undefined, - stmt.params.map( - p => ts.createParameter( - /* decorators */ undefined, /* modifiers */ undefined, - /* dotDotDotToken */ undefined, p.name)), - /* type */ undefined, this._visitStatements(stmt.statements))); + stmt, + ts.createFunctionDeclaration( + /* decorators */ undefined, this.getModifiers(stmt), + /* asteriskToken */ undefined, stmt.name, /* typeParameters */ undefined, + stmt.params.map( + p => ts.createParameter( + /* decorators */ undefined, /* modifiers */ undefined, + /* dotDotDotToken */ undefined, p.name)), + /* type */ undefined, this._visitStatements(stmt.statements))); } visitExpressionStmt(stmt: ExpressionStatement) { @@ -401,7 +412,8 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { (stmt.constructorMethod && [ts.createConstructor( /* decorators */ undefined, /* modifiers */ undefined, - /* parameters */ stmt.constructorMethod.params.map( + /* parameters */ + stmt.constructorMethod.params.map( p => ts.createParameter( /* decorators */ undefined, /* modifiers */ undefined, @@ -415,7 +427,7 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { method => ts.createMethod( /* decorators */ undefined, /* modifiers */ translateModifiers(method.modifiers), - /* astriskToken */ undefined, method.name !/* guarded by filter */, + /* astriskToken */ undefined, method.name!/* guarded by filter */, /* questionToken */ undefined, /* typeParameters */ undefined, method.params.map( p => ts.createParameter( @@ -423,13 +435,14 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { /* dotDotDotToken */ undefined, p.name)), /* type */ undefined, this._visitStatements(method.body))); return this.record( - stmt, ts.createClassDeclaration( - /* decorators */ undefined, modifiers, stmt.name, /* typeParameters*/ undefined, - stmt.parent && [ts.createHeritageClause( - ts.SyntaxKind.ExtendsKeyword, - [stmt.parent.visitExpression(this, null)])] || - [], - [...fields, ...getters, ...constructor, ...methods])); + stmt, + ts.createClassDeclaration( + /* decorators */ undefined, modifiers, stmt.name, /* typeParameters*/ undefined, + stmt.parent && + [ts.createHeritageClause( + ts.SyntaxKind.ExtendsKeyword, [stmt.parent.visitExpression(this, null)])] || + [], + [...fields, ...getters, ...constructor, ...methods])); } visitIfStmt(stmt: IfStmt) { @@ -443,19 +456,21 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitTryCatchStmt(stmt: TryCatchStmt): RecordedNode<ts.TryStatement> { return this.record( - stmt, ts.createTry( - this._visitStatements(stmt.bodyStmts), - ts.createCatchClause( - CATCH_ERROR_NAME, this._visitStatementsPrefix( - [ts.createVariableStatement( - /* modifiers */ undefined, - [ts.createVariableDeclaration( - CATCH_STACK_NAME, /* type */ undefined, - ts.createPropertyAccess( - ts.createIdentifier(CATCH_ERROR_NAME), - ts.createIdentifier(CATCH_STACK_NAME)))])], - stmt.catchStmts)), - /* finallyBlock */ undefined)); + stmt, + ts.createTry( + this._visitStatements(stmt.bodyStmts), + ts.createCatchClause( + CATCH_ERROR_NAME, + this._visitStatementsPrefix( + [ts.createVariableStatement( + /* modifiers */ undefined, + [ts.createVariableDeclaration( + CATCH_STACK_NAME, /* type */ undefined, + ts.createPropertyAccess( + ts.createIdentifier(CATCH_ERROR_NAME), + ts.createIdentifier(CATCH_STACK_NAME)))])], + stmt.catchStmts)), + /* finallyBlock */ undefined)); } visitThrowStmt(stmt: ThrowStmt) { @@ -481,7 +496,9 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { } // ExpressionVisitor - visitWrappedNodeExpr(expr: WrappedNodeExpr<any>) { return this.record(expr, expr.node); } + visitWrappedNodeExpr(expr: WrappedNodeExpr<any>) { + return this.record(expr, expr.node); + } visitTypeofExpr(expr: TypeofExpr) { const typeOf = ts.createTypeOf(expr.expr.visitExpression(this, null)); @@ -508,8 +525,9 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitWriteVarExpr(expr: WriteVarExpr): RecordedNode<ts.BinaryExpression> { return this.record( - expr, ts.createAssignment( - ts.createIdentifier(expr.name), expr.value.visitExpression(this, null))); + expr, + ts.createAssignment( + ts.createIdentifier(expr.name), expr.value.visitExpression(this, null))); } visitWriteKeyExpr(expr: WriteKeyExpr): RecordedNode<ts.BinaryExpression> { @@ -523,9 +541,10 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitWritePropExpr(expr: WritePropExpr): RecordedNode<ts.BinaryExpression> { return this.record( - expr, ts.createAssignment( - ts.createPropertyAccess(expr.receiver.visitExpression(this, null), expr.name), - expr.value.visitExpression(this, null))); + expr, + ts.createAssignment( + ts.createPropertyAccess(expr.receiver.visitExpression(this, null), expr.name), + expr.value.visitExpression(this, null))); } visitInvokeMethodExpr(expr: InvokeMethodExpr): RecordedNode<ts.CallExpression> { @@ -539,19 +558,23 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitInvokeFunctionExpr(expr: InvokeFunctionExpr): RecordedNode<ts.CallExpression> { return this.record( - expr, ts.createCall( - expr.fn.visitExpression(this, null), /* typeArguments */ undefined, - expr.args.map(arg => arg.visitExpression(this, null)))); + expr, + ts.createCall( + expr.fn.visitExpression(this, null), /* typeArguments */ undefined, + expr.args.map(arg => arg.visitExpression(this, null)))); } visitInstantiateExpr(expr: InstantiateExpr): RecordedNode<ts.NewExpression> { return this.record( - expr, ts.createNew( - expr.classExpr.visitExpression(this, null), /* typeArguments */ undefined, - expr.args.map(arg => arg.visitExpression(this, null)))); + expr, + ts.createNew( + expr.classExpr.visitExpression(this, null), /* typeArguments */ undefined, + expr.args.map(arg => arg.visitExpression(this, null)))); } - visitLiteralExpr(expr: LiteralExpr) { return this.record(expr, createLiteral(expr.value)); } + visitLiteralExpr(expr: LiteralExpr) { + return this.record(expr, createLiteral(expr.value)); + } visitLocalizedString(expr: LocalizedString, context: any) { throw new Error('localized strings are not supported in pre-ivy mode.'); @@ -567,13 +590,14 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { expr, ts.createParen(ts.createConditional( expr.condition.visitExpression(this, null), expr.trueCase.visitExpression(this, null), - expr.falseCase !.visitExpression(this, null)))); + expr.falseCase!.visitExpression(this, null)))); } visitNotExpr(expr: NotExpr): RecordedNode<ts.PrefixUnaryExpression> { return this.record( - expr, ts.createPrefix( - ts.SyntaxKind.ExclamationToken, expr.condition.visitExpression(this, null))); + expr, + ts.createPrefix( + ts.SyntaxKind.ExclamationToken, expr.condition.visitExpression(this, null))); } visitAssertNotNullExpr(expr: AssertNotNull): RecordedNode<ts.Expression> { @@ -586,15 +610,16 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitFunctionExpr(expr: FunctionExpr) { return this.record( - expr, ts.createFunctionExpression( - /* modifiers */ undefined, /* astriskToken */ undefined, - /* name */ expr.name || undefined, - /* typeParameters */ undefined, - expr.params.map( - p => ts.createParameter( - /* decorators */ undefined, /* modifiers */ undefined, - /* dotDotDotToken */ undefined, p.name)), - /* type */ undefined, this._visitStatements(expr.statements))); + expr, + ts.createFunctionExpression( + /* modifiers */ undefined, /* astriskToken */ undefined, + /* name */ expr.name || undefined, + /* typeParameters */ undefined, + expr.params.map( + p => ts.createParameter( + /* decorators */ undefined, /* modifiers */ undefined, + /* dotDotDotToken */ undefined, p.name)), + /* type */ undefined, this._visitStatements(expr.statements))); } visitBinaryOperatorExpr(expr: BinaryOperatorExpr): @@ -676,21 +701,23 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { visitLiteralMapExpr(expr: LiteralMapExpr): RecordedNode<ts.ObjectLiteralExpression> { return this.record( - expr, ts.createObjectLiteral(expr.entries.map( - entry => ts.createPropertyAssignment( - entry.quoted || !_VALID_IDENTIFIER_RE.test(entry.key) ? - ts.createLiteral(entry.key) : - entry.key, - entry.value.visitExpression(this, null))))); + expr, + ts.createObjectLiteral(expr.entries.map( + entry => ts.createPropertyAssignment( + entry.quoted || !_VALID_IDENTIFIER_RE.test(entry.key) ? + ts.createLiteral(entry.key) : + entry.key, + entry.value.visitExpression(this, null))))); } visitCommaExpr(expr: CommaExpr): RecordedNode<ts.Expression> { return this.record( - expr, expr.parts.map(e => e.visitExpression(this, null)) - .reduce<ts.Expression|null>( - (left, right) => - left ? ts.createBinary(left, ts.SyntaxKind.CommaToken, right) : right, - null)); + expr, + expr.parts.map(e => e.visitExpression(this, null)) + .reduce<ts.Expression|null>( + (left, right) => + left ? ts.createBinary(left, ts.SyntaxKind.CommaToken, right) : right, + null)); } private _visitStatements(statements: Statement[]): ts.Block { @@ -705,7 +732,7 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { private _visitIdentifier(value: ExternalReference): ts.Expression { // name can only be null during JIT which never executes this code. - const moduleName = value.moduleName, name = value.name !; + const moduleName = value.moduleName, name = value.name!; let prefixIdent: ts.Identifier|null = null; if (moduleName) { let prefix = this._importsWithPrefixes.get(moduleName); @@ -730,7 +757,7 @@ export class NodeEmitterVisitor implements StatementVisitor, ExpressionVisitor { } -function getMethodName(methodRef: {name: string | null; builtin: BuiltinMethod | null}): string { +function getMethodName(methodRef: {name: string|null; builtin: BuiltinMethod | null}): string { if (methodRef.name) { return methodRef.name; } else { @@ -760,6 +787,6 @@ function modifierFromModifier(modifier: StmtModifier): ts.Modifier { return error(`unknown statement modifier`); } -function translateModifiers(modifiers: StmtModifier[] | null): ts.Modifier[]|undefined { - return modifiers == null ? undefined : modifiers !.map(modifierFromModifier); +function translateModifiers(modifiers: StmtModifier[]|null): ts.Modifier[]|undefined { + return modifiers == null ? undefined : modifiers!.map(modifierFromModifier); } diff --git a/packages/compiler-cli/src/transformers/program.ts b/packages/compiler-cli/src/transformers/program.ts index eb631c4c2dae4..89d483b6ff226 100644 --- a/packages/compiler-cli/src/transformers/program.ts +++ b/packages/compiler-cli/src/transformers/program.ts @@ -7,26 +7,26 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotCompiler, AotCompilerHost, AotCompilerOptions, EmitterVisitorContext, FormattedMessageChain, GeneratedFile, MessageBundle, NgAnalyzedFile, NgAnalyzedFileWithInjectables, NgAnalyzedModules, ParseSourceSpan, PartialModule, Position, Serializer, StaticSymbol, TypeScriptEmitter, Xliff, Xliff2, Xmb, core, createAotCompiler, getParseErrors, isFormattedError, isSyntaxError} from '@angular/compiler'; +import {AotCompiler, AotCompilerHost, AotCompilerOptions, core, createAotCompiler, EmitterVisitorContext, FormattedMessageChain, GeneratedFile, getParseErrors, isFormattedError, isSyntaxError, MessageBundle, NgAnalyzedFile, NgAnalyzedFileWithInjectables, NgAnalyzedModules, ParseSourceSpan, PartialModule, Position, Serializer, StaticSymbol, TypeScriptEmitter, Xliff, Xliff2, Xmb} from '@angular/compiler'; import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; -import {TypeCheckHost, translateDiagnostics} from '../diagnostics/translate_diagnostics'; -import {MetadataCollector, ModuleMetadata, createBundleIndexHost} from '../metadata'; +import {translateDiagnostics, TypeCheckHost} from '../diagnostics/translate_diagnostics'; +import {createBundleIndexHost, MetadataCollector, ModuleMetadata} from '../metadata'; import {NgtscProgram} from '../ngtsc/program'; import {verifySupportedTypeScriptVersion} from '../typescript_support'; import {CompilerHost, CompilerOptions, CustomTransformers, DEFAULT_ERROR_CODE, Diagnostic, DiagnosticMessageChain, EmitFlags, LazyRoute, LibrarySummary, Program, SOURCE, TsEmitArguments, TsEmitCallback, TsMergeEmitResultsCallback} from './api'; -import {CodeGenerator, TsCompilerAotCompilerTypeCheckHostAdapter, getOriginalReferences} from './compiler_host'; -import {InlineResourcesMetadataTransformer, getInlineResourcesTransformFactory} from './inline_resources'; -import {LowerMetadataTransform, getExpressionLoweringTransformFactory} from './lower_expressions'; +import {CodeGenerator, getOriginalReferences, TsCompilerAotCompilerTypeCheckHostAdapter} from './compiler_host'; +import {getInlineResourcesTransformFactory, InlineResourcesMetadataTransformer} from './inline_resources'; +import {getExpressionLoweringTransformFactory, LowerMetadataTransform} from './lower_expressions'; import {MetadataCache, MetadataTransformer} from './metadata_cache'; import {getAngularEmitterTransformFactory} from './node_emitter_transform'; import {PartialModuleMetadataTransformer} from './r3_metadata_transform'; -import {StripDecoratorsMetadataTransformer, getDecoratorStripTransformerFactory} from './r3_strip_decorators'; +import {getDecoratorStripTransformerFactory, StripDecoratorsMetadataTransformer} from './r3_strip_decorators'; import {getAngularClassTransformerFactory} from './r3_transform'; -import {DTS, GENERATED_FILES, StructureIsReused, TS, createMessageDiagnostic, isInRootDir, ngToTsDiagnostic, tsStructureIsReused, userError} from './util'; +import {createMessageDiagnostic, DTS, GENERATED_FILES, isInRootDir, ngToTsDiagnostic, StructureIsReused, TS, tsStructureIsReused, userError} from './util'; /** @@ -60,18 +60,23 @@ const emptyModules: NgAnalyzedModules = { files: [] }; -const defaultEmitCallback: TsEmitCallback = - ({program, targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, - customTransformers}) => - program.emit( - targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); +const defaultEmitCallback: TsEmitCallback = ({ + program, + targetSourceFile, + writeFile, + cancellationToken, + emitOnlyDtsFiles, + customTransformers +}) => + program.emit( + targetSourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers); class AngularCompilerProgram implements Program { private rootNames: string[]; private metadataCache: MetadataCache; // Metadata cache used exclusively for the flat module index // TODO(issue/24571): remove '!'. - private flatModuleMetadataCache !: MetadataCache; + private flatModuleMetadataCache!: MetadataCache; private loweringMetadataTransform: LowerMetadataTransform; private oldProgramLibrarySummaries: Map<string, LibrarySummary>|undefined; private oldProgramEmittedGeneratedFiles: Map<string, GeneratedFile>|undefined; @@ -84,18 +89,18 @@ class AngularCompilerProgram implements Program { // Lazily initialized fields // TODO(issue/24571): remove '!'. - private _compiler !: AotCompiler; + private _compiler!: AotCompiler; // TODO(issue/24571): remove '!'. - private _hostAdapter !: TsCompilerAotCompilerTypeCheckHostAdapter; + private _hostAdapter!: TsCompilerAotCompilerTypeCheckHostAdapter; // TODO(issue/24571): remove '!'. - private _tsProgram !: ts.Program; + private _tsProgram!: ts.Program; private _analyzedModules: NgAnalyzedModules|undefined; private _analyzedInjectables: NgAnalyzedFileWithInjectables[]|undefined; private _structuralDiagnostics: Diagnostic[]|undefined; private _programWithStubs: ts.Program|undefined; private _optionsDiagnostics: Diagnostic[] = []; // TODO(issue/24571): remove '!'. - private _reifiedDecorators !: Set<StaticSymbol>; + private _reifiedDecorators!: Set<StaticSymbol>; constructor( rootNames: ReadonlyArray<string>, private options: CompilerOptions, @@ -124,7 +129,7 @@ class AngularCompilerProgram implements Program { code: DEFAULT_ERROR_CODE }))); } else { - this.rootNames.push(indexName !); + this.rootNames.push(indexName!); this.host = bundleHost; } } @@ -175,7 +180,9 @@ class AngularCompilerProgram implements Program { return result; } - getTsProgram(): ts.Program { return this.tsProgram; } + getTsProgram(): ts.Program { + return this.tsProgram; + } getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken) { return this.tsProgram.getOptionsDiagnostics(cancellationToken); @@ -256,17 +263,19 @@ class AngularCompilerProgram implements Program { return this._emitRender2(parameters); } - private _emitRender3( - { - emitFlags = EmitFlags.Default, cancellationToken, customTransformers, - emitCallback = defaultEmitCallback, mergeEmitResultsCallback = mergeEmitResults, - }: { - emitFlags?: EmitFlags, - cancellationToken?: ts.CancellationToken, - customTransformers?: CustomTransformers, - emitCallback?: TsEmitCallback, - mergeEmitResultsCallback?: TsMergeEmitResultsCallback, - } = {}): ts.EmitResult { + private _emitRender3({ + emitFlags = EmitFlags.Default, + cancellationToken, + customTransformers, + emitCallback = defaultEmitCallback, + mergeEmitResultsCallback = mergeEmitResults, + }: { + emitFlags?: EmitFlags, + cancellationToken?: ts.CancellationToken, + customTransformers?: CustomTransformers, + emitCallback?: TsEmitCallback, + mergeEmitResultsCallback?: TsMergeEmitResultsCallback, + } = {}): ts.EmitResult { const emitStart = Date.now(); if ((emitFlags & (EmitFlags.JS | EmitFlags.DTS | EmitFlags.Metadata | EmitFlags.Codegen)) === 0) { @@ -276,7 +285,7 @@ class AngularCompilerProgram implements Program { // analyzedModules and analyzedInjectables are created together. If one exists, so does the // other. const modules = - this.compiler.emitAllPartialModules(this.analyzedModules, this._analyzedInjectables !); + this.compiler.emitAllPartialModules(this.analyzedModules, this._analyzedInjectables!); const writeTsFile: ts.WriteFileCallback = (outFileName, outData, writeByteOrderMark, onError?, sourceFiles?) => { @@ -306,7 +315,8 @@ class AngularCompilerProgram implements Program { program: this.tsProgram, host: this.host, options: this.options, - writeFile: writeTsFile, emitOnlyDtsFiles, + writeFile: writeTsFile, + emitOnlyDtsFiles, customTransformers: tsCustomTransformers }); } finally { @@ -319,17 +329,19 @@ class AngularCompilerProgram implements Program { } } - private _emitRender2( - { - emitFlags = EmitFlags.Default, cancellationToken, customTransformers, - emitCallback = defaultEmitCallback, mergeEmitResultsCallback = mergeEmitResults, - }: { - emitFlags?: EmitFlags, - cancellationToken?: ts.CancellationToken, - customTransformers?: CustomTransformers, - emitCallback?: TsEmitCallback, - mergeEmitResultsCallback?: TsMergeEmitResultsCallback, - } = {}): ts.EmitResult { + private _emitRender2({ + emitFlags = EmitFlags.Default, + cancellationToken, + customTransformers, + emitCallback = defaultEmitCallback, + mergeEmitResultsCallback = mergeEmitResults, + }: { + emitFlags?: EmitFlags, + cancellationToken?: ts.CancellationToken, + customTransformers?: CustomTransformers, + emitCallback?: TsEmitCallback, + mergeEmitResultsCallback?: TsMergeEmitResultsCallback, + } = {}): ts.EmitResult { const emitStart = Date.now(); if (emitFlags & EmitFlags.I18nBundle) { const locale = this.options.i18nOutLocale || null; @@ -413,7 +425,8 @@ class AngularCompilerProgram implements Program { program: this.tsProgram, host: this.host, options: this.options, - writeFile: writeTsFile, emitOnlyDtsFiles, + writeFile: writeTsFile, + emitOnlyDtsFiles, customTransformers: tsCustomTransformers, targetSourceFile: this.tsProgram.getSourceFile(fileName), }))); @@ -423,7 +436,8 @@ class AngularCompilerProgram implements Program { program: this.tsProgram, host: this.host, options: this.options, - writeFile: writeTsFile, emitOnlyDtsFiles, + writeFile: writeTsFile, + emitOnlyDtsFiles, customTransformers: tsCustomTransformers }); emittedUserTsCount = this.tsProgram.getSourceFiles().length - genTsFiles.length; @@ -466,7 +480,7 @@ class AngularCompilerProgram implements Program { if (emitFlags & EmitFlags.Codegen) { genJsonFiles.forEach(gf => { const outFileName = srcToOutPath(gf.genFileUrl); - this.writeFile(outFileName, gf.source !, false, undefined, gf); + this.writeFile(outFileName, gf.source!, false, undefined, gf); }); } let metadataJsonCount = 0; @@ -501,21 +515,21 @@ class AngularCompilerProgram implements Program { if (!this._compiler) { this._createCompiler(); } - return this._compiler !; + return this._compiler!; } private get hostAdapter(): TsCompilerAotCompilerTypeCheckHostAdapter { if (!this._hostAdapter) { this._createCompiler(); } - return this._hostAdapter !; + return this._hostAdapter!; } private get analyzedModules(): NgAnalyzedModules { if (!this._analyzedModules) { this.initSync(); } - return this._analyzedModules !; + return this._analyzedModules!; } private get structuralDiagnostics(): ReadonlyArray<Diagnostic> { @@ -531,7 +545,7 @@ class AngularCompilerProgram implements Program { if (!this._tsProgram) { this.initSync(); } - return this._tsProgram !; + return this._tsProgram!; } private get reifiedDecorators(): Set<StaticSymbol> { @@ -617,7 +631,7 @@ class AngularCompilerProgram implements Program { private _createCompiler() { const codegen: CodeGenerator = { generateFile: (genFileName, baseFileName) => - this._compiler.emitBasicStub(genFileName, baseFileName), + this._compiler.emitBasicStub(genFileName, baseFileName), findGeneratedFileNames: (fileName) => this._compiler.findGeneratedFileNames(fileName), }; @@ -646,7 +660,7 @@ class AngularCompilerProgram implements Program { const codegen: CodeGenerator = { generateFile: (genFileName, baseFileName) => - this.compiler.emitBasicStub(genFileName, baseFileName), + this.compiler.emitBasicStub(genFileName, baseFileName), findGeneratedFileNames: (fileName) => this.compiler.findGeneratedFileNames(fileName), }; @@ -692,7 +706,7 @@ class AngularCompilerProgram implements Program { if (generate) { // Note: ! is ok as hostAdapter.shouldGenerateFile will always return a baseFileName // for .ngfactory.ts files. - const genFile = this.compiler.emitTypeCheckStub(sf.fileName, baseFileName !); + const genFile = this.compiler.emitTypeCheckStub(sf.fileName, baseFileName!); if (genFile) { this.hostAdapter.updateGeneratedFile(genFile); } @@ -782,11 +796,12 @@ class AngularCompilerProgram implements Program { private getSourceFilesForEmit(): ts.SourceFile[]|undefined { // TODO(tbosch): if one of the files contains a `const enum` // always emit all files -> return undefined! - let sourceFilesToEmit = this.tsProgram.getSourceFiles().filter( - sf => { return !sf.isDeclarationFile && !GENERATED_FILES.test(sf.fileName); }); + let sourceFilesToEmit = this.tsProgram.getSourceFiles().filter(sf => { + return !sf.isDeclarationFile && !GENERATED_FILES.test(sf.fileName); + }); if (this.oldProgramEmittedSourceFiles) { sourceFilesToEmit = sourceFilesToEmit.filter(sf => { - const oldFile = this.oldProgramEmittedSourceFiles !.get(sf.fileName); + const oldFile = this.oldProgramEmittedSourceFiles!.get(sf.fileName); return sf !== oldFile; }); } @@ -849,7 +864,8 @@ class AngularCompilerProgram implements Program { export function createProgram({rootNames, options, host, oldProgram}: { rootNames: ReadonlyArray<string>, options: CompilerOptions, - host: CompilerHost, oldProgram?: Program + host: CompilerHost, + oldProgram?: Program }): Program { if (options.enableIvy !== false) { return new NgtscProgram(rootNames, options, host, oldProgram as NgtscProgram | undefined); @@ -887,7 +903,9 @@ function getAotCompilerOptions(options: CompilerOptions): AotCompilerOptions { return { locale: options.i18nInLocale, i18nFormat: options.i18nInFormat || options.i18nOutFormat, - i18nUseExternalIds: options.i18nUseExternalIds, translations, missingTranslation, + i18nUseExternalIds: options.i18nUseExternalIds, + translations, + missingTranslation, enableSummariesForJit: options.enableSummariesForJit, preserveWhitespaces: options.preserveWhitespaces, fullTemplateTypeCheck: options.fullTemplateTypeCheck, @@ -931,8 +949,8 @@ function normalizeSeparators(path: string): string { * POSIX normalized paths for output paths. */ export function createSrcToOutPathMapper( - outDir: string | undefined, sampleSrcFileName: string | undefined, - sampleOutFileName: string | undefined, host: { + outDir: string|undefined, sampleSrcFileName: string|undefined, + sampleOutFileName: string|undefined, host: { dirname: typeof path.dirname, resolve: typeof path.resolve, relative: typeof path.relative @@ -971,14 +989,14 @@ export function createSrcToOutPathMapper( } export function i18nExtract( - formatName: string | null, outFile: string | null, host: ts.CompilerHost, - options: CompilerOptions, bundle: MessageBundle): string[] { + formatName: string|null, outFile: string|null, host: ts.CompilerHost, options: CompilerOptions, + bundle: MessageBundle): string[] { formatName = formatName || 'xlf'; // Checks the format and returns the extension const ext = i18nGetExtension(formatName); const content = i18nSerialize(bundle, formatName, options); const dstFile = outFile || `messages.${ext}`; - const dstPath = path.resolve(options.outDir || options.basePath !, dstFile); + const dstPath = path.resolve(options.outDir || options.basePath!, dstFile); host.writeFile(dstPath, content, false, undefined, []); return [dstPath]; } @@ -1045,7 +1063,7 @@ function mergeEmitResults(emitResults: ts.EmitResult[]): ts.EmitResult { function diagnosticSourceOfSpan(span: ParseSourceSpan): ts.SourceFile { // For diagnostics, TypeScript only uses the fileName and text properties. // The redundant '()' are here is to avoid having clang-format breaking the line incorrectly. - return ({ fileName: span.start.file.url, text: span.start.file.content } as any); + return ({fileName: span.start.file.url, text: span.start.file.content} as any); } function diagnosticSourceOfFileName(fileName: string, program: ts.Program): ts.SourceFile { @@ -1055,7 +1073,7 @@ function diagnosticSourceOfFileName(fileName: string, program: ts.Program): ts.S // If we are reporting diagnostics for a source file that is not in the project then we need // to fake a source file so the diagnostic formatting routines can emit the file name. // The redundant '()' are here is to avoid having clang-format breaking the line incorrectly. - return ({ fileName, text: '' } as any); + return ({fileName, text: ''} as any); } diff --git a/packages/compiler-cli/src/transformers/r3_metadata_transform.ts b/packages/compiler-cli/src/transformers/r3_metadata_transform.ts index ace19fea1103a..d0aefbf5531ad 100644 --- a/packages/compiler-cli/src/transformers/r3_metadata_transform.ts +++ b/packages/compiler-cli/src/transformers/r3_metadata_transform.ts @@ -9,7 +9,7 @@ import {ClassStmt, PartialModule, Statement, StmtModifier} from '@angular/compiler'; import * as ts from 'typescript'; -import {MetadataCollector, MetadataValue, ModuleMetadata, isClassMetadata} from '../metadata/index'; +import {isClassMetadata, MetadataCollector, MetadataValue, ModuleMetadata} from '../metadata/index'; import {MetadataTransformer, ValueTransform} from './metadata_cache'; diff --git a/packages/compiler-cli/src/transformers/r3_strip_decorators.ts b/packages/compiler-cli/src/transformers/r3_strip_decorators.ts index c5feabee50aa9..1d2bba7cdb136 100644 --- a/packages/compiler-cli/src/transformers/r3_strip_decorators.ts +++ b/packages/compiler-cli/src/transformers/r3_strip_decorators.ts @@ -9,7 +9,7 @@ import {StaticReflector, StaticSymbol} from '@angular/compiler'; import * as ts from 'typescript'; -import {MetadataValue, isClassMetadata, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicCallExpression} from '../metadata'; +import {isClassMetadata, isMetadataImportedSymbolReferenceExpression, isMetadataSymbolicCallExpression, MetadataValue} from '../metadata'; import {MetadataTransformer, ValueTransform} from './metadata_cache'; @@ -39,8 +39,14 @@ export function getDecoratorStripTransformerFactory( }); if (decorators.length !== node.decorators.length) { return ts.updateClassDeclaration( - node, decorators, node.modifiers, node.name, node.typeParameters, - node.heritageClauses || [], node.members, ); + node, + decorators, + node.modifiers, + node.name, + node.typeParameters, + node.heritageClauses || [], + node.members, + ); } return node; }; @@ -130,7 +136,7 @@ function resolveToStaticSymbol( if (!ts.isImportSpecifier(decl)) { return null; } - const moduleSpecifier = decl.parent !.parent !.parent !.moduleSpecifier; + const moduleSpecifier = decl.parent!.parent!.parent!.moduleSpecifier; if (!ts.isStringLiteral(moduleSpecifier)) { return null; } diff --git a/packages/compiler-cli/src/transformers/util.ts b/packages/compiler-cli/src/transformers/util.ts index 8d35326e27a29..9df0d763657fc 100644 --- a/packages/compiler-cli/src/transformers/util.ts +++ b/packages/compiler-cli/src/transformers/util.ts @@ -16,7 +16,11 @@ export const GENERATED_FILES = /(.*?)\.(ngfactory|shim\.ngstyle|ngstyle|ngsummar export const DTS = /\.d\.ts$/; export const TS = /^(?!.*\.d\.ts$).*\.ts$/; -export const enum StructureIsReused {Not = 0, SafeModules = 1, Completely = 2} +export const enum StructureIsReused { + Not = 0, + SafeModules = 1, + Completely = 2 +} // Note: This is an internal property in TypeScript. Use it only for assertions and tests. export function tsStructureIsReused(program: ts.Program): StructureIsReused { @@ -36,7 +40,8 @@ export function createMessageDiagnostic(messageText: string): ts.Diagnostic&Diag file: undefined, start: undefined, length: undefined, - category: ts.DiagnosticCategory.Message, messageText, + category: ts.DiagnosticCategory.Message, + messageText, code: DEFAULT_ERROR_CODE, source: SOURCE, }; @@ -76,7 +81,7 @@ export function ngToTsDiagnostic(ng: Diagnostic): ts.Diagnostic { // Note: We can't use a real ts.SourceFile, // but we can at least mirror the properties `fileName` and `text`, which // are mostly used for error reporting. - file = { fileName: ng.span.start.file.url, text: ng.span.start.file.content } as ts.SourceFile; + file = {fileName: ng.span.start.file.url, text: ng.span.start.file.content} as ts.SourceFile; start = ng.span.start.offset; length = ng.span.end.offset - start; } @@ -84,6 +89,8 @@ export function ngToTsDiagnostic(ng: Diagnostic): ts.Diagnostic { file, messageText: ng.messageText, category: ng.category, - code: ng.code, start, length, + code: ng.code, + start, + length, }; } diff --git a/packages/compiler-cli/src/typescript_support.ts b/packages/compiler-cli/src/typescript_support.ts index 3a3e3e6476ed1..98945def78e8b 100644 --- a/packages/compiler-cli/src/typescript_support.ts +++ b/packages/compiler-cli/src/typescript_support.ts @@ -49,8 +49,8 @@ export function restoreTypeScriptVersionForTesting(): void { */ export function checkVersion(version: string, minVersion: string, maxVersion: string) { if ((compareVersions(version, minVersion) < 0 || compareVersions(version, maxVersion) >= 0)) { - throw new Error( - `The Angular Compiler requires TypeScript >=${minVersion} and <${maxVersion} but ${version} was found instead.`); + throw new Error(`The Angular Compiler requires TypeScript >=${minVersion} and <${ + maxVersion} but ${version} was found instead.`); } } diff --git a/packages/compiler-cli/test/compliance/mock_compile.ts b/packages/compiler-cli/test/compliance/mock_compile.ts index e0c905ded73ff..bae4cc8632d94 100644 --- a/packages/compiler-cli/test/compliance/mock_compile.ts +++ b/packages/compiler-cli/test/compliance/mock_compile.ts @@ -7,8 +7,9 @@ */ import {AotCompilerOptions} from '@angular/compiler'; import {escapeRegExp} from '@angular/compiler/src/util'; -import {MockCompilerHost, MockData, MockDirectory, arrayToMockDir, toMockFileArray} from '@angular/compiler/test/aot/test_util'; +import {arrayToMockDir, MockCompilerHost, MockData, MockDirectory, toMockFileArray} from '@angular/compiler/test/aot/test_util'; import * as ts from 'typescript'; + import {NodeJSFileSystem, setFileSystem} from '../../src/ngtsc/file_system'; import {NgtscProgram} from '../../src/ngtsc/program'; @@ -22,10 +23,11 @@ const NUMBER = /\d+/; const ELLIPSIS = '…'; const TOKEN = new RegExp( - `\\s*((${IDENTIFIER.source})|(${BACKTICK_STRING.source})|(${OPERATOR.source})|(${STRING.source})|${NUMBER.source}|${ELLIPSIS})\\s*`, + `\\s*((${IDENTIFIER.source})|(${BACKTICK_STRING.source})|(${OPERATOR.source})|(${ + STRING.source})|${NUMBER.source}|${ELLIPSIS})\\s*`, 'y'); -type Piece = string | RegExp; +type Piece = string|RegExp; const SKIP = /(?:.|\n|\r)*/; @@ -116,15 +118,16 @@ export function expectEmit( const context = fullContext.length > contextLength ? `...${fullContext.substr(-contextLength)}` : fullContext; - fail( - `${description}: Failed to find "${expectedPiece}" after "${context}" in:\n'${source.substr(0,last)}[<---HERE expected "${expectedPiece}"]${source.substr(last)}'`); + fail(`${description}: Failed to find "${expectedPiece}" after "${context}" in:\n'${ + source.substr(0, last)}[<---HERE expected "${expectedPiece}"]${source.substr(last)}'`); return; } else { last = (m.index || 0) + m[0].length; } } fail( - `Test helper failure: Expected expression failed but the reporting logic could not find where it failed in: ${source}`); + `Test helper failure: Expected expression failed but the reporting logic could not find where it failed in: ${ + source}`); } else { if (assertIdentifiers) { // It might be possible to add the constraints in the original regexp (see `buildMatcher`) @@ -141,8 +144,8 @@ export function expectEmit( const name = matches[groups.get(id) as number]; const regexp = assertIdentifiers[id]; if (!regexp.test(name)) { - throw Error( - `${description}: The matching identifier "${id}" is "${name}" which doesn't match ${regexp}`); + throw Error(`${description}: The matching identifier "${id}" is "${ + name}" which doesn't match ${regexp}`); } } } @@ -160,7 +163,7 @@ const MATCHING_IDENT = /^\$.*\$$/; * - the `regexp` to be used to match the generated code, * - the `groups` which maps `$...$` identifier to their position in the regexp matches. */ -function buildMatcher(pieces: (string | RegExp)[]): {regexp: RegExp, groups: Map<string, number>} { +function buildMatcher(pieces: (string|RegExp)[]): {regexp: RegExp, groups: Map<string, number>} { const results: string[] = []; let first = true; let group = 0; @@ -196,7 +199,9 @@ function buildMatcher(pieces: (string | RegExp)[]): {regexp: RegExp, groups: Map export function compile( data: MockDirectory, angularFiles: MockData, options: AotCompilerOptions = {}, - errorCollector: (error: any, fileName?: string) => void = error => { throw error;}): { + errorCollector: (error: any, fileName?: string) => void = error => { + throw error; + }): { source: string, } { setFileSystem(new NodeJSFileSystem()); @@ -211,7 +216,8 @@ export function compile( target: ts.ScriptTarget.ES2015, module: ts.ModuleKind.ES2015, moduleResolution: ts.ModuleResolutionKind.NodeJs, - enableI18nLegacyMessageIdFormat: false, ...options, + enableI18nLegacyMessageIdFormat: false, + ...options, }, mockCompilerHost); program.emit(); diff --git a/packages/compiler-cli/test/compliance/mock_compiler_spec.ts b/packages/compiler-cli/test/compliance/mock_compiler_spec.ts index a1422aa4cc832..fe6166022ce3c 100644 --- a/packages/compiler-cli/test/compliance/mock_compiler_spec.ts +++ b/packages/compiler-cli/test/compliance/mock_compiler_spec.ts @@ -100,14 +100,14 @@ describe('mock_compiler', () => { it('should be able to properly handle string literals with escaped quote', () => { const files = { app: { - 'test.ts': String.raw `const identifier = "\"quoted\"";`, + 'test.ts': String.raw`const identifier = "\"quoted\"";`, } }; const result = compile(files, angularFiles); expect(() => { - expectEmit(result.source, String.raw `const $a$ = "\"quoted\"";`, 'Output does not match.'); + expectEmit(result.source, String.raw`const $a$ = "\"quoted\"";`, 'Output does not match.'); }).not.toThrow(); }); }); diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts index 1df894c1c0a52..00f1155b5876b 100644 --- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts @@ -16,7 +16,6 @@ import {compile, expectEmit} from './mock_compile'; * test in compiler_canonical_spec.ts should have a corresponding test here. */ describe('compiler compliance', () => { - const angularFiles = setup({ compileAngular: false, compileAnimations: false, @@ -49,7 +48,8 @@ describe('compiler compliance', () => { // The template should look like this (where IDENT is a wild card for an identifier): const template = ` … - consts: [["title", "Hello", ${AttributeMarker.Classes}, "my-app"], ["cx", "20", "cy", "30", "r", "50"]], + consts: [["title", "Hello", ${ + AttributeMarker.Classes}, "my-app"], ["cx", "20", "cy", "30", "r", "50"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "div", 0); @@ -536,7 +536,6 @@ describe('compiler compliance', () => { const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect template'); }); - }); describe('components & directives', () => { @@ -867,7 +866,6 @@ describe('compiler compliance', () => { }); describe('value composition', () => { - it('should support array literals', () => { const files = { app: { @@ -1143,7 +1141,6 @@ describe('compiler compliance', () => { }); describe('content projection', () => { - it('should support content projection in root template', () => { const files = { app: { @@ -1319,7 +1316,8 @@ describe('compiler compliance', () => { } const $_c4$ = [[["span", "title", "tofirst"]], "*"]; … - consts: [["id", "second", ${AttributeMarker.Template}, "ngIf"], ["id", "third", ${AttributeMarker.Template}, "ngIf"], ["id", "second"], ["id", "third"]], + consts: [["id", "second", ${AttributeMarker.Template}, "ngIf"], ["id", "third", ${ + AttributeMarker.Template}, "ngIf"], ["id", "second"], ["id", "third"]], template: function Cmp_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵprojectionDef($_c4$); @@ -1534,7 +1532,8 @@ describe('compiler compliance', () => { decls: 1, vars: 1, consts: [ - ["ngProjectAs", ".someclass", ${AttributeMarker.ProjectAs}, ["", 8, "someclass"], ${AttributeMarker.Template}, "ngIf"], + ["ngProjectAs", ".someclass", ${AttributeMarker.ProjectAs}, ["", 8, "someclass"], ${ + AttributeMarker.Template}, "ngIf"], ["ngProjectAs", ".someclass", ${AttributeMarker.ProjectAs}, ["", 8, "someclass"]] ], template: function MyApp_Template(rf, ctx) { @@ -1552,7 +1551,6 @@ describe('compiler compliance', () => { const result = compile(files, angularFiles); expectEmit(result.source, SimpleComponentDefinition, 'Incorrect MyApp definition'); }); - }); describe('queries', () => { @@ -2044,9 +2042,7 @@ describe('compiler compliance', () => { }); describe('pipes', () => { - it('should render pipes', () => { - const files = { app: { 'spec.ts': ` @@ -2217,7 +2213,6 @@ describe('compiler compliance', () => { it('should generate the proper instruction when injecting ChangeDetectorRef into a pipe', () => { - const files = { app: { 'spec.ts': ` @@ -2282,7 +2277,6 @@ describe('compiler compliance', () => { expectEmit(source, MyOtherPipeDefinition, 'Invalid alternate pipe definition'); expectEmit(source, MyOtherPipeFactory, 'Invalid alternate pipe factory function'); }); - }); it('local reference', () => { @@ -2477,7 +2471,8 @@ describe('compiler compliance', () => { } // ... - consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], ["foo", ""], [${AttributeMarker.Template}, "ngIf"]], + consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], ["foo", ""], [${ + AttributeMarker.Template}, "ngIf"]], template:function MyComponent_Template(rf, ctx){ if (rf & 1) { $i0$.ɵɵtemplate(0, MyComponent_div_0_Template, 4, 1, "div", 0); @@ -3280,7 +3275,6 @@ describe('compiler compliance', () => { const result = compile(files, angularFiles); expectEmit(result.source, MyAppDeclaration, 'Invalid component definition'); }); - }); describe('inherited base classes', () => { @@ -3849,7 +3843,7 @@ describe('compiler compliance', () => { } }; const result = compile(files, angularFiles); - expect(result.source.match(/ɵdir/g) !.length).toBe(1); + expect(result.source.match(/ɵdir/g)!.length).toBe(1); }); }); }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts index 98cdd94271e88..1a962dc5ee17a 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_binding_spec.ts @@ -405,7 +405,6 @@ describe('compiler compliance: bindings', () => { expectEmit(result.source, template, 'Incorrect template'); }); - }); describe('attribute bindings', () => { @@ -640,13 +639,13 @@ describe('compiler compliance: bindings', () => { }; const template = ` - consts: [["target", "_blank", "aria-label", "link", ${AttributeMarker.Bindings}, "title", "id", "customEvent"]], + consts: [["target", "_blank", "aria-label", "link", ${ + AttributeMarker.Bindings}, "title", "id", "customEvent"]], … `; const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect attribute array'); }); - }); describe('host bindings', () => { @@ -850,12 +849,15 @@ describe('compiler compliance: bindings', () => { HostAttributeComp.ɵcmp = $r3$.ɵɵdefineComponent({ type: HostAttributeComp, selectors: [["my-host-attribute-component"]], - hostAttrs: ["title", "hello there from component", ${AttributeMarker.Styles}, "opacity", "1"], + hostAttrs: ["title", "hello there from component", ${ + AttributeMarker.Styles}, "opacity", "1"], … HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({ type: HostAttributeDir, selectors: [["", "hostAttributeDir", ""]], - hostAttrs: ["title", "hello there from directive", ${AttributeMarker.Classes}, "one", "two", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"], + hostAttrs: ["title", "hello there from directive", ${ + AttributeMarker.Classes}, "one", "two", ${ + AttributeMarker.Styles}, "width", "200px", "height", "500px"], hostVars: 4, hostBindings: function HostAttributeDir_HostBindings(rf, ctx) { … @@ -1216,7 +1218,6 @@ describe('compiler compliance: bindings', () => { `; expectEmit(result.source, template, 'Incorrect template'); }); - }); describe('non bindable behavior', () => { @@ -1420,7 +1421,5 @@ describe('compiler compliance: bindings', () => { const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect handling of elements with no children'); }); - }); - }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts index 935d4e447af6a..91f70e9d03c87 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_di_spec.ts @@ -386,8 +386,7 @@ describe('compiler compliance: dependency injection', () => { expectEmit(source, MyPipeDefs, 'Invalid pipe factory function'); expectEmit(source, MyOtherPipeDefs, 'Invalid pipe factory function'); - expect(source.match(/MyPipe\.ɵfac =/g) !.length).toBe(1); - expect(source.match(/MyOtherPipe\.ɵfac =/g) !.length).toBe(1); + expect(source.match(/MyPipe\.ɵfac =/g)!.length).toBe(1); + expect(source.match(/MyOtherPipe\.ɵfac =/g)!.length).toBe(1); }); - }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts index 918ef6701ed61..b71ff345c949b 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_directives_spec.ts @@ -10,7 +10,6 @@ import {setup} from '@angular/compiler/test/aot/test_util'; import {compile, expectEmit} from './mock_compile'; describe('compiler compliance: directives', () => { - const angularFiles = setup({ compileAngular: false, compileAnimations: false, @@ -18,7 +17,6 @@ describe('compiler compliance: directives', () => { }); describe('matching', () => { - it('should not match directives on i18n attribute', () => { const files = { app: { @@ -114,7 +112,6 @@ describe('compiler compliance: directives', () => { }); it('should match directives on element bindings', () => { - const files = { app: { 'spec.ts': ` @@ -273,7 +270,6 @@ describe('compiler compliance: directives', () => { }); it('should match directives on ng-template bindings', () => { - const files = { app: { 'spec.ts': ` @@ -321,7 +317,6 @@ describe('compiler compliance: directives', () => { }); it('should match structural directives', () => { - const files = { app: { 'spec.ts': ` @@ -362,11 +357,9 @@ describe('compiler compliance: directives', () => { const source = result.source; expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ɵcmp'); - }); it('should match directives on element outputs', () => { - const files = { app: { 'spec.ts': ` @@ -413,6 +406,5 @@ describe('compiler compliance: directives', () => { expectEmit(source, MyComponentDefinition, 'Incorrect ChildComponent.ɵcmp'); }); - }); }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts index 935859f2dfad6..eee7e684edada 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts @@ -58,7 +58,9 @@ const verifyTranslationIds = }); const regexp = /const\s*MSG_EXTERNAL_(.+?)\s*=\s*goog\.getMsg/g; const ids = extract(output, regexp, v => v[1]); - ids.forEach(id => { generatedIds.add(id.split('$$')[0]); }); + ids.forEach(id => { + generatedIds.add(id.split('$$')[0]); + }); const delta = diff(extractedIds, generatedIds); if (delta.size) { // check if we have ids in exception list @@ -179,7 +181,6 @@ const verify = (input: string, output: string, extra: any = {}): void => { }; describe('i18n support in the template compiler', () => { - describe('element attributes', () => { it('should add the meaning and description as JsDoc comments and metadata blocks', () => { const input = ` @@ -193,7 +194,7 @@ describe('i18n support in the template compiler', () => { <div i18n="Some text \\' [BACKUP_MESSAGE_ID: xxx]">Content H</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -269,8 +270,8 @@ describe('i18n support in the template compiler', () => { if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** * @desc [BACKUP_$` + - String.raw `{MESSAGE}_ID:idH]` + - '`' + String.raw `desc + String.raw`{MESSAGE}_ID:idH]` + + '`' + String.raw`desc */ const $MSG_EXTERNAL_idG$$APP_SPEC_TS_24$ = goog.getMsg("Title G"); $I18N_23$ = $MSG_EXTERNAL_idG$$APP_SPEC_TS_24$; @@ -338,7 +339,7 @@ describe('i18n support in the template compiler', () => { // TODO (FW-1942): update the code to avoid adding `title` attribute in plain form // into the `consts` array on Component def. - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6616505470450179563$$APP_SPEC_TS_1$ = goog.getMsg("Hello"); @@ -368,7 +369,7 @@ describe('i18n support in the template compiler', () => { // TODO (FW-1942): update the code to avoid adding `title` attribute in plain form // into the `consts` array on Component def. - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6616505470450179563$$APP_SPEC_TS_1$ = goog.getMsg("Hello"); @@ -409,7 +410,7 @@ describe('i18n support in the template compiler', () => { <ng-template i18n-title title="Hello {{ name }}"></ng-template> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_3771704108176831903$$APP_SPEC_TS_1$ = goog.getMsg("Hello {$interpolation}", { @@ -419,7 +420,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`Hello $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c2$ = ["title", $I18N_0$]; … @@ -444,7 +445,7 @@ describe('i18n support in the template compiler', () => { <ng-template *ngIf="true" i18n-title title="Hello {{ name }}"></ng-template> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_3771704108176831903$$APP_SPEC_TS__1$ = goog.getMsg("Hello {$interpolation}", { @@ -454,7 +455,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`Hello $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c2$ = ["title", $I18N_0$]; … @@ -531,7 +532,7 @@ describe('i18n support in the template compiler', () => { <div id="static" i18n-title="m|d" title="introduction"></div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -572,7 +573,7 @@ describe('i18n support in the template compiler', () => { ></div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_5526535577705876535$$APP_SPEC_TS_1$ = goog.getMsg("static text"); @@ -594,7 +595,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`:m|d:intro $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } var $I18N_3$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -609,7 +610,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_3$ = $localize \`:m1|d1:$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c1$ = [ "aria-roledescription", $I18N_1$, @@ -629,9 +630,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_6$ = $localize \`:m2|d2:$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + - String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` + - String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + + String.raw`{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` + + String.raw`{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`; } var $I18N_7$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -642,7 +643,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_7$ = $localize \`$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c3$ = [ "title", $I18N_6$, @@ -651,7 +652,10 @@ describe('i18n support in the template compiler', () => { … decls: 5, vars: 8, - consts: [["id", "dynamic-1", ${AttributeMarker.I18n}, "aria-roledescription", "title", "aria-label"], ["id", "dynamic-2", ${AttributeMarker.I18n}, "title", "aria-roledescription"]], + consts: [["id", "dynamic-1", ${ + AttributeMarker + .I18n}, "aria-roledescription", "title", "aria-label"], ["id", "dynamic-2", ${ + AttributeMarker.I18n}, "title", "aria-roledescription"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "div", 0); @@ -680,7 +684,7 @@ describe('i18n support in the template compiler', () => { <div i18n-title="m|d" title="intro {% valueA | uppercase %}"></div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -694,7 +698,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \`:m|d:intro $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c3$ = ["title", $I18N_1$]; … @@ -722,7 +726,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -736,7 +740,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \`:m|d:different scope $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c2$ = ["title", $I18N_1$]; function MyComponent_div_0_Template(rf, ctx) { @@ -758,7 +762,8 @@ describe('i18n support in the template compiler', () => { … decls: 1, vars: 1, - consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.I18n}, "title"]], + consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${ + AttributeMarker.I18n}, "title"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_div_0_Template, 4, 3, "div", 0); @@ -777,7 +782,7 @@ describe('i18n support in the template compiler', () => { <div i18n-title title="{{valueA.getRawValue()?.getTitle()}} title"></div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_3462388422673575127$$APP_SPEC_TS_2$ = goog.getMsg("{$interpolation} title", { @@ -787,7 +792,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \`$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: title\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: title\`; } const $_c3$ = ["title", $I18N_1$]; … @@ -825,7 +830,7 @@ describe('i18n support in the template compiler', () => { ></div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_5526535577705876535$$APP_SPEC_TS_1$ = goog.getMsg("static text"); @@ -847,7 +852,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`:m|d:intro $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } var $I18N_3$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -862,7 +867,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_3$ = $localize \`:m1|d1:$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c1$ = [ "aria-roledescription", $I18N_1$, @@ -882,9 +887,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_6$ = $localize \`:m2|d2:$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + - String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` + - String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + + String.raw`{"\uFFFD1\uFFFD"}:INTERPOLATION_1: and again $` + + String.raw`{"\uFFFD2\uFFFD"}:INTERPOLATION_2:\`; } var $I18N_7$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -895,7 +900,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_7$ = $localize \`$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c3$ = [ "title", $I18N_6$, @@ -938,7 +943,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_2$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -952,7 +957,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`:m|d:different scope $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c4$ = ["title", $I18N_2$]; function MyComponent_div_0_Template(rf, ctx) { @@ -974,7 +979,8 @@ describe('i18n support in the template compiler', () => { … decls: 1, vars: 1, - consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.I18n}, "title"]], + consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${ + AttributeMarker.I18n}, "title"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_div_0_Template, 4, 3, "div", 0); @@ -993,7 +999,7 @@ describe('i18n support in the template compiler', () => { <div i18n i18n-title="m|d" title="Element title">Some content</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -1036,7 +1042,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_ID_WITH_INVALID_CHARS$$APP_SPEC_TS_1$ = goog.getMsg("Element title"); @@ -1075,7 +1081,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "div"); @@ -1097,7 +1103,7 @@ describe('i18n support in the template compiler', () => { <div i18n>Some <!-- comments --> text</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_1$ = goog.getMsg("Some text"); @@ -1115,11 +1121,11 @@ describe('i18n support in the template compiler', () => { <div i18n>Some text 'with single quotes', "with double quotes", \`with backticks\` and without quotes.</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_4924931801512133405$$APP_SPEC_TS_0$ = goog.getMsg("Some text 'with single quotes', \"with double quotes\", ` + - '`with backticks`' + String.raw ` and without quotes."); + '`with backticks`' + String.raw` and without quotes."); $I18N_0$ = $MSG_EXTERNAL_4924931801512133405$$APP_SPEC_TS_0$; } else { @@ -1132,16 +1138,16 @@ describe('i18n support in the template compiler', () => { it('should handle interpolations wrapped in backticks', () => { const input = '<div i18n>`{{ count }}`</div>'; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_1$ = goog.getMsg("` + - '`{$interpolation}`' + String.raw `", { "interpolation": "\uFFFD0\uFFFD" }); + '`{$interpolation}`' + String.raw`", { "interpolation": "\uFFFD0\uFFFD" }); $I18N_0$ = $MSG_APP_SPEC_TS_1$; } else { $I18N_0$ = $localize \`\\\`$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\\\`\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\\\`\`; }`; verify(input, output); }); @@ -1155,7 +1161,7 @@ describe('i18n support in the template compiler', () => { <div i18n>My i18n block #3</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS_0$ = goog.getMsg("My i18n block #1"); @@ -1213,7 +1219,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7597881511811528589$$APP_SPEC_TS_0$ = goog.getMsg(" Named interpolation: {$phA} Named interpolation with spaces: {$phB} ", { @@ -1224,8 +1230,8 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` Named interpolation: $` + - String.raw `{"\uFFFD0\uFFFD"}:PH_A: Named interpolation with spaces: $` + - String.raw `{"\uFFFD1\uFFFD"}:PH_B: \`; + String.raw`{"\uFFFD0\uFFFD"}:PH_A: Named interpolation with spaces: $` + + String.raw`{"\uFFFD1\uFFFD"}:PH_B: \`; } … decls: 2, @@ -1252,7 +1258,7 @@ describe('i18n support in the template compiler', () => { <div i18n>{% valueA %}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6749967533321674787$$APP_SPEC_TS_0$ = goog.getMsg("{$interpolation}", { @@ -1262,7 +1268,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } … template: function MyComponent_Template(rf, ctx) { @@ -1290,7 +1296,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_1$$APP_SPEC_TS_1$ = goog.getMsg(" {$interpolation} {$interpolation_1} {$interpolation_2} ", { @@ -1302,9 +1308,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + - String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + - String.raw `{"\uFFFD2\uFFFD"}:INTERPOLATION_2: \`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + + String.raw`{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + + String.raw`{"\uFFFD2\uFFFD"}:INTERPOLATION_2: \`; } … template: function MyComponent_Template(rf, ctx) { @@ -1333,7 +1339,7 @@ describe('i18n support in the template compiler', () => { <div i18n>My i18n block #{{ three + four + five }}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_572579892698764378$$APP_SPEC_TS_0$ = goog.getMsg("My i18n block #{$interpolation}", { @@ -1343,7 +1349,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`My i18n block #$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -1354,7 +1360,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \`My i18n block #$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } var $I18N_2$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -1365,7 +1371,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`My i18n block #$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } … decls: 7, @@ -1418,7 +1424,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7905233330103651696$$APP_SPEC_TS_0$ = goog.getMsg(" My i18n block #{$interpolation} {$startTagSpan}Plain text in nested element{$closeTagSpan}", { @@ -1430,9 +1436,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` My i18n block #$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + - String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:Plain text in nested element$` + - String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + + String.raw`{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:Plain text in nested element$` + + String.raw`{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; } var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -1448,14 +1454,14 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \` My i18n block #$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + - String.raw `{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` + - String.raw `{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` + String.raw + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + + String.raw`{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` + + String.raw`{"[\uFFFD#6\uFFFD|\uFFFD#7\uFFFD]"}:START_TAG_DIV:$` + String.raw `{"\uFFFD#8\uFFFD"}:START_TAG_SPAN: More bindings in more nested element: $` + - String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + - String.raw `{"\uFFFD/#8\uFFFD"}:CLOSE_TAG_SPAN:$` + - String.raw `{"[\uFFFD/#7\uFFFD|\uFFFD/#6\uFFFD]"}:CLOSE_TAG_DIV:$` + - String.raw `{"[\uFFFD/#7\uFFFD|\uFFFD/#6\uFFFD]"}:CLOSE_TAG_DIV:\`; + String.raw`{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + + String.raw`{"\uFFFD/#8\uFFFD"}:CLOSE_TAG_SPAN:$` + + String.raw`{"[\uFFFD/#7\uFFFD|\uFFFD/#6\uFFFD]"}:CLOSE_TAG_DIV:$` + + String.raw`{"[\uFFFD/#7\uFFFD|\uFFFD/#6\uFFFD]"}:CLOSE_TAG_DIV:\`; } $I18N_1$ = $r3$.ɵɵi18nPostprocess($I18N_1$); … @@ -1509,7 +1515,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_2$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_4782264005467235841$$APP_SPEC_TS_3$ = goog.getMsg("Span title {$interpolation} and {$interpolation_1}", { @@ -1520,8 +1526,8 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`Span title $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + - String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: and $` + + String.raw`{"\uFFFD1\uFFFD"}:INTERPOLATION_1:\`; } const $_c4$ = ["title", $I18N_2$]; var $I18N_0$; @@ -1535,9 +1541,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` My i18n block #1 with value: $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #1) $` + - String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; + String.raw`{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; } var $I18N_7$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -1548,7 +1554,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_7$ = $localize \`Span title $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c9$ = ["title", $I18N_7$]; var $I18N_6$; @@ -1562,9 +1568,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_6$ = $localize \` My i18n block #2 with value $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + String.raw `{"\uFFFD#7\uFFFD"}:START_TAG_SPAN: Plain text in nested element (block #2) $` + - String.raw `{"\uFFFD/#7\uFFFD"}:CLOSE_TAG_SPAN:\`; + String.raw`{"\uFFFD/#7\uFFFD"}:CLOSE_TAG_SPAN:\`; } … decls: 9, @@ -1623,7 +1629,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7679414751795588050$$APP_SPEC_TS__1$ = goog.getMsg(" Some other content {$interpolation} {$startTagDiv} More nested levels with bindings {$interpolation_1} {$closeTagDiv}", { @@ -1636,10 +1642,10 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \` Some other content $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + - String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_DIV: More nested levels with bindings $` + - String.raw `{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + - String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_DIV:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION: $` + + String.raw`{"\uFFFD#3\uFFFD"}:START_TAG_DIV: More nested levels with bindings $` + + String.raw`{"\uFFFD1\uFFFD"}:INTERPOLATION_1: $` + + String.raw`{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_DIV:\`; } … function MyComponent_div_2_Template(rf, ctx) { @@ -1688,7 +1694,7 @@ describe('i18n support in the template compiler', () => { <img src="logo.png" i18n *ngIf="visible" i18n-title title="App logo #{{ id }}" /> `; - const output = String.raw ` + const output = String.raw` function MyComponent_img_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "img", 0); @@ -1703,7 +1709,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`App logo #$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } const $_c4$ = ["title", $I18N_2$]; function MyComponent_img_2_Template(rf, ctx) { @@ -1721,7 +1727,11 @@ describe('i18n support in the template compiler', () => { … decls: 3, vars: 2, - consts: [["src", "logo.png"], ["src", "logo.png", ${AttributeMarker.Template}, "ngIf"], ["src", "logo.png", ${AttributeMarker.Bindings}, "title", ${AttributeMarker.Template}, "ngIf"], ["src", "logo.png", ${AttributeMarker.I18n}, "title"]], + consts: [["src", "logo.png"], ["src", "logo.png", ${ + AttributeMarker.Template}, "ngIf"], ["src", "logo.png", ${ + AttributeMarker.Bindings}, "title", ${ + AttributeMarker.Template}, "ngIf"], ["src", "logo.png", ${ + AttributeMarker.I18n}, "title"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelement(0, "img", 0); @@ -1765,7 +1775,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` function MyComponent_div_2_div_4_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵi18nStart(0, $I18N_0$, 2); @@ -1821,13 +1831,13 @@ describe('i18n support in the template compiler', () => { $I18N_0$ = $localize \` Some content $` + String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_DIV_2: Some other content $` + - String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw + String.raw`{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw `{"[\uFFFD#2:1\uFFFD|\uFFFD#2:2\uFFFD|\uFFFD#2:3\uFFFD]"}:START_TAG_DIV: More nested levels with bindings $` + - String.raw `{"\uFFFD1:1\uFFFD"}:INTERPOLATION_1: $` + String.raw + String.raw`{"\uFFFD1:1\uFFFD"}:INTERPOLATION_1: $` + String.raw `{"\uFFFD*4:2\uFFFD\uFFFD#1:2\uFFFD"}:START_TAG_DIV_1: Content inside sub-template $` + - String.raw `{"\uFFFD0:2\uFFFD"}:INTERPOLATION_2: $` + String.raw + String.raw`{"\uFFFD0:2\uFFFD"}:INTERPOLATION_2: $` + String.raw `{"[\uFFFD#2:1\uFFFD|\uFFFD#2:2\uFFFD|\uFFFD#2:3\uFFFD]"}:START_TAG_DIV: Bottom level element $` + - String.raw `{"\uFFFD1:2\uFFFD"}:INTERPOLATION_3: $` + String.raw + String.raw`{"\uFFFD1:2\uFFFD"}:INTERPOLATION_3: $` + String.raw `{"[\uFFFD/#2:2\uFFFD|\uFFFD/#1:2\uFFFD\uFFFD/*4:2\uFFFD|\uFFFD/#2:1\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD|\uFFFD/#2:3\uFFFD|\uFFFD/#1:3\uFFFD\uFFFD/*3:3\uFFFD]"}:CLOSE_TAG_DIV:$` + String.raw `{"[\uFFFD/#2:2\uFFFD|\uFFFD/#1:2\uFFFD\uFFFD/*4:2\uFFFD|\uFFFD/#2:1\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD|\uFFFD/#2:3\uFFFD|\uFFFD/#1:3\uFFFD\uFFFD/*3:3\uFFFD]"}:CLOSE_TAG_DIV:$` + @@ -1837,9 +1847,9 @@ describe('i18n support in the template compiler', () => { `{"[\uFFFD/#2:2\uFFFD|\uFFFD/#1:2\uFFFD\uFFFD/*4:2\uFFFD|\uFFFD/#2:1\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD|\uFFFD/#2:3\uFFFD|\uFFFD/#1:3\uFFFD\uFFFD/*3:3\uFFFD]"}:CLOSE_TAG_DIV:$` + String.raw `{"\uFFFD*3:3\uFFFD\uFFFD#1:3\uFFFD"}:START_TAG_DIV_3: Some other content $` + - String.raw `{"\uFFFD0:3\uFFFD"}:INTERPOLATION_4: $` + String.raw + String.raw`{"\uFFFD0:3\uFFFD"}:INTERPOLATION_4: $` + String.raw `{"[\uFFFD#2:1\uFFFD|\uFFFD#2:2\uFFFD|\uFFFD#2:3\uFFFD]"}:START_TAG_DIV: More nested levels with bindings $` + - String.raw `{"\uFFFD1:3\uFFFD"}:INTERPOLATION_5: $` + String.raw + String.raw`{"\uFFFD1:3\uFFFD"}:INTERPOLATION_5: $` + String.raw `{"[\uFFFD/#2:2\uFFFD|\uFFFD/#1:2\uFFFD\uFFFD/*4:2\uFFFD|\uFFFD/#2:1\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD|\uFFFD/#2:3\uFFFD|\uFFFD/#1:3\uFFFD\uFFFD/*3:3\uFFFD]"}:CLOSE_TAG_DIV:$` + String.raw `{"[\uFFFD/#2:2\uFFFD|\uFFFD/#1:2\uFFFD\uFFFD/*4:2\uFFFD|\uFFFD/#2:1\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD|\uFFFD/#2:3\uFFFD|\uFFFD/#1:3\uFFFD\uFFFD/*3:3\uFFFD]"}:CLOSE_TAG_DIV:\`; @@ -1891,7 +1901,7 @@ describe('i18n support in the template compiler', () => { <div i18n *ngIf="visible">Some other content <span>{{ valueA }}</span></div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_119975189388320493$$APP_SPEC_TS__1$ = goog.getMsg("Some other content {$startTagSpan}{$interpolation}{$closeTagSpan}", { @@ -1903,9 +1913,9 @@ describe('i18n support in the template compiler', () => { } else { $I18N_1$ = $localize \`Some other content $` + - String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:$` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:$` + - String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; + String.raw`{"\uFFFD#2\uFFFD"}:START_TAG_SPAN:$` + + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:$` + + String.raw`{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_SPAN:\`; } … function MyComponent_div_0_Template(rf, ctx) { @@ -1945,7 +1955,7 @@ describe('i18n support in the template compiler', () => { <div i18n (click)="onClick()">Hello</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_2$ = goog.getMsg("Hello"); @@ -1976,7 +1986,7 @@ describe('i18n support in the template compiler', () => { <div i18n>My i18n block #1</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_4890179241114413722$$APP_SPEC_TS_0$ = goog.getMsg("My i18n block #1"); @@ -2003,7 +2013,7 @@ describe('i18n support in the template compiler', () => { <div i18n>{age, select, 10 {ten} 20 {twenty} other {other}}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); @@ -2041,7 +2051,7 @@ describe('i18n support in the template compiler', () => { <ng-container i18n>My i18n block #2</ng-container> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_2413150872298537152$$APP_SPEC_TS_0$ = goog.getMsg("My i18n block #2"); @@ -2083,7 +2093,7 @@ describe('i18n support in the template compiler', () => { <span i18n style="padding: 10px;">Text #2</span> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_5295701706185791735$$APP_SPEC_TS_1$ = goog.getMsg("Text #1"); @@ -2103,7 +2113,8 @@ describe('i18n support in the template compiler', () => { … decls: 4, vars: 0, - consts: [[${AttributeMarker.Classes}, "myClass"], [${AttributeMarker.Styles}, "padding", "10px"]], + consts: [[${AttributeMarker.Classes}, "myClass"], [${ + AttributeMarker.Styles}, "padding", "10px"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "span", 0); @@ -2126,7 +2137,7 @@ describe('i18n support in the template compiler', () => { <ng-container i18n>Some content: {{ valueA | uppercase }}</ng-container> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS_0$ = goog.getMsg("Some content: {$interpolation}", { @@ -2136,7 +2147,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`Some content: $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } … decls: 3, @@ -2164,7 +2175,7 @@ describe('i18n support in the template compiler', () => { <ng-template i18n>Some content: {{ valueA | uppercase }}</ng-template> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_355394464191978948$$APP_SPEC_TS__0$ = goog.getMsg("Some content: {$interpolation}", { @@ -2174,7 +2185,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`Some content: $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION:\`; } function MyComponent_ng_template_0_Template(rf, ctx) { if (rf & 1) { @@ -2208,7 +2219,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_702706566400598764$$APP_SPEC_TS_0$ = goog.getMsg("{$startTagNgTemplate}Template content: {$interpolation}{$closeTagNgTemplate}{$startTagNgContainer}Container content: {$interpolation_1}{$closeTagNgContainer}", { @@ -2223,12 +2234,12 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`$` + - String.raw `{"\uFFFD*2:1\uFFFD"}:START_TAG_NG_TEMPLATE:Template content: $` + - String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION:$` + - String.raw `{"\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_NG_TEMPLATE:$` + - String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_NG_CONTAINER:Container content: $` + - String.raw `{"\uFFFD0\uFFFD"}:INTERPOLATION_1:$` + - String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; + String.raw`{"\uFFFD*2:1\uFFFD"}:START_TAG_NG_TEMPLATE:Template content: $` + + String.raw`{"\uFFFD0:1\uFFFD"}:INTERPOLATION:$` + + String.raw`{"\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_NG_TEMPLATE:$` + + String.raw`{"\uFFFD#3\uFFFD"}:START_TAG_NG_CONTAINER:Container content: $` + + String.raw`{"\uFFFD0\uFFFD"}:INTERPOLATION_1:$` + + String.raw`{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; } function MyComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) { @@ -2272,7 +2283,7 @@ describe('i18n support in the template compiler', () => { <ng-container>{age, select, 10 {ten} 20 {twenty} other {other}}</ng-container> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); @@ -2341,7 +2352,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` function MyComponent_ng_template_2_ng_template_2_ng_template_1_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵi18n(0, $I18N_0$, 3); @@ -2380,11 +2391,11 @@ describe('i18n support in the template compiler', () => { $I18N_0$ = $localize \`$` + String.raw `{"[\uFFFD*2:1\uFFFD|\uFFFD*2:2\uFFFD|\uFFFD*1:3\uFFFD]"}:START_TAG_NG_TEMPLATE: Template A: $` + - String.raw `{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw + String.raw`{"\uFFFD0:1\uFFFD"}:INTERPOLATION: $` + String.raw `{"[\uFFFD*2:1\uFFFD|\uFFFD*2:2\uFFFD|\uFFFD*1:3\uFFFD]"}:START_TAG_NG_TEMPLATE: Template B: $` + - String.raw `{"\uFFFD0:2\uFFFD"}:INTERPOLATION_1: $` + String.raw + String.raw`{"\uFFFD0:2\uFFFD"}:INTERPOLATION_1: $` + String.raw `{"[\uFFFD*2:1\uFFFD|\uFFFD*2:2\uFFFD|\uFFFD*1:3\uFFFD]"}:START_TAG_NG_TEMPLATE: Template C: $` + - String.raw `{"\uFFFD0:3\uFFFD"}:INTERPOLATION_2: $` + String.raw + String.raw`{"\uFFFD0:3\uFFFD"}:INTERPOLATION_2: $` + String.raw `{"[\uFFFD/*1:3\uFFFD|\uFFFD/*2:2\uFFFD|\uFFFD/*2:1\uFFFD]"}:CLOSE_TAG_NG_TEMPLATE:$` + String.raw `{"[\uFFFD/*1:3\uFFFD|\uFFFD/*2:2\uFFFD|\uFFFD/*2:1\uFFFD]"}:CLOSE_TAG_NG_TEMPLATE:$` + @@ -2429,7 +2440,7 @@ describe('i18n support in the template compiler', () => { <ng-template i18n>{age, select, 10 {ten} 20 {twenty} other {other}}</ng-template> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); @@ -2493,7 +2504,7 @@ describe('i18n support in the template compiler', () => { </ng-template> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_4891196282781544695$$APP_SPEC_TS_0$ = goog.getMsg("{$tagImg} is my logo #1 ", { @@ -2503,7 +2514,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \`$` + - String.raw `{"\uFFFD#2\uFFFD\uFFFD/#2\uFFFD"}:TAG_IMG: is my logo #1 \`; + String.raw`{"\uFFFD#2\uFFFD\uFFFD/#2\uFFFD"}:TAG_IMG: is my logo #1 \`; } var $I18N_2$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { @@ -2514,7 +2525,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_2$ = $localize \`$` + - String.raw `{"\uFFFD#1\uFFFD\uFFFD/#1\uFFFD"}:TAG_IMG: is my logo #2 \`; + String.raw`{"\uFFFD#1\uFFFD\uFFFD/#1\uFFFD"}:TAG_IMG: is my logo #2 \`; } function MyComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) { @@ -2550,7 +2561,7 @@ describe('i18n support in the template compiler', () => { </ng-template> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_8537814667662432133$$APP_SPEC_TS__0$ = goog.getMsg(" Root content {$startTagNgContainer} Nested content {$closeTagNgContainer}", { @@ -2563,7 +2574,7 @@ describe('i18n support in the template compiler', () => { $I18N_0$ = $localize \` Root content $` + String.raw `{"\uFFFD*1:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_NG_CONTAINER: Nested content $` + - String.raw `{"\uFFFD/#1:1\uFFFD\uFFFD/*1:1\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; + String.raw`{"\uFFFD/#1:1\uFFFD\uFFFD/*1:1\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; } … `; @@ -2580,7 +2591,7 @@ describe('i18n support in the template compiler', () => { // TODO(FW-635): currently we generate unique consts for each i18n block even though it // might contain the same content. This should be optimized by translation statements caching, // that can be implemented in the future within FW-635. - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6563391987554512024$$APP_SPEC_TS_0$ = goog.getMsg("Test"); @@ -2610,7 +2621,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_1$ = goog.getMsg(" Hello {$startTagNgContainer}there{$closeTagNgContainer}", { "startTagNgContainer": "\uFFFD#2\uFFFD", "closeTagNgContainer": "\uFFFD/#2\uFFFD" }); @@ -2618,8 +2629,8 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` Hello $` + - String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there$` + - String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; + String.raw`{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there$` + + String.raw`{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; } … decls: 3, @@ -2646,7 +2657,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_1$ = goog.getMsg(" Hello {$startTagNgContainer}there {$startTagStrong}!{$closeTagStrong}{$closeTagNgContainer}", { "startTagNgContainer": "\uFFFD#2\uFFFD", "startTagStrong": "\uFFFD#3\uFFFD", "closeTagStrong": "\uFFFD/#3\uFFFD", "closeTagNgContainer": "\uFFFD/#2\uFFFD" }); @@ -2654,10 +2665,10 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` Hello $` + - String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there $` + - String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_STRONG:!$` + - String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_STRONG:$` + - String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; + String.raw`{"\uFFFD#2\uFFFD"}:START_TAG_NG_CONTAINER:there $` + + String.raw`{"\uFFFD#3\uFFFD"}:START_TAG_STRONG:!$` + + String.raw`{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_STRONG:$` + + String.raw`{"\uFFFD/#2\uFFFD"}:CLOSE_TAG_NG_CONTAINER:\`; } … decls: 4, @@ -2686,7 +2697,7 @@ describe('i18n support in the template compiler', () => { <ng-container *ngIf="someFlag" i18n>Content B</ng-container> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_3308216566145348998$$APP_SPEC_TS___2$ = goog.getMsg("Content A"); @@ -2747,7 +2758,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_963542717423364282$$APP_SPEC_TS_0$ = goog.getMsg("\n Some text\n {$startTagSpan}Text inside span{$closeTagSpan}\n ", { @@ -2760,8 +2771,8 @@ describe('i18n support in the template compiler', () => { $I18N_0$ = $localize \` Some text $` + - String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_SPAN:Text inside span$` + - String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_SPAN: + String.raw`{"\uFFFD#3\uFFFD"}:START_TAG_SPAN:Text inside span$` + + String.raw`{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_SPAN: \`; } … @@ -2788,7 +2799,7 @@ describe('i18n support in the template compiler', () => { <div i18n>{gender, select, male {male} female {female} other {other}}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); @@ -2825,7 +2836,7 @@ describe('i18n support in the template compiler', () => { <div i18n>{gender, select, single {'single quotes'} double {"double quotes"} other {other}}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_4166854826696768832$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, single {'single quotes'} double {\"double quotes\"} other {other}}"); @@ -2847,7 +2858,7 @@ describe('i18n support in the template compiler', () => { {age, select, 10 {ten} 20 {twenty} other {other}} `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_8806993169187953163$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {other}}"); @@ -2887,7 +2898,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); @@ -2955,7 +2966,9 @@ describe('i18n support in the template compiler', () => { … decls: 4, vars: 3, - consts: [["title", "icu only", ${AttributeMarker.Template}, "ngIf"], ["title", "icu and text", ${AttributeMarker.Template}, "ngIf"], ["title", "icu only"], ["title", "icu and text"]], + consts: [["title", "icu only", ${ + AttributeMarker.Template}, "ngIf"], ["title", "icu and text", ${ + AttributeMarker.Template}, "ngIf"], ["title", "icu only"], ["title", "icu and text"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "div"); @@ -2984,7 +2997,7 @@ describe('i18n support in the template compiler', () => { <div i18n>{age, select, 10 {ten} 20 {twenty} other {{% other %}}}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_2949673783721159566$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, 10 {ten} 20 {twenty} other {{INTERPOLATION}}}"); @@ -3024,7 +3037,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_2417296354340576868$$APP_SPEC_TS_1$ = goog.getMsg("{VAR_SELECT, select, male {male - {START_BOLD_TEXT}male{CLOSE_BOLD_TEXT}} female {female {START_BOLD_TEXT}female{CLOSE_BOLD_TEXT}} other {{START_TAG_DIV}{START_ITALIC_TEXT}other{CLOSE_ITALIC_TEXT}{CLOSE_TAG_DIV}}}"); @@ -3057,13 +3070,13 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{$I18N_1$}:ICU: $` + - String.raw `{"\uFFFD#2\uFFFD"}:START_BOLD_TEXT:Other content$` + - String.raw `{"\uFFFD/#2\uFFFD"}:CLOSE_BOLD_TEXT:$` + - String.raw `{"\uFFFD#3\uFFFD"}:START_TAG_DIV:$` + - String.raw `{"\uFFFD#4\uFFFD"}:START_ITALIC_TEXT:Another content$` + - String.raw `{"\uFFFD/#4\uFFFD"}:CLOSE_ITALIC_TEXT:$` + - String.raw `{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_DIV:\`; + String.raw`{$I18N_1$}:ICU: $` + + String.raw`{"\uFFFD#2\uFFFD"}:START_BOLD_TEXT:Other content$` + + String.raw`{"\uFFFD/#2\uFFFD"}:CLOSE_BOLD_TEXT:$` + + String.raw`{"\uFFFD#3\uFFFD"}:START_TAG_DIV:$` + + String.raw`{"\uFFFD#4\uFFFD"}:START_ITALIC_TEXT:Another content$` + + String.raw`{"\uFFFD/#4\uFFFD"}:CLOSE_ITALIC_TEXT:$` + + String.raw`{"\uFFFD/#3\uFFFD"}:CLOSE_TAG_DIV:\`; } … decls: 5, @@ -3096,7 +3109,7 @@ describe('i18n support in the template compiler', () => { <div i18n>{gender, select, male {male of age: {{ ageA + ageB + ageC }}} female {female} other {other}}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6879461626778511059$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, male {male of age: {INTERPOLATION}} female {female} other {other}}"); @@ -3137,7 +3150,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); @@ -3170,7 +3183,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{$I18N_1$}:ICU: $` + String.raw `{$I18N_2$}:ICU_1: \`; + String.raw`{$I18N_1$}:ICU: $` + String.raw`{$I18N_2$}:ICU_1: \`; } … decls: 2, @@ -3205,7 +3218,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_APP_SPEC_TS_1$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); @@ -3251,12 +3264,12 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + - String.raw `{"\uFFFD#2\uFFFD"}:START_TAG_DIV: $` + - String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw + String.raw`{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + + String.raw`{"\uFFFD#2\uFFFD"}:START_TAG_DIV: $` + + String.raw`{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw `{"[\uFFFD/#2\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*3:1\uFFFD]"}:CLOSE_TAG_DIV:$` + - String.raw `{"\uFFFD*3:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_DIV_1: $` + - String.raw `{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw + String.raw`{"\uFFFD*3:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_DIV_1: $` + + String.raw`{"\uFFFDI18N_EXP_ICU\uFFFD"}:ICU: $` + String.raw `{"[\uFFFD/#2\uFFFD|\uFFFD/#1:1\uFFFD\uFFFD/*3:1\uFFFD]"}:CLOSE_TAG_DIV:\`; } $I18N_0$ = $r3$.ɵɵi18nPostprocess($I18N_0$, { @@ -3314,7 +3327,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_343563413083115114$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT_1, select, male {male of age: {VAR_SELECT, select, 10 {ten} 20 {twenty} 30 {thirty} other {other}}} female {female} other {other}}"); @@ -3334,7 +3347,7 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{$I18N_1$}:ICU: \`; + String.raw`{$I18N_1$}:ICU: \`; } … decls: 2, vars: 2, @@ -3370,7 +3383,7 @@ describe('i18n support in the template compiler', () => { }</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6870293071705078389$$APP_SPEC_TS_1$ = goog.getMsg("{VAR_PLURAL, plural, =0 {zero} =2 {{INTERPOLATION} {VAR_SELECT, select, cat {cats} dog {dogs} other {animals}} !} other {other - {INTERPOLATION}}}"); @@ -3414,7 +3427,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7842238767399919809$$APP_SPEC_TS_1$ = goog.getMsg("{VAR_SELECT, select, male {male} female {female} other {other}}"); @@ -3449,10 +3462,10 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{$I18N_1$}:ICU: $` + - String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` + - String.raw `{$I18N_3$}:ICU_1: $` + - String.raw `{"\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_SPAN:\`; + String.raw`{$I18N_1$}:ICU: $` + + String.raw`{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` + + String.raw`{$I18N_3$}:ICU_1: $` + + String.raw`{"\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_SPAN:\`; } function MyComponent_span_2_Template(rf, ctx) { if (rf & 1) { @@ -3501,7 +3514,7 @@ describe('i18n support in the template compiler', () => { </div> `; - const output = String.raw ` + const output = String.raw` var $I18N_1$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_7825031864601787094$$APP_SPEC_TS_1$ = goog.getMsg("{VAR_SELECT, select, male {male {INTERPOLATION}} female {female {INTERPOLATION_1}} other {other}}"); @@ -3539,10 +3552,10 @@ describe('i18n support in the template compiler', () => { } else { $I18N_0$ = $localize \` $` + - String.raw `{I18N_1}:ICU: $` + - String.raw `{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` + - String.raw `{I18N_3}:ICU_1: $` + - String.raw `{"\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_SPAN:\`; + String.raw`{I18N_1}:ICU: $` + + String.raw`{"\uFFFD*2:1\uFFFD\uFFFD#1:1\uFFFD"}:START_TAG_SPAN: $` + + String.raw`{I18N_3}:ICU_1: $` + + String.raw`{"\uFFFD/#1:1\uFFFD\uFFFD/*2:1\uFFFD"}:CLOSE_TAG_SPAN:\`; } function MyComponent_span_2_Template(rf, ctx) { if (rf & 1) { @@ -3592,7 +3605,7 @@ describe('i18n support in the template compiler', () => { }</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { const $MSG_EXTERNAL_6318060397235942326$$APP_SPEC_TS_0$ = goog.getMsg("{VAR_SELECT, select, male {male {PH_A}} female {female {PH_B}} other {other {PH_WITH_SPACES}}}"); @@ -3632,7 +3645,7 @@ describe('i18n support in the template compiler', () => { <div i18n="meaningA|descA@@idA">{count, select, 1 {one} other {more than one}}</div> `; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { /** @@ -3656,7 +3669,7 @@ describe('i18n support in the template compiler', () => { it('should add legacy message ids if `enableI18nLegacyMessageIdFormat` is true', () => { const input = `<div i18n>Some Message</div>`; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { … } else { @@ -3671,7 +3684,7 @@ describe('i18n support in the template compiler', () => { it('should add legacy message ids if `enableI18nLegacyMessageIdFormat` is undefined', () => { const input = `<div i18n>Some Message</div>`; - const output = String.raw ` + const output = String.raw` var $I18N_0$; if (typeof ngI18nClosureMode !== "undefined" && ngI18nClosureMode) { … } else { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_input_outputs_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_input_outputs_spec.ts index b77b35449eae3..5d435b8d66326 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_input_outputs_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_input_outputs_spec.ts @@ -85,5 +85,4 @@ describe('compiler compliance: listen()', () => { expectEmit(result.source, componentDef, 'Incorrect component definition'); expectEmit(result.source, directiveDef, 'Incorrect directive definition'); }); - }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts index 9534349ef4111..b43dcafd45f57 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_listener_spec.ts @@ -10,8 +10,8 @@ import {setup} from '@angular/compiler/test/aot/test_util'; import {compile, expectEmit} from './mock_compile'; /* These tests are codified version of the tests in compiler_canonical_spec.ts. Every - * test in compiler_canonical_spec.ts should have a corresponding test here. - */ + * test in compiler_canonical_spec.ts should have a corresponding test here. + */ describe('compiler compliance: listen()', () => { const angularFiles = setup({ compileAngular: false, @@ -292,7 +292,8 @@ describe('compiler compliance: listen()', () => { const template = ` … - consts: [[${AttributeMarker.Bindings}, "click", "change"], [${AttributeMarker.Bindings}, "update", "delete"]], + consts: [[${AttributeMarker.Bindings}, "click", "change"], [${ + AttributeMarker.Bindings}, "update", "delete"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵelementStart(0, "div", 0); @@ -446,5 +447,4 @@ describe('compiler compliance: listen()', () => { const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect host bindings'); }); - }); diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts index ba798596054b1..685b1ef69c2cd 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_styling_spec.ts @@ -622,7 +622,6 @@ describe('compiler compliance: styling', () => { const result = compile(files, angularFiles); expect(result.source).not.toContain('styling'); }); - }); describe('[class]', () => { @@ -743,7 +742,8 @@ describe('compiler compliance: styling', () => { selectors:[["my-component"]], decls: 1, vars: 2, - consts: [[${AttributeMarker.Classes}, "foo", ${AttributeMarker.Styles}, "width", "100px"]], + consts: [[${AttributeMarker.Classes}, "foo", ${ + AttributeMarker.Styles}, "width", "100px"]], template: function MyComponent_Template(rf, $ctx$) { if (rf & 1) { $r3$.ɵɵelement(0, "div", 0); @@ -782,7 +782,6 @@ describe('compiler compliance: styling', () => { const result = compile(files, angularFiles); expect(result.source).not.toContain('styling'); }); - }); describe('[style] mixed with [class]', () => { @@ -1005,7 +1004,8 @@ describe('compiler compliance: styling', () => { }; const template = ` - hostAttrs: [${AttributeMarker.Classes}, "foo", "baz", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"], + hostAttrs: [${AttributeMarker.Classes}, "foo", "baz", ${ + AttributeMarker.Styles}, "width", "200px", "height", "500px"], hostVars: 8, hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { @@ -1594,7 +1594,6 @@ describe('compiler compliance: styling', () => { expectEmit(result.source, template, 'Incorrect handling of interpolated style properties'); }); - }); describe('instruction chaining', () => { @@ -1981,7 +1980,8 @@ describe('compiler compliance: styling', () => { }; const template = ` - hostAttrs: ["title", "foo title", ${AttributeMarker.Classes}, "foo", "baz", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"], + hostAttrs: ["title", "foo title", ${AttributeMarker.Classes}, "foo", "baz", ${ + AttributeMarker.Styles}, "width", "200px", "height", "500px"], hostVars: 6, hostBindings: function MyComponent_HostBindings(rf, ctx) { if (rf & 2) { diff --git a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts index c6e795d9ba3c0..4b103875262ca 100644 --- a/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts +++ b/packages/compiler-cli/test/compliance/r3_view_compiler_template_spec.ts @@ -103,7 +103,10 @@ describe('compiler compliance: template', () => { } } // ... - consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Bindings}, "title", "click", ${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Bindings}, "title", "click"]], + consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${ + AttributeMarker.Bindings}, "title", "click", ${ + AttributeMarker.Template}, "ngFor", "ngForOf"], [${ + AttributeMarker.Bindings}, "title", "click"]], template:function MyComponent_Template(rf, ctx){ if (rf & 1) { $i0$.ɵɵtemplate(0, MyComponent_ul_0_Template, 2, 1, "ul", 0); @@ -157,7 +160,8 @@ describe('compiler compliance: template', () => { } } // ... - consts: [[${AttributeMarker.Bindings}, "click", ${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Bindings}, "click"]], + consts: [[${AttributeMarker.Bindings}, "click", ${ + AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Bindings}, "click"]], template: function MyComponent_Template(rf, ctx) { if (rf & 1) { $r3$.ɵɵtemplate(0, MyComponent_div_0_Template, 1, 0, "div", 0); @@ -329,7 +333,8 @@ describe('compiler compliance: template', () => { } // ... - consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${AttributeMarker.Template}, "ngIf"]], + consts: [[${AttributeMarker.Template}, "ngFor", "ngForOf"], [${ + AttributeMarker.Template}, "ngIf"]], template:function MyComponent_Template(rf, ctx){ if (rf & 1) { $i0$.ɵɵtemplate(0, MyComponent_div_0_Template, 2, 1, "div", 0); @@ -472,7 +477,6 @@ describe('compiler compliance: template', () => { }); it('should support local refs on <ng-template>', () => { - const files = { app: { 'spec.ts': ` @@ -511,7 +515,6 @@ describe('compiler compliance: template', () => { }); it('should support directive outputs on <ng-template>', () => { - const files = { app: { 'spec.ts': ` @@ -545,7 +548,6 @@ describe('compiler compliance: template', () => { const result = compile(files, angularFiles); expectEmit(result.source, template, 'Incorrect template'); - }); it('should allow directive inputs as an interpolated prop on <ng-template>', () => { diff --git a/packages/compiler-cli/test/diagnostics/check_types_spec.ts b/packages/compiler-cli/test/diagnostics/check_types_spec.ts index de0810397ba85..d2155d93d0843 100644 --- a/packages/compiler-cli/test/diagnostics/check_types_spec.ts +++ b/packages/compiler-cli/test/diagnostics/check_types_spec.ts @@ -11,7 +11,8 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import * as ts from 'typescript'; -import {TestSupport, expectNoDiagnostics, setup} from '../test_support'; + +import {expectNoDiagnostics, setup, TestSupport} from '../test_support'; type MockFiles = { [fileName: string]: string @@ -47,19 +48,19 @@ describe('ng type checker', () => { } function reject( - message: string | RegExp, location: RegExp | null, files: MockFiles, + message: string|RegExp, location: RegExp|null, files: MockFiles, overrideOptions: ng.CompilerOptions = {}) { const diagnostics = compileAndCheck([QUICKSTART, files], overrideOptions); if (!diagnostics || !diagnostics.length) { throw new Error('Expected a diagnostic error message'); } else { - const matches: (d: ng.Diagnostic | ts.Diagnostic) => boolean = typeof message === 'string' ? + const matches: (d: ng.Diagnostic|ts.Diagnostic) => boolean = typeof message === 'string' ? d => ng.isNgDiagnostic(d)&& d.messageText == message : d => ng.isNgDiagnostic(d) && message.test(d.messageText); const matchingDiagnostics = diagnostics.filter(matches) as ng.Diagnostic[]; if (!matchingDiagnostics || !matchingDiagnostics.length) { - throw new Error( - `Expected a diagnostics matching ${message}, received\n ${diagnostics.map(d => d.messageText).join('\n ')}`); + throw new Error(`Expected a diagnostics matching ${message}, received\n ${ + diagnostics.map(d => d.messageText).join('\n ')}`); } if (location) { @@ -72,7 +73,9 @@ describe('ng type checker', () => { } } - it('should accept unmodified QuickStart', () => { accept(); }); + it('should accept unmodified QuickStart', () => { + accept(); + }); it('should accept unmodified QuickStart with tests for unused variables', () => { accept({}, { @@ -523,7 +526,7 @@ describe('ng type checker', () => { }; const r = - (message: string | RegExp, location: RegExp | null, files: MockFiles, + (message: string|RegExp, location: RegExp|null, files: MockFiles, options: ng.AngularCompilerOptions = {}) => { reject( message, location, {'src/app.component.ts': '', 'src/lib.ts': '', ...files}, @@ -712,16 +715,18 @@ describe('ng type checker', () => { }); function addTests(config: {fullTemplateTypeCheck: boolean}) { - function a(template: string) { accept({'src/app.component.html': template}, config); } + function a(template: string) { + accept({'src/app.component.html': template}, config); + } - function r(template: string, message: string | RegExp, location: string) { + function r(template: string, message: string|RegExp, location: string) { reject( message, new RegExp(`app\.component\.html\@${location}$`), {'src/app.component.html': template}, config); } function rejectOnlyWithFullTemplateTypeCheck( - template: string, message: string | RegExp, location: string) { + template: string, message: string|RegExp, location: string) { if (config.fullTemplateTypeCheck) { r(template, message, location); } else { @@ -732,23 +737,33 @@ describe('ng type checker', () => { it('should report an invalid field access', () => { r('<div>{{fame}}<div>', `Property 'fame' does not exist on type 'AppComponent'.`, '0:5'); }); - it('should reject a reference to a field of a nullable', - () => { r('<div>{{maybePerson.name}}</div>', `Object is possibly 'undefined'.`, '0:5'); }); - it('should accept a reference to a field of a nullable using using non-null-assert', - () => { a('{{maybePerson!.name}}'); }); - it('should accept a safe property access of a nullable person', - () => { a('{{maybePerson?.name}}'); }); + it('should reject a reference to a field of a nullable', () => { + r('<div>{{maybePerson.name}}</div>', `Object is possibly 'undefined'.`, '0:5'); + }); + it('should accept a reference to a field of a nullable using using non-null-assert', () => { + a('{{maybePerson!.name}}'); + }); + it('should accept a safe property access of a nullable person', () => { + a('{{maybePerson?.name}}'); + }); - it('should accept using a library pipe', () => { a('{{1 | libPipe}}'); }); - it('should accept using a library directive', - () => { a('<div libDir #libDir="libDir">{{libDir.name}}</div>'); }); + it('should accept using a library pipe', () => { + a('{{1 | libPipe}}'); + }); + it('should accept using a library directive', () => { + a('<div libDir #libDir="libDir">{{libDir.name}}</div>'); + }); - it('should accept a function call', () => { a('{{getName()}}'); }); + it('should accept a function call', () => { + a('{{getName()}}'); + }); it('should reject an invalid method', () => { r('<div>{{getFame()}}</div>', `Property 'getFame' does not exist on type 'AppComponent'. Did you mean 'getName'?`, '0:5'); }); - it('should accept a field access of a method result', () => { a('{{getPerson().name}}'); }); + it('should accept a field access of a method result', () => { + a('{{getPerson().name}}'); + }); it('should reject an invalid field reference of a method result', () => { r('<div>{{getPerson().fame}}</div>', `Property 'fame' does not exist on type 'Person'.`, '0:5'); @@ -756,10 +771,13 @@ describe('ng type checker', () => { it('should reject an access to a nullable field of a method result', () => { r('<div>{{getMaybePerson().name}}</div>', `Object is possibly 'undefined'.`, '0:5'); }); - it('should accept a nullable assert of a nullable field references of a method result', - () => { a('{{getMaybePerson()!.name}}'); }); + it('should accept a nullable assert of a nullable field references of a method result', () => { + a('{{getMaybePerson()!.name}}'); + }); it('should accept a safe property access of a nullable field reference of a method result', - () => { a('{{getMaybePerson()?.name}}'); }); + () => { + a('{{getMaybePerson()?.name}}'); + }); it('should report an invalid field access inside of an ng-template', () => { rejectOnlyWithFullTemplateTypeCheck( @@ -779,8 +797,9 @@ describe('ng type checker', () => { } describe('with lowered expressions', () => { - it('should not report lowered expressions as errors', - () => { expectNoDiagnostics({}, compileAndCheck([LOWERING_QUICKSTART])); }); + it('should not report lowered expressions as errors', () => { + expectNoDiagnostics({}, compileAndCheck([LOWERING_QUICKSTART])); + }); }); }); diff --git a/packages/compiler-cli/test/diagnostics/typescript_version_spec.ts b/packages/compiler-cli/test/diagnostics/typescript_version_spec.ts index 605b3e1ed79cf..3e817cced5539 100644 --- a/packages/compiler-cli/test/diagnostics/typescript_version_spec.ts +++ b/packages/compiler-cli/test/diagnostics/typescript_version_spec.ts @@ -18,8 +18,9 @@ describe('toNumbers', () => { }); describe('compareNumbers', () => { - - it('should handle empty arrays', () => { expect(compareNumbers([], [])).toEqual(0); }); + it('should handle empty arrays', () => { + expect(compareNumbers([], [])).toEqual(0); + }); it('should handle arrays of same length', () => { expect(compareNumbers([1], [3])).toEqual(-1); diff --git a/packages/compiler-cli/test/extract_i18n_spec.ts b/packages/compiler-cli/test/extract_i18n_spec.ts index f2d4aad0468dc..39569ac55472a 100644 --- a/packages/compiler-cli/test/extract_i18n_spec.ts +++ b/packages/compiler-cli/test/extract_i18n_spec.ts @@ -207,7 +207,9 @@ describe('extract_i18n command line', () => { beforeEach(() => { errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error); const support = setup(); - write = (fileName: string, content: string) => { support.write(fileName, content); }; + write = (fileName: string, content: string) => { + support.write(fileName, content); + }; basePath = support.basePath; outDir = path.join(basePath, 'built'); write('tsconfig-base.json', `{ diff --git a/packages/compiler-cli/test/helpers/src/mock_file_loading.ts b/packages/compiler-cli/test/helpers/src/mock_file_loading.ts index 8cfdf54f3ff73..baf20e7ed42c2 100644 --- a/packages/compiler-cli/test/helpers/src/mock_file_loading.ts +++ b/packages/compiler-cli/test/helpers/src/mock_file_loading.ts @@ -7,7 +7,7 @@ */ /// <reference types="node" /> -import {readFileSync, readdirSync, statSync} from 'fs'; +import {readdirSync, readFileSync, statSync} from 'fs'; import {resolve} from 'path'; import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '..'; diff --git a/packages/compiler-cli/test/helpers/src/runfile_helpers.ts b/packages/compiler-cli/test/helpers/src/runfile_helpers.ts index bb848881dd54f..72ad3c9d7b0bf 100644 --- a/packages/compiler-cli/test/helpers/src/runfile_helpers.ts +++ b/packages/compiler-cli/test/helpers/src/runfile_helpers.ts @@ -22,7 +22,7 @@ export function getAngularPackagesFromRunfiles() { const runfilesManifestPath = process.env.RUNFILES_MANIFEST_FILE; if (!runfilesManifestPath) { - const packageRunfilesDir = path.join(process.env.RUNFILES !, 'angular/packages'); + const packageRunfilesDir = path.join(process.env.RUNFILES!, 'angular/packages'); return fs.readdirSync(packageRunfilesDir) .map(name => ({name, pkgPath: path.join(packageRunfilesDir, name, 'npm_package/')})) diff --git a/packages/compiler-cli/test/metadata/bundler_spec.ts b/packages/compiler-cli/test/metadata/bundler_spec.ts index 8e147e1a98f13..7f8d297a1d8a8 100644 --- a/packages/compiler-cli/test/metadata/bundler_spec.ts +++ b/packages/compiler-cli/test/metadata/bundler_spec.ts @@ -15,7 +15,6 @@ import {ClassMetadata, MetadataEntry, MetadataGlobalReferenceExpression, ModuleM import {Directory, MockAotContext, MockCompilerHost} from '../mocks'; describe('compiler host adapter', () => { - it('should retrieve metadata for an explicit index relative path reference', () => { const context = new MockAotContext('.', SIMPLE_LIBRARY); const host = new MockCompilerHost(context); @@ -28,7 +27,7 @@ describe('compiler host adapter', () => { const metadata = adapter.getMetadataFor('./lib/src/two/index', '.'); expect(metadata).toBeDefined(); - expect(Object.keys(metadata !.metadata).sort()).toEqual([ + expect(Object.keys(metadata!.metadata).sort()).toEqual([ 'PrivateTwo', 'TWO_CLASSES', 'Two', @@ -48,7 +47,7 @@ describe('compiler host adapter', () => { const metadata = adapter.getMetadataFor('./lib/src/two', '.'); expect(metadata).toBeDefined(); - expect(Object.keys(metadata !.metadata).sort()).toEqual([ + expect(Object.keys(metadata!.metadata).sort()).toEqual([ 'PrivateTwo', 'TWO_CLASSES', 'Two', @@ -82,7 +81,7 @@ describe('compiler host adapter', () => { const metadata = adapter.getMetadataFor('./lib/src/index', '.'); expect(metadata).toBeDefined(); - expect(metadata !.exports !.map(e => e.export !) + expect(metadata!.exports!.map(e => e.export !) .reduce((prev, next) => prev.concat(next), []) .sort()) .toEqual([ @@ -127,13 +126,13 @@ describe('compiler host adapter', () => { const metadata = adapter.getMetadataFor('./lib', '.'); expect(metadata).toBeDefined(); - expect(Object.keys(metadata !.metadata).sort()).toEqual([ + expect(Object.keys(metadata!.metadata).sort()).toEqual([ 'ONE_CLASSES', 'One', 'OneMore', 'PrivateOne', ]); - expect(Array.isArray(metadata !.metadata !['ONE_CLASSES'])).toBeTruthy(); + expect(Array.isArray(metadata!.metadata!['ONE_CLASSES'])).toBeTruthy(); }); it('should look for non-declaration file when resolving metadata via a package.json "types" entry', @@ -180,19 +179,17 @@ describe('compiler host adapter', () => { const metadata = adapter.getMetadataFor('./lib', '.'); expect(metadata).toBeDefined(); - expect(Object.keys(metadata !.metadata).sort()).toEqual([ + expect(Object.keys(metadata!.metadata).sort()).toEqual([ 'ONE_CLASSES', 'One', 'OneMore', 'PrivateOne', ]); - expect(Array.isArray(metadata !.metadata !['ONE_CLASSES'])).toBeTruthy(); - + expect(Array.isArray(metadata!.metadata!['ONE_CLASSES'])).toBeTruthy(); }); }); describe('metadata bundler', () => { - it('should be able to bundle a simple library', () => { const host = new MockStringBundlerHost('/', SIMPLE_LIBRARY); const bundler = new MetadataBundler('/lib/index', undefined, host, 'prfx_'); @@ -203,9 +200,9 @@ describe('metadata bundler', () => { const originalOne = './src/one'; const originalTwo = './src/two/index'; - expect(Object.keys(result.metadata.origins !) + expect(Object.keys(result.metadata.origins!) .sort() - .map(name => ({name, value: result.metadata.origins ![name]}))) + .map(name => ({name, value: result.metadata.origins![name]}))) .toEqual([ {name: 'ONE_CLASSES', value: originalOne}, {name: 'One', value: originalOne}, {name: 'OneMore', value: originalOne}, {name: 'TWO_CLASSES', value: originalTwo}, @@ -239,7 +236,7 @@ describe('metadata bundler', () => { }); const bundler = new MetadataBundler('/lib/index', undefined, host); const bundledMetadata = bundler.getMetadataBundle().metadata; - const deepIndexMetadata = host.getMetadataFor('/lib/deep/index') !; + const deepIndexMetadata = host.getMetadataFor('/lib/deep/index')!; // The unbundled metadata should reference symbols using the relative module path. expect(deepIndexMetadata.metadata['MyClass']).toEqual(jasmine.objectContaining<MetadataEntry>({ @@ -419,7 +416,7 @@ describe('metadata bundler', () => { from: 'external_one' } ]); - expect(result.metadata.origins !['E']).toBeUndefined(); + expect(result.metadata.origins!['E']).toBeUndefined(); }); it('should be able to bundle a library with multiple unnamed re-exports', () => { @@ -456,7 +453,7 @@ describe('metadata bundler', () => { const bundler = new MetadataBundler('/public-api', undefined, host); const result = bundler.getMetadataBundle(); - const {A, A2, A3, B1, B2} = result.metadata.metadata as{ + const {A, A2, A3, B1, B2} = result.metadata.metadata as { A: ClassMetadata, A2: MetadataGlobalReferenceExpression, A3: ClassMetadata, diff --git a/packages/compiler-cli/test/metadata/collector_spec.ts b/packages/compiler-cli/test/metadata/collector_spec.ts index dffe560d32aaa..5b591e0beaf99 100644 --- a/packages/compiler-cli/test/metadata/collector_spec.ts +++ b/packages/compiler-cli/test/metadata/collector_spec.ts @@ -9,9 +9,9 @@ import * as ts from 'typescript'; import {MetadataCollector} from '../../src/metadata/collector'; -import {ClassMetadata, ConstructorMetadata, METADATA_VERSION, MetadataEntry, MetadataMap, MetadataSymbolicExpression, ModuleMetadata, isClassMetadata, isMetadataGlobalReferenceExpression} from '../../src/metadata/schema'; +import {ClassMetadata, ConstructorMetadata, isClassMetadata, isMetadataGlobalReferenceExpression, METADATA_VERSION, MetadataEntry, MetadataMap, MetadataSymbolicExpression, ModuleMetadata} from '../../src/metadata/schema'; -import {Directory, Host, expectValidSources} from './typescript.mocks'; +import {Directory, expectValidSources, Host} from './typescript.mocks'; describe('Collector', () => { const documentRegistry = ts.createDocumentRegistry(); @@ -40,20 +40,22 @@ describe('Collector', () => { 'interface-reference.ts', 'static-type-check-members.ts', ]); service = ts.createLanguageService(host, documentRegistry); - program = service.getProgram() !; + program = service.getProgram()!; collector = new MetadataCollector({quotedNames: true}); }); - it('should not have errors in test data', () => { expectValidSources(service, program); }); + it('should not have errors in test data', () => { + expectValidSources(service, program); + }); it('should return undefined for modules that have no metadata', () => { - const sourceFile = program.getSourceFile('app/empty.ts') !; + const sourceFile = program.getSourceFile('app/empty.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toBeUndefined(); }); it('should treat all symbols of .d.ts files as exported', () => { - const sourceFile = program.getSourceFile('declarations.d.ts') !; + const sourceFile = program.getSourceFile('declarations.d.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -66,7 +68,7 @@ describe('Collector', () => { }); it('should return an interface reference for types', () => { - const sourceFile = program.getSourceFile('/exported-type.ts') !; + const sourceFile = program.getSourceFile('/exported-type.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -76,7 +78,7 @@ describe('Collector', () => { }); it('should return an interface reference for interfaces', () => { - const sourceFile = program.getSourceFile('app/hero.ts') !; + const sourceFile = program.getSourceFile('app/hero.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -86,13 +88,13 @@ describe('Collector', () => { }); it('should preserve module names from TypeScript sources', () => { - const sourceFile = program.getSourceFile('named-module.d.ts') !; + const sourceFile = program.getSourceFile('named-module.d.ts')!; const metadata = collector.getMetadata(sourceFile); - expect(metadata !['importAs']).toEqual('some-named-module'); + expect(metadata!['importAs']).toEqual('some-named-module'); }); it('should be able to collect a simple component\'s metadata', () => { - const sourceFile = program.getSourceFile('app/hero-detail.component.ts') !; + const sourceFile = program.getSourceFile('app/hero-detail.component.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -144,7 +146,7 @@ describe('Collector', () => { }); it('should be able to get a more complicated component\'s metadata', () => { - const sourceFile = program.getSourceFile('/app/app.component.ts') !; + const sourceFile = program.getSourceFile('/app/app.component.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -236,7 +238,7 @@ describe('Collector', () => { }); it('should return the values of exported variables', () => { - const sourceFile = program.getSourceFile('/app/mock-heroes.ts') !; + const sourceFile = program.getSourceFile('/app/mock-heroes.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -262,14 +264,14 @@ describe('Collector', () => { let casesMetadata: ModuleMetadata; beforeEach(() => { - casesFile = program.getSourceFile('/app/cases-data.ts') !; - casesMetadata = collector.getMetadata(casesFile) !; + casesFile = program.getSourceFile('/app/cases-data.ts')!; + casesMetadata = collector.getMetadata(casesFile)!; }); it('should provide any reference for an any ctor parameter type', () => { const casesAny = <ClassMetadata>casesMetadata.metadata['CaseAny']; expect(casesAny).toBeTruthy(); - const ctorData = casesAny.members !['__ctor__'] as ConstructorMetadata[]; + const ctorData = casesAny.members!['__ctor__'] as ConstructorMetadata[]; expect(ctorData).toEqual([{ __symbolic: 'constructor', parameters: [{__symbolic: 'reference', name: 'any'} as MetadataSymbolicExpression] @@ -300,7 +302,8 @@ describe('Collector', () => { it('should record references to parameterized types', () => { const casesForIn = <ClassMetadata>casesMetadata.metadata['NgFor']; expect(casesForIn).toEqual({ - __symbolic: 'class', decorators: [{ + __symbolic: 'class', + decorators: [{ __symbolic: 'call', expression: { __symbolic: 'reference', @@ -310,21 +313,21 @@ describe('Collector', () => { character: 7 } }], - members: { - __ctor__: [{ - __symbolic: 'constructor', - parameters: [{ - __symbolic: 'reference', - name: 'ClassReference', - arguments: [{__symbolic: 'reference', name: 'NgForRow'}] - }] - }] - } + members: { + __ctor__: [{ + __symbolic: 'constructor', + parameters: [{ + __symbolic: 'reference', + name: 'ClassReference', + arguments: [{__symbolic: 'reference', name: 'NgForRow'}] + }] + }] + } } as any as ClassMetadata); // TODO: Review use of `any` here (#19904) }); it('should report errors for destructured imports', () => { - const unsupported1 = program.getSourceFile('/unsupported-1.ts') !; + const unsupported1 = program.getSourceFile('/unsupported-1.ts')!; const metadata = collector.getMetadata(unsupported1); expect(metadata).toEqual({ __symbolic: 'module', @@ -340,11 +343,11 @@ describe('Collector', () => { }); it('should report an error for references to unexpected types', () => { - const unsupported1 = program.getSourceFile('/unsupported-2.ts') !; - const metadata = collector.getMetadata(unsupported1) !; + const unsupported1 = program.getSourceFile('/unsupported-2.ts')!; + const metadata = collector.getMetadata(unsupported1)!; const barClass = <ClassMetadata>metadata.metadata['Bar']; - const ctor = <ConstructorMetadata>barClass.members !['__ctor__'][0]; - const parameter = ctor.parameters ![0]; + const ctor = <ConstructorMetadata>barClass.members!['__ctor__'][0]; + const parameter = ctor.parameters![0]; expect(parameter).toEqual({ __symbolic: 'error', message: 'Reference to non-exported class', @@ -355,18 +358,19 @@ describe('Collector', () => { }); it('should be able to handle import star type references', () => { - const importStar = program.getSourceFile('/import-star.ts') !; - const metadata = collector.getMetadata(importStar) !; + const importStar = program.getSourceFile('/import-star.ts')!; + const metadata = collector.getMetadata(importStar)!; const someClass = <ClassMetadata>metadata.metadata['SomeClass']; - const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0]; + const ctor = <ConstructorMetadata>someClass.members!['__ctor__'][0]; const parameters = ctor.parameters; - expect(parameters).toEqual([{ - __symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29 - } as MetadataSymbolicExpression]); + expect(parameters).toEqual([ + {__symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29} as + MetadataSymbolicExpression + ]); }); it('should record all exported classes', () => { - const sourceFile = program.getSourceFile('/exported-classes.ts') !; + const sourceFile = program.getSourceFile('/exported-classes.ts')!; const metadata = collector.getMetadata(sourceFile); expect(metadata).toEqual({ __symbolic: 'module', @@ -380,7 +384,7 @@ describe('Collector', () => { }); it('should be able to record functions', () => { - const exportedFunctions = program.getSourceFile('/exported-functions.ts') !; + const exportedFunctions = program.getSourceFile('/exported-functions.ts')!; const metadata = collector.getMetadata(exportedFunctions); expect(metadata).toEqual({ __symbolic: 'module', @@ -440,26 +444,27 @@ describe('Collector', () => { }); it('should be able to handle import star type references', () => { - const importStar = program.getSourceFile('/import-star.ts') !; - const metadata = collector.getMetadata(importStar) !; + const importStar = program.getSourceFile('/import-star.ts')!; + const metadata = collector.getMetadata(importStar)!; const someClass = <ClassMetadata>metadata.metadata['SomeClass']; - const ctor = <ConstructorMetadata>someClass.members !['__ctor__'][0]; + const ctor = <ConstructorMetadata>someClass.members!['__ctor__'][0]; const parameters = ctor.parameters; - expect(parameters).toEqual([{ - __symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29 - } as MetadataSymbolicExpression]); + expect(parameters).toEqual([ + {__symbolic: 'reference', module: 'angular2/common', name: 'NgFor', line: 6, character: 29} as + MetadataSymbolicExpression + ]); }); it('should be able to collect the value of an enum', () => { - const enumSource = program.getSourceFile('/exported-enum.ts') !; - const metadata = collector.getMetadata(enumSource) !; + const enumSource = program.getSourceFile('/exported-enum.ts')!; + const metadata = collector.getMetadata(enumSource)!; const someEnum: any = metadata.metadata['SomeEnum']; expect(someEnum).toEqual({A: 0, B: 1, C: 100, D: 101}); }); it('should ignore a non-export enum', () => { - const enumSource = program.getSourceFile('/private-enum.ts') !; - const metadata = collector.getMetadata(enumSource) !; + const enumSource = program.getSourceFile('/private-enum.ts')!; + const metadata = collector.getMetadata(enumSource)!; const publicEnum: any = metadata.metadata['PublicEnum']; const privateEnum: any = metadata.metadata['PrivateEnum']; expect(publicEnum).toEqual({a: 0, b: 1, c: 2}); @@ -467,8 +472,8 @@ describe('Collector', () => { }); it('should be able to collect enums initialized from consts', () => { - const enumSource = program.getSourceFile('/exported-enum.ts') !; - const metadata = collector.getMetadata(enumSource) !; + const enumSource = program.getSourceFile('/exported-enum.ts')!; + const metadata = collector.getMetadata(enumSource)!; const complexEnum: any = metadata.metadata['ComplexEnum']; expect(complexEnum).toEqual({ A: 0, @@ -486,8 +491,8 @@ describe('Collector', () => { }); it('should be able to collect a simple static method', () => { - const staticSource = program.getSourceFile('/static-method.ts') !; - const metadata = collector.getMetadata(staticSource) !; + const staticSource = program.getSourceFile('/static-method.ts')!; + const metadata = collector.getMetadata(staticSource)!; expect(metadata).toBeDefined(); const classData = <ClassMetadata>metadata.metadata['MyModule']; expect(classData).toBeDefined(); @@ -504,43 +509,45 @@ describe('Collector', () => { }); it('should be able to collect a call to a static method', () => { - const staticSource = program.getSourceFile('/static-method-call.ts') !; - const metadata = collector.getMetadata(staticSource) !; + const staticSource = program.getSourceFile('/static-method-call.ts')!; + const metadata = collector.getMetadata(staticSource)!; expect(metadata).toBeDefined(); const classData = <ClassMetadata>metadata.metadata['Foo']; expect(classData).toBeDefined(); - expect(classData.decorators).toEqual([{ - __symbolic: 'call', - expression: { - __symbolic: 'reference', - module: 'angular2/core', - name: 'Component', - line: 4, - character: 5 - }, - arguments: [{ - providers: { - __symbolic: 'call', - expression: { - __symbolic: 'select', + expect(classData.decorators).toEqual([ + { + __symbolic: 'call', + expression: { + __symbolic: 'reference', + module: 'angular2/core', + name: 'Component', + line: 4, + character: 5 + }, + arguments: [{ + providers: { + __symbolic: 'call', expression: { - __symbolic: 'reference', - module: './static-method', - name: 'MyModule', - line: 5, - character: 17 + __symbolic: 'select', + expression: { + __symbolic: 'reference', + module: './static-method', + name: 'MyModule', + line: 5, + character: 17 + }, + member: 'with' }, - member: 'with' - }, - arguments: ['a'] - } - }] - }] as any as MetadataSymbolicExpression[]); // TODO: Review use of `any` here (#19904) + arguments: ['a'] + } + }] + } + ] as any as MetadataSymbolicExpression[]); // TODO: Review use of `any` here (#19904) }); it('should be able to collect a static field', () => { - const staticSource = program.getSourceFile('/static-field.ts') !; - const metadata = collector.getMetadata(staticSource) !; + const staticSource = program.getSourceFile('/static-field.ts')!; + const metadata = collector.getMetadata(staticSource)!; expect(metadata).toBeDefined(); const classData = <ClassMetadata>metadata.metadata['MyModule']; expect(classData).toBeDefined(); @@ -548,8 +555,8 @@ describe('Collector', () => { }); it('should ignore static type check members without a value', () => { - const typeCheckMembers = program.getSourceFile('/static-type-check-members.ts') !; - const metadata = collector.getMetadata(typeCheckMembers) !; + const typeCheckMembers = program.getSourceFile('/static-type-check-members.ts')!; + const metadata = collector.getMetadata(typeCheckMembers)!; const classData = <ClassMetadata>metadata.metadata['MyDirective']; expect(classData.statics).toEqual({ foo: 'bar', @@ -560,42 +567,44 @@ describe('Collector', () => { }); it('should be able to collect a reference to a static field', () => { - const staticSource = program.getSourceFile('/static-field-reference.ts') !; - const metadata = collector.getMetadata(staticSource) !; + const staticSource = program.getSourceFile('/static-field-reference.ts')!; + const metadata = collector.getMetadata(staticSource)!; expect(metadata).toBeDefined(); const classData = <ClassMetadata>metadata.metadata['Foo']; expect(classData).toBeDefined(); - expect(classData.decorators).toEqual([{ - __symbolic: 'call', - expression: { - __symbolic: 'reference', - module: 'angular2/core', - name: 'Component', - line: 4, - character: 5 - }, - arguments: [{ - providers: [{ - provide: 'a', - useValue: { - __symbolic: 'select', - expression: { - __symbolic: 'reference', - module: './static-field', - name: 'MyModule', - line: 5, - character: 45 - }, - member: 'VALUE' - } + expect(classData.decorators).toEqual([ + { + __symbolic: 'call', + expression: { + __symbolic: 'reference', + module: 'angular2/core', + name: 'Component', + line: 4, + character: 5 + }, + arguments: [{ + providers: [{ + provide: 'a', + useValue: { + __symbolic: 'select', + expression: { + __symbolic: 'reference', + module: './static-field', + name: 'MyModule', + line: 5, + character: 45 + }, + member: 'VALUE' + } + }] }] - }] - }] as any as MetadataSymbolicExpression[]); // TODO: Review use of `any` here (#19904) + } + ] as any as MetadataSymbolicExpression[]); // TODO: Review use of `any` here (#19904) }); it('should be able to collect a method with a conditional expression', () => { - const source = program.getSourceFile('/static-method-with-if.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/static-method-with-if.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata).toBeDefined(); const classData = <ClassMetadata>metadata.metadata['MyModule']; expect(classData).toBeDefined(); @@ -619,8 +628,8 @@ describe('Collector', () => { }); it('should be able to collect a method with a default parameter', () => { - const source = program.getSourceFile('/static-method-with-default.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/static-method-with-default.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata).toBeDefined(); const classData = <ClassMetadata>metadata.metadata['MyModule']; expect(classData).toBeDefined(); @@ -648,8 +657,8 @@ describe('Collector', () => { }); it('should be able to collect re-exported symbols', () => { - const source = program.getSourceFile('/re-exports.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/re-exports.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata.exports).toEqual([ {from: './static-field', export: ['MyModule']}, {from: './static-field-reference', export: [{name: 'Foo', as: 'OtherModule'}]}, @@ -658,14 +667,14 @@ describe('Collector', () => { }); it('should be able to collect a export as symbol', () => { - const source = program.getSourceFile('export-as.d.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('export-as.d.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata.metadata).toEqual({SomeFunction: {__symbolic: 'function'}}); }); it('should be able to collect exports with no module specifier', () => { - const source = program.getSourceFile('/re-exports-2.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/re-exports-2.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata.metadata).toEqual({ MyClass: Object({__symbolic: 'class'}), OtherModule: { @@ -686,8 +695,8 @@ describe('Collector', () => { }); it('should collect an error symbol if collecting a reference to a non-exported symbol', () => { - const source = program.getSourceFile('/local-symbol-ref.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/local-symbol-ref.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata.metadata).toEqual({ REQUIRED_VALIDATOR: { __symbolic: 'error', @@ -714,8 +723,8 @@ describe('Collector', () => { }); it('should collect an error symbol if collecting a reference to a non-exported function', () => { - const source = program.getSourceFile('/local-function-ref.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/local-function-ref.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata.metadata).toEqual({ REQUIRED_VALIDATOR: { __symbolic: 'error', @@ -742,8 +751,8 @@ describe('Collector', () => { }); it('should collect an error for a simple function that references a local variable', () => { - const source = program.getSourceFile('/local-symbol-ref-func.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/local-symbol-ref-func.ts')!; + const metadata = collector.getMetadata(source)!; expect(metadata.metadata).toEqual({ foo: { __symbolic: 'function', @@ -760,8 +769,8 @@ describe('Collector', () => { }); it('should collect any for interface parameter reference', () => { - const source = program.getSourceFile('/interface-reference.ts') !; - const metadata = collector.getMetadata(source) !; + const source = program.getSourceFile('/interface-reference.ts')!; + const metadata = collector.getMetadata(source)!; expect((metadata.metadata['SomeClass'] as ClassMetadata).members).toEqual({ __ctor__: [{ __symbolic: 'constructor', @@ -787,11 +796,13 @@ describe('Collector', () => { return expect(metadata.metadata['value']); } - it('should be able to collect a raw interpolated string', - () => { e('`simple value`').toBe('simple value'); }); + it('should be able to collect a raw interpolated string', () => { + e('`simple value`').toBe('simple value'); + }); - it('should be able to interpolate a single value', - () => { e('`${foo}`', 'const foo = "foo value"').toBe('foo value'); }); + it('should be able to interpolate a single value', () => { + e('`${foo}`', 'const foo = "foo value"').toBe('foo value'); + }); it('should be able to interpolate multiple values', () => { e('`foo:${foo}, bar:${bar}, end`', 'const foo = "foo"; const bar = "bar";') @@ -894,30 +905,30 @@ describe('Collector', () => { toString(): string { return \`InjectionToken \${this._desc}\`; } } as any;`, ts.ScriptTarget.Latest, true); - const metadata = collector.getMetadata(source) !; + const metadata = collector.getMetadata(source)!; expect(metadata.metadata).toEqual({InjectionToken: {__symbolic: 'class'}}); }); describe('in strict mode', () => { it('should throw if an error symbol is collecting a reference to a non-exported symbol', () => { - const source = program.getSourceFile('/local-symbol-ref.ts') !; + const source = program.getSourceFile('/local-symbol-ref.ts')!; expect(() => collector.getMetadata(source, true)).toThrowError(/Reference to a local symbol/); }); it('should throw if an error if collecting a reference to a non-exported function', () => { - const source = program.getSourceFile('/local-function-ref.ts') !; + const source = program.getSourceFile('/local-function-ref.ts')!; expect(() => collector.getMetadata(source, true)) .toThrowError(/Reference to a non-exported function/); }); it('should throw for references to unexpected types', () => { - const unsupported2 = program.getSourceFile('/unsupported-2.ts') !; + const unsupported2 = program.getSourceFile('/unsupported-2.ts')!; expect(() => collector.getMetadata(unsupported2, true)) .toThrowError(/Reference to non-exported class/); }); it('should throw for errors in a static method', () => { - const unsupported3 = program.getSourceFile('/unsupported-3.ts') !; + const unsupported3 = program.getSourceFile('/unsupported-3.ts')!; expect(() => collector.getMetadata(unsupported3, true)) .toThrowError(/Reference to a non-exported class/); }); @@ -927,34 +938,39 @@ describe('Collector', () => { it('should not throw with a class with no name', () => { const fileName = '/invalid-class.ts'; override(fileName, 'export class'); - const invalidClass = program.getSourceFile(fileName) !; + const invalidClass = program.getSourceFile(fileName)!; expect(() => collector.getMetadata(invalidClass)).not.toThrow(); }); it('should not throw with a function with no name', () => { const fileName = '/invalid-function.ts'; override(fileName, 'export function'); - const invalidFunction = program.getSourceFile(fileName) !; + const invalidFunction = program.getSourceFile(fileName)!; expect(() => collector.getMetadata(invalidFunction)).not.toThrow(); }); }); - describe('inheritance', () => { - it('should record `extends` clauses for declared classes', () => { - const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts') !) !; - expect(metadata.metadata['DeclaredChildClass']) + describe( + 'inheritance', () => { + it('should record `extends` clauses for declared classes', + () => { + const metadata = + collector.getMetadata(program.getSourceFile('/class-inheritance.ts')!)!; + expect(metadata.metadata['DeclaredChildClass']) .toEqual({__symbolic: 'class', extends: {__symbolic: 'reference', name: 'ParentClass'}}); - }); + }); - it('should record `extends` clauses for classes in the same file', () => { - const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts') !) !; - expect(metadata.metadata['ChildClassSameFile']) + it('should record `extends` clauses for classes in the same file', + () => { + const metadata = + collector.getMetadata(program.getSourceFile('/class-inheritance.ts')!)!; + expect(metadata.metadata['ChildClassSameFile']) .toEqual({__symbolic: 'class', extends: {__symbolic: 'reference', name: 'ParentClass'}}); - }); + }); - it('should record `extends` clauses for classes in a different file', () => { - const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts') !) !; - expect(metadata.metadata['ChildClassOtherFile']).toEqual({ + it('should record `extends` clauses for classes in a different file', () => { + const metadata = collector.getMetadata(program.getSourceFile('/class-inheritance.ts')!)!; + expect(metadata.metadata['ChildClassOtherFile']).toEqual({ __symbolic: 'class', extends: { __symbolic: 'reference', @@ -964,29 +980,29 @@ describe('Collector', () => { character: 45, } }); - }); + }); - function expectClass(entry: MetadataEntry): entry is ClassMetadata { - const result = isClassMetadata(entry); - expect(result).toBeTruthy(); - return result; - } + function expectClass(entry: MetadataEntry): entry is ClassMetadata { + const result = isClassMetadata(entry); + expect(result).toBeTruthy(); + return result; + } - it('should collect the correct arity for a class', () => { - const metadata = collector.getMetadata(program.getSourceFile('/class-arity.ts') !) !; - - const zero = metadata.metadata['Zero']; - if (expectClass(zero)) expect(zero.arity).toBeUndefined(); - const one = metadata.metadata['One']; - if (expectClass(one)) expect(one.arity).toBe(1); - const two = metadata.metadata['Two']; - if (expectClass(two)) expect(two.arity).toBe(2); - const three = metadata.metadata['Three']; - if (expectClass(three)) expect(three.arity).toBe(3); - const nine = metadata.metadata['Nine']; - if (expectClass(nine)) expect(nine.arity).toBe(9); - }); - }); + it('should collect the correct arity for a class', () => { + const metadata = collector.getMetadata(program.getSourceFile('/class-arity.ts')!)!; + + const zero = metadata.metadata['Zero']; + if (expectClass(zero)) expect(zero.arity).toBeUndefined(); + const one = metadata.metadata['One']; + if (expectClass(one)) expect(one.arity).toBe(1); + const two = metadata.metadata['Two']; + if (expectClass(two)) expect(two.arity).toBe(2); + const three = metadata.metadata['Three']; + if (expectClass(three)) expect(three.arity).toBe(3); + const nine = metadata.metadata['Nine']; + if (expectClass(nine)) expect(nine.arity).toBe(9); + }); + }); describe('regression', () => { it('should be able to collect a short-hand property value', () => { @@ -1053,11 +1069,12 @@ describe('Collector', () => { expect((metadata.metadata.MyIf as any).statics.typeGuard) .not.toBeUndefined('typeGuard was not collected'); }); - }); describe('references', () => { - beforeEach(() => { collector = new MetadataCollector({quotedNames: true}); }); + beforeEach(() => { + collector = new MetadataCollector({quotedNames: true}); + }); it('should record a reference to an exported field of a useValue', () => { const metadata = collectSource(` @@ -1113,13 +1130,13 @@ describe('Collector', () => { } return value; }); - expect(metadata !.metadata['a']).toEqual({__symbolic: 'reference', name: lambdaTemp}); + expect(metadata!.metadata['a']).toEqual({__symbolic: 'reference', name: lambdaTemp}); }); it('should compose substitution functions', () => { const collector = new MetadataCollector({ - substituteExpression: (value, node) => isMetadataGlobalReferenceExpression(value) && - value.name == lambdaTemp ? + substituteExpression: (value, node) => + isMetadataGlobalReferenceExpression(value) && value.name == lambdaTemp ? {__symbolic: 'reference', name: value.name + '2'} : value }); @@ -1133,19 +1150,19 @@ describe('Collector', () => { } return value; }); - expect(metadata !.metadata['a']).toEqual({__symbolic: 'reference', name: lambdaTemp + '2'}); + expect(metadata!.metadata['a']).toEqual({__symbolic: 'reference', name: lambdaTemp + '2'}); }); }); function override(fileName: string, content: string) { host.overrideFile(fileName, content); host.addFile(fileName); - program = service.getProgram() !; + program = service.getProgram()!; } function collectSource(content: string): ModuleMetadata { const sourceFile = createSource(content); - return collector.getMetadata(sourceFile) !; + return collector.getMetadata(sourceFile)!; } }); diff --git a/packages/compiler-cli/test/metadata/evaluator_spec.ts b/packages/compiler-cli/test/metadata/evaluator_spec.ts index 6bd8f5167a0af..405ff7418957d 100644 --- a/packages/compiler-cli/test/metadata/evaluator_spec.ts +++ b/packages/compiler-cli/test/metadata/evaluator_spec.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {Evaluator} from '../../src/metadata/evaluator'; import {Symbols} from '../../src/metadata/symbols'; -import {Directory, Host, expectNoDiagnostics, findVar, findVarInitializer} from './typescript.mocks'; +import {Directory, expectNoDiagnostics, findVar, findVarInitializer, Host} from './typescript.mocks'; describe('Evaluator', () => { const documentRegistry = ts.createDocumentRegistry(); @@ -27,7 +27,7 @@ describe('Evaluator', () => { 'newExpression.ts', 'errors.ts', 'declared.ts' ]); service = ts.createLanguageService(host, documentRegistry); - program = service.getProgram() !; + program = service.getProgram()!; typeChecker = program.getTypeChecker(); symbols = new Symbols(null as any as ts.SourceFile); evaluator = new Evaluator(symbols, new Map()); @@ -45,7 +45,7 @@ describe('Evaluator', () => { }); it('should be able to fold literal expressions', () => { - const consts = program.getSourceFile('consts.ts') !; + const consts = program.getSourceFile('consts.ts')!; expect(evaluator.isFoldable(findVarInitializer(consts, 'someName'))).toBeTruthy(); expect(evaluator.isFoldable(findVarInitializer(consts, 'someBool'))).toBeTruthy(); expect(evaluator.isFoldable(findVarInitializer(consts, 'one'))).toBeTruthy(); @@ -53,7 +53,7 @@ describe('Evaluator', () => { }); it('should be able to fold expressions with foldable references', () => { - const expressions = program.getSourceFile('expressions.ts') !; + const expressions = program.getSourceFile('expressions.ts')!; symbols.define('someName', 'some-name'); symbols.define('someBool', true); symbols.define('one', 1); @@ -67,7 +67,7 @@ describe('Evaluator', () => { }); it('should be able to evaluate literal expressions', () => { - const consts = program.getSourceFile('consts.ts') !; + const consts = program.getSourceFile('consts.ts')!; expect(evaluator.evaluateNode(findVarInitializer(consts, 'someName'))).toBe('some-name'); expect(evaluator.evaluateNode(findVarInitializer(consts, 'someBool'))).toBe(true); expect(evaluator.evaluateNode(findVarInitializer(consts, 'one'))).toBe(1); @@ -75,7 +75,7 @@ describe('Evaluator', () => { }); it('should be able to evaluate expressions', () => { - const expressions = program.getSourceFile('expressions.ts') !; + const expressions = program.getSourceFile('expressions.ts')!; symbols.define('someName', 'some-name'); symbols.define('someBool', true); symbols.define('one', 1); @@ -118,11 +118,10 @@ describe('Evaluator', () => { expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftRight'))).toEqual(-1 >> 2); expect(evaluator.evaluateNode(findVarInitializer(expressions, 'bShiftRightU'))) .toEqual(-1 >>> 2); - }); it('should report recursive references as symbolic', () => { - const expressions = program.getSourceFile('expressions.ts') !; + const expressions = program.getSourceFile('expressions.ts')!; expect(evaluator.evaluateNode(findVarInitializer(expressions, 'recursiveA'))) .toEqual({__symbolic: 'reference', name: 'recursiveB'}); expect(evaluator.evaluateNode(findVarInitializer(expressions, 'recursiveB'))) @@ -130,13 +129,13 @@ describe('Evaluator', () => { }); it('should correctly handle special cases for CONST_EXPR', () => { - const const_expr = program.getSourceFile('const_expr.ts') !; + const const_expr = program.getSourceFile('const_expr.ts')!; expect(evaluator.evaluateNode(findVarInitializer(const_expr, 'bTrue'))).toEqual(true); expect(evaluator.evaluateNode(findVarInitializer(const_expr, 'bFalse'))).toEqual(false); }); it('should resolve a forwardRef', () => { - const forwardRef = program.getSourceFile('forwardRef.ts') !; + const forwardRef = program.getSourceFile('forwardRef.ts')!; expect(evaluator.evaluateNode(findVarInitializer(forwardRef, 'bTrue'))).toEqual(true); expect(evaluator.evaluateNode(findVarInitializer(forwardRef, 'bFalse'))).toEqual(false); }); @@ -144,7 +143,7 @@ describe('Evaluator', () => { it('should return new expressions', () => { symbols.define('Value', {__symbolic: 'reference', module: './classes', name: 'Value'}); evaluator = new Evaluator(symbols, new Map()); - const newExpression = program.getSourceFile('newExpression.ts') !; + const newExpression = program.getSourceFile('newExpression.ts')!; expect(evaluator.evaluateNode(findVarInitializer(newExpression, 'someValue'))).toEqual({ __symbolic: 'new', expression: @@ -160,9 +159,9 @@ describe('Evaluator', () => { }); it('should support reference to a declared module type', () => { - const declared = program.getSourceFile('declared.ts') !; - const aDecl = findVar(declared, 'a') !; - expect(evaluator.evaluateNode(aDecl.type !)).toEqual({ + const declared = program.getSourceFile('declared.ts')!; + const aDecl = findVar(declared, 'a')!; + expect(evaluator.evaluateNode(aDecl.type!)).toEqual({ __symbolic: 'select', expression: {__symbolic: 'reference', name: 'Foo'}, member: 'A' @@ -170,28 +169,28 @@ describe('Evaluator', () => { }); it('should return errors for unsupported expressions', () => { - const errors = program.getSourceFile('errors.ts') !; - const fDecl = findVar(errors, 'f') !; - expect(evaluator.evaluateNode(fDecl.initializer !)) + const errors = program.getSourceFile('errors.ts')!; + const fDecl = findVar(errors, 'f')!; + expect(evaluator.evaluateNode(fDecl.initializer!)) .toEqual({__symbolic: 'error', message: 'Lambda not supported', line: 1, character: 12}); - const eDecl = findVar(errors, 'e') !; - expect(evaluator.evaluateNode(eDecl.type !)).toEqual({ + const eDecl = findVar(errors, 'e')!; + expect(evaluator.evaluateNode(eDecl.type!)).toEqual({ __symbolic: 'error', message: 'Could not resolve type', line: 2, character: 11, context: {typeName: 'NotFound'} }); - const sDecl = findVar(errors, 's') !; - expect(evaluator.evaluateNode(sDecl.initializer !)).toEqual({ + const sDecl = findVar(errors, 's')!; + expect(evaluator.evaluateNode(sDecl.initializer!)).toEqual({ __symbolic: 'error', message: 'Name expected', line: 3, character: 14, context: {received: '1'} }); - const tDecl = findVar(errors, 't') !; - expect(evaluator.evaluateNode(tDecl.initializer !)).toEqual({ + const tDecl = findVar(errors, 't')!; + expect(evaluator.evaluateNode(tDecl.initializer!)).toEqual({ __symbolic: 'error', message: 'Expression form not supported', line: 4, @@ -200,16 +199,16 @@ describe('Evaluator', () => { }); it('should be able to fold an array spread', () => { - const expressions = program.getSourceFile('expressions.ts') !; + const expressions = program.getSourceFile('expressions.ts')!; symbols.define('arr', [1, 2, 3, 4]); - const arrSpread = findVar(expressions, 'arrSpread') !; - expect(evaluator.evaluateNode(arrSpread.initializer !)).toEqual([0, 1, 2, 3, 4, 5]); + const arrSpread = findVar(expressions, 'arrSpread')!; + expect(evaluator.evaluateNode(arrSpread.initializer!)).toEqual([0, 1, 2, 3, 4, 5]); }); it('should be able to produce a spread expression', () => { - const expressions = program.getSourceFile('expressions.ts') !; - const arrSpreadRef = findVar(expressions, 'arrSpreadRef') !; - expect(evaluator.evaluateNode(arrSpreadRef.initializer !)).toEqual([ + const expressions = program.getSourceFile('expressions.ts')!; + const arrSpreadRef = findVar(expressions, 'arrSpreadRef')!; + expect(evaluator.evaluateNode(arrSpreadRef.initializer!)).toEqual([ 0, {__symbolic: 'spread', expression: {__symbolic: 'reference', name: 'arrImport'}}, 5 ]); }); @@ -218,8 +217,8 @@ describe('Evaluator', () => { const source = sourceFileOf(` export var a = new f; `); - const expr = findVar(source, 'a') !; - expect(evaluator.evaluateNode(expr.initializer !)) + const expr = findVar(source, 'a')!; + expect(evaluator.evaluateNode(expr.initializer!)) .toEqual({__symbolic: 'new', expression: {__symbolic: 'reference', name: 'f'}}); }); @@ -244,7 +243,7 @@ describe('Evaluator', () => { export var a = () => b; `); const expr = findVar(source, 'a'); - expect(evaluator.evaluateNode(expr !.initializer !)) + expect(evaluator.evaluateNode(expr!.initializer!)) .toEqual({__symbolic: 'reference', name: lambdaTemp}); }); @@ -256,7 +255,7 @@ describe('Evaluator', () => { ]; `); const expr = findVar(source, 'a'); - expect(evaluator.evaluateNode(expr !.initializer !)).toEqual([ + expect(evaluator.evaluateNode(expr!.initializer!)).toEqual([ {provide: 'someValue', useFactory: {__symbolic: 'reference', name: lambdaTemp}} ]); }); diff --git a/packages/compiler-cli/test/metadata/symbols_spec.ts b/packages/compiler-cli/test/metadata/symbols_spec.ts index 8ea2e70edb673..37c5a693fdb45 100644 --- a/packages/compiler-cli/test/metadata/symbols_spec.ts +++ b/packages/compiler-cli/test/metadata/symbols_spec.ts @@ -11,7 +11,7 @@ import * as ts from 'typescript'; import {isMetadataGlobalReferenceExpression} from '../../src/metadata/schema'; import {Symbols} from '../../src/metadata/symbols'; -import {Directory, Host, expectNoDiagnostics} from './typescript.mocks'; +import {Directory, expectNoDiagnostics, Host} from './typescript.mocks'; describe('Symbols', () => { let symbols: Symbols; @@ -42,9 +42,9 @@ describe('Symbols', () => { beforeEach(() => { host = new Host(FILES, ['consts.ts', 'expressions.ts', 'imports.ts']); service = ts.createLanguageService(host); - program = service.getProgram() !; - expressions = program.getSourceFile('expressions.ts') !; - imports = program.getSourceFile('imports.ts') !; + program = service.getProgram()!; + expressions = program.getSourceFile('expressions.ts')!; + imports = program.getSourceFile('imports.ts')!; }); it('should not have syntax errors in the test sources', () => { @@ -111,7 +111,7 @@ describe('Symbols', () => { } return false; }; - ts.forEachChild(core !, visit); + ts.forEachChild(core!, visit); }); }); diff --git a/packages/compiler-cli/test/metadata/typescript.mocks.ts b/packages/compiler-cli/test/metadata/typescript.mocks.ts index 44d3bb39fbd14..71d214406d2d0 100644 --- a/packages/compiler-cli/test/metadata/typescript.mocks.ts +++ b/packages/compiler-cli/test/metadata/typescript.mocks.ts @@ -10,7 +10,9 @@ import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; -export interface Directory { [name: string]: (Directory|string); } +export interface Directory { + [name: string]: (Directory|string); +} export class Host implements ts.LanguageServiceHost { private overrides = new Map<string, string>(); @@ -26,20 +28,30 @@ export class Host implements ts.LanguageServiceHost { }; } - getScriptFileNames(): string[] { return this.scripts; } + getScriptFileNames(): string[] { + return this.scripts; + } - getScriptVersion(fileName: string): string { return this.version.toString(); } + getScriptVersion(fileName: string): string { + return this.version.toString(); + } getScriptSnapshot(fileName: string): ts.IScriptSnapshot|undefined { const content = this.getFileContent(fileName); if (content) return ts.ScriptSnapshot.fromString(content); } - fileExists(fileName: string): boolean { return this.getFileContent(fileName) != null; } + fileExists(fileName: string): boolean { + return this.getFileContent(fileName) != null; + } - getCurrentDirectory(): string { return '/'; } + getCurrentDirectory(): string { + return '/'; + } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } overrideFile(fileName: string, content: string) { this.overrides.set(fileName, content); @@ -81,24 +93,52 @@ export function open(directory: Directory, fileName: string): Directory|string|u export class MockNode implements ts.Node { decorators?: ts.NodeArray<ts.Decorator>; modifiers?: ts.NodeArray<ts.Modifier>; - parent !: ts.Node; + parent!: ts.Node; constructor( public kind: ts.SyntaxKind = ts.SyntaxKind.Identifier, public flags: ts.NodeFlags = 0, public pos: number = 0, public end: number = 0) {} - getSourceFile(): ts.SourceFile { return null as any as ts.SourceFile; } - getChildCount(sourceFile?: ts.SourceFile): number { return 0; } - getChildAt(index: number, sourceFile?: ts.SourceFile): ts.Node { return null as any as ts.Node; } - getChildren(sourceFile?: ts.SourceFile): ts.Node[] { return []; } - getStart(sourceFile?: ts.SourceFile): number { return 0; } - getFullStart(): number { return 0; } - getEnd(): number { return 0; } - getWidth(sourceFile?: ts.SourceFile): number { return 0; } - getFullWidth(): number { return 0; } - getLeadingTriviaWidth(sourceFile?: ts.SourceFile): number { return 0; } - getFullText(sourceFile?: ts.SourceFile): string { return ''; } - getText(sourceFile?: ts.SourceFile): string { return ''; } - getFirstToken(sourceFile?: ts.SourceFile): ts.Node { return null as any as ts.Node; } - getLastToken(sourceFile?: ts.SourceFile): ts.Node { return null as any as ts.Node; } + getSourceFile(): ts.SourceFile { + return null as any as ts.SourceFile; + } + getChildCount(sourceFile?: ts.SourceFile): number { + return 0; + } + getChildAt(index: number, sourceFile?: ts.SourceFile): ts.Node { + return null as any as ts.Node; + } + getChildren(sourceFile?: ts.SourceFile): ts.Node[] { + return []; + } + getStart(sourceFile?: ts.SourceFile): number { + return 0; + } + getFullStart(): number { + return 0; + } + getEnd(): number { + return 0; + } + getWidth(sourceFile?: ts.SourceFile): number { + return 0; + } + getFullWidth(): number { + return 0; + } + getLeadingTriviaWidth(sourceFile?: ts.SourceFile): number { + return 0; + } + getFullText(sourceFile?: ts.SourceFile): string { + return ''; + } + getText(sourceFile?: ts.SourceFile): string { + return ''; + } + getFirstToken(sourceFile?: ts.SourceFile): ts.Node { + return null as any as ts.Node; + } + getLastToken(sourceFile?: ts.SourceFile): ts.Node { + return null as any as ts.Node; + } forEachChild<T>( cbNode: (node: ts.Node) => T | undefined, cbNodeArray?: (nodes: ts.NodeArray<ts.Node>) => T | undefined): T|undefined { @@ -111,10 +151,10 @@ export class MockIdentifier extends MockNode implements ts.Identifier { isInJSDocNamespace?: boolean; decorators?: ts.NodeArray<ts.Decorator>; modifiers?: ts.NodeArray<ts.Modifier>; - parent !: ts.Node; + parent!: ts.Node; public text: string; // TODO(issue/24571): remove '!'. - public escapedText !: ts.__String; + public escapedText!: ts.__String; // tslint:disable public _declarationBrand: any; public _primaryExpressionBrand: any; @@ -135,7 +175,7 @@ export class MockIdentifier extends MockNode implements ts.Identifier { } export class MockVariableDeclaration extends MockNode implements ts.VariableDeclaration { - parent !: ts.VariableDeclarationList | ts.CatchClause; + parent!: ts.VariableDeclarationList|ts.CatchClause; exclamationToken?: ts.Token<ts.SyntaxKind.ExclamationToken>; type?: ts.TypeNode; initializer?: ts.Expression; @@ -151,32 +191,46 @@ export class MockVariableDeclaration extends MockNode implements ts.VariableDecl super(kind, flags, pos, end); } - static of (name: string): MockVariableDeclaration { + static of(name: string): MockVariableDeclaration { return new MockVariableDeclaration(new MockIdentifier(name)); } } export class MockSymbol implements ts.Symbol { - declarations !: ts.Declaration[]; - valueDeclaration !: ts.Declaration; + declarations!: ts.Declaration[]; + valueDeclaration!: ts.Declaration; members?: ts.UnderscoreEscapedMap<ts.Symbol>; exports?: ts.UnderscoreEscapedMap<ts.Symbol>; globalExports?: ts.UnderscoreEscapedMap<ts.Symbol>; // TODO(issue/24571): remove '!'. - public escapedName !: ts.__String; + public escapedName!: ts.__String; constructor( public name: string, private node: ts.Declaration = MockVariableDeclaration.of(name), public flags: ts.SymbolFlags = 0) {} - getFlags(): ts.SymbolFlags { return this.flags; } - getName(): string { return this.name; } - getEscapedName(): ts.__String { return this.escapedName; } - getDeclarations(): ts.Declaration[] { return [this.node]; } - getDocumentationComment(): ts.SymbolDisplayPart[] { return []; } + getFlags(): ts.SymbolFlags { + return this.flags; + } + getName(): string { + return this.name; + } + getEscapedName(): ts.__String { + return this.escapedName; + } + getDeclarations(): ts.Declaration[] { + return [this.node]; + } + getDocumentationComment(): ts.SymbolDisplayPart[] { + return []; + } // TODO(vicb): removed in TS 2.2 - getJsDocTags(): any[] { return []; } + getJsDocTags(): any[] { + return []; + } - static of (name: string): MockSymbol { return new MockSymbol(name); } + static of(name: string): MockSymbol { + return new MockSymbol(name); + } } export function expectNoDiagnostics(diagnostics: ts.Diagnostic[]) { @@ -219,14 +273,14 @@ export function findVar(sourceFile: ts.SourceFile, name: string): ts.VariableDec export function findVarInitializer(sourceFile: ts.SourceFile, name: string): ts.Expression { const v = findVar(sourceFile, name); expect(v && v.initializer).toBeDefined(); - return v !.initializer !; + return v!.initializer!; } export function isClass(node: ts.Node): node is ts.ClassDeclaration { return node.kind === ts.SyntaxKind.ClassDeclaration; } -export function isNamed(node: ts.Node | undefined, name: string): node is ts.Identifier { +export function isNamed(node: ts.Node|undefined, name: string): node is ts.Identifier { return !!node && node.kind === ts.SyntaxKind.Identifier && (<ts.Identifier>node).text === name; } diff --git a/packages/compiler-cli/test/mocks.ts b/packages/compiler-cli/test/mocks.ts index a1ac68edd5309..7d8d083d3edfe 100644 --- a/packages/compiler-cli/test/mocks.ts +++ b/packages/compiler-cli/test/mocks.ts @@ -8,16 +8,22 @@ import * as ts from 'typescript'; -export type Entry = string | Directory; +export type Entry = string|Directory; -export interface Directory { [name: string]: Entry; } +export interface Directory { + [name: string]: Entry; +} export class MockAotContext { private files: Entry[]; - constructor(public currentDirectory: string, ...files: Entry[]) { this.files = files; } + constructor(public currentDirectory: string, ...files: Entry[]) { + this.files = files; + } - fileExists(fileName: string): boolean { return typeof this.getEntry(fileName) === 'string'; } + fileExists(fileName: string): boolean { + return typeof this.getEntry(fileName) === 'string'; + } directoryExists(path: string): boolean { return path === this.currentDirectory || typeof this.getEntry(path) === 'object'; @@ -28,7 +34,7 @@ export class MockAotContext { if (typeof data === 'string') { return data; } - return undefined !; + return undefined!; } readResource(fileName: string): Promise<string> { @@ -41,14 +47,16 @@ export class MockAotContext { writeFile(fileName: string, data: string): void { const parts = fileName.split('/'); - const name = parts.pop() !; + const name = parts.pop()!; const entry = this.getEntry(parts); if (entry && typeof entry !== 'string') { entry[name] = data; } } - assumeFileExists(fileName: string): void { this.writeFile(fileName, ''); } + assumeFileExists(fileName: string): void { + this.writeFile(fileName, ''); + } getEntry(fileName: string|string[]): Entry|undefined { let parts = typeof fileName === 'string' ? fileName.split('/') : fileName; @@ -69,7 +77,9 @@ export class MockAotContext { } } - override(files: Entry) { return new MockAotContext(this.currentDirectory, files, ...this.files); } + override(files: Entry) { + return new MockAotContext(this.currentDirectory, files, ...this.files); + } } function first<T>(a: T[], cb: (value: T) => T | undefined): T|undefined { @@ -82,7 +92,7 @@ function first<T>(a: T[], cb: (value: T) => T | undefined): T|undefined { function getEntryFromFiles(parts: string[], files: Entry) { let current = files; while (parts.length) { - const part = parts.shift() !; + const part = parts.shift()!; if (typeof current === 'string') { return undefined; } @@ -98,7 +108,7 @@ function getEntryFromFiles(parts: string[], files: Entry) { function normalize(parts: string[]): string[] { const result: string[] = []; while (parts.length) { - const part = parts.shift() !; + const part = parts.shift()!; switch (part) { case '.': break; @@ -115,9 +125,13 @@ function normalize(parts: string[]): string[] { export class MockCompilerHost implements ts.CompilerHost { constructor(private context: MockAotContext) {} - fileExists(fileName: string): boolean { return this.context.fileExists(fileName); } + fileExists(fileName: string): boolean { + return this.context.fileExists(fileName); + } - readFile(fileName: string): string { return this.context.readFile(fileName); } + readFile(fileName: string): string { + return this.context.readFile(fileName); + } directoryExists(directoryName: string): boolean { return this.context.directoryExists(directoryName); @@ -130,7 +144,7 @@ export class MockCompilerHost implements ts.CompilerHost { if (sourceText != null) { return ts.createSourceFile(fileName, sourceText, languageVersion); } else { - return undefined !; + return undefined!; } } @@ -138,15 +152,28 @@ export class MockCompilerHost implements ts.CompilerHost { return ts.getDefaultLibFileName(options); } - writeFile: ts.WriteFileCallback = (fileName, text) => { this.context.writeFile(fileName, text); }; + writeFile: ts.WriteFileCallback = + (fileName, text) => { + this.context.writeFile(fileName, text); + } - getCurrentDirectory(): string { return this.context.currentDirectory; } + getCurrentDirectory(): string { + return this.context.currentDirectory; + } - getCanonicalFileName(fileName: string): string { return fileName; } + getCanonicalFileName(fileName: string): string { + return fileName; + } - useCaseSensitiveFileNames(): boolean { return false; } + useCaseSensitiveFileNames(): boolean { + return false; + } - getNewLine(): string { return '\n'; } + getNewLine(): string { + return '\n'; + } - getDirectories(path: string): string[] { return this.context.getDirectories(path); } + getDirectories(path: string): string[] { + return this.context.getDirectories(path); + } } diff --git a/packages/compiler-cli/test/ngtsc/component_indexing_spec.ts b/packages/compiler-cli/test/ngtsc/component_indexing_spec.ts index ff05d00593ee9..a1f9e9a989db4 100644 --- a/packages/compiler-cli/test/ngtsc/component_indexing_spec.ts +++ b/packages/compiler-cli/test/ngtsc/component_indexing_spec.ts @@ -14,7 +14,7 @@ import {NgtscTestEnvironment} from './env'; runInEachFileSystem(() => { describe('ngtsc component indexing', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; let testSourceFile: AbsoluteFsPath; let testTemplateFile: AbsoluteFsPath; @@ -177,10 +177,10 @@ runInEachFileSystem(() => { expect(testComp).toBeDefined(); expect(testImportComp).toBeDefined(); - expect(testComp !.template.usedComponents.size).toBe(0); - expect(testImportComp !.template.usedComponents.size).toBe(1); + expect(testComp!.template.usedComponents.size).toBe(0); + expect(testImportComp!.template.usedComponents.size).toBe(1); - const [usedComp] = Array.from(testImportComp !.template.usedComponents); + const [usedComp] = Array.from(testImportComp!.template.usedComponents); expect(indexed.get(usedComp)).toEqual(testComp); }); }); diff --git a/packages/compiler-cli/test/ngtsc/env.ts b/packages/compiler-cli/test/ngtsc/env.ts index d8c63fb1fa389..1d5a2deb6a209 100644 --- a/packages/compiler-cli/test/ngtsc/env.ts +++ b/packages/compiler-cli/test/ngtsc/env.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {CustomTransformers, Program, defaultGatherDiagnostics} from '@angular/compiler-cli'; +import {CustomTransformers, defaultGatherDiagnostics, Program} from '@angular/compiler-cli'; import * as api from '@angular/compiler-cli/src/transformers/api'; import * as ts from 'typescript'; import {createCompilerHost, createProgram} from '../../index'; import {main, mainDiagnosticsForTest, readNgcCommandLineAndConfiguration} from '../../src/main'; -import {AbsoluteFsPath, FileSystem, NgtscCompilerHost, absoluteFrom, getFileSystem} from '../../src/ngtsc/file_system'; +import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, NgtscCompilerHost} from '../../src/ngtsc/file_system'; import {Folder, MockFileSystem} from '../../src/ngtsc/file_system/testing'; import {IndexedComponent} from '../../src/ngtsc/indexer'; import {NgtscProgram} from '../../src/ngtsc/program'; @@ -115,7 +115,7 @@ export class NgtscTestEnvironment { if (this.multiCompileHostExt === null) { throw new Error(`Not tracking written files - call enableMultipleCompilations()`); } - this.changedResources !.clear(); + this.changedResources!.clear(); this.multiCompileHostExt.flushWrittenFileTracking(); } @@ -123,7 +123,9 @@ export class NgtscTestEnvironment { * Older versions of the CLI do not provide the `CompilerHost.getModifiedResourceFiles()` method. * This results in the `changedResources` set being `null`. */ - simulateLegacyCLICompilerHost() { this.changedResources = null; } + simulateLegacyCLICompilerHost() { + this.changedResources = null; + } getFilesWrittenSinceLastFlush(): Set<string> { if (this.multiCompileHostExt === null) { @@ -142,7 +144,7 @@ export class NgtscTestEnvironment { const absFilePath = this.fs.resolve(this.basePath, fileName); if (this.multiCompileHostExt !== null) { this.multiCompileHostExt.invalidate(absFilePath); - this.changedResources !.add(absFilePath); + this.changedResources!.add(absFilePath); } this.fs.ensureDir(this.fs.dirname(absFilePath)); this.fs.writeFile(absFilePath, content); @@ -156,8 +158,7 @@ export class NgtscTestEnvironment { this.multiCompileHostExt.invalidate(absFilePath); } - tsconfig(extraOpts: {[key: string]: string | boolean | null} = {}, extraRootDirs?: string[]): - void { + tsconfig(extraOpts: {[key: string]: string|boolean|null} = {}, extraRootDirs?: string[]): void { const tsconfig: {[key: string]: any} = { extends: './tsconfig-base.json', angularCompilerOptions: {...extraOpts, enableIvy: true}, @@ -179,7 +180,7 @@ export class NgtscTestEnvironment { */ driveMain(customTransformers?: CustomTransformers): void { const errorSpy = jasmine.createSpy('consoleError').and.callFake(console.error); - let reuseProgram: {program: Program | undefined}|undefined = undefined; + let reuseProgram: {program: Program|undefined}|undefined = undefined; if (this.multiCompileHostExt !== null) { reuseProgram = { program: this.oldProgram || undefined, @@ -191,7 +192,7 @@ export class NgtscTestEnvironment { expect(errorSpy).not.toHaveBeenCalled(); expect(exitCode).toBe(0); if (this.multiCompileHostExt !== null) { - this.oldProgram = reuseProgram !.program !; + this.oldProgram = reuseProgram!.program!; } } @@ -200,7 +201,7 @@ export class NgtscTestEnvironment { */ driveDiagnostics(): ReadonlyArray<ts.Diagnostic> { // ngtsc only produces ts.Diagnostic messages. - let reuseProgram: {program: Program | undefined}|undefined = undefined; + let reuseProgram: {program: Program|undefined}|undefined = undefined; if (this.multiCompileHostExt !== null) { reuseProgram = { program: this.oldProgram || undefined, @@ -212,7 +213,7 @@ export class NgtscTestEnvironment { if (this.multiCompileHostExt !== null) { - this.oldProgram = reuseProgram !.program !; + this.oldProgram = reuseProgram!.program!; } // In ngtsc, only `ts.Diagnostic`s are produced. @@ -245,7 +246,7 @@ export class NgtscTestEnvironment { } class AugmentedCompilerHost extends NgtscCompilerHost { - delegate !: ts.CompilerHost; + delegate!: ts.CompilerHost; } const ROOT_PREFIX = 'root/'; @@ -283,7 +284,7 @@ class MultiCompileHostExt extends AugmentedCompilerHost implements Partial<ts.Co fileName: string, languageVersion: ts.ScriptTarget, onError?: (message: string) => void, shouldCreateNewSourceFile?: boolean): ts.SourceFile|undefined { if (this.cache.has(fileName)) { - return this.cache.get(fileName) !; + return this.cache.get(fileName)!; } const sf = super.getSourceFile(fileName, languageVersion); if (sf !== undefined) { @@ -292,7 +293,9 @@ class MultiCompileHostExt extends AugmentedCompilerHost implements Partial<ts.Co return sf; } - flushWrittenFileTracking(): void { this.writtenFiles.clear(); } + flushWrittenFileTracking(): void { + this.writtenFiles.clear(); + } writeFile( fileName: string, data: string, writeByteOrderMark: boolean, @@ -302,9 +305,13 @@ class MultiCompileHostExt extends AugmentedCompilerHost implements Partial<ts.Co this.writtenFiles.add(fileName); } - getFilesWrittenSinceLastFlush(): Set<string> { return this.writtenFiles; } + getFilesWrittenSinceLastFlush(): Set<string> { + return this.writtenFiles; + } - invalidate(fileName: string): void { this.cache.delete(fileName); } + invalidate(fileName: string): void { + this.cache.delete(fileName); + } } class ResourceLoadingCompileHost extends AugmentedCompilerHost implements api.CompilerHost { @@ -323,7 +330,7 @@ function makeWrapHost(wrapped: AugmentedCompilerHost): (host: ts.CompilerHost) = return new Proxy(delegate, { get: (target: ts.CompilerHost, name: string): any => { if ((wrapped as any)[name] !== undefined) { - return (wrapped as any)[name] !.bind(wrapped); + return (wrapped as any)[name]!.bind(wrapped); } return (target as any)[name]; } diff --git a/packages/compiler-cli/test/ngtsc/fake_core/index.ts b/packages/compiler-cli/test/ngtsc/fake_core/index.ts index 17ae37d6bce7b..b1c7451d13f9f 100644 --- a/packages/compiler-cli/test/ngtsc/fake_core/index.ts +++ b/packages/compiler-cli/test/ngtsc/fake_core/index.ts @@ -8,19 +8,19 @@ interface FnWithArg<T> { (...args: any[]): T; - new (...args: any[]): T; + new(...args: any[]): T; } function callableClassDecorator(): FnWithArg<(clazz: any) => any> { - return null !; + return null!; } function callableParamDecorator(): FnWithArg<(a: any, b: any, c: any) => void> { - return null !; + return null!; } function callablePropDecorator(): FnWithArg<(a: any, b: any) => any> { - return null !; + return null!; } export const Component = callableClassDecorator(); @@ -66,7 +66,9 @@ export function forwardRef<T>(fn: () => T): T { return fn(); } -export interface SimpleChanges { [propName: string]: any; } +export interface SimpleChanges { + [propName: string]: any; +} export type ɵɵNgModuleDefWithMeta<ModuleT, DeclarationsT, ImportsT, ExportsT> = any; export type ɵɵDirectiveDefWithMeta< @@ -89,11 +91,15 @@ export const CUSTOM_ELEMENTS_SCHEMA: any = false; export const NO_ERRORS_SCHEMA: any = false; export class EventEmitter<T> { - subscribe(generatorOrNext?: any, error?: any, complete?: any): unknown { return null; } + subscribe(generatorOrNext?: any, error?: any, complete?: any): unknown { + return null; + } } -export interface QueryList<T>/* implements Iterable<T> */ { [Symbol.iterator]: () => Iterator<T>; } +export interface QueryList<T>/* implements Iterable<T> */ { + [Symbol.iterator]: () => Iterator<T>; +} -export type NgIterable<T> = Array<T>| Iterable<T>; +export type NgIterable<T> = Array<T>|Iterable<T>; export class NgZone {} diff --git a/packages/compiler-cli/test/ngtsc/incremental_error_spec.ts b/packages/compiler-cli/test/ngtsc/incremental_error_spec.ts index 16a51005c3798..c850b74c7f14d 100644 --- a/packages/compiler-cli/test/ngtsc/incremental_error_spec.ts +++ b/packages/compiler-cli/test/ngtsc/incremental_error_spec.ts @@ -16,7 +16,7 @@ const testFiles = loadStandardTestFiles(); runInEachFileSystem(() => { describe('ngtsc incremental compilation with errors', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); @@ -66,7 +66,7 @@ runInEachFileSystem(() => { `); const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/other.ts')); + expect(diags[0].file!.fileName).toBe(_('/other.ts')); expectToHaveWritten([]); // Remove the error. /other.js should now be emitted again. @@ -92,7 +92,7 @@ runInEachFileSystem(() => { const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/other.ts')); + expect(diags[0].file!.fileName).toBe(_('/other.ts')); expectToHaveWritten([]); // Remove the error. All files should be emitted. @@ -128,7 +128,7 @@ runInEachFileSystem(() => { const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/other.ts')); + expect(diags[0].file!.fileName).toBe(_('/other.ts')); expectToHaveWritten([]); // Remove the error. All files should be emitted. @@ -175,7 +175,7 @@ runInEachFileSystem(() => { const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/other.ts')); + expect(diags[0].file!.fileName).toBe(_('/other.ts')); expectToHaveWritten([]); // Remove the error. All files should be emitted. diff --git a/packages/compiler-cli/test/ngtsc/incremental_spec.ts b/packages/compiler-cli/test/ngtsc/incremental_spec.ts index f8842baae6b36..6cf7f993435e8 100644 --- a/packages/compiler-cli/test/ngtsc/incremental_spec.ts +++ b/packages/compiler-cli/test/ngtsc/incremental_spec.ts @@ -15,7 +15,7 @@ const testFiles = loadStandardTestFiles(); runInEachFileSystem(() => { describe('ngtsc incremental compilation', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); diff --git a/packages/compiler-cli/test/ngtsc/modulewithproviders_spec.ts b/packages/compiler-cli/test/ngtsc/modulewithproviders_spec.ts index 3035661e28fb9..59663f0f5a8be 100644 --- a/packages/compiler-cli/test/ngtsc/modulewithproviders_spec.ts +++ b/packages/compiler-cli/test/ngtsc/modulewithproviders_spec.ts @@ -17,7 +17,7 @@ const testFiles = loadStandardTestFiles(); runInEachFileSystem(() => { describe('ModuleWithProviders generic type transform', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); diff --git a/packages/compiler-cli/test/ngtsc/monorepo_spec.ts b/packages/compiler-cli/test/ngtsc/monorepo_spec.ts index ac90576641fca..f6b0666a9b85f 100644 --- a/packages/compiler-cli/test/ngtsc/monorepo_spec.ts +++ b/packages/compiler-cli/test/ngtsc/monorepo_spec.ts @@ -16,7 +16,7 @@ const testFiles = loadStandardTestFiles(); runInEachFileSystem(() => { describe('monorepos', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles, absoluteFrom('/app')); diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 6131de87df807..288d9c4c04340 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -38,12 +38,12 @@ const setClassMetadataRegExp = (expectedType: string): RegExp => const testFiles = loadStandardTestFiles(); function getDiagnosticSourceCode(diag: ts.Diagnostic): string { - return diag.file !.text.substr(diag.start !, diag.length !); + return diag.file!.text.substr(diag.start!, diag.length!); } runInEachFileSystem(os => { describe('ngtsc behavioral tests', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); @@ -369,7 +369,6 @@ runInEachFileSystem(os => { // that start with `C:`. if (os !== 'Windows' || platform() === 'win32') { describe('when closure annotations are requested', () => { - it('should add @nocollapse to static fields', () => { env.tsconfig({ 'annotateForClosureCompiler': true, @@ -531,7 +530,6 @@ runInEachFileSystem(os => { verifyOutput(env.getContents('test.js')); }); }); - }); } @@ -1714,7 +1712,8 @@ runInEachFileSystem(os => { }); ['ContentChild', 'ContentChildren'].forEach(decorator => { - it(`should throw if \`descendants\` field of @${decorator}'s options argument has wrong type`, + it(`should throw if \`descendants\` field of @${ + decorator}'s options argument has wrong type`, () => { env.tsconfig({}); env.write('test.ts', ` @@ -2148,7 +2147,6 @@ runInEachFileSystem(os => { expect(jsContents) .toContain('Test.ɵfac = function Test_Factory(t) { i0.ɵɵinvalidFactory()'); }); - }); }); @@ -3466,7 +3464,9 @@ runInEachFileSystem(os => { }); describe('ngfactory shims', () => { - beforeEach(() => { env.tsconfig({'generateNgFactoryShims': true}); }); + beforeEach(() => { + env.tsconfig({'generateNgFactoryShims': true}); + }); it('should generate correct type annotation for NgModuleFactory calls in ngfactories', () => { env.write('test.ts', ` @@ -3568,7 +3568,9 @@ runInEachFileSystem(os => { describe('ngsummary shim generation', () => { - beforeEach(() => { env.tsconfig({'generateNgSummaryShims': true}); }); + beforeEach(() => { + env.tsconfig({'generateNgSummaryShims': true}); + }); it('should generate a summary stub for decorated classes in the input file only', () => { env.write('test.ts', ` @@ -3792,7 +3794,6 @@ runInEachFileSystem(os => { }); it('should use imported types in setClassMetadata if they can be represented as values', () => { - env.write(`types.ts`, ` export class MyTypeA {} export class MyTypeB {} @@ -3824,7 +3825,6 @@ runInEachFileSystem(os => { it('should use imported types in setClassMetadata if they can be represented as values and imported as `* as foo`', () => { - env.write(`types.ts`, ` export class MyTypeA {} export class MyTypeB {} @@ -3855,7 +3855,6 @@ runInEachFileSystem(os => { }); it('should use default-imported types if they can be represented as values', () => { - env.write(`types.ts`, ` export default class Default {} export class Other {} @@ -3883,7 +3882,6 @@ runInEachFileSystem(os => { it('should use `undefined` in setClassMetadata if types can\'t be represented as values', () => { - env.write(`types.ts`, ` export type MyType = Map<any, any>; `); @@ -4059,7 +4057,6 @@ runInEachFileSystem(os => { it('should not generate an error when a local ref is unresolved' + ' (outside of template type-checking)', () => { - env.write('test.ts', ` import {Component} from '@angular/core'; @@ -4347,7 +4344,7 @@ runInEachFileSystem(os => { } }); - it('should throw if @Component is missing a template', async() => { + it('should throw if @Component is missing a template', async () => { env.write('test.ts', ` import {Component} from '@angular/core'; @@ -4359,10 +4356,10 @@ runInEachFileSystem(os => { const diags = await driveDiagnostics(); expect(diags[0].messageText).toBe('component is missing a template'); - expect(diags[0].file !.fileName).toBe(absoluteFrom('/test.ts')); + expect(diags[0].file!.fileName).toBe(absoluteFrom('/test.ts')); }); - it('should throw if `styleUrls` is defined incorrectly in @Component', async() => { + it('should throw if `styleUrls` is defined incorrectly in @Component', async () => { env.write('test.ts', ` import {Component} from '@angular/core'; @@ -4376,7 +4373,7 @@ runInEachFileSystem(os => { const diags = await driveDiagnostics(); expect(diags[0].messageText).toBe('styleUrls must be an array of strings'); - expect(diags[0].file !.fileName).toBe(absoluteFrom('/test.ts')); + expect(diags[0].file!.fileName).toBe(absoluteFrom('/test.ts')); }); }); }); @@ -4497,7 +4494,7 @@ runInEachFileSystem(os => { // Verify that the error is for the correct class. const error = errors[0] as ts.Diagnostic; - const id = expectTokenAtPosition(error.file !, error.start !, ts.isIdentifier); + const id = expectTokenAtPosition(error.file!, error.start!, ts.isIdentifier); expect(id.text).toBe('Dir'); expect(ts.isClassDeclaration(id.parent)).toBe(true); }); @@ -4804,7 +4801,7 @@ runInEachFileSystem(os => { const diag = env.driveDiagnostics(); expect(diag.length).toBe(1); - expect(diag[0] !.code).toEqual(ngErrorCode(ErrorCode.NGMODULE_REEXPORT_NAME_COLLISION)); + expect(diag[0]!.code).toEqual(ngErrorCode(ErrorCode.NGMODULE_REEXPORT_NAME_COLLISION)); }); it('should not error when two directives with the same declared name are exported from the same NgModule, but one is exported from the file directly', @@ -6701,9 +6698,7 @@ export const Foo = Foo__PRE_R3__; const diags = env.driveDiagnostics(); expect(diags.length).toBe(0); }); - }); - }); function expectTokenAtPosition<T extends ts.Node>( @@ -6714,5 +6709,7 @@ export const Foo = Foo__PRE_R3__; return node as T; } - function normalize(input: string): string { return input.replace(/\s+/g, ' ').trim(); } + function normalize(input: string): string { + return input.replace(/\s+/g, ' ').trim(); + } }); diff --git a/packages/compiler-cli/test/ngtsc/scope_spec.ts b/packages/compiler-cli/test/ngtsc/scope_spec.ts index 91651047060f6..904bedd75f4e9 100644 --- a/packages/compiler-cli/test/ngtsc/scope_spec.ts +++ b/packages/compiler-cli/test/ngtsc/scope_spec.ts @@ -20,7 +20,7 @@ const testFiles = loadStandardTestFiles(); runInEachFileSystem(() => { describe('ngtsc module scopes', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); @@ -92,11 +92,11 @@ runInEachFileSystem(() => { const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); const node = findContainingClass(diagnosticToNode(diags[0], ts.isIdentifier)); - expect(node.name !.text).toEqual('TestDir'); + expect(node.name!.text).toEqual('TestDir'); - const relatedNodes = new Set(diags[0].relatedInformation !.map( + const relatedNodes = new Set(diags[0].relatedInformation!.map( related => - findContainingClass(diagnosticToNode(related, ts.isIdentifier)).name !.text)); + findContainingClass(diagnosticToNode(related, ts.isIdentifier)).name!.text)); expect(relatedNodes).toContain('ModuleA'); expect(relatedNodes).toContain('ModuleB'); expect(relatedNodes.size).toBe(2); @@ -141,11 +141,11 @@ runInEachFileSystem(() => { const diags = env.driveDiagnostics(); expect(diags.length).toBe(1); const node = findContainingClass(diagnosticToNode(diags[0], ts.isIdentifier)); - expect(node.name !.text).toEqual('TestDir'); + expect(node.name!.text).toEqual('TestDir'); - const relatedNodes = new Set(diags[0].relatedInformation !.map( + const relatedNodes = new Set(diags[0].relatedInformation!.map( related => - findContainingClass(diagnosticToNode(related, ts.isIdentifier)).name !.text)); + findContainingClass(diagnosticToNode(related, ts.isIdentifier)).name!.text)); expect(relatedNodes).toContain('ModuleA'); expect(relatedNodes).toContain('ModuleB'); expect(relatedNodes.size).toBe(2); @@ -386,13 +386,13 @@ runInEachFileSystem(() => { }); function diagnosticToNode<T extends ts.Node>( - diagnostic: ts.Diagnostic | Diagnostic | ts.DiagnosticRelatedInformation, + diagnostic: ts.Diagnostic|Diagnostic|ts.DiagnosticRelatedInformation, guard: (node: ts.Node) => node is T): T { const diag = diagnostic as ts.Diagnostic | ts.DiagnosticRelatedInformation; if (diag.file === undefined) { throw new Error(`Expected ts.Diagnostic to have a file source`); } - const node = getTokenAtPosition(diag.file, diag.start !); + const node = getTokenAtPosition(diag.file, diag.start!); expect(guard(node)).toBe(true); return node as T; } diff --git a/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts b/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts index 2dbd7df5424f4..dff529f602872 100644 --- a/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts +++ b/packages/compiler-cli/test/ngtsc/sourcemap_utils.ts @@ -85,7 +85,7 @@ export function getMappedSegments( while (currentMapping) { const nextMapping = mappings.shift(); if (nextMapping) { - const source = sources.get(currentMapping.source) !; + const source = sources.get(currentMapping.source)!; const segment = { generated: generated.getSegment('generated', currentMapping, nextMapping), source: source.getSegment('original', currentMapping, nextMapping), diff --git a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts index 5c51defba1735..aed02b33a4098 100644 --- a/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_mapping_spec.ts @@ -14,13 +14,13 @@ import {tsSourceMapBug29300Fixed} from '../../src/ngtsc/util/src/ts_source_map_b import {loadStandardTestFiles} from '../helpers/src/mock_file_loading'; import {NgtscTestEnvironment} from './env'; -import {SegmentMapping, getMappedSegments} from './sourcemap_utils'; +import {getMappedSegments, SegmentMapping} from './sourcemap_utils'; const testFiles = loadStandardTestFiles(); runInEachFileSystem((os) => { describe('template source-mapping', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); @@ -323,7 +323,6 @@ runInEachFileSystem((os) => { expect(mappings).toContain( {source: '</div>', generated: 'i0.ɵɵelementEnd()', sourceUrl: '../test.ts'}); - }); it('should map ng-template [ngFor] scenario', () => { @@ -518,7 +517,7 @@ runInEachFileSystem((os) => { }); } - function compileAndMap(template: string, templateUrl: string | null = null) { + function compileAndMap(template: string, templateUrl: string|null = null) { const templateConfig = templateUrl ? `templateUrl: '${templateUrl}'` : ('template: `' + template.replace(/`/g, '\\`') + '`'); env.tsconfig({sourceMap: true}); diff --git a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts index 4d3aaafd78fb2..e77209c7e03ae 100644 --- a/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts +++ b/packages/compiler-cli/test/ngtsc/template_typecheck_spec.ts @@ -19,7 +19,7 @@ const testFiles = loadStandardTestFiles(); runInEachFileSystem(() => { describe('ngtsc type checking', () => { - let env !: NgtscTestEnvironment; + let env!: NgtscTestEnvironment; beforeEach(() => { env = NgtscTestEnvironment.setup(testFiles); @@ -1502,8 +1502,9 @@ export declare class AnimationEvent { }); describe('legacy schema checking with the DOM schema', () => { - beforeEach( - () => { env.tsconfig({ivyTemplateTypeCheck: true, fullTemplateTypeCheck: false}); }); + beforeEach(() => { + env.tsconfig({ivyTemplateTypeCheck: true, fullTemplateTypeCheck: false}); + }); it('should check for unknown elements', () => { env.write('test.ts', ` @@ -1734,7 +1735,7 @@ export declare class AnimationEvent { } }); - it('should be correct for direct templates', async() => { + it('should be correct for direct templates', async () => { env.write('test.ts', ` import {Component, NgModule} from '@angular/core'; @@ -1750,11 +1751,11 @@ export declare class AnimationEvent { const diags = await driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/test.ts')); + expect(diags[0].file!.fileName).toBe(_('/test.ts')); expect(getSourceCodeForDiagnostic(diags[0])).toBe('user.does_not_exist'); }); - it('should be correct for indirect templates', async() => { + it('should be correct for indirect templates', async () => { env.write('test.ts', ` import {Component, NgModule} from '@angular/core'; @@ -1772,12 +1773,12 @@ export declare class AnimationEvent { const diags = await driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/test.ts') + ' (TestCmp template)'); + expect(diags[0].file!.fileName).toBe(_('/test.ts') + ' (TestCmp template)'); expect(getSourceCodeForDiagnostic(diags[0])).toBe('user.does_not_exist'); - expect(getSourceCodeForDiagnostic(diags[0].relatedInformation ![0])).toBe('TEMPLATE'); + expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])).toBe('TEMPLATE'); }); - it('should be correct for external templates', async() => { + it('should be correct for external templates', async () => { env.write('template.html', `<p> {{user.does_not_exist}} </p>`); @@ -1795,9 +1796,9 @@ export declare class AnimationEvent { const diags = await driveDiagnostics(); expect(diags.length).toBe(1); - expect(diags[0].file !.fileName).toBe(_('/template.html')); + expect(diags[0].file!.fileName).toBe(_('/template.html')); expect(getSourceCodeForDiagnostic(diags[0])).toBe('user.does_not_exist'); - expect(getSourceCodeForDiagnostic(diags[0].relatedInformation ![0])) + expect(getSourceCodeForDiagnostic(diags[0].relatedInformation![0])) .toBe(`'./template.html'`); }); }); @@ -1841,6 +1842,6 @@ export declare class AnimationEvent { }); function getSourceCodeForDiagnostic(diag: ts.Diagnostic): string { - const text = diag.file !.text; - return text.substr(diag.start !, diag.length !); + const text = diag.file!.text; + return text.substr(diag.start!, diag.length!); } diff --git a/packages/compiler-cli/test/perform_compile_spec.ts b/packages/compiler-cli/test/perform_compile_spec.ts index 8696ab19550f4..d3e25172165fd 100644 --- a/packages/compiler-cli/test/perform_compile_spec.ts +++ b/packages/compiler-cli/test/perform_compile_spec.ts @@ -10,7 +10,7 @@ import * as path from 'path'; import {readConfiguration} from '../src/perform_compile'; -import {TestSupport, setup} from './test_support'; +import {setup, TestSupport} from './test_support'; describe('perform_compile', () => { let support: TestSupport; diff --git a/packages/compiler-cli/test/perform_watch_spec.ts b/packages/compiler-cli/test/perform_watch_spec.ts index 1ce31d7ac6d84..6cc620ca773b6 100644 --- a/packages/compiler-cli/test/perform_watch_spec.ts +++ b/packages/compiler-cli/test/perform_watch_spec.ts @@ -14,7 +14,7 @@ import * as ts from 'typescript'; import * as ng from '../index'; import {FileChangeEvent, performWatchCompilation} from '../src/perform_watch'; -import {TestSupport, expectNoDiagnostics, setup} from './test_support'; +import {expectNoDiagnostics, setup, TestSupport} from './test_support'; describe('perform watch', () => { let testSupport: TestSupport; @@ -105,23 +105,23 @@ describe('perform watch', () => { performWatchCompilation(host); expect(fs.existsSync(mainNgFactory)).toBe(true); - expect(fileExistsSpy !).toHaveBeenCalledWith(mainTsPath); - expect(fileExistsSpy !).toHaveBeenCalledWith(utilTsPath); - expect(getSourceFileSpy !).toHaveBeenCalledWith(mainTsPath, ts.ScriptTarget.ES5); - expect(getSourceFileSpy !).toHaveBeenCalledWith(utilTsPath, ts.ScriptTarget.ES5); + expect(fileExistsSpy!).toHaveBeenCalledWith(mainTsPath); + expect(fileExistsSpy!).toHaveBeenCalledWith(utilTsPath); + expect(getSourceFileSpy!).toHaveBeenCalledWith(mainTsPath, ts.ScriptTarget.ES5); + expect(getSourceFileSpy!).toHaveBeenCalledWith(utilTsPath, ts.ScriptTarget.ES5); - fileExistsSpy !.calls.reset(); - getSourceFileSpy !.calls.reset(); + fileExistsSpy!.calls.reset(); + getSourceFileSpy!.calls.reset(); // trigger a single file change // -> all other files should be cached host.triggerFileChange(FileChangeEvent.Change, utilTsPath); expectNoDiagnostics(config.options, host.diagnostics); - expect(fileExistsSpy !).not.toHaveBeenCalledWith(mainTsPath); - expect(fileExistsSpy !).toHaveBeenCalledWith(utilTsPath); - expect(getSourceFileSpy !).not.toHaveBeenCalledWith(mainTsPath, ts.ScriptTarget.ES5); - expect(getSourceFileSpy !).toHaveBeenCalledWith(utilTsPath, ts.ScriptTarget.ES5); + expect(fileExistsSpy!).not.toHaveBeenCalledWith(mainTsPath); + expect(fileExistsSpy!).toHaveBeenCalledWith(utilTsPath); + expect(getSourceFileSpy!).not.toHaveBeenCalledWith(mainTsPath, ts.ScriptTarget.ES5); + expect(getSourceFileSpy!).toHaveBeenCalledWith(utilTsPath, ts.ScriptTarget.ES5); // trigger a folder change // -> nothing should be cached @@ -129,10 +129,10 @@ describe('perform watch', () => { FileChangeEvent.CreateDeleteDir, path.resolve(testSupport.basePath, 'src')); expectNoDiagnostics(config.options, host.diagnostics); - expect(fileExistsSpy !).toHaveBeenCalledWith(mainTsPath); - expect(fileExistsSpy !).toHaveBeenCalledWith(utilTsPath); - expect(getSourceFileSpy !).toHaveBeenCalledWith(mainTsPath, ts.ScriptTarget.ES5); - expect(getSourceFileSpy !).toHaveBeenCalledWith(utilTsPath, ts.ScriptTarget.ES5); + expect(fileExistsSpy!).toHaveBeenCalledWith(mainTsPath); + expect(fileExistsSpy!).toHaveBeenCalledWith(utilTsPath); + expect(getSourceFileSpy!).toHaveBeenCalledWith(mainTsPath, ts.ScriptTarget.ES5); + expect(getSourceFileSpy!).toHaveBeenCalledWith(utilTsPath, ts.ScriptTarget.ES5); }); // https://github.com/angular/angular/pull/26036 @@ -239,10 +239,18 @@ class MockWatchHost { diagnostics: ng.Diagnostic[] = []; constructor(public config: ng.ParsedConfiguration) {} - reportDiagnostics(diags: ng.Diagnostics) { this.diagnostics.push(...(diags as ng.Diagnostic[])); } - readConfiguration() { return this.config; } - createCompilerHost(options: ng.CompilerOptions) { return ng.createCompilerHost({options}); } - createEmitCallback() { return undefined; } + reportDiagnostics(diags: ng.Diagnostics) { + this.diagnostics.push(...(diags as ng.Diagnostic[])); + } + readConfiguration() { + return this.config; + } + createCompilerHost(options: ng.CompilerOptions) { + return ng.createCompilerHost({options}); + } + createEmitCallback() { + return undefined; + } onFileChange( options: ng.CompilerOptions, listener: (event: FileChangeEvent, fileName: string) => void, ready: () => void) { @@ -258,7 +266,9 @@ class MockWatchHost { this.timeoutListeners[id] = callback; return id; } - clearTimeout(timeoutId: any): void { delete this.timeoutListeners[timeoutId]; } + clearTimeout(timeoutId: any): void { + delete this.timeoutListeners[timeoutId]; + } flushTimeouts() { const listeners = this.timeoutListeners; this.timeoutListeners = {}; diff --git a/packages/compiler-cli/test/test_support.ts b/packages/compiler-cli/test/test_support.ts index 84f07874afdfc..5d337d4def080 100644 --- a/packages/compiler-cli/test/test_support.ts +++ b/packages/compiler-cli/test/test_support.ts @@ -15,7 +15,7 @@ import {NodeJSFileSystem, setFileSystem} from '../src/ngtsc/file_system'; import {getAngularPackagesFromRunfiles, resolveNpmTreeArtifact} from '../test/helpers'; // TEST_TMPDIR is always set by Bazel. -const tmpdir = process.env.TEST_TMPDIR !; +const tmpdir = process.env.TEST_TMPDIR!; export function makeTempDir(): string { let dir: string; @@ -97,8 +97,11 @@ function createTestSupportFor(basePath: string) { } function writeFiles(...mockDirs: {[fileName: string]: string}[]) { - mockDirs.forEach( - (dir) => { Object.keys(dir).forEach((fileName) => { write(fileName, dir[fileName]); }); }); + mockDirs.forEach((dir) => { + Object.keys(dir).forEach((fileName) => { + write(fileName, dir[fileName]); + }); + }); } function createCompilerOptions(overrideOptions: ng.CompilerOptions = {}): ng.CompilerOptions { diff --git a/packages/compiler-cli/test/transformers/compiler_host_spec.ts b/packages/compiler-cli/test/transformers/compiler_host_spec.ts index 9a43783b541b4..123306c2cac35 100644 --- a/packages/compiler-cli/test/transformers/compiler_host_spec.ts +++ b/packages/compiler-cli/test/transformers/compiler_host_spec.ts @@ -11,7 +11,7 @@ import * as ts from 'typescript'; import {MetadataCollector} from '../../src/metadata/collector'; import {CompilerHost, CompilerOptions, LibrarySummary} from '../../src/transformers/api'; -import {TsCompilerAotCompilerTypeCheckHostAdapter, createCompilerHost} from '../../src/transformers/compiler_host'; +import {createCompilerHost, TsCompilerAotCompilerTypeCheckHostAdapter} from '../../src/transformers/compiler_host'; import {Directory, Entry, MockAotContext, MockCompilerHost} from '../mocks'; const dummyModule = 'export let foo: any[];'; @@ -53,12 +53,15 @@ describe('NgCompilerHost', () => { } = {}) { return new TsCompilerAotCompilerTypeCheckHostAdapter( rootNames, options, ngHost, new MetadataCollector(), codeGenerator, - new Map(librarySummaries.map(entry => [entry.fileName, entry] as[string, LibrarySummary]))); + new Map( + librarySummaries.map(entry => [entry.fileName, entry] as [string, LibrarySummary]))); } describe('fileNameToModuleName', () => { let host: TsCompilerAotCompilerTypeCheckHostAdapter; - beforeEach(() => { host = createHost(); }); + beforeEach(() => { + host = createHost(); + }); it('should use a package import when accessing a package from a source file', () => { expect(host.fileNameToModuleName('/tmp/node_modules/@angular/core.d.ts', '/tmp/main.ts')) @@ -239,9 +242,8 @@ describe('NgCompilerHost', () => { it('should not get tripped on nested node_modules', () => { const genSf = generate('/tmp/node_modules/lib1/node_modules/lib2/thing', { - 'tmp': { - 'node_modules': {'lib1': {'node_modules': {'lib2': {'thing.ts': `// some content`}}}} - } + 'tmp': + {'node_modules': {'lib1': {'node_modules': {'lib2': {'thing.ts': `// some content`}}}}} }); expect(genSf.moduleName).toBe('lib2/thing.ngfactory'); }); @@ -387,8 +389,9 @@ describe('NgCompilerHost', () => { () => host.updateGeneratedFile(new compiler.GeneratedFile( '/tmp/src/index.ts', '/tmp/src/index.ngfactory.ts', [new compiler.DeclareVarStmt( - 'x', new compiler.ExternalExpr( - new compiler.ExternalReference('otherModule', 'aName')))]))) + 'x', + new compiler.ExternalExpr( + new compiler.ExternalReference('otherModule', 'aName')))]))) .toThrowError([ `Illegal State: external references changed in /tmp/src/index.ngfactory.ts.`, `Old: aModule.`, `New: otherModule` diff --git a/packages/compiler-cli/test/transformers/inline_resources_spec.ts b/packages/compiler-cli/test/transformers/inline_resources_spec.ts index 290dbb4929bdf..3dbe49afea512 100644 --- a/packages/compiler-cli/test/transformers/inline_resources_spec.ts +++ b/packages/compiler-cli/test/transformers/inline_resources_spec.ts @@ -8,8 +8,8 @@ import * as ts from 'typescript'; -import {MetadataCollector, isClassMetadata} from '../../src/metadata/index'; -import {InlineResourcesMetadataTransformer, getInlineResourcesTransformFactory} from '../../src/transformers/inline_resources'; +import {isClassMetadata, MetadataCollector} from '../../src/metadata/index'; +import {getInlineResourcesTransformFactory, InlineResourcesMetadataTransformer} from '../../src/transformers/inline_resources'; import {MetadataCache} from '../../src/transformers/metadata_cache'; import {MockAotContext, MockCompilerHost} from '../mocks'; diff --git a/packages/compiler-cli/test/transformers/lower_expressions_spec.ts b/packages/compiler-cli/test/transformers/lower_expressions_spec.ts index da873f8f0b290..99b7e4572569d 100644 --- a/packages/compiler-cli/test/transformers/lower_expressions_spec.ts +++ b/packages/compiler-cli/test/transformers/lower_expressions_spec.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {MetadataCollector, ModuleMetadata} from '../../src/metadata/index'; -import {LowerMetadataTransform, LoweringRequest, RequestLocationMap, getExpressionLoweringTransformFactory} from '../../src/transformers/lower_expressions'; +import {getExpressionLoweringTransformFactory, LoweringRequest, LowerMetadataTransform, RequestLocationMap} from '../../src/transformers/lower_expressions'; import {MetadataCache} from '../../src/transformers/metadata_cache'; import {Directory, MockAotContext, MockCompilerHost} from '../mocks'; @@ -196,14 +196,16 @@ function convert(annotatedSource: string) { const program = ts.createProgram( [fileName], {module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2017}, host); - const moduleSourceFile = program.getSourceFile(fileName) !; + const moduleSourceFile = program.getSourceFile(fileName)!; const transformers: ts.CustomTransformers = { before: [getExpressionLoweringTransformFactory( { - getRequests(sourceFile: ts.SourceFile): RequestLocationMap{ + getRequests(sourceFile: ts.SourceFile): RequestLocationMap { if (sourceFile.fileName == moduleSourceFile.fileName) { return requests; - } else {return new Map();} + } else { + return new Map(); + } } }, program)] @@ -254,6 +256,7 @@ function collect(annotatedSource: string) { 'someName.ts', unannotatedSource, ts.ScriptTarget.Latest, /* setParentNodes */ true); return { metadata: cache.getMetadata(sourceFile), - requests: transformer.getRequests(sourceFile), annotations + requests: transformer.getRequests(sourceFile), + annotations }; } \ No newline at end of file diff --git a/packages/compiler-cli/test/transformers/metadata_reader_spec.ts b/packages/compiler-cli/test/transformers/metadata_reader_spec.ts index 306c215483d55..13437c54ecd1e 100644 --- a/packages/compiler-cli/test/transformers/metadata_reader_spec.ts +++ b/packages/compiler-cli/test/transformers/metadata_reader_spec.ts @@ -23,10 +23,9 @@ describe('metadata reader', () => { readFile: (fileName) => context.readFile(fileName), getSourceFileMetadata: (fileName) => { const sourceText = context.readFile(fileName); - return sourceText != null ? - metadataCollector.getMetadata( - ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest)) : - undefined; + return sourceText != null ? metadataCollector.getMetadata(ts.createSourceFile( + fileName, sourceText, ts.ScriptTarget.Latest)) : + undefined; }, }; }); @@ -42,11 +41,13 @@ describe('metadata reader', () => { expect(readMetadata('node_modules/@angular/unused.d.ts', host)).toEqual([dummyMetadata]); }); - it('should be able to read empty metadata ', - () => { expect(readMetadata('node_modules/@angular/empty.d.ts', host)).toEqual([]); }); + it('should be able to read empty metadata ', () => { + expect(readMetadata('node_modules/@angular/empty.d.ts', host)).toEqual([]); + }); - it('should return undefined for missing modules', - () => { expect(readMetadata('node_modules/@angular/missing.d.ts', host)).toBeUndefined(); }); + it('should return undefined for missing modules', () => { + expect(readMetadata('node_modules/@angular/missing.d.ts', host)).toBeUndefined(); + }); it(`should add missing v${METADATA_VERSION} metadata from v1 metadata and .d.ts files`, () => { expect(readMetadata('metadata_versions/v1.d.ts', host)).toEqual([ @@ -117,8 +118,8 @@ const FILES: Entry = { 'node_modules': { '@angular': { 'core.d.ts': dummyModule, - 'core.metadata.json': - `{"__symbolic":"module", "version": ${METADATA_VERSION}, "metadata": {"foo": {"__symbolic": "class"}}}`, + 'core.metadata.json': `{"__symbolic":"module", "version": ${ + METADATA_VERSION}, "metadata": {"foo": {"__symbolic": "class"}}}`, 'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}}, 'unused.d.ts': dummyModule, 'empty.d.ts': 'export declare var a: string;', diff --git a/packages/compiler-cli/test/transformers/node_emitter_spec.ts b/packages/compiler-cli/test/transformers/node_emitter_spec.ts index c5e3ce09cb6b3..0b53d4b380c22 100644 --- a/packages/compiler-cli/test/transformers/node_emitter_spec.ts +++ b/packages/compiler-cli/test/transformers/node_emitter_spec.ts @@ -38,7 +38,7 @@ describe('TypeScriptNodeEmitter', () => { }); function emitStmt( - stmt: o.Statement | o.Statement[], format: Format = Format.Flat, preamble?: string): string { + stmt: o.Statement|o.Statement[], format: Format = Format.Flat, preamble?: string): string { const stmts = Array.isArray(stmt) ? stmt : [stmt]; const program = ts.createProgram( @@ -246,8 +246,8 @@ describe('TypeScriptNodeEmitter', () => { expect(emitStmt(new o.DeclareFunctionStmt( 'someFn', [], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE))) .toEqual(`function someFn() { return 1; }`); - expect(emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1', o.INT_TYPE)], [ - ]))).toEqual(`function someFn(param1) { }`); + expect(emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1', o.INT_TYPE)], []))) + .toEqual(`function someFn(param1) { }`); }); describe('comments', () => { @@ -256,8 +256,9 @@ describe('TypeScriptNodeEmitter', () => { .toBe('/* SomePreamble */ a;'); }); - it('should support singleline comments', - () => { expect(emitStmt(new o.CommentStmt('Simple comment'))).toBe('// Simple comment'); }); + it('should support singleline comments', () => { + expect(emitStmt(new o.CommentStmt('Simple comment'))).toBe('// Simple comment'); + }); it('should support multiline comments', () => { expect(emitStmt(new o.CommentStmt('Multiline comment', true))) @@ -314,86 +315,90 @@ describe('TypeScriptNodeEmitter', () => { `try { body(); } catch (error) { var stack = error.stack; catchFn(error, stack); }`); }); - it('should support support throwing', - () => { expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); }); + it('should support support throwing', () => { + expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); + }); describe('classes', () => { let callSomeMethod: o.Statement; - beforeEach(() => { callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); }); + beforeEach(() => { + callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); + }); it('should support declaring classes', () => { - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ - ]))).toEqual('class SomeClass { }'); - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [], [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, []))) + .toEqual('class SomeClass { }'); + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [], [ o.StmtModifier.Exported ]))).toEqual('class SomeClass { } exports.SomeClass = SomeClass;'); - expect(emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, [ - ]))).toEqual('class SomeClass extends SomeSuperClass { }'); + expect( + emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null!, []))) + .toEqual('class SomeClass extends SomeSuperClass { }'); }); it('should support declaring constructors', () => { const superCall = o.SUPER_EXPR.callFn([o.variable('someParam')]).toStmt(); - expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], []), []))) + expect(emitStmt( + new o.ClassStmt('SomeClass', null!, [], [], new o.ClassMethod(null!, [], []), []))) .toEqual(`class SomeClass { constructor() { } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], - new o.ClassMethod(null !, [new o.FnParam('someParam', o.INT_TYPE)], []), []))) + 'SomeClass', null!, [], [], + new o.ClassMethod(null!, [new o.FnParam('someParam', o.INT_TYPE)], []), []))) .toEqual(`class SomeClass { constructor(someParam) { } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [superCall]), []))) + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], [superCall]), []))) .toEqual(`class SomeClass { constructor() { super(someParam); } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [callSomeMethod]), []))) + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], [callSomeMethod]), []))) .toEqual(`class SomeClass { constructor() { this.someMethod(); } }`); }); it('should support declaring fields', () => { expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [new o.ClassField('someField')], [], null !, []))) + 'SomeClass', null!, [new o.ClassField('someField')], [], null!, []))) .toEqual(`class SomeClass { constructor() { this.someField = null; } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [new o.ClassField('someField', o.INT_TYPE)], [], null !, []))) + 'SomeClass', null!, [new o.ClassField('someField', o.INT_TYPE)], [], null!, []))) .toEqual(`class SomeClass { constructor() { this.someField = null; } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, - [new o.ClassField('someField', o.INT_TYPE, [o.StmtModifier.Private])], [], null !, + 'SomeClass', null!, + [new o.ClassField('someField', o.INT_TYPE, [o.StmtModifier.Private])], [], null!, []))) .toEqual(`class SomeClass { constructor() { this.someField = null; } }`); }); it('should support declaring getters', () => { expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [])], null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [])], null!, []))) .toEqual(`class SomeClass { get someGetter() { } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [], o.INT_TYPE)], null !, + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [], o.INT_TYPE)], null!, []))) .toEqual(`class SomeClass { get someGetter() { } }`); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [callSomeMethod])], - null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [callSomeMethod])], null!, + []))) .toEqual(`class SomeClass { get someGetter() { this.someMethod(); } }`); expect( emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], - [new o.ClassGetter('someGetter', [], null !, [o.StmtModifier.Private])], null !, []))) + 'SomeClass', null!, [], + [new o.ClassGetter('someGetter', [], null!, [o.StmtModifier.Private])], null!, []))) .toEqual(`class SomeClass { get someGetter() { } }`); }); it('should support methods', () => { - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [ new o.ClassMethod('someMethod', [], []) ]))).toEqual(`class SomeClass { someMethod() { } }`); - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [ new o.ClassMethod('someMethod', [], [], o.INT_TYPE) ]))).toEqual(`class SomeClass { someMethod() { } }`); - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [ new o.ClassMethod('someMethod', [new o.FnParam('someParam', o.INT_TYPE)], []) ]))).toEqual(`class SomeClass { someMethod(someParam) { } }`); - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [ new o.ClassMethod('someMethod', [], [callSomeMethod]) ]))).toEqual(`class SomeClass { someMethod() { this.someMethod(); } }`); }); @@ -431,7 +436,7 @@ describe('TypeScriptNodeEmitter', () => { it('should support combined types', () => { const writeVarExpr = o.variable('a').set(o.NULL_EXPR); - expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(null !)))).toEqual('var a = null;'); + expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(null!)))).toEqual('var a = null;'); expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(o.INT_TYPE)))).toEqual('var a = null;'); expect(emitStmt(writeVarExpr.toDeclStmt(new o.MapType(null)))).toEqual('var a = null;'); @@ -439,7 +444,7 @@ describe('TypeScriptNodeEmitter', () => { }); describe('source maps', () => { - function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string { + function emitStmt(stmt: o.Statement|o.Statement[], preamble?: string): string { const stmts = Array.isArray(stmt) ? stmt : [stmt]; const program = ts.createProgram( @@ -473,13 +478,15 @@ describe('TypeScriptNodeEmitter', () => { function mappingItemsOf(text: string) { // find the source map: const sourceMapMatch = /sourceMappingURL\=data\:application\/json;base64,(.*)$/.exec(text); - const sourceMapBase64 = sourceMapMatch ![1]; + const sourceMapBase64 = sourceMapMatch![1]; const sourceMapBuffer = Buffer.from(sourceMapBase64, 'base64'); const sourceMapText = sourceMapBuffer.toString('utf8'); const sourceMapParsed = JSON.parse(sourceMapText); const consumer = new sourceMap.SourceMapConsumer(sourceMapParsed); const mappings: any[] = []; - consumer.eachMapping((mapping: any) => { mappings.push(mapping); }); + consumer.eachMapping((mapping: any) => { + mappings.push(mapping); + }); return mappings; } @@ -503,7 +510,7 @@ describe('TypeScriptNodeEmitter', () => { generatedColumn: 0, originalLine: 1, originalColumn: 0, - name: null ! // TODO: Review use of `!` here (#19904) + name: null! // TODO: Review use of `!` here (#19904) }, { source: sourceUrl, @@ -511,7 +518,7 @@ describe('TypeScriptNodeEmitter', () => { generatedColumn: 16, originalLine: 1, originalColumn: 26, - name: null ! // TODO: Review use of `!` here (#19904) + name: null! // TODO: Review use of `!` here (#19904) } ]); }); @@ -558,7 +565,10 @@ const FILES: Directory = { somePackage: {'someGenFile.ts': `export var a: number;`} }; -const enum Format { Raw, Flat } +const enum Format { + Raw, + Flat +} function normalizeResult(result: string, format: Format): string { // Remove TypeScript prefixes diff --git a/packages/compiler-cli/test/transformers/program_spec.ts b/packages/compiler-cli/test/transformers/program_spec.ts index a7013540050b1..8f3dc5ccdd34a 100644 --- a/packages/compiler-cli/test/transformers/program_spec.ts +++ b/packages/compiler-cli/test/transformers/program_spec.ts @@ -10,11 +10,12 @@ import * as ng from '@angular/compiler-cli'; import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; + import {formatDiagnostics} from '../../src/perform_compile'; import {CompilerHost, EmitFlags, LazyRoute} from '../../src/transformers/api'; import {createSrcToOutPathMapper} from '../../src/transformers/program'; import {StructureIsReused, tsStructureIsReused} from '../../src/transformers/util'; -import {TestSupport, expectNoDiagnosticsInProgram, setup, stripAnsi} from '../test_support'; +import {expectNoDiagnosticsInProgram, setup, stripAnsi, TestSupport} from '../test_support'; describe('ng program', () => { let testSupport: TestSupport; @@ -83,21 +84,21 @@ describe('ng program', () => { const originalGetSourceFile = host.getSourceFile; const cache = new Map<string, ts.SourceFile>(); - host.getSourceFile = function( - fileName: string, languageVersion: ts.ScriptTarget): ts.SourceFile | - undefined { - const sf = originalGetSourceFile.call(host, fileName, languageVersion); - if (sf) { - if (cache.has(sf.fileName)) { - const oldSf = cache.get(sf.fileName) !; - if (oldSf.getFullText() === sf.getFullText()) { - return oldSf; - } - } - cache.set(sf.fileName, sf); - } - return sf; - }; + host.getSourceFile = function(fileName: string, languageVersion: ts.ScriptTarget): + ts.SourceFile| + undefined { + const sf = originalGetSourceFile.call(host, fileName, languageVersion); + if (sf) { + if (cache.has(sf.fileName)) { + const oldSf = cache.get(sf.fileName)!; + if (oldSf.getFullText() === sf.getFullText()) { + return oldSf; + } + } + cache.set(sf.fileName, sf); + } + return sf; + }; return host; } @@ -248,7 +249,8 @@ describe('ng program', () => { fileCache.delete(path.posix.join(testSupport.basePath, 'src/index.ts')); const p6 = ng.createProgram({ rootNames: [path.posix.join(testSupport.basePath, 'src/index.ts')], - options: testSupport.createCompilerOptions(options), host, + options: testSupport.createCompilerOptions(options), + host, oldProgram: p5 }); const p7 = compile(p6, options, undefined, host).program; @@ -295,7 +297,6 @@ describe('ng program', () => { describe( 'verify that program structure is reused within tsc in order to speed up incremental compilation', () => { - it('should reuse the old ts program completely if nothing changed', () => { testSupport.writeFiles({'src/index.ts': createModuleAndCompSource('main')}); const host = createWatchModeHost(); @@ -351,7 +352,6 @@ describe('ng program', () => { expect(tsStructureIsReused(p2.getTsProgram())).toBe(StructureIsReused.SafeModules); }); }); - }); it('should not typecheck templates if skipTemplateCodegen is set but fullTemplateTypeCheck is not', @@ -473,7 +473,7 @@ describe('ng program', () => { host.writeFile = (fileName: string, data: string, writeByteOrderMark: boolean, - onError: ((message: string) => void) | undefined, + onError: ((message: string) => void)|undefined, sourceFiles?: ReadonlyArray<ts.SourceFile>) => { written.set(fileName, {original: sourceFiles, data}); }; @@ -487,19 +487,19 @@ describe('ng program', () => { const writeData = written.get(path.posix.join(testSupport.basePath, fileName)); expect(writeData).toBeTruthy(); expect( - writeData !.original !.some( + writeData!.original!.some( sf => sf.fileName === path.posix.join(testSupport.basePath, checks.originalFileName))) .toBe(true); switch (checks.shouldBe) { case ShouldBe.Empty: - expect(writeData !.data).toMatch(/^(\s*\/\*([^*]|\*[^/])*\*\/\s*)?$/); + expect(writeData!.data).toMatch(/^(\s*\/\*([^*]|\*[^/])*\*\/\s*)?$/); break; case ShouldBe.EmptyExport: - expect(writeData !.data) + expect(writeData!.data) .toMatch(/^((\s*\/\*([^*]|\*[^/])*\*\/\s*)|(\s*export\s*{\s*}\s*;\s*)|())$/); break; case ShouldBe.NoneEmpty: - expect(writeData !.data).not.toBe(''); + expect(writeData!.data).not.toBe(''); break; } } @@ -1099,15 +1099,15 @@ describe('ng program', () => { }); const host = ng.createCompilerHost({options}); const originalGetSourceFile = host.getSourceFile; - host.getSourceFile = (fileName: string, languageVersion: ts.ScriptTarget, - onError?: ((message: string) => void) | undefined): ts.SourceFile | - undefined => { - // We should never try to load .ngfactory.ts files - if (fileName.match(/\.ngfactory\.ts$/)) { - throw new Error(`Non existent ngfactory file: ` + fileName); - } - return originalGetSourceFile.call(host, fileName, languageVersion, onError); - }; + host.getSourceFile = + (fileName: string, languageVersion: ts.ScriptTarget, + onError?: ((message: string) => void)|undefined): ts.SourceFile|undefined => { + // We should never try to load .ngfactory.ts files + if (fileName.match(/\.ngfactory\.ts$/)) { + throw new Error(`Non existent ngfactory file: ` + fileName); + } + return originalGetSourceFile.call(host, fileName, languageVersion, onError); + }; const program = ng.createProgram({rootNames: allRootNames, options, host}); const structuralErrors = program.getNgStructuralDiagnostics(); expect(structuralErrors.length).toBe(1); @@ -1115,5 +1115,4 @@ describe('ng program', () => { .toContain('Function expressions are not supported'); }); }); - }); diff --git a/packages/compiler-cli/test/transformers/r3_metadata_transform_spec.ts b/packages/compiler-cli/test/transformers/r3_metadata_transform_spec.ts index 47b1d23dfb23b..7ab230c0e615a 100644 --- a/packages/compiler-cli/test/transformers/r3_metadata_transform_spec.ts +++ b/packages/compiler-cli/test/transformers/r3_metadata_transform_spec.ts @@ -9,12 +9,11 @@ import {ClassField, ClassMethod, ClassStmt, PartialModule, Statement, StmtModifier} from '@angular/compiler'; import * as ts from 'typescript'; -import {MetadataCollector, isClassMetadata} from '../../src/metadata/index'; +import {isClassMetadata, MetadataCollector} from '../../src/metadata/index'; import {MetadataCache} from '../../src/transformers/metadata_cache'; import {PartialModuleMetadataTransformer} from '../../src/transformers/r3_metadata_transform'; describe('r3_transform_spec', () => { - it('should add a static method to collected metadata', () => { const fileName = '/some/directory/someFileName.ts'; const className = 'SomeClass'; diff --git a/packages/compiler-cli/test/transformers/r3_transform_spec.ts b/packages/compiler-cli/test/transformers/r3_transform_spec.ts index 5b893cf6dee69..adf93e26b68ca 100644 --- a/packages/compiler-cli/test/transformers/r3_transform_spec.ts +++ b/packages/compiler-cli/test/transformers/r3_transform_spec.ts @@ -30,8 +30,9 @@ describe('r3_transform_spec', () => { .toContain('static someMethod(v) { return v; }'); }); - it('should be able to generate a static field declaration', - () => { expect(emitStaticField(o.literal(10))).toContain('SomeClass.someField = 10'); }); + it('should be able to generate a static field declaration', () => { + expect(emitStaticField(o.literal(10))).toContain('SomeClass.someField = 10'); + }); it('should be able to import a symbol', () => { expect(emitStaticMethod(new o.ReturnStatement( @@ -90,8 +91,8 @@ describe('r3_transform_spec', () => { } function emitStaticMethod( - stmt: o.Statement | o.Statement[], parameters: string[] = [], - methodName: string = 'someMethod', className: string = 'SomeClass'): string { + stmt: o.Statement|o.Statement[], parameters: string[] = [], methodName: string = 'someMethod', + className: string = 'SomeClass'): string { const module: PartialModule = { fileName: someGenFileName, statements: [classMethod(stmt, parameters, methodName, className)] @@ -122,7 +123,7 @@ const FILES: Directory = { }; function classMethod( - stmt: o.Statement | o.Statement[], parameters: string[] = [], methodName: string = 'someMethod', + stmt: o.Statement|o.Statement[], parameters: string[] = [], methodName: string = 'someMethod', className: string = 'SomeClass'): o.ClassStmt { const statements = Array.isArray(stmt) ? stmt : [stmt]; return new o.ClassStmt( diff --git a/packages/compiler-cli/test/typescript_support_spec.ts b/packages/compiler-cli/test/typescript_support_spec.ts index 6a6c03c34ad04..0995ac5238f9c 100644 --- a/packages/compiler-cli/test/typescript_support_spec.ts +++ b/packages/compiler-cli/test/typescript_support_spec.ts @@ -11,8 +11,8 @@ describe('checkVersion', () => { const MIN_TS_VERSION = '2.7.2'; const MAX_TS_VERSION = '2.8.0'; - const versionError = (version: string) => - `The Angular Compiler requires TypeScript >=${MIN_TS_VERSION} and <${MAX_TS_VERSION} but ${version} was found instead.`; + const versionError = (version: string) => `The Angular Compiler requires TypeScript >=${ + MIN_TS_VERSION} and <${MAX_TS_VERSION} but ${version} was found instead.`; it('should not throw when a supported TypeScript version is used', () => { expect(() => checkVersion('2.7.2', MIN_TS_VERSION, MAX_TS_VERSION)).not.toThrow(); From 83a9159063dc9d93c51f462eb28db3f3ad83e87b Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh <alx+alxhub@alxandria.net> Date: Wed, 8 Apr 2020 10:14:18 -0700 Subject: [PATCH 161/262] style(compiler): reformat of codebase with new clang-format version (#36520) This commit reformats the packages/compiler tree using the new version of clang-format. PR Close #36520 --- packages/compiler/src/aot/compiler.ts | 106 +- packages/compiler/src/aot/compiler_factory.ts | 6 +- packages/compiler/src/aot/formatted_error.ts | 6 +- packages/compiler/src/aot/generated_file.ts | 4 +- packages/compiler/src/aot/lazy_routes.ts | 2 +- packages/compiler/src/aot/static_reflector.ts | 62 +- packages/compiler/src/aot/static_symbol.ts | 2 +- .../src/aot/static_symbol_resolver.ts | 35 +- packages/compiler/src/aot/summary_resolver.ts | 12 +- .../compiler/src/aot/summary_serializer.ts | 45 +- packages/compiler/src/ast_path.ts | 26 +- packages/compiler/src/compile_metadata.ts | 140 +- .../compiler/src/compiler_facade_interface.ts | 14 +- .../src/compiler_util/expression_converter.ts | 214 +- packages/compiler/src/config.ts | 27 +- packages/compiler/src/constant_pool.ts | 31 +- packages/compiler/src/core.ts | 57 +- packages/compiler/src/css_parser/css_ast.ts | 32 +- packages/compiler/src/css_parser/css_lexer.ts | 19 +- .../compiler/src/css_parser/css_parser.ts | 65 +- packages/compiler/src/directive_normalizer.ts | 71 +- packages/compiler/src/directive_resolver.ts | 9 +- .../compiler/src/expression_parser/ast.ts | 68 +- .../compiler/src/expression_parser/lexer.ts | 48 +- .../compiler/src/expression_parser/parser.ts | 57 +- packages/compiler/src/i18n/digest.ts | 7 +- packages/compiler/src/i18n/extractor.ts | 4 +- .../compiler/src/i18n/extractor_merger.ts | 53 +- packages/compiler/src/i18n/i18n_ast.ts | 36 +- packages/compiler/src/i18n/i18n_parser.ts | 6 +- packages/compiler/src/i18n/message_bundle.ts | 12 +- packages/compiler/src/i18n/parse_util.ts | 4 +- .../src/i18n/serializers/placeholder.ts | 4 +- .../src/i18n/serializers/serializer.ts | 14 +- .../compiler/src/i18n/serializers/xliff.ts | 46 +- .../compiler/src/i18n/serializers/xliff2.ts | 34 +- packages/compiler/src/i18n/serializers/xmb.ts | 16 +- .../src/i18n/serializers/xml_helper.ts | 32 +- packages/compiler/src/i18n/serializers/xtb.ts | 40 +- .../compiler/src/i18n/translation_bundle.ts | 16 +- packages/compiler/src/injectable_compiler.ts | 2 +- .../compiler/src/injectable_compiler_2.ts | 4 +- packages/compiler/src/jit/compiler.ts | 39 +- packages/compiler/src/jit_compiler_facade.ts | 26 +- packages/compiler/src/metadata_resolver.ts | 135 +- packages/compiler/src/ml_parser/ast.ts | 32 +- .../compiler/src/ml_parser/html_parser.ts | 6 +- packages/compiler/src/ml_parser/html_tags.ts | 29 +- .../src/ml_parser/html_whitespaces.ts | 12 +- .../src/ml_parser/icu_ast_expander.ts | 18 +- packages/compiler/src/ml_parser/lexer.ts | 36 +- packages/compiler/src/ml_parser/parser.ts | 14 +- packages/compiler/src/ml_parser/tags.ts | 4 +- packages/compiler/src/ml_parser/xml_parser.ts | 6 +- packages/compiler/src/ml_parser/xml_tags.ts | 14 +- packages/compiler/src/ng_module_compiler.ts | 6 +- packages/compiler/src/ng_module_resolver.ts | 6 +- .../compiler/src/output/abstract_emitter.ts | 46 +- .../src/output/abstract_js_emitter.ts | 6 +- packages/compiler/src/output/js_emitter.ts | 2 +- packages/compiler/src/output/output_ast.ts | 252 +- .../compiler/src/output/output_interpreter.ts | 40 +- packages/compiler/src/output/output_jit.ts | 8 +- packages/compiler/src/output/source_map.ts | 32 +- packages/compiler/src/output/ts_emitter.ts | 11 +- packages/compiler/src/output/value_util.ts | 6 +- packages/compiler/src/pipe_resolver.ts | 2 +- packages/compiler/src/provider_analyzer.ts | 46 +- packages/compiler/src/render3/r3_ast.ts | 82 +- packages/compiler/src/render3/r3_factory.ts | 10 +- packages/compiler/src/render3/r3_jit.ts | 40 +- .../src/render3/r3_module_compiler.ts | 17 +- .../compiler/src/render3/r3_pipe_compiler.ts | 4 +- .../src/render3/r3_template_transform.ts | 32 +- packages/compiler/src/render3/util.ts | 5 +- packages/compiler/src/render3/view/api.ts | 2 +- .../compiler/src/render3/view/compiler.ts | 45 +- .../compiler/src/render3/view/i18n/context.ts | 20 +- .../src/render3/view/i18n/get_msg_utils.ts | 19 +- .../src/render3/view/i18n/icu_serializer.ts | 11 +- .../src/render3/view/i18n/localize_utils.ts | 4 +- .../compiler/src/render3/view/i18n/meta.ts | 20 +- .../compiler/src/render3/view/i18n/util.ts | 6 +- .../compiler/src/render3/view/style_parser.ts | 10 +- .../src/render3/view/styling_builder.ts | 7 +- packages/compiler/src/render3/view/t2_api.ts | 10 +- .../compiler/src/render3/view/t2_binder.ts | 36 +- .../compiler/src/render3/view/template.ts | 176 +- packages/compiler/src/render3/view/util.ts | 24 +- packages/compiler/src/resource_loader.ts | 4 +- .../src/schema/dom_element_schema_registry.ts | 18 +- .../src/schema/dom_security_schema.ts | 2 +- packages/compiler/src/selector.ts | 24 +- packages/compiler/src/shadow_css.ts | 37 +- packages/compiler/src/style_compiler.ts | 4 +- packages/compiler/src/summary_resolver.ts | 28 +- .../src/template_parser/binding_parser.ts | 47 +- .../src/template_parser/template_ast.ts | 16 +- .../src/template_parser/template_parser.ts | 153 +- .../src/template_parser/template_preparser.ts | 6 +- packages/compiler/src/url_resolver.ts | 22 +- packages/compiler/src/util.ts | 24 +- .../src/view_compiler/provider_compiler.ts | 11 +- .../src/view_compiler/type_check_compiler.ts | 18 +- .../src/view_compiler/view_compiler.ts | 81 +- packages/compiler/test/aot/compiler_spec.ts | 43 +- .../compiler/test/aot/jit_summaries_spec.ts | 38 +- packages/compiler/test/aot/regression_spec.ts | 2 +- .../test/aot/static_reflector_spec.ts | 21 +- .../test/aot/static_symbol_resolver_spec.ts | 71 +- .../test/aot/summary_resolver_spec.ts | 16 +- .../test/aot/summary_serializer_spec.ts | 11 +- packages/compiler/test/aot/test_util.ts | 134 +- .../test/compiler_facade_interface_spec.ts | 84 +- packages/compiler/test/config_spec.ts | 4 +- packages/compiler/test/core_spec.ts | 4 +- .../test/css_parser/css_lexer_spec.ts | 593 +-- .../test/css_parser/css_parser_spec.ts | 10 +- .../test/css_parser/css_visitor_spec.ts | 299 +- .../compiler/test/directive_lifecycle_spec.ts | 33 +- .../test/directive_normalizer_spec.ts | 18 +- .../test/directive_resolver_mock_spec.ts | 2 +- .../compiler/test/directive_resolver_spec.ts | 104 +- .../test/expression_parser/lexer_spec.ts | 34 +- .../test/expression_parser/parser_spec.ts | 169 +- .../test/expression_parser/utils/unparser.ts | 12 +- .../test/expression_parser/utils/validator.ts | 6 +- packages/compiler/test/i18n/digest_spec.ts | 26 +- .../test/i18n/extractor_merger_spec.ts | 29 +- .../test/i18n/i18n_html_parser_spec.ts | 1 - .../compiler/test/i18n/i18n_parser_spec.ts | 18 +- .../compiler/test/i18n/integration_common.ts | 6 +- .../test/i18n/integration_xliff2_spec.ts | 3 +- .../test/i18n/integration_xliff_spec.ts | 3 +- .../test/i18n/integration_xmb_xtb_spec.ts | 3 +- .../compiler/test/i18n/message_bundle_spec.ts | 10 +- .../test/i18n/serializers/i18n_ast_spec.ts | 24 +- .../test/i18n/serializers/placeholder_spec.ts | 5 +- .../test/i18n/serializers/xliff2_spec.ts | 166 +- .../test/i18n/serializers/xliff_spec.ts | 167 +- .../test/i18n/serializers/xmb_spec.ts | 2 +- .../test/i18n/serializers/xml_helper_spec.ts | 11 +- .../test/i18n/serializers/xtb_spec.ts | 22 +- .../test/i18n/translation_bundle_spec.ts | 42 +- packages/compiler/test/integration_spec.ts | 4 +- .../compiler/test/metadata_resolver_spec.ts | 51 +- .../test/ml_parser/ast_serializer_spec.ts | 4 +- .../compiler/test/ml_parser/ast_spec_utils.ts | 2 +- .../test/ml_parser/html_parser_spec.ts | 63 +- .../test/ml_parser/html_whitespaces_spec.ts | 1 - .../test/ml_parser/icu_ast_expander_spec.ts | 22 +- .../compiler/test/ml_parser/lexer_spec.ts | 5 +- packages/compiler/test/ml_parser/util/util.ts | 11 +- .../compiler/test/ng_module_resolver_spec.ts | 5 +- .../output/abstract_emitter_node_only_spec.ts | 16 +- .../test/output/abstract_emitter_spec.ts | 38 +- .../test/output/js_emitter_node_only_spec.ts | 8 +- .../compiler/test/output/js_emitter_spec.ts | 55 +- .../compiler/test/output/output_ast_spec.ts | 4 +- .../compiler/test/output/output_jit_spec.ts | 2 +- .../compiler/test/output/source_map_spec.ts | 12 +- .../test/output/ts_emitter_node_only_spec.ts | 4 +- .../compiler/test/output/ts_emitter_spec.ts | 87 +- packages/compiler/test/pipe_resolver_spec.ts | 5 +- .../test/render3/r3_ast_spans_spec.ts | 14 +- .../render3/r3_template_transform_spec.ts | 23 +- .../test/render3/style_parser_spec.ts | 5 +- .../compiler/test/render3/util/expression.ts | 20 +- .../test/render3/view/binding_spec.ts | 15 +- .../compiler/test/render3/view/i18n_spec.ts | 33 +- packages/compiler/test/render3/view/util.ts | 2 +- .../test/resource_loader_mock_spec.ts | 26 +- .../compiler/test/runtime_compiler_spec.ts | 31 +- .../dom_element_schema_registry_spec.ts | 19 +- .../compiler/test/schema/schema_extractor.ts | 8 +- .../compiler/test/selector/selector_spec.ts | 21 +- packages/compiler/test/shadow_css_spec.ts | 51 +- packages/compiler/test/spies.ts | 4 +- .../compiler/test/style_url_resolver_spec.ts | 30 +- .../template_parser/binding_parser_spec.ts | 15 +- .../template_parser_absolute_span_spec.ts | 2 +- .../template_parser/template_parser_spec.ts | 3515 +++++++++-------- .../template_preparser_spec.ts | 4 +- .../test/template_parser/util/expression.ts | 24 +- .../test/template_parser/util/metadata.ts | 47 +- packages/compiler/test/url_resolver_spec.ts | 9 +- packages/compiler/test/util_spec.ts | 13 +- .../testing/src/directive_resolver_mock.ts | 6 +- .../testing/src/ng_module_resolver_mock.ts | 8 +- .../testing/src/output/source_map_util.ts | 3 +- .../testing/src/pipe_resolver_mock.ts | 12 +- .../testing/src/resource_loader_mock.ts | 18 +- .../testing/src/schema_registry_mock.ts | 20 +- 193 files changed, 5685 insertions(+), 4355 deletions(-) diff --git a/packages/compiler/src/aot/compiler.ts b/packages/compiler/src/aot/compiler.ts index 27e08eeb9698f..24ea205e9e11f 100644 --- a/packages/compiler/src/aot/compiler.ts +++ b/packages/compiler/src/aot/compiler.ts @@ -11,7 +11,7 @@ import {CompilerConfig} from '../config'; import {ConstantPool} from '../constant_pool'; import {ViewEncapsulation} from '../core'; import {MessageBundle} from '../i18n/message_bundle'; -import {Identifiers, createTokenForExternalReference} from '../identifiers'; +import {createTokenForExternalReference, Identifiers} from '../identifiers'; import {InjectableCompiler} from '../injectable_compiler'; import {CompileMetadataResolver} from '../metadata_resolver'; import {HtmlParser} from '../ml_parser/html_parser'; @@ -31,9 +31,9 @@ import {SummaryResolver} from '../summary_resolver'; import {BindingParser} from '../template_parser/binding_parser'; import {TemplateAst} from '../template_parser/template_ast'; import {TemplateParser} from '../template_parser/template_parser'; -import {OutputContext, ValueVisitor, error, newArray, syntaxError, visitValue} from '../util'; +import {error, newArray, OutputContext, syntaxError, ValueVisitor, visitValue} from '../util'; import {TypeCheckCompiler} from '../view_compiler/type_check_compiler'; -import {ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler'; +import {ViewCompiler, ViewCompileResult} from '../view_compiler/view_compiler'; import {AotCompilerHost} from './compiler_host'; import {AotCompilerOptions} from './compiler_options'; @@ -46,7 +46,11 @@ import {StaticSymbolResolver} from './static_symbol_resolver'; import {createForJitStub, serializeSummaries} from './summary_serializer'; import {ngfactoryFilePath, normalizeGenFileSuffix, splitTypescriptSuffix, summaryFileName, summaryForJitFileName} from './util'; -const enum StubEmitFlags { Basic = 1 << 0, TypeCheck = 1 << 1, All = TypeCheck | Basic } +const enum StubEmitFlags { + Basic = 1 << 0, + TypeCheck = 1 << 1, + All = TypeCheck | Basic +} export class AotCompiler { private _templateAstCache = @@ -64,7 +68,9 @@ export class AotCompiler { private _summaryResolver: SummaryResolver<StaticSymbol>, private _symbolResolver: StaticSymbolResolver) {} - clearCache() { this._metadataResolver.clearCache(); } + clearCache() { + this._metadataResolver.clearCache(); + } analyzeModulesSync(rootFiles: string[]): NgAnalyzedModules { const analyzeResult = analyzeAndValidateNgModules( @@ -123,7 +129,7 @@ export class AotCompiler { const fileSuffix = normalizeGenFileSuffix(splitTypescriptSuffix(file.fileName, true)[1]); file.directives.forEach((dirSymbol) => { const compMeta = - this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol) !.metadata; + this._metadataResolver.getNonNormalizedDirectiveMetadata(dirSymbol)!.metadata; if (!compMeta.isComponent) { return; } @@ -149,7 +155,8 @@ export class AotCompiler { if (genFileName.endsWith('.ngfactory.ts')) { if (!originalFileName) { throw new Error( - `Assertion error: require the original file for .ngfactory.ts stubs. File: ${genFileName}`); + `Assertion error: require the original file for .ngfactory.ts stubs. File: ${ + genFileName}`); } const originalFile = this._analyzeFile(originalFileName); this._createNgFactoryStub(outputCtx, originalFile, StubEmitFlags.Basic); @@ -157,7 +164,8 @@ export class AotCompiler { if (this._options.enableSummariesForJit) { if (!originalFileName) { throw new Error( - `Assertion error: require the original file for .ngsummary.ts stubs. File: ${genFileName}`); + `Assertion error: require the original file for .ngsummary.ts stubs. File: ${ + genFileName}`); } const originalFile = this._analyzeFile(originalFileName); _createEmptyStub(outputCtx); @@ -319,10 +327,10 @@ export class AotCompiler { const html = compMeta.template !.template !; // Template URL points to either an HTML or TS file depending on whether // the file is used with `templateUrl:` or `template:`, respectively. - const templateUrl = compMeta.template !.templateUrl !; + const templateUrl = compMeta.template !.templateUrl!; const interpolationConfig = InterpolationConfig.fromArray(compMeta.template !.interpolation); - errors.push(...messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig) !); + errors.push(...messageBundle.updateFromTemplate(html, templateUrl, interpolationConfig)!); }); }); @@ -342,7 +350,7 @@ export class AotCompiler { if (!contextMap.has(fileName)) { contextMap.set(fileName, this._createOutputContext(fileName)); } - return contextMap.get(fileName) !; + return contextMap.get(fileName)!; }; files.forEach( @@ -381,13 +389,13 @@ export class AotCompiler { directives.forEach(directiveType => { const directiveMetadata = this._metadataResolver.getDirectiveMetadata(directiveType); if (directiveMetadata.isComponent) { - const module = ngModuleByPipeOrDirective.get(directiveType) !; + const module = ngModuleByPipeOrDirective.get(directiveType)!; module || - error( - `Cannot determine the module for component '${identifierName(directiveMetadata.type)}'`); + error(`Cannot determine the module for component '${ + identifierName(directiveMetadata.type)}'`); - let htmlAst = directiveMetadata.template !.htmlAst !; - const preserveWhitespaces = directiveMetadata !.template !.preserveWhitespaces; + let htmlAst = directiveMetadata.template !.htmlAst!; + const preserveWhitespaces = directiveMetadata!.template !.preserveWhitespaces; if (!preserveWhitespaces) { htmlAst = removeWhitespaces(htmlAst); @@ -412,7 +420,9 @@ export class AotCompiler { const pipes = module.transitiveModule.pipes.map( pipe => this._metadataResolver.getPipeSummary(pipe.reference)); - pipes.forEach(pipe => { pipeTypeByName.set(pipe.name, pipe.type.reference); }); + pipes.forEach(pipe => { + pipeTypeByName.set(pipe.name, pipe.type.reference); + }); compileR3Component( context, directiveMetadata, render3Ast, this.reflector, hostBindingParser, @@ -484,8 +494,8 @@ export class AotCompiler { } const ngModule = ngModuleByPipeOrDirective.get(dirType); if (!ngModule) { - throw new Error( - `Internal Error: cannot determine the module for component ${identifierName(compMeta.type)}!`); + throw new Error(`Internal Error: cannot determine the module for component ${ + identifierName(compMeta.type)}!`); } // compile styles @@ -524,27 +534,27 @@ export class AotCompiler { .map(symbol => this._symbolResolver.resolveSymbol(symbol)); const typeData: { summary: CompileTypeSummary, - metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata | - CompileTypeMetadata + metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata| + CompileTypeMetadata }[] = [ ...ngModules.map( meta => ({ - summary: this._metadataResolver.getNgModuleSummary(meta.type.reference) !, - metadata: this._metadataResolver.getNgModuleMetadata(meta.type.reference) ! + summary: this._metadataResolver.getNgModuleSummary(meta.type.reference)!, + metadata: this._metadataResolver.getNgModuleMetadata(meta.type.reference)! })), ...directives.map(ref => ({ - summary: this._metadataResolver.getDirectiveSummary(ref) !, - metadata: this._metadataResolver.getDirectiveMetadata(ref) ! + summary: this._metadataResolver.getDirectiveSummary(ref)!, + metadata: this._metadataResolver.getDirectiveMetadata(ref)! })), ...pipes.map(ref => ({ - summary: this._metadataResolver.getPipeSummary(ref) !, - metadata: this._metadataResolver.getPipeMetadata(ref) ! + summary: this._metadataResolver.getPipeSummary(ref)!, + metadata: this._metadataResolver.getPipeMetadata(ref)! })), ...injectables.map( ref => ({ - summary: this._metadataResolver.getInjectableSummary(ref.symbol) !, - metadata: this._metadataResolver.getInjectableSummary(ref.symbol) !.type + summary: this._metadataResolver.getInjectableSummary(ref.symbol)!, + metadata: this._metadataResolver.getInjectableSummary(ref.symbol)!.type })) ]; const forJitOutputCtx = this._options.enableSummariesForJit ? @@ -621,7 +631,7 @@ export class AotCompiler { .toDeclStmt( o.importType( Identifiers.ComponentFactory, - [o.expressionType(outputCtx.importExpr(compMeta.type.reference)) !], + [o.expressionType(outputCtx.importExpr(compMeta.type.reference))!], [o.TypeModifier.Const]), [o.StmtModifier.Final, o.StmtModifier.Exported])); } @@ -648,15 +658,15 @@ export class AotCompiler { directiveIdentifiers: CompileIdentifierMetadata[]): {template: TemplateAst[], pipes: CompilePipeSummary[]} { if (this._templateAstCache.has(compMeta.type.reference)) { - return this._templateAstCache.get(compMeta.type.reference) !; + return this._templateAstCache.get(compMeta.type.reference)!; } - const preserveWhitespaces = compMeta !.template !.preserveWhitespaces; + const preserveWhitespaces = compMeta!.template !.preserveWhitespaces; const directives = directiveIdentifiers.map(dir => this._metadataResolver.getDirectiveSummary(dir.reference)); const pipes = ngModule.transitiveModule.pipes.map( pipe => this._metadataResolver.getPipeSummary(pipe.reference)); const result = this._templateParser.parse( - compMeta, compMeta.template !.htmlAst !, directives, pipes, ngModule.schemas, + compMeta, compMeta.template !.htmlAst!, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template !), preserveWhitespaces); this._templateAstCache.set(compMeta.type.reference, result); return result; @@ -664,8 +674,7 @@ export class AotCompiler { private _createOutputContext(genFilePath: string): OutputContext { const importExpr = - (symbol: StaticSymbol, typeParams: o.Type[] | null = null, - useSummaries: boolean = true) => { + (symbol: StaticSymbol, typeParams: o.Type[]|null = null, useSummaries: boolean = true) => { if (!(symbol instanceof StaticSymbol)) { throw new Error(`Internal error: unknown identifier ${JSON.stringify(symbol)}`); } @@ -710,7 +719,7 @@ export class AotCompiler { stylesheetMetadata: CompileStylesheetMetadata, isShimmed: boolean, fileSuffix: string): GeneratedFile { const outputCtx = this._createOutputContext( - _stylesModuleUrl(stylesheetMetadata.moduleUrl !, isShimmed, fileSuffix)); + _stylesModuleUrl(stylesheetMetadata.moduleUrl!, isShimmed, fileSuffix)); const compiledStylesheet = this._styleCompiler.compileStyles(outputCtx, compMeta, stylesheetMetadata, isShimmed); _resolveStyleStatements(this._symbolResolver, compiledStylesheet, isShimmed, fileSuffix); @@ -748,8 +757,8 @@ export class AotCompiler { return allLazyRoutes; } seenRoutes.add(symbol); - const lazyRoutes = listLazyRoutes( - self._metadataResolver.getNgModuleMetadata(symbol, true) !, self.reflector); + const lazyRoutes = + listLazyRoutes(self._metadataResolver.getNgModuleMetadata(symbol, true)!, self.reflector); for (const lazyRoute of lazyRoutes) { allLazyRoutes.push(lazyRoute); visitLazyRoute(lazyRoute.referencedModule, seenRoutes, allLazyRoutes); @@ -803,7 +812,9 @@ export interface NgAnalyzedFile { exportsNonSourceFiles: boolean; } -export interface NgAnalyzeModulesHost { isSourceFile(filePath: string): boolean; } +export interface NgAnalyzeModulesHost { + isSourceFile(filePath: string): boolean; +} export function analyzeNgModules( fileNames: string[], host: NgAnalyzeModulesHost, staticSymbolResolver: StaticSymbolResolver, @@ -823,8 +834,8 @@ export function analyzeAndValidateNgModules( function validateAnalyzedModules(analyzedModules: NgAnalyzedModules): NgAnalyzedModules { if (analyzedModules.symbolsMissingModule && analyzedModules.symbolsMissingModule.length) { const messages = analyzedModules.symbolsMissingModule.map( - s => - `Cannot determine the module for class ${s.name} in ${s.filePath}! Add ${s.name} to the NgModule to fix it.`); + s => `Cannot determine the module for class ${s.name} in ${s.filePath}! Add ${ + s.name} to the NgModule to fix it.`); throw syntaxError(messages.join('\n')); } return analyzedModules; @@ -918,8 +929,13 @@ export function analyzeFile( }); } return { - fileName, directives, abstractDirectives, pipes, - ngModules, injectables, exportsNonSourceFiles, + fileName, + directives, + abstractDirectives, + pipes, + ngModules, + injectables, + exportsNonSourceFiles, }; } @@ -957,7 +973,9 @@ function isValueExportingNonSourceFile(host: NgAnalyzeModulesHost, metadata: any let exportsNonSourceFiles = false; class Visitor implements ValueVisitor { - visitArray(arr: any[], context: any): any { arr.forEach(v => visitValue(v, this, context)); } + visitArray(arr: any[], context: any): any { + arr.forEach(v => visitValue(v, this, context)); + } visitStringMap(map: {[key: string]: any}, context: any): any { Object.keys(map).forEach((key) => visitValue(map[key], this, context)); } diff --git a/packages/compiler/src/aot/compiler_factory.ts b/packages/compiler/src/aot/compiler_factory.ts index 6122764f43844..e6cdaeaad9c94 100644 --- a/packages/compiler/src/aot/compiler_factory.ts +++ b/packages/compiler/src/aot/compiler_factory.ts @@ -36,9 +36,9 @@ import {StaticSymbol, StaticSymbolCache} from './static_symbol'; import {StaticSymbolResolver} from './static_symbol_resolver'; import {AotSummaryResolver} from './summary_resolver'; -export function createAotUrlResolver(host: { - resourceNameToFileName(resourceName: string, containingFileName: string): string | null; -}): UrlResolver { +export function createAotUrlResolver( + host: {resourceNameToFileName(resourceName: string, containingFileName: string): string|null;}): + UrlResolver { return { resolve: (basePath: string, url: string) => { const filePath = host.resourceNameToFileName(url, basePath); diff --git a/packages/compiler/src/aot/formatted_error.ts b/packages/compiler/src/aot/formatted_error.ts index b99e0f2f289ab..2f47a6c98caaa 100644 --- a/packages/compiler/src/aot/formatted_error.ts +++ b/packages/compiler/src/aot/formatted_error.ts @@ -20,7 +20,7 @@ export interface FormattedMessageChain { next?: FormattedMessageChain[]; } -export type FormattedError = Error & { +export type FormattedError = Error&{ chain: FormattedMessageChain; position?: Position; }; @@ -34,10 +34,10 @@ function indentStr(level: number): string { return half + half + (level % 2 === 1 ? ' ' : ''); } -function formatChain(chain: FormattedMessageChain | undefined, indent: number = 0): string { +function formatChain(chain: FormattedMessageChain|undefined, indent: number = 0): string { if (!chain) return ''; const position = chain.position ? - `${chain.position.fileName}(${chain.position.line+1},${chain.position.column+1})` : + `${chain.position.fileName}(${chain.position.line + 1},${chain.position.column + 1})` : ''; const prefix = position && indent === 0 ? `${position}: ` : ''; const postfix = position && indent !== 0 ? ` at ${position}` : ''; diff --git a/packages/compiler/src/aot/generated_file.ts b/packages/compiler/src/aot/generated_file.ts index 0973fbaa60fca..ff1fa07cc2b6b 100644 --- a/packages/compiler/src/aot/generated_file.ts +++ b/packages/compiler/src/aot/generated_file.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Statement, areAllEquivalent} from '../output/output_ast'; +import {areAllEquivalent, Statement} from '../output/output_ast'; import {TypeScriptEmitter} from '../output/ts_emitter'; export class GeneratedFile { @@ -36,7 +36,7 @@ export class GeneratedFile { } // Note: the constructor guarantees that if this.source is not filled, // then this.stmts is. - return areAllEquivalent(this.stmts !, other.stmts !); + return areAllEquivalent(this.stmts!, other.stmts!); } } diff --git a/packages/compiler/src/aot/lazy_routes.ts b/packages/compiler/src/aot/lazy_routes.ts index ab32b34d1ca52..9351518315368 100644 --- a/packages/compiler/src/aot/lazy_routes.ts +++ b/packages/compiler/src/aot/lazy_routes.ts @@ -34,7 +34,7 @@ export function listLazyRoutes( return allLazyRoutes; } -function _collectLoadChildren(routes: string | Route | Route[], target: string[] = []): string[] { +function _collectLoadChildren(routes: string|Route|Route[], target: string[] = []): string[] { if (typeof routes === 'string') { target.push(routes); } else if (Array.isArray(routes)) { diff --git a/packages/compiler/src/aot/static_reflector.ts b/packages/compiler/src/aot/static_reflector.ts index 6b6008ab49353..c3d4d5459744a 100644 --- a/packages/compiler/src/aot/static_reflector.ts +++ b/packages/compiler/src/aot/static_reflector.ts @@ -8,12 +8,12 @@ import {CompileSummaryKind} from '../compile_metadata'; import {CompileReflector} from '../compile_reflector'; -import {MetadataFactory, createAttribute, createComponent, createContentChild, createContentChildren, createDirective, createHost, createHostBinding, createHostListener, createInject, createInjectable, createInput, createNgModule, createOptional, createOutput, createPipe, createSelf, createSkipSelf, createViewChild, createViewChildren} from '../core'; +import {createAttribute, createComponent, createContentChild, createContentChildren, createDirective, createHost, createHostBinding, createHostListener, createInject, createInjectable, createInput, createNgModule, createOptional, createOutput, createPipe, createSelf, createSkipSelf, createViewChild, createViewChildren, MetadataFactory} from '../core'; import * as o from '../output/output_ast'; import {SummaryResolver} from '../summary_resolver'; import {syntaxError} from '../util'; -import {FormattedMessageChain, formattedError} from './formatted_error'; +import {formattedError, FormattedMessageChain} from './formatted_error'; import {StaticSymbol} from './static_symbol'; import {StaticSymbolResolver} from './static_symbol_resolver'; @@ -50,13 +50,13 @@ export class StaticReflector implements CompileReflector { private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>(); private resolvedExternalReferences = new Map<string, StaticSymbol>(); // TODO(issue/24571): remove '!'. - private injectionToken !: StaticSymbol; + private injectionToken!: StaticSymbol; // TODO(issue/24571): remove '!'. - private opaqueToken !: StaticSymbol; + private opaqueToken!: StaticSymbol; // TODO(issue/24571): remove '!'. - ROUTES !: StaticSymbol; + ROUTES!: StaticSymbol; // TODO(issue/24571): remove '!'. - private ANALYZE_FOR_ENTRY_COMPONENTS !: StaticSymbol; + private ANALYZE_FOR_ENTRY_COMPONENTS!: StaticSymbol; private annotationForParentClassWithSummaryKind = new Map<CompileSummaryKind, MetadataFactory<any>[]>(); @@ -110,10 +110,10 @@ export class StaticReflector implements CompileReflector { if (declarationSymbol) return declarationSymbol; } const refSymbol = - this.symbolResolver.getSymbolByModule(ref.moduleName !, ref.name !, containingFile); + this.symbolResolver.getSymbolByModule(ref.moduleName!, ref.name!, containingFile); const declarationSymbol = this.findSymbolDeclaration(refSymbol); if (!containingFile) { - this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName !); + this.symbolResolver.recordModuleNameForFileName(refSymbol.filePath, ref.moduleName!); this.symbolResolver.recordImportAs(declarationSymbol, refSymbol); } if (key) { @@ -192,16 +192,20 @@ export class StaticReflector implements CompileReflector { const summary = this.summaryResolver.resolveSummary(parentType); if (summary && summary.type) { const requiredAnnotationTypes = - this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind !) !; + this.annotationForParentClassWithSummaryKind.get(summary.type.summaryKind!)!; const typeHasRequiredAnnotation = requiredAnnotationTypes.some( (requiredType) => ownAnnotations.some(ann => requiredType.isTypeOf(ann))); if (!typeHasRequiredAnnotation) { this.reportError( formatMetadataError( metadataError( - `Class ${type.name} in ${type.filePath} extends from a ${CompileSummaryKind[summary.type.summaryKind!]} in another compilation unit without duplicating the decorator`, + `Class ${type.name} in ${type.filePath} extends from a ${ + CompileSummaryKind[summary.type.summaryKind! + ]} in another compilation unit without duplicating the decorator`, /* summary */ undefined, - `Please add a ${requiredAnnotationTypes.map((type) => type.ngMetadataName).join(' or ')} decorator to the class`), + `Please add a ${ + requiredAnnotationTypes.map((type) => type.ngMetadataName) + .join(' or ')} decorator to the class`), type), type); } @@ -221,7 +225,7 @@ export class StaticReflector implements CompileReflector { if (parentType) { const parentPropMetadata = this.propMetadata(parentType); Object.keys(parentPropMetadata).forEach((parentProp) => { - propMetadata ![parentProp] = parentPropMetadata[parentProp]; + propMetadata![parentProp] = parentPropMetadata[parentProp]; }); } @@ -231,10 +235,10 @@ export class StaticReflector implements CompileReflector { const prop = (<any[]>propData) .find(a => a['__symbolic'] == 'property' || a['__symbolic'] == 'method'); const decorators: any[] = []; - if (propMetadata ![propName]) { - decorators.push(...propMetadata ![propName]); + if (propMetadata![propName]) { + decorators.push(...propMetadata![propName]); } - propMetadata ![propName] = decorators; + propMetadata![propName] = decorators; if (prop && prop['decorators']) { decorators.push(...this.simplify(type, prop['decorators'])); } @@ -271,7 +275,7 @@ export class StaticReflector implements CompileReflector { if (decorators) { nestedResult.push(...decorators); } - parameters !.push(nestedResult); + parameters!.push(nestedResult); }); } else if (parentType) { parameters = this.parameters(parentType); @@ -297,7 +301,7 @@ export class StaticReflector implements CompileReflector { if (parentType) { const parentMethodNames = this._methodNames(parentType); Object.keys(parentMethodNames).forEach((parentProp) => { - methodNames ![parentProp] = parentMethodNames[parentProp]; + methodNames![parentProp] = parentMethodNames[parentProp]; }); } @@ -305,7 +309,7 @@ export class StaticReflector implements CompileReflector { Object.keys(members).forEach((propName) => { const propData = members[propName]; const isMethod = (<any[]>propData).some(a => a['__symbolic'] == 'method'); - methodNames ![propName] = methodNames ![propName] || isMethod; + methodNames![propName] = methodNames![propName] || isMethod; }); this.methodCache.set(type, methodNames); } @@ -485,7 +489,7 @@ export class StaticReflector implements CompileReflector { // Propagate the message text up but add a message to the chain that explains how we got // here. // e.chain implies e.symbol - const summaryMsg = e.chain ? 'references \'' + e.symbol !.name + '\'' : errorSummary(e); + const summaryMsg = e.chain ? 'references \'' + e.symbol!.name + '\'' : errorSummary(e); const summary = `'${nestedContext.name}' ${summaryMsg}`; const chain = {message: summary, position: e.position, next: e.chain}; // TODO(chuckj): retrieve the position information indirectly from the collectors node @@ -494,7 +498,8 @@ export class StaticReflector implements CompileReflector { { message: e.message, advise: e.advise, - context: e.context, chain, + context: e.context, + chain, symbol: nestedContext }, context); @@ -566,7 +571,8 @@ export class StaticReflector implements CompileReflector { { message: FUNCTION_CALL_NOT_SUPPORTED, context: functionSymbol, - value: targetFunction, position + value: targetFunction, + position }, context); } @@ -875,7 +881,7 @@ interface MetadataMessageChain { next?: MetadataMessageChain; } -type MetadataError = Error & { +type MetadataError = Error&{ position?: Position; advise?: string; summary?: string; @@ -916,7 +922,8 @@ function expandedMessage(message: string, context: any): string { switch (message) { case REFERENCE_TO_NONEXPORTED_CLASS: if (context && context.className) { - return `References to a non-exported class are not supported in decorators but ${context.className} was referenced.`; + return `References to a non-exported class are not supported in decorators but ${ + context.className} was referenced.`; } break; case VARIABLE_NOT_INITIALIZED: @@ -935,7 +942,8 @@ function expandedMessage(message: string, context: any): string { return 'Function calls are not supported in decorators'; case REFERENCE_TO_LOCAL_SYMBOL: if (context && context.name) { - return `Reference to a local (non-exported) symbols are not supported in decorators but '${context.name}' was referenced`; + return `Reference to a local (non-exported) symbols are not supported in decorators but '${ + context.name}' was referenced`; } break; case LAMBDA_NOT_SUPPORTED: @@ -1040,7 +1048,9 @@ abstract class BindingScope { } class PopulatedScope extends BindingScope { - constructor(private bindings: Map<string, any>) { super(); } + constructor(private bindings: Map<string, any>) { + super(); + } resolve(name: string): any { return this.bindings.has(name) ? this.bindings.get(name) : BindingScope.missing; @@ -1048,7 +1058,7 @@ class PopulatedScope extends BindingScope { } function formatMetadataMessageChain( - chain: MetadataMessageChain, advise: string | undefined): FormattedMessageChain { + chain: MetadataMessageChain, advise: string|undefined): FormattedMessageChain { const expanded = expandedMessage(chain.message, chain.context); const nesting = chain.symbol ? ` in '${chain.symbol.name}'` : ''; const message = `${expanded}${nesting}`; diff --git a/packages/compiler/src/aot/static_symbol.ts b/packages/compiler/src/aot/static_symbol.ts index cb47dd9e67f42..aaec3f0f2d0e3 100644 --- a/packages/compiler/src/aot/static_symbol.ts +++ b/packages/compiler/src/aot/static_symbol.ts @@ -31,7 +31,7 @@ export class StaticSymbolCache { get(declarationFile: string, name: string, members?: string[]): StaticSymbol { members = members || []; - const memberSuffix = members.length ? `.${ members.join('.')}` : ''; + const memberSuffix = members.length ? `.${members.join('.')}` : ''; const key = `"${declarationFile}".${name}${memberSuffix}`; let result = this.cache.get(key); if (!result) { diff --git a/packages/compiler/src/aot/static_symbol_resolver.ts b/packages/compiler/src/aot/static_symbol_resolver.ts index 8ec20dcd2ac13..de5db1f246d40 100644 --- a/packages/compiler/src/aot/static_symbol_resolver.ts +++ b/packages/compiler/src/aot/static_symbol_resolver.ts @@ -76,12 +76,12 @@ export class StaticSymbolResolver { resolveSymbol(staticSymbol: StaticSymbol): ResolvedStaticSymbol { if (staticSymbol.members.length > 0) { - return this._resolveSymbolMembers(staticSymbol) !; + return this._resolveSymbolMembers(staticSymbol)!; } // Note: always ask for a summary first, // as we might have read shallow metadata via a .d.ts file // for the symbol. - const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol) !; + const resultFromSummary = this._resolveSymbolFromSummary(staticSymbol)!; if (resultFromSummary) { return resultFromSummary; } @@ -93,7 +93,7 @@ export class StaticSymbolResolver { // have summaries, only .d.ts files. So we always need to check both, the summary // and metadata. this._createSymbolsOf(staticSymbol.filePath); - return this.resolvedSymbols.get(staticSymbol) !; + return this.resolvedSymbols.get(staticSymbol)!; } /** @@ -119,15 +119,14 @@ export class StaticSymbolResolver { const baseSymbol = this.getStaticSymbol(summarizedFileName, summarizedName, staticSymbol.members); const baseImportAs = this.getImportAs(baseSymbol, useSummaries); - return baseImportAs ? - this.getStaticSymbol( - summaryForJitFileName(baseImportAs.filePath), summaryForJitName(baseImportAs.name), - baseSymbol.members) : - null; + return baseImportAs ? this.getStaticSymbol( + summaryForJitFileName(baseImportAs.filePath), + summaryForJitName(baseImportAs.name), baseSymbol.members) : + null; } let result = (useSummaries && this.summaryResolver.getImportAs(staticSymbol)) || null; if (!result) { - result = this.importAs.get(staticSymbol) !; + result = this.importAs.get(staticSymbol)!; } return result; } @@ -347,8 +346,8 @@ export class StaticSymbolResolver { // correctly. const originFilePath = this.resolveModule(origin, filePath); if (!originFilePath) { - this.reportError(new Error( - `Couldn't resolve original symbol for ${origin} from ${this.host.getOutputName(filePath)}`)); + this.reportError(new Error(`Couldn't resolve original symbol for ${origin} from ${ + this.host.getOutputName(filePath)}`)); } else { this.symbolResourcePaths.set(symbol, originFilePath); } @@ -413,7 +412,7 @@ export class StaticSymbolResolver { } let filePath: string; if (module) { - filePath = self.resolveModule(module, sourceSymbol.filePath) !; + filePath = self.resolveModule(module, sourceSymbol.filePath)!; if (!filePath) { return { __symbolic: 'error', @@ -501,8 +500,11 @@ export class StaticSymbolResolver { } if (moduleMetadata['version'] != SUPPORTED_SCHEMA_VERSION) { const errorMessage = moduleMetadata['version'] == 2 ? - `Unsupported metadata version ${moduleMetadata['version']} for module ${module}. This module should be compiled with a newer version of ngc` : - `Metadata version mismatch for module ${this.host.getOutputName(module)}, found version ${moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`; + `Unsupported metadata version ${moduleMetadata['version']} for module ${ + module}. This module should be compiled with a newer version of ngc` : + `Metadata version mismatch for module ${ + this.host.getOutputName(module)}, found version ${ + moduleMetadata['version']}, expected ${SUPPORTED_SCHEMA_VERSION}`; this.reportError(new Error(errorMessage)); } this.metadataCache.set(module, moduleMetadata); @@ -514,9 +516,8 @@ export class StaticSymbolResolver { getSymbolByModule(module: string, symbolName: string, containingFile?: string): StaticSymbol { const filePath = this.resolveModule(module, containingFile); if (!filePath) { - this.reportError( - new Error(`Could not resolve module ${module}${containingFile ? ' relative to ' + - this.host.getOutputName(containingFile) : ''}`)); + this.reportError(new Error(`Could not resolve module ${module}${ + containingFile ? ' relative to ' + this.host.getOutputName(containingFile) : ''}`)); return this.getStaticSymbol(`ERROR:${module}`, symbolName); } return this.getStaticSymbol(filePath, symbolName); diff --git a/packages/compiler/src/aot/summary_resolver.ts b/packages/compiler/src/aot/summary_resolver.ts index 0f2c1f855eeb4..9d795b287b44b 100644 --- a/packages/compiler/src/aot/summary_resolver.ts +++ b/packages/compiler/src/aot/summary_resolver.ts @@ -71,7 +71,7 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> { let summary = this.summaryCache.get(rootSymbol); if (!summary) { this._loadSummaryFile(staticSymbol.filePath); - summary = this.summaryCache.get(staticSymbol) !; + summary = this.summaryCache.get(staticSymbol)!; } return (rootSymbol === staticSymbol && summary) || null; } @@ -85,7 +85,7 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> { getImportAs(staticSymbol: StaticSymbol): StaticSymbol { staticSymbol.assertNoMembers(); - return this.importAs.get(staticSymbol) !; + return this.importAs.get(staticSymbol)!; } /** @@ -95,7 +95,9 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> { return this.knownFileNameToModuleNames.get(importedFilePath) || null; } - addSummary(summary: Summary<StaticSymbol>) { this.summaryCache.set(summary.symbol, summary); } + addSummary(summary: Summary<StaticSymbol>) { + this.summaryCache.set(summary.symbol, summary); + } private _loadSummaryFile(filePath: string): boolean { let hasSummary = this.loadedFilePaths.get(filePath); @@ -121,7 +123,9 @@ export class AotSummaryResolver implements SummaryResolver<StaticSymbol> { if (moduleName) { this.knownFileNameToModuleNames.set(filePath, moduleName); } - importAs.forEach((importAs) => { this.importAs.set(importAs.symbol, importAs.importAs); }); + importAs.forEach((importAs) => { + this.importAs.set(importAs.symbol, importAs.importAs); + }); } return hasSummary; } diff --git a/packages/compiler/src/aot/summary_serializer.ts b/packages/compiler/src/aot/summary_serializer.ts index fbc7941491e4e..8157d3d2281aa 100644 --- a/packages/compiler/src/aot/summary_serializer.ts +++ b/packages/compiler/src/aot/summary_serializer.ts @@ -15,12 +15,12 @@ import {ResolvedStaticSymbol, StaticSymbolResolver, unwrapResolvedMetadata} from import {isLoweredSymbol, ngfactoryFilePath, summaryForJitFileName, summaryForJitName} from './util'; export function serializeSummaries( - srcFileName: string, forJitCtx: OutputContext | null, + srcFileName: string, forJitCtx: OutputContext|null, summaryResolver: SummaryResolver<StaticSymbol>, symbolResolver: StaticSymbolResolver, symbols: ResolvedStaticSymbol[], types: { summary: CompileTypeSummary, - metadata: CompileNgModuleMetadata | CompileDirectiveMetadata | CompilePipeMetadata | - CompileTypeMetadata + metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata| + CompileTypeMetadata }[], createExternalSymbolReexports = false): {json: string, exportAs: {symbol: StaticSymbol, exportAs: string}[]} { @@ -41,7 +41,9 @@ export function serializeSummaries( const {json, exportAs} = toJsonSerializer.serialize(createExternalSymbolReexports); if (forJitCtx) { const forJitSerializer = new ForJitSerializer(forJitCtx, symbolResolver, summaryResolver); - types.forEach(({summary, metadata}) => { forJitSerializer.addSourceType(summary, metadata); }); + types.forEach(({summary, metadata}) => { + forJitSerializer.addSourceType(summary, metadata); + }); toJsonSerializer.unprocessedSymbolSummariesBySymbol.forEach((summary) => { if (summaryResolver.isLibraryFile(summary.symbol.filePath) && summary.type) { forJitSerializer.addLibType(summary.type); @@ -55,7 +57,7 @@ export function serializeSummaries( export function deserializeSummaries( symbolCache: StaticSymbolCache, summaryResolver: SummaryResolver<StaticSymbol>, libraryFileName: string, json: string): { - moduleName: string | null, + moduleName: string|null, summaries: Summary<StaticSymbol>[], importAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] } { @@ -144,7 +146,7 @@ class ToJsonSerializer extends ValueTransformer { processedSummary.metadata = this.processValue(metadata, SerializationFlags.ResolveValue); if (metadata instanceof StaticSymbol && this.summaryResolver.isLibraryFile(metadata.filePath)) { - const declarationSymbol = this.symbols[this.indexBySymbol.get(metadata) !]; + const declarationSymbol = this.symbols[this.indexBySymbol.get(metadata)!]; if (!isLoweredSymbol(declarationSymbol.name)) { // Note: symbols that were introduced during codegen in the user file can have a reexport // if a user used `export *`. However, we can't rely on this as tsickle will change @@ -194,7 +196,7 @@ class ToJsonSerializer extends ValueTransformer { summaries: this.processedSummaries, symbols: this.symbols.map((symbol, index) => { symbol.assertNoMembers(); - let importAs: string|number = undefined !; + let importAs: string|number = undefined!; if (this.summaryResolver.isLibraryFile(symbol.filePath)) { const reexportSymbol = this.reexportedBy.get(symbol); if (reexportSymbol) { @@ -202,7 +204,7 @@ class ToJsonSerializer extends ValueTransformer { // user, we just proxy the external static symbol reference to the manual export. // This ensures that the AOT compiler imports the external symbol through the // user export and does not introduce another dependency which is not needed. - importAs = this.indexBySymbol.get(reexportSymbol) !; + importAs = this.indexBySymbol.get(reexportSymbol)!; } else if (createExternalSymbolReexports) { // In this case, the given external static symbol is *not* manually exported by // the user, and we manually create a re-export in the factory file so that we @@ -270,7 +272,7 @@ class ToJsonSerializer extends ValueTransformer { if (this.unprocessedSymbolSummariesBySymbol.has(baseSymbol)) { // the summary for this symbol was already added // -> nothing to do. - return index !; + return index!; } summary = this.loadSummary(baseSymbol); if (summary && summary.metadata instanceof StaticSymbol) { @@ -324,8 +326,9 @@ class ForJitSerializer { private summaryResolver: SummaryResolver<StaticSymbol>) {} addSourceType( - summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata| - CompilePipeMetadata|CompileTypeMetadata) { + summary: CompileTypeSummary, + metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata| + CompileTypeMetadata) { this.data.push({summary, metadata, isLibrary: false}); } @@ -356,7 +359,7 @@ class ForJitSerializer { const fnName = summaryForJitName(summary.type.reference.name); createSummaryForJitFunction( this.outputCtx, summary.type.reference, - this.serializeSummaryWithDeps(summary, metadata !)); + this.serializeSummaryWithDeps(summary, metadata!)); } } @@ -372,8 +375,9 @@ class ForJitSerializer { } private serializeSummaryWithDeps( - summary: CompileTypeSummary, metadata: CompileNgModuleMetadata|CompileDirectiveMetadata| - CompilePipeMetadata|CompileTypeMetadata): o.Expression { + summary: CompileTypeSummary, + metadata: CompileNgModuleMetadata|CompileDirectiveMetadata|CompilePipeMetadata| + CompileTypeMetadata): o.Expression { const expressions: o.Expression[] = [this.serializeSummary(summary)]; let providers: CompileProviderMetadata[] = []; if (metadata instanceof CompileNgModuleMetadata) { @@ -403,7 +407,8 @@ class ForJitSerializer { // i.e. we didn't generate .ngsummary.ts files for these. expressions.push( ...providers.filter(provider => !!provider.useClass).map(provider => this.serializeSummary({ - summaryKind: CompileSummaryKind.Injectable, type: provider.useClass + summaryKind: CompileSummaryKind.Injectable, + type: provider.useClass } as CompileTypeSummary))); return o.literalArr(expressions); } @@ -425,7 +430,9 @@ class ForJitSerializer { return new o.LiteralMapExpr(Object.keys(map).map( (key) => new o.LiteralMapEntry(key, visitValue(map[key], this, context), false))); } - visitPrimitive(value: any, context: any): any { return o.literal(value); } + visitPrimitive(value: any, context: any): any { + return o.literal(value); + } visitOther(value: any, context: any): any { if (value instanceof StaticSymbol) { return outputCtx.importExpr(value); @@ -441,7 +448,7 @@ class ForJitSerializer { class FromJsonDeserializer extends ValueTransformer { // TODO(issue/24571): remove '!'. - private symbols !: StaticSymbol[]; + private symbols!: StaticSymbol[]; constructor( private symbolCache: StaticSymbolCache, @@ -450,11 +457,11 @@ class FromJsonDeserializer extends ValueTransformer { } deserialize(libraryFileName: string, json: string): { - moduleName: string | null, + moduleName: string|null, summaries: Summary<StaticSymbol>[], importAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] } { - const data: {moduleName: string | null, summaries: any[], symbols: any[]} = JSON.parse(json); + const data: {moduleName: string|null, summaries: any[], symbols: any[]} = JSON.parse(json); const allImportAs: {symbol: StaticSymbol, importAs: StaticSymbol}[] = []; this.symbols = data.symbols.map( (serializedSymbol) => this.symbolCache.get( diff --git a/packages/compiler/src/ast_path.ts b/packages/compiler/src/ast_path.ts index cb019a47ebdb8..2d1e3a95b1a41 100644 --- a/packages/compiler/src/ast_path.ts +++ b/packages/compiler/src/ast_path.ts @@ -26,23 +26,35 @@ export class AstPath<T> { constructor(private path: T[], public position: number = -1) {} - get empty(): boolean { return !this.path || !this.path.length; } - get head(): T|undefined { return this.path[0]; } - get tail(): T|undefined { return this.path[this.path.length - 1]; } + get empty(): boolean { + return !this.path || !this.path.length; + } + get head(): T|undefined { + return this.path[0]; + } + get tail(): T|undefined { + return this.path[this.path.length - 1]; + } parentOf(node: T|undefined): T|undefined { return node && this.path[this.path.indexOf(node) - 1]; } - childOf(node: T): T|undefined { return this.path[this.path.indexOf(node) + 1]; } + childOf(node: T): T|undefined { + return this.path[this.path.indexOf(node) + 1]; + } - first<N extends T>(ctor: {new (...args: any[]): N}): N|undefined { + first<N extends T>(ctor: {new(...args: any[]): N}): N|undefined { for (let i = this.path.length - 1; i >= 0; i--) { let item = this.path[i]; if (item instanceof ctor) return <N>item; } } - push(node: T) { this.path.push(node); } + push(node: T) { + this.path.push(node); + } - pop(): T { return this.path.pop() !; } + pop(): T { + return this.path.pop()!; + } } diff --git a/packages/compiler/src/compile_metadata.ts b/packages/compiler/src/compile_metadata.ts index 7d8b3be1f6960..adba967933bc6 100644 --- a/packages/compiler/src/compile_metadata.ts +++ b/packages/compiler/src/compile_metadata.ts @@ -24,8 +24,8 @@ export function sanitizeIdentifier(name: string): string { let _anonymousTypeIndex = 0; -export function identifierName(compileIdentifier: CompileIdentifierMetadata | null | undefined): - string|null { +export function identifierName(compileIdentifier: CompileIdentifierMetadata|null|undefined): string| + null { if (!compileIdentifier || !compileIdentifier.reference) { return null; } @@ -72,9 +72,13 @@ export function componentFactoryName(compType: any): string { return `${identifierName({reference: compType})}NgFactory`; } -export interface ProxyClass { setDelegate(delegate: any): void; } +export interface ProxyClass { + setDelegate(delegate: any): void; +} -export interface CompileIdentifierMetadata { reference: any; } +export interface CompileIdentifierMetadata { + reference: any; +} export enum CompileSummaryKind { Pipe, @@ -175,8 +179,8 @@ export class CompileStylesheetMetadata { styles: string[]; styleUrls: string[]; constructor( - {moduleUrl, styles, - styleUrls}: {moduleUrl?: string, styles?: string[], styleUrls?: string[]} = {}) { + {moduleUrl, styles, styleUrls}: + {moduleUrl?: string, styles?: string[], styleUrls?: string[]} = {}) { this.moduleUrl = moduleUrl || null; this.styles = _normalizeArray(styles); this.styleUrls = _normalizeArray(styleUrls); @@ -209,10 +213,21 @@ export class CompileTemplateMetadata { ngContentSelectors: string[]; interpolation: [string, string]|null; preserveWhitespaces: boolean; - constructor({encapsulation, template, templateUrl, htmlAst, styles, styleUrls, - externalStylesheets, animations, ngContentSelectors, interpolation, isInline, - preserveWhitespaces}: { - encapsulation: ViewEncapsulation | null, + constructor({ + encapsulation, + template, + templateUrl, + htmlAst, + styles, + styleUrls, + externalStylesheets, + animations, + ngContentSelectors, + interpolation, + isInline, + preserveWhitespaces + }: { + encapsulation: ViewEncapsulation|null, template: string|null, templateUrl: string|null, htmlAst: HtmlParseTreeResult|null, @@ -286,9 +301,27 @@ export interface CompileDirectiveSummary extends CompileTypeSummary { * Metadata regarding compilation of a directive. */ export class CompileDirectiveMetadata { - static create({isHost, type, isComponent, selector, exportAs, changeDetection, inputs, outputs, - host, providers, viewProviders, queries, guards, viewQueries, entryComponents, - template, componentViewType, rendererType, componentFactory}: { + static create({ + isHost, + type, + isComponent, + selector, + exportAs, + changeDetection, + inputs, + outputs, + host, + providers, + viewProviders, + queries, + guards, + viewQueries, + entryComponents, + template, + componentViewType, + rendererType, + componentFactory + }: { isHost: boolean, type: CompileTypeMetadata, isComponent: boolean, @@ -347,7 +380,10 @@ export class CompileDirectiveMetadata { return new CompileDirectiveMetadata({ isHost, type, - isComponent: !!isComponent, selector, exportAs, changeDetection, + isComponent: !!isComponent, + selector, + exportAs, + changeDetection, inputs: inputsMap, outputs: outputsMap, hostListeners, @@ -389,27 +425,29 @@ export class CompileDirectiveMetadata { rendererType: StaticSymbol|object|null; componentFactory: StaticSymbol|object|null; - constructor({isHost, - type, - isComponent, - selector, - exportAs, - changeDetection, - inputs, - outputs, - hostListeners, - hostProperties, - hostAttributes, - providers, - viewProviders, - queries, - guards, - viewQueries, - entryComponents, - template, - componentViewType, - rendererType, - componentFactory}: { + constructor({ + isHost, + type, + isComponent, + selector, + exportAs, + changeDetection, + inputs, + outputs, + hostListeners, + hostProperties, + hostAttributes, + providers, + viewProviders, + queries, + guards, + viewQueries, + entryComponents, + template, + componentViewType, + rendererType, + componentFactory + }: { isHost: boolean, type: CompileTypeMetadata, isComponent: boolean, @@ -534,7 +572,7 @@ export interface CompileNgModuleSummary extends CompileTypeSummary { export class CompileShallowModuleMetadata { // TODO(issue/24571): remove '!'. - type !: CompileTypeMetadata; + type!: CompileTypeMetadata; rawExports: any; rawImports: any; @@ -562,9 +600,21 @@ export class CompileNgModuleMetadata { transitiveModule: TransitiveCompileNgModuleMetadata; - constructor({type, providers, declaredDirectives, exportedDirectives, declaredPipes, - exportedPipes, entryComponents, bootstrapComponents, importedModules, - exportedModules, schemas, transitiveModule, id}: { + constructor({ + type, + providers, + declaredDirectives, + exportedDirectives, + declaredPipes, + exportedPipes, + entryComponents, + bootstrapComponents, + importedModules, + exportedModules, + schemas, + transitiveModule, + id + }: { type: CompileTypeMetadata, providers: CompileProviderMetadata[], declaredDirectives: CompileIdentifierMetadata[], @@ -595,7 +645,7 @@ export class CompileNgModuleMetadata { } toSummary(): CompileNgModuleSummary { - const module = this.transitiveModule !; + const module = this.transitiveModule!; return { summaryKind: CompileSummaryKind.NgModule, type: this.type, @@ -666,7 +716,7 @@ export class TransitiveCompileNgModuleMetadata { } } -function _normalizeArray(obj: any[] | undefined | null): any[] { +function _normalizeArray(obj: any[]|undefined|null): any[] { return obj || []; } @@ -698,7 +748,7 @@ export class ProviderMeta { } export function flatten<T>(list: Array<T|T[]>): T[] { - return list.reduce((flat: any[], item: T | T[]): T[] => { + return list.reduce((flat: any[], item: T|T[]): T[] => { const flatItem = Array.isArray(item) ? flatten(item) : item; return (<T[]>flat).concat(flatItem); }, []); @@ -712,7 +762,7 @@ function jitSourceUrl(url: string) { export function templateSourceUrl( ngModuleType: CompileIdentifierMetadata, compMeta: {type: CompileIdentifierMetadata}, - templateMeta: {isInline: boolean, templateUrl: string | null}) { + templateMeta: {isInline: boolean, templateUrl: string|null}) { let url: string; if (templateMeta.isInline) { if (compMeta.type.reference instanceof StaticSymbol) { @@ -723,13 +773,13 @@ export function templateSourceUrl( url = `${identifierName(ngModuleType)}/${identifierName(compMeta.type)}.html`; } } else { - url = templateMeta.templateUrl !; + url = templateMeta.templateUrl!; } return compMeta.type.reference instanceof StaticSymbol ? url : jitSourceUrl(url); } export function sharedStylesheetJitUrl(meta: CompileStylesheetMetadata, id: number) { - const pathParts = meta.moduleUrl !.split(/\/\\/g); + const pathParts = meta.moduleUrl!.split(/\/\\/g); const baseName = pathParts[pathParts.length - 1]; return jitSourceUrl(`css/${id}${baseName}.ngstyle.js`); } diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts index 79d06d41c1147..e563344f23f6a 100644 --- a/packages/compiler/src/compiler_facade_interface.ts +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -22,7 +22,9 @@ * ``` */ -export interface ExportedCompilerFacade { ɵcompilerFacade: CompilerFacade; } +export interface ExportedCompilerFacade { + ɵcompilerFacade: CompilerFacade; +} export interface CompilerFacade { compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade): @@ -44,13 +46,15 @@ export interface CompilerFacade { R3ResolvedDependencyType: typeof R3ResolvedDependencyType; R3FactoryTarget: typeof R3FactoryTarget; - ResourceLoader: {new (): ResourceLoader}; + ResourceLoader: {new(): ResourceLoader}; } -export interface CoreEnvironment { [name: string]: Function; } +export interface CoreEnvironment { + [name: string]: Function; +} export type ResourceLoader = { - get(url: string): Promise<string>| string; + get(url: string): Promise<string>|string; }; export type StringMap = { @@ -58,7 +62,7 @@ export type StringMap = { }; export type StringMapWithRename = { - [key: string]: string | [string, string]; + [key: string]: string|[string, string]; }; export type Provider = any; diff --git a/packages/compiler/src/compiler_util/expression_converter.ts b/packages/compiler/src/compiler_util/expression_converter.ts index b446f6a7501f8..dd7c741d8086b 100644 --- a/packages/compiler/src/compiler_util/expression_converter.ts +++ b/packages/compiler/src/compiler_util/expression_converter.ts @@ -11,7 +11,9 @@ import {Identifiers} from '../identifiers'; import * as o from '../output/output_ast'; import {ParseSourceSpan} from '../parse_util'; -export class EventHandlerVars { static event = o.variable('$event'); } +export class EventHandlerVars { + static event = o.variable('$event'); +} export interface LocalResolver { getLocal(name: string): o.Expression|null; @@ -68,7 +70,7 @@ export type InterpolationFunction = (args: o.Expression[]) => o.Expression; * used in an action binding (e.g. an event handler). */ export function convertActionBinding( - localResolver: LocalResolver | null, implicitReceiver: o.Expression, action: cdAst.AST, + localResolver: LocalResolver|null, implicitReceiver: o.Expression, action: cdAst.AST, bindingId: string, interpolationFunction?: InterpolationFunction, baseSourceSpan?: ParseSourceSpan, implicitReceiverAccesses?: Set<string>): ConvertActionBindingResult { @@ -110,7 +112,7 @@ export function convertActionBinding( } const lastIndex = actionStmts.length - 1; - let preventDefaultVar: o.ReadVarExpr = null !; + let preventDefaultVar: o.ReadVarExpr = null!; if (lastIndex >= 0) { const lastStatement = actionStmts[lastIndex]; const returnExpr = convertStmtIntoExpression(lastStatement); @@ -126,7 +128,9 @@ export function convertActionBinding( return new ConvertActionBindingResult(actionStmts, preventDefaultVar); } -export interface BuiltinConverter { (args: o.Expression[]): o.Expression; } +export interface BuiltinConverter { + (args: o.Expression[]): o.Expression; +} export interface BuiltinConverterFactory { createLiteralArrayConverter(argCount: number): BuiltinConverter; @@ -158,7 +162,7 @@ export enum BindingForm { * `convertPropertyBindingBuiltins`. */ export function convertPropertyBinding( - localResolver: LocalResolver | null, implicitReceiver: o.Expression, + localResolver: LocalResolver|null, implicitReceiver: o.Expression, expressionWithoutBuiltins: cdAst.AST, bindingId: string, form: BindingForm, interpolationFunction?: InterpolationFunction): ConvertPropertyBindingResult { if (!localResolver) { @@ -284,7 +288,9 @@ function convertToStatementIfNeeded(mode: _Mode, expr: o.Expression): o.Expressi } class _BuiltinAstConverter extends cdAst.AstTransformer { - constructor(private _converterFactory: BuiltinConverterFactory) { super(); } + constructor(private _converterFactory: BuiltinConverterFactory) { + super(); + } visitPipe(ast: cdAst.BindingPipe, context: any): any { const args = [ast.exp, ...ast.args].map(ast => ast.visit(this, context)); return new BuiltinFunctionCall( @@ -384,9 +390,10 @@ class _AstToIrVisitor implements cdAst.AstVisitor { visitConditional(ast: cdAst.Conditional, mode: _Mode): any { const value: o.Expression = this._visit(ast.condition, _Mode.Expression); return convertToStatementIfNeeded( - mode, value.conditional( - this._visit(ast.trueExp, _Mode.Expression), - this._visit(ast.falseExp, _Mode.Expression), this.convertSourceSpan(ast.span))); + mode, + value.conditional( + this._visit(ast.trueExp, _Mode.Expression), this._visit(ast.falseExp, _Mode.Expression), + this.convertSourceSpan(ast.span))); } visitPipe(ast: cdAst.BindingPipe, mode: _Mode): any { @@ -400,7 +407,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor { if (ast instanceof BuiltinFunctionCall) { fnResult = ast.converter(convertedArgs); } else { - fnResult = this._visit(ast.target !, _Mode.Expression) + fnResult = this._visit(ast.target!, _Mode.Expression) .callFn(convertedArgs, this.convertSourceSpan(ast.span)); } return convertToStatementIfNeeded(mode, fnResult); @@ -467,7 +474,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor { mode, o.literal(ast.value, type, this.convertSourceSpan(ast.span))); } - private _getLocal(name: string): o.Expression|null { return this._localResolver.getLocal(name); } + private _getLocal(name: string): o.Expression|null { + return this._localResolver.getLocal(name); + } visitMethodCall(ast: cdAst.MethodCall, mode: _Mode): any { if (ast.receiver instanceof cdAst.ImplicitReceiver && ast.name == '$any') { @@ -558,8 +567,8 @@ class _AstToIrVisitor implements cdAst.AstVisitor { // Otherwise it's an error. const receiver = ast.name; const value = (ast.value instanceof cdAst.PropertyRead) ? ast.value.name : undefined; - throw new Error( - `Cannot assign value "${value}" to template variable "${receiver}". Template variables are read-only.`); + throw new Error(`Cannot assign value "${value}" to template variable "${ + receiver}". Template variables are read-only.`); } } } @@ -579,7 +588,9 @@ class _AstToIrVisitor implements cdAst.AstVisitor { return this.convertSafeAccess(ast, this.leftMostSafeNode(ast), mode); } - visitAll(asts: cdAst.AST[], mode: _Mode): any { return asts.map(ast => this._visit(ast, mode)); } + visitAll(asts: cdAst.AST[], mode: _Mode): any { + return asts.map(ast => this._visit(ast, mode)); + } visitQuote(ast: cdAst.Quote, mode: _Mode): any { throw new Error(`Quotes are not supported for evaluation! @@ -634,7 +645,7 @@ class _AstToIrVisitor implements cdAst.AstVisitor { // which comes in as leftMostSafe to this routine. let guardedExpression = this._visit(leftMostSafe.receiver, _Mode.Expression); - let temporary: o.ReadVarExpr = undefined !; + let temporary: o.ReadVarExpr = undefined!; if (this.needsTemporary(leftMostSafe.receiver)) { // If the expression has method calls or pipes then we need to save the result into a // temporary variable to avoid calling stateful or impure code more than once. @@ -652,14 +663,16 @@ class _AstToIrVisitor implements cdAst.AstVisitor { // leftMostNode with its unguarded version in the call to `this.visit()`. if (leftMostSafe instanceof cdAst.SafeMethodCall) { this._nodeMap.set( - leftMostSafe, new cdAst.MethodCall( - leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, - leftMostSafe.name, leftMostSafe.args)); + leftMostSafe, + new cdAst.MethodCall( + leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, leftMostSafe.name, + leftMostSafe.args)); } else { this._nodeMap.set( - leftMostSafe, new cdAst.PropertyRead( - leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, - leftMostSafe.name)); + leftMostSafe, + new cdAst.PropertyRead( + leftMostSafe.span, leftMostSafe.sourceSpan, leftMostSafe.receiver, + leftMostSafe.name)); } // Recursively convert the node now without the guarded member access. @@ -690,25 +703,63 @@ class _AstToIrVisitor implements cdAst.AstVisitor { return (this._nodeMap.get(ast) || ast).visit(visitor); }; return ast.visit({ - visitBinary(ast: cdAst.Binary) { return null; }, - visitChain(ast: cdAst.Chain) { return null; }, - visitConditional(ast: cdAst.Conditional) { return null; }, - visitFunctionCall(ast: cdAst.FunctionCall) { return null; }, - visitImplicitReceiver(ast: cdAst.ImplicitReceiver) { return null; }, - visitInterpolation(ast: cdAst.Interpolation) { return null; }, - visitKeyedRead(ast: cdAst.KeyedRead) { return visit(this, ast.obj); }, - visitKeyedWrite(ast: cdAst.KeyedWrite) { return null; }, - visitLiteralArray(ast: cdAst.LiteralArray) { return null; }, - visitLiteralMap(ast: cdAst.LiteralMap) { return null; }, - visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) { return null; }, - visitMethodCall(ast: cdAst.MethodCall) { return visit(this, ast.receiver); }, - visitPipe(ast: cdAst.BindingPipe) { return null; }, - visitPrefixNot(ast: cdAst.PrefixNot) { return null; }, - visitNonNullAssert(ast: cdAst.NonNullAssert) { return null; }, - visitPropertyRead(ast: cdAst.PropertyRead) { return visit(this, ast.receiver); }, - visitPropertyWrite(ast: cdAst.PropertyWrite) { return null; }, - visitQuote(ast: cdAst.Quote) { return null; }, - visitSafeMethodCall(ast: cdAst.SafeMethodCall) { return visit(this, ast.receiver) || ast; }, + visitBinary(ast: cdAst.Binary) { + return null; + }, + visitChain(ast: cdAst.Chain) { + return null; + }, + visitConditional(ast: cdAst.Conditional) { + return null; + }, + visitFunctionCall(ast: cdAst.FunctionCall) { + return null; + }, + visitImplicitReceiver(ast: cdAst.ImplicitReceiver) { + return null; + }, + visitInterpolation(ast: cdAst.Interpolation) { + return null; + }, + visitKeyedRead(ast: cdAst.KeyedRead) { + return visit(this, ast.obj); + }, + visitKeyedWrite(ast: cdAst.KeyedWrite) { + return null; + }, + visitLiteralArray(ast: cdAst.LiteralArray) { + return null; + }, + visitLiteralMap(ast: cdAst.LiteralMap) { + return null; + }, + visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) { + return null; + }, + visitMethodCall(ast: cdAst.MethodCall) { + return visit(this, ast.receiver); + }, + visitPipe(ast: cdAst.BindingPipe) { + return null; + }, + visitPrefixNot(ast: cdAst.PrefixNot) { + return null; + }, + visitNonNullAssert(ast: cdAst.NonNullAssert) { + return null; + }, + visitPropertyRead(ast: cdAst.PropertyRead) { + return visit(this, ast.receiver); + }, + visitPropertyWrite(ast: cdAst.PropertyWrite) { + return null; + }, + visitQuote(ast: cdAst.Quote) { + return null; + }, + visitSafeMethodCall(ast: cdAst.SafeMethodCall) { + return visit(this, ast.receiver) || ast; + }, visitSafePropertyRead(ast: cdAst.SafePropertyRead) { return visit(this, ast.receiver) || ast; } @@ -726,29 +777,66 @@ class _AstToIrVisitor implements cdAst.AstVisitor { return ast.some(ast => visit(visitor, ast)); }; return ast.visit({ - visitBinary(ast: cdAst.Binary): - boolean{return visit(this, ast.left) || visit(this, ast.right);}, - visitChain(ast: cdAst.Chain) { return false; }, - visitConditional(ast: cdAst.Conditional): - boolean{return visit(this, ast.condition) || visit(this, ast.trueExp) || - visit(this, ast.falseExp);}, - visitFunctionCall(ast: cdAst.FunctionCall) { return true; }, - visitImplicitReceiver(ast: cdAst.ImplicitReceiver) { return false; }, - visitInterpolation(ast: cdAst.Interpolation) { return visitSome(this, ast.expressions); }, - visitKeyedRead(ast: cdAst.KeyedRead) { return false; }, - visitKeyedWrite(ast: cdAst.KeyedWrite) { return false; }, - visitLiteralArray(ast: cdAst.LiteralArray) { return true; }, - visitLiteralMap(ast: cdAst.LiteralMap) { return true; }, - visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) { return false; }, - visitMethodCall(ast: cdAst.MethodCall) { return true; }, - visitPipe(ast: cdAst.BindingPipe) { return true; }, - visitPrefixNot(ast: cdAst.PrefixNot) { return visit(this, ast.expression); }, - visitNonNullAssert(ast: cdAst.PrefixNot) { return visit(this, ast.expression); }, - visitPropertyRead(ast: cdAst.PropertyRead) { return false; }, - visitPropertyWrite(ast: cdAst.PropertyWrite) { return false; }, - visitQuote(ast: cdAst.Quote) { return false; }, - visitSafeMethodCall(ast: cdAst.SafeMethodCall) { return true; }, - visitSafePropertyRead(ast: cdAst.SafePropertyRead) { return false; } + visitBinary(ast: cdAst.Binary): boolean { + return visit(this, ast.left) || visit(this, ast.right); + }, + visitChain(ast: cdAst.Chain) { + return false; + }, + visitConditional(ast: cdAst.Conditional): boolean { + return visit(this, ast.condition) || visit(this, ast.trueExp) || visit(this, ast.falseExp); + }, + visitFunctionCall(ast: cdAst.FunctionCall) { + return true; + }, + visitImplicitReceiver(ast: cdAst.ImplicitReceiver) { + return false; + }, + visitInterpolation(ast: cdAst.Interpolation) { + return visitSome(this, ast.expressions); + }, + visitKeyedRead(ast: cdAst.KeyedRead) { + return false; + }, + visitKeyedWrite(ast: cdAst.KeyedWrite) { + return false; + }, + visitLiteralArray(ast: cdAst.LiteralArray) { + return true; + }, + visitLiteralMap(ast: cdAst.LiteralMap) { + return true; + }, + visitLiteralPrimitive(ast: cdAst.LiteralPrimitive) { + return false; + }, + visitMethodCall(ast: cdAst.MethodCall) { + return true; + }, + visitPipe(ast: cdAst.BindingPipe) { + return true; + }, + visitPrefixNot(ast: cdAst.PrefixNot) { + return visit(this, ast.expression); + }, + visitNonNullAssert(ast: cdAst.PrefixNot) { + return visit(this, ast.expression); + }, + visitPropertyRead(ast: cdAst.PropertyRead) { + return false; + }, + visitPropertyWrite(ast: cdAst.PropertyWrite) { + return false; + }, + visitQuote(ast: cdAst.Quote) { + return false; + }, + visitSafeMethodCall(ast: cdAst.SafeMethodCall) { + return true; + }, + visitSafePropertyRead(ast: cdAst.SafePropertyRead) { + return false; + } }); } diff --git a/packages/compiler/src/config.ts b/packages/compiler/src/config.ts index c3f50e6a33c4a..69e0589e9f7c0 100644 --- a/packages/compiler/src/config.ts +++ b/packages/compiler/src/config.ts @@ -20,16 +20,21 @@ export class CompilerConfig { public preserveWhitespaces: boolean; public strictInjectionParameters: boolean; - constructor( - {defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, jitDevMode = false, - missingTranslation = null, preserveWhitespaces, strictInjectionParameters}: { - defaultEncapsulation?: ViewEncapsulation, - useJit?: boolean, - jitDevMode?: boolean, - missingTranslation?: MissingTranslationStrategy|null, - preserveWhitespaces?: boolean, - strictInjectionParameters?: boolean, - } = {}) { + constructor({ + defaultEncapsulation = ViewEncapsulation.Emulated, + useJit = true, + jitDevMode = false, + missingTranslation = null, + preserveWhitespaces, + strictInjectionParameters + }: { + defaultEncapsulation?: ViewEncapsulation, + useJit?: boolean, + jitDevMode?: boolean, + missingTranslation?: MissingTranslationStrategy|null, + preserveWhitespaces?: boolean, + strictInjectionParameters?: boolean, + } = {}) { this.defaultEncapsulation = defaultEncapsulation; this.useJit = !!useJit; this.jitDevMode = !!jitDevMode; @@ -40,6 +45,6 @@ export class CompilerConfig { } export function preserveWhitespacesDefault( - preserveWhitespacesOption: boolean | null, defaultSetting = false): boolean { + preserveWhitespacesOption: boolean|null, defaultSetting = false): boolean { return preserveWhitespacesOption === null ? defaultSetting : preserveWhitespacesOption; } diff --git a/packages/compiler/src/constant_pool.ts b/packages/compiler/src/constant_pool.ts index 7be8ff12a2c6a..ae58887171b33 100644 --- a/packages/compiler/src/constant_pool.ts +++ b/packages/compiler/src/constant_pool.ts @@ -7,7 +7,7 @@ */ import * as o from './output/output_ast'; -import {OutputContext, error} from './util'; +import {error, OutputContext} from './util'; const CONSTANT_PREFIX = '_c'; @@ -21,7 +21,12 @@ const CONSTANT_PREFIX = '_c'; */ const UNKNOWN_VALUE_KEY = o.variable('<unknown>'); -export const enum DefinitionKind {Injector, Directive, Component, Pipe} +export const enum DefinitionKind { + Injector, + Directive, + Component, + Pipe +} /** * Context to use when producing a key. @@ -43,7 +48,7 @@ class FixupExpression extends o.Expression { private original: o.Expression; // TODO(issue/24571): remove '!'. - shared !: boolean; + shared!: boolean; constructor(public resolved: o.Expression) { super(resolved.type); @@ -64,7 +69,9 @@ class FixupExpression extends o.Expression { return e instanceof FixupExpression && this.resolved.isEquivalent(e.resolved); } - isConstant() { return true; } + isConstant() { + return true; + } fixup(expression: o.Expression) { this.resolved = expression; @@ -169,7 +176,7 @@ export class ConstantPool { const resultExpressions = values.map( (e, index) => e.isConstant() ? this.getConstLiteral(e, true) : o.variable(`a${index}`)); const parameters = - resultExpressions.filter(isVariable).map(e => new o.FnParam(e.name !, o.DYNAMIC_TYPE)); + resultExpressions.filter(isVariable).map(e => new o.FnParam(e.name!, o.DYNAMIC_TYPE)); const pureFunctionDeclaration = o.fn(parameters, [new o.ReturnStatement(resultMap(resultExpressions))], o.INFERRED_TYPE); const name = this.freshName(); @@ -190,7 +197,9 @@ export class ConstantPool { * a digit so the prefix should be a constant string (not based on user input) and * must not end in a digit. */ - uniqueName(prefix: string): string { return `${prefix}${this.nextNameIndex++}`; } + uniqueName(prefix: string): string { + return `${prefix}${this.nextNameIndex++}`; + } private definitionsOf(kind: DefinitionKind): Map<any, FixupExpression> { switch (kind) { @@ -222,7 +231,9 @@ export class ConstantPool { return '<unknown>'; } - private freshName(): string { return this.uniqueName(CONSTANT_PREFIX); } + private freshName(): string { + return this.uniqueName(CONSTANT_PREFIX); + } private keyOf(expression: o.Expression) { return expression.visitExpression(new KeyVisitor(), KEY_CONTEXT); @@ -259,7 +270,9 @@ class KeyVisitor implements o.ExpressionVisitor { `EX:${ast.value.runtime.name}`; } - visitReadVarExpr(node: o.ReadVarExpr) { return `VAR:${node.name}`; } + visitReadVarExpr(node: o.ReadVarExpr) { + return `VAR:${node.name}`; + } visitTypeofExpr(node: o.TypeofExpr, context: any): string { return `TYPEOF:${node.expr.visitExpression(this, context)}`; @@ -284,7 +297,7 @@ class KeyVisitor implements o.ExpressionVisitor { visitLocalizedString = invalid; } -function invalid<T>(this: o.ExpressionVisitor, arg: o.Expression | o.Statement): never { +function invalid<T>(this: o.ExpressionVisitor, arg: o.Expression|o.Statement): never { throw new Error( `Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`); } diff --git a/packages/compiler/src/core.ts b/packages/compiler/src/core.ts index 70da45b3aa46f..f5d29c5d59257 100644 --- a/packages/compiler/src/core.ts +++ b/packages/compiler/src/core.ts @@ -14,12 +14,16 @@ import {CssSelector} from './selector'; -export interface Inject { token: any; } +export interface Inject { + token: any; +} export const createInject = makeMetadataFactory<Inject>('Inject', (token: any) => ({token})); export const createInjectionToken = makeMetadataFactory<object>( 'InjectionToken', (desc: string) => ({_desc: desc, ɵprov: undefined})); -export interface Attribute { attributeName?: string; } +export interface Attribute { + attributeName?: string; +} export const createAttribute = makeMetadataFactory<Attribute>('Attribute', (attributeName?: string) => ({attributeName})); @@ -37,14 +41,17 @@ export const createContentChildren = makeMetadataFactory<Query>( (selector?: any, data: any = {}) => ({selector, first: false, isViewQuery: false, descendants: false, ...data})); export const createContentChild = makeMetadataFactory<Query>( - 'ContentChild', (selector?: any, data: any = {}) => - ({selector, first: true, isViewQuery: false, descendants: true, ...data})); + 'ContentChild', + (selector?: any, data: any = {}) => + ({selector, first: true, isViewQuery: false, descendants: true, ...data})); export const createViewChildren = makeMetadataFactory<Query>( - 'ViewChildren', (selector?: any, data: any = {}) => - ({selector, first: false, isViewQuery: true, descendants: true, ...data})); + 'ViewChildren', + (selector?: any, data: any = {}) => + ({selector, first: false, isViewQuery: true, descendants: true, ...data})); export const createViewChild = makeMetadataFactory<Query>( - 'ViewChild', (selector: any, data: any) => - ({selector, first: true, isViewQuery: true, descendants: true, ...data})); + 'ViewChild', + (selector: any, data: any) => + ({selector, first: true, isViewQuery: true, descendants: true, ...data})); export interface Directive { selector?: string; @@ -94,15 +101,21 @@ export interface Pipe { } export const createPipe = makeMetadataFactory<Pipe>('Pipe', (p: Pipe) => ({pure: true, ...p})); -export interface Input { bindingPropertyName?: string; } +export interface Input { + bindingPropertyName?: string; +} export const createInput = makeMetadataFactory<Input>('Input', (bindingPropertyName?: string) => ({bindingPropertyName})); -export interface Output { bindingPropertyName?: string; } +export interface Output { + bindingPropertyName?: string; +} export const createOutput = makeMetadataFactory<Output>( 'Output', (bindingPropertyName?: string) => ({bindingPropertyName})); -export interface HostBinding { hostPropertyName?: string; } +export interface HostBinding { + hostPropertyName?: string; +} export const createHostBinding = makeMetadataFactory<HostBinding>( 'HostBinding', (hostPropertyName?: string) => ({hostPropertyName})); @@ -140,7 +153,9 @@ export interface Injectable { } export const createInjectable = makeMetadataFactory('Injectable', (injectable: Injectable = {}) => injectable); -export interface SchemaMetadata { name: string; } +export interface SchemaMetadata { + name: string; +} export const CUSTOM_ELEMENTS_SCHEMA: SchemaMetadata = { name: 'custom-elements' @@ -155,7 +170,9 @@ export const createSelf = makeMetadataFactory('Self'); export const createSkipSelf = makeMetadataFactory('SkipSelf'); export const createHost = makeMetadataFactory('Host'); -export interface Type extends Function { new (...args: any[]): any; } +export interface Type extends Function { + new(...args: any[]): any; +} export const Type = Function; export enum SecurityContext { @@ -240,7 +257,10 @@ export const enum InjectFlags { Optional = 1 << 3, } -export const enum ArgumentType {Inline = 0, Dynamic = 1} +export const enum ArgumentType { + Inline = 0, + Dynamic = 1 +} export const enum BindingFlags { TypeElementAttribute = 1 << 0, @@ -255,7 +275,10 @@ export const enum BindingFlags { Types = TypeElementAttribute | TypeElementClass | TypeElementStyle | TypeProperty } -export const enum QueryBindingType {First = 0, All = 1} +export const enum QueryBindingType { + First = 0, + All = 1 +} export const enum QueryValueType { ElementRef = 0, @@ -324,7 +347,7 @@ export const enum SelectorFlags { // These are a copy the CSS types from core/src/render3/interfaces/projection.ts // They are duplicated here as they cannot be directly referenced from core. -export type R3CssSelector = (string | SelectorFlags)[]; +export type R3CssSelector = (string|SelectorFlags)[]; export type R3CssSelectorList = R3CssSelector[]; function parserSelectorToSimpleSelector(selector: CssSelector): R3CssSelector { @@ -363,7 +386,7 @@ function parserSelectorToR3Selector(selector: CssSelector): R3CssSelector { return positive.concat(...negative); } -export function parseSelectorToR3Selector(selector: string | null): R3CssSelectorList { +export function parseSelectorToR3Selector(selector: string|null): R3CssSelectorList { return selector ? CssSelector.parse(selector).map(parserSelectorToR3Selector) : []; } diff --git a/packages/compiler/src/css_parser/css_ast.ts b/packages/compiler/src/css_parser/css_ast.ts index b217b089b657d..08e86510a5668 100644 --- a/packages/compiler/src/css_parser/css_ast.ts +++ b/packages/compiler/src/css_parser/css_ast.ts @@ -46,8 +46,12 @@ export interface CssAstVisitor { export abstract class CssAst { constructor(public location: ParseSourceSpan) {} - get start(): ParseLocation { return this.location.start; } - get end(): ParseLocation { return this.location.end; } + get start(): ParseLocation { + return this.location.start; + } + get end(): ParseLocation { + return this.location.end; + } abstract visit(visitor: CssAstVisitor, context?: any): any; } @@ -55,11 +59,15 @@ export class CssStyleValueAst extends CssAst { constructor(location: ParseSourceSpan, public tokens: CssToken[], public strValue: string) { super(location); } - visit(visitor: CssAstVisitor, context?: any): any { return visitor.visitCssValue(this); } + visit(visitor: CssAstVisitor, context?: any): any { + return visitor.visitCssValue(this); + } } export abstract class CssRuleAst extends CssAst { - constructor(location: ParseSourceSpan) { super(location); } + constructor(location: ParseSourceSpan) { + super(location); + } } export class CssBlockRuleAst extends CssRuleAst { @@ -158,7 +166,9 @@ export class CssDefinitionAst extends CssAst { } export abstract class CssSelectorPartAst extends CssAst { - constructor(location: ParseSourceSpan) { super(location); } + constructor(location: ParseSourceSpan) { + super(location); + } } export class CssSelectorAst extends CssSelectorPartAst { @@ -195,8 +205,12 @@ export class CssPseudoSelectorAst extends CssSelectorPartAst { } export class CssBlockAst extends CssAst { - constructor(location: ParseSourceSpan, public entries: CssAst[]) { super(location); } - visit(visitor: CssAstVisitor, context?: any): any { return visitor.visitCssBlock(this, context); } + constructor(location: ParseSourceSpan, public entries: CssAst[]) { + super(location); + } + visit(visitor: CssAstVisitor, context?: any): any { + return visitor.visitCssBlock(this, context); + } } /* @@ -213,7 +227,9 @@ export class CssStylesBlockAst extends CssBlockAst { } export class CssStyleSheetAst extends CssAst { - constructor(location: ParseSourceSpan, public rules: CssAst[]) { super(location); } + constructor(location: ParseSourceSpan, public rules: CssAst[]) { + super(location); + } visit(visitor: CssAstVisitor, context?: any): any { return visitor.visitCssStyleSheet(this, context); } diff --git a/packages/compiler/src/css_parser/css_lexer.ts b/packages/compiler/src/css_parser/css_lexer.ts index ea574dbf95408..31fc632eba1d1 100644 --- a/packages/compiler/src/css_parser/css_lexer.ts +++ b/packages/compiler/src/css_parser/css_lexer.ts @@ -117,7 +117,7 @@ function _trackWhitespace(mode: CssLexerMode) { export class CssScanner { // TODO(issue/24571): remove '!'. - peek !: number; + peek!: number; peekPeek: number; length: number = 0; index: number = -1; @@ -135,7 +135,9 @@ export class CssScanner { this.advance(); } - getMode(): CssLexerMode { return this._currentMode; } + getMode(): CssLexerMode { + return this._currentMode; + } setMode(mode: CssLexerMode) { if (this._currentMode != mode) { @@ -198,7 +200,7 @@ export class CssScanner { const previousLine = this.line; const previousColumn = this.column; - let next: CssToken = undefined !; + let next: CssToken = undefined!; const output = this.scan(); if (output != null) { // just incase the inner scan method returned an error @@ -236,9 +238,10 @@ export class CssScanner { } error = cssScannerError( - next, generateErrorMessage( - this.input, errorMessage, next.strValue, previousIndex, previousLine, - previousColumn)); + next, + generateErrorMessage( + this.input, errorMessage, next.strValue, previousIndex, previousLine, + previousColumn)); } return new LexedCssResult(error, next); @@ -254,7 +257,7 @@ export class CssScanner { const token = this._scan(); if (token == null) return null; - const error = this._currentError !; + const error = this._currentError!; this._currentError = null; if (!trackWS) { @@ -461,7 +464,7 @@ export class CssScanner { const startingColumn = this.column; this.advance(); if (isIdentifierStart(this.peek, this.peekPeek)) { - const ident = this.scanIdentifier() !; + const ident = this.scanIdentifier()!; const strValue = '@' + ident.strValue; return new CssToken(start, startingColumn, this.line, CssTokenType.AtKeyword, strValue); } else { diff --git a/packages/compiler/src/css_parser/css_parser.ts b/packages/compiler/src/css_parser/css_parser.ts index 2650e3deecb01..eeebbf8d614aa 100644 --- a/packages/compiler/src/css_parser/css_parser.ts +++ b/packages/compiler/src/css_parser/css_parser.ts @@ -9,7 +9,7 @@ import * as chars from '../chars'; import {ParseError, ParseLocation, ParseSourceFile, ParseSourceSpan} from '../parse_util'; -import {BlockType, CssAst, CssAtRulePredicateAst, CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStyleSheetAst, CssStyleValueAst, CssStylesBlockAst, CssUnknownRuleAst, CssUnknownTokenListAst, mergeTokens} from './css_ast'; +import {BlockType, CssAst, CssAtRulePredicateAst, CssBlockAst, CssBlockDefinitionRuleAst, CssBlockRuleAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStylesBlockAst, CssStyleSheetAst, CssStyleValueAst, CssUnknownRuleAst, CssUnknownTokenListAst, mergeTokens} from './css_ast'; import {CssLexer, CssLexerMode, CssScanner, CssToken, CssTokenType, generateErrorMessage, getRawMessage, isNewline} from './css_lexer'; const SPACE_OPERATOR = ' '; @@ -84,11 +84,11 @@ export class ParsedCssResult { export class CssParser { private _errors: CssParseError[] = []; // TODO(issue/24571): remove '!'. - private _file !: ParseSourceFile; + private _file!: ParseSourceFile; // TODO(issue/24571): remove '!'. - private _scanner !: CssScanner; + private _scanner!: CssScanner; // TODO(issue/24571): remove '!'. - private _lastToken !: CssToken; + private _lastToken!: CssToken; /** * @param css the CSS code that will be parsed @@ -125,11 +125,13 @@ export class CssParser { // EOF token that was emitted sometime during the lexing span = this._generateSourceSpan(firstRule, this._lastToken); } - return new CssStyleSheetAst(span !, results); + return new CssStyleSheetAst(span!, results); } /** @internal */ - _getSourceContent(): string { return this._scanner != null ? this._scanner.input : ''; } + _getSourceContent(): string { + return this._scanner != null ? this._scanner.input : ''; + } /** @internal */ _extractSourceContent(start: number, end: number): string { @@ -159,9 +161,9 @@ export class CssParser { let endColumn: number = -1; let endIndex: number = -1; if (end instanceof CssAst) { - endLine = end.location.end.line !; - endColumn = end.location.end.col !; - endIndex = end.location.end.offset !; + endLine = end.location.end.line!; + endColumn = end.location.end.col!; + endIndex = end.location.end.offset!; } else if (end instanceof CssToken) { endLine = end.line; endColumn = end.column; @@ -253,7 +255,7 @@ export class CssParser { case BlockType.Viewport: case BlockType.FontFace: - block = this._parseStyleBlock(delimiters) !; + block = this._parseStyleBlock(delimiters)!; span = this._generateSourceSpan(startToken, block); return new CssBlockRuleAst(span, type, block); @@ -293,7 +295,7 @@ export class CssParser { span = this._generateSourceSpan(startToken, tokens[tokens.length - 1]); query = new CssAtRulePredicateAst(span, strValue, tokens); block = this._parseBlock(delimiters); - strValue = this._extractSourceContent(start, block.end.offset !); + strValue = this._extractSourceContent(start, block.end.offset!); span = this._generateSourceSpan(startToken, block); return new CssBlockDefinitionRuleAst(span, strValue, type, query, block); @@ -310,11 +312,15 @@ export class CssParser { token); this._collectUntilDelim(delimiters | LBRACE_DELIM_FLAG | SEMICOLON_DELIM_FLAG) - .forEach((token) => { listOfTokens.push(token); }); + .forEach((token) => { + listOfTokens.push(token); + }); if (this._scanner.peek == chars.$LBRACE) { listOfTokens.push(this._consume(CssTokenType.Character, '{')); this._collectUntilDelim(delimiters | RBRACE_DELIM_FLAG | LBRACE_DELIM_FLAG) - .forEach((token) => { listOfTokens.push(token); }); + .forEach((token) => { + listOfTokens.push(token); + }); listOfTokens.push(this._consume(CssTokenType.Character, '}')); } endToken = listOfTokens[listOfTokens.length - 1]; @@ -339,7 +345,9 @@ export class CssParser { const innerTokens: CssToken[] = []; selectors.forEach((selector: CssSelectorAst) => { selector.selectorParts.forEach((part: CssSimpleSelectorAst) => { - part.tokens.forEach((token: CssToken) => { innerTokens.push(token); }); + part.tokens.forEach((token: CssToken) => { + innerTokens.push(token); + }); }); }); const endToken = innerTokens[innerTokens.length - 1]; @@ -376,7 +384,7 @@ export class CssParser { /** @internal */ _scan(): CssToken { - const output = this._scanner.scan() !; + const output = this._scanner.scan()!; const token = output.token; const error = output.error; if (error != null) { @@ -387,7 +395,9 @@ export class CssParser { } /** @internal */ - _getScannerIndex(): number { return this._scanner.index; } + _getScannerIndex(): number { + return this._scanner.index; + } /** @internal */ _consume(type: CssTokenType, value: string|null = null): CssToken { @@ -432,7 +442,7 @@ export class CssParser { } const stylesBlock = this._parseStyleBlock(delimiters | RBRACE_DELIM_FLAG); const span = this._generateSourceSpan(stepTokens[0], stylesBlock); - const ast = new CssKeyframeDefinitionAst(span, stepTokens, stylesBlock !); + const ast = new CssKeyframeDefinitionAst(span, stepTokens, stylesBlock!); this._scanner.setMode(CssLexerMode.BLOCK); return ast; @@ -523,7 +533,7 @@ export class CssParser { const selectorCssTokens: CssToken[] = []; const pseudoSelectors: CssPseudoSelectorAst[] = []; - let previousToken: CssToken = undefined !; + let previousToken: CssToken = undefined!; const selectorPartDelimiters = delimiters | SPACE_DELIM_FLAG; let loopOverSelector = !characterContainsDelimiter(this._scanner.peek, selectorPartDelimiters); @@ -576,7 +586,8 @@ export class CssParser { hasAttributeError || this._scanner.getMode() == CssLexerMode.ATTRIBUTE_SELECTOR; if (hasAttributeError) { this._error( - `Unbalanced CSS attribute selector at column ${previousToken.line}:${previousToken.column}`, + `Unbalanced CSS attribute selector at column ${previousToken.line}:${ + previousToken.column}`, previousToken); } @@ -671,8 +682,8 @@ export class CssParser { endTokenOrAst = operator; } - const span = this._generateSourceSpan(startTokenOrAst !, endTokenOrAst); - return new CssSimpleSelectorAst(span, selectorCssTokens, strValue, pseudoSelectors, operator !); + const span = this._generateSourceSpan(startTokenOrAst!, endTokenOrAst); + return new CssSimpleSelectorAst(span, selectorCssTokens, strValue, pseudoSelectors, operator!); } /** @internal */ @@ -701,7 +712,7 @@ export class CssParser { const tokens: CssToken[] = []; let wsStr = ''; - let previous: CssToken = undefined !; + let previous: CssToken = undefined!; while (!characterContainsDelimiter(this._scanner.peek, delimiters)) { let token: CssToken; if (previous != null && previous.type == CssTokenType.Identifier && @@ -841,7 +852,9 @@ export class CssParser { const remainingTokens = this._collectUntilDelim( delimiters | COLON_DELIM_FLAG | SEMICOLON_DELIM_FLAG, CssTokenType.Identifier); if (remainingTokens.length > 0) { - remainingTokens.forEach((token) => { propStr.push(token.strValue); }); + remainingTokens.forEach((token) => { + propStr.push(token.strValue); + }); } endToken = prop = @@ -868,7 +881,7 @@ export class CssParser { } const span = this._generateSourceSpan(prop, endToken); - return new CssDefinitionAst(span, prop, value !); + return new CssDefinitionAst(span, prop, value!); } /** @internal */ @@ -899,5 +912,7 @@ export class CssParseError extends ParseError { return new CssParseError(span, 'CSS Parse Error: ' + errMsg); } - constructor(span: ParseSourceSpan, message: string) { super(span, message); } + constructor(span: ParseSourceSpan, message: string) { + super(span, message); + } } diff --git a/packages/compiler/src/directive_normalizer.ts b/packages/compiler/src/directive_normalizer.ts index 38e54961ba1db..366cea285a889 100644 --- a/packages/compiler/src/directive_normalizer.ts +++ b/packages/compiler/src/directive_normalizer.ts @@ -17,7 +17,7 @@ import {ResourceLoader} from './resource_loader'; import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver'; import {PreparsedElementType, preparseElement} from './template_parser/template_preparser'; import {UrlResolver} from './url_resolver'; -import {SyncAsync, isDefined, stringify, syntaxError} from './util'; +import {isDefined, stringify, SyncAsync, syntaxError} from './util'; export interface PrenormalizedTemplateMetadata { ngModuleType: any; @@ -40,16 +40,19 @@ export class DirectiveNormalizer { private _resourceLoader: ResourceLoader, private _urlResolver: UrlResolver, private _htmlParser: HtmlParser, private _config: CompilerConfig) {} - clearCache(): void { this._resourceLoaderCache.clear(); } + clearCache(): void { + this._resourceLoaderCache.clear(); + } clearCacheFor(normalizedDirective: CompileDirectiveMetadata): void { if (!normalizedDirective.isComponent) { return; } const template = normalizedDirective.template !; - this._resourceLoaderCache.delete(template.templateUrl !); - template.externalStylesheets.forEach( - (stylesheet) => { this._resourceLoaderCache.delete(stylesheet.moduleUrl !); }); + this._resourceLoaderCache.delete(template.templateUrl!); + template.externalStylesheets.forEach((stylesheet) => { + this._resourceLoaderCache.delete(stylesheet.moduleUrl!); + }); } private _fetch(url: string): SyncAsync<string> { @@ -65,17 +68,18 @@ export class DirectiveNormalizer { SyncAsync<CompileTemplateMetadata> { if (isDefined(prenormData.template)) { if (isDefined(prenormData.templateUrl)) { - throw syntaxError( - `'${stringify(prenormData.componentType)}' component cannot define both template and templateUrl`); + throw syntaxError(`'${ + stringify(prenormData + .componentType)}' component cannot define both template and templateUrl`); } if (typeof prenormData.template !== 'string') { - throw syntaxError( - `The template specified for component ${stringify(prenormData.componentType)} is not a string`); + throw syntaxError(`The template specified for component ${ + stringify(prenormData.componentType)} is not a string`); } } else if (isDefined(prenormData.templateUrl)) { if (typeof prenormData.templateUrl !== 'string') { - throw syntaxError( - `The templateUrl specified for component ${stringify(prenormData.componentType)} is not a string`); + throw syntaxError(`The templateUrl specified for component ${ + stringify(prenormData.componentType)} is not a string`); } } else { throw syntaxError( @@ -84,8 +88,8 @@ export class DirectiveNormalizer { if (isDefined(prenormData.preserveWhitespaces) && typeof prenormData.preserveWhitespaces !== 'boolean') { - throw syntaxError( - `The preserveWhitespaces option for component ${stringify(prenormData.componentType)} must be a boolean`); + throw syntaxError(`The preserveWhitespaces option for component ${ + stringify(prenormData.componentType)} must be a boolean`); } return SyncAsync.then( @@ -101,7 +105,7 @@ export class DirectiveNormalizer { template = prenomData.template; templateUrl = prenomData.moduleUrl; } else { - templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl !); + templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl!); template = this._fetch(templateUrl); } return SyncAsync.then( @@ -112,7 +116,7 @@ export class DirectiveNormalizer { prenormData: PrenormalizedTemplateMetadata, template: string, templateAbsUrl: string): PreparsedTemplate { const isInline = !!prenormData.template; - const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation !); + const interpolationConfig = InterpolationConfig.fromArray(prenormData.interpolation!); const templateUrl = templateSourceUrl( {reference: prenormData.ngModuleType}, {type: {reference: prenormData.componentType}}, {isInline, templateUrl: templateAbsUrl}); @@ -140,8 +144,12 @@ export class DirectiveNormalizer { .styleUrls; return { template, - templateUrl: templateAbsUrl, isInline, - htmlAst: rootNodesAndErrors, styles, inlineStyleUrls, styleUrls, + templateUrl: templateAbsUrl, + isInline, + htmlAst: rootNodesAndErrors, + styles, + inlineStyleUrls, + styleUrls, ngContentSelectors: visitor.ngContentSelectors, }; } @@ -172,7 +180,7 @@ export class DirectiveNormalizer { const styleUrls = preparsedTemplate.styleUrls; const externalStylesheets = styleUrls.map(styleUrl => { - const stylesheet = stylesheets.get(styleUrl) !; + const stylesheet = stylesheets.get(styleUrl)!; const styles = [...stylesheet.styles]; this._inlineStyles(stylesheet.styleUrls, stylesheets, styles); return new CompileStylesheetMetadata({moduleUrl: styleUrl, styles: styles}); @@ -190,11 +198,14 @@ export class DirectiveNormalizer { encapsulation, template: preparsedTemplate.template, templateUrl: preparsedTemplate.templateUrl, - htmlAst: preparsedTemplate.htmlAst, styles, styleUrls, + htmlAst: preparsedTemplate.htmlAst, + styles, + styleUrls, ngContentSelectors: preparsedTemplate.ngContentSelectors, animations: prenormData.animations, interpolation: prenormData.interpolation, - isInline: preparsedTemplate.isInline, externalStylesheets, + isInline: preparsedTemplate.isInline, + externalStylesheets, preserveWhitespaces: preserveWhitespacesDefault( prenormData.preserveWhitespaces, this._config.preserveWhitespaces), }); @@ -204,7 +215,7 @@ export class DirectiveNormalizer { styleUrls: string[], stylesheets: Map<string, CompileStylesheetMetadata>, targetStyles: string[]) { styleUrls.forEach(styleUrl => { - const stylesheet = stylesheets.get(styleUrl) !; + const stylesheet = stylesheets.get(styleUrl)!; stylesheet.styles.forEach(style => targetStyles.push(style)); this._inlineStyles(stylesheet.styleUrls, stylesheets, targetStyles); }); @@ -232,7 +243,7 @@ export class DirectiveNormalizer { } private _normalizeStylesheet(stylesheet: CompileStylesheetMetadata): CompileStylesheetMetadata { - const moduleUrl = stylesheet.moduleUrl !; + const moduleUrl = stylesheet.moduleUrl!; const allStyleUrls = stylesheet.styleUrls.filter(isStyleUrlResolvable) .map(url => this._urlResolver.resolve(moduleUrl, url)); @@ -297,13 +308,21 @@ class TemplatePreparseVisitor implements html.Visitor { return null; } - visitExpansion(ast: html.Expansion, context: any): any { html.visitAll(this, ast.cases); } + visitExpansion(ast: html.Expansion, context: any): any { + html.visitAll(this, ast.cases); + } visitExpansionCase(ast: html.ExpansionCase, context: any): any { html.visitAll(this, ast.expression); } - visitComment(ast: html.Comment, context: any): any { return null; } - visitAttribute(ast: html.Attribute, context: any): any { return null; } - visitText(ast: html.Text, context: any): any { return null; } + visitComment(ast: html.Comment, context: any): any { + return null; + } + visitAttribute(ast: html.Attribute, context: any): any { + return null; + } + visitText(ast: html.Text, context: any): any { + return null; + } } diff --git a/packages/compiler/src/directive_resolver.ts b/packages/compiler/src/directive_resolver.ts index be786b4a9bb44..78764f5f597b4 100644 --- a/packages/compiler/src/directive_resolver.ts +++ b/packages/compiler/src/directive_resolver.ts @@ -7,7 +7,7 @@ */ import {CompileReflector} from './compile_reflector'; -import {Component, Directive, Type, createComponent, createContentChild, createContentChildren, createDirective, createHostBinding, createHostListener, createInput, createOutput, createViewChild, createViewChildren} from './core'; +import {Component, createComponent, createContentChild, createContentChildren, createDirective, createHostBinding, createHostListener, createInput, createOutput, createViewChild, createViewChildren, Directive, Type} from './core'; import {resolveForwardRef, splitAtColon, stringify} from './util'; const QUERY_METADATA_IDENTIFIERS = [ @@ -109,7 +109,9 @@ export class DirectiveResolver { return this._merge(dm, inputs, outputs, host, queries, guards, directiveType); } - private _extractPublicName(def: string) { return splitAtColon(def, [null !, def])[1].trim(); } + private _extractPublicName(def: string) { + return splitAtColon(def, [null!, def])[1].trim(); + } private _dedupeBindings(bindings: string[]): string[] { const names = new Set<string>(); @@ -168,7 +170,8 @@ export class DirectiveResolver { host: mergedHost, exportAs: directive.exportAs, queries: mergedQueries, - providers: directive.providers, guards + providers: directive.providers, + guards }); } } diff --git a/packages/compiler/src/expression_parser/ast.ts b/packages/compiler/src/expression_parser/ast.ts index ecf5492c5eb4e..756831b97b0c9 100644 --- a/packages/compiler/src/expression_parser/ast.ts +++ b/packages/compiler/src/expression_parser/ast.ts @@ -31,8 +31,12 @@ export class AST { * Absolute location of the expression AST in a source code file. */ public sourceSpan: AbsoluteSourceSpan) {} - visit(visitor: AstVisitor, context: any = null): any { return null; } - toString(): string { return 'AST'; } + visit(visitor: AstVisitor, context: any = null): any { + return null; + } + toString(): string { + return 'AST'; + } } /** @@ -54,8 +58,12 @@ export class Quote extends AST { public uninterpretedExpression: string, public location: any) { super(span, sourceSpan); } - visit(visitor: AstVisitor, context: any = null): any { return visitor.visitQuote(this, context); } - toString(): string { return 'Quote'; } + visit(visitor: AstVisitor, context: any = null): any { + return visitor.visitQuote(this, context); + } + toString(): string { + return 'Quote'; + } } export class EmptyExpr extends AST { @@ -77,7 +85,9 @@ export class Chain extends AST { constructor(span: ParseSpan, sourceSpan: AbsoluteSourceSpan, public expressions: any[]) { super(span, sourceSpan); } - visit(visitor: AstVisitor, context: any = null): any { return visitor.visitChain(this, context); } + visit(visitor: AstVisitor, context: any = null): any { + return visitor.visitChain(this, context); + } } export class Conditional extends AST { @@ -148,7 +158,9 @@ export class BindingPipe extends AST { public args: any[], public nameSpan: AbsoluteSourceSpan) { super(span, sourceSpan); } - visit(visitor: AstVisitor, context: any = null): any { return visitor.visitPipe(this, context); } + visit(visitor: AstVisitor, context: any = null): any { + return visitor.visitPipe(this, context); + } } export class LiteralPrimitive extends AST { @@ -280,7 +292,9 @@ export class ASTWithSource extends AST { } return this.ast.visit(visitor, context); } - toString(): string { return `${this.source} in ${this.location}`; } + toString(): string { + return `${this.source} in ${this.location}`; + } } /** @@ -302,7 +316,7 @@ export class ASTWithSource extends AST { * the LHS of a HTML attribute to the expression in the RHS. All other bindings * in the example above are derived solely from the RHS. */ -export type TemplateBinding = VariableBinding | ExpressionBinding; +export type TemplateBinding = VariableBinding|ExpressionBinding; export class VariableBinding { /** @@ -379,7 +393,9 @@ export class RecursiveAstVisitor implements AstVisitor { this.visit(ast.left, context); this.visit(ast.right, context); } - visitChain(ast: Chain, context: any): any { this.visitAll(ast.expressions, context); } + visitChain(ast: Chain, context: any): any { + this.visitAll(ast.expressions, context); + } visitConditional(ast: Conditional, context: any): any { this.visit(ast.condition, context); this.visit(ast.trueExp, context); @@ -411,15 +427,23 @@ export class RecursiveAstVisitor implements AstVisitor { visitLiteralArray(ast: LiteralArray, context: any): any { this.visitAll(ast.expressions, context); } - visitLiteralMap(ast: LiteralMap, context: any): any { this.visitAll(ast.values, context); } + visitLiteralMap(ast: LiteralMap, context: any): any { + this.visitAll(ast.values, context); + } visitLiteralPrimitive(ast: LiteralPrimitive, context: any): any {} visitMethodCall(ast: MethodCall, context: any): any { this.visit(ast.receiver, context); this.visitAll(ast.args, context); } - visitPrefixNot(ast: PrefixNot, context: any): any { this.visit(ast.expression, context); } - visitNonNullAssert(ast: NonNullAssert, context: any): any { this.visit(ast.expression, context); } - visitPropertyRead(ast: PropertyRead, context: any): any { this.visit(ast.receiver, context); } + visitPrefixNot(ast: PrefixNot, context: any): any { + this.visit(ast.expression, context); + } + visitNonNullAssert(ast: NonNullAssert, context: any): any { + this.visit(ast.expression, context); + } + visitPropertyRead(ast: PropertyRead, context: any): any { + this.visit(ast.receiver, context); + } visitPropertyWrite(ast: PropertyWrite, context: any): any { this.visit(ast.receiver, context); this.visit(ast.value, context); @@ -441,7 +465,9 @@ export class RecursiveAstVisitor implements AstVisitor { } export class AstTransformer implements AstVisitor { - visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { return ast; } + visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { + return ast; + } visitInterpolation(ast: Interpolation, context: any): AST { return new Interpolation(ast.span, ast.sourceSpan, ast.strings, this.visitAll(ast.expressions)); @@ -476,7 +502,7 @@ export class AstTransformer implements AstVisitor { visitFunctionCall(ast: FunctionCall, context: any): AST { return new FunctionCall( - ast.span, ast.sourceSpan, ast.target !.visit(this), this.visitAll(ast.args)); + ast.span, ast.sourceSpan, ast.target!.visit(this), this.visitAll(ast.args)); } visitLiteralArray(ast: LiteralArray, context: any): AST { @@ -542,7 +568,9 @@ export class AstTransformer implements AstVisitor { // A transformer that only creates new nodes if the transformer makes a change or // a change is made a child node. export class AstMemoryEfficientTransformer implements AstVisitor { - visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { return ast; } + visitImplicitReceiver(ast: ImplicitReceiver, context: any): AST { + return ast; + } visitInterpolation(ast: Interpolation, context: any): Interpolation { const expressions = this.visitAll(ast.expressions); @@ -551,7 +579,9 @@ export class AstMemoryEfficientTransformer implements AstVisitor { return ast; } - visitLiteralPrimitive(ast: LiteralPrimitive, context: any): AST { return ast; } + visitLiteralPrimitive(ast: LiteralPrimitive, context: any): AST { + return ast; + } visitPropertyRead(ast: PropertyRead, context: any): AST { const receiver = ast.receiver.visit(this); @@ -704,7 +734,9 @@ export class AstMemoryEfficientTransformer implements AstVisitor { return ast; } - visitQuote(ast: Quote, context: any): AST { return ast; } + visitQuote(ast: Quote, context: any): AST { + return ast; + } } // Bindings diff --git a/packages/compiler/src/expression_parser/lexer.ts b/packages/compiler/src/expression_parser/lexer.ts index c4ccbb87af66a..b942ecd4f7e1e 100644 --- a/packages/compiler/src/expression_parser/lexer.ts +++ b/packages/compiler/src/expression_parser/lexer.ts @@ -42,37 +42,61 @@ export class Token { return this.type == TokenType.Character && this.numValue == code; } - isNumber(): boolean { return this.type == TokenType.Number; } + isNumber(): boolean { + return this.type == TokenType.Number; + } - isString(): boolean { return this.type == TokenType.String; } + isString(): boolean { + return this.type == TokenType.String; + } isOperator(operator: string): boolean { return this.type == TokenType.Operator && this.strValue == operator; } - isIdentifier(): boolean { return this.type == TokenType.Identifier; } + isIdentifier(): boolean { + return this.type == TokenType.Identifier; + } - isKeyword(): boolean { return this.type == TokenType.Keyword; } + isKeyword(): boolean { + return this.type == TokenType.Keyword; + } - isKeywordLet(): boolean { return this.type == TokenType.Keyword && this.strValue == 'let'; } + isKeywordLet(): boolean { + return this.type == TokenType.Keyword && this.strValue == 'let'; + } - isKeywordAs(): boolean { return this.type == TokenType.Keyword && this.strValue == 'as'; } + isKeywordAs(): boolean { + return this.type == TokenType.Keyword && this.strValue == 'as'; + } - isKeywordNull(): boolean { return this.type == TokenType.Keyword && this.strValue == 'null'; } + isKeywordNull(): boolean { + return this.type == TokenType.Keyword && this.strValue == 'null'; + } isKeywordUndefined(): boolean { return this.type == TokenType.Keyword && this.strValue == 'undefined'; } - isKeywordTrue(): boolean { return this.type == TokenType.Keyword && this.strValue == 'true'; } + isKeywordTrue(): boolean { + return this.type == TokenType.Keyword && this.strValue == 'true'; + } - isKeywordFalse(): boolean { return this.type == TokenType.Keyword && this.strValue == 'false'; } + isKeywordFalse(): boolean { + return this.type == TokenType.Keyword && this.strValue == 'false'; + } - isKeywordThis(): boolean { return this.type == TokenType.Keyword && this.strValue == 'this'; } + isKeywordThis(): boolean { + return this.type == TokenType.Keyword && this.strValue == 'this'; + } - isError(): boolean { return this.type == TokenType.Error; } + isError(): boolean { + return this.type == TokenType.Error; + } - toNumber(): number { return this.type == TokenType.Number ? this.numValue : -1; } + toNumber(): number { + return this.type == TokenType.Number ? this.numValue : -1; + } toString(): string|null { switch (this.type) { diff --git a/packages/compiler/src/expression_parser/parser.ts b/packages/compiler/src/expression_parser/parser.ts index cb5f2dba08fb5..d003edff14035 100644 --- a/packages/compiler/src/expression_parser/parser.ts +++ b/packages/compiler/src/expression_parser/parser.ts @@ -10,8 +10,8 @@ import * as chars from '../chars'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../ml_parser/interpolation_config'; import {escapeRegExp} from '../util'; -import {AST, ASTWithSource, AbsoluteSourceSpan, AstVisitor, Binary, BindingPipe, Chain, Conditional, EmptyExpr, ExpressionBinding, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralMapKey, LiteralPrimitive, MethodCall, NonNullAssert, ParseSpan, ParserError, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding, TemplateBindingIdentifier, VariableBinding} from './ast'; -import {EOF, Lexer, Token, TokenType, isIdentifier, isQuote} from './lexer'; +import {AbsoluteSourceSpan, AST, AstVisitor, ASTWithSource, Binary, BindingPipe, Chain, Conditional, EmptyExpr, ExpressionBinding, FunctionCall, ImplicitReceiver, Interpolation, KeyedRead, KeyedWrite, LiteralArray, LiteralMap, LiteralMapKey, LiteralPrimitive, MethodCall, NonNullAssert, ParserError, ParseSpan, PrefixNot, PropertyRead, PropertyWrite, Quote, SafeMethodCall, SafePropertyRead, TemplateBinding, TemplateBindingIdentifier, VariableBinding} from './ast'; +import {EOF, isIdentifier, isQuote, Lexer, Token, TokenType} from './lexer'; export class SplitInterpolation { constructor(public strings: string[], public expressions: string[], public offsets: number[]) {} @@ -253,7 +253,8 @@ export class Parser { const parts = input.split(regexp); if (parts.length > 1) { this._reportError( - `Got interpolation (${interpolationConfig.start}${interpolationConfig.end}) where expression was expected`, + `Got interpolation (${interpolationConfig.start}${ + interpolationConfig.end}) where expression was expected`, input, `at column ${this._findInterpolationErrorColumn(parts, 1, interpolationConfig)} in`, location); @@ -300,7 +301,9 @@ export class _ParseAST { return i < this.tokens.length ? this.tokens[i] : EOF; } - get next(): Token { return this.peek(0); } + get next(): Token { + return this.peek(0); + } get inputIndex(): number { return (this.index < this.tokens.length) ? this.next.index + this.offset : @@ -310,7 +313,9 @@ export class _ParseAST { /** * Returns the absolute offset of the start of the current token. */ - get currentAbsoluteOffset(): number { return this.absoluteOffset + this.inputIndex; } + get currentAbsoluteOffset(): number { + return this.absoluteOffset + this.inputIndex; + } span(start: number) { // `end` is either the @@ -326,10 +331,12 @@ export class _ParseAST { if (!this.sourceSpanCache.has(serial)) { this.sourceSpanCache.set(serial, this.span(start).toAbsolute(this.absoluteOffset)); } - return this.sourceSpanCache.get(serial) !; + return this.sourceSpanCache.get(serial)!; } - advance() { this.index++; } + advance() { + this.index++; + } consumeOptionalCharacter(code: number): boolean { if (this.next.isCharacter(code)) { @@ -340,8 +347,12 @@ export class _ParseAST { } } - peekKeywordLet(): boolean { return this.next.isKeywordLet(); } - peekKeywordAs(): boolean { return this.next.isKeywordAs(); } + peekKeywordLet(): boolean { + return this.next.isKeywordLet(); + } + peekKeywordAs(): boolean { + return this.next.isKeywordAs(); + } expectCharacter(code: number) { if (this.consumeOptionalCharacter(code)) return; @@ -428,7 +439,9 @@ export class _ParseAST { return result; } - parseExpression(): AST { return this.parseConditional(); } + parseExpression(): AST { + return this.parseConditional(); + } parseConditional(): AST { const start = this.inputIndex; @@ -984,8 +997,8 @@ export class _ParseAST { (this.rbracesExpected <= 0 || !n.isCharacter(chars.$RBRACE)) && (this.rbracketsExpected <= 0 || !n.isCharacter(chars.$RBRACKET))) { if (this.next.isError()) { - this.errors.push(new ParserError( - this.next.toString() !, this.input, this.locationText(), this.location)); + this.errors.push( + new ParserError(this.next.toString()!, this.input, this.locationText(), this.location)); } this.advance(); n = this.next; @@ -1014,9 +1027,13 @@ class SimpleExpressionChecker implements AstVisitor { visitFunctionCall(ast: FunctionCall, context: any) {} - visitLiteralArray(ast: LiteralArray, context: any) { this.visitAll(ast.expressions); } + visitLiteralArray(ast: LiteralArray, context: any) { + this.visitAll(ast.expressions); + } - visitLiteralMap(ast: LiteralMap, context: any) { this.visitAll(ast.values); } + visitLiteralMap(ast: LiteralMap, context: any) { + this.visitAll(ast.values); + } visitBinary(ast: Binary, context: any) {} @@ -1026,13 +1043,17 @@ class SimpleExpressionChecker implements AstVisitor { visitConditional(ast: Conditional, context: any) {} - visitPipe(ast: BindingPipe, context: any) { this.errors.push('pipes'); } + visitPipe(ast: BindingPipe, context: any) { + this.errors.push('pipes'); + } visitKeyedRead(ast: KeyedRead, context: any) {} visitKeyedWrite(ast: KeyedWrite, context: any) {} - visitAll(asts: any[]): any[] { return asts.map(node => node.visit(this)); } + visitAll(asts: any[]): any[] { + return asts.map(node => node.visit(this)); + } visitChain(ast: Chain, context: any) {} @@ -1052,5 +1073,7 @@ class IvySimpleExpressionChecker extends SimpleExpressionChecker { ast.right.visit(this); } - visitPrefixNot(ast: PrefixNot, context: any) { ast.expression.visit(this); } + visitPrefixNot(ast: PrefixNot, context: any) { + ast.expression.visit(this); + } } diff --git a/packages/compiler/src/i18n/digest.ts b/packages/compiler/src/i18n/digest.ts index e81a26e6a1a7d..58ff21d394501 100644 --- a/packages/compiler/src/i18n/digest.ts +++ b/packages/compiler/src/i18n/digest.ts @@ -48,7 +48,9 @@ export function computeDecimalDigest(message: i18n.Message): string { * @internal */ class _SerializerVisitor implements i18n.Visitor { - visitText(text: i18n.Text, context: any): any { return text.value; } + visitText(text: i18n.Text, context: any): any { + return text.value; + } visitContainer(container: i18n.Container, context: any): any { return `[${container.children.map(child => child.visit(this)).join(', ')}]`; @@ -63,7 +65,8 @@ class _SerializerVisitor implements i18n.Visitor { visitTagPlaceholder(ph: i18n.TagPlaceholder, context: any): any { return ph.isVoid ? `<ph tag name="${ph.startName}"/>` : - `<ph tag name="${ph.startName}">${ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`; + `<ph tag name="${ph.startName}">${ + ph.children.map(child => child.visit(this)).join(', ')}</ph name="${ph.closeName}">`; } visitPlaceholder(ph: i18n.Placeholder, context: any): any { diff --git a/packages/compiler/src/i18n/extractor.ts b/packages/compiler/src/i18n/extractor.ts index 8b950feb6d109..43a6d06489e0c 100644 --- a/packages/compiler/src/i18n/extractor.ts +++ b/packages/compiler/src/i18n/extractor.ts @@ -78,11 +78,11 @@ export class Extractor { // Template URL points to either an HTML or TS file depending on // whether the file is used with `templateUrl:` or `template:`, // respectively. - const templateUrl = compMeta.template !.templateUrl !; + const templateUrl = compMeta.template !.templateUrl!; const interpolationConfig = InterpolationConfig.fromArray(compMeta.template !.interpolation); errors.push(...this.messageBundle.updateFromTemplate( - html, templateUrl, interpolationConfig) !); + html, templateUrl, interpolationConfig)!); }); }); diff --git a/packages/compiler/src/i18n/extractor_merger.ts b/packages/compiler/src/i18n/extractor_merger.ts index 0a45f6db38119..5133826c933ee 100644 --- a/packages/compiler/src/i18n/extractor_merger.ts +++ b/packages/compiler/src/i18n/extractor_merger.ts @@ -9,8 +9,9 @@ import * as html from '../ml_parser/ast'; import {InterpolationConfig} from '../ml_parser/interpolation_config'; import {ParseTreeResult} from '../ml_parser/parser'; + import * as i18n from './i18n_ast'; -import {I18nMessageFactory, createI18nMessageFactory} from './i18n_parser'; +import {createI18nMessageFactory, I18nMessageFactory} from './i18n_parser'; import {I18nError} from './parse_util'; import {TranslationBundle} from './translation_bundle'; @@ -56,44 +57,44 @@ enum _VisitorMode { */ class _Visitor implements html.Visitor { // TODO(issue/24571): remove '!'. - private _depth !: number; + private _depth!: number; // <el i18n>...</el> // TODO(issue/24571): remove '!'. - private _inI18nNode !: boolean; + private _inI18nNode!: boolean; // TODO(issue/24571): remove '!'. - private _inImplicitNode !: boolean; + private _inImplicitNode!: boolean; // <!--i18n-->...<!--/i18n--> // TODO(issue/24571): remove '!'. - private _inI18nBlock !: boolean; + private _inI18nBlock!: boolean; // TODO(issue/24571): remove '!'. - private _blockMeaningAndDesc !: string; + private _blockMeaningAndDesc!: string; // TODO(issue/24571): remove '!'. - private _blockChildren !: html.Node[]; + private _blockChildren!: html.Node[]; // TODO(issue/24571): remove '!'. - private _blockStartDepth !: number; + private _blockStartDepth!: number; // {<icu message>} // TODO(issue/24571): remove '!'. - private _inIcu !: boolean; + private _inIcu!: boolean; // set to void 0 when not in a section private _msgCountAtSectionStart: number|undefined; // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; // TODO(issue/24571): remove '!'. - private _mode !: _VisitorMode; + private _mode!: _VisitorMode; // _VisitorMode.Extract only // TODO(issue/24571): remove '!'. - private _messages !: i18n.Message[]; + private _messages!: i18n.Message[]; // _VisitorMode.Merge only // TODO(issue/24571): remove '!'. - private _translations !: TranslationBundle; + private _translations!: TranslationBundle; // TODO(issue/24571): remove '!'. - private _createI18nMessage !: I18nMessageFactory; + private _createI18nMessage!: I18nMessageFactory; constructor(private _implicitTags: string[], private _implicitAttrs: {[k: string]: string[]}) {} @@ -123,7 +124,7 @@ class _Visitor implements html.Visitor { this._translations = translations; // Construct a single fake root element - const wrapper = new html.Element('wrapper', [], nodes, undefined !, undefined, undefined); + const wrapper = new html.Element('wrapper', [], nodes, undefined!, undefined, undefined); const translatedNode = wrapper.visit(this, null); @@ -193,14 +194,14 @@ class _Visitor implements html.Visitor { i18nCommentsWarned = true; const details = comment.sourceSpan.details ? `, ${comment.sourceSpan.details}` : ''; // TODO(ocombe): use a log service once there is a public one available - console.warn( - `I18n comments are deprecated, use an <ng-container> element instead (${comment.sourceSpan.start}${details})`); + console.warn(`I18n comments are deprecated, use an <ng-container> element instead (${ + comment.sourceSpan.start}${details})`); } this._inI18nBlock = true; this._blockStartDepth = this._depth; this._blockChildren = []; this._blockMeaningAndDesc = - comment.value !.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim(); + comment.value!.replace(_I18N_COMMENT_PREFIX_REGEXP, '').trim(); this._openTranslatableSection(comment); } } else { @@ -208,7 +209,7 @@ class _Visitor implements html.Visitor { if (this._depth == this._blockStartDepth) { this._closeTranslatableSection(comment, this._blockChildren); this._inI18nBlock = false; - const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc) !; + const message = this._addMessage(this._blockChildren, this._blockMeaningAndDesc)!; // merge attributes in sections const nodes = this._translateMessage(comment, message); return html.visitAll(this, nodes); @@ -234,7 +235,7 @@ class _Visitor implements html.Visitor { const wasInI18nNode = this._inI18nNode; const wasInImplicitNode = this._inImplicitNode; let childNodes: html.Node[] = []; - let translatedChildNodes: html.Node[] = undefined !; + let translatedChildNodes: html.Node[] = undefined!; // Extract: // - top level nodes with the (implicit) "i18n" attribute if not already in a section @@ -249,7 +250,7 @@ class _Visitor implements html.Visitor { if (!this._isInTranslatableSection && !this._inIcu) { if (i18nAttr || isTopLevelImplicit) { this._inI18nNode = true; - const message = this._addMessage(el.children, i18nMeta) !; + const message = this._addMessage(el.children, i18nMeta)!; translatedChildNodes = this._translateMessage(el, message); } @@ -400,12 +401,14 @@ class _Visitor implements html.Visitor { } else { this._reportError( el, - `Unexpected translation for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`); + `Unexpected translation for attribute "${attr.name}" (id="${ + id || this._translations.digest(message)}")`); } } else { this._reportError( el, - `Translation unavailable for attribute "${attr.name}" (id="${id || this._translations.digest(message)}")`); + `Translation unavailable for attribute "${attr.name}" (id="${ + id || this._translations.digest(message)}")`); } } else { translatedAttributes.push(attr); @@ -476,7 +479,7 @@ class _Visitor implements html.Visitor { 0); if (significantChildren == 1) { - for (let i = this._messages.length - 1; i >= startIndex !; i--) { + for (let i = this._messages.length - 1; i >= startIndex!; i--) { const ast = this._messages[i].nodes; if (!(ast.length == 1 && ast[0] instanceof i18n.Text)) { this._messages.splice(i, 1); @@ -489,7 +492,7 @@ class _Visitor implements html.Visitor { } private _reportError(node: html.Node, msg: string): void { - this._errors.push(new I18nError(node.sourceSpan !, msg)); + this._errors.push(new I18nError(node.sourceSpan!, msg)); } } diff --git a/packages/compiler/src/i18n/i18n_ast.ts b/packages/compiler/src/i18n/i18n_ast.ts index 9ec6afe1ba611..ef0b1156f024e 100644 --- a/packages/compiler/src/i18n/i18n_ast.ts +++ b/packages/compiler/src/i18n/i18n_ast.ts @@ -57,24 +57,30 @@ export interface Node { export class Text implements Node { constructor(public value: string, public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context?: any): any { return visitor.visitText(this, context); } + visit(visitor: Visitor, context?: any): any { + return visitor.visitText(this, context); + } } // TODO(vicb): do we really need this node (vs an array) ? export class Container implements Node { constructor(public children: Node[], public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context?: any): any { return visitor.visitContainer(this, context); } + visit(visitor: Visitor, context?: any): any { + return visitor.visitContainer(this, context); + } } export class Icu implements Node { // TODO(issue/24571): remove '!'. - public expressionPlaceholder !: string; + public expressionPlaceholder!: string; constructor( public expression: string, public type: string, public cases: {[k: string]: Node}, public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context?: any): any { return visitor.visitIcu(this, context); } + visit(visitor: Visitor, context?: any): any { + return visitor.visitIcu(this, context); + } } export class TagPlaceholder implements Node { @@ -83,13 +89,17 @@ export class TagPlaceholder implements Node { public closeName: string, public children: Node[], public isVoid: boolean, public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context?: any): any { return visitor.visitTagPlaceholder(this, context); } + visit(visitor: Visitor, context?: any): any { + return visitor.visitTagPlaceholder(this, context); + } } export class Placeholder implements Node { constructor(public value: string, public name: string, public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context?: any): any { return visitor.visitPlaceholder(this, context); } + visit(visitor: Visitor, context?: any): any { + return visitor.visitPlaceholder(this, context); + } } export class IcuPlaceholder implements Node { @@ -97,7 +107,9 @@ export class IcuPlaceholder implements Node { previousMessage?: Message; constructor(public value: Icu, public name: string, public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context?: any): any { return visitor.visitIcuPlaceholder(this, context); } + visit(visitor: Visitor, context?: any): any { + return visitor.visitIcuPlaceholder(this, context); + } } /** @@ -106,7 +118,7 @@ export class IcuPlaceholder implements Node { * This information is either a `Message`, which indicates it is the root of an i18n message, or a * `Node`, which indicates is it part of a containing `Message`. */ -export type I18nMeta = Message | Node; +export type I18nMeta = Message|Node; export interface Visitor { visitText(text: Text, context?: any): any; @@ -119,7 +131,9 @@ export interface Visitor { // Clone the AST export class CloneVisitor implements Visitor { - visitText(text: Text, context?: any): Text { return new Text(text.value, text.sourceSpan); } + visitText(text: Text, context?: any): Text { + return new Text(text.value, text.sourceSpan); + } visitContainer(container: Container, context?: any): Container { const children = container.children.map(n => n.visit(this, context)); @@ -158,7 +172,9 @@ export class RecurseVisitor implements Visitor { } visitIcu(icu: Icu, context?: any): any { - Object.keys(icu.cases).forEach(k => { icu.cases[k].visit(this); }); + Object.keys(icu.cases).forEach(k => { + icu.cases[k].visit(this); + }); } visitTagPlaceholder(ph: TagPlaceholder, context?: any): any { diff --git a/packages/compiler/src/i18n/i18n_parser.ts b/packages/compiler/src/i18n/i18n_parser.ts index f1be0895c82d4..5c19595f72427 100644 --- a/packages/compiler/src/i18n/i18n_parser.ts +++ b/packages/compiler/src/i18n/i18n_parser.ts @@ -83,7 +83,7 @@ class _I18nVisitor implements html.Visitor { const isVoid: boolean = getHtmlTagDefinition(el.name).isVoid; const startPhName = context.placeholderRegistry.getStartTagPlaceholderName(el.name, attrs, isVoid); - context.placeholderToContent[startPhName] = el.sourceSpan !.toString(); + context.placeholderToContent[startPhName] = el.sourceSpan!.toString(); let closePhName = ''; @@ -93,7 +93,7 @@ class _I18nVisitor implements html.Visitor { } const node = new i18n.TagPlaceholder( - el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan !); + el.name, attrs, startPhName, closePhName, children, isVoid, el.sourceSpan!); return context.visitNodeFn(el, node); } @@ -103,7 +103,7 @@ class _I18nVisitor implements html.Visitor { } visitText(text: html.Text, context: I18nMessageVisitorContext): i18n.Node { - const node = this._visitTextWithInterpolation(text.value, text.sourceSpan !, context); + const node = this._visitTextWithInterpolation(text.value, text.sourceSpan!, context); return context.visitNodeFn(text, node); } diff --git a/packages/compiler/src/i18n/message_bundle.ts b/packages/compiler/src/i18n/message_bundle.ts index 882ac54eb3d62..dcc7269c23f2e 100644 --- a/packages/compiler/src/i18n/message_bundle.ts +++ b/packages/compiler/src/i18n/message_bundle.ts @@ -47,7 +47,9 @@ export class MessageBundle { // Return the message in the internal format // The public (serialized) format might be different, see the `write` method. - getMessages(): i18n.Message[] { return this._messages; } + getMessages(): i18n.Message[] { + return this._messages; + } write(serializer: Serializer, filterSources?: (path: string) => string): string { const messages: {[id: string]: i18n.Message} = {}; @@ -88,18 +90,18 @@ class MapPlaceholderNames extends i18n.CloneVisitor { } visitTagPlaceholder(ph: i18n.TagPlaceholder, mapper: PlaceholderMapper): i18n.TagPlaceholder { - const startName = mapper.toPublicName(ph.startName) !; - const closeName = ph.closeName ? mapper.toPublicName(ph.closeName) ! : ph.closeName; + const startName = mapper.toPublicName(ph.startName)!; + const closeName = ph.closeName ? mapper.toPublicName(ph.closeName)! : ph.closeName; const children = ph.children.map(n => n.visit(this, mapper)); return new i18n.TagPlaceholder( ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan); } visitPlaceholder(ph: i18n.Placeholder, mapper: PlaceholderMapper): i18n.Placeholder { - return new i18n.Placeholder(ph.value, mapper.toPublicName(ph.name) !, ph.sourceSpan); + return new i18n.Placeholder(ph.value, mapper.toPublicName(ph.name)!, ph.sourceSpan); } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, mapper: PlaceholderMapper): i18n.IcuPlaceholder { - return new i18n.IcuPlaceholder(ph.value, mapper.toPublicName(ph.name) !, ph.sourceSpan); + return new i18n.IcuPlaceholder(ph.value, mapper.toPublicName(ph.name)!, ph.sourceSpan); } } diff --git a/packages/compiler/src/i18n/parse_util.ts b/packages/compiler/src/i18n/parse_util.ts index 37acd859ac61d..0a02a5b4169bf 100644 --- a/packages/compiler/src/i18n/parse_util.ts +++ b/packages/compiler/src/i18n/parse_util.ts @@ -12,5 +12,7 @@ import {ParseError, ParseSourceSpan} from '../parse_util'; * An i18n error. */ export class I18nError extends ParseError { - constructor(span: ParseSourceSpan, msg: string) { super(span, msg); } + constructor(span: ParseSourceSpan, msg: string) { + super(span, msg); + } } diff --git a/packages/compiler/src/i18n/serializers/placeholder.ts b/packages/compiler/src/i18n/serializers/placeholder.ts index def0996964c6d..34b131cb6b41e 100644 --- a/packages/compiler/src/i18n/serializers/placeholder.ts +++ b/packages/compiler/src/i18n/serializers/placeholder.ts @@ -106,7 +106,9 @@ export class PlaceholderRegistry { return start + strAttrs + end; } - private _hashClosingTag(tag: string): string { return this._hashTag(`/${tag}`, {}, false); } + private _hashClosingTag(tag: string): string { + return this._hashTag(`/${tag}`, {}, false); + } private _generateUniqueName(base: string): string { const seen = this._placeHolderNameCounts.hasOwnProperty(base); diff --git a/packages/compiler/src/i18n/serializers/serializer.ts b/packages/compiler/src/i18n/serializers/serializer.ts index 4fb7dc8aee6c1..5cca7d2543dc7 100644 --- a/packages/compiler/src/i18n/serializers/serializer.ts +++ b/packages/compiler/src/i18n/serializers/serializer.ts @@ -15,13 +15,15 @@ export abstract class Serializer { abstract write(messages: i18n.Message[], locale: string|null): string; abstract load(content: string, url: string): - {locale: string | null, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}}; + {locale: string|null, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}}; abstract digest(message: i18n.Message): string; // Creates a name mapper, see `PlaceholderMapper` // Returning `null` means that no name mapping is used. - createNameMapper(message: i18n.Message): PlaceholderMapper|null { return null; } + createNameMapper(message: i18n.Message): PlaceholderMapper|null { + return null; + } } /** @@ -61,7 +63,9 @@ export class SimplePlaceholderMapper extends i18n.RecurseVisitor implements Plac null; } - visitText(text: i18n.Text, context?: any): any { return null; } + visitText(text: i18n.Text, context?: any): any { + return null; + } visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): any { this.visitPlaceholderName(ph.startName); @@ -69,7 +73,9 @@ export class SimplePlaceholderMapper extends i18n.RecurseVisitor implements Plac this.visitPlaceholderName(ph.closeName); } - visitPlaceholder(ph: i18n.Placeholder, context?: any): any { this.visitPlaceholderName(ph.name); } + visitPlaceholder(ph: i18n.Placeholder, context?: any): any { + this.visitPlaceholderName(ph.name); + } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any { this.visitPlaceholderName(ph.name); diff --git a/packages/compiler/src/i18n/serializers/xliff.ts b/packages/compiler/src/i18n/serializers/xliff.ts index b546ce14e1936..732d4eecfb258 100644 --- a/packages/compiler/src/i18n/serializers/xliff.ts +++ b/packages/compiler/src/i18n/serializers/xliff.ts @@ -46,9 +46,9 @@ export class Xliff extends Serializer { new xml.CR(10), new xml.Tag( _CONTEXT_TAG, {'context-type': 'sourcefile'}, [new xml.Text(source.filePath)]), - new xml.CR(10), new xml.Tag( - _CONTEXT_TAG, {'context-type': 'linenumber'}, - [new xml.Text(`${source.startLine}`)]), + new xml.CR(10), + new xml.Tag(_CONTEXT_TAG, {'context-type': 'linenumber'}, [new xml.Text( + `${source.startLine}`)]), new xml.CR(8)); contextTags.push(new xml.CR(8), contextGroupTag); }); @@ -112,14 +112,18 @@ export class Xliff extends Serializer { throw new Error(`xliff parse errors:\n${errors.join('\n')}`); } - return {locale: locale !, i18nNodesByMsgId}; + return {locale: locale!, i18nNodesByMsgId}; } - digest(message: i18n.Message): string { return digest(message); } + digest(message: i18n.Message): string { + return digest(message); + } } class _WriteVisitor implements i18n.Visitor { - visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; } + visitText(text: i18n.Text, context?: any): xml.Node[] { + return [new xml.Text(text.value)]; + } visitContainer(container: i18n.Container, context?: any): xml.Node[] { const nodes: xml.Node[] = []; @@ -161,8 +165,8 @@ class _WriteVisitor implements i18n.Visitor { } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): xml.Node[] { - const equivText = - `{${ph.value.expression}, ${ph.value.type}, ${Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ')}}`; + const equivText = `{${ph.value.expression}, ${ph.value.type}, ${ + Object.keys(ph.value.cases).map((value: string) => value + ' {...}').join(' ')}}`; return [new xml.Tag(_PLACEHOLDER_TAG, {id: ph.name, 'equiv-text': equivText})]; } @@ -175,11 +179,11 @@ class _WriteVisitor implements i18n.Visitor { // Extract messages as xml nodes from the xliff file class XliffParser implements ml.Visitor { // TODO(issue/24571): remove '!'. - private _unitMlString !: string | null; + private _unitMlString!: string|null; // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; // TODO(issue/24571): remove '!'. - private _msgIdToHtml !: {[msgId: string]: string}; + private _msgIdToHtml!: {[msgId: string]: string}; private _locale: string|null = null; parse(xliff: string, url: string) { @@ -201,7 +205,7 @@ class XliffParser implements ml.Visitor { visitElement(element: ml.Element, context: any): any { switch (element.name) { case _UNIT_TAG: - this._unitMlString = null !; + this._unitMlString = null!; const idAttr = element.attrs.find((attr) => attr.name === 'id'); if (!idAttr) { this._addError(element, `<${_UNIT_TAG}> misses the "id" attribute`); @@ -227,9 +231,9 @@ class XliffParser implements ml.Visitor { break; case _TARGET_TAG: - const innerTextStart = element.startSourceSpan !.end.offset; - const innerTextEnd = element.endSourceSpan !.start.offset; - const content = element.startSourceSpan !.start.file.content; + const innerTextStart = element.startSourceSpan!.end.offset; + const innerTextEnd = element.endSourceSpan!.start.offset; + const content = element.startSourceSpan!.start.file.content; const innerText = content.slice(innerTextStart, innerTextEnd); this._unitMlString = innerText; break; @@ -260,14 +264,14 @@ class XliffParser implements ml.Visitor { visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {} private _addError(node: ml.Node, message: string): void { - this._errors.push(new I18nError(node.sourceSpan !, message)); + this._errors.push(new I18nError(node.sourceSpan!, message)); } } // Convert ml nodes (xliff syntax) to i18n nodes class XmlToI18n implements ml.Visitor { // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; convert(message: string, url: string) { const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true}); @@ -283,13 +287,15 @@ class XmlToI18n implements ml.Visitor { }; } - visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan !); } + visitText(text: ml.Text, context: any) { + return new i18n.Text(text.value, text.sourceSpan!); + } visitElement(el: ml.Element, context: any): i18n.Placeholder|ml.Node[]|null { if (el.name === _PLACEHOLDER_TAG) { const nameAttr = el.attrs.find((attr) => attr.name === 'id'); if (nameAttr) { - return new i18n.Placeholder('', nameAttr.value, el.sourceSpan !); + return new i18n.Placeholder('', nameAttr.value, el.sourceSpan!); } this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "id" attribute`); @@ -326,7 +332,7 @@ class XmlToI18n implements ml.Visitor { visitAttribute(attribute: ml.Attribute, context: any) {} private _addError(node: ml.Node, message: string): void { - this._errors.push(new I18nError(node.sourceSpan !, message)); + this._errors.push(new I18nError(node.sourceSpan!, message)); } } diff --git a/packages/compiler/src/i18n/serializers/xliff2.ts b/packages/compiler/src/i18n/serializers/xliff2.ts index a8ba85d597c89..a0d62bc7dc176 100644 --- a/packages/compiler/src/i18n/serializers/xliff2.ts +++ b/packages/compiler/src/i18n/serializers/xliff2.ts @@ -54,8 +54,8 @@ export class Xliff2 extends Serializer { message.sources.forEach((source: i18n.MessageSpan) => { notes.children.push(new xml.CR(8), new xml.Tag('note', {category: 'location'}, [ - new xml.Text( - `${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`) + new xml.Text(`${source.filePath}:${source.startLine}${ + source.endLine !== source.startLine ? ',' + source.endLine : ''}`) ])); }); @@ -105,17 +105,21 @@ export class Xliff2 extends Serializer { throw new Error(`xliff2 parse errors:\n${errors.join('\n')}`); } - return {locale: locale !, i18nNodesByMsgId}; + return {locale: locale!, i18nNodesByMsgId}; } - digest(message: i18n.Message): string { return decimalDigest(message); } + digest(message: i18n.Message): string { + return decimalDigest(message); + } } class _WriteVisitor implements i18n.Visitor { // TODO(issue/24571): remove '!'. - private _nextPlaceholderId !: number; + private _nextPlaceholderId!: number; - visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; } + visitText(text: i18n.Text, context?: any): xml.Node[] { + return [new xml.Text(text.value)]; + } visitContainer(container: i18n.Container, context?: any): xml.Node[] { const nodes: xml.Node[] = []; @@ -192,11 +196,11 @@ class _WriteVisitor implements i18n.Visitor { // Extract messages as xml nodes from the xliff file class Xliff2Parser implements ml.Visitor { // TODO(issue/24571): remove '!'. - private _unitMlString !: string | null; + private _unitMlString!: string|null; // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; // TODO(issue/24571): remove '!'. - private _msgIdToHtml !: {[msgId: string]: string}; + private _msgIdToHtml!: {[msgId: string]: string}; private _locale: string|null = null; parse(xliff: string, url: string) { @@ -242,9 +246,9 @@ class Xliff2Parser implements ml.Visitor { break; case _TARGET_TAG: - const innerTextStart = element.startSourceSpan !.end.offset; - const innerTextEnd = element.endSourceSpan !.start.offset; - const content = element.startSourceSpan !.start.file.content; + const innerTextStart = element.startSourceSpan!.end.offset; + const innerTextEnd = element.endSourceSpan!.start.offset; + const content = element.startSourceSpan!.start.file.content; const innerText = content.slice(innerTextStart, innerTextEnd); this._unitMlString = innerText; break; @@ -290,7 +294,7 @@ class Xliff2Parser implements ml.Visitor { // Convert ml nodes (xliff syntax) to i18n nodes class XmlToI18n implements ml.Visitor { // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; convert(message: string, url: string) { const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true}); @@ -306,7 +310,9 @@ class XmlToI18n implements ml.Visitor { }; } - visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan); } + visitText(text: ml.Text, context: any) { + return new i18n.Text(text.value, text.sourceSpan); + } visitElement(el: ml.Element, context: any): i18n.Node[]|null { switch (el.name) { diff --git a/packages/compiler/src/i18n/serializers/xmb.ts b/packages/compiler/src/i18n/serializers/xmb.ts index eeddddc869e38..a12e785506d2d 100644 --- a/packages/compiler/src/i18n/serializers/xmb.ts +++ b/packages/compiler/src/i18n/serializers/xmb.ts @@ -57,10 +57,10 @@ export class Xmb extends Serializer { let sourceTags: xml.Tag[] = []; message.sources.forEach((source: i18n.MessageSpan) => { - sourceTags.push(new xml.Tag(_SOURCE_TAG, {}, [ - new xml.Text( - `${source.filePath}:${source.startLine}${source.endLine !== source.startLine ? ',' + source.endLine : ''}`) - ])); + sourceTags.push(new xml.Tag( + _SOURCE_TAG, {}, + [new xml.Text(`${source.filePath}:${source.startLine}${ + source.endLine !== source.startLine ? ',' + source.endLine : ''}`)])); }); rootNode.children.push( @@ -85,7 +85,9 @@ export class Xmb extends Serializer { throw new Error('Unsupported'); } - digest(message: i18n.Message): string { return digest(message); } + digest(message: i18n.Message): string { + return digest(message); + } createNameMapper(message: i18n.Message): PlaceholderMapper { @@ -94,7 +96,9 @@ export class Xmb extends Serializer { } class _Visitor implements i18n.Visitor { - visitText(text: i18n.Text, context?: any): xml.Node[] { return [new xml.Text(text.value)]; } + visitText(text: i18n.Text, context?: any): xml.Node[] { + return [new xml.Text(text.value)]; + } visitContainer(container: i18n.Container, context: any): xml.Node[] { const nodes: xml.Node[] = []; diff --git a/packages/compiler/src/i18n/serializers/xml_helper.ts b/packages/compiler/src/i18n/serializers/xml_helper.ts index 27a8d10c5a8f7..6863cce5df897 100644 --- a/packages/compiler/src/i18n/serializers/xml_helper.ts +++ b/packages/compiler/src/i18n/serializers/xml_helper.ts @@ -25,7 +25,9 @@ class _Visitor implements IVisitor { return `<${tag.name}${strAttrs}>${strChildren.join('')}</${tag.name}>`; } - visitText(text: Text): string { return text.value; } + visitText(text: Text): string { + return text.value; + } visitDeclaration(decl: Declaration): string { return `<?xml${this._serializeAttributes(decl.attrs)} ?>`; @@ -47,7 +49,9 @@ export function serialize(nodes: Node[]): string { return nodes.map((node: Node): string => node.visit(_visitor)).join(''); } -export interface Node { visit(visitor: IVisitor): any; } +export interface Node { + visit(visitor: IVisitor): any; +} export class Declaration implements Node { public attrs: {[k: string]: string} = {}; @@ -58,13 +62,17 @@ export class Declaration implements Node { }); } - visit(visitor: IVisitor): any { return visitor.visitDeclaration(this); } + visit(visitor: IVisitor): any { + return visitor.visitDeclaration(this); + } } export class Doctype implements Node { constructor(public rootTag: string, public dtd: string) {} - visit(visitor: IVisitor): any { return visitor.visitDoctype(this); } + visit(visitor: IVisitor): any { + return visitor.visitDoctype(this); + } } export class Tag implements Node { @@ -78,18 +86,26 @@ export class Tag implements Node { }); } - visit(visitor: IVisitor): any { return visitor.visitTag(this); } + visit(visitor: IVisitor): any { + return visitor.visitTag(this); + } } export class Text implements Node { value: string; - constructor(unescapedValue: string) { this.value = escapeXml(unescapedValue); } + constructor(unescapedValue: string) { + this.value = escapeXml(unescapedValue); + } - visit(visitor: IVisitor): any { return visitor.visitText(this); } + visit(visitor: IVisitor): any { + return visitor.visitText(this); + } } export class CR extends Text { - constructor(ws: number = 0) { super(`\n${new Array(ws + 1).join(' ')}`); } + constructor(ws: number = 0) { + super(`\n${new Array(ws + 1).join(' ')}`); + } } const _ESCAPED_CHARS: [RegExp, string][] = [ diff --git a/packages/compiler/src/i18n/serializers/xtb.ts b/packages/compiler/src/i18n/serializers/xtb.ts index 441c03fa049e0..dede3078827f9 100644 --- a/packages/compiler/src/i18n/serializers/xtb.ts +++ b/packages/compiler/src/i18n/serializers/xtb.ts @@ -19,7 +19,9 @@ const _TRANSLATION_TAG = 'translation'; const _PLACEHOLDER_TAG = 'ph'; export class Xtb extends Serializer { - write(messages: i18n.Message[], locale: string|null): string { throw new Error('Unsupported'); } + write(messages: i18n.Message[], locale: string|null): string { + throw new Error('Unsupported'); + } load(content: string, url: string): {locale: string, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}} { @@ -49,10 +51,12 @@ export class Xtb extends Serializer { throw new Error(`xtb parse errors:\n${errors.join('\n')}`); } - return {locale: locale !, i18nNodesByMsgId}; + return {locale: locale!, i18nNodesByMsgId}; } - digest(message: i18n.Message): string { return digest(message); } + digest(message: i18n.Message): string { + return digest(message); + } createNameMapper(message: i18n.Message): PlaceholderMapper { return new SimplePlaceholderMapper(message, toPublicName); @@ -68,18 +72,20 @@ function createLazyProperty(messages: any, id: string, valueFn: () => any) { Object.defineProperty(messages, id, {enumerable: true, value}); return value; }, - set: _ => { throw new Error('Could not overwrite an XTB translation'); }, + set: _ => { + throw new Error('Could not overwrite an XTB translation'); + }, }); } // Extract messages as xml nodes from the xtb file class XtbParser implements ml.Visitor { // TODO(issue/24571): remove '!'. - private _bundleDepth !: number; + private _bundleDepth!: number; // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; // TODO(issue/24571): remove '!'. - private _msgIdToHtml !: {[msgId: string]: string}; + private _msgIdToHtml!: {[msgId: string]: string}; private _locale: string|null = null; parse(xtb: string, url: string) { @@ -124,10 +130,10 @@ class XtbParser implements ml.Visitor { if (this._msgIdToHtml.hasOwnProperty(id)) { this._addError(element, `Duplicated translations for msg ${id}`); } else { - const innerTextStart = element.startSourceSpan !.end.offset; - const innerTextEnd = element.endSourceSpan !.start.offset; - const content = element.startSourceSpan !.start.file.content; - const innerText = content.slice(innerTextStart !, innerTextEnd !); + const innerTextStart = element.startSourceSpan!.end.offset; + const innerTextEnd = element.endSourceSpan!.start.offset; + const content = element.startSourceSpan!.start.file.content; + const innerText = content.slice(innerTextStart!, innerTextEnd!); this._msgIdToHtml[id] = innerText; } } @@ -149,14 +155,14 @@ class XtbParser implements ml.Visitor { visitExpansionCase(expansionCase: ml.ExpansionCase, context: any): any {} private _addError(node: ml.Node, message: string): void { - this._errors.push(new I18nError(node.sourceSpan !, message)); + this._errors.push(new I18nError(node.sourceSpan!, message)); } } // Convert ml nodes (xtb syntax) to i18n nodes class XmlToI18n implements ml.Visitor { // TODO(issue/24571): remove '!'. - private _errors !: I18nError[]; + private _errors!: I18nError[]; convert(message: string, url: string) { const xmlIcu = new XmlParser().parse(message, url, {tokenizeExpansionForms: true}); @@ -172,7 +178,9 @@ class XmlToI18n implements ml.Visitor { }; } - visitText(text: ml.Text, context: any) { return new i18n.Text(text.value, text.sourceSpan !); } + visitText(text: ml.Text, context: any) { + return new i18n.Text(text.value, text.sourceSpan!); + } visitExpansion(icu: ml.Expansion, context: any) { const caseMap: {[value: string]: i18n.Node} = {}; @@ -195,7 +203,7 @@ class XmlToI18n implements ml.Visitor { if (el.name === _PLACEHOLDER_TAG) { const nameAttr = el.attrs.find((attr) => attr.name === 'name'); if (nameAttr) { - return new i18n.Placeholder('', nameAttr.value, el.sourceSpan !); + return new i18n.Placeholder('', nameAttr.value, el.sourceSpan!); } this._addError(el, `<${_PLACEHOLDER_TAG}> misses the "name" attribute`); @@ -210,6 +218,6 @@ class XmlToI18n implements ml.Visitor { visitAttribute(attribute: ml.Attribute, context: any) {} private _addError(node: ml.Node, message: string): void { - this._errors.push(new I18nError(node.sourceSpan !, message)); + this._errors.push(new I18nError(node.sourceSpan!, message)); } } diff --git a/packages/compiler/src/i18n/translation_bundle.ts b/packages/compiler/src/i18n/translation_bundle.ts index 30da42a421061..62bfb357e9c13 100644 --- a/packages/compiler/src/i18n/translation_bundle.ts +++ b/packages/compiler/src/i18n/translation_bundle.ts @@ -30,7 +30,7 @@ export class TranslationBundle { missingTranslationStrategy: MissingTranslationStrategy = MissingTranslationStrategy.Warning, console?: Console) { this._i18nToHtml = new I18nToHtmlVisitor( - _i18nNodesByMsgId, locale, digest, mapperFactory !, missingTranslationStrategy, console); + _i18nNodesByMsgId, locale, digest, mapperFactory!, missingTranslationStrategy, console); } // Creates a `TranslationBundle` by parsing the given `content` with the `serializer`. @@ -40,7 +40,7 @@ export class TranslationBundle { console?: Console): TranslationBundle { const {locale, i18nNodesByMsgId} = serializer.load(content, url); const digestFn = (m: i18n.Message) => serializer.digest(m); - const mapperFactory = (m: i18n.Message) => serializer.createNameMapper(m) !; + const mapperFactory = (m: i18n.Message) => serializer.createNameMapper(m)!; return new TranslationBundle( i18nNodesByMsgId, locale, digestFn, mapperFactory, missingTranslationStrategy, console); } @@ -56,16 +56,18 @@ export class TranslationBundle { return html.nodes; } - has(srcMsg: i18n.Message): boolean { return this.digest(srcMsg) in this._i18nNodesByMsgId; } + has(srcMsg: i18n.Message): boolean { + return this.digest(srcMsg) in this._i18nNodesByMsgId; + } } class I18nToHtmlVisitor implements i18n.Visitor { // TODO(issue/24571): remove '!'. - private _srcMsg !: i18n.Message; + private _srcMsg!: i18n.Message; private _contextStack: {msg: i18n.Message, mapper: (name: string) => string}[] = []; private _errors: I18nError[] = []; // TODO(issue/24571): remove '!'. - private _mapper !: (name: string) => string; + private _mapper!: (name: string) => string; constructor( private _i18nNodesByMsgId: {[msgId: string]: i18n.Node[]} = {}, private _locale: string|null, @@ -166,7 +168,7 @@ class I18nToHtmlVisitor implements i18n.Visitor { // When there is a translation use its nodes as the source // And create a mapper to convert serialized placeholder names to internal names nodes = this._i18nNodesByMsgId[id]; - this._mapper = (name: string) => mapper ? mapper.toInternalName(name) ! : name; + this._mapper = (name: string) => mapper ? mapper.toInternalName(name)! : name; } else { // When no translation has been found // - report an error / a warning / nothing, @@ -185,7 +187,7 @@ class I18nToHtmlVisitor implements i18n.Visitor { this._mapper = (name: string) => name; } const text = nodes.map(node => node.visit(this)).join(''); - const context = this._contextStack.pop() !; + const context = this._contextStack.pop()!; this._srcMsg = context.msg; this._mapper = context.mapper; return text; diff --git a/packages/compiler/src/injectable_compiler.ts b/packages/compiler/src/injectable_compiler.ts index 6018fb88090e5..d503c868b46ef 100644 --- a/packages/compiler/src/injectable_compiler.ts +++ b/packages/compiler/src/injectable_compiler.ts @@ -121,7 +121,7 @@ export class InjectableCompiler { compile(injectable: CompileInjectableMetadata, ctx: OutputContext): void { if (this.alwaysGenerateDef || injectable.providedIn !== undefined) { - const className = identifierName(injectable.type) !; + const className = identifierName(injectable.type)!; const clazz = new o.ClassStmt( className, null, [ diff --git a/packages/compiler/src/injectable_compiler_2.ts b/packages/compiler/src/injectable_compiler_2.ts index b3b0a2221b684..6fbe107c1656d 100644 --- a/packages/compiler/src/injectable_compiler_2.ts +++ b/packages/compiler/src/injectable_compiler_2.ts @@ -8,8 +8,8 @@ import {Identifiers} from './identifiers'; import * as o from './output/output_ast'; -import {R3DependencyMetadata, R3FactoryDelegateType, R3FactoryMetadata, R3FactoryTarget, compileFactoryFunction} from './render3/r3_factory'; -import {R3Reference, mapToMapExpression, typeWithParameters} from './render3/util'; +import {compileFactoryFunction, R3DependencyMetadata, R3FactoryDelegateType, R3FactoryMetadata, R3FactoryTarget} from './render3/r3_factory'; +import {mapToMapExpression, R3Reference, typeWithParameters} from './render3/util'; export interface InjectableDef { expression: o.Expression; diff --git a/packages/compiler/src/jit/compiler.ts b/packages/compiler/src/jit/compiler.ts index 8fd53b03c8834..ed6d8da08e6b0 100644 --- a/packages/compiler/src/jit/compiler.ts +++ b/packages/compiler/src/jit/compiler.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileTypeSummary, ProviderMeta, ProxyClass, identifierName, ngModuleJitUrl, sharedStylesheetJitUrl, templateJitUrl, templateSourceUrl} from '../compile_metadata'; +import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeSummary, CompileProviderMetadata, CompileStylesheetMetadata, CompileTypeSummary, identifierName, ngModuleJitUrl, ProviderMeta, ProxyClass, sharedStylesheetJitUrl, templateJitUrl, templateSourceUrl} from '../compile_metadata'; import {CompileReflector} from '../compile_reflector'; import {CompilerConfig} from '../config'; import {ConstantPool} from '../constant_pool'; @@ -20,7 +20,7 @@ import {CompiledStylesheet, StyleCompiler} from '../style_compiler'; import {SummaryResolver} from '../summary_resolver'; import {TemplateAst} from '../template_parser/template_ast'; import {TemplateParser} from '../template_parser/template_parser'; -import {Console, OutputContext, SyncAsync, stringify} from '../util'; +import {Console, OutputContext, stringify, SyncAsync} from '../util'; import {ViewCompiler} from '../view_compiler/view_compiler'; export interface ModuleWithComponentFactories { @@ -97,7 +97,9 @@ export class JitCompiler { } } - hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); } + hasAotSummary(ref: Type) { + return !!this._summaryResolver.resolveSummary(ref); + } private _filterJitIdentifiers(ids: CompileIdentifierMetadata[]): any[] { return ids.map(mod => mod.reference).filter((ref) => !this.hasAotSummary(ref)); @@ -124,12 +126,12 @@ export class JitCompiler { private _loadModules(mainModule: any, isSync: boolean): SyncAsync<any> { const loading: Promise<any>[] = []; - const mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule) !; + const mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule)!; // Note: for runtime compilation, we want to transitively compile all modules, // so we also need to load the declared directives / pipes for all nested modules. this._filterJitIdentifiers(mainNgModule.transitiveModule.modules).forEach((nestedNgModule) => { // getNgModuleMetadata only returns null if the value passed in is not an NgModule - const moduleMeta = this._metadataResolver.getNgModuleMetadata(nestedNgModule) !; + const moduleMeta = this._metadataResolver.getNgModuleMetadata(nestedNgModule)!; this._filterJitIdentifiers(moduleMeta.declaredDirectives).forEach((ref) => { const promise = this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync); @@ -144,9 +146,9 @@ export class JitCompiler { } private _compileModule(moduleType: Type): object { - let ngModuleFactory = this._compiledNgModuleCache.get(moduleType) !; + let ngModuleFactory = this._compiledNgModuleCache.get(moduleType)!; if (!ngModuleFactory) { - const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType) !; + const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType)!; // Always provide a bound Compiler const extraProviders = this.getExtraNgModuleProviders(moduleMeta.type.reference); const outputCtx = createOutputContext(); @@ -162,13 +164,13 @@ export class JitCompiler { * @internal */ _compileComponents(mainModule: Type, allComponentFactories: object[]|null) { - const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule) !; + const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule)!; const moduleByJitDirective = new Map<any, CompileNgModuleMetadata>(); const templates = new Set<CompiledTemplate>(); const transJitModules = this._filterJitIdentifiers(ngModule.transitiveModule.modules); transJitModules.forEach((localMod) => { - const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod) !; + const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod)!; this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => { moduleByJitDirective.set(dirRef, localModuleMeta); const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef); @@ -184,12 +186,12 @@ export class JitCompiler { }); }); transJitModules.forEach((localMod) => { - const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod) !; + const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod)!; this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => { const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef); if (dirMeta.isComponent) { dirMeta.entryComponents.forEach((entryComponentType) => { - const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType) !; + const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType)!; templates.add( this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta)); }); @@ -197,7 +199,7 @@ export class JitCompiler { }); localModuleMeta.entryComponents.forEach((entryComponentType) => { if (!this.hasAotSummary(entryComponentType.componentType)) { - const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType) !; + const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType)!; templates.add( this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta)); } @@ -227,8 +229,9 @@ export class JitCompiler { private _createCompiledHostTemplate(compType: Type, ngModule: CompileNgModuleMetadata): CompiledTemplate { if (!ngModule) { - throw new Error( - `Component ${stringify(compType)} is not part of any NgModule or the module has not been imported into your module.`); + throw new Error(`Component ${ + stringify( + compType)} is not part of any NgModule or the module has not been imported into your module.`); } let compiledTemplate = this._compiledHostTemplateCache.get(compType); if (!compiledTemplate) { @@ -267,7 +270,7 @@ export class JitCompiler { compMeta.template !.externalStylesheets.forEach((stylesheetMeta) => { const compiledStylesheet = this._styleCompiler.compileStyles(createOutputContext(), compMeta, stylesheetMeta); - externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl !, compiledStylesheet); + externalStylesheetsByModuleUrl.set(stylesheetMeta.moduleUrl!, compiledStylesheet); }); this._resolveStylesCompileResult(componentStylesheet, externalStylesheetsByModuleUrl); const pipes = template.ngModule.transitiveModule.pipes.map( @@ -295,14 +298,14 @@ export class JitCompiler { const pipes = ngModule.transitiveModule.pipes.map( pipe => this._metadataResolver.getPipeSummary(pipe.reference)); return this._templateParser.parse( - compMeta, compMeta.template !.htmlAst !, directives, pipes, ngModule.schemas, + compMeta, compMeta.template !.htmlAst!, directives, pipes, ngModule.schemas, templateSourceUrl(ngModule.type, compMeta, compMeta.template !), preserveWhitespaces); } private _resolveStylesCompileResult( result: CompiledStylesheet, externalStylesheetsByModuleUrl: Map<string, CompiledStylesheet>) { result.dependencies.forEach((dep, i) => { - const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl) !; + const nestedCompileResult = externalStylesheetsByModuleUrl.get(dep.moduleUrl)!; const nestedStylesArr = this._resolveAndEvalStylesCompileResult( nestedCompileResult, externalStylesheetsByModuleUrl); dep.setValue(nestedStylesArr); @@ -329,7 +332,7 @@ export class JitCompiler { } class CompiledTemplate { - private _viewClass: Function = null !; + private _viewClass: Function = null!; isCompiled = false; constructor( diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index 172eaa2a3f736..f2fb2c85591a6 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -16,13 +16,13 @@ import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './ml_parser/int import {DeclareVarStmt, Expression, LiteralExpr, Statement, StmtModifier, WrappedNodeExpr} from './output/output_ast'; import {JitEvaluator} from './output/output_jit'; import {ParseError, ParseSourceSpan, r3JitTypeSourceSpan} from './parse_util'; -import {R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType, compileFactoryFunction} from './render3/r3_factory'; +import {compileFactoryFunction, R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType} from './render3/r3_factory'; import {R3JitReflector} from './render3/r3_jit'; -import {R3InjectorMetadata, R3NgModuleMetadata, compileInjector, compileNgModule} from './render3/r3_module_compiler'; -import {R3PipeMetadata, compilePipeFromMetadata} from './render3/r3_pipe_compiler'; +import {compileInjector, compileNgModule, R3InjectorMetadata, R3NgModuleMetadata} from './render3/r3_module_compiler'; +import {compilePipeFromMetadata, R3PipeMetadata} from './render3/r3_pipe_compiler'; import {R3Reference} from './render3/util'; import {R3DirectiveMetadata, R3QueryMetadata} from './render3/view/api'; -import {ParsedHostBindings, compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, verifyHostBindings} from './render3/view/compiler'; +import {compileComponentFromMetadata, compileDirectiveFromMetadata, ParsedHostBindings, parseHostBindings, verifyHostBindings} from './render3/view/compiler'; import {makeBindingParser, parseTemplate} from './render3/view/template'; import {ResourceLoader} from './resource_loader'; import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry'; @@ -277,7 +277,7 @@ function wrapExpression(obj: any, property: string): WrappedNodeExpr<any>|undefi } } -function computeProvidedIn(providedIn: Type | string | null | undefined): Expression { +function computeProvidedIn(providedIn: Type|string|null|undefined): Expression { if (providedIn == null || typeof providedIn === 'string') { return new LiteralExpr(providedIn); } else { @@ -305,8 +305,8 @@ function convertR3DependencyMetadata(facade: R3DependencyMetadataFacade): R3Depe }; } -function convertR3DependencyMetadataArray(facades: R3DependencyMetadataFacade[] | null | undefined): - R3DependencyMetadata[]|null { +function convertR3DependencyMetadataArray(facades: R3DependencyMetadataFacade[]|null| + undefined): R3DependencyMetadata[]|null { return facades == null ? null : facades.map(convertR3DependencyMetadata); } @@ -356,13 +356,11 @@ function isOutput(value: any): value is Output { } function parseInputOutputs(values: string[]): StringMap { - return values.reduce( - (map, value) => { - const [field, property] = value.split(',').map(piece => piece.trim()); - map[field] = property || field; - return map; - }, - {} as StringMap); + return values.reduce((map, value) => { + const [field, property] = value.split(',').map(piece => piece.trim()); + map[field] = property || field; + return map; + }, {} as StringMap); } export function publishFacade(global: any) { diff --git a/packages/compiler/src/metadata_resolver.ts b/packages/compiler/src/metadata_resolver.ts index b5e28006a330c..ff85eb216c00d 100644 --- a/packages/compiler/src/metadata_resolver.ts +++ b/packages/compiler/src/metadata_resolver.ts @@ -12,7 +12,7 @@ import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions'; import * as cpl from './compile_metadata'; import {CompileReflector} from './compile_reflector'; import {CompilerConfig} from './config'; -import {ChangeDetectionStrategy, Component, Directive, Injectable, ModuleWithProviders, Provider, Query, SchemaMetadata, Type, ViewEncapsulation, createAttribute, createComponent, createHost, createInject, createInjectable, createInjectionToken, createNgModule, createOptional, createSelf, createSkipSelf} from './core'; +import {ChangeDetectionStrategy, Component, createAttribute, createComponent, createHost, createInject, createInjectable, createInjectionToken, createNgModule, createOptional, createSelf, createSkipSelf, Directive, Injectable, ModuleWithProviders, Provider, Query, SchemaMetadata, Type, ViewEncapsulation} from './core'; import {DirectiveNormalizer} from './directive_normalizer'; import {DirectiveResolver, findLast} from './directive_resolver'; import {Identifiers} from './identifiers'; @@ -23,7 +23,7 @@ import {PipeResolver} from './pipe_resolver'; import {ElementSchemaRegistry} from './schema/element_schema_registry'; import {CssSelector} from './selector'; import {SummaryResolver} from './summary_resolver'; -import {Console, SyncAsync, ValueTransformer, isPromise, noUndefined, resolveForwardRef, stringify, syntaxError, visitValue} from './util'; +import {Console, isPromise, noUndefined, resolveForwardRef, stringify, SyncAsync, syntaxError, ValueTransformer, visitValue} from './util'; export type ErrorCollector = (error: any, type?: any) => void; @@ -55,7 +55,9 @@ export class CompileMetadataResolver { private _staticSymbolCache: StaticSymbolCache, private _reflector: CompileReflector, private _errorCollector?: ErrorCollector) {} - getReflector(): CompileReflector { return this._reflector; } + getReflector(): CompileReflector { + return this._reflector; + } clearCacheFor(type: Type) { const dirMeta = this._directiveCache.get(type); @@ -176,7 +178,7 @@ export class CompileMetadataResolver { } // Note: ! is ok here as this method should only be called with normalized directive // metadata, which always fills in the selector. - const template = CssSelector.parse(compMeta.selector !)[0].getMatchingElementTemplate(); + const template = CssSelector.parse(compMeta.selector!)[0].getMatchingElementTemplate(); const templateUrl = ''; const htmlAst = this._htmlParser.parse(template, templateUrl); return cpl.CompileDirectiveMetadata.create({ @@ -209,8 +211,8 @@ export class CompileMetadataResolver { guards: {}, viewQueries: [], componentViewType: hostViewType, - rendererType: - {id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {}} as object, + rendererType: {id: '__Host__', encapsulation: ViewEncapsulation.None, styles: [], data: {}} as + object, entryComponents: [], componentFactory: null }); @@ -221,9 +223,9 @@ export class CompileMetadataResolver { return null; } directiveType = resolveForwardRef(directiveType); - const {annotation, metadata} = this.getNonNormalizedDirectiveMetadata(directiveType) !; + const {annotation, metadata} = this.getNonNormalizedDirectiveMetadata(directiveType)!; - const createDirectiveMetadata = (templateMetadata: cpl.CompileTemplateMetadata | null) => { + const createDirectiveMetadata = (templateMetadata: cpl.CompileTemplateMetadata|null) => { const normalizedDirMeta = new cpl.CompileDirectiveMetadata({ isHost: false, type: metadata.type, @@ -248,7 +250,7 @@ export class CompileMetadataResolver { template: templateMetadata }); if (templateMetadata) { - this.initComponentFactory(metadata.componentFactory !, templateMetadata.ngContentSelectors); + this.initComponentFactory(metadata.componentFactory!, templateMetadata.ngContentSelectors); } this._directiveCache.set(directiveType, normalizedDirMeta); this._summaryCache.set(directiveType, normalizedDirMeta.toSummary()); @@ -296,7 +298,7 @@ export class CompileMetadataResolver { if (!dirMeta) { return null; } - let nonNormalizedTemplateMetadata: cpl.CompileTemplateMetadata = undefined !; + let nonNormalizedTemplateMetadata: cpl.CompileTemplateMetadata = undefined!; if (createComponent.isTypeOf(dirMeta)) { // component @@ -323,7 +325,7 @@ export class CompileMetadataResolver { }); } - let changeDetectionStrategy: ChangeDetectionStrategy = null !; + let changeDetectionStrategy: ChangeDetectionStrategy = null!; let viewProviders: cpl.CompileProviderMetadata[] = []; let entryComponentMetadata: cpl.CompileEntryComponentMetadata[] = []; let selector = dirMeta.selector; @@ -331,7 +333,7 @@ export class CompileMetadataResolver { if (createComponent.isTypeOf(dirMeta)) { // Component const compMeta = dirMeta as Component; - changeDetectionStrategy = compMeta.changeDetection !; + changeDetectionStrategy = compMeta.changeDetection!; if (compMeta.viewProviders) { viewProviders = this._getProvidersMetadata( compMeta.viewProviders, entryComponentMetadata, @@ -339,7 +341,7 @@ export class CompileMetadataResolver { } if (compMeta.entryComponents) { entryComponentMetadata = flattenAndDedupeArray(compMeta.entryComponents) - .map((type) => this._getEntryComponentMetadata(type) !) + .map((type) => this._getEntryComponentMetadata(type)!) .concat(entryComponentMetadata); } if (!selector) { @@ -348,7 +350,7 @@ export class CompileMetadataResolver { } else { // Directive if (!selector) { - selector = null !; + selector = null!; } } @@ -401,11 +403,12 @@ export class CompileMetadataResolver { * This assumes `loadNgModuleDirectiveAndPipeMetadata` has been called first. */ getDirectiveMetadata(directiveType: any): cpl.CompileDirectiveMetadata { - const dirMeta = this._directiveCache.get(directiveType) !; + const dirMeta = this._directiveCache.get(directiveType)!; if (!dirMeta) { this._reportError( syntaxError( - `Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${stringifyType(directiveType)}.`), + `Illegal state: getDirectiveMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Directive ${ + stringifyType(directiveType)}.`), directiveType); } return dirMeta; @@ -530,7 +533,7 @@ export class CompileMetadataResolver { if (meta.imports) { flattenAndDedupeArray(meta.imports).forEach((importedType) => { - let importedModuleType: Type = undefined !; + let importedModuleType: Type = undefined!; if (isValidType(importedType)) { importedModuleType = importedType; } else if (importedType && importedType.ngModule) { @@ -549,8 +552,9 @@ export class CompileMetadataResolver { if (!alreadyCollecting) alreadyCollecting = new Set(); if (alreadyCollecting.has(importedModuleType)) { this._reportError( - syntaxError( - `${this._getTypeDescriptor(importedModuleType)} '${stringifyType(importedType)}' is imported recursively by the module '${stringifyType(moduleType)}'.`), + syntaxError(`${this._getTypeDescriptor(importedModuleType)} '${ + stringifyType(importedType)}' is imported recursively by the module '${ + stringifyType(moduleType)}'.`), moduleType); return; } @@ -560,8 +564,9 @@ export class CompileMetadataResolver { alreadyCollecting.delete(importedModuleType); if (!importedModuleSummary) { this._reportError( - syntaxError( - `Unexpected ${this._getTypeDescriptor(importedType)} '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'. Please add a @NgModule annotation.`), + syntaxError(`Unexpected ${this._getTypeDescriptor(importedType)} '${ + stringifyType(importedType)}' imported by the module '${ + stringifyType(moduleType)}'. Please add a @NgModule annotation.`), moduleType); return; } @@ -569,7 +574,8 @@ export class CompileMetadataResolver { } else { this._reportError( syntaxError( - `Unexpected value '${stringifyType(importedType)}' imported by the module '${stringifyType(moduleType)}'`), + `Unexpected value '${stringifyType(importedType)}' imported by the module '${ + stringifyType(moduleType)}'`), moduleType); return; } @@ -581,15 +587,17 @@ export class CompileMetadataResolver { if (!isValidType(exportedType)) { this._reportError( syntaxError( - `Unexpected value '${stringifyType(exportedType)}' exported by the module '${stringifyType(moduleType)}'`), + `Unexpected value '${stringifyType(exportedType)}' exported by the module '${ + stringifyType(moduleType)}'`), moduleType); return; } if (!alreadyCollecting) alreadyCollecting = new Set(); if (alreadyCollecting.has(exportedType)) { this._reportError( - syntaxError( - `${this._getTypeDescriptor(exportedType)} '${stringify(exportedType)}' is exported recursively by the module '${stringifyType(moduleType)}'`), + syntaxError(`${this._getTypeDescriptor(exportedType)} '${ + stringify(exportedType)}' is exported recursively by the module '${ + stringifyType(moduleType)}'`), moduleType); return; } @@ -612,7 +620,8 @@ export class CompileMetadataResolver { if (!isValidType(declaredType)) { this._reportError( syntaxError( - `Unexpected value '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'`), + `Unexpected value '${stringifyType(declaredType)}' declared by the module '${ + stringifyType(moduleType)}'`), moduleType); return; } @@ -634,8 +643,10 @@ export class CompileMetadataResolver { this._addTypeToModule(declaredType, moduleType); } else { this._reportError( - syntaxError( - `Unexpected ${this._getTypeDescriptor(declaredType)} '${stringifyType(declaredType)}' declared by the module '${stringifyType(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`), + syntaxError(`Unexpected ${this._getTypeDescriptor(declaredType)} '${ + stringifyType(declaredType)}' declared by the module '${ + stringifyType( + moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`), moduleType); return; } @@ -653,8 +664,9 @@ export class CompileMetadataResolver { transitiveModule.addExportedPipe(exportedId); } else { this._reportError( - syntaxError( - `Can't export ${this._getTypeDescriptor(exportedId.reference)} ${stringifyType(exportedId.reference)} from ${stringifyType(moduleType)} as it was neither declared nor imported!`), + syntaxError(`Can't export ${this._getTypeDescriptor(exportedId.reference)} ${ + stringifyType(exportedId.reference)} from ${ + stringifyType(moduleType)} as it was neither declared nor imported!`), moduleType); return; } @@ -670,15 +682,16 @@ export class CompileMetadataResolver { if (meta.entryComponents) { entryComponents.push(...flattenAndDedupeArray(meta.entryComponents) - .map(type => this._getEntryComponentMetadata(type) !)); + .map(type => this._getEntryComponentMetadata(type)!)); } if (meta.bootstrap) { flattenAndDedupeArray(meta.bootstrap).forEach(type => { if (!isValidType(type)) { this._reportError( - syntaxError( - `Unexpected value '${stringifyType(type)}' used in the bootstrap property of module '${stringifyType(moduleType)}'`), + syntaxError(`Unexpected value '${ + stringifyType(type)}' used in the bootstrap property of module '${ + stringifyType(moduleType)}'`), moduleType); return; } @@ -687,7 +700,7 @@ export class CompileMetadataResolver { } entryComponents.push( - ...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference) !)); + ...bootstrapComponents.map(type => this._getEntryComponentMetadata(type.reference)!)); if (meta.schemas) { schemas.push(...flattenAndDedupeArray(meta.schemas)); @@ -710,7 +723,7 @@ export class CompileMetadataResolver { }); entryComponents.forEach((id) => transitiveModule.addEntryComponent(id)); - providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta !.type)); + providers.forEach((provider) => transitiveModule.addProvider(provider, compileMeta!.type)); transitiveModule.addModule(compileMeta.type); this._ngModuleCache.set(moduleType, compileMeta); return compileMeta; @@ -753,9 +766,13 @@ export class CompileMetadataResolver { if (oldModule && oldModule !== moduleType) { this._reportError( syntaxError( - `Type ${stringifyType(type)} is part of the declarations of 2 modules: ${stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` + - `Please consider moving ${stringifyType(type)} to a higher module that imports ${stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` + - `You can also create a new NgModule that exports and includes ${stringifyType(type)} then import that NgModule in ${stringifyType(oldModule)} and ${stringifyType(moduleType)}.`), + `Type ${stringifyType(type)} is part of the declarations of 2 modules: ${ + stringifyType(oldModule)} and ${stringifyType(moduleType)}! ` + + `Please consider moving ${stringifyType(type)} to a higher module that imports ${ + stringifyType(oldModule)} and ${stringifyType(moduleType)}. ` + + `You can also create a new NgModule that exports and includes ${ + stringifyType(type)} then import that NgModule in ${ + stringifyType(oldModule)} and ${stringifyType(moduleType)}.`), moduleType); return; } @@ -870,7 +887,8 @@ export class CompileMetadataResolver { if (!pipeMeta) { this._reportError( syntaxError( - `Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${stringifyType(pipeType)}.`), + `Illegal state: getPipeMetadata can only be called after loadNgModuleDirectiveAndPipeMetadata for a module that declares it. Pipe ${ + stringifyType(pipeType)}.`), pipeType); } return pipeMeta || null; @@ -898,7 +916,7 @@ export class CompileMetadataResolver { private _loadPipeMetadata(pipeType: any): cpl.CompilePipeMetadata { pipeType = resolveForwardRef(pipeType); - const pipeAnnotation = this._pipeResolver.resolve(pipeType) !; + const pipeAnnotation = this._pipeResolver.resolve(pipeType)!; const pipeMeta = new cpl.CompilePipeMetadata({ type: this._getTypeMetadata(pipeType), @@ -962,7 +980,6 @@ export class CompileMetadataResolver { isOptional, token: this._getTokenMetadata(token) }; - }); if (hasUnknownDeps) { @@ -1000,7 +1017,7 @@ export class CompileMetadataResolver { this._getProvidersMetadata(provider, targetEntryComponents, debugInfo, compileProviders); } else { provider = resolveForwardRef(provider); - let providerMeta: cpl.ProviderMeta = undefined !; + let providerMeta: cpl.ProviderMeta = undefined!; if (provider && typeof provider === 'object' && provider.hasOwnProperty('provide')) { this._validateProvider(provider); providerMeta = new cpl.ProviderMeta(provider.provide, provider); @@ -1027,8 +1044,11 @@ export class CompileMetadataResolver { []) .join(', '); this._reportError( - syntaxError( - `Invalid ${debugInfo ? debugInfo : 'provider'} - only instances of Provider and Type are allowed, got: [${providersInfo}]`), + syntaxError(`Invalid ${ + debugInfo ? + debugInfo : + 'provider'} - only instances of Provider and Type are allowed, got: [${ + providersInfo}]`), type); return; } @@ -1045,8 +1065,8 @@ export class CompileMetadataResolver { private _validateProvider(provider: any): void { if (provider.hasOwnProperty('useClass') && provider.useClass == null) { - this._reportError(syntaxError( - `Invalid provider for ${stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}. + this._reportError(syntaxError(`Invalid provider for ${ + stringifyType(provider.provide)}. useClass cannot be ${provider.useClass}. Usually it happens when: 1. There's a circular dependency (might be caused by using index.ts (barrel) files). 2. Class was used before it was declared. Use forwardRef in this case.`)); @@ -1085,12 +1105,12 @@ export class CompileMetadataResolver { cpl.CompileEntryComponentMetadata|null { const dirMeta = this.getNonNormalizedDirectiveMetadata(dirType); if (dirMeta && dirMeta.metadata.isComponent) { - return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory !}; + return {componentType: dirType, componentFactory: dirMeta.metadata.componentFactory!}; } const dirSummary = <cpl.CompileDirectiveSummary>this._loadSummary(dirType, cpl.CompileSummaryKind.Directive); if (dirSummary && dirSummary.isComponent) { - return {componentType: dirType, componentFactory: dirSummary.componentFactory !}; + return {componentType: dirType, componentFactory: dirSummary.componentFactory!}; } if (throwIfNotFound) { throw syntaxError(`${dirType.name} cannot be used as an entry component.`); @@ -1108,9 +1128,9 @@ export class CompileMetadataResolver { } getProviderMetadata(provider: cpl.ProviderMeta): cpl.CompileProviderMetadata { - let compileDeps: cpl.CompileDiDependencyMetadata[] = undefined !; - let compileTypeMetadata: cpl.CompileTypeMetadata = null !; - let compileFactoryMetadata: cpl.CompileFactoryMetadata = null !; + let compileDeps: cpl.CompileDiDependencyMetadata[] = undefined!; + let compileTypeMetadata: cpl.CompileTypeMetadata = null!; + let compileFactoryMetadata: cpl.CompileFactoryMetadata = null!; let token: cpl.CompileTokenMetadata = this._getTokenMetadata(provider.token); if (provider.useClass) { @@ -1152,7 +1172,9 @@ export class CompileMetadataResolver { return res; } - private _queryVarBindings(selector: any): string[] { return selector.split(/\s*,\s*/); } + private _queryVarBindings(selector: any): string[] { + return selector.split(/\s*,\s*/); + } private _getQueryMetadata(q: Query, propertyName: string, typeOrFunc: Type|Function): cpl.CompileQueryMetadata { @@ -1163,8 +1185,8 @@ export class CompileMetadataResolver { } else { if (!q.selector) { this._reportError( - syntaxError( - `Can't construct a query for the property "${propertyName}" of "${stringifyType(typeOrFunc)}" since the query selector wasn't defined.`), + syntaxError(`Can't construct a query for the property "${propertyName}" of "${ + stringifyType(typeOrFunc)}" since the query selector wasn't defined.`), typeOrFunc); selectors = []; } else { @@ -1175,8 +1197,9 @@ export class CompileMetadataResolver { return { selectors, first: q.first, - descendants: q.descendants, propertyName, - read: q.read ? this._getTokenMetadata(q.read) : null !, + descendants: q.descendants, + propertyName, + read: q.read ? this._getTokenMetadata(q.read) : null!, static: q.static }; } diff --git a/packages/compiler/src/ml_parser/ast.ts b/packages/compiler/src/ml_parser/ast.ts index 20e8343553f5a..8dc7761030a87 100644 --- a/packages/compiler/src/ml_parser/ast.ts +++ b/packages/compiler/src/ml_parser/ast.ts @@ -24,7 +24,9 @@ export class Text extends NodeWithI18n { constructor(public value: string, sourceSpan: ParseSourceSpan, i18n?: I18nMeta) { super(sourceSpan, i18n); } - visit(visitor: Visitor, context: any): any { return visitor.visitText(this, context); } + visit(visitor: Visitor, context: any): any { + return visitor.visitText(this, context); + } } export class Expansion extends NodeWithI18n { @@ -33,7 +35,9 @@ export class Expansion extends NodeWithI18n { sourceSpan: ParseSourceSpan, public switchValueSourceSpan: ParseSourceSpan, i18n?: I18nMeta) { super(sourceSpan, i18n); } - visit(visitor: Visitor, context: any): any { return visitor.visitExpansion(this, context); } + visit(visitor: Visitor, context: any): any { + return visitor.visitExpansion(this, context); + } } export class ExpansionCase implements Node { @@ -41,7 +45,9 @@ export class ExpansionCase implements Node { public value: string, public expression: Node[], public sourceSpan: ParseSourceSpan, public valueSourceSpan: ParseSourceSpan, public expSourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context: any): any { return visitor.visitExpansionCase(this, context); } + visit(visitor: Visitor, context: any): any { + return visitor.visitExpansionCase(this, context); + } } export class Attribute extends NodeWithI18n { @@ -50,7 +56,9 @@ export class Attribute extends NodeWithI18n { public valueSpan?: ParseSourceSpan, i18n?: I18nMeta) { super(sourceSpan, i18n); } - visit(visitor: Visitor, context: any): any { return visitor.visitAttribute(this, context); } + visit(visitor: Visitor, context: any): any { + return visitor.visitAttribute(this, context); + } } export class Element extends NodeWithI18n { @@ -60,12 +68,16 @@ export class Element extends NodeWithI18n { public endSourceSpan: ParseSourceSpan|null = null, i18n?: I18nMeta) { super(sourceSpan, i18n); } - visit(visitor: Visitor, context: any): any { return visitor.visitElement(this, context); } + visit(visitor: Visitor, context: any): any { + return visitor.visitElement(this, context); + } } export class Comment implements Node { constructor(public value: string|null, public sourceSpan: ParseSourceSpan) {} - visit(visitor: Visitor, context: any): any { return visitor.visitComment(this, context); } + visit(visitor: Visitor, context: any): any { + return visitor.visitComment(this, context); + } } export interface Visitor { @@ -85,7 +97,7 @@ export function visitAll(visitor: Visitor, nodes: Node[], context: any = null): const result: any[] = []; const visit = visitor.visit ? - (ast: Node) => visitor.visit !(ast, context) || ast.visit(visitor, context) : + (ast: Node) => visitor.visit!(ast, context) || ast.visit(visitor, context) : (ast: Node) => ast.visit(visitor, context); nodes.forEach(ast => { const astResult = visit(ast); @@ -111,7 +123,9 @@ export class RecursiveVisitor implements Visitor { visitComment(ast: Comment, context: any): any {} visitExpansion(ast: Expansion, context: any): any { - return this.visitChildren(context, visit => { visit(ast.cases); }); + return this.visitChildren(context, visit => { + visit(ast.cases); + }); } visitExpansionCase(ast: ExpansionCase, context: any): any {} @@ -120,7 +134,7 @@ export class RecursiveVisitor implements Visitor { context: any, cb: (visit: (<V extends Node>(children: V[]|undefined) => void)) => void) { let results: any[][] = []; let t = this; - function visit<T extends Node>(children: T[] | undefined) { + function visit<T extends Node>(children: T[]|undefined) { if (children) results.push(visitAll(t, children, context)); } cb(visit); diff --git a/packages/compiler/src/ml_parser/html_parser.ts b/packages/compiler/src/ml_parser/html_parser.ts index 5e788523dbed9..bc1d33282053d 100644 --- a/packages/compiler/src/ml_parser/html_parser.ts +++ b/packages/compiler/src/ml_parser/html_parser.ts @@ -8,12 +8,14 @@ import {getHtmlTagDefinition} from './html_tags'; import {TokenizeOptions} from './lexer'; -import {ParseTreeResult, Parser} from './parser'; +import {Parser, ParseTreeResult} from './parser'; export {ParseTreeResult, TreeError} from './parser'; export class HtmlParser extends Parser { - constructor() { super(getHtmlTagDefinition); } + constructor() { + super(getHtmlTagDefinition); + } parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult { return super.parse(source, url, options); diff --git a/packages/compiler/src/ml_parser/html_tags.ts b/packages/compiler/src/ml_parser/html_tags.ts index f2dc36a415e97..5e978fdb6368a 100644 --- a/packages/compiler/src/ml_parser/html_tags.ts +++ b/packages/compiler/src/ml_parser/html_tags.ts @@ -18,16 +18,21 @@ export class HtmlTagDefinition implements TagDefinition { ignoreFirstLf: boolean; canSelfClose: boolean = false; - constructor( - {closedByChildren, implicitNamespacePrefix, contentType = TagContentType.PARSABLE_DATA, - closedByParent = false, isVoid = false, ignoreFirstLf = false}: { - closedByChildren?: string[], - closedByParent?: boolean, - implicitNamespacePrefix?: string, - contentType?: TagContentType, - isVoid?: boolean, - ignoreFirstLf?: boolean - } = {}) { + constructor({ + closedByChildren, + implicitNamespacePrefix, + contentType = TagContentType.PARSABLE_DATA, + closedByParent = false, + isVoid = false, + ignoreFirstLf = false + }: { + closedByChildren?: string[], + closedByParent?: boolean, + implicitNamespacePrefix?: string, + contentType?: TagContentType, + isVoid?: boolean, + ignoreFirstLf?: boolean + } = {}) { if (closedByChildren && closedByChildren.length > 0) { closedByChildren.forEach(tagName => this.closedByChildren[tagName] = true); } @@ -43,11 +48,11 @@ export class HtmlTagDefinition implements TagDefinition { } } -let _DEFAULT_TAG_DEFINITION !: HtmlTagDefinition; +let _DEFAULT_TAG_DEFINITION!: HtmlTagDefinition; // see http://www.w3.org/TR/html51/syntax.html#optional-tags // This implementation does not fully conform to the HTML5 spec. -let TAG_DEFINITIONS !: {[key: string]: HtmlTagDefinition}; +let TAG_DEFINITIONS!: {[key: string]: HtmlTagDefinition}; export function getHtmlTagDefinition(tagName: string): HtmlTagDefinition { if (!TAG_DEFINITIONS) { diff --git a/packages/compiler/src/ml_parser/html_whitespaces.ts b/packages/compiler/src/ml_parser/html_whitespaces.ts index b2431c15c2186..9dfb1721072c4 100644 --- a/packages/compiler/src/ml_parser/html_whitespaces.ts +++ b/packages/compiler/src/ml_parser/html_whitespaces.ts @@ -81,11 +81,17 @@ export class WhitespaceVisitor implements html.Visitor { return null; } - visitComment(comment: html.Comment, context: any): any { return comment; } + visitComment(comment: html.Comment, context: any): any { + return comment; + } - visitExpansion(expansion: html.Expansion, context: any): any { return expansion; } + visitExpansion(expansion: html.Expansion, context: any): any { + return expansion; + } - visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return expansionCase; } + visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { + return expansionCase; + } } export function removeWhitespaces(htmlAstWithErrors: ParseTreeResult): ParseTreeResult { diff --git a/packages/compiler/src/ml_parser/icu_ast_expander.ts b/packages/compiler/src/ml_parser/icu_ast_expander.ts index 3e7d5d15ac84f..1285aabb9aa58 100644 --- a/packages/compiler/src/ml_parser/icu_ast_expander.ts +++ b/packages/compiler/src/ml_parser/icu_ast_expander.ts @@ -46,7 +46,9 @@ export class ExpansionResult { } export class ExpansionError extends ParseError { - constructor(span: ParseSourceSpan, errorMsg: string) { super(span, errorMsg); } + constructor(span: ParseSourceSpan, errorMsg: string) { + super(span, errorMsg); + } } /** @@ -64,11 +66,17 @@ class _Expander implements html.Visitor { element.startSourceSpan, element.endSourceSpan); } - visitAttribute(attribute: html.Attribute, context: any): any { return attribute; } + visitAttribute(attribute: html.Attribute, context: any): any { + return attribute; + } - visitText(text: html.Text, context: any): any { return text; } + visitText(text: html.Text, context: any): any { + return text; + } - visitComment(comment: html.Comment, context: any): any { return comment; } + visitComment(comment: html.Comment, context: any): any { + return comment; + } visitExpansion(icu: html.Expansion, context: any): any { this.isExpanded = true; @@ -87,7 +95,7 @@ function _expandPluralForm(ast: html.Expansion, errors: ParseError[]): html.Elem if (PLURAL_CASES.indexOf(c.value) == -1 && !c.value.match(/^=\d+$/)) { errors.push(new ExpansionError( c.valueSourceSpan, - `Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(", ")}`)); + `Plural cases should be "=<number>" or one of ${PLURAL_CASES.join(', ')}`)); } const expansionResult = expandNodes(c.expression); diff --git a/packages/compiler/src/ml_parser/lexer.ts b/packages/compiler/src/ml_parser/lexer.ts index 98ff8f423b5c4..e499f5994c873 100644 --- a/packages/compiler/src/ml_parser/lexer.ts +++ b/packages/compiler/src/ml_parser/lexer.ts @@ -764,7 +764,7 @@ function mergeTextTokens(srcTokens: Token[]): Token[] { for (let i = 0; i < srcTokens.length; i++) { const token = srcTokens[i]; if (lastDstToken && lastDstToken.type == TokenType.TEXT && token.type == TokenType.TEXT) { - lastDstToken.parts[0] ! += token.parts[0]; + lastDstToken.parts[0]! += token.parts[0]; lastDstToken.sourceSpan.end = token.sourceSpan.end; } else { lastDstToken = token; @@ -849,15 +849,27 @@ class PlainCharacterCursor implements CharacterCursor { } } - clone(): PlainCharacterCursor { return new PlainCharacterCursor(this); } + clone(): PlainCharacterCursor { + return new PlainCharacterCursor(this); + } - peek() { return this.state.peek; } - charsLeft() { return this.end - this.state.offset; } - diff(other: this) { return this.state.offset - other.state.offset; } + peek() { + return this.state.peek; + } + charsLeft() { + return this.end - this.state.offset; + } + diff(other: this) { + return this.state.offset - other.state.offset; + } - advance(): void { this.advanceState(this.state); } + advance(): void { + this.advanceState(this.state); + } - init(): void { this.updatePeek(this.state); } + init(): void { + this.updatePeek(this.state); + } getSpan(start?: this, leadingTriviaCodePoints?: number[]): ParseSourceSpan { start = start || this; @@ -880,7 +892,9 @@ class PlainCharacterCursor implements CharacterCursor { return this.input.substring(start.state.offset, this.state.offset); } - charAt(pos: number): number { return this.input.charCodeAt(pos); } + charAt(pos: number): number { + return this.input.charCodeAt(pos); + } protected advanceState(state: CursorState) { if (state.offset >= this.end) { @@ -913,7 +927,7 @@ class EscapedCharacterCursor extends PlainCharacterCursor { super(fileOrCursor); this.internalState = {...fileOrCursor.internalState}; } else { - super(fileOrCursor, range !); + super(fileOrCursor, range!); this.internalState = this.state; } } @@ -929,7 +943,9 @@ class EscapedCharacterCursor extends PlainCharacterCursor { this.processEscapeSequence(); } - clone(): EscapedCharacterCursor { return new EscapedCharacterCursor(this); } + clone(): EscapedCharacterCursor { + return new EscapedCharacterCursor(this); + } getChars(start: this): string { const cursor = start.clone(); diff --git a/packages/compiler/src/ml_parser/parser.ts b/packages/compiler/src/ml_parser/parser.ts index 88aca6d6f3cbd..cbb46723eda8b 100644 --- a/packages/compiler/src/ml_parser/parser.ts +++ b/packages/compiler/src/ml_parser/parser.ts @@ -10,7 +10,7 @@ import {ParseError, ParseSourceSpan} from '../parse_util'; import * as html from './ast'; import * as lex from './lexer'; -import {TagDefinition, getNsPrefix, isNgContainer, mergeNsAndName} from './tags'; +import {getNsPrefix, isNgContainer, mergeNsAndName, TagDefinition} from './tags'; export class TreeError extends ParseError { static create(elementName: string|null, span: ParseSourceSpan, msg: string): TreeError { @@ -43,7 +43,7 @@ export class Parser { class _TreeBuilder { private _index: number = -1; // TODO(issue/24571): remove '!'. - private _peek !: lex.Token; + private _peek!: lex.Token; private _rootNodes: html.Node[] = []; private _errors: TreeError[] = []; @@ -283,7 +283,7 @@ class _TreeBuilder { endTagToken.parts[0], endTagToken.parts[1], this._getParentElement()); if (this._getParentElement()) { - this._getParentElement() !.endSourceSpan = endTagToken.sourceSpan; + this._getParentElement()!.endSourceSpan = endTagToken.sourceSpan; } if (this.getTagDefinition(fullName).isVoid) { @@ -291,8 +291,8 @@ class _TreeBuilder { fullName, endTagToken.sourceSpan, `Void elements do not have end tags "${endTagToken.parts[1]}"`)); } else if (!this._popElement(fullName)) { - const errMsg = - `Unexpected closing tag "${fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`; + const errMsg = `Unexpected closing tag "${ + fullName}". It may happen when the tag has already been closed by another tag. For more info see https://www.w3.org/TR/html5/syntax.html#closing-elements-that-have-implied-end-tags`; this._errors.push(TreeError.create(fullName, endTagToken.sourceSpan, errMsg)); } } @@ -316,7 +316,7 @@ class _TreeBuilder { const fullName = mergeNsAndName(attrName.parts[0], attrName.parts[1]); let end = attrName.sourceSpan.end; let value = ''; - let valueSpan: ParseSourceSpan = undefined !; + let valueSpan: ParseSourceSpan = undefined!; if (this._peek.type === lex.TokenType.ATTR_QUOTE) { this._advance(); } @@ -344,7 +344,7 @@ class _TreeBuilder { * `<ng-container>` elements are skipped as they are not rendered as DOM element. */ private _getParentElementSkippingContainers(): - {parent: html.Element | null, container: html.Element|null} { + {parent: html.Element|null, container: html.Element|null} { let container: html.Element|null = null; for (let i = this._elementStack.length - 1; i >= 0; i--) { diff --git a/packages/compiler/src/ml_parser/tags.ts b/packages/compiler/src/ml_parser/tags.ts index 038f4fe053754..386db35d1ed46 100644 --- a/packages/compiler/src/ml_parser/tags.ts +++ b/packages/compiler/src/ml_parser/tags.ts @@ -23,7 +23,7 @@ export interface TagDefinition { isClosedByChild(name: string): boolean; } -export function splitNsName(elementName: string): [string | null, string] { +export function splitNsName(elementName: string): [string|null, string] { if (elementName[0] != ':') { return [null, elementName]; } @@ -54,7 +54,7 @@ export function isNgTemplate(tagName: string): boolean { export function getNsPrefix(fullName: string): string; export function getNsPrefix(fullName: null): null; -export function getNsPrefix(fullName: string | null): string|null { +export function getNsPrefix(fullName: string|null): string|null { return fullName === null ? null : splitNsName(fullName)[0]; } diff --git a/packages/compiler/src/ml_parser/xml_parser.ts b/packages/compiler/src/ml_parser/xml_parser.ts index dc6dffb0420d0..2f7933f356393 100644 --- a/packages/compiler/src/ml_parser/xml_parser.ts +++ b/packages/compiler/src/ml_parser/xml_parser.ts @@ -7,13 +7,15 @@ */ import {TokenizeOptions} from './lexer'; -import {ParseTreeResult, Parser} from './parser'; +import {Parser, ParseTreeResult} from './parser'; import {getXmlTagDefinition} from './xml_tags'; export {ParseTreeResult, TreeError} from './parser'; export class XmlParser extends Parser { - constructor() { super(getXmlTagDefinition); } + constructor() { + super(getXmlTagDefinition); + } parse(source: string, url: string, options?: TokenizeOptions): ParseTreeResult { return super.parse(source, url, options); diff --git a/packages/compiler/src/ml_parser/xml_tags.ts b/packages/compiler/src/ml_parser/xml_tags.ts index ab52c15dd18bf..75d14a3d8e428 100644 --- a/packages/compiler/src/ml_parser/xml_tags.ts +++ b/packages/compiler/src/ml_parser/xml_tags.ts @@ -11,19 +11,23 @@ import {TagContentType, TagDefinition} from './tags'; export class XmlTagDefinition implements TagDefinition { closedByParent: boolean = false; // TODO(issue/24571): remove '!'. - requiredParents !: {[key: string]: boolean}; + requiredParents!: {[key: string]: boolean}; // TODO(issue/24571): remove '!'. - parentToAdd !: string; + parentToAdd!: string; // TODO(issue/24571): remove '!'. - implicitNamespacePrefix !: string; + implicitNamespacePrefix!: string; contentType: TagContentType = TagContentType.PARSABLE_DATA; isVoid: boolean = false; ignoreFirstLf: boolean = false; canSelfClose: boolean = true; - requireExtraParent(currentParent: string): boolean { return false; } + requireExtraParent(currentParent: string): boolean { + return false; + } - isClosedByChild(name: string): boolean { return false; } + isClosedByChild(name: string): boolean { + return false; + } } const _TAG_DEFINITION = new XmlTagDefinition(); diff --git a/packages/compiler/src/ng_module_compiler.ts b/packages/compiler/src/ng_module_compiler.ts index 6ff46bcb765b7..f26dfc7092a85 100644 --- a/packages/compiler/src/ng_module_compiler.ts +++ b/packages/compiler/src/ng_module_compiler.ts @@ -43,8 +43,8 @@ export class NgModuleCompiler { }); const ngModuleDef = o.importExpr(Identifiers.moduleDef).callFn([o.literalArr(providerDefs)]); - const ngModuleDefFactory = o.fn( - [new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE); + const ngModuleDefFactory = + o.fn([new o.FnParam(LOG_VAR.name!)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE); const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`; this._createNgModuleFactory( @@ -77,7 +77,7 @@ export class NgModuleCompiler { .set(value) .toDeclStmt( o.importType( - Identifiers.NgModuleFactory, [o.expressionType(ctx.importExpr(reference)) !], + Identifiers.NgModuleFactory, [o.expressionType(ctx.importExpr(reference))!], [o.TypeModifier.Const]), [o.StmtModifier.Final, o.StmtModifier.Exported]); diff --git a/packages/compiler/src/ng_module_resolver.ts b/packages/compiler/src/ng_module_resolver.ts index 6996f376a145e..fa1ca5010b70b 100644 --- a/packages/compiler/src/ng_module_resolver.ts +++ b/packages/compiler/src/ng_module_resolver.ts @@ -7,7 +7,7 @@ */ import {CompileReflector} from './compile_reflector'; -import {NgModule, Type, createNgModule} from './core'; +import {createNgModule, NgModule, Type} from './core'; import {findLast} from './directive_resolver'; import {stringify} from './util'; @@ -18,7 +18,9 @@ import {stringify} from './util'; export class NgModuleResolver { constructor(private _reflector: CompileReflector) {} - isNgModule(type: any) { return this._reflector.annotations(type).some(createNgModule.isTypeOf); } + isNgModule(type: any) { + return this._reflector.annotations(type).some(createNgModule.isTypeOf); + } resolve(type: Type, throwIfNotFound = true): NgModule|null { const ngModuleMeta: NgModule = diff --git a/packages/compiler/src/output/abstract_emitter.ts b/packages/compiler/src/output/abstract_emitter.ts index 3c809fa59016f..0e1463890db71 100644 --- a/packages/compiler/src/output/abstract_emitter.ts +++ b/packages/compiler/src/output/abstract_emitter.ts @@ -28,31 +28,39 @@ class _EmittedLine { } export class EmitterVisitorContext { - static createRoot(): EmitterVisitorContext { return new EmitterVisitorContext(0); } + static createRoot(): EmitterVisitorContext { + return new EmitterVisitorContext(0); + } private _lines: _EmittedLine[]; private _classes: o.ClassStmt[] = []; private _preambleLineCount = 0; - constructor(private _indent: number) { this._lines = [new _EmittedLine(_indent)]; } + constructor(private _indent: number) { + this._lines = [new _EmittedLine(_indent)]; + } /** * @internal strip this from published d.ts files due to * https://github.com/microsoft/TypeScript/issues/36216 */ - private get _currentLine(): _EmittedLine { return this._lines[this._lines.length - 1]; } + private get _currentLine(): _EmittedLine { + return this._lines[this._lines.length - 1]; + } - println(from?: {sourceSpan: ParseSourceSpan | null}|null, lastPart: string = ''): void { + println(from?: {sourceSpan: ParseSourceSpan|null}|null, lastPart: string = ''): void { this.print(from || null, lastPart, true); } - lineIsEmpty(): boolean { return this._currentLine.parts.length === 0; } + lineIsEmpty(): boolean { + return this._currentLine.parts.length === 0; + } lineLength(): number { return this._currentLine.indent * _INDENT_WITH.length + this._currentLine.partsLength; } - print(from: {sourceSpan: ParseSourceSpan | null}|null, part: string, newLine: boolean = false) { + print(from: {sourceSpan: ParseSourceSpan|null}|null, part: string, newLine: boolean = false) { if (part.length > 0) { this._currentLine.parts.push(part); this._currentLine.partsLength += part.length; @@ -83,9 +91,13 @@ export class EmitterVisitorContext { } } - pushClass(clazz: o.ClassStmt) { this._classes.push(clazz); } + pushClass(clazz: o.ClassStmt) { + this._classes.push(clazz); + } - popClass(): o.ClassStmt { return this._classes.pop() !; } + popClass(): o.ClassStmt { + return this._classes.pop()!; + } get currentClass(): o.ClassStmt|null { return this._classes.length > 0 ? this._classes[this._classes.length - 1] : null; @@ -135,7 +147,7 @@ export class EmitterVisitorContext { } while (spanIdx < spans.length) { - const span = spans[spanIdx] !; + const span = spans[spanIdx]!; const source = span.start.file; const sourceLine = span.start.line; const sourceCol = span.start.col; @@ -156,7 +168,9 @@ export class EmitterVisitorContext { return map; } - setPreambleLineCount(count: number) { return this._preambleLineCount = count; } + setPreambleLineCount(count: number) { + return this._preambleLineCount = count; + } spanOf(line: number, column: number): ParseSourceSpan|null { const emittedLine = this._lines[line - this._preambleLineCount]; @@ -243,7 +257,9 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex if (stmt.multiline) { ctx.println(stmt, `/* ${stmt.comment} */`); } else { - stmt.comment.split('\n').forEach((line) => { ctx.println(stmt, `// ${line}`); }); + stmt.comment.split('\n').forEach((line) => { + ctx.println(stmt, `// ${line}`); + }); } return null; } @@ -327,7 +343,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex expr.expr.visitExpression(this, ctx); } visitReadVarExpr(ast: o.ReadVarExpr, ctx: EmitterVisitorContext): any { - let varName = ast.name !; + let varName = ast.name!; if (ast.builtin != null) { switch (ast.builtin) { case o.BuiltinVar.Super: @@ -337,10 +353,10 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex varName = 'this'; break; case o.BuiltinVar.CatchError: - varName = CATCH_ERROR_VAR.name !; + varName = CATCH_ERROR_VAR.name!; break; case o.BuiltinVar.CatchStack: - varName = CATCH_STACK_VAR.name !; + varName = CATCH_STACK_VAR.name!; break; default: throw new Error(`Unknown builtin variable ${ast.builtin}`); @@ -388,7 +404,7 @@ export abstract class AbstractEmitterVisitor implements o.StatementVisitor, o.Ex ctx.print(ast, '? '); ast.trueCase.visitExpression(this, ctx); ctx.print(ast, ': '); - ast.falseCase !.visitExpression(this, ctx); + ast.falseCase!.visitExpression(this, ctx); ctx.print(ast, `)`); return null; } diff --git a/packages/compiler/src/output/abstract_js_emitter.ts b/packages/compiler/src/output/abstract_js_emitter.ts index fde1fbe80b091..3802f1a98d865 100644 --- a/packages/compiler/src/output/abstract_js_emitter.ts +++ b/packages/compiler/src/output/abstract_js_emitter.ts @@ -11,7 +11,9 @@ import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitor import * as o from './output_ast'; export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor { - constructor() { super(false); } + constructor() { + super(false); + } visitDeclareClassStmt(stmt: o.ClassStmt, ctx: EmitterVisitorContext): any { ctx.pushClass(stmt); this._visitClassConstructor(stmt, ctx); @@ -101,7 +103,7 @@ export abstract class AbstractJsEmitterVisitor extends AbstractEmitterVisitor { visitInvokeFunctionExpr(expr: o.InvokeFunctionExpr, ctx: EmitterVisitorContext): string|null { const fnExpr = expr.fn; if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) { - ctx.currentClass !.parent !.visitExpression(this, ctx); + ctx.currentClass!.parent!.visitExpression(this, ctx); ctx.print(expr, `.call(this`); if (expr.args.length > 0) { ctx.print(expr, `, `); diff --git a/packages/compiler/src/output/js_emitter.ts b/packages/compiler/src/output/js_emitter.ts index 16ae3138e74a0..4589676db62b6 100644 --- a/packages/compiler/src/output/js_emitter.ts +++ b/packages/compiler/src/output/js_emitter.ts @@ -51,7 +51,7 @@ class JsEmitterVisitor extends AbstractJsEmitterVisitor { } ctx.print(ast, `${prefix}.`); } - ctx.print(ast, name !); + ctx.print(ast, name!); return null; } visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: EmitterVisitorContext): any { diff --git a/packages/compiler/src/output/output_ast.ts b/packages/compiler/src/output/output_ast.ts index 5e6660af2f73d..d8d313f561ddd 100644 --- a/packages/compiler/src/output/output_ast.ts +++ b/packages/compiler/src/output/output_ast.ts @@ -24,7 +24,9 @@ export abstract class Type { } abstract visitType(visitor: TypeVisitor, context: any): any; - hasModifier(modifier: TypeModifier): boolean { return this.modifiers !.indexOf(modifier) !== -1; } + hasModifier(modifier: TypeModifier): boolean { + return this.modifiers!.indexOf(modifier) !== -1; + } } export enum BuiltinTypeName { @@ -60,7 +62,9 @@ export class ExpressionType extends Type { export class ArrayType extends Type { - constructor(public of : Type, modifiers: TypeModifier[]|null = null) { super(modifiers); } + constructor(public of: Type, modifiers: TypeModifier[]|null = null) { + super(modifiers); + } visitType(visitor: TypeVisitor, context: any): any { return visitor.visitArrayType(this, context); } @@ -73,7 +77,9 @@ export class MapType extends Type { super(modifiers); this.valueType = valueType || null; } - visitType(visitor: TypeVisitor, context: any): any { return visitor.visitMapType(this, context); } + visitType(visitor: TypeVisitor, context: any): any { + return visitor.visitMapType(this, context); + } } export const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); @@ -113,15 +119,15 @@ export enum BinaryOperator { BiggerEquals } -export function nullSafeIsEquivalent<T extends{isEquivalent(other: T): boolean}>( - base: T | null, other: T | null) { +export function nullSafeIsEquivalent<T extends {isEquivalent(other: T): boolean}>( + base: T|null, other: T|null) { if (base == null || other == null) { return base == other; } return base.isEquivalent(other); } -export function areAllEquivalent<T extends{isEquivalent(other: T): boolean}>( +export function areAllEquivalent<T extends {isEquivalent(other: T): boolean}>( base: T[], other: T[]) { const len = base.length; if (len !== other.length) { @@ -243,7 +249,9 @@ export abstract class Expression { return new CastExpr(this, type, sourceSpan); } - toStmt(): Statement { return new ExpressionStatement(this, null); } + toStmt(): Statement { + return new ExpressionStatement(this, null); + } } export enum BuiltinVar { @@ -272,7 +280,9 @@ export class ReadVarExpr extends Expression { return e instanceof ReadVarExpr && this.name === e.name && this.builtin === e.builtin; } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitReadVarExpr(this, context); @@ -299,7 +309,9 @@ export class TypeofExpr extends Expression { return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr); } - isConstant(): boolean { return this.expr.isConstant(); } + isConstant(): boolean { + return this.expr.isConstant(); + } } export class WrappedNodeExpr<T> extends Expression { @@ -311,7 +323,9 @@ export class WrappedNodeExpr<T> extends Expression { return e instanceof WrappedNodeExpr && this.node === e.node; } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWrappedNodeExpr(this, context); @@ -330,7 +344,9 @@ export class WriteVarExpr extends Expression { return e instanceof WriteVarExpr && this.name === e.name && this.value.isEquivalent(e.value); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWriteVarExpr(this, context); @@ -340,7 +356,9 @@ export class WriteVarExpr extends Expression { return new DeclareVarStmt(this.name, this.value, type, modifiers, this.sourceSpan); } - toConstDecl(): DeclareVarStmt { return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]); } + toConstDecl(): DeclareVarStmt { + return this.toDeclStmt(INFERRED_TYPE, [StmtModifier.Final]); + } } @@ -358,7 +376,9 @@ export class WriteKeyExpr extends Expression { this.index.isEquivalent(e.index) && this.value.isEquivalent(e.value); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWriteKeyExpr(this, context); @@ -380,7 +400,9 @@ export class WritePropExpr extends Expression { this.name === e.name && this.value.isEquivalent(e.value); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitWritePropExpr(this, context); @@ -414,7 +436,9 @@ export class InvokeMethodExpr extends Expression { this.name === e.name && this.builtin === e.builtin && areAllEquivalent(this.args, e.args); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitInvokeMethodExpr(this, context); @@ -434,7 +458,9 @@ export class InvokeFunctionExpr extends Expression { areAllEquivalent(this.args, e.args) && this.pure === e.pure; } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitInvokeFunctionExpr(this, context); @@ -454,7 +480,9 @@ export class InstantiateExpr extends Expression { areAllEquivalent(this.args, e.args); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitInstantiateExpr(this, context); @@ -473,7 +501,9 @@ export class LiteralExpr extends Expression { return e instanceof LiteralExpr && this.value === e.value; } - isConstant() { return true; } + isConstant() { + return true; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitLiteralExpr(this, context); @@ -494,7 +524,9 @@ export class LocalizedString extends Expression { return false; } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitLocalizedString(this, context); @@ -521,8 +553,9 @@ export class LocalizedString extends Expression { metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`; } if (this.metaBlock.legacyIds) { - this.metaBlock.legacyIds.forEach( - legacyId => { metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`; }); + this.metaBlock.legacyIds.forEach(legacyId => { + metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`; + }); } return createCookedRawString(metaBlock, this.messageParts[0]); } @@ -588,7 +621,9 @@ export class ExternalExpr extends Expression { this.value.moduleName === e.value.moduleName && this.value.runtime === e.value.runtime; } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitExternalExpr(this, context); @@ -616,7 +651,9 @@ export class ConditionalExpr extends Expression { this.trueCase.isEquivalent(e.trueCase) && nullSafeIsEquivalent(this.falseCase, e.falseCase); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitConditionalExpr(this, context); @@ -633,7 +670,9 @@ export class NotExpr extends Expression { return e instanceof NotExpr && this.condition.isEquivalent(e.condition); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitNotExpr(this, context); @@ -649,7 +688,9 @@ export class AssertNotNull extends Expression { return e instanceof AssertNotNull && this.condition.isEquivalent(e.condition); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitAssertNotNullExpr(this, context); @@ -665,7 +706,9 @@ export class CastExpr extends Expression { return e instanceof CastExpr && this.value.isEquivalent(e.value); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitCastExpr(this, context); @@ -676,7 +719,9 @@ export class CastExpr extends Expression { export class FnParam { constructor(public name: string, public type: Type|null = null) {} - isEquivalent(param: FnParam): boolean { return this.name === param.name; } + isEquivalent(param: FnParam): boolean { + return this.name === param.name; + } } @@ -692,7 +737,9 @@ export class FunctionExpr extends Expression { areAllEquivalent(this.statements, e.statements); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitFunctionExpr(this, context); @@ -719,7 +766,9 @@ export class BinaryOperatorExpr extends Expression { this.lhs.isEquivalent(e.lhs) && this.rhs.isEquivalent(e.rhs); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitBinaryOperatorExpr(this, context); @@ -739,7 +788,9 @@ export class ReadPropExpr extends Expression { this.name === e.name; } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitReadPropExpr(this, context); @@ -763,7 +814,9 @@ export class ReadKeyExpr extends Expression { this.index.isEquivalent(e.index); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitReadKeyExpr(this, context); @@ -782,7 +835,9 @@ export class LiteralArrayExpr extends Expression { this.entries = entries; } - isConstant() { return this.entries.every(e => e.isConstant()); } + isConstant() { + return this.entries.every(e => e.isConstant()); + } isEquivalent(e: Expression): boolean { return e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries); @@ -813,7 +868,9 @@ export class LiteralMapExpr extends Expression { return e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries); } - isConstant() { return this.entries.every(e => e.value.isConstant()); } + isConstant() { + return this.entries.every(e => e.value.isConstant()); + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitLiteralMapExpr(this, context); @@ -829,7 +886,9 @@ export class CommaExpr extends Expression { return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts); } - isConstant() { return false; } + isConstant() { + return false; + } visitExpression(visitor: ExpressionVisitor, context: any): any { return visitor.visitCommaExpr(this, context); @@ -892,7 +951,9 @@ export abstract class Statement { abstract visitStatement(visitor: StatementVisitor, context: any): any; - hasModifier(modifier: StmtModifier): boolean { return this.modifiers !.indexOf(modifier) !== -1; } + hasModifier(modifier: StmtModifier): boolean { + return this.modifiers!.indexOf(modifier) !== -1; + } } @@ -965,7 +1026,9 @@ export class AbstractClassPart { } this.type = type || null; } - hasModifier(modifier: StmtModifier): boolean { return this.modifiers !.indexOf(modifier) !== -1; } + hasModifier(modifier: StmtModifier): boolean { + return this.modifiers!.indexOf(modifier) !== -1; + } } export class ClassField extends AbstractClassPart { @@ -974,7 +1037,9 @@ export class ClassField extends AbstractClassPart { public initializer?: Expression) { super(type, modifiers); } - isEquivalent(f: ClassField) { return this.name === f.name; } + isEquivalent(f: ClassField) { + return this.name === f.name; + } } @@ -1044,7 +1109,9 @@ export class CommentStmt extends Statement { constructor(public comment: string, public multiline = false, sourceSpan?: ParseSourceSpan|null) { super(null, sourceSpan); } - isEquivalent(stmt: Statement): boolean { return stmt instanceof CommentStmt; } + isEquivalent(stmt: Statement): boolean { + return stmt instanceof CommentStmt; + } visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitCommentStmt(this, context); } @@ -1060,7 +1127,9 @@ export class JSDocCommentStmt extends Statement { visitStatement(visitor: StatementVisitor, context: any): any { return visitor.visitJSDocCommentStmt(this, context); } - toString(): string { return serializeTags(this.tags); } + toString(): string { + return serializeTags(this.tags); + } } export class TryCatchStmt extends Statement { @@ -1105,11 +1174,17 @@ export interface StatementVisitor { } export class AstTransformer implements StatementVisitor, ExpressionVisitor { - transformExpr(expr: Expression, context: any): Expression { return expr; } + transformExpr(expr: Expression, context: any): Expression { + return expr; + } - transformStmt(stmt: Statement, context: any): Statement { return stmt; } + transformStmt(stmt: Statement, context: any): Statement { + return stmt; + } - visitReadVarExpr(ast: ReadVarExpr, context: any): any { return this.transformExpr(ast, context); } + visitReadVarExpr(ast: ReadVarExpr, context: any): any { + return this.transformExpr(ast, context); + } visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any { return this.transformExpr(ast, context); @@ -1148,7 +1223,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor { const method = ast.builtin || ast.name; return this.transformExpr( new InvokeMethodExpr( - ast.receiver.visitExpression(this, context), method !, + ast.receiver.visitExpression(this, context), method!, this.visitAllExpressions(ast.args, context), ast.type, ast.sourceSpan), context); } @@ -1169,7 +1244,9 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor { context); } - visitLiteralExpr(ast: LiteralExpr, context: any): any { return this.transformExpr(ast, context); } + visitLiteralExpr(ast: LiteralExpr, context: any): any { + return this.transformExpr(ast, context); + } visitLocalizedString(ast: LocalizedString, context: any): any { return this.transformExpr( @@ -1188,7 +1265,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor { new ConditionalExpr( ast.condition.visitExpression(this, context), ast.trueCase.visitExpression(this, context), - ast.falseCase !.visitExpression(this, context), ast.type, ast.sourceSpan), + ast.falseCase!.visitExpression(this, context), ast.type, ast.sourceSpan), context); } @@ -1284,7 +1361,7 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor { } visitDeclareClassStmt(stmt: ClassStmt, context: any): any { - const parent = stmt.parent !.visitExpression(this, context); + const parent = stmt.parent!.visitExpression(this, context); const getters = stmt.getters.map( getter => new ClassGetter( getter.name, this.visitAllStatements(getter.body, context), getter.type, @@ -1341,14 +1418,18 @@ export class AstTransformer implements StatementVisitor, ExpressionVisitor { export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor { - visitType(ast: Type, context: any): any { return ast; } + visitType(ast: Type, context: any): any { + return ast; + } visitExpression(ast: Expression, context: any): any { if (ast.type) { ast.type.visitType(this, context); } return ast; } - visitBuiltinType(type: BuiltinType, context: any): any { return this.visitType(type, context); } + visitBuiltinType(type: BuiltinType, context: any): any { + return this.visitType(type, context); + } visitExpressionType(type: ExpressionType, context: any): any { type.value.visitExpression(this, context); if (type.typeParams !== null) { @@ -1356,10 +1437,18 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor } return this.visitType(type, context); } - visitArrayType(type: ArrayType, context: any): any { return this.visitType(type, context); } - visitMapType(type: MapType, context: any): any { return this.visitType(type, context); } - visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any { return ast; } - visitTypeofExpr(ast: TypeofExpr, context: any): any { return this.visitExpression(ast, context); } + visitArrayType(type: ArrayType, context: any): any { + return this.visitType(type, context); + } + visitMapType(type: MapType, context: any): any { + return this.visitType(type, context); + } + visitWrappedNodeExpr(ast: WrappedNodeExpr<any>, context: any): any { + return ast; + } + visitTypeofExpr(ast: TypeofExpr, context: any): any { + return this.visitExpression(ast, context); + } visitReadVarExpr(ast: ReadVarExpr, context: any): any { return this.visitExpression(ast, context); } @@ -1408,7 +1497,7 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor visitConditionalExpr(ast: ConditionalExpr, context: any): any { ast.condition.visitExpression(this, context); ast.trueCase.visitExpression(this, context); - ast.falseCase !.visitExpression(this, context); + ast.falseCase!.visitExpression(this, context); return this.visitExpression(ast, context); } visitNotExpr(ast: NotExpr, context: any): any { @@ -1482,7 +1571,7 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor return stmt; } visitDeclareClassStmt(stmt: ClassStmt, context: any): any { - stmt.parent !.visitExpression(this, context); + stmt.parent!.visitExpression(this, context); stmt.getters.forEach(getter => this.visitAllStatements(getter.body, context)); if (stmt.constructorMethod) { this.visitAllStatements(stmt.constructorMethod.body, context); @@ -1505,8 +1594,12 @@ export class RecursiveAstVisitor implements StatementVisitor, ExpressionVisitor stmt.error.visitExpression(this, context); return stmt; } - visitCommentStmt(stmt: CommentStmt, context: any): any { return stmt; } - visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any { return stmt; } + visitCommentStmt(stmt: CommentStmt, context: any): any { + return stmt; + } + visitJSDocCommentStmt(stmt: JSDocCommentStmt, context: any): any { + return stmt; + } visitAllStatements(stmts: Statement[], context: any): void { stmts.forEach(stmt => stmt.visitStatement(this, context)); } @@ -1551,7 +1644,7 @@ class _FindExternalReferencesVisitor extends RecursiveAstVisitor { } export function applySourceSpanToStatementIfNeeded( - stmt: Statement, sourceSpan: ParseSourceSpan | null): Statement { + stmt: Statement, sourceSpan: ParseSourceSpan|null): Statement { if (!sourceSpan) { return stmt; } @@ -1560,7 +1653,7 @@ export function applySourceSpanToStatementIfNeeded( } export function applySourceSpanToExpressionIfNeeded( - expr: Expression, sourceSpan: ParseSourceSpan | null): Expression { + expr: Expression, sourceSpan: ParseSourceSpan|null): Expression { if (!sourceSpan) { return expr; } @@ -1569,7 +1662,9 @@ export function applySourceSpanToExpressionIfNeeded( } class _ApplySourceSpanTransformer extends AstTransformer { - constructor(private sourceSpan: ParseSourceSpan) { super(); } + constructor(private sourceSpan: ParseSourceSpan) { + super(); + } private _clone(obj: any): any { const clone = Object.create(obj.constructor.prototype); for (let prop of Object.keys(obj)) { @@ -1596,25 +1691,25 @@ class _ApplySourceSpanTransformer extends AstTransformer { } export function variable( - name: string, type?: Type | null, sourceSpan?: ParseSourceSpan | null): ReadVarExpr { + name: string, type?: Type|null, sourceSpan?: ParseSourceSpan|null): ReadVarExpr { return new ReadVarExpr(name, type, sourceSpan); } export function importExpr( - id: ExternalReference, typeParams: Type[] | null = null, - sourceSpan?: ParseSourceSpan | null): ExternalExpr { + id: ExternalReference, typeParams: Type[]|null = null, + sourceSpan?: ParseSourceSpan|null): ExternalExpr { return new ExternalExpr(id, null, typeParams, sourceSpan); } export function importType( - id: ExternalReference, typeParams: Type[] | null = null, - typeModifiers: TypeModifier[] | null = null): ExpressionType|null { + id: ExternalReference, typeParams: Type[]|null = null, + typeModifiers: TypeModifier[]|null = null): ExpressionType|null { return id != null ? expressionType(importExpr(id, typeParams, null), typeModifiers) : null; } export function expressionType( - expr: Expression, typeModifiers: TypeModifier[] | null = null, - typeParams: Type[] | null = null): ExpressionType { + expr: Expression, typeModifiers: TypeModifier[]|null = null, + typeParams: Type[]|null = null): ExpressionType { return new ExpressionType(expr, typeModifiers, typeParams); } @@ -1623,30 +1718,28 @@ export function typeofExpr(expr: Expression) { } export function literalArr( - values: Expression[], type?: Type | null, - sourceSpan?: ParseSourceSpan | null): LiteralArrayExpr { + values: Expression[], type?: Type|null, sourceSpan?: ParseSourceSpan|null): LiteralArrayExpr { return new LiteralArrayExpr(values, type, sourceSpan); } export function literalMap( values: {key: string, quoted: boolean, value: Expression}[], - type: MapType | null = null): LiteralMapExpr { + type: MapType|null = null): LiteralMapExpr { return new LiteralMapExpr( values.map(e => new LiteralMapEntry(e.key, e.value, e.quoted)), type, null); } -export function not(expr: Expression, sourceSpan?: ParseSourceSpan | null): NotExpr { +export function not(expr: Expression, sourceSpan?: ParseSourceSpan|null): NotExpr { return new NotExpr(expr, sourceSpan); } -export function assertNotNull( - expr: Expression, sourceSpan?: ParseSourceSpan | null): AssertNotNull { +export function assertNotNull(expr: Expression, sourceSpan?: ParseSourceSpan|null): AssertNotNull { return new AssertNotNull(expr, sourceSpan); } export function fn( - params: FnParam[], body: Statement[], type?: Type | null, sourceSpan?: ParseSourceSpan | null, - name?: string | null): FunctionExpr { + params: FnParam[], body: Statement[], type?: Type|null, sourceSpan?: ParseSourceSpan|null, + name?: string|null): FunctionExpr { return new FunctionExpr(params, body, type, sourceSpan, name); } @@ -1655,13 +1748,13 @@ export function ifStmt(condition: Expression, thenClause: Statement[], elseClaus } export function literal( - value: any, type?: Type | null, sourceSpan?: ParseSourceSpan | null): LiteralExpr { + value: any, type?: Type|null, sourceSpan?: ParseSourceSpan|null): LiteralExpr { return new LiteralExpr(value, type, sourceSpan); } export function localizedString( metaBlock: I18nMeta, messageParts: string[], placeholderNames: string[], - expressions: Expression[], sourceSpan?: ParseSourceSpan | null): LocalizedString { + expressions: Expression[], sourceSpan?: ParseSourceSpan|null): LocalizedString { return new LocalizedString(metaBlock, messageParts, placeholderNames, expressions, sourceSpan); } @@ -1684,13 +1777,12 @@ export const enum JSDocTagName { */ export type JSDocTag = { // `tagName` is e.g. "param" in an `@param` declaration - tagName: JSDocTagName | string, + tagName: JSDocTagName|string, // Any remaining text on the tag, e.g. the description text?: string, -} | { +}|{ // no `tagName` for plain text documentation that occurs before any `@param` lines - tagName?: undefined, - text: string, + tagName?: undefined, text: string, }; /* diff --git a/packages/compiler/src/output/output_interpreter.ts b/packages/compiler/src/output/output_interpreter.ts index 6fbde79917f9d..c9a33b81558e9 100644 --- a/packages/compiler/src/output/output_interpreter.ts +++ b/packages/compiler/src/output/output_interpreter.ts @@ -15,7 +15,9 @@ export function interpretStatements( const visitor = new StatementInterpreter(reflector); visitor.visitAllStatements(statements, ctx); const result: {[key: string]: any} = {}; - ctx.exports.forEach((exportName) => { result[exportName] = ctx.vars.get(exportName); }); + ctx.exports.forEach((exportName) => { + result[exportName] = ctx.vars.get(exportName); + }); return result; } @@ -63,7 +65,7 @@ function createDynamicClass( _classStmt.methods.forEach(function(method: o.ClassMethod) { const paramNames = method.params.map(param => param.name); // Note: use `function` instead of arrow function to capture `this` - propertyDescriptors[method.name !] = { + propertyDescriptors[method.name!] = { writable: false, configurable: false, value: function(...args: any[]) { @@ -77,7 +79,9 @@ function createDynamicClass( // Note: use `function` instead of arrow function to capture `this` const ctor = function(this: Object, ...args: any[]) { const instanceCtx = new _ExecutionContext(_ctx, this, _classStmt.name, _ctx.vars); - _classStmt.fields.forEach((field) => { (this as any)[field.name] = undefined; }); + _classStmt.fields.forEach((field) => { + (this as any)[field.name] = undefined; + }); _executeFunctionStatements( ctorParamNames, args, _classStmt.constructorMethod.body, instanceCtx, _visitor); }; @@ -88,7 +92,9 @@ function createDynamicClass( class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { constructor(private reflector: CompileReflector) {} - debugAst(ast: o.Expression|o.Statement|o.Type): string { return debugOutputAstAsTypeScript(ast); } + debugAst(ast: o.Expression|o.Statement|o.Type): string { + return debugOutputAstAsTypeScript(ast); + } visitDeclareVarStmt(stmt: o.DeclareVarStmt, ctx: _ExecutionContext): any { const initialValue = stmt.value ? stmt.value.visitExpression(this, ctx) : undefined; @@ -106,7 +112,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { currCtx.vars.set(expr.name, value); return value; } - currCtx = currCtx.parent !; + currCtx = currCtx.parent!; } throw new Error(`Not declared variable ${expr.name}`); } @@ -117,7 +123,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { throw new Error('Cannot interpret a TypeofExpr'); } visitReadVarExpr(ast: o.ReadVarExpr, ctx: _ExecutionContext): any { - let varName = ast.name !; + let varName = ast.name!; if (ast.builtin != null) { switch (ast.builtin) { case o.BuiltinVar.Super: @@ -139,7 +145,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { if (currCtx.vars.has(varName)) { return currCtx.vars.get(varName); } - currCtx = currCtx.parent !; + currCtx = currCtx.parent!; } throw new Error(`Not declared variable ${varName}`); } @@ -176,7 +182,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { throw new Error(`Unknown builtin method ${expr.builtin}`); } } else { - result = receiver[expr.name !].apply(receiver, args); + result = receiver[expr.name!].apply(receiver, args); } return result; } @@ -184,7 +190,7 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { const args = this.visitAllExpressions(stmt.args, ctx); const fnExpr = stmt.fn; if (fnExpr instanceof o.ReadVarExpr && fnExpr.builtin === o.BuiltinVar.Super) { - ctx.instance !.constructor.prototype.constructor.apply(ctx.instance, args); + ctx.instance!.constructor.prototype.constructor.apply(ctx.instance, args); return null; } else { const fn = stmt.fn.visitExpression(this, ctx); @@ -227,15 +233,23 @@ class StatementInterpreter implements o.StatementVisitor, o.ExpressionVisitor { visitThrowStmt(stmt: o.ThrowStmt, ctx: _ExecutionContext): any { throw stmt.error.visitExpression(this, ctx); } - visitCommentStmt(stmt: o.CommentStmt, context?: any): any { return null; } - visitJSDocCommentStmt(stmt: o.JSDocCommentStmt, context?: any): any { return null; } + visitCommentStmt(stmt: o.CommentStmt, context?: any): any { + return null; + } + visitJSDocCommentStmt(stmt: o.JSDocCommentStmt, context?: any): any { + return null; + } visitInstantiateExpr(ast: o.InstantiateExpr, ctx: _ExecutionContext): any { const args = this.visitAllExpressions(ast.args, ctx); const clazz = ast.classExpr.visitExpression(this, ctx); return new clazz(...args); } - visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { return ast.value; } - visitLocalizedString(ast: o.LocalizedString, context: any): any { return null; } + visitLiteralExpr(ast: o.LiteralExpr, ctx: _ExecutionContext): any { + return ast.value; + } + visitLocalizedString(ast: o.LocalizedString, context: any): any { + return null; + } visitExternalExpr(ast: o.ExternalExpr, ctx: _ExecutionContext): any { return this.reflector.resolveExternalReference(ast.value); } diff --git a/packages/compiler/src/output/output_jit.ts b/packages/compiler/src/output/output_jit.ts index e446a1351bc7a..6e570cfe05bb0 100644 --- a/packages/compiler/src/output/output_jit.ts +++ b/packages/compiler/src/output/output_jit.ts @@ -87,7 +87,9 @@ export class JitEvaluator { * @param args The arguments to pass to the function being executed. * @returns The return value of the executed function. */ - executeFunction(fn: Function, args: any[]) { return fn(...args); } + executeFunction(fn: Function, args: any[]) { + return fn(...args); + } } /** @@ -98,7 +100,9 @@ export class JitEmitterVisitor extends AbstractJsEmitterVisitor { private _evalArgValues: any[] = []; private _evalExportedVars: string[] = []; - constructor(private reflector: CompileReflector) { super(); } + constructor(private reflector: CompileReflector) { + super(); + } createReturnStmt(ctx: EmitterVisitorContext) { const stmt = new o.ReturnStatement(new o.LiteralMapExpr(this._evalExportedVars.map( diff --git a/packages/compiler/src/output/source_map.ts b/packages/compiler/src/output/source_map.ts index 359e5fb071617..739f563b8fbd2 100644 --- a/packages/compiler/src/output/source_map.ts +++ b/packages/compiler/src/output/source_map.ts @@ -23,10 +23,10 @@ type Segment = { export type SourceMap = { version: number, file?: string, - sourceRoot: string, - sources: string[], - sourcesContent: (string | null)[], - mappings: string, + sourceRoot: string, + sources: string[], + sourcesContent: (string|null)[], + mappings: string, }; export class SourceMapGenerator { @@ -75,10 +75,12 @@ export class SourceMapGenerator { } /** - * @internal strip this from published d.ts files due to - * https://github.com/microsoft/TypeScript/issues/36216 - */ - private get currentLine(): Segment[]|null { return this.lines.slice(-1)[0]; } + * @internal strip this from published d.ts files due to + * https://github.com/microsoft/TypeScript/issues/36216 + */ + private get currentLine(): Segment[]|null { + return this.lines.slice(-1)[0]; + } toJSON(): SourceMap|null { if (!this.hasMappings) { @@ -87,7 +89,7 @@ export class SourceMapGenerator { const sourcesIndex = new Map<string, number>(); const sources: string[] = []; - const sourcesContent: (string | null)[] = []; + const sourcesContent: (string|null)[] = []; Array.from(this.sourcesContent.keys()).forEach((url: string, i: number) => { sourcesIndex.set(url, i); @@ -113,14 +115,14 @@ export class SourceMapGenerator { if (segment.sourceUrl != null) { // zero-based index into the “sources” list segAsStr += - toBase64VLQ(sourcesIndex.get(segment.sourceUrl) ! - lastSourceIndex); - lastSourceIndex = sourcesIndex.get(segment.sourceUrl) !; + toBase64VLQ(sourcesIndex.get(segment.sourceUrl)! - lastSourceIndex); + lastSourceIndex = sourcesIndex.get(segment.sourceUrl)!; // the zero-based starting line in the original source - segAsStr += toBase64VLQ(segment.sourceLine0 ! - lastSourceLine0); - lastSourceLine0 = segment.sourceLine0 !; + segAsStr += toBase64VLQ(segment.sourceLine0! - lastSourceLine0); + lastSourceLine0 = segment.sourceLine0!; // the zero-based starting column in the original source - segAsStr += toBase64VLQ(segment.sourceCol0 ! - lastSourceCol0); - lastSourceCol0 = segment.sourceCol0 !; + segAsStr += toBase64VLQ(segment.sourceCol0! - lastSourceCol0); + lastSourceCol0 = segment.sourceCol0!; } return segAsStr; diff --git a/packages/compiler/src/output/ts_emitter.ts b/packages/compiler/src/output/ts_emitter.ts index e82a3258e0850..514d570448962 100644 --- a/packages/compiler/src/output/ts_emitter.ts +++ b/packages/compiler/src/output/ts_emitter.ts @@ -15,8 +15,7 @@ import * as o from './output_ast'; const _debugFilePath = '/debug/lib'; -export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]): - string { +export function debugOutputAstAsTypeScript(ast: o.Statement|o.Expression|o.Type|any[]): string { const converter = new _TsEmitterVisitor(); const ctx = EmitterVisitorContext.createRoot(); const asts: any[] = Array.isArray(ast) ? ast : [ast]; @@ -147,7 +146,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor reexports = []; this.reexports.set(moduleName, reexports); } - reexports.push({name: name !, as: stmt.name}); + reexports.push({name: name!, as: stmt.name}); return null; } } @@ -175,7 +174,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor visitCastExpr(ast: o.CastExpr, ctx: EmitterVisitorContext): any { ctx.print(ast, `(<`); - ast.type !.visitType(this, ctx); + ast.type!.visitType(this, ctx); ctx.print(ast, `>`); ast.value.visitExpression(this, ctx); ctx.print(ast, `)`); @@ -422,7 +421,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor } ctx.print(null, `${prefix}.`); } - ctx.print(null, name !); + ctx.print(null, name!); if (this.typeExpression > 0) { // If we are in a type expression that refers to a generic type then supply @@ -433,7 +432,7 @@ class _TsEmitterVisitor extends AbstractEmitterVisitor implements o.TypeVisitor const suppliedParameters = typeParams || []; if (suppliedParameters.length > 0) { ctx.print(null, `<`); - this.visitAllObjects(type => type.visitType(this, ctx), typeParams !, ctx, ','); + this.visitAllObjects(type => type.visitType(this, ctx), typeParams!, ctx, ','); ctx.print(null, `>`); } } diff --git a/packages/compiler/src/output/value_util.ts b/packages/compiler/src/output/value_util.ts index dd621c3817505..b568069f36e93 100644 --- a/packages/compiler/src/output/value_util.ts +++ b/packages/compiler/src/output/value_util.ts @@ -14,7 +14,7 @@ import * as o from './output_ast'; export const QUOTED_KEYS = '$quoted$'; export function convertValueToOutputAst( - ctx: OutputContext, value: any, type: o.Type | null = null): o.Expression { + ctx: OutputContext, value: any, type: o.Type|null = null): o.Expression { return visitValue(value, new _ValueOutputAstTransformer(ctx), type); } @@ -43,7 +43,9 @@ class _ValueOutputAstTransformer implements ValueTransformer { return new o.LiteralMapExpr(entries, type); } - visitPrimitive(value: any, type: o.Type): o.Expression { return o.literal(value, type); } + visitPrimitive(value: any, type: o.Type): o.Expression { + return o.literal(value, type); + } visitOther(value: any, type: o.Type): o.Expression { if (value instanceof o.Expression) { diff --git a/packages/compiler/src/pipe_resolver.ts b/packages/compiler/src/pipe_resolver.ts index 4f15e9a3ee12c..c965571e6a082 100644 --- a/packages/compiler/src/pipe_resolver.ts +++ b/packages/compiler/src/pipe_resolver.ts @@ -7,7 +7,7 @@ */ import {CompileReflector} from './compile_reflector'; -import {Pipe, Type, createPipe} from './core'; +import {createPipe, Pipe, Type} from './core'; import {findLast} from './directive_resolver'; import {resolveForwardRef, stringify} from './util'; diff --git a/packages/compiler/src/provider_analyzer.ts b/packages/compiler/src/provider_analyzer.ts index f4b335957a7b7..677dbbaf00127 100644 --- a/packages/compiler/src/provider_analyzer.ts +++ b/packages/compiler/src/provider_analyzer.ts @@ -9,12 +9,14 @@ import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompileNgModuleMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileTokenMetadata, CompileTypeMetadata, tokenName, tokenReference} from './compile_metadata'; import {CompileReflector} from './compile_reflector'; -import {Identifiers, createTokenForExternalReference} from './identifiers'; +import {createTokenForExternalReference, Identifiers} from './identifiers'; import {ParseError, ParseSourceSpan} from './parse_util'; import {AttrAst, DirectiveAst, ProviderAst, ProviderAstType, QueryMatch, ReferenceAst} from './template_parser/template_ast'; export class ProviderError extends ParseError { - constructor(message: string, span: ParseSourceSpan) { super(span, message); } + constructor(message: string, span: ParseSourceSpan) { + super(span, message); + } } export interface QueryWithId { @@ -125,7 +127,9 @@ export class ProviderElementContext { get queryMatches(): QueryMatch[] { const allMatches: QueryMatch[] = []; - this._queriedTokens.forEach((matches: QueryMatch[]) => { allMatches.push(...matches); }); + this._queriedTokens.forEach((matches: QueryMatch[]) => { + allMatches.push(...matches); + }); return allMatches; } @@ -171,9 +175,10 @@ export class ProviderElementContext { requestingProviderType: ProviderAstType, token: CompileTokenMetadata, eager: boolean): ProviderAst|null { const resolvedProvider = this._allProviders.get(tokenReference(token)); - if (!resolvedProvider || ((requestingProviderType === ProviderAstType.Directive || - requestingProviderType === ProviderAstType.PublicService) && - resolvedProvider.providerType === ProviderAstType.PrivateService) || + if (!resolvedProvider || + ((requestingProviderType === ProviderAstType.Directive || + requestingProviderType === ProviderAstType.PublicService) && + resolvedProvider.providerType === ProviderAstType.PrivateService) || ((requestingProviderType === ProviderAstType.PrivateService || requestingProviderType === ProviderAstType.PublicService) && resolvedProvider.providerType === ProviderAstType.Builtin)) { @@ -191,25 +196,25 @@ export class ProviderElementContext { this._seenProviders.set(tokenReference(token), true); const transformedProviders = resolvedProvider.providers.map((provider) => { let transformedUseValue = provider.useValue; - let transformedUseExisting = provider.useExisting !; - let transformedDeps: CompileDiDependencyMetadata[] = undefined !; + let transformedUseExisting = provider.useExisting!; + let transformedDeps: CompileDiDependencyMetadata[] = undefined!; if (provider.useExisting != null) { const existingDiDep = this._getDependency( - resolvedProvider.providerType, {token: provider.useExisting}, eager) !; + resolvedProvider.providerType, {token: provider.useExisting}, eager)!; if (existingDiDep.token != null) { transformedUseExisting = existingDiDep.token; } else { - transformedUseExisting = null !; + transformedUseExisting = null!; transformedUseValue = existingDiDep.value; } } else if (provider.useFactory) { const deps = provider.deps || provider.useFactory.diDeps; transformedDeps = - deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager) !); + deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager)!); } else if (provider.useClass) { const deps = provider.deps || provider.useClass.diDeps; transformedDeps = - deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager) !); + deps.map((dep) => this._getDependency(resolvedProvider.providerType, dep, eager)!); } return _transformProvider(provider, { useExisting: transformedUseExisting, @@ -227,7 +232,7 @@ export class ProviderElementContext { requestingProviderType: ProviderAstType, dep: CompileDiDependencyMetadata, eager: boolean = false): CompileDiDependencyMetadata|null { if (dep.isAttribute) { - const attrValue = this._attrs[dep.token !.value]; + const attrValue = this._attrs[dep.token!.value]; return {isValue: true, value: attrValue == null ? null : attrValue}; } @@ -248,7 +253,7 @@ export class ProviderElementContext { } if (tokenReference(dep.token) === this.viewContext.reflector.resolveExternalReference(Identifiers.ViewContainerRef)) { - (this as{transformedHasViewContainer: boolean}).transformedHasViewContainer = true; + (this as {transformedHasViewContainer: boolean}).transformedHasViewContainer = true; } } // access the injector @@ -290,8 +295,8 @@ export class ProviderElementContext { // check @Host restriction if (!result) { if (!dep.isHost || this.viewContext.component.isHost || - this.viewContext.component.type.reference === tokenReference(dep.token !) || - this.viewContext.viewProviders.get(tokenReference(dep.token !)) != null) { + this.viewContext.component.type.reference === tokenReference(dep.token!) || + this.viewContext.viewProviders.get(tokenReference(dep.token!)) != null) { result = dep; } else { result = dep.isOptional ? {isValue: true, value: null} : null; @@ -368,15 +373,15 @@ export class NgModuleProviderAnalyzer { this._seenProviders.set(tokenReference(token), true); const transformedProviders = resolvedProvider.providers.map((provider) => { let transformedUseValue = provider.useValue; - let transformedUseExisting = provider.useExisting !; - let transformedDeps: CompileDiDependencyMetadata[] = undefined !; + let transformedUseExisting = provider.useExisting!; + let transformedDeps: CompileDiDependencyMetadata[] = undefined!; if (provider.useExisting != null) { const existingDiDep = this._getDependency({token: provider.useExisting}, eager, resolvedProvider.sourceSpan); if (existingDiDep.token != null) { transformedUseExisting = existingDiDep.token; } else { - transformedUseExisting = null !; + transformedUseExisting = null!; transformedUseValue = existingDiDep.value; } } else if (provider.useFactory) { @@ -478,7 +483,8 @@ function _resolveProviders( let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token)); if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) { targetErrors.push(new ProviderError( - `Mixing multi and non multi provider is not possible for token ${tokenName(resolvedProvider.token)}`, + `Mixing multi and non multi provider is not possible for token ${ + tokenName(resolvedProvider.token)}`, sourceSpan)); } if (!resolvedProvider) { diff --git a/packages/compiler/src/render3/r3_ast.ts b/packages/compiler/src/render3/r3_ast.ts index 45ae7dd79d12d..3fa682a768b6a 100644 --- a/packages/compiler/src/render3/r3_ast.ts +++ b/packages/compiler/src/render3/r3_ast.ts @@ -18,19 +18,25 @@ export interface Node { export class Text implements Node { constructor(public value: string, public sourceSpan: ParseSourceSpan) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitText(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitText(this); + } } export class BoundText implements Node { constructor(public value: AST, public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundText(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitBoundText(this); + } } export class TextAttribute implements Node { constructor( public name: string, public value: string, public sourceSpan: ParseSourceSpan, public valueSpan?: ParseSourceSpan, public i18n?: I18nMeta) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTextAttribute(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitTextAttribute(this); + } } export class BoundAttribute implements Node { @@ -45,7 +51,9 @@ export class BoundAttribute implements Node { prop.valueSpan, i18n); } - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundAttribute(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitBoundAttribute(this); + } } export class BoundEvent implements Node { @@ -62,7 +70,9 @@ export class BoundEvent implements Node { event.name, event.type, event.handler, target, phase, event.sourceSpan, event.handlerSpan); } - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitBoundEvent(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitBoundEvent(this); + } } export class Element implements Node { @@ -76,7 +86,9 @@ export class Element implements Node { this.sourceSpan = new ParseSourceSpan(sourceSpan.start, endSourceSpan.end); } } - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitElement(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitElement(this); + } } export class Template implements Node { @@ -86,36 +98,46 @@ export class Template implements Node { public children: Node[], public references: Reference[], public variables: Variable[], public sourceSpan: ParseSourceSpan, public startSourceSpan: ParseSourceSpan|null, public endSourceSpan: ParseSourceSpan|null, public i18n?: I18nMeta) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitTemplate(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitTemplate(this); + } } export class Content implements Node { constructor( public selector: string, public attributes: TextAttribute[], public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitContent(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitContent(this); + } } export class Variable implements Node { constructor( public name: string, public value: string, public sourceSpan: ParseSourceSpan, public valueSpan?: ParseSourceSpan) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitVariable(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitVariable(this); + } } export class Reference implements Node { constructor( public name: string, public value: string, public sourceSpan: ParseSourceSpan, public valueSpan?: ParseSourceSpan) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitReference(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitReference(this); + } } export class Icu implements Node { constructor( public vars: {[name: string]: BoundText}, - public placeholders: {[name: string]: Text | BoundText}, public sourceSpan: ParseSourceSpan, + public placeholders: {[name: string]: Text|BoundText}, public sourceSpan: ParseSourceSpan, public i18n?: I18nMeta) {} - visit<Result>(visitor: Visitor<Result>): Result { return visitor.visitIcu(this); } + visit<Result>(visitor: Visitor<Result>): Result { + return visitor.visitIcu(this); + } } export interface Visitor<Result = any> { @@ -210,16 +232,34 @@ export class TransformVisitor implements Visitor<Node> { return template; } - visitContent(content: Content): Node { return content; } + visitContent(content: Content): Node { + return content; + } - visitVariable(variable: Variable): Node { return variable; } - visitReference(reference: Reference): Node { return reference; } - visitTextAttribute(attribute: TextAttribute): Node { return attribute; } - visitBoundAttribute(attribute: BoundAttribute): Node { return attribute; } - visitBoundEvent(attribute: BoundEvent): Node { return attribute; } - visitText(text: Text): Node { return text; } - visitBoundText(text: BoundText): Node { return text; } - visitIcu(icu: Icu): Node { return icu; } + visitVariable(variable: Variable): Node { + return variable; + } + visitReference(reference: Reference): Node { + return reference; + } + visitTextAttribute(attribute: TextAttribute): Node { + return attribute; + } + visitBoundAttribute(attribute: BoundAttribute): Node { + return attribute; + } + visitBoundEvent(attribute: BoundEvent): Node { + return attribute; + } + visitText(text: Text): Node { + return text; + } + visitBoundText(text: BoundText): Node { + return text; + } + visitIcu(icu: Icu): Node { + return icu; + } } export function visitAll<Result>(visitor: Visitor<Result>, nodes: Node[]): Result[] { diff --git a/packages/compiler/src/render3/r3_factory.ts b/packages/compiler/src/render3/r3_factory.ts index e0bcc39ad817a..dfb6fea44b13a 100644 --- a/packages/compiler/src/render3/r3_factory.ts +++ b/packages/compiler/src/render3/r3_factory.ts @@ -89,8 +89,8 @@ export interface R3ExpressionFactoryMetadata extends R3ConstructorFactoryMetadat expression: o.Expression; } -export type R3FactoryMetadata = R3ConstructorFactoryMetadata | R3DelegatedFactoryMetadata | - R3DelegatedFnOrClassMetadata | R3ExpressionFactoryMetadata; +export type R3FactoryMetadata = R3ConstructorFactoryMetadata|R3DelegatedFactoryMetadata| + R3DelegatedFnOrClassMetadata|R3ExpressionFactoryMetadata; export enum R3FactoryTarget { Directive = 0, @@ -280,8 +280,7 @@ export function compileFactoryFunction(meta: R3FactoryMetadata): R3FactoryFn { `${meta.name}_Factory`), statements, type: o.expressionType(o.importExpr( - R3.FactoryDef, - [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType])) + R3.FactoryDef, [typeWithParameters(meta.type.type, meta.typeArgumentCount), ctorDepsType])) }; } @@ -402,7 +401,8 @@ export function dependenciesFromGlobalMetadata( // Construct the dependency. deps.push({ token, - attribute: null, resolved, + attribute: null, + resolved, host: !!dependency.isHost, optional: !!dependency.isOptional, self: !!dependency.isSelf, diff --git a/packages/compiler/src/render3/r3_jit.ts b/packages/compiler/src/render3/r3_jit.ts index 6c73d6a6a8085..89b7cc9c0c4c6 100644 --- a/packages/compiler/src/render3/r3_jit.ts +++ b/packages/compiler/src/render3/r3_jit.ts @@ -21,28 +21,44 @@ export class R3JitReflector implements CompileReflector { resolveExternalReference(ref: o.ExternalReference): any { // This reflector only handles @angular/core imports. if (ref.moduleName !== '@angular/core') { - throw new Error( - `Cannot resolve external reference to ${ref.moduleName}, only references to @angular/core are supported.`); + throw new Error(`Cannot resolve external reference to ${ + ref.moduleName}, only references to @angular/core are supported.`); } - if (!this.context.hasOwnProperty(ref.name !)) { + if (!this.context.hasOwnProperty(ref.name!)) { throw new Error(`No value provided for @angular/core symbol '${ref.name!}'.`); } - return this.context[ref.name !]; + return this.context[ref.name!]; } - parameters(typeOrFunc: any): any[][] { throw new Error('Not implemented.'); } + parameters(typeOrFunc: any): any[][] { + throw new Error('Not implemented.'); + } - annotations(typeOrFunc: any): any[] { throw new Error('Not implemented.'); } + annotations(typeOrFunc: any): any[] { + throw new Error('Not implemented.'); + } - shallowAnnotations(typeOrFunc: any): any[] { throw new Error('Not implemented.'); } + shallowAnnotations(typeOrFunc: any): any[] { + throw new Error('Not implemented.'); + } - tryAnnotations(typeOrFunc: any): any[] { throw new Error('Not implemented.'); } + tryAnnotations(typeOrFunc: any): any[] { + throw new Error('Not implemented.'); + } - propMetadata(typeOrFunc: any): {[key: string]: any[];} { throw new Error('Not implemented.'); } + propMetadata(typeOrFunc: any): {[key: string]: any[];} { + throw new Error('Not implemented.'); + } - hasLifecycleHook(type: any, lcProperty: string): boolean { throw new Error('Not implemented.'); } + hasLifecycleHook(type: any, lcProperty: string): boolean { + throw new Error('Not implemented.'); + } - guards(typeOrFunc: any): {[key: string]: any;} { throw new Error('Not implemented.'); } + guards(typeOrFunc: any): {[key: string]: any;} { + throw new Error('Not implemented.'); + } - componentModuleUrl(type: any, cmpMetadata: any): string { throw new Error('Not implemented.'); } + componentModuleUrl(type: any, cmpMetadata: any): string { + throw new Error('Not implemented.'); + } } diff --git a/packages/compiler/src/render3/r3_module_compiler.ts b/packages/compiler/src/render3/r3_module_compiler.ts index 833a88bc533e4..69379d08b2b3e 100644 --- a/packages/compiler/src/render3/r3_module_compiler.ts +++ b/packages/compiler/src/render3/r3_module_compiler.ts @@ -12,9 +12,9 @@ import {mapLiteral} from '../output/map_util'; import * as o from '../output/output_ast'; import {OutputContext} from '../util'; -import {R3DependencyMetadata, R3FactoryTarget, compileFactoryFunction} from './r3_factory'; +import {compileFactoryFunction, R3DependencyMetadata, R3FactoryTarget} from './r3_factory'; import {Identifiers as R3} from './r3_identifiers'; -import {R3Reference, convertMetaToOutput, jitOnlyGuardedExpression, mapToMapExpression} from './util'; +import {convertMetaToOutput, jitOnlyGuardedExpression, mapToMapExpression, R3Reference} from './util'; export interface R3NgModuleDef { expression: o.Expression; @@ -108,9 +108,7 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef { } = meta; const additionalStatements: o.Statement[] = []; - const definitionMap = { - type: internalType - } as{ + const definitionMap = {type: internalType} as { type: o.Expression, bootstrap: o.Expression, declarations: o.Expression, @@ -177,7 +175,7 @@ export function compileNgModule(meta: R3NgModuleMetadata): R3NgModuleDef { function generateSetNgModuleScopeCall(meta: R3NgModuleMetadata): o.Statement|null { const {adjacentType: moduleType, declarations, imports, exports, containsForwardDecls} = meta; - const scopeMap = {} as{ + const scopeMap = {} as { declarations: o.Expression, imports: o.Expression, exports: o.Expression, @@ -247,7 +245,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef { }); const definitionMap = { factory: result.factory, - } as{factory: o.Expression, providers: o.Expression, imports: o.Expression}; + } as {factory: o.Expression, providers: o.Expression, imports: o.Expression}; if (meta.providers !== null) { definitionMap.providers = meta.providers; @@ -267,7 +265,7 @@ export function compileInjector(meta: R3InjectorMetadata): R3InjectorDef { export function compileNgModuleFromRender2( ctx: OutputContext, ngModule: CompileShallowModuleMetadata, injectableCompiler: InjectableCompiler): void { - const className = identifierName(ngModule.type) !; + const className = identifierName(ngModule.type)!; const rawImports = ngModule.rawImports ? [ngModule.rawImports] : []; const rawExports = ngModule.rawExports ? [ngModule.rawExports] : []; @@ -288,7 +286,8 @@ export function compileNgModuleFromRender2( /* name */ 'ɵinj', /* type */ o.INFERRED_TYPE, /* modifiers */[o.StmtModifier.Static], - /* initializer */ injectorDef, )], + /* initializer */ injectorDef, + )], /* getters */[], /* constructorMethod */ new o.ClassMethod(null, [], []), /* methods */[])); diff --git a/packages/compiler/src/render3/r3_pipe_compiler.ts b/packages/compiler/src/render3/r3_pipe_compiler.ts index 703a001a48a25..25797c6635cbe 100644 --- a/packages/compiler/src/render3/r3_pipe_compiler.ts +++ b/packages/compiler/src/render3/r3_pipe_compiler.ts @@ -10,9 +10,9 @@ import {CompilePipeMetadata, identifierName} from '../compile_metadata'; import {CompileReflector} from '../compile_reflector'; import {DefinitionKind} from '../constant_pool'; import * as o from '../output/output_ast'; -import {OutputContext, error} from '../util'; +import {error, OutputContext} from '../util'; -import {R3DependencyMetadata, R3FactoryTarget, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory'; +import {compileFactoryFunction, dependenciesFromGlobalMetadata, R3DependencyMetadata, R3FactoryTarget} from './r3_factory'; import {Identifiers as R3} from './r3_identifiers'; import {R3Reference, typeWithParameters, wrapReference} from './util'; diff --git a/packages/compiler/src/render3/r3_template_transform.ts b/packages/compiler/src/render3/r3_template_transform.ts index 84245d0066f76..7ab7acd4ab359 100644 --- a/packages/compiler/src/render3/r3_template_transform.ts +++ b/packages/compiler/src/render3/r3_template_transform.ts @@ -215,7 +215,7 @@ class HtmlAstToIvyAst implements html.Visitor { // Moreover, if the node is an element, then we need to hoist its attributes to the template // node for matching against content projection selectors. const attrs = this.extractAttributes('ng-template', templateParsedProperties, i18nAttrsMeta); - const templateAttrs: (t.TextAttribute | t.BoundAttribute)[] = []; + const templateAttrs: (t.TextAttribute|t.BoundAttribute)[] = []; attrs.literal.forEach(attr => templateAttrs.push(attr)); attrs.bound.forEach(attr => templateAttrs.push(attr)); const hoistedAttrs = parsedElement instanceof t.Element ? @@ -260,12 +260,12 @@ class HtmlAstToIvyAst implements html.Visitor { return null; } if (!isI18nRootNode(expansion.i18n)) { - throw new Error( - `Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${expansion.sourceSpan.toString()}. Expected a "Message"`); + throw new Error(`Invalid type "${expansion.i18n.constructor}" for "i18n" property of ${ + expansion.sourceSpan.toString()}. Expected a "Message"`); } const message = expansion.i18n; const vars: {[name: string]: t.BoundText} = {}; - const placeholders: {[name: string]: t.Text | t.BoundText} = {}; + const placeholders: {[name: string]: t.Text|t.BoundText} = {}; // extract VARs from ICUs - we process them separately while // assembling resulting message via goog.getMsg function, since // we need to pass them to top-level goog.getMsg call @@ -284,9 +284,13 @@ class HtmlAstToIvyAst implements html.Visitor { return new t.Icu(vars, placeholders, expansion.sourceSpan, message); } - visitExpansionCase(expansionCase: html.ExpansionCase): null { return null; } + visitExpansionCase(expansionCase: html.ExpansionCase): null { + return null; + } - visitComment(comment: html.Comment): null { return null; } + visitComment(comment: html.Comment): null { + return null; + } // convert view engine `ParsedProperty` to a format suitable for IVY private extractAttributes( @@ -460,18 +464,26 @@ class NonBindableVisitor implements html.Visitor { ast.startSourceSpan, ast.endSourceSpan); } - visitComment(comment: html.Comment): any { return null; } + visitComment(comment: html.Comment): any { + return null; + } visitAttribute(attribute: html.Attribute): t.TextAttribute { return new t.TextAttribute( attribute.name, attribute.value, attribute.sourceSpan, undefined, attribute.i18n); } - visitText(text: html.Text): t.Text { return new t.Text(text.value, text.sourceSpan); } + visitText(text: html.Text): t.Text { + return new t.Text(text.value, text.sourceSpan); + } - visitExpansion(expansion: html.Expansion): any { return null; } + visitExpansion(expansion: html.Expansion): any { + return null; + } - visitExpansionCase(expansionCase: html.ExpansionCase): any { return null; } + visitExpansionCase(expansionCase: html.ExpansionCase): any { + return null; + } } const NON_BINDABLE_VISITOR = new NonBindableVisitor(); diff --git a/packages/compiler/src/render3/util.ts b/packages/compiler/src/render3/util.ts index 5572495dcfffb..a450f8c0f28c0 100644 --- a/packages/compiler/src/render3/util.ts +++ b/packages/compiler/src/render3/util.ts @@ -13,14 +13,13 @@ import {OutputContext} from '../util'; /** * Convert an object map with `Expression` values into a `LiteralMapExpr`. */ -export function mapToMapExpression(map: {[key: string]: o.Expression | undefined}): - o.LiteralMapExpr { +export function mapToMapExpression(map: {[key: string]: o.Expression|undefined}): o.LiteralMapExpr { const result = Object.keys(map).map( key => ({ key, // The assertion here is because really TypeScript doesn't allow us to express that if the // key is present, it will have a value, but this is true in reality. - value: map[key] !, + value: map[key]!, quoted: false, })); return o.literalMap(result); diff --git a/packages/compiler/src/render3/view/api.ts b/packages/compiler/src/render3/view/api.ts index 5b6a2d55945b1..a369af694d80c 100644 --- a/packages/compiler/src/render3/view/api.ts +++ b/packages/compiler/src/render3/view/api.ts @@ -88,7 +88,7 @@ export interface R3DirectiveMetadata { /** * A mapping of input field names to the property names. */ - inputs: {[field: string]: string | [string, string]}; + inputs: {[field: string]: string|[string, string]}; /** * A mapping of output field names to the property names. diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index eb924357e82ce..08b6344011341 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -20,17 +20,17 @@ import {CssSelector, SelectorMatcher} from '../../selector'; import {ShadowCss} from '../../shadow_css'; import {CONTENT_ATTR, HOST_ATTR} from '../../style_compiler'; import {BindingParser} from '../../template_parser/binding_parser'; -import {OutputContext, error} from '../../util'; +import {error, OutputContext} from '../../util'; import {BoundEvent} from '../r3_ast'; -import {R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType, compileFactoryFunction} from '../r3_factory'; +import {compileFactoryFunction, R3DependencyMetadata, R3FactoryTarget, R3ResolvedDependencyType} from '../r3_factory'; import {Identifiers as R3} from '../r3_identifiers'; import {Render3ParseResult} from '../r3_template_transform'; import {prepareSyntheticListenerFunctionName, prepareSyntheticPropertyName, typeWithParameters} from '../util'; import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3HostMetadata, R3QueryMetadata} from './api'; import {MIN_STYLING_BINDING_SLOTS_REQUIRED, StylingBuilder, StylingInstructionCall} from './styling_builder'; -import {BindingScope, TemplateDefinitionBuilder, ValueConverter, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn} from './template'; -import {CONTEXT_NAME, DefinitionMap, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, chainedInstruction, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator} from './util'; +import {BindingScope, makeBindingParser, prepareEventListenerParameters, renderFlagCheckIfStmt, resolveSanitizationFn, TemplateDefinitionBuilder, ValueConverter} from './template'; +import {asLiteral, chainedInstruction, conditionallyCreateMapObjectLiteral, CONTEXT_NAME, DefinitionMap, getQueryPredicate, RENDER_FLAGS, TEMPORARY_NAME, temporaryAllocator} from './util'; const EMPTY_ARRAY: any[] = []; @@ -65,9 +65,10 @@ function baseDirectiveFields( // e.g. `hostBindings: (rf, ctx) => { ... } definitionMap.set( - 'hostBindings', createHostBindingsFunction( - meta.host, meta.typeSourceSpan, bindingParser, constantPool, - meta.selector || '', meta.name, definitionMap)); + 'hostBindings', + createHostBindingsFunction( + meta.host, meta.typeSourceSpan, bindingParser, constantPool, meta.selector || '', + meta.name, definitionMap)); // e.g 'inputs: {a: 'a'}` definitionMap.set('inputs', conditionallyCreateMapObjectLiteral(meta.inputs, true)); @@ -85,8 +86,7 @@ function baseDirectiveFields( /** * Add features to the definition map. */ -function addFeatures( - definitionMap: DefinitionMap, meta: R3DirectiveMetadata | R3ComponentMetadata) { +function addFeatures(definitionMap: DefinitionMap, meta: R3DirectiveMetadata|R3ComponentMetadata) { // e.g. `features: [NgOnChangesFeature]` const features: o.Expression[] = []; @@ -148,10 +148,11 @@ export function compileComponentFromMetadata( const selectorAttributes = firstSelector.getAttrs(); if (selectorAttributes.length) { definitionMap.set( - 'attrs', constantPool.getConstLiteral( - o.literalArr(selectorAttributes.map( - value => value != null ? o.literal(value) : o.literal(undefined))), - /* forceShared */ true)); + 'attrs', + constantPool.getConstLiteral( + o.literalArr(selectorAttributes.map( + value => value != null ? o.literal(value) : o.literal(undefined))), + /* forceShared */ true)); } } @@ -273,7 +274,7 @@ export function compileComponentFromMetadata( export function compileDirectiveFromRender2( outputCtx: OutputContext, directive: CompileDirectiveMetadata, reflector: CompileReflector, bindingParser: BindingParser) { - const name = identifierName(directive.type) !; + const name = identifierName(directive.type)!; name || error(`Cannot resolver the name of ${directive.type}`); const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Directive); @@ -306,7 +307,7 @@ export function compileComponentFromRender2( outputCtx: OutputContext, component: CompileDirectiveMetadata, render3Ast: Render3ParseResult, reflector: CompileReflector, bindingParser: BindingParser, directiveTypeBySel: Map<string, any>, pipeTypeByName: Map<string, any>) { - const name = identifierName(component.type) !; + const name = identifierName(component.type)!; name || error(`Cannot resolver the name of ${component.type}`); const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Component); @@ -372,7 +373,8 @@ function queriesFromGlobalMetadata( propertyName: query.propertyName, first: query.first, predicate: selectorsFromGlobalMetadata(query.selectors, outputCtx), - descendants: query.descendants, read, + descendants: query.descendants, + read, static: !!query.static }; }); @@ -464,7 +466,7 @@ function stringAsType(str: string): o.Type { return o.expressionType(o.literal(str)); } -function stringMapAsType(map: {[key: string]: string | string[]}): o.Type { +function stringMapAsType(map: {[key: string]: string|string[]}): o.Type { const mapValues = Object.keys(map).map(key => { const value = Array.isArray(map[key]) ? map[key][0] : map[key]; return { @@ -723,7 +725,7 @@ function convertStylingCall( function getBindingNameAndInstruction(binding: ParsedProperty): {bindingName: string, instruction: o.ExternalReference, isAttribute: boolean} { let bindingName = binding.name; - let instruction !: o.ExternalReference; + let instruction!: o.ExternalReference; // Check to see if this is an attr binding or a property binding const attrMatches = bindingName.match(ATTR_REGEX); @@ -817,8 +819,7 @@ export interface ParsedHostBindings { specialAttributes: {styleAttr?: string; classAttr?: string;}; } -export function parseHostBindings(host: {[key: string]: string | o.Expression}): - ParsedHostBindings { +export function parseHostBindings(host: {[key: string]: string|o.Expression}): ParsedHostBindings { const attributes: {[key: string]: o.Expression} = {}; const listeners: {[key: string]: string} = {}; const properties: {[key: string]: string} = {}; @@ -893,5 +894,7 @@ export function verifyHostBindings( function compileStyles(styles: string[], selector: string, hostSelector: string): string[] { const shadowCss = new ShadowCss(); - return styles.map(style => { return shadowCss !.shimCssText(style, selector, hostSelector); }); + return styles.map(style => { + return shadowCss!.shimCssText(style, selector, hostSelector); + }); } diff --git a/packages/compiler/src/render3/view/i18n/context.ts b/packages/compiler/src/render3/view/i18n/context.ts index 2151b19938589..7ca7b64d9f758 100644 --- a/packages/compiler/src/render3/view/i18n/context.ts +++ b/packages/compiler/src/render3/view/i18n/context.ts @@ -46,7 +46,7 @@ export class I18nContext { public placeholders = new Map<string, any[]>(); public isEmitted: boolean = false; - private _registry !: any; + private _registry!: any; private _unresolvedCtxCount: number = 0; constructor( @@ -66,9 +66,15 @@ export class I18nContext { updatePlaceholderMap(this.placeholders, ph, content); } - get icus() { return this._registry.icus; } - get isRoot() { return this.level === 0; } - get isResolved() { return this._unresolvedCtxCount === 0; } + get icus() { + return this._registry.icus; + } + get isRoot() { + return this.level === 0; + } + get isResolved() { + return this._unresolvedCtxCount === 0; + } getSerializedPlaceholders() { const result = new Map<string, any[]>(); @@ -78,7 +84,9 @@ export class I18nContext { } // public API to accumulate i18n-related content - appendBinding(binding: AST) { this.bindings.add(binding); } + appendBinding(binding: AST) { + this.bindings.add(binding); + } appendIcu(name: string, ref: o.Expression) { updatePlaceholderMap(this._registry.icus, name, ref); } @@ -181,7 +189,7 @@ function wrapTag(symbol: string, {index, ctx, isVoid}: any, closed?: boolean): s wrap(symbol, index, ctx, closed); } -function findTemplateFn(ctx: number, templateIndex: number | null) { +function findTemplateFn(ctx: number, templateIndex: number|null) { return (token: any) => typeof token === 'object' && token.type === TagType.TEMPLATE && token.index === templateIndex && token.ctx === ctx; } diff --git a/packages/compiler/src/render3/view/i18n/get_msg_utils.ts b/packages/compiler/src/render3/view/i18n/get_msg_utils.ts index e601904793492..d03fa7660a7bc 100644 --- a/packages/compiler/src/render3/view/i18n/get_msg_utils.ts +++ b/packages/compiler/src/render3/view/i18n/get_msg_utils.ts @@ -47,23 +47,32 @@ export function createGoogleGetMsgStatements( * placeholders in `{$placeholder}` (for plain messages) or `{PLACEHOLDER}` (inside ICUs) format. */ class GetMsgSerializerVisitor implements i18n.Visitor { - private formatPh(value: string): string { return `{$${formatI18nPlaceholderName(value)}}`; } + private formatPh(value: string): string { + return `{$${formatI18nPlaceholderName(value)}}`; + } - visitText(text: i18n.Text): any { return text.value; } + visitText(text: i18n.Text): any { + return text.value; + } visitContainer(container: i18n.Container): any { return container.children.map(child => child.visit(this)).join(''); } - visitIcu(icu: i18n.Icu): any { return serializeIcuNode(icu); } + visitIcu(icu: i18n.Icu): any { + return serializeIcuNode(icu); + } visitTagPlaceholder(ph: i18n.TagPlaceholder): any { return ph.isVoid ? this.formatPh(ph.startName) : - `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`; + `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${ + this.formatPh(ph.closeName)}`; } - visitPlaceholder(ph: i18n.Placeholder): any { return this.formatPh(ph.name); } + visitPlaceholder(ph: i18n.Placeholder): any { + return this.formatPh(ph.name); + } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any { return this.formatPh(ph.name); diff --git a/packages/compiler/src/render3/view/i18n/icu_serializer.ts b/packages/compiler/src/render3/view/i18n/icu_serializer.ts index 8e5aa0b7ffd66..c0f645bf3f8aa 100644 --- a/packages/compiler/src/render3/view/i18n/icu_serializer.ts +++ b/packages/compiler/src/render3/view/i18n/icu_serializer.ts @@ -11,7 +11,9 @@ import * as i18n from '../../../i18n/i18n_ast'; import {formatI18nPlaceholderName} from './util'; class IcuSerializerVisitor implements i18n.Visitor { - visitText(text: i18n.Text): any { return text.value; } + visitText(text: i18n.Text): any { + return text.value; + } visitContainer(container: i18n.Container): any { return container.children.map(child => child.visit(this)).join(''); @@ -27,10 +29,13 @@ class IcuSerializerVisitor implements i18n.Visitor { visitTagPlaceholder(ph: i18n.TagPlaceholder): any { return ph.isVoid ? this.formatPh(ph.startName) : - `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${this.formatPh(ph.closeName)}`; + `${this.formatPh(ph.startName)}${ph.children.map(child => child.visit(this)).join('')}${ + this.formatPh(ph.closeName)}`; } - visitPlaceholder(ph: i18n.Placeholder): any { return this.formatPh(ph.name); } + visitPlaceholder(ph: i18n.Placeholder): any { + return this.formatPh(ph.name); + } visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any { return this.formatPh(ph.name); diff --git a/packages/compiler/src/render3/view/i18n/localize_utils.ts b/packages/compiler/src/render3/view/i18n/localize_utils.ts index 2e8dc4cdb6915..e3c79c28983e2 100644 --- a/packages/compiler/src/render3/view/i18n/localize_utils.ts +++ b/packages/compiler/src/render3/view/i18n/localize_utils.ts @@ -28,7 +28,9 @@ class MessagePiece { } class LiteralPiece extends MessagePiece {} class PlaceholderPiece extends MessagePiece { - constructor(name: string) { super(formatI18nPlaceholderName(name, /* useCamelCase */ false)); } + constructor(name: string) { + super(formatI18nPlaceholderName(name, /* useCamelCase */ false)); + } } /** diff --git a/packages/compiler/src/render3/view/i18n/meta.ts b/packages/compiler/src/render3/view/i18n/meta.ts index 6269e69e27673..d294b40258ce0 100644 --- a/packages/compiler/src/render3/view/i18n/meta.ts +++ b/packages/compiler/src/render3/view/i18n/meta.ts @@ -8,12 +8,12 @@ import {computeDecimalDigest, computeDigest, decimalDigest} from '../../../i18n/digest'; import * as i18n from '../../../i18n/i18n_ast'; -import {VisitNodeFn, createI18nMessageFactory} from '../../../i18n/i18n_parser'; +import {createI18nMessageFactory, VisitNodeFn} from '../../../i18n/i18n_parser'; import * as html from '../../../ml_parser/ast'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../ml_parser/interpolation_config'; import * as o from '../../../output/output_ast'; -import {I18N_ATTR, I18N_ATTR_PREFIX, hasI18nAttrs, icuFromI18nMessage} from './util'; +import {hasI18nAttrs, I18N_ATTR, I18N_ATTR_PREFIX, icuFromI18nMessage} from './util'; export type I18nMeta = { id?: string, @@ -134,10 +134,18 @@ export class I18nMetaVisitor implements html.Visitor { return expansion; } - visitText(text: html.Text): any { return text; } - visitAttribute(attribute: html.Attribute): any { return attribute; } - visitComment(comment: html.Comment): any { return comment; } - visitExpansionCase(expansionCase: html.ExpansionCase): any { return expansionCase; } + visitText(text: html.Text): any { + return text; + } + visitAttribute(attribute: html.Attribute): any { + return attribute; + } + visitComment(comment: html.Comment): any { + return comment; + } + visitExpansionCase(expansionCase: html.ExpansionCase): any { + return expansionCase; + } /** * Parse the general form `meta` passed into extract the explicit metadata needed to create a diff --git a/packages/compiler/src/render3/view/i18n/util.ts b/packages/compiler/src/render3/view/i18n/util.ts index baa0e2e9f7b9c..c6b48ee840133 100644 --- a/packages/compiler/src/render3/view/i18n/util.ts +++ b/packages/compiler/src/render3/view/i18n/util.ts @@ -49,7 +49,7 @@ export function icuFromI18nMessage(message: i18n.Message) { return message.nodes[0] as i18n.IcuPlaceholder; } -export function wrapI18nPlaceholder(content: string | number, contextId: number = 0): string { +export function wrapI18nPlaceholder(content: string|number, contextId: number = 0): string { const blockId = contextId > 0 ? `:${contextId}` : ''; return `${I18N_PLACEHOLDER_SYMBOL}${content}${blockId}${I18N_PLACEHOLDER_SYMBOL}`; } @@ -147,7 +147,7 @@ export function formatI18nPlaceholderName(name: string, useCamelCase: boolean = if (/^\d+$/.test(chunks[chunks.length - 1])) { postfix = chunks.pop(); } - let raw = chunks.shift() !.toLowerCase(); + let raw = chunks.shift()!.toLowerCase(); if (chunks.length) { raw += chunks.map(c => c.charAt(0).toUpperCase() + c.slice(1).toLowerCase()).join(''); } @@ -170,5 +170,5 @@ export function getTranslationConstPrefix(extra: string): string { */ export function declareI18nVariable(variable: o.ReadVarExpr): o.Statement { return new o.DeclareVarStmt( - variable.name !, undefined, o.INFERRED_TYPE, null, variable.sourceSpan); + variable.name!, undefined, o.INFERRED_TYPE, null, variable.sourceSpan); } diff --git a/packages/compiler/src/render3/view/style_parser.ts b/packages/compiler/src/render3/view/style_parser.ts index f0de8e362ba6c..668df7d27e3df 100644 --- a/packages/compiler/src/render3/view/style_parser.ts +++ b/packages/compiler/src/render3/view/style_parser.ts @@ -110,7 +110,11 @@ export function stripUnnecessaryQuotes(value: string): string { } export function hyphenate(value: string): string { - return value.replace(/[a-z][A-Z]/g, v => { - return v.charAt(0) + '-' + v.charAt(1); - }).toLowerCase(); + return value + .replace( + /[a-z][A-Z]/g, + v => { + return v.charAt(0) + '-' + v.charAt(1); + }) + .toLowerCase(); } diff --git a/packages/compiler/src/render3/view/styling_builder.ts b/packages/compiler/src/render3/view/styling_builder.ts index 2ac2d6114ee93..6860d3e543344 100644 --- a/packages/compiler/src/render3/view/styling_builder.ts +++ b/packages/compiler/src/render3/view/styling_builder.ts @@ -226,7 +226,10 @@ export class StylingBuilder { const entry: BoundStylingEntry = { name: property, sanitize: property ? isStyleSanitizable(property) : true, - unit: unit || bindingUnit, value, sourceSpan, hasOverrideFlag + unit: unit || bindingUnit, + value, + sourceSpan, + hasOverrideFlag }; if (isMapBased) { this._styleMapInput = entry; @@ -385,7 +388,7 @@ export class StylingBuilder { supportsInterpolation: true, sourceSpan: stylingInput.sourceSpan, allocateBindingSlots: totalBindingSlotsRequired, - params: (convertFn: (value: any) => o.Expression | o.Expression[]) => { + params: (convertFn: (value: any) => o.Expression|o.Expression[]) => { const convertResult = convertFn(mapValue); const params = Array.isArray(convertResult) ? convertResult : [convertResult]; return params; diff --git a/packages/compiler/src/render3/view/t2_api.ts b/packages/compiler/src/render3/view/t2_api.ts index ed651075b89a4..c0d2de5b2cf17 100644 --- a/packages/compiler/src/render3/view/t2_api.ts +++ b/packages/compiler/src/render3/view/t2_api.ts @@ -22,7 +22,9 @@ import {BoundAttribute, BoundEvent, Element, Node, Reference, Template, TextAttr /** * A logical target for analysis, which could contain a template or other types of bindings. */ -export interface Target { template?: Node[]; } +export interface Target { + template?: Node[]; +} /** * Metadata regarding a directive that's needed to match it against template elements. This is @@ -44,7 +46,7 @@ export interface DirectiveMeta { * * Goes from property names to field names. */ - inputs: {[property: string]: string | [string, string]}; + inputs: {[property: string]: string|[string, string]}; /** * Set of outputs which this directive claims. @@ -67,7 +69,9 @@ export interface DirectiveMeta { * * The returned `BoundTarget` has an API for extracting information about the processed target. */ -export interface TargetBinder<D extends DirectiveMeta> { bind(target: Target): BoundTarget<D>; } +export interface TargetBinder<D extends DirectiveMeta> { + bind(target: Target): BoundTarget<D>; +} /** * Result of performing the binding operation against a `Target`. diff --git a/packages/compiler/src/render3/view/t2_binder.ts b/packages/compiler/src/render3/view/t2_binder.ts index e56270c972ce5..2f6eba2ce6005 100644 --- a/packages/compiler/src/render3/view/t2_binder.ts +++ b/packages/compiler/src/render3/view/t2_binder.ts @@ -152,7 +152,7 @@ class Scope implements Visitor { lookup(name: string): Reference|Variable|null { if (this.namedEntities.has(name)) { // Found in the local scope. - return this.namedEntities.get(name) !; + return this.namedEntities.get(name)!; } else if (this.parentScope !== undefined) { // Not in the local scope, but there's a parent scope so check there. return this.parentScope.lookup(name); @@ -217,11 +217,17 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor { return {directives, bindings, references}; } - private ingest(template: Node[]): void { template.forEach(node => node.visit(this)); } + private ingest(template: Node[]): void { + template.forEach(node => node.visit(this)); + } - visitElement(element: Element): void { this.visitElementOrTemplate(element.name, element); } + visitElement(element: Element): void { + this.visitElementOrTemplate(element.name, element); + } - visitTemplate(template: Template): void { this.visitElementOrTemplate('ng-template', template); } + visitTemplate(template: Template): void { + this.visitElementOrTemplate('ng-template', template); + } visitElementOrTemplate(elementName: string, node: Element|Template): void { // First, determine the HTML shape of the node for the purpose of directive matching. @@ -269,7 +275,7 @@ class DirectiveBinder<DirectiveT extends DirectiveMeta> implements Visitor { }); // Associate attributes/bindings on the node with directives or with the node itself. - type BoundNode = BoundAttribute | BoundEvent | TextAttribute; + type BoundNode = BoundAttribute|BoundEvent|TextAttribute; const setAttributeBinding = (attribute: BoundNode, ioType: keyof Pick<DirectiveMeta, 'inputs'|'outputs'>) => { const dir = directives.find(dir => dir[ioType].hasOwnProperty(attribute.name)); @@ -432,11 +438,17 @@ class TemplateBinder extends RecursiveAstVisitor implements Visitor { // The remaining visitors are concerned with processing AST expressions within template bindings - visitBoundAttribute(attribute: BoundAttribute) { attribute.value.visit(this); } + visitBoundAttribute(attribute: BoundAttribute) { + attribute.value.visit(this); + } - visitBoundEvent(event: BoundEvent) { event.handler.visit(this); } + visitBoundEvent(event: BoundEvent) { + event.handler.visit(this); + } - visitBoundText(text: BoundText) { text.value.visit(this); } + visitBoundText(text: BoundText) { + text.value.visit(this); + } visitPipe(ast: BindingPipe, context: any): any { this.usedPipes.add(ast.name); return super.visitPipe(ast, context); @@ -526,7 +538,9 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar return this.symbols.get(symbol) || null; } - getNestingLevel(template: Template): number { return this.nestingLevel.get(template) || 0; } + getNestingLevel(template: Template): number { + return this.nestingLevel.get(template) || 0; + } getUsedDirectives(): DirectiveT[] { const set = new Set<DirectiveT>(); @@ -534,5 +548,7 @@ export class R3BoundTarget<DirectiveT extends DirectiveMeta> implements BoundTar return Array.from(set.values()); } - getUsedPipes(): string[] { return Array.from(this.usedPipes); } + getUsedPipes(): string[] { + return Array.from(this.usedPipes); + } } diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index afbee7b6d4cec..f92a3904ceaf6 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -7,7 +7,7 @@ */ import {flatten, sanitizeIdentifier} from '../../compile_metadata'; -import {BindingForm, BuiltinFunctionCall, LocalResolver, convertActionBinding, convertPropertyBinding, convertUpdateArguments} from '../../compiler_util/expression_converter'; +import {BindingForm, BuiltinFunctionCall, convertActionBinding, convertPropertyBinding, convertUpdateArguments, LocalResolver} from '../../compiler_util/expression_converter'; import {ConstantPool} from '../../constant_pool'; import * as core from '../../core'; import {AST, AstMemoryEfficientTransformer, BindingPipe, BindingType, FunctionCall, ImplicitReceiver, Interpolation, LiteralArray, LiteralMap, LiteralPrimitive, ParsedEventType, PropertyRead} from '../../expression_parser/ast'; @@ -36,9 +36,9 @@ import {I18nContext} from './i18n/context'; import {createGoogleGetMsgStatements} from './i18n/get_msg_utils'; import {createLocalizeStatements} from './i18n/localize_utils'; import {I18nMetaVisitor} from './i18n/meta'; -import {I18N_ICU_MAPPING_PREFIX, TRANSLATION_PREFIX, assembleBoundTextPlaceholders, assembleI18nBoundString, declareI18nVariable, getTranslationConstPrefix, i18nFormatPlaceholderNames, icuFromI18nMessage, isI18nRootNode, isSingleI18nIcu, placeholdersToParams, wrapI18nPlaceholder} from './i18n/util'; +import {assembleBoundTextPlaceholders, assembleI18nBoundString, declareI18nVariable, getTranslationConstPrefix, I18N_ICU_MAPPING_PREFIX, i18nFormatPlaceholderNames, icuFromI18nMessage, isI18nRootNode, isSingleI18nIcu, placeholdersToParams, TRANSLATION_PREFIX, wrapI18nPlaceholder} from './i18n/util'; import {StylingBuilder, StylingInstruction} from './styling_builder'; -import {CONTEXT_NAME, IMPLICIT_REFERENCE, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, asLiteral, chainedInstruction, getAttrsForDirectiveMatching, getInterpolationArgsLength, invalid, trimTrailingNulls, unsupported} from './util'; +import {asLiteral, chainedInstruction, CONTEXT_NAME, getAttrsForDirectiveMatching, getInterpolationArgsLength, IMPLICIT_REFERENCE, invalid, NON_BINDABLE_ATTR, REFERENCE_PREFIX, RENDER_FLAGS, trimTrailingNulls, unsupported} from './util'; @@ -61,8 +61,8 @@ export function renderFlagCheckIfStmt( } export function prepareEventListenerParameters( - eventAst: t.BoundEvent, handlerName: string | null = null, - scope: BindingScope | null = null): o.Expression[] { + eventAst: t.BoundEvent, handlerName: string|null = null, + scope: BindingScope|null = null): o.Expression[] { const {type, name, target, phase, handler} = eventAst; if (target && !GLOBAL_TARGET_RESOLVERS.has(target)) { throw new Error(`Unexpected global target '${target}' defined for '${name}' event. @@ -85,7 +85,7 @@ export function prepareEventListenerParameters( statements.push(...bindingExpr.render3Stmts); const eventName: string = - type === ParsedEventType.Animation ? prepareSyntheticListenerName(name, phase !) : name; + type === ParsedEventType.Animation ? prepareSyntheticListenerName(name, phase!) : name; const fnName = handlerName && sanitizeIdentifier(handlerName); const fnArgs: o.FnParam[] = []; @@ -98,7 +98,7 @@ export function prepareEventListenerParameters( if (target) { params.push( o.literal(false), // `useCapture` flag, defaults to `false` - o.importExpr(GLOBAL_TARGET_RESOLVERS.get(target) !)); + o.importExpr(GLOBAL_TARGET_RESOLVERS.get(target)!)); } return params; } @@ -207,12 +207,12 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver // - this template has parent i18n context // - or the template has i18n meta associated with it, // but it's not initiated by the Element (e.g. <ng-template i18n>) - const initI18nContext = - this.i18nContext || (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) && - !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n)); + const initI18nContext = this.i18nContext || + (isI18nRootNode(i18n) && !isSingleI18nIcu(i18n) && + !(isSingleElementTemplate(nodes) && nodes[0].i18n === i18n)); const selfClosingI18nInstruction = hasTextChildrenOnly(nodes); if (initI18nContext) { - this.i18nStart(null, i18n !, selfClosingI18nInstruction); + this.i18nStart(null, i18n!, selfClosingI18nInstruction); } // This is the initial pass through the nodes of this template. In this pass, we @@ -295,10 +295,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver } // LocalResolver - getLocal(name: string): o.Expression|null { return this._bindingScope.get(name); } + getLocal(name: string): o.Expression|null { + return this._bindingScope.get(name); + } // LocalResolver - notifyImplicitReceiverUse(): void { this._bindingScope.notifyImplicitReceiverUse(); } + notifyImplicitReceiverUse(): void { + this._bindingScope.notifyImplicitReceiverUse(); + } private i18nTranslate( message: i18n.Message, params: {[name: string]: o.Expression} = {}, ref?: o.ReadVarExpr, @@ -335,12 +339,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver private i18nAppendBindings(expressions: AST[]) { if (expressions.length > 0) { - expressions.forEach(expression => this.i18n !.appendBinding(expression)); + expressions.forEach(expression => this.i18n!.appendBinding(expression)); } } - private i18nBindProps(props: {[key: string]: t.Text | t.BoundText}): - {[key: string]: o.Expression} { + private i18nBindProps(props: {[key: string]: t.Text|t.BoundText}): {[key: string]: o.Expression} { const bound: {[key: string]: o.Expression} = {}; Object.keys(props).forEach(key => { const prop = props[key]; @@ -351,7 +354,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver this.allocateBindingSlots(value); if (value instanceof Interpolation) { const {strings, expressions} = value; - const {id, bindings} = this.i18n !; + const {id, bindings} = this.i18n!; const label = assembleI18nBoundString(strings, bindings.size, id); this.i18nAppendBindings(expressions); bound[key] = o.literal(label); @@ -424,7 +427,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver void { const index = this.allocateDataSlot(); if (this.i18nContext) { - this.i18n = this.i18nContext.forkChildContext(index, this.templateIndex !, meta); + this.i18n = this.i18nContext.forkChildContext(index, this.templateIndex!, meta); } else { const ref = o.variable(this.constantPool.uniqueName(TRANSLATION_PREFIX)); this.i18n = new I18nContext(index, ref, 0, this.templateIndex, meta); @@ -479,7 +482,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver const i18nAttrArgs: o.Expression[] = []; const bindings: ChainableBindingInstruction[] = []; attrs.forEach(attr => { - const message = attr.i18n !as i18n.Message; + const message = attr.i18n! as i18n.Message; if (attr instanceof t.TextAttribute) { i18nAttrArgs.push(o.literal(attr.name), this.i18nTranslate(message)); } else { @@ -559,7 +562,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver this.creationInstruction(ngContent.sourceSpan, R3.projection, parameters); if (this.i18n) { - this.i18n.appendProjection(ngContent.i18n !, slot); + this.i18n.appendProjection(ngContent.i18n!, slot); } } @@ -571,7 +574,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver const isI18nRootElement: boolean = isI18nRootNode(element.i18n) && !isSingleI18nIcu(element.i18n); - const i18nAttrs: (t.TextAttribute | t.BoundAttribute)[] = []; + const i18nAttrs: (t.TextAttribute|t.BoundAttribute)[] = []; const outputAttrs: t.TextAttribute[] = []; const [namespaceKey, elementName] = splitNsName(element.name); @@ -633,7 +636,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver } if (this.i18n) { - this.i18n.appendElement(element.i18n !, elementIndex); + this.i18n.appendElement(element.i18n!, elementIndex); } // Note that we do not append text node instructions and ICUs inside i18n section, @@ -676,7 +679,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver // Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and // listeners, to make sure i18nAttributes instruction targets current element at runtime. if (isI18nRootElement) { - this.i18nStart(element.sourceSpan, element.i18n !, createSelfClosingI18nInstruction); + this.i18nStart(element.sourceSpan, element.i18n!, createSelfClosingI18nInstruction); } } @@ -757,7 +760,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver propertyBindings.push({ name: attrName, sourceSpan: input.sourceSpan, - value: () => this.convertPropertyBinding(value), params + value: () => this.convertPropertyBinding(value), + params }); } } else if (inputType === BindingType.Attribute) { @@ -773,7 +777,8 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver attributeBindings.push({ name: attrName, sourceSpan: input.sourceSpan, - value: () => this.convertPropertyBinding(boundValue), params + value: () => this.convertPropertyBinding(boundValue), + params }); } } else { @@ -801,7 +806,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver t.visitAll(this, element.children); if (!isI18nRootElement && this.i18n) { - this.i18n.appendElement(element.i18n !, elementIndex, true); + this.i18n.appendElement(element.i18n!, elementIndex, true); } if (!createSelfClosingInstruction) { @@ -823,7 +828,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver const templateIndex = this.allocateDataSlot(); if (this.i18n) { - this.i18n.appendTemplate(template.i18n !, templateIndex); + this.i18n.appendTemplate(template.i18n!, templateIndex); } const tagName = sanitizeIdentifier(template.tagName || ''); @@ -892,7 +897,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver // Only add normal input/output binding instructions on explicit <ng-template> elements. if (template.tagName === NG_TEMPLATE_TAG_NAME) { const inputs: t.BoundAttribute[] = []; - const i18nAttrs: (t.TextAttribute | t.BoundAttribute)[] = + const i18nAttrs: (t.TextAttribute|t.BoundAttribute)[] = template.attributes.filter(attr => !!attr.i18n); template.inputs.forEach( @@ -935,7 +940,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver const value = text.value.visit(this._valueConverter); this.allocateBindingSlots(value); if (value instanceof Interpolation) { - this.i18n.appendBoundText(text.i18n !); + this.i18n.appendBoundText(text.i18n!); this.i18nAppendBindings(value.expressions); } return; @@ -975,15 +980,15 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver // to generate i18n context and the necessary instructions if (!this.i18n) { initWasInvoked = true; - this.i18nStart(null, icu.i18n !, true); + this.i18nStart(null, icu.i18n!, true); } - const i18n = this.i18n !; + const i18n = this.i18n!; const vars = this.i18nBindProps(icu.vars); const placeholders = this.i18nBindProps(icu.placeholders); // output ICU directly and keep ICU reference in context - const message = icu.i18n !as i18n.Message; + const message = icu.i18n! as i18n.Message; // we always need post-processing function for ICUs, to make sure that: // - all placeholders in a form of {PLACEHOLDER} are replaced with actual values (note: @@ -1016,13 +1021,21 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver return null; } - private allocateDataSlot() { return this._dataIndex++; } + private allocateDataSlot() { + return this._dataIndex++; + } - getConstCount() { return this._dataIndex; } + getConstCount() { + return this._dataIndex; + } - getVarCount() { return this._pureFunctionSlots; } + getVarCount() { + return this._pureFunctionSlots; + } - getConsts() { return this._constants; } + getConsts() { + return this._constants; + } getNgContentSelectors(): o.Expression|null { return this._ngContentReservedSlots.length ? @@ -1030,7 +1043,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver null; } - private bindingContext() { return `${this._bindingContext++}`; } + private bindingContext() { + return `${this._bindingContext++}`; + } private templatePropertyBindings( templateIndex: number, attrs: (t.BoundAttribute|t.TextAttribute)[]) { @@ -1092,11 +1107,10 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver calls.push({ sourceSpan: call.sourceSpan, value: () => { - return call - .params( - value => (call.supportsInterpolation && value instanceof Interpolation) ? - this.getUpdateInstructionArguments(value) : - this.convertPropertyBinding(value)) as o.Expression[]; + return call.params( + value => (call.supportsInterpolation && value instanceof Interpolation) ? + this.getUpdateInstructionArguments(value) : + this.convertPropertyBinding(value)) as o.Expression[]; } }); }); @@ -1114,7 +1128,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver } private creationInstructionChain(reference: o.ExternalReference, calls: { - sourceSpan: ParseSourceSpan | null, + sourceSpan: ParseSourceSpan|null, params: () => o.Expression[] }[]) { const span = calls.length ? calls[0].sourceSpan : null; @@ -1228,8 +1242,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver private matchDirectives(elementName: string, elOrTpl: t.Element|t.Template) { if (this.directiveMatcher) { const selector = createCssSelector(elementName, getAttrsForDirectiveMatching(elOrTpl)); - this.directiveMatcher.match( - selector, (cssSelector, staticType) => { this.directives.add(staticType); }); + this.directiveMatcher.match(selector, (cssSelector, staticType) => { + this.directives.add(staticType); + }); } } @@ -1277,7 +1292,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver attrExprs.push(...getNgProjectAsLiteral(ngProjectAsAttr)); } - function addAttrExpr(key: string | number, value?: o.Expression): void { + function addAttrExpr(key: string|number, value?: o.Expression): void { if (typeof key === 'string') { if (!alreadySeen.has(key)) { attrExprs.push(...getAttributeNameLiterals(key)); @@ -1390,7 +1405,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver const eventName: string = outputAst.name; const bindingFnName = outputAst.type === ParsedEventType.Animation ? // synthetic @listener.foo values are treated the exact same as are standard listeners - prepareSyntheticListenerFunctionName(eventName, outputAst.phase !) : + prepareSyntheticListenerFunctionName(eventName, outputAst.phase!) : sanitizeIdentifier(eventName); const handlerName = `${this.templateName}_${tagName}_${bindingFnName}_${index}_listener`; const scope = this._bindingScope.nestedScope(this._bindingScope.bindingLevel); @@ -1492,7 +1507,7 @@ function pureFunctionCallInfo(args: o.Expression[]) { } function instruction( - span: ParseSourceSpan | null, reference: o.ExternalReference, + span: ParseSourceSpan|null, reference: o.ExternalReference, params: o.Expression[]): o.Expression { return o.importExpr(reference, null, span).callFn(params, span); } @@ -1504,7 +1519,7 @@ function generateNextContextExpr(relativeLevelDiff: number): o.Expression { } function getLiteralFactory( - constantPool: ConstantPool, literal: o.LiteralArrayExpr | o.LiteralMapExpr, + constantPool: ConstantPool, literal: o.LiteralArrayExpr|o.LiteralMapExpr, allocateSlots: (numSlots: number) => number): o.Expression { const {literalFactory, literalFactoryArguments} = constantPool.getLiteralFactory(literal); // Allocate 1 slot for the result plus 1 per argument @@ -1570,9 +1585,8 @@ const SHARED_CONTEXT_KEY = '$$shared_ctx$$'; * declaration should always come before the local ref declaration. */ type BindingData = { - retrievalLevel: number; lhs: o.Expression; declareLocalCallback?: DeclareLocalVarCallback; - declare: boolean; - priority: number; + retrievalLevel: number; lhs: o.Expression; + declareLocalCallback?: DeclareLocalVarCallback; declare: boolean; priority: number; localRef: boolean; }; @@ -1580,7 +1594,11 @@ type BindingData = { * The sorting priority of a local variable declaration. Higher numbers * mean the declaration will appear first in the generated code. */ -const enum DeclarationPriority { DEFAULT = 0, CONTEXT = 1, SHARED_CONTEXT = 2 } +const enum DeclarationPriority { + DEFAULT = 0, + CONTEXT = 1, + SHARED_CONTEXT = 2 +} export class BindingScope implements LocalResolver { /** Keeps a map from local variables to their BindingData. */ @@ -1669,7 +1687,9 @@ export class BindingScope implements LocalResolver { } // Implemented as part of LocalResolver. - getLocal(name: string): (o.Expression|null) { return this.get(name); } + getLocal(name: string): (o.Expression|null) { + return this.get(name); + } // Implemented as part of LocalResolver. notifyImplicitReceiverUse(): void { @@ -1677,7 +1697,7 @@ export class BindingScope implements LocalResolver { // Since the implicit receiver is accessed in an embedded view, we need to // ensure that we declare a shared context variable for the current template // in the update variables. - this.map.get(SHARED_CONTEXT_KEY + 0) !.declare = true; + this.map.get(SHARED_CONTEXT_KEY + 0)!.declare = true; } } @@ -1698,7 +1718,7 @@ export class BindingScope implements LocalResolver { this.generateSharedContextVar(retrievalLevel); } // Shared context variables are always generated as "ReadVarExpr". - return this.map.get(bindingKey) !.lhs as o.ReadVarExpr; + return this.map.get(bindingKey)!.lhs as o.ReadVarExpr; } getSharedContextName(retrievalLevel: number): o.ReadVarExpr|null { @@ -1735,7 +1755,7 @@ export class BindingScope implements LocalResolver { } getComponentProperty(name: string): o.Expression { - const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0) !; + const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0)!; componentValue.declare = true; this.maybeRestoreView(0, false); return componentValue.lhs.prop(name); @@ -1748,11 +1768,11 @@ export class BindingScope implements LocalResolver { // 2 - we are looking up a local ref, which requires restoring the view where the local // ref is stored if (this.isListenerScope() && (retrievalLevel < this.bindingLevel || localRefLookup)) { - if (!this.parent !.restoreViewVariable) { + if (!this.parent!.restoreViewVariable) { // parent saves variable to generate a shared `const $s$ = getCurrentView();` instruction - this.parent !.restoreViewVariable = o.variable(this.parent !.freshReferenceName()); + this.parent!.restoreViewVariable = o.variable(this.parent!.freshReferenceName()); } - this.restoreViewVariable = this.parent !.restoreViewVariable; + this.restoreViewVariable = this.parent!.restoreViewVariable; } } @@ -1771,19 +1791,22 @@ export class BindingScope implements LocalResolver { []; } - isListenerScope() { return this.parent && this.parent.bindingLevel === this.bindingLevel; } + isListenerScope() { + return this.parent && this.parent.bindingLevel === this.bindingLevel; + } variableDeclarations(): o.Statement[] { let currentContextLevel = 0; return Array.from(this.map.values()) - .filter(value => value.declare) - .sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority) - .reduce((stmts: o.Statement[], value: BindingData) => { - const levelDiff = this.bindingLevel - value.retrievalLevel; - const currStmts = value.declareLocalCallback !(this, levelDiff - currentContextLevel); - currentContextLevel = levelDiff; - return stmts.concat(currStmts); - }, []) as o.Statement[]; + .filter(value => value.declare) + .sort((a, b) => b.retrievalLevel - a.retrievalLevel || b.priority - a.priority) + .reduce((stmts: o.Statement[], value: BindingData) => { + const levelDiff = this.bindingLevel - value.retrievalLevel; + const currStmts = + value.declareLocalCallback!(this, levelDiff - currentContextLevel); + currentContextLevel = levelDiff; + return stmts.concat(currStmts); + }, []) as o.Statement[]; } @@ -1985,10 +2008,10 @@ export interface ParseTemplateOptions { export function parseTemplate( template: string, templateUrl: string, options: ParseTemplateOptions = {}): { errors?: ParseError[], - nodes: t.Node[], - styleUrls: string[], - styles: string[], - ngContentSelectors: string[] + nodes: t.Node[], + styleUrls: string[], + styles: string[], + ngContentSelectors: string[] } { const {interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat} = options; const bindingParser = makeBindingParser(interpolationConfig); @@ -2126,9 +2149,10 @@ export function getTranslationDeclStmts( const statements: o.Statement[] = [ declareI18nVariable(variable), o.ifStmt( - createClosureModeGuard(), createGoogleGetMsgStatements( - variable, message, closureVar, - i18nFormatPlaceholderNames(params, /* useCamelCase */ true)), + createClosureModeGuard(), + createGoogleGetMsgStatements( + variable, message, closureVar, + i18nFormatPlaceholderNames(params, /* useCamelCase */ true)), createLocalizeStatements( variable, message, i18nFormatPlaceholderNames(params, /* useCamelCase */ false))), ]; diff --git a/packages/compiler/src/render3/view/util.ts b/packages/compiler/src/render3/view/util.ts index 84b9d323bcb01..c762194774404 100644 --- a/packages/compiler/src/render3/view/util.ts +++ b/packages/compiler/src/render3/view/util.ts @@ -69,7 +69,7 @@ export function unsupported(this: void|Function, feature: string): never { throw new Error(`Feature ${feature} is not supported yet`); } -export function invalid<T>(this: t.Visitor, arg: o.Expression | o.Statement | t.Node): never { +export function invalid<T>(this: t.Visitor, arg: o.Expression|o.Statement|t.Node): never { throw new Error( `Invalid state: Visitor ${this.constructor.name} doesn't handle ${arg.constructor.name}`); } @@ -82,7 +82,7 @@ export function asLiteral(value: any): o.Expression { } export function conditionallyCreateMapObjectLiteral( - keys: {[key: string]: string | string[]}, keepDeclared?: boolean): o.Expression|null { + keys: {[key: string]: string|string[]}, keepDeclared?: boolean): o.Expression|null { if (Object.getOwnPropertyNames(keys).length > 0) { return mapToExpression(keys, keepDeclared); } @@ -90,7 +90,7 @@ export function conditionallyCreateMapObjectLiteral( } function mapToExpression( - map: {[key: string]: string | string[]}, keepDeclared?: boolean): o.Expression { + map: {[key: string]: string|string[]}, keepDeclared?: boolean): o.Expression { return o.literalMap(Object.getOwnPropertyNames(map).map(key => { // canonical syntax: `dirProp: publicProp` // if there is no `:`, use dirProp = elProp @@ -153,7 +153,9 @@ export class DefinitionMap { } } - toLiteralMap(): o.LiteralMapExpr { return o.literalMap(this.values); } + toLiteralMap(): o.LiteralMapExpr { + return o.literalMap(this.values); + } } /** @@ -165,8 +167,8 @@ export class DefinitionMap { * object maps a property name to its (static) value. For any bindings, this map simply maps the * property name to an empty string. */ -export function getAttrsForDirectiveMatching(elOrTpl: t.Element | t.Template): - {[name: string]: string} { +export function getAttrsForDirectiveMatching(elOrTpl: t.Element| + t.Template): {[name: string]: string} { const attributesMap: {[name: string]: string} = {}; @@ -179,8 +181,12 @@ export function getAttrsForDirectiveMatching(elOrTpl: t.Element | t.Template): } }); - elOrTpl.inputs.forEach(i => { attributesMap[i.name] = ''; }); - elOrTpl.outputs.forEach(o => { attributesMap[o.name] = ''; }); + elOrTpl.inputs.forEach(i => { + attributesMap[i.name] = ''; + }); + elOrTpl.outputs.forEach(o => { + attributesMap[o.name] = ''; + }); } return attributesMap; @@ -188,7 +194,7 @@ export function getAttrsForDirectiveMatching(elOrTpl: t.Element | t.Template): /** Returns a call expression to a chained instruction, e.g. `property(params[0])(params[1])`. */ export function chainedInstruction( - reference: o.ExternalReference, calls: o.Expression[][], span?: ParseSourceSpan | null) { + reference: o.ExternalReference, calls: o.Expression[][], span?: ParseSourceSpan|null) { let expression = o.importExpr(reference, null, span) as o.Expression; if (calls.length > 0) { diff --git a/packages/compiler/src/resource_loader.ts b/packages/compiler/src/resource_loader.ts index a0237cd17bb03..1f59cc981e0c9 100644 --- a/packages/compiler/src/resource_loader.ts +++ b/packages/compiler/src/resource_loader.ts @@ -11,5 +11,7 @@ * to load templates. */ export class ResourceLoader { - get(url: string): Promise<string>|string { return ''; } + get(url: string): Promise<string>|string { + return ''; + } } diff --git a/packages/compiler/src/schema/dom_element_schema_registry.ts b/packages/compiler/src/schema/dom_element_schema_registry.ts index e74e90ae4f0db..8705c219573fd 100644 --- a/packages/compiler/src/schema/dom_element_schema_registry.ts +++ b/packages/compiler/src/schema/dom_element_schema_registry.ts @@ -253,7 +253,9 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry { typeNames.split(',').forEach(tag => this._schema[tag.toLowerCase()] = type); const superType = superName && this._schema[superName.toLowerCase()]; if (superType) { - Object.keys(superType).forEach((prop: string) => { type[prop] = superType[prop]; }); + Object.keys(superType).forEach((prop: string) => { + type[prop] = superType[prop]; + }); } properties.forEach((property: string) => { if (property.length > 0) { @@ -350,9 +352,13 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry { return ctx ? ctx : SecurityContext.NONE; } - getMappedPropName(propName: string): string { return _ATTR_TO_PROP[propName] || propName; } + getMappedPropName(propName: string): string { + return _ATTR_TO_PROP[propName] || propName; + } - getDefaultComponentElementName(): string { return 'ng-component'; } + getDefaultComponentElementName(): string { + return 'ng-component'; + } validateProperty(name: string): {error: boolean, msg?: string} { if (name.toLowerCase().startsWith('on')) { @@ -376,7 +382,9 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry { } } - allKnownElementNames(): string[] { return Object.keys(this._schema); } + allKnownElementNames(): string[] { + return Object.keys(this._schema); + } normalizeAnimationStyleProperty(propName: string): string { return dashCaseToCamelCase(propName); @@ -386,7 +394,7 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry { {error: string, value: string} { let unit: string = ''; const strVal = val.toString().trim(); - let errorMsg: string = null !; + let errorMsg: string = null!; if (_isPixelDimensionStyle(camelCaseProp) && val !== 0 && val !== '0') { if (typeof val === 'number') { diff --git a/packages/compiler/src/schema/dom_security_schema.ts b/packages/compiler/src/schema/dom_security_schema.ts index 73bff2233e38b..7768f29f194ce 100644 --- a/packages/compiler/src/schema/dom_security_schema.ts +++ b/packages/compiler/src/schema/dom_security_schema.ts @@ -20,7 +20,7 @@ import {SecurityContext} from '../core'; // ================================================================================================= /** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */ -let _SECURITY_SCHEMA !: {[k: string]: SecurityContext}; +let _SECURITY_SCHEMA!: {[k: string]: SecurityContext}; export function SECURITY_SCHEMA(): {[k: string]: SecurityContext} { if (!_SECURITY_SCHEMA) { diff --git a/packages/compiler/src/selector.ts b/packages/compiler/src/selector.ts index b5e131de5df5c..a2d4aaaff66ca 100644 --- a/packages/compiler/src/selector.ts +++ b/packages/compiler/src/selector.ts @@ -118,9 +118,13 @@ export class CssSelector { this.notSelectors.length === 0; } - hasElementSelector(): boolean { return !!this.element; } + hasElementSelector(): boolean { + return !!this.element; + } - setElement(element: string|null = null) { this.element = element; } + setElement(element: string|null = null) { + this.element = element; + } /** Gets a template string for an element that matches the selector. */ getMatchingElementTemplate(): string { @@ -150,7 +154,9 @@ export class CssSelector { this.attrs.push(name, value && value.toLowerCase() || ''); } - addClassName(name: string) { this.classNames.push(name.toLowerCase()); } + addClassName(name: string) { + this.classNames.push(name.toLowerCase()); + } toString(): string { let res: string = this.element || ''; @@ -189,7 +195,7 @@ export class SelectorMatcher<T = any> { private _listContexts: SelectorListContext[] = []; addSelectables(cssSelectors: CssSelector[], callbackCtxt?: T) { - let listContext: SelectorListContext = null !; + let listContext: SelectorListContext = null!; if (cssSelectors.length > 1) { listContext = new SelectorListContext(cssSelectors); this._listContexts.push(listContext); @@ -284,10 +290,10 @@ export class SelectorMatcher<T = any> { * @param cssSelector A css selector * @param matchedCallback This callback will be called with the object handed into `addSelectable` * @return boolean true if a match was found - */ + */ match(cssSelector: CssSelector, matchedCallback: ((c: CssSelector, a: T) => void)|null): boolean { let result = false; - const element = cssSelector.element !; + const element = cssSelector.element!; const classNames = cssSelector.classNames; const attrs = cssSelector.attrs; @@ -315,7 +321,7 @@ export class SelectorMatcher<T = any> { const name = attrs[i]; const value = attrs[i + 1]; - const terminalValuesMap = this._attrValueMap.get(name) !; + const terminalValuesMap = this._attrValueMap.get(name)!; if (value) { result = this._matchTerminal(terminalValuesMap, '', cssSelector, matchedCallback) || result; @@ -323,7 +329,7 @@ export class SelectorMatcher<T = any> { result = this._matchTerminal(terminalValuesMap, value, cssSelector, matchedCallback) || result; - const partialValuesMap = this._attrValuePartialMap.get(name) !; + const partialValuesMap = this._attrValuePartialMap.get(name)!; if (value) { result = this._matchPartial(partialValuesMap, '', cssSelector, matchedCallback) || result; } @@ -343,7 +349,7 @@ export class SelectorMatcher<T = any> { } let selectables: SelectorContext<T>[] = map.get(name) || []; - const starSelectables: SelectorContext<T>[] = map.get('*') !; + const starSelectables: SelectorContext<T>[] = map.get('*')!; if (starSelectables) { selectables = selectables.concat(starSelectables); } diff --git a/packages/compiler/src/shadow_css.ts b/packages/compiler/src/shadow_css.ts index c65e6883bf016..0ce9bd570c626 100644 --- a/packages/compiler/src/shadow_css.ts +++ b/packages/compiler/src/shadow_css.ts @@ -138,13 +138,13 @@ export class ShadowCss { constructor() {} /* - * Shim some cssText with the given selector. Returns cssText that can - * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css). - * - * When strictStyling is true: - * - selector is the attribute added to all elements inside the host, - * - hostSelector is the attribute added to the host itself. - */ + * Shim some cssText with the given selector. Returns cssText that can + * be included in the document via WebComponents.ShadowCSS.addCssToDocument(css). + * + * When strictStyling is true: + * - selector is the attribute added to all elements inside the host, + * - hostSelector is the attribute added to the host itself. + */ shimCssText(cssText: string, selector: string, hostSelector: string = ''): string { const commentsWithHash = extractCommentsWithHash(cssText); cssText = stripComments(cssText); @@ -172,11 +172,12 @@ export class ShadowCss { * * scopeName menu-item { * - **/ + **/ private _insertPolyfillDirectivesInCssText(cssText: string): string { // Difference with webcomponents.js: does not handle comments - return cssText.replace( - _cssContentNextSelectorRe, function(...m: string[]) { return m[2] + '{'; }); + return cssText.replace(_cssContentNextSelectorRe, function(...m: string[]) { + return m[2] + '{'; + }); } /* @@ -193,7 +194,7 @@ export class ShadowCss { * * scopeName menu-item {...} * - **/ + **/ private _insertPolyfillRulesInCssText(cssText: string): string { // Difference with webcomponents.js: does not handle comments return cssText.replace(_cssContentRuleRe, (...m: string[]) => { @@ -209,7 +210,7 @@ export class ShadowCss { * and converts this to * * scopeName .foo { ... } - */ + */ private _scopeCssText(cssText: string, scopeSelector: string, hostSelector: string): string { const unscopedRules = this._extractUnscopedRulesFromCssText(cssText); // replace :host and :host-context -shadowcsshost and -shadowcsshost respectively @@ -238,7 +239,7 @@ export class ShadowCss { * * menu-item {...} * - **/ + **/ private _extractUnscopedRulesFromCssText(cssText: string): string { // Difference with webcomponents.js: does not handle comments let r = ''; @@ -257,7 +258,7 @@ export class ShadowCss { * to * * .foo<scopeName> > .bar - */ + */ private _convertColonHost(cssText: string): string { return this._convertColonRule(cssText, _cssColonHostRe, this._colonHostPartReplacer); } @@ -276,7 +277,7 @@ export class ShadowCss { * to * * .foo<scopeName> .bar { ... } - */ + */ private _convertColonHostContext(cssText: string): string { return this._convertColonRule( cssText, _cssColonHostContextRe, this._colonHostContextPartReplacer); @@ -315,7 +316,7 @@ export class ShadowCss { /* * Convert combinators like ::shadow and pseudo-elements like ::content * by replacing with space. - */ + */ private _convertShadowDOMSelectors(cssText: string): string { return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, ' '), cssText); } @@ -505,7 +506,9 @@ class SafeSelector { return content.replace(/__ph-(\d+)__/g, (ph, index) => this.placeholders[+index]); } - content(): string { return this._content; } + content(): string { + return this._content; + } } const _cssContentNextSelectorRe = diff --git a/packages/compiler/src/style_compiler.ts b/packages/compiler/src/style_compiler.ts index 751a7c3ca8090..e484d8b7468ef 100644 --- a/packages/compiler/src/style_compiler.ts +++ b/packages/compiler/src/style_compiler.ts @@ -66,7 +66,7 @@ export class StyleCompiler { stylesheet.styleUrls.forEach((styleUrl) => { const exprIndex = styleExpressions.length; // Note: This placeholder will be filled later. - styleExpressions.push(null !); + styleExpressions.push(null!); dependencies.push(new StylesCompileDependency( getStylesVarName(null), styleUrl, (value) => styleExpressions[exprIndex] = outputCtx.importExpr(value))); @@ -89,7 +89,7 @@ export class StyleCompiler { } } -function getStylesVarName(component: CompileDirectiveMetadata | null): string { +function getStylesVarName(component: CompileDirectiveMetadata|null): string { let result = `styles`; if (component) { result += `_${identifierName(component.type)}`; diff --git a/packages/compiler/src/summary_resolver.ts b/packages/compiler/src/summary_resolver.ts index 38d7dda3a07f9..8b53145ab98b2 100644 --- a/packages/compiler/src/summary_resolver.ts +++ b/packages/compiler/src/summary_resolver.ts @@ -28,14 +28,28 @@ export abstract class SummaryResolver<T> { export class JitSummaryResolver implements SummaryResolver<Type> { private _summaries = new Map<Type, Summary<Type>>(); - isLibraryFile(): boolean { return false; } - toSummaryFileName(fileName: string): string { return fileName; } - fromSummaryFileName(fileName: string): string { return fileName; } + isLibraryFile(): boolean { + return false; + } + toSummaryFileName(fileName: string): string { + return fileName; + } + fromSummaryFileName(fileName: string): string { + return fileName; + } resolveSummary(reference: Type): Summary<Type>|null { return this._summaries.get(reference) || null; } - getSymbolsOf(): Type[] { return []; } - getImportAs(reference: Type): Type { return reference; } - getKnownModuleName(fileName: string) { return null; } - addSummary(summary: Summary<Type>) { this._summaries.set(summary.symbol, summary); } + getSymbolsOf(): Type[] { + return []; + } + getImportAs(reference: Type): Type { + return reference; + } + getKnownModuleName(fileName: string) { + return null; + } + addSummary(summary: Summary<Type>) { + this._summaries.set(summary.symbol, summary); + } } diff --git a/packages/compiler/src/template_parser/binding_parser.ts b/packages/compiler/src/template_parser/binding_parser.ts index deec96edced1f..f6dde21f6d4cf 100644 --- a/packages/compiler/src/template_parser/binding_parser.ts +++ b/packages/compiler/src/template_parser/binding_parser.ts @@ -8,7 +8,7 @@ import {CompileDirectiveSummary, CompilePipeSummary} from '../compile_metadata'; import {SecurityContext} from '../core'; -import {ASTWithSource, AbsoluteSourceSpan, BindingPipe, BindingType, BoundElementProperty, EmptyExpr, ParsedEvent, ParsedEventType, ParsedProperty, ParsedPropertyType, ParsedVariable, ParserError, RecursiveAstVisitor, TemplateBinding, VariableBinding} from '../expression_parser/ast'; +import {AbsoluteSourceSpan, ASTWithSource, BindingPipe, BindingType, BoundElementProperty, EmptyExpr, ParsedEvent, ParsedEventType, ParsedProperty, ParsedPropertyType, ParsedVariable, ParserError, RecursiveAstVisitor, TemplateBinding, VariableBinding} from '../expression_parser/ast'; import {Parser} from '../expression_parser/parser'; import {InterpolationConfig} from '../ml_parser/interpolation_config'; import {mergeNsAndName} from '../ml_parser/tags'; @@ -45,9 +45,13 @@ export class BindingParser { } } - get interpolationConfig(): InterpolationConfig { return this._interpolationConfig; } + get interpolationConfig(): InterpolationConfig { + return this._interpolationConfig; + } - getUsedPipes(): CompilePipeSummary[] { return Array.from(this._usedPipes.values()); } + getUsedPipes(): CompilePipeSummary[] { + return Array.from(this._usedPipes.values()); + } createBoundHostProperties(dirMeta: CompileDirectiveSummary, sourceSpan: ParseSourceSpan): ParsedProperty[]|null { @@ -61,7 +65,9 @@ export class BindingParser { boundProps); } else { this._reportError( - `Value of the host property binding "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, + `Value of the host property binding "${ + propName}" needs to be a string representing an expression but got "${ + expression}" (${typeof expression})`, sourceSpan); } }); @@ -89,7 +95,9 @@ export class BindingParser { this.parseEvent(propName, expression, sourceSpan, sourceSpan, [], targetEvents); } else { this._reportError( - `Value of the host listener "${propName}" needs to be a string representing an expression but got "${expression}" (${typeof expression})`, + `Value of the host listener "${ + propName}" needs to be a string representing an expression but got "${ + expression}" (${typeof expression})`, sourceSpan); } }); @@ -103,7 +111,7 @@ export class BindingParser { try { const ast = this._exprParser.parseInterpolation( - value, sourceInfo, sourceSpan.start.offset, this._interpolationConfig) !; + value, sourceInfo, sourceSpan.start.offset, this._interpolationConfig)!; if (ast) this._reportExpressionParserErrors(ast.errors, sourceSpan); this._checkPipes(ast, sourceSpan); return ast; @@ -183,8 +191,9 @@ export class BindingParser { this._checkPipes(binding.value, sourceSpan); } }); - bindingsResult.warnings.forEach( - (warning) => { this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); }); + bindingsResult.warnings.forEach((warning) => { + this._reportError(warning, sourceSpan, ParseErrorLevel.WARNING); + }); return bindingsResult.templateBindings; } catch (e) { this._reportError(`${e}`, sourceSpan); @@ -257,7 +266,7 @@ export class BindingParser { name: string, ast: ASTWithSource, sourceSpan: ParseSourceSpan, valueSpan: ParseSourceSpan|undefined, targetMatchableAttrs: string[][], targetProps: ParsedProperty[]) { - targetMatchableAttrs.push([name, ast.source !]); + targetMatchableAttrs.push([name, ast.source!]); targetProps.push( new ParsedProperty(name, ast, ParsedPropertyType.DEFAULT, sourceSpan, valueSpan)); } @@ -275,7 +284,7 @@ export class BindingParser { // states will be applied by angular when the element is attached/detached const ast = this._parseBinding( expression || 'undefined', false, valueSpan || sourceSpan, absoluteOffset); - targetMatchableAttrs.push([name, ast.source !]); + targetMatchableAttrs.push([name, ast.source!]); targetProps.push( new ParsedProperty(name, ast, ParsedPropertyType.ANIMATION, sourceSpan, valueSpan)); } @@ -310,10 +319,10 @@ export class BindingParser { } let unit: string|null = null; - let bindingType: BindingType = undefined !; + let bindingType: BindingType = undefined!; let boundPropertyName: string|null = null; const parts = boundProp.name.split(PROPERTY_PARTS_SEPARATOR); - let securityContexts: SecurityContext[] = undefined !; + let securityContexts: SecurityContext[] = undefined!; // Check for special cases (prefix style, attr, class) if (parts.length > 1) { @@ -401,13 +410,15 @@ export class BindingParser { default: this._reportError( - `The provided animation output phase value "${phase}" for "@${eventName}" is not supported (use start or done)`, + `The provided animation output phase value "${phase}" for "@${ + eventName}" is not supported (use start or done)`, sourceSpan); break; } } else { this._reportError( - `The animation trigger output event (@${eventName}) is missing its phase value name (start or done are currently supported)`, + `The animation trigger output event (@${ + eventName}) is missing its phase value name (start or done are currently supported)`, sourceSpan); } } @@ -416,9 +427,9 @@ export class BindingParser { name: string, expression: string, sourceSpan: ParseSourceSpan, handlerSpan: ParseSourceSpan, targetMatchableAttrs: string[][], targetEvents: ParsedEvent[]) { // long format: 'target: eventName' - const [target, eventName] = splitAtColon(name, [null !, name]); + const [target, eventName] = splitAtColon(name, [null!, name]); const ast = this._parseAction(expression, handlerSpan); - targetMatchableAttrs.push([name !, ast.source !]); + targetMatchableAttrs.push([name!, ast.source!]); targetEvents.push( new ParsedEvent(eventName, target, ParsedEventType.Regular, ast, sourceSpan, handlerSpan)); // Don't detect directives for event names for now, @@ -465,7 +476,7 @@ export class BindingParser { const collector = new PipeCollector(); ast.visit(collector); collector.pipes.forEach((ast, pipeName) => { - const pipeMeta = this.pipesByName !.get(pipeName); + const pipeMeta = this.pipesByName!.get(pipeName); if (!pipeMeta) { this._reportError( `The pipe '${pipeName}' could not be found`, @@ -488,7 +499,7 @@ export class BindingParser { const report = isAttr ? this._schemaRegistry.validateAttribute(propName) : this._schemaRegistry.validateProperty(propName); if (report.error) { - this._reportError(report.msg !, sourceSpan, ParseErrorLevel.ERROR); + this._reportError(report.msg!, sourceSpan, ParseErrorLevel.ERROR); } } } diff --git a/packages/compiler/src/template_parser/template_ast.ts b/packages/compiler/src/template_parser/template_ast.ts index 2a876bcc6ec5e..62be9f756b479 100644 --- a/packages/compiler/src/template_parser/template_ast.ts +++ b/packages/compiler/src/template_parser/template_ast.ts @@ -36,7 +36,9 @@ export interface TemplateAst { export class TextAst implements TemplateAst { constructor( public value: string, public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {} - visit(visitor: TemplateAstVisitor, context: any): any { return visitor.visitText(this, context); } + visit(visitor: TemplateAstVisitor, context: any): any { + return visitor.visitText(this, context); + } } /** @@ -56,7 +58,9 @@ export class BoundTextAst implements TemplateAst { */ export class AttrAst implements TemplateAst { constructor(public name: string, public value: string, public sourceSpan: ParseSourceSpan) {} - visit(visitor: TemplateAstVisitor, context: any): any { return visitor.visitAttr(this, context); } + visit(visitor: TemplateAstVisitor, context: any): any { + return visitor.visitAttr(this, context); + } } export const enum PropertyBindingType { @@ -319,7 +323,9 @@ export class NullTemplateVisitor implements TemplateAstVisitor { * in an template ast recursively. */ export class RecursiveTemplateAstVisitor extends NullTemplateVisitor implements TemplateAstVisitor { - constructor() { super(); } + constructor() { + super(); + } // Nodes with children visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { @@ -358,7 +364,7 @@ export class RecursiveTemplateAstVisitor extends NullTemplateVisitor implements cb: (visit: (<V extends TemplateAst>(children: V[]|undefined) => void)) => void) { let results: any[][] = []; let t = this; - function visit<T extends TemplateAst>(children: T[] | undefined) { + function visit<T extends TemplateAst>(children: T[]|undefined) { if (children && children.length) results.push(templateVisitAll(t, children, context)); } cb(visit); @@ -373,7 +379,7 @@ export function templateVisitAll( visitor: TemplateAstVisitor, asts: TemplateAst[], context: any = null): any[] { const result: any[] = []; const visit = visitor.visit ? - (ast: TemplateAst) => visitor.visit !(ast, context) || ast.visit(visitor, context) : + (ast: TemplateAst) => visitor.visit!(ast, context) || ast.visit(visitor, context) : (ast: TemplateAst) => ast.visit(visitor, context); asts.forEach(ast => { const astResult = visit(ast); diff --git a/packages/compiler/src/template_parser/template_parser.ts b/packages/compiler/src/template_parser/template_parser.ts index 453a32b29ed8f..2323b8f6838f4 100644 --- a/packages/compiler/src/template_parser/template_parser.ts +++ b/packages/compiler/src/template_parser/template_parser.ts @@ -12,7 +12,7 @@ import {CompilerConfig} from '../config'; import {SchemaMetadata} from '../core'; import {AST, ASTWithSource, EmptyExpr, ParsedEvent, ParsedProperty, ParsedVariable} from '../expression_parser/ast'; import {Parser} from '../expression_parser/parser'; -import {Identifiers, createTokenForExternalReference, createTokenForReference} from '../identifiers'; +import {createTokenForExternalReference, createTokenForReference, Identifiers} from '../identifiers'; import * as html from '../ml_parser/ast'; import {HtmlParser, ParseTreeResult} from '../ml_parser/html_parser'; import {removeWhitespaces, replaceNgsp} from '../ml_parser/html_whitespaces'; @@ -57,7 +57,7 @@ const IDENT_EVENT_IDX = 10; const TEMPLATE_ATTR_PREFIX = '*'; const CLASS_ATTR = 'class'; -let _TEXT_CSS_SELECTOR !: CssSelector; +let _TEXT_CSS_SELECTOR!: CssSelector; function TEXT_CSS_SELECTOR(): CssSelector { if (!_TEXT_CSS_SELECTOR) { _TEXT_CSS_SELECTOR = CssSelector.parse('*')[0]; @@ -84,7 +84,9 @@ export class TemplateParser { private _htmlParser: HtmlParser, private _console: Console, public transforms: t.TemplateAstVisitor[]) {} - public get expressionParser() { return this._exprParser; } + public get expressionParser() { + return this._exprParser; + } parse( component: CompileDirectiveMetadata, template: string|ParseTreeResult, @@ -93,9 +95,9 @@ export class TemplateParser { preserveWhitespaces: boolean): {template: t.TemplateAst[], pipes: CompilePipeSummary[]} { const result = this.tryParse( component, template, directives, pipes, schemas, templateUrl, preserveWhitespaces); - const warnings = result.errors !.filter(error => error.level === ParseErrorLevel.WARNING); + const warnings = result.errors!.filter(error => error.level === ParseErrorLevel.WARNING); - const errors = result.errors !.filter(error => error.level === ParseErrorLevel.ERROR); + const errors = result.errors!.filter(error => error.level === ParseErrorLevel.ERROR); if (warnings.length > 0) { this._console.warn(`Template parse warnings:\n${warnings.join('\n')}`); @@ -106,7 +108,7 @@ export class TemplateParser { throw syntaxError(`Template parse errors:\n${errorString}`, errors); } - return {template: result.templateAst !, pipes: result.usedPipes !}; + return {template: result.templateAst!, pipes: result.usedPipes!}; } tryParse( @@ -114,7 +116,7 @@ export class TemplateParser { directives: CompileDirectiveSummary[], pipes: CompilePipeSummary[], schemas: SchemaMetadata[], templateUrl: string, preserveWhitespaces: boolean): TemplateParseResult { let htmlParseResult = typeof template === 'string' ? - this._htmlParser !.parse(template, templateUrl, { + this._htmlParser!.parse(template, templateUrl, { tokenizeExpansionForms: true, interpolationConfig: this.getInterpolationConfig(component) }) : @@ -139,7 +141,7 @@ export class TemplateParser { const uniqDirectives = removeSummaryDuplicates(directives); const uniqPipes = removeSummaryDuplicates(pipes); const providerViewContext = new ProviderViewContext(this._reflector, component); - let interpolationConfig: InterpolationConfig = undefined !; + let interpolationConfig: InterpolationConfig = undefined!; if (component.template && component.template.interpolation) { interpolationConfig = { start: component.template.interpolation[0], @@ -147,7 +149,7 @@ export class TemplateParser { }; } const bindingParser = new BindingParser( - this._exprParser, interpolationConfig !, this._schemaRegistry, uniqPipes, errors); + this._exprParser, interpolationConfig!, this._schemaRegistry, uniqPipes, errors); const parseVisitor = new TemplateParseVisitor( this._reflector, this._config, providerViewContext, uniqDirectives, bindingParser, this._schemaRegistry, schemas, errors); @@ -164,8 +166,9 @@ export class TemplateParser { } if (this.transforms) { - this.transforms.forEach( - (transform: t.TemplateAstVisitor) => { result = t.templateVisitAll(transform, result); }); + this.transforms.forEach((transform: t.TemplateAstVisitor) => { + result = t.templateVisitAll(transform, result); + }); } return new TemplateParseResult(result, usedPipes, errors); @@ -224,29 +227,35 @@ class TemplateParseVisitor implements html.Visitor { // Note: queries start with id 1 so we can use the number in a Bloom filter! this.contentQueryStartId = providerViewContext.component.viewQueries.length + 1; directives.forEach((directive, index) => { - const selector = CssSelector.parse(directive.selector !); + const selector = CssSelector.parse(directive.selector!); this.selectorMatcher.addSelectables(selector, directive); this.directivesIndex.set(directive, index); }); } - visitExpansion(expansion: html.Expansion, context: any): any { return null; } + visitExpansion(expansion: html.Expansion, context: any): any { + return null; + } - visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return null; } + visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { + return null; + } visitText(text: html.Text, parent: ElementContext): any { - const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()) !; + const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!; const valueNoNgsp = replaceNgsp(text.value); - const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan !); - return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan !) : - new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan !); + const expr = this._bindingParser.parseInterpolation(valueNoNgsp, text.sourceSpan!); + return expr ? new t.BoundTextAst(expr, ngContentIndex, text.sourceSpan!) : + new t.TextAst(valueNoNgsp, ngContentIndex, text.sourceSpan!); } visitAttribute(attribute: html.Attribute, context: any): any { return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan); } - visitComment(comment: html.Comment, context: any): any { return null; } + visitComment(comment: html.Comment, context: any): any { + return null; + } visitElement(element: html.Element, parent: ElementContext): any { const queryStartIndex = this.contentQueryStartId; @@ -307,7 +316,7 @@ class TemplateParseVisitor implements html.Visitor { const parsedVariables: ParsedVariable[] = []; const absoluteOffset = (attr.valueSpan || attr.sourceSpan).start.offset; this._bindingParser.parseInlineTemplateBinding( - templateKey !, templateValue !, attr.sourceSpan, absoluteOffset, templateMatchableAttrs, + templateKey!, templateValue!, attr.sourceSpan, absoluteOffset, templateMatchableAttrs, templateElementOrDirectiveProps, parsedVariables); templateElementVars.push(...parsedVariables.map(v => t.VariableAst.fromParsedVariable(v))); } @@ -326,52 +335,51 @@ class TemplateParseVisitor implements html.Visitor { const boundDirectivePropNames = new Set<string>(); const directiveAsts = this._createDirectiveAsts( isTemplateElement, element.name, directiveMetas, elementOrDirectiveProps, - elementOrDirectiveRefs, element.sourceSpan !, references, boundDirectivePropNames); + elementOrDirectiveRefs, element.sourceSpan!, references, boundDirectivePropNames); const elementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts( element.name, elementOrDirectiveProps, boundDirectivePropNames); const isViewRoot = parent.isTemplateElement || hasInlineTemplates; const providerContext = new ProviderElementContext( - this.providerViewContext, parent.providerContext !, isViewRoot, directiveAsts, attrs, - references, isTemplateElement, queryStartIndex, element.sourceSpan !); + this.providerViewContext, parent.providerContext!, isViewRoot, directiveAsts, attrs, + references, isTemplateElement, queryStartIndex, element.sourceSpan!); const children: t.TemplateAst[] = html.visitAll( preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, ElementContext.create( isTemplateElement, directiveAsts, - isTemplateElement ? parent.providerContext ! : providerContext)); + isTemplateElement ? parent.providerContext! : providerContext)); providerContext.afterElement(); // Override the actual selector when the `ngProjectAs` attribute is provided const projectionSelector = preparsedElement.projectAs != '' ? CssSelector.parse(preparsedElement.projectAs)[0] : elementCssSelector; - const ngContentIndex = parent.findNgContentIndex(projectionSelector) !; + const ngContentIndex = parent.findNgContentIndex(projectionSelector)!; let parsedElement: t.TemplateAst; if (preparsedElement.type === PreparsedElementType.NG_CONTENT) { // `<ng-content>` element if (element.children && !element.children.every(_isEmptyTextNode)) { - this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan !); + this._reportError(`<ng-content> element cannot have content.`, element.sourceSpan!); } parsedElement = new t.NgContentAst( - this.ngContentCount++, hasInlineTemplates ? null ! : ngContentIndex, - element.sourceSpan !); + this.ngContentCount++, hasInlineTemplates ? null! : ngContentIndex, element.sourceSpan!); } else if (isTemplateElement) { // `<ng-template>` element this._assertAllEventsPublishedByDirectives(directiveAsts, events); this._assertNoComponentsNorElementBindingsOnTemplate( - directiveAsts, elementProps, element.sourceSpan !); + directiveAsts, elementProps, element.sourceSpan!); parsedElement = new t.EmbeddedTemplateAst( attrs, events, references, elementVars, providerContext.transformedDirectiveAsts, providerContext.transformProviders, providerContext.transformedHasViewContainer, - providerContext.queryMatches, children, hasInlineTemplates ? null ! : ngContentIndex, - element.sourceSpan !); + providerContext.queryMatches, children, hasInlineTemplates ? null! : ngContentIndex, + element.sourceSpan!); } else { // element other than `<ng-content>` and `<ng-template>` this._assertElementExists(matchElement, element); - this._assertOnlyOneComponent(directiveAsts, element.sourceSpan !); + this._assertOnlyOneComponent(directiveAsts, element.sourceSpan!); const ngContentIndex = hasInlineTemplates ? null : parent.findNgContentIndex(projectionSelector); @@ -389,22 +397,22 @@ class TemplateParseVisitor implements html.Visitor { const {directives} = this._parseDirectives(this.selectorMatcher, templateSelector); const templateBoundDirectivePropNames = new Set<string>(); const templateDirectiveAsts = this._createDirectiveAsts( - true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan !, [], + true, elName, directives, templateElementOrDirectiveProps, [], element.sourceSpan!, [], templateBoundDirectivePropNames); const templateElementProps: t.BoundElementPropertyAst[] = this._createElementPropertyAsts( elName, templateElementOrDirectiveProps, templateBoundDirectivePropNames); this._assertNoComponentsNorElementBindingsOnTemplate( - templateDirectiveAsts, templateElementProps, element.sourceSpan !); + templateDirectiveAsts, templateElementProps, element.sourceSpan!); const templateProviderContext = new ProviderElementContext( - this.providerViewContext, parent.providerContext !, parent.isTemplateElement, - templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan !); + this.providerViewContext, parent.providerContext!, parent.isTemplateElement, + templateDirectiveAsts, [], [], true, templateQueryStartIndex, element.sourceSpan!); templateProviderContext.afterElement(); parsedElement = new t.EmbeddedTemplateAst( [], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, templateProviderContext.transformProviders, templateProviderContext.transformedHasViewContainer, templateProviderContext.queryMatches, - [parsedElement], ngContentIndex, element.sourceSpan !); + [parsedElement], ngContentIndex, element.sourceSpan!); } return parsedElement; @@ -538,7 +546,7 @@ class TemplateParseVisitor implements html.Visitor { let matchElement = false; selectorMatcher.match(elementCssSelector, (selector, directive) => { - directives[this.directivesIndex.get(directive) !] = directive; + directives[this.directivesIndex.get(directive)!] = directive; matchElement = matchElement || selector.hasElementSelector(); }); @@ -554,7 +562,7 @@ class TemplateParseVisitor implements html.Visitor { elementSourceSpan: ParseSourceSpan, targetReferences: t.ReferenceAst[], targetBoundDirectivePropNames: Set<string>): t.DirectiveAst[] { const matchedReferences = new Set<string>(); - let component: CompileDirectiveSummary = null !; + let component: CompileDirectiveSummary = null!; const directiveAsts = directives.map((directive) => { const sourceSpan = new ParseSourceSpan( @@ -566,15 +574,14 @@ class TemplateParseVisitor implements html.Visitor { } const directiveProperties: t.BoundDirectivePropertyAst[] = []; const boundProperties = - this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan) !; + this._bindingParser.createDirectiveHostPropertyAsts(directive, elementName, sourceSpan)!; let hostProperties = boundProperties.map(prop => t.BoundElementPropertyAst.fromBoundProperty(prop)); // Note: We need to check the host properties here as well, // as we don't know the element name in the DirectiveWrapperCompiler yet. hostProperties = this._checkPropertiesInSchema(elementName, hostProperties); - const parsedEvents = - this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan) !; + const parsedEvents = this._bindingParser.createDirectiveHostEventAsts(directive, sourceSpan)!; this._createDirectivePropertyAsts( directive.inputs, props, directiveProperties, targetBoundDirectivePropNames); elementOrDirectiveRefs.forEach((elOrDirRef) => { @@ -602,7 +609,7 @@ class TemplateParseVisitor implements html.Visitor { elOrDirRef.sourceSpan); } } else if (!component) { - let refToken: CompileTokenMetadata = null !; + let refToken: CompileTokenMetadata = null!; if (isTemplateElement) { refToken = createTokenForExternalReference(this.reflector, Identifiers.TemplateRef); } @@ -663,7 +670,7 @@ class TemplateParseVisitor implements html.Visitor { private _findComponentDirectiveNames(directives: t.DirectiveAst[]): string[] { return this._findComponentDirectives(directives) - .map(directive => identifierName(directive.directive.type) !); + .map(directive => identifierName(directive.directive.type)!); } private _assertOnlyOneComponent(directives: t.DirectiveAst[], sourceSpan: ParseSourceSpan) { @@ -691,16 +698,16 @@ class TemplateParseVisitor implements html.Visitor { if (!matchElement && !this._schemaRegistry.hasElement(elName, this._schemas)) { let errorMsg = `'${elName}' is not a known element:\n`; - errorMsg += - `1. If '${elName}' is an Angular component, then verify that it is part of this module.\n`; + errorMsg += `1. If '${ + elName}' is an Angular component, then verify that it is part of this module.\n`; if (elName.indexOf('-') > -1) { - errorMsg += - `2. If '${elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; + errorMsg += `2. If '${ + elName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; } else { errorMsg += `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; } - this._reportError(errorMsg, element.sourceSpan !); + this._reportError(errorMsg, element.sourceSpan!); } } @@ -714,7 +721,8 @@ class TemplateParseVisitor implements html.Visitor { } elementProps.forEach(prop => { this._reportError( - `Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, + `Property binding ${ + prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, sourceSpan); }); } @@ -733,7 +741,9 @@ class TemplateParseVisitor implements html.Visitor { events.forEach(event => { if (event.target != null || !allDirectiveEvents.has(event.name)) { this._reportError( - `Event binding ${event.fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, + `Event binding ${ + event + .fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, event.sourceSpan); } }); @@ -746,16 +756,20 @@ class TemplateParseVisitor implements html.Visitor { return boundProps.filter((boundProp) => { if (boundProp.type === t.PropertyBindingType.Property && !this._schemaRegistry.hasProperty(elementName, boundProp.name, this._schemas)) { - let errorMsg = - `Can't bind to '${boundProp.name}' since it isn't a known property of '${elementName}'.`; + let errorMsg = `Can't bind to '${boundProp.name}' since it isn't a known property of '${ + elementName}'.`; if (elementName.startsWith('ng-')) { errorMsg += - `\n1. If '${boundProp.name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` + + `\n1. If '${ + boundProp + .name}' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component.` + `\n2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; } else if (elementName.indexOf('-') > -1) { errorMsg += - `\n1. If '${elementName}' is an Angular component and it has '${boundProp.name}' input, then verify that it is part of this module.` + - `\n2. If '${elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` + + `\n1. If '${elementName}' is an Angular component and it has '${ + boundProp.name}' input, then verify that it is part of this module.` + + `\n2. If '${ + elementName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.` + `\n3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; } this._reportError(errorMsg, boundProp.sourceSpan); @@ -791,20 +805,26 @@ class NonBindableVisitor implements html.Visitor { ast.name, html.visitAll(this, ast.attrs), [], [], [], [], [], false, [], children, ngContentIndex, ast.sourceSpan, ast.endSourceSpan); } - visitComment(comment: html.Comment, context: any): any { return null; } + visitComment(comment: html.Comment, context: any): any { + return null; + } visitAttribute(attribute: html.Attribute, context: any): t.AttrAst { return new t.AttrAst(attribute.name, attribute.value, attribute.sourceSpan); } visitText(text: html.Text, parent: ElementContext): t.TextAst { - const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR()) !; - return new t.TextAst(text.value, ngContentIndex, text.sourceSpan !); + const ngContentIndex = parent.findNgContentIndex(TEXT_CSS_SELECTOR())!; + return new t.TextAst(text.value, ngContentIndex, text.sourceSpan!); } - visitExpansion(expansion: html.Expansion, context: any): any { return expansion; } + visitExpansion(expansion: html.Expansion, context: any): any { + return expansion; + } - visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { return expansionCase; } + visitExpansionCase(expansionCase: html.ExpansionCase, context: any): any { + return expansionCase; + } } /** @@ -824,7 +844,7 @@ class ElementOrDirectiveRef { } /** Splits a raw, potentially comma-delimited `exportAs` value into an array of names. */ -function splitExportAs(exportAs: string | null): string[] { +function splitExportAs(exportAs: string|null): string[] { return exportAs ? exportAs.split(',').map(e => e.trim()) : []; } @@ -837,7 +857,7 @@ class ElementContext { isTemplateElement: boolean, directives: t.DirectiveAst[], providerContext: ProviderElementContext): ElementContext { const matcher = new SelectorMatcher(); - let wildcardNgContentIndex: number = null !; + let wildcardNgContentIndex: number = null!; const component = directives.find(directive => directive.directive.isComponent); if (component) { const ngContentSelectors = component.directive.template !.ngContentSelectors; @@ -859,8 +879,9 @@ class ElementContext { findNgContentIndex(selector: CssSelector): number|null { const ngContentIndices: number[] = []; - this._ngContentIndexMatcher.match( - selector, (selector, ngContentIndex) => { ngContentIndices.push(ngContentIndex); }); + this._ngContentIndexMatcher.match(selector, (selector, ngContentIndex) => { + ngContentIndices.push(ngContentIndex); + }); ngContentIndices.sort(); if (this._wildcardNgContentIndex != null) { ngContentIndices.push(this._wildcardNgContentIndex); @@ -897,7 +918,7 @@ function _isEmptyTextNode(node: html.Node): boolean { return node instanceof html.Text && node.value.trim().length == 0; } -export function removeSummaryDuplicates<T extends{type: CompileTypeMetadata}>(items: T[]): T[] { +export function removeSummaryDuplicates<T extends {type: CompileTypeMetadata}>(items: T[]): T[] { const map = new Map<any, T>(); items.forEach((item) => { diff --git a/packages/compiler/src/template_parser/template_preparser.ts b/packages/compiler/src/template_parser/template_preparser.ts index d76d53b2314e8..515806cceb7a5 100644 --- a/packages/compiler/src/template_parser/template_preparser.ts +++ b/packages/compiler/src/template_parser/template_preparser.ts @@ -20,9 +20,9 @@ const NG_NON_BINDABLE_ATTR = 'ngNonBindable'; const NG_PROJECT_AS = 'ngProjectAs'; export function preparseElement(ast: html.Element): PreparsedElement { - let selectAttr: string = null !; - let hrefAttr: string = null !; - let relAttr: string = null !; + let selectAttr: string = null!; + let hrefAttr: string = null!; + let relAttr: string = null!; let nonBindable = false; let projectAs = ''; ast.attrs.forEach(attr => { diff --git a/packages/compiler/src/url_resolver.ts b/packages/compiler/src/url_resolver.ts index 3f819309c0c6f..daf54b89168df 100644 --- a/packages/compiler/src/url_resolver.ts +++ b/packages/compiler/src/url_resolver.ts @@ -33,9 +33,13 @@ export function createOfflineCompileUrlResolver(): UrlResolver { * Attacker-controlled data introduced by a template could expose your * application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security). */ -export interface UrlResolver { resolve(baseUrl: string, url: string): string; } +export interface UrlResolver { + resolve(baseUrl: string, url: string): string; +} -export interface UrlResolverCtor { new (packagePrefix?: string|null): UrlResolver; } +export interface UrlResolverCtor { + new(packagePrefix?: string|null): UrlResolver; +} export const UrlResolver: UrlResolverCtor = class UrlResolverImpl { constructor(private _packagePrefix: string|null = null) {} @@ -242,16 +246,16 @@ enum _ComponentIndex { * arbitrary strings may still look like path names. */ function _split(uri: string): Array<string|any> { - return uri.match(_splitRe) !; + return uri.match(_splitRe)!; } /** - * Removes dot segments in given path component, as described in - * RFC 3986, section 5.2.4. - * - * @param path A non-empty path component. - * @return Path component with removed dot segments. - */ + * Removes dot segments in given path component, as described in + * RFC 3986, section 5.2.4. + * + * @param path A non-empty path component. + * @return Path component with removed dot segments. + */ function _removeDotSegments(path: string): string { if (path == '/') return '/'; diff --git a/packages/compiler/src/util.ts b/packages/compiler/src/util.ts index 789219e115234..1cd8db706128e 100644 --- a/packages/compiler/src/util.ts +++ b/packages/compiler/src/util.ts @@ -52,8 +52,8 @@ export function isDefined(val: any): boolean { return val !== null && val !== undefined; } -export function noUndefined<T>(val: T | undefined): T { - return val === undefined ? null ! : val; +export function noUndefined<T>(val: T|undefined): T { + return val === undefined ? null! : val; } export interface ValueVisitor { @@ -69,14 +69,20 @@ export class ValueTransformer implements ValueVisitor { } visitStringMap(map: {[key: string]: any}, context: any): any { const result: {[key: string]: any} = {}; - Object.keys(map).forEach(key => { result[key] = visitValue(map[key], this, context); }); + Object.keys(map).forEach(key => { + result[key] = visitValue(map[key], this, context); + }); return result; } - visitPrimitive(value: any, context: any): any { return value; } - visitOther(value: any, context: any): any { return value; } + visitPrimitive(value: any, context: any): any { + return value; + } + visitOther(value: any, context: any): any { + return value; + } } -export type SyncAsync<T> = T | Promise<T>; +export type SyncAsync<T> = T|Promise<T>; export const SyncAsync = { assertSync: <T>(value: SyncAsync<T>): T => { @@ -86,7 +92,9 @@ export const SyncAsync = { return value; }, then: <T, R>(value: SyncAsync<T>, cb: (value: T) => R | Promise<R>| SyncAsync<R>): - SyncAsync<R> => { return isPromise(value) ? value.then(cb) : cb(value);}, + SyncAsync<R> => { + return isPromise(value) ? value.then(cb) : cb(value); + }, all: <T>(syncAsyncValues: SyncAsync<T>[]): SyncAsync<T[]> => { return syncAsyncValues.some(isPromise) ? Promise.all(syncAsyncValues) : syncAsyncValues as T[]; } @@ -259,7 +267,7 @@ export function newArray<T>(size: number, value: T): T[]; export function newArray<T>(size: number, value?: T): T[] { const list: T[] = []; for (let i = 0; i < size; i++) { - list.push(value !); + list.push(value!); } return list; } \ No newline at end of file diff --git a/packages/compiler/src/view_compiler/provider_compiler.ts b/packages/compiler/src/view_compiler/provider_compiler.ts index baa833cd53b02..8dbc2b182fcf9 100644 --- a/packages/compiler/src/view_compiler/provider_compiler.ts +++ b/packages/compiler/src/view_compiler/provider_compiler.ts @@ -9,7 +9,7 @@ import {CompileDiDependencyMetadata, CompileEntryComponentMetadata, CompileProviderMetadata, CompileTokenMetadata} from '../compile_metadata'; import {CompileReflector} from '../compile_reflector'; import {DepFlags, NodeFlags} from '../core'; -import {Identifiers, createTokenForExternalReference} from '../identifiers'; +import {createTokenForExternalReference, Identifiers} from '../identifiers'; import {LifecycleHooks} from '../lifecycle_reflector'; import * as o from '../output/output_ast'; import {convertValueToOutputAst} from '../output/value_util'; @@ -45,7 +45,8 @@ export function providerDef(ctx: OutputContext, providerAst: ProviderAst): { singleProviderDef(ctx, flags, providerAst.providerType, providerAst.providers[0]); return { providerExpr, - flags: providerFlags, depsExpr, + flags: providerFlags, + depsExpr, tokenExpr: tokenExpr(ctx, providerAst.token), }; } @@ -96,9 +97,9 @@ function singleProviderDef( let providerExpr: o.Expression; let deps: CompileDiDependencyMetadata[]; if (providerType === ProviderAstType.Directive || providerType === ProviderAstType.Component) { - providerExpr = ctx.importExpr(providerMeta.useClass !.reference); + providerExpr = ctx.importExpr(providerMeta.useClass!.reference); flags |= NodeFlags.TypeDirective; - deps = providerMeta.deps || providerMeta.useClass !.diDeps; + deps = providerMeta.deps || providerMeta.useClass!.diDeps; } else { if (providerMeta.useClass) { providerExpr = ctx.importExpr(providerMeta.useClass.reference); @@ -130,7 +131,7 @@ function tokenExpr(ctx: OutputContext, tokenMeta: CompileTokenMetadata): o.Expre export function depDef(ctx: OutputContext, dep: CompileDiDependencyMetadata): o.Expression { // Note: the following fields have already been normalized out by provider_analyzer: // - isAttribute, isHost - const expr = dep.isValue ? convertValueToOutputAst(ctx, dep.value) : tokenExpr(ctx, dep.token !); + const expr = dep.isValue ? convertValueToOutputAst(ctx, dep.value) : tokenExpr(ctx, dep.token!); let flags = DepFlags.None; if (dep.isSkipSelf) { flags |= DepFlags.SkipSelf; diff --git a/packages/compiler/src/view_compiler/type_check_compiler.ts b/packages/compiler/src/view_compiler/type_check_compiler.ts index 02a3b9ec1aeac..7d06d5ee209bf 100644 --- a/packages/compiler/src/view_compiler/type_check_compiler.ts +++ b/packages/compiler/src/view_compiler/type_check_compiler.ts @@ -10,11 +10,11 @@ import {AotCompilerOptions} from '../aot/compiler_options'; import {StaticReflector} from '../aot/static_reflector'; import {StaticSymbol} from '../aot/static_symbol'; import {CompileDirectiveMetadata, CompilePipeSummary} from '../compile_metadata'; -import {BindingForm, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter'; +import {BindingForm, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins, EventHandlerVars, LocalResolver} from '../compiler_util/expression_converter'; import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast'; import * as o from '../output/output_ast'; import {ParseSourceSpan} from '../parse_util'; -import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast'; +import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, ReferenceAst, TemplateAst, TemplateAstVisitor, templateVisitAll, TextAst, VariableAst} from '../template_parser/template_ast'; import {OutputContext} from '../util'; @@ -40,7 +40,7 @@ export class TypeCheckCompiler { usedPipes.forEach(p => pipes.set(p.name, p.type.reference)); let embeddedViewCount = 0; const viewBuilderFactory = - (parent: ViewBuilder | null, guards: GuardExpression[]): ViewBuilder => { + (parent: ViewBuilder|null, guards: GuardExpression[]): ViewBuilder => { const embeddedViewIndex = embeddedViewCount++; return new ViewBuilder( this.options, this.reflector, externalReferenceVars, parent, component.type.reference, @@ -66,7 +66,7 @@ interface ViewBuilderFactory { // Note: This is used as key in Map and should therefore be // unique per value. -type OutputVarType = o.BuiltinTypeName | StaticSymbol; +type OutputVarType = o.BuiltinTypeName|StaticSymbol; interface Expression { context: OutputVarType; @@ -247,10 +247,12 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { directives: DirectiveAst[], references: ReferenceAst[], }) { - ast.directives.forEach((dirAst) => { this.visitDirective(dirAst); }); + ast.directives.forEach((dirAst) => { + this.visitDirective(dirAst); + }); ast.references.forEach((ref) => { - let outputVarType: OutputVarType = null !; + let outputVarType: OutputVarType = null!; // Note: The old view compiler used to use an `any` type // for directives exposed via `exportAs`. // We keep this behaivor behind a flag for now. @@ -331,8 +333,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { // for arrays. return this.options.fullTemplateTypeCheck ? arr : arr.cast(o.DYNAMIC_TYPE); }, - createLiteralMapConverter: - (keys: {key: string, quoted: boolean}[]) => (values: o.Expression[]) => { + createLiteralMapConverter: (keys: {key: string, quoted: boolean}[]) => + (values: o.Expression[]) => { const entries = keys.map((k, i) => ({ key: k.key, value: values[i], diff --git a/packages/compiler/src/view_compiler/view_compiler.ts b/packages/compiler/src/view_compiler/view_compiler.ts index a0ede7a73e067..8a52d633eadad 100644 --- a/packages/compiler/src/view_compiler/view_compiler.ts +++ b/packages/compiler/src/view_compiler/view_compiler.ts @@ -8,7 +8,7 @@ import {CompileDirectiveMetadata, CompilePipeSummary, CompileQueryMetadata, rendererTypeName, tokenReference, viewClassName} from '../compile_metadata'; import {CompileReflector} from '../compile_reflector'; -import {BindingForm, BuiltinConverter, EventHandlerVars, LocalResolver, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins} from '../compiler_util/expression_converter'; +import {BindingForm, BuiltinConverter, convertActionBinding, convertPropertyBinding, convertPropertyBindingBuiltins, EventHandlerVars, LocalResolver} from '../compiler_util/expression_converter'; import {ArgumentType, BindingFlags, ChangeDetectionStrategy, NodeFlags, QueryBindingType, QueryValueType, ViewFlags} from '../core'; import {AST, ASTWithSource, Interpolation} from '../expression_parser/ast'; import {Identifiers} from '../identifiers'; @@ -17,7 +17,7 @@ import {isNgContainer} from '../ml_parser/tags'; import * as o from '../output/output_ast'; import {convertValueToOutputAst} from '../output/value_util'; import {ParseSourceSpan} from '../parse_util'; -import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '../template_parser/template_ast'; +import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAst, QueryMatch, ReferenceAst, TemplateAst, TemplateAstVisitor, templateVisitAll, TextAst, VariableAst} from '../template_parser/template_ast'; import {OutputContext} from '../util'; import {componentFactoryResolverProviderDef, depDef, lifecycleHookToNodeFlag, providerDef} from './provider_compiler'; @@ -38,7 +38,7 @@ export class ViewCompiler { styles: o.Expression, usedPipes: CompilePipeSummary[]): ViewCompileResult { let embeddedViewCount = 0; - let renderComponentVarName: string = undefined !; + let renderComponentVarName: string = undefined!; if (!component.isHost) { const template = component.template !; const customRenderData: o.LiteralMapEntry[] = []; @@ -48,7 +48,7 @@ export class ViewCompiler { } const renderComponentVar = o.variable(rendererTypeName(component.type.reference)); - renderComponentVarName = renderComponentVar.name !; + renderComponentVarName = renderComponentVar.name!; outputCtx.statements.push( renderComponentVar .set(o.importExpr(Identifiers.createRendererType2).callFn([new o.LiteralMapExpr([ @@ -61,7 +61,7 @@ export class ViewCompiler { [o.StmtModifier.Final, o.StmtModifier.Exported])); } - const viewBuilderFactory = (parent: ViewBuilder | null): ViewBuilder => { + const viewBuilderFactory = (parent: ViewBuilder|null): ViewBuilder => { const embeddedViewIndex = embeddedViewCount++; return new ViewBuilder( this._reflector, outputCtx, parent, component, embeddedViewIndex, usedPipes, @@ -101,7 +101,9 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { private nodes: (() => { sourceSpan: ParseSourceSpan | null, nodeDef: o.Expression, - nodeFlags: NodeFlags, updateDirectives?: UpdateExpression[], updateRenderer?: UpdateExpression[] + nodeFlags: NodeFlags, + updateDirectives?: UpdateExpression[], + updateRenderer?: UpdateExpression[] })[] = []; private purePipeNodeIndices: {[pipeName: string]: number} = Object.create(null); // Need Object.create so that we don't have builtin values... @@ -121,7 +123,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { // to be able to introduce the new view compiler without too many errors. this.compType = this.embeddedViewIndex > 0 ? o.DYNAMIC_TYPE : - o.expressionType(outputCtx.importExpr(this.component.type.reference)) !; + o.expressionType(outputCtx.importExpr(this.component.type.reference))!; this.viewName = viewClassName(this.component.type.reference, this.embeddedViewIndex); } @@ -181,7 +183,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { viewFlags |= ViewFlags.OnPush; } const viewFactory = new o.DeclareFunctionStmt( - this.viewName, [new o.FnParam(LOG_VAR.name !)], + this.viewName, [new o.FnParam(LOG_VAR.name!)], [new o.ReturnStatement(o.importExpr(Identifiers.viewDef).callFn([ o.literal(viewFlags), o.literalArr(nodeDefExprs), @@ -199,13 +201,13 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { let updateFn: o.Expression; if (updateStmts.length > 0) { const preStmts: o.Statement[] = []; - if (!this.component.isHost && o.findReadVarNames(updateStmts).has(COMP_VAR.name !)) { + if (!this.component.isHost && o.findReadVarNames(updateStmts).has(COMP_VAR.name!)) { preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType)); } updateFn = o.fn( [ - new o.FnParam(CHECK_VAR.name !, o.INFERRED_TYPE), - new o.FnParam(VIEW_VAR.name !, o.INFERRED_TYPE) + new o.FnParam(CHECK_VAR.name!, o.INFERRED_TYPE), + new o.FnParam(VIEW_VAR.name!, o.INFERRED_TYPE) ], [...preStmts, ...updateStmts], o.INFERRED_TYPE); } else { @@ -219,9 +221,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { this.nodes.push(() => ({ sourceSpan: ast.sourceSpan, nodeFlags: NodeFlags.TypeNgContent, - nodeDef: o.importExpr(Identifiers.ngContentDef).callFn([ - o.literal(ast.ngContentIndex), o.literal(ast.index) - ]) + nodeDef: o.importExpr(Identifiers.ngContentDef) + .callFn([o.literal(ast.ngContentIndex), o.literal(ast.index)]) })); } @@ -242,7 +243,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { visitBoundText(ast: BoundTextAst, context: any): any { const nodeIndex = this.nodes.length; // reserve the space in the nodeDefs array - this.nodes.push(null !); + this.nodes.push(null!); const astWithSource = <ASTWithSource>ast.value; const inter = <Interpolation>astWithSource.ast; @@ -270,7 +271,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { const nodeIndex = this.nodes.length; // reserve the space in the nodeDefs array - this.nodes.push(null !); + this.nodes.push(null!); const {flags, queryMatchesExpr, hostEvents} = this._visitElementOrTemplate(nodeIndex, ast); @@ -301,7 +302,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { visitElement(ast: ElementAst, context: any): any { const nodeIndex = this.nodes.length; // reserve the space in the nodeDefs array so we can add children - this.nodes.push(null !); + this.nodes.push(null!); // Using a null element name creates an anchor. const elName: string|null = isNgContainer(ast.name) ? null : ast.name; @@ -382,7 +383,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { queryMatches: QueryMatch[] }): { flags: NodeFlags, - usedEvents: [string | null, string][], + usedEvents: [string|null, string][], queryMatchesExpr: o.Expression, hostBindings: {context: o.Expression, inputAst: BoundElementPropertyAst, dirAst: DirectiveAst}[], @@ -409,7 +410,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { this._visitComponentFactoryResolverProvider(ast.directives); ast.providers.forEach(providerAst => { - let dirAst: DirectiveAst = undefined !; + let dirAst: DirectiveAst = undefined!; ast.directives.forEach(localDirAst => { if (localDirAst.directive.type.reference === tokenReference(providerAst.token)) { dirAst = localDirAst; @@ -427,7 +428,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { let queryMatchExprs: o.Expression[] = []; ast.queryMatches.forEach((match) => { - let valueType: QueryValueType = undefined !; + let valueType: QueryValueType = undefined!; if (tokenReference(match.value) === this.reflector.resolveExternalReference(Identifiers.ElementRef)) { valueType = QueryValueType.ElementRef; @@ -445,7 +446,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { } }); ast.references.forEach((ref) => { - let valueType: QueryValueType = undefined !; + let valueType: QueryValueType = undefined!; if (!ref.value) { valueType = QueryValueType.RenderElement; } else if ( @@ -459,7 +460,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { } }); ast.outputs.forEach((outputAst) => { - hostEvents.push({context: COMP_VAR, eventAst: outputAst, dirAst: null !}); + hostEvents.push({context: COMP_VAR, eventAst: outputAst, dirAst: null!}); }); return { @@ -480,7 +481,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { } { const nodeIndex = this.nodes.length; // reserve the space in the nodeDefs array so we can add children - this.nodes.push(null !); + this.nodes.push(null!); dirAst.directive.queries.forEach((query, queryIndex) => { const queryId = dirAst.contentQueryStartId + queryIndex; @@ -554,7 +555,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { })); const hostEvents = dirAst.hostEvents.map((hostEventAst) => ({ context: dirContextExpr, - eventAst: hostEventAst, dirAst, + eventAst: hostEventAst, + dirAst, })); // Check index is the same as the node index during compilation @@ -727,7 +729,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { private _createPipeConverter(expression: UpdateExpression, name: string, argCount: number): BuiltinConverter { - const pipe = this.usedPipes.find((pipeSummary) => pipeSummary.name === name) !; + const pipe = this.usedPipes.find((pipeSummary) => pipeSummary.name === name)!; if (pipe.pure) { const checkIndex = this.nodes.length; this.nodes.push(() => ({ @@ -803,13 +805,12 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { context: expression.context, value: convertPropertyBindingBuiltins( { - createLiteralArrayConverter: (argCount: number) => this._createLiteralArrayConverter( - expression.sourceSpan, argCount), - createLiteralMapConverter: - (keys: {key: string, quoted: boolean}[]) => - this._createLiteralMapConverter(expression.sourceSpan, keys), + createLiteralArrayConverter: (argCount: number) => + this._createLiteralArrayConverter(expression.sourceSpan, argCount), + createLiteralMapConverter: (keys: {key: string, quoted: boolean}[]) => + this._createLiteralMapConverter(expression.sourceSpan, keys), createPipeConverter: (name: string, argCount: number) => - this._createPipeConverter(expression, name, argCount) + this._createPipeConverter(expression, name, argCount) }, expression.value) }; @@ -848,7 +849,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { return {updateRendererStmts, updateDirectivesStmts, nodeDefExprs}; function createUpdateStatements( - nodeIndex: number, sourceSpan: ParseSourceSpan | null, expressions: UpdateExpression[], + nodeIndex: number, sourceSpan: ParseSourceSpan|null, expressions: UpdateExpression[], allowEmptyExprs: boolean): o.Statement[] { const updateStmts: o.Statement[] = []; const exprs = expressions.map(({sourceSpan, context, value}) => { @@ -892,14 +893,14 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { if (handleEventStmts.length > 0) { const preStmts: o.Statement[] = [ALLOW_DEFAULT_VAR.set(o.literal(true)).toDeclStmt(o.BOOL_TYPE)]; - if (!this.component.isHost && o.findReadVarNames(handleEventStmts).has(COMP_VAR.name !)) { + if (!this.component.isHost && o.findReadVarNames(handleEventStmts).has(COMP_VAR.name!)) { preStmts.push(COMP_VAR.set(VIEW_VAR.prop('component')).toDeclStmt(this.compType)); } handleEventFn = o.fn( [ - new o.FnParam(VIEW_VAR.name !, o.INFERRED_TYPE), - new o.FnParam(EVENT_NAME_VAR.name !, o.INFERRED_TYPE), - new o.FnParam(EventHandlerVars.event.name !, o.INFERRED_TYPE) + new o.FnParam(VIEW_VAR.name!, o.INFERRED_TYPE), + new o.FnParam(EVENT_NAME_VAR.name!, o.INFERRED_TYPE), + new o.FnParam(EventHandlerVars.event.name!, o.INFERRED_TYPE) ], [...preStmts, ...handleEventStmts, new o.ReturnStatement(ALLOW_DEFAULT_VAR)], o.INFERRED_TYPE); @@ -975,7 +976,9 @@ function elementBindingDef(inputAst: BoundElementPropertyAst, dirAst: DirectiveA function fixedAttrsDef(elementAst: ElementAst): o.Expression { const mapResult: {[key: string]: string} = Object.create(null); - elementAst.attrs.forEach(attrAst => { mapResult[attrAst.name] = attrAst.value; }); + elementAst.attrs.forEach(attrAst => { + mapResult[attrAst.name] = attrAst.value; + }); elementAst.directives.forEach(dirAst => { Object.keys(dirAst.directive.hostAttributes).forEach(name => { const value = dirAst.directive.hostAttributes[name]; @@ -1014,7 +1017,7 @@ function callUnwrapValue(nodeIndex: number, bindingIdx: number, expr: o.Expressi } function elementEventNameAndTarget( - eventAst: BoundEventAst, dirAst: DirectiveAst | null): {name: string, target: string | null} { + eventAst: BoundEventAst, dirAst: DirectiveAst|null): {name: string, target: string|null} { if (eventAst.isAnimation) { return { name: `@${eventAst.name}.${eventAst.phase}`, @@ -1037,6 +1040,6 @@ function calcStaticDynamicQueryFlags(query: CompileQueryMetadata) { return flags; } -export function elementEventFullName(target: string | null, name: string): string { +export function elementEventFullName(target: string|null, name: string): string { return target ? `${target}:${name}` : name; } diff --git a/packages/compiler/test/aot/compiler_spec.ts b/packages/compiler/test/aot/compiler_spec.ts index fd30a6d1a95c6..3084b9d3905b6 100644 --- a/packages/compiler/test/aot/compiler_spec.ts +++ b/packages/compiler/test/aot/compiler_spec.ts @@ -13,7 +13,7 @@ import {extractSourceMap, originalPositionFor} from '@angular/compiler/testing/s import {NodeFlags} from '@angular/core/src/view/index'; import * as ts from 'typescript'; -import {EmittingCompilerHost, MockAotCompilerHost, MockCompilerHost, MockDirectory, MockMetadataBundlerHost, arrayToMockDir, compile, expectNoDiagnostics, isInBazel, settings, setup, toMockFileArray} from './test_util'; +import {arrayToMockDir, compile, EmittingCompilerHost, expectNoDiagnostics, isInBazel, MockAotCompilerHost, MockCompilerHost, MockDirectory, MockMetadataBundlerHost, settings, setup, toMockFileArray} from './test_util'; describe('compiler (unbundled Angular)', () => { let angularFiles = setup(); @@ -53,11 +53,11 @@ describe('compiler (unbundled Angular)', () => { function compileApp(): GeneratedFile { const {genFiles} = compile([rootDir, angularFiles]); return genFiles.find( - genFile => genFile.srcFileUrl === componentPath && genFile.genFileUrl.endsWith('.ts')) !; + genFile => genFile.srcFileUrl === componentPath && genFile.genFileUrl.endsWith('.ts'))!; } function findLineAndColumn( - file: string, token: string): {line: number | null, column: number | null} { + file: string, token: string): {line: number|null, column: number|null} { const index = file.indexOf(token); if (index === -1) { return {line: null, column: null}; @@ -84,7 +84,9 @@ describe('compiler (unbundled Angular)', () => { describe('inline templates', () => { const ngUrl = `${componentPath}.AppComponent.html`; - function templateDecorator(template: string) { return `template: \`${template}\`,`; } + function templateDecorator(template: string) { + return `template: \`${template}\`,`; + } declareTests({ngUrl, templateDecorator}); }); @@ -125,7 +127,7 @@ describe('compiler (unbundled Angular)', () => { const genFile = compileApp(); const genSource = toTypeScript(genFile); - const sourceMap = extractSourceMap(genSource) !; + const sourceMap = extractSourceMap(genSource)!; expect(sourceMap.file).toEqual(genFile.genFileUrl); // Note: the generated file also contains code that is not mapped to @@ -146,7 +148,7 @@ describe('compiler (unbundled Angular)', () => { const genFile = compileApp(); const genSource = toTypeScript(genFile); - const sourceMap = extractSourceMap(genSource) !; + const sourceMap = extractSourceMap(genSource)!; expect(originalPositionFor(sourceMap, findLineAndColumn(genSource, `'span'`))) .toEqual({line: 2, column: 3, source: ngUrl}); }); @@ -158,7 +160,7 @@ describe('compiler (unbundled Angular)', () => { const genFile = compileApp(); const genSource = toTypeScript(genFile); - const sourceMap = extractSourceMap(genSource) !; + const sourceMap = extractSourceMap(genSource)!; expect(originalPositionFor(sourceMap, findLineAndColumn(genSource, `someMethod()`))) .toEqual({line: 2, column: 9, source: ngUrl}); }); @@ -170,7 +172,7 @@ describe('compiler (unbundled Angular)', () => { const genFile = compileApp(); const genSource = toTypeScript(genFile); - const sourceMap = extractSourceMap(genSource) !; + const sourceMap = extractSourceMap(genSource)!; expect(originalPositionFor(sourceMap, findLineAndColumn(genSource, `someMethod()`))) .toEqual({line: 2, column: 9, source: ngUrl}); }); @@ -180,7 +182,7 @@ describe('compiler (unbundled Angular)', () => { const genFile = compileApp(); const genSource = toTypeScript(genFile); - const sourceMap = extractSourceMap(genSource) !; + const sourceMap = extractSourceMap(genSource)!; expect(originalPositionFor(sourceMap, {line: 1, column: 0})) .toEqual({line: 1, column: 0, source: ngFactoryPath}); }); @@ -205,7 +207,6 @@ describe('compiler (unbundled Angular)', () => { compile([FILES, angularFiles]); expect(warnSpy).toHaveBeenCalledWith( `Warning: Can't resolve all parameters for MyService in /app/app.ts: (?). This will become an error in Angular v6.x`); - }); it('should error if not all arguments of an @Injectable class can be resolved if strictInjectionParameters is true', @@ -279,7 +280,7 @@ describe('compiler (unbundled Angular)', () => { }; compile([FILES, angularFiles], { postCompile: program => { - const factorySource = program.getSourceFile('/app/app.ngfactory.ts') !; + const factorySource = program.getSourceFile('/app/app.ngfactory.ts')!; expect(factorySource.text).not.toContain('\'/app/app.ngfactory\''); } }); @@ -321,7 +322,7 @@ describe('compiler (unbundled Angular)', () => { const genFilePreamble = '/* Hello world! */'; const {genFiles} = compile([FILES, angularFiles]); const genFile = - genFiles.find(gf => gf.srcFileUrl === '/app/app.ts' && gf.genFileUrl.endsWith('.ts')) !; + genFiles.find(gf => gf.srcFileUrl === '/app/app.ts' && gf.genFileUrl.endsWith('.ts'))!; const genSource = toTypeScript(genFile, genFilePreamble); expect(genSource.startsWith(genFilePreamble)).toBe(true); }); @@ -445,9 +446,9 @@ describe('compiler (unbundled Angular)', () => { } }; const {genFiles} = compile([FILES, angularFiles]); - const genFile = genFiles.find(genFile => genFile.srcFileUrl === '/app/app.ts') !; + const genFile = genFiles.find(genFile => genFile.srcFileUrl === '/app/app.ts')!; const genSource = toTypeScript(genFile); - const createComponentFactoryCall = /ɵccf\([^)]*\)/m.exec(genSource) ![0].replace(/\s*/g, ''); + const createComponentFactoryCall = /ɵccf\([^)]*\)/m.exec(genSource)![0].replace(/\s*/g, ''); // selector expect(createComponentFactoryCall).toContain('my-comp'); // inputs @@ -476,10 +477,9 @@ describe('compiler (unbundled Angular)', () => { }; const {genFiles} = compile([FILES, angularFiles]); const genFile = - genFiles.find(gf => gf.srcFileUrl === '/app/app.ts' && gf.genFileUrl.endsWith('.ts')) !; + genFiles.find(gf => gf.srcFileUrl === '/app/app.ts' && gf.genFileUrl.endsWith('.ts'))!; const genSource = toTypeScript(genFile); expect(genSource).not.toContain('check('); - }); }); @@ -492,7 +492,6 @@ describe('compiler (unbundled Angular)', () => { inheritanceWithSummariesSpecs(() => angularSummaryFiles); describe('external symbol re-exports enabled', () => { - it('should not reexport type symbols mentioned in constructors', () => { const libInput: MockDirectory = { 'lib': { @@ -520,7 +519,7 @@ describe('compiler (unbundled Angular)', () => { const {genFiles: appGenFiles} = compile( [appInput, libOutDir, angularSummaryFiles], {useSummaries: true, createExternalSymbolFactoryReexports: true}); - const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; + const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts')!; const appNgFactoryTs = toTypeScript(appNgFactory); expect(appNgFactoryTs).not.toContain('AType'); expect(appNgFactoryTs).toContain('AValue'); @@ -570,7 +569,7 @@ describe('compiler (unbundled Angular)', () => { const {genFiles: appGenFiles} = compile( [appInput, libOutDir, angularSummaryFiles], {useSummaries: true, createExternalSymbolFactoryReexports: true}); - const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; + const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts')!; const appNgFactoryTs = toTypeScript(appNgFactory); // metadata of ctor calls is preserved, so we reexport the argument @@ -614,7 +613,7 @@ describe('compiler (unbundled Angular)', () => { const {genFiles: appGenFiles} = compile( [appInput, libOutDir, angularSummaryFiles], {useSummaries: true, createExternalSymbolFactoryReexports: true}); - const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts') !; + const appNgFactory = appGenFiles.find((f) => f.genFileUrl === '/app/main.ngfactory.ts')!; const appNgFactoryTs = toTypeScript(appNgFactory); // we don't need to reexport exported symbols via the .ngfactory @@ -707,7 +706,7 @@ describe('compiler (unbundled Angular)', () => { compile([libInput, getAngularSummaryFiles()], {useSummaries: true}); const {genFiles} = compile([libOutDir, appInput, getAngularSummaryFiles()], {useSummaries: true}); - const mainNgFactory = genFiles.find(gf => gf.srcFileUrl === '/app/main.ts') !; + const mainNgFactory = genFiles.find(gf => gf.srcFileUrl === '/app/main.ts')!; const flags = NodeFlags.TypeDirective | NodeFlags.Component | NodeFlags.OnDestroy; expect(toTypeScript(mainNgFactory)) .toContain(`${flags},(null as any),0,i1.Extends,[i2.AParam]`); @@ -761,7 +760,7 @@ describe('compiler (unbundled Angular)', () => { const {genFiles} = compile( [lib1OutDir, lib2OutDir, appInput, getAngularSummaryFiles()], {useSummaries: true}); - const mainNgFactory = genFiles.find(gf => gf.srcFileUrl === '/app/main.ts') !; + const mainNgFactory = genFiles.find(gf => gf.srcFileUrl === '/app/main.ts')!; const flags = NodeFlags.TypeDirective | NodeFlags.Component | NodeFlags.OnDestroy; const mainNgFactorySource = toTypeScript(mainNgFactory); expect(mainNgFactorySource).toContain(`import * as i2 from '/lib1/base';`); diff --git a/packages/compiler/test/aot/jit_summaries_spec.ts b/packages/compiler/test/aot/jit_summaries_spec.ts index 08bbdd27df737..52ca5d290d73a 100644 --- a/packages/compiler/test/aot/jit_summaries_spec.ts +++ b/packages/compiler/test/aot/jit_summaries_spec.ts @@ -8,7 +8,7 @@ import {AotCompiler, AotCompilerHost, AotCompilerOptions, CompileSummaryKind, GeneratedFile, toTypeScript} from '@angular/compiler'; -import {MockDirectory, compile, setup} from './test_util'; +import {compile, MockDirectory, setup} from './test_util'; describe('aot summaries for jit', () => { let angularFiles = setup(); @@ -19,7 +19,7 @@ describe('aot summaries for jit', () => { }); function compileApp( - rootDir: MockDirectory, options: {useSummaries?: boolean}& AotCompilerOptions = {}): + rootDir: MockDirectory, options: {useSummaries?: boolean}&AotCompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} { return compile( [rootDir, options.useSummaries ? angularSummaryFiles : angularFiles], @@ -42,7 +42,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toContain(`import * as i0 from '/app/app.module'`); @@ -71,7 +71,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toContain(`import * as i0 from '/app/app.module'`); @@ -100,7 +100,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toContain(`import * as i0 from '/app/app.module'`); @@ -126,7 +126,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toContain(`import * as i0 from '/app/app.module'`); @@ -165,7 +165,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toMatch(/useClass:\{\s*reference:i1.MyService/); @@ -199,7 +199,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toMatch(/useClass:\{\s*reference:i1.MyService/); @@ -226,7 +226,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toMatch( @@ -248,7 +248,7 @@ describe('aot summaries for jit', () => { const rootDir = {'app': appDir}; const genFile = - compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts') !; + compileApp(rootDir).genFiles.find(f => f.genFileUrl === '/app/app.module.ngsummary.ts')!; const genSource = toTypeScript(genFile); expect(genSource).toMatch( @@ -301,10 +301,9 @@ describe('aot summaries for jit', () => { createExternalSymbolFactoryReexports: true, }); - const lib2ModuleNgSummary = - lib2Gen.find(f => f.genFileUrl === '/lib2/module.ngsummary.ts') !; + const lib2ModuleNgSummary = lib2Gen.find(f => f.genFileUrl === '/lib2/module.ngsummary.ts')!; const lib2ReexportNgSummary = - lib2Gen.find(f => f.genFileUrl === '/lib2/reexport.ngsummary.ts') !; + lib2Gen.find(f => f.genFileUrl === '/lib2/reexport.ngsummary.ts')!; // ngsummaries should add reexports for imported NgModules from a direct dependency expect(toTypeScript(lib2ModuleNgSummary)) @@ -336,10 +335,9 @@ describe('aot summaries for jit', () => { useSummaries: true, createExternalSymbolFactoryReexports: true }).genFiles; - const lib3ModuleNgSummary = - lib3Gen.find(f => f.genFileUrl === '/lib3/module.ngsummary.ts') !; + const lib3ModuleNgSummary = lib3Gen.find(f => f.genFileUrl === '/lib3/module.ngsummary.ts')!; const lib3ReexportNgSummary = - lib3Gen.find(f => f.genFileUrl === '/lib3/reexport.ngsummary.ts') !; + lib3Gen.find(f => f.genFileUrl === '/lib3/reexport.ngsummary.ts')!; // ngsummary.ts files should use the reexported values from direct and deep deps const lib3ModuleNgSummarySource = toTypeScript(lib3ModuleNgSummary); @@ -398,9 +396,9 @@ describe('aot summaries for jit', () => { const {outDir: lib2Out, genFiles: lib2Gen} = compileApp(lib2In, {useSummaries: true}); - const lib2ModuleNgSummary = lib2Gen.find(f => f.genFileUrl === '/lib2/module.ngsummary.ts') !; + const lib2ModuleNgSummary = lib2Gen.find(f => f.genFileUrl === '/lib2/module.ngsummary.ts')!; const lib2ReexportNgSummary = - lib2Gen.find(f => f.genFileUrl === '/lib2/reexport.ngsummary.ts') !; + lib2Gen.find(f => f.genFileUrl === '/lib2/reexport.ngsummary.ts')!; // ngsummaries should not add reexports by default for imported NgModules from a direct // dependency @@ -435,9 +433,9 @@ describe('aot summaries for jit', () => { }; const lib3Gen = compileApp(lib3In, {useSummaries: true}).genFiles; - const lib3ModuleNgSummary = lib3Gen.find(f => f.genFileUrl === '/lib3/module.ngsummary.ts') !; + const lib3ModuleNgSummary = lib3Gen.find(f => f.genFileUrl === '/lib3/module.ngsummary.ts')!; const lib3ReexportNgSummary = - lib3Gen.find(f => f.genFileUrl === '/lib3/reexport.ngsummary.ts') !; + lib3Gen.find(f => f.genFileUrl === '/lib3/reexport.ngsummary.ts')!; // ngsummary.ts files should use the external symbols which are manually re-exported from // "lib2" from their original symbol location. With re-exported external symbols this would diff --git a/packages/compiler/test/aot/regression_spec.ts b/packages/compiler/test/aot/regression_spec.ts index 8c768559a133a..d7e74946db371 100644 --- a/packages/compiler/test/aot/regression_spec.ts +++ b/packages/compiler/test/aot/regression_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {MockDirectory, compile, expectNoDiagnostics, setup} from './test_util'; +import {compile, expectNoDiagnostics, MockDirectory, setup} from './test_util'; describe('regressions', () => { let angularFiles = setup(); diff --git a/packages/compiler/test/aot/static_reflector_spec.ts b/packages/compiler/test/aot/static_reflector_spec.ts index ced6e99bf1525..5f382c0e17ddf 100644 --- a/packages/compiler/test/aot/static_reflector_spec.ts +++ b/packages/compiler/test/aot/static_reflector_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost, core as compilerCore} from '@angular/compiler'; +import {core as compilerCore, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, StaticSymbolResolverHost} from '@angular/compiler'; import {CollectorOptions, METADATA_VERSION} from '@angular/compiler-cli'; import {MockStaticSymbolResolverHost, MockSummaryResolver} from './static_symbol_resolver_spec'; @@ -358,7 +358,7 @@ describe('StaticReflector', () => { it('should record data about the error in the exception', () => { let threw = false; try { - const metadata = host.getMetadataFor('/tmp/src/invalid-metadata.ts') !; + const metadata = host.getMetadataFor('/tmp/src/invalid-metadata.ts')!; expect(metadata).toBeDefined(); const moduleMetadata: any = metadata[0]['metadata']; expect(moduleMetadata).toBeDefined(); @@ -1334,10 +1334,9 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = { 'decorators': [{ '__symbolic': 'call', 'expression': {'__symbolic': 'reference', 'name': 'Directive', 'module': '@angular/core'}, - 'arguments': [{ - 'selector': '[ngFor][ngForOf]', - 'inputs': ['ngForTrackBy', 'ngForOf', 'ngForTemplate'] - }] + 'arguments': [ + {'selector': '[ngFor][ngForOf]', 'inputs': ['ngForTrackBy', 'ngForOf', 'ngForTemplate']} + ] }], 'members': { '__ctor__': [{ @@ -1345,11 +1344,8 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = { 'parameters': [ {'__symbolic': 'reference', 'module': '@angular/core', 'name': 'ViewContainerRef'}, {'__symbolic': 'reference', 'module': '@angular/core', 'name': 'TemplateRef'}, - {'__symbolic': 'reference', 'module': '@angular/core', 'name': 'IterableDiffers'}, { - '__symbolic': 'reference', - 'module': '@angular/core', - 'name': 'ChangeDetectorRef' - } + {'__symbolic': 'reference', 'module': '@angular/core', 'name': 'IterableDiffers'}, + {'__symbolic': 'reference', 'module': '@angular/core', 'name': 'ChangeDetectorRef'} ] }] } @@ -1387,8 +1383,7 @@ const DEFAULT_TEST_DATA: {[key: string]: any} = { '__symbolic': 'property', 'decorators': [{ '__symbolic': 'call', - 'expression': - {'__symbolic': 'reference', 'name': 'Input', 'module': '@angular/core'} + 'expression': {'__symbolic': 'reference', 'name': 'Input', 'module': '@angular/core'} }] }], 'onMouseOver': [{ diff --git a/packages/compiler/test/aot/static_symbol_resolver_spec.ts b/packages/compiler/test/aot/static_symbol_resolver_spec.ts index 112adcc680cd6..3e0edd7d70cae 100644 --- a/packages/compiler/test/aot/static_symbol_resolver_spec.ts +++ b/packages/compiler/test/aot/static_symbol_resolver_spec.ts @@ -19,7 +19,9 @@ describe('StaticSymbolResolver', () => { let symbolResolver: StaticSymbolResolver; let symbolCache: StaticSymbolCache; - beforeEach(() => { symbolCache = new StaticSymbolCache(); }); + beforeEach(() => { + symbolCache = new StaticSymbolCache(); + }); function init( testData: {[key: string]: any} = DEFAULT_TEST_DATA, summaries: Summary<StaticSymbol>[] = [], @@ -36,7 +38,8 @@ describe('StaticSymbolResolver', () => { () => symbolResolver.resolveSymbol( symbolResolver.getSymbolByModule('src/version-error', 'e'))) .toThrow(new Error( - `Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected ${METADATA_VERSION}`)); + `Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected ${ + METADATA_VERSION}`)); }); it('should throw an exception for version 2 metadata', () => { @@ -159,7 +162,6 @@ describe('StaticSymbolResolver', () => { }); describe('importAs', () => { - it('should calculate importAs relationship for non source files without summaries', () => { init( { @@ -241,7 +243,6 @@ describe('StaticSymbolResolver', () => { expect(symbolResolver.getImportAs(symbolCache.get('/test2.d.ts', 'a', ['someMember']))) .toBe(symbolCache.get('/test3.d.ts', 'b', ['someMember'])); }); - }); it('should replace references by StaticSymbols', () => { @@ -345,10 +346,9 @@ describe('StaticSymbolResolver', () => { __symbolic: 'class', arity: 1, members: { - __ctor__: [{ - __symbolic: 'constructor', - parameters: [symbolCache.get('/test.d.ts', 'AParam')] - }] + __ctor__: [ + {__symbolic: 'constructor', parameters: [symbolCache.get('/test.d.ts', 'AParam')]} + ] } } } @@ -423,7 +423,6 @@ describe('StaticSymbolResolver', () => { expect(symbol.name).toEqual('One'); expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts'); }); - }); export class MockSummaryResolver implements SummaryResolver<StaticSymbol> { @@ -431,9 +430,11 @@ export class MockSummaryResolver implements SummaryResolver<StaticSymbol> { symbol: StaticSymbol, importAs: StaticSymbol }[] = []) {} - addSummary(summary: Summary<StaticSymbol>) { this.summaries.push(summary); } + addSummary(summary: Summary<StaticSymbol>) { + this.summaries.push(summary); + } resolveSummary(reference: StaticSymbol): Summary<StaticSymbol> { - return this.summaries.find(summary => summary.symbol === reference) !; + return this.summaries.find(summary => summary.symbol === reference)!; } getSymbolsOf(filePath: string): StaticSymbol[]|null { const symbols = this.summaries.filter(summary => summary.symbol.filePath === filePath) @@ -442,12 +443,20 @@ export class MockSummaryResolver implements SummaryResolver<StaticSymbol> { } getImportAs(symbol: StaticSymbol): StaticSymbol { const entry = this.importAs.find(entry => entry.symbol === symbol); - return entry ? entry.importAs : undefined !; + return entry ? entry.importAs : undefined!; + } + getKnownModuleName(fileName: string): string|null { + return null; + } + isLibraryFile(filePath: string): boolean { + return filePath.endsWith('.d.ts'); + } + toSummaryFileName(filePath: string): string { + return filePath.replace(/(\.d)?\.ts$/, '.d.ts'); + } + fromSummaryFileName(filePath: string): string { + return filePath; } - getKnownModuleName(fileName: string): string|null { return null; } - isLibraryFile(filePath: string): boolean { return filePath.endsWith('.d.ts'); } - toSummaryFileName(filePath: string): string { return filePath.replace(/(\.d)?\.ts$/, '.d.ts'); } - fromSummaryFileName(filePath: string): string { return filePath; } } export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost { @@ -459,7 +468,9 @@ export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost { // In tests, assume that symbols are not re-exported moduleNameToFileName(modulePath: string, containingFile?: string): string { - function splitPath(path: string): string[] { return path.split(/\/|\\/g); } + function splitPath(path: string): string[] { + return path.split(/\/|\\/g); + } function resolvePath(pathParts: string[]): string { const result: string[] = []; @@ -490,7 +501,7 @@ export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost { } if (modulePath.indexOf('.') === 0) { - const baseName = pathTo(containingFile !, modulePath); + const baseName = pathTo(containingFile!, modulePath); const tsName = baseName + '.ts'; if (this._getMetadataFor(tsName)) { return tsName; @@ -498,14 +509,18 @@ export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost { return baseName + '.d.ts'; } if (modulePath == 'unresolved') { - return undefined !; + return undefined!; } return '/tmp/' + modulePath + '.d.ts'; } - getMetadataFor(moduleId: string): any { return this._getMetadataFor(moduleId); } + getMetadataFor(moduleId: string): any { + return this._getMetadataFor(moduleId); + } - getOutputName(filePath: string): string { return filePath; } + getOutputName(filePath: string): string { + return filePath; + } private _getMetadataFor(filePath: string): any { if (this.data[filePath] && filePath.match(TS_EXT)) { @@ -515,13 +530,13 @@ export class MockStaticSymbolResolverHost implements StaticSymbolResolverHost { filePath, this.data[filePath], ts.ScriptTarget.ES5, /* setParentNodes */ true); const diagnostics: ts.Diagnostic[] = (<any>sf).parseDiagnostics; if (diagnostics && diagnostics.length) { - const errors = - diagnostics - .map(d => { - const {line, character} = ts.getLineAndCharacterOfPosition(d.file !, d.start !); - return `(${line}:${character}): ${d.messageText}`; - }) - .join('\n'); + const errors = diagnostics + .map(d => { + const {line, character} = + ts.getLineAndCharacterOfPosition(d.file!, d.start!); + return `(${line}:${character}): ${d.messageText}`; + }) + .join('\n'); throw Error(`Error encountered during parse of file ${filePath}\n${errors}`); } return [this.collector.getMetadata(sf)]; diff --git a/packages/compiler/test/aot/summary_resolver_spec.ts b/packages/compiler/test/aot/summary_resolver_spec.ts index d518319c2d5b0..b4e416b7e25cd 100644 --- a/packages/compiler/test/aot/summary_resolver_spec.ts +++ b/packages/compiler/test/aot/summary_resolver_spec.ts @@ -23,7 +23,9 @@ const EXT = /(\.d)?\.ts$/; let symbolCache: StaticSymbolCache; let host: MockAotSummaryResolverHost; - beforeEach(() => { symbolCache = new StaticSymbolCache(); }); + beforeEach(() => { + symbolCache = new StaticSymbolCache(); + }); function init(summaries: {[filePath: string]: string} = {}) { host = new MockAotSummaryResolverHost(summaries); @@ -121,11 +123,17 @@ export class MockAotSummaryResolverHost implements AotSummaryResolverHost { return sourceFileName.replace(EXT, '') + '.d.ts'; } - fromSummaryFileName(filePath: string): string { return filePath; } + fromSummaryFileName(filePath: string): string { + return filePath; + } - isSourceFile(filePath: string) { return !filePath.endsWith('.d.ts'); } + isSourceFile(filePath: string) { + return !filePath.endsWith('.d.ts'); + } - loadSummary(filePath: string): string { return this.summaries[filePath]; } + loadSummary(filePath: string): string { + return this.summaries[filePath]; + } } export function createMockOutputContext(): OutputContext { diff --git a/packages/compiler/test/aot/summary_serializer_spec.ts b/packages/compiler/test/aot/summary_serializer_spec.ts index 3410c609217fa..fb9bc5711157e 100644 --- a/packages/compiler/test/aot/summary_serializer_spec.ts +++ b/packages/compiler/test/aot/summary_serializer_spec.ts @@ -12,7 +12,7 @@ import {deserializeSummaries, serializeSummaries} from '@angular/compiler/src/ao import {summaryFileName} from '@angular/compiler/src/aot/util'; import {MockStaticSymbolResolverHost} from './static_symbol_resolver_spec'; -import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_resolver_spec'; +import {createMockOutputContext, MockAotSummaryResolverHost} from './summary_resolver_spec'; { @@ -22,7 +22,9 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res let symbolCache: StaticSymbolCache; let host: MockAotSummaryResolverHost; - beforeEach(() => { symbolCache = new StaticSymbolCache(); }); + beforeEach(() => { + symbolCache = new StaticSymbolCache(); + }); function init( summaries: {[filePath: string]: string} = {}, metadata: {[key: string]: any} = {}) { @@ -101,7 +103,7 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res members: {aMethod: {__symbolic: 'function'}}, statics: {aStatic: true} }); - expect(summaries[1].type !.type.reference) + expect(summaries[1].type!.type.reference) .toBe(symbolCache.get('/tmp/some_service.d.ts', 'SomeService')); }); @@ -274,7 +276,7 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res '/tmp/external_svc.d.ts', 'SomeService')]); // SomService is a transitive dep, but should have been serialized as well. expect(summaries[2].symbol).toBe(symbolCache.get('/tmp/external_svc.d.ts', 'SomeService')); - expect(summaries[2].type !.type.reference) + expect(summaries[2].type!.type.reference) .toBe(symbolCache.get('/tmp/external_svc.d.ts', 'SomeService')); // there was no summary for non_summary, but it should have // been serialized as well. @@ -387,7 +389,6 @@ import {MockAotSummaryResolverHost, createMockOutputContext} from './summary_res describe('symbol re-exports enabled', () => { - it('should not create "importAs" names for ctor arguments which are types of reexported classes in libraries', () => { init(); diff --git a/packages/compiler/test/aot/test_util.ts b/packages/compiler/test/aot/test_util.ts index f516d6f300416..112deff7e0dc2 100644 --- a/packages/compiler/test/aot/test_util.ts +++ b/packages/compiler/test/aot/test_util.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AotCompilerHost, AotCompilerOptions, GeneratedFile, createAotCompiler, toTypeScript} from '@angular/compiler'; +import {AotCompilerHost, AotCompilerOptions, createAotCompiler, GeneratedFile, toTypeScript} from '@angular/compiler'; import {MetadataBundlerHost} from '@angular/compiler-cli/src/metadata/bundler'; import {MetadataCollector} from '@angular/compiler-cli/src/metadata/collector'; import {ModuleMetadata} from '@angular/compiler-cli/src/metadata/index'; @@ -15,7 +15,9 @@ import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; -export interface MetadataProvider { getMetadata(source: ts.SourceFile): ModuleMetadata|undefined; } +export interface MetadataProvider { + getMetadata(source: ts.SourceFile): ModuleMetadata|undefined; +} let nodeModulesPath: string; let angularSourcePath: string; @@ -23,13 +25,13 @@ let rootPath: string; calcPathsOnDisc(); -export type MockFileOrDirectory = string | MockDirectory; +export type MockFileOrDirectory = string|MockDirectory; export type MockDirectory = { - [name: string]: MockFileOrDirectory | undefined; + [name: string]: MockFileOrDirectory|undefined; }; -export function isDirectory(data: MockFileOrDirectory | undefined): data is MockDirectory { +export function isDirectory(data: MockFileOrDirectory|undefined): data is MockDirectory { return typeof data !== 'string'; } @@ -119,9 +121,13 @@ export class EmittingCompilerHost implements ts.CompilerHost { return Array.from(this.writtenFiles).map(f => ({name: f[0], content: f[1]})); } - public get scripts(): string[] { return this.scriptNames; } + public get scripts(): string[] { + return this.scriptNames; + } - public get written(): Map<string, string> { return this.writtenFiles; } + public get written(): Map<string, string> { + return this.writtenFiles; + } public effectiveName(fileName: string): string { const prefix = '@angular/'; @@ -154,7 +160,9 @@ export class EmittingCompilerHost implements ts.CompilerHost { (fs.existsSync(directoryName) && fs.statSync(directoryName).isDirectory()); } - getCurrentDirectory(): string { return this.root; } + getCurrentDirectory(): string { + return this.root; + } getDirectories(dir: string): string[] { const result = open(dir, this.options.mockData); @@ -179,7 +187,9 @@ export class EmittingCompilerHost implements ts.CompilerHost { throw new Error(`File not found '${fileName}'.`); } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } writeFile: ts.WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean, @@ -197,8 +207,12 @@ export class EmittingCompilerHost implements ts.CompilerHost { getCanonicalFileName(fileName: string): string { return fileName; } - useCaseSensitiveFileNames(): boolean { return false; } - getNewLine(): string { return '\n'; } + useCaseSensitiveFileNames(): boolean { + return false; + } + getNewLine(): string { + return '\n'; + } private getAddedDirectories(): Set<string> { let result = this.cachedAddedDirectories; @@ -247,7 +261,9 @@ export class MockCompilerHost implements ts.CompilerHost { this.sourceFiles.delete(fileName); } - assumeFileExists(fileName: string) { this.assumeExists.add(fileName); } + assumeFileExists(fileName: string) { + this.assumeExists.add(fileName); + } remove(files: string[]) { // Remove the files from the list of scripts. @@ -274,11 +290,17 @@ export class MockCompilerHost implements ts.CompilerHost { return false; } - readFile(fileName: string): string { return this.getFileContent(fileName) !; } + readFile(fileName: string): string { + return this.getFileContent(fileName)!; + } - trace(s: string): void { this.traces.push(s); } + trace(s: string): void { + this.traces.push(s); + } - getCurrentDirectory(): string { return '/'; } + getCurrentDirectory(): string { + return '/'; + } getDirectories(dir: string): string[] { const effectiveName = this.getEffectiveName(dir); @@ -303,10 +325,12 @@ export class MockCompilerHost implements ts.CompilerHost { this.sourceFiles.set(fileName, result); } } - return result !; + return result!; } - getDefaultLibFileName(options: ts.CompilerOptions): string { return 'lib.d.ts'; } + getDefaultLibFileName(options: ts.CompilerOptions): string { + return 'lib.d.ts'; + } writeFile: ts.WriteFileCallback = (fileName: string, data: string, writeByteOrderMark: boolean) => { @@ -317,8 +341,12 @@ export class MockCompilerHost implements ts.CompilerHost { getCanonicalFileName(fileName: string): string { return fileName; } - useCaseSensitiveFileNames(): boolean { return false; } - getNewLine(): string { return '\n'; } + useCaseSensitiveFileNames(): boolean { + return false; + } + getNewLine(): string { + return '\n'; + } // Private methods private getFileContent(fileName: string): string|undefined { @@ -373,9 +401,13 @@ export class MockAotCompilerHost implements AotCompilerHost { }; } - hideMetadata() { this.metadataVisible = false; } + hideMetadata() { + this.metadataVisible = false; + } - tsFilesOnly() { this.dtsAreSource = false; } + tsFilesOnly() { + this.dtsAreSource = false; + } // StaticSymbolResolverHost getMetadataFor(modulePath: string): {[key: string]: any}[]|undefined { @@ -414,7 +446,9 @@ export class MockAotCompilerHost implements AotCompilerHost { return resolved ? resolved.resolvedFileName : null; } - getOutputName(filePath: string) { return filePath; } + getOutputName(filePath: string) { + return filePath; + } resourceNameToFileName(resourceName: string, containingFile: string) { // Note: we convert package paths into relative paths to be compatible with the the @@ -428,16 +462,22 @@ export class MockAotCompilerHost implements AotCompilerHost { } // AotSummaryResolverHost - loadSummary(filePath: string): string|null { return this.tsHost.readFile(filePath); } + loadSummary(filePath: string): string|null { + return this.tsHost.readFile(filePath); + } isSourceFile(sourceFilePath: string): boolean { return !GENERATED_FILES.test(sourceFilePath) && (this.dtsAreSource || !DTS.test(sourceFilePath)); } - toSummaryFileName(filePath: string): string { return filePath.replace(EXT, '') + '.d.ts'; } + toSummaryFileName(filePath: string): string { + return filePath.replace(EXT, '') + '.d.ts'; + } - fromSummaryFileName(filePath: string): string { return filePath; } + fromSummaryFileName(filePath: string): string { + return filePath; + } // AotCompilerHost fileNameToModuleName(importedFile: string, containingFile: string): string { @@ -464,7 +504,7 @@ export class MockMetadataBundlerHost implements MetadataBundlerHost { } } -function find(fileName: string, data: MockFileOrDirectory | undefined): MockFileOrDirectory| +function find(fileName: string, data: MockFileOrDirectory|undefined): MockFileOrDirectory| undefined { if (!data) return undefined; const names = fileName.split('/'); @@ -479,7 +519,7 @@ function find(fileName: string, data: MockFileOrDirectory | undefined): MockFile return current; } -function open(fileName: string, data: MockFileOrDirectory | undefined): string|undefined { +function open(fileName: string, data: MockFileOrDirectory|undefined): string|undefined { let result = find(fileName, data); if (typeof result === 'string') { return result; @@ -487,7 +527,7 @@ function open(fileName: string, data: MockFileOrDirectory | undefined): string|u return undefined; } -function directoryExists(dirname: string, data: MockFileOrDirectory | undefined): boolean { +function directoryExists(dirname: string, data: MockFileOrDirectory|undefined): boolean { let result = find(dirname, data); return !!result && typeof result !== 'string'; } @@ -497,7 +537,7 @@ export type MockFileArray = { content: string }[]; -export type MockData = MockDirectory | Map<string, string>| (MockDirectory | Map<string, string>)[]; +export type MockData = MockDirectory|Map<string, string>|(MockDirectory|Map<string, string>)[]; export function toMockFileArray(data: MockData, target: MockFileArray = []): MockFileArray { if (data instanceof Map) { @@ -512,7 +552,7 @@ export function toMockFileArray(data: MockData, target: MockFileArray = []): Moc function mockDirToFileArray(dir: MockDirectory, path: string, target: MockFileArray) { Object.keys(dir).forEach((localFileName) => { - const value = dir[localFileName] !; + const value = dir[localFileName]!; const fileName = `${path}/${localFileName}`; if (typeof value === 'string') { target.push({fileName, content: value}); @@ -523,12 +563,16 @@ function mockDirToFileArray(dir: MockDirectory, path: string, target: MockFileAr } function mapToMockFileArray(files: Map<string, string>, target: MockFileArray) { - files.forEach((content, fileName) => { target.push({fileName, content}); }); + files.forEach((content, fileName) => { + target.push({fileName, content}); + }); } export function arrayToMockMap(arr: MockFileArray): Map<string, string> { const map = new Map<string, string>(); - arr.forEach(({fileName, content}) => { map.set(fileName, content); }); + arr.forEach(({fileName, content}) => { + map.set(fileName, content); + }); return map; } @@ -594,8 +638,8 @@ function readBazelWrittenFilesFrom( map.set(path.posix.join('/node_modules/@angular', packageName, 'index.d.ts'), content); } } catch (e) { - console.error( - `Consider adding //packages/${packageName} as a data dependency in the BUILD.bazel rule for the failing test`); + console.error(`Consider adding //packages/${ + packageName} as a data dependency in the BUILD.bazel rule for the failing test`); throw e; } } @@ -606,8 +650,8 @@ export function isInBazel(): boolean { export function setup(options: { compileAngular: boolean, - compileFakeCore?: boolean, - compileAnimations: boolean, compileCommon?: boolean + compileFakeCore?: boolean, compileAnimations: boolean, + compileCommon?: boolean } = { compileAngular: true, compileAnimations: true, @@ -687,7 +731,9 @@ export function expectNoDiagnostics(program: ts.Program) { return ''; } - function chars(len: number, ch: string): string { return newArray(len, ch).join(''); } + function chars(len: number, ch: string): string { + return newArray(len, ch).join(''); + } function lineNoOf(offset: number, text: string): number { let result = 1; @@ -699,8 +745,8 @@ export function expectNoDiagnostics(program: ts.Program) { function lineInfo(diagnostic: ts.Diagnostic): string { if (diagnostic.file) { - const start = diagnostic.start !; - let end = diagnostic.start ! + diagnostic.length !; + const start = diagnostic.start!; + let end = diagnostic.start! + diagnostic.length!; const source = diagnostic.file.text; let lineStart = start; let lineEnd = end; @@ -726,8 +772,8 @@ export function expectNoDiagnostics(program: ts.Program) { 'Errors from TypeScript:\n' + diagnostics .map( - d => - `${fileInfo(d)}${ts.flattenDiagnosticMessageText(d.messageText, '\n')}${lineInfo(d)}`) + d => `${fileInfo(d)}${ts.flattenDiagnosticMessageText(d.messageText, '\n')}${ + lineInfo(d)}`) .join(' \n')); } } @@ -758,7 +804,7 @@ export function compile( useSummaries?: boolean, preCompile?: (program: ts.Program) => void, postCompile?: (program: ts.Program) => void, - }& AotCompilerOptions = {}, + }&AotCompilerOptions = {}, tsOptions: ts.CompilerOptions = {}): {genFiles: GeneratedFile[], outDir: MockDirectory} { // when using summaries, always emit so the next step can use the results. const emit = options.emit || options.useSummaries; @@ -777,7 +823,9 @@ export function compile( const tsSettings = {...settings, ...tsOptions}; const program = ts.createProgram([...host.scriptNames], tsSettings, host); preCompile(program); - const {compiler, reflector} = createAotCompiler(aotHost, options, (err) => { throw err; }); + const {compiler, reflector} = createAotCompiler(aotHost, options, (err) => { + throw err; + }); const analyzedModules = compiler.analyzeModulesSync(program.getSourceFiles().map(sf => sf.fileName)); const genFiles = compiler.emitAllImpls(analyzedModules); diff --git a/packages/compiler/test/compiler_facade_interface_spec.ts b/packages/compiler/test/compiler_facade_interface_spec.ts index dcb97afd31932..fd58bc9d91c6e 100644 --- a/packages/compiler/test/compiler_facade_interface_spec.ts +++ b/packages/compiler/test/compiler_facade_interface_spec.ts @@ -26,87 +26,87 @@ import * as compiler from '../src/compiler_facade_interface'; */ const coreExportedCompilerFacade1: core.ExportedCompilerFacade = - null !as compiler.ExportedCompilerFacade; + null! as compiler.ExportedCompilerFacade; const compilerExportedCompilerFacade2: compiler.ExportedCompilerFacade = - null !as core.ExportedCompilerFacade; + null! as core.ExportedCompilerFacade; -const coreCompilerFacade: core.CompilerFacade = null !as compiler.CompilerFacade; -const compilerCompilerFacade: compiler.CompilerFacade = null !as core.CompilerFacade; +const coreCompilerFacade: core.CompilerFacade = null! as compiler.CompilerFacade; +const compilerCompilerFacade: compiler.CompilerFacade = null! as core.CompilerFacade; -const coreCoreEnvironment: core.CoreEnvironment = null !as compiler.CoreEnvironment; -const compilerCoreEnvironment: compiler.CoreEnvironment = null !as core.CoreEnvironment; +const coreCoreEnvironment: core.CoreEnvironment = null! as compiler.CoreEnvironment; +const compilerCoreEnvironment: compiler.CoreEnvironment = null! as core.CoreEnvironment; -const coreResourceLoader: core.ResourceLoader = null !as compiler.ResourceLoader; -const compilerResourceLoader: compiler.ResourceLoader = null !as core.ResourceLoader; +const coreResourceLoader: core.ResourceLoader = null! as compiler.ResourceLoader; +const compilerResourceLoader: compiler.ResourceLoader = null! as core.ResourceLoader; -const coreStringMap: core.StringMap = null !as compiler.StringMap; -const compilerStringMap: compiler.StringMap = null !as core.StringMap; +const coreStringMap: core.StringMap = null! as compiler.StringMap; +const compilerStringMap: compiler.StringMap = null! as core.StringMap; -const coreProvider: core.Provider = null !as compiler.Provider; -const compilerProvider: compiler.Provider = null !as core.Provider; +const coreProvider: core.Provider = null! as compiler.Provider; +const compilerProvider: compiler.Provider = null! as core.Provider; const coreR3ResolvedDependencyType: core.R3ResolvedDependencyType = - null !as compiler.R3ResolvedDependencyType; + null! as compiler.R3ResolvedDependencyType; const compilerR3ResolvedDependencyType: compiler.R3ResolvedDependencyType = - null !as core.R3ResolvedDependencyType; + null! as core.R3ResolvedDependencyType; const coreR3ResolvedDependencyType2: R3ResolvedDependencyType = - null !as core.R3ResolvedDependencyType; + null! as core.R3ResolvedDependencyType; const compilerR3ResolvedDependencyType2: R3ResolvedDependencyType = - null !as core.R3ResolvedDependencyType; + null! as core.R3ResolvedDependencyType; const coreR3ResolvedDependencyType3: core.R3ResolvedDependencyType = - null !as R3ResolvedDependencyType; + null! as R3ResolvedDependencyType; const compilerR3ResolvedDependencyType3: compiler.R3ResolvedDependencyType = - null !as R3ResolvedDependencyType; + null! as R3ResolvedDependencyType; -const coreR3FactoryTarget: core.R3FactoryTarget = null !as compiler.R3FactoryTarget; -const compilerR3FactoryTarget: compiler.R3FactoryTarget = null !as core.R3FactoryTarget; +const coreR3FactoryTarget: core.R3FactoryTarget = null! as compiler.R3FactoryTarget; +const compilerR3FactoryTarget: compiler.R3FactoryTarget = null! as core.R3FactoryTarget; -const coreR3FactoryTarget2: R3FactoryTarget = null !as core.R3FactoryTarget; -const compilerR3FactoryTarget2: R3FactoryTarget = null !as core.R3FactoryTarget; +const coreR3FactoryTarget2: R3FactoryTarget = null! as core.R3FactoryTarget; +const compilerR3FactoryTarget2: R3FactoryTarget = null! as core.R3FactoryTarget; -const coreR3FactoryTarget3: core.R3FactoryTarget = null !as R3FactoryTarget; -const compilerR3FactoryTarget3: compiler.R3FactoryTarget = null !as R3FactoryTarget; +const coreR3FactoryTarget3: core.R3FactoryTarget = null! as R3FactoryTarget; +const compilerR3FactoryTarget3: compiler.R3FactoryTarget = null! as R3FactoryTarget; const coreR3DependencyMetadataFacade: core.R3DependencyMetadataFacade = - null !as compiler.R3DependencyMetadataFacade; + null! as compiler.R3DependencyMetadataFacade; const compilerR3DependencyMetadataFacade: compiler.R3DependencyMetadataFacade = - null !as core.R3DependencyMetadataFacade; + null! as core.R3DependencyMetadataFacade; -const coreR3PipeMetadataFacade: core.R3PipeMetadataFacade = null !as compiler.R3PipeMetadataFacade; +const coreR3PipeMetadataFacade: core.R3PipeMetadataFacade = null! as compiler.R3PipeMetadataFacade; const compilerR3PipeMetadataFacade: compiler.R3PipeMetadataFacade = - null !as core.R3PipeMetadataFacade; + null! as core.R3PipeMetadataFacade; const coreR3InjectableMetadataFacade: core.R3InjectableMetadataFacade = - null !as compiler.R3InjectableMetadataFacade; + null! as compiler.R3InjectableMetadataFacade; const compilerR3InjectableMetadataFacade: compiler.R3InjectableMetadataFacade = - null !as core.R3InjectableMetadataFacade; + null! as core.R3InjectableMetadataFacade; const coreR3NgModuleMetadataFacade: core.R3NgModuleMetadataFacade = - null !as compiler.R3NgModuleMetadataFacade; + null! as compiler.R3NgModuleMetadataFacade; const compilerR3NgModuleMetadataFacade: compiler.R3NgModuleMetadataFacade = - null !as core.R3NgModuleMetadataFacade; + null! as core.R3NgModuleMetadataFacade; const coreR3InjectorMetadataFacade: core.R3InjectorMetadataFacade = - null !as compiler.R3InjectorMetadataFacade; + null! as compiler.R3InjectorMetadataFacade; const compilerR3InjectorMetadataFacade: compiler.R3InjectorMetadataFacade = - null !as core.R3InjectorMetadataFacade; + null! as core.R3InjectorMetadataFacade; const coreR3DirectiveMetadataFacade: core.R3DirectiveMetadataFacade = - null !as compiler.R3DirectiveMetadataFacade; + null! as compiler.R3DirectiveMetadataFacade; const compilerR3DirectiveMetadataFacade: compiler.R3DirectiveMetadataFacade = - null !as core.R3DirectiveMetadataFacade; + null! as core.R3DirectiveMetadataFacade; const coreR3ComponentMetadataFacade: core.R3ComponentMetadataFacade = - null !as compiler.R3ComponentMetadataFacade; + null! as compiler.R3ComponentMetadataFacade; const compilerR3ComponentMetadataFacade: compiler.R3ComponentMetadataFacade = - null !as core.R3ComponentMetadataFacade; + null! as core.R3ComponentMetadataFacade; -const coreViewEncapsulation: core.ViewEncapsulation = null !as compiler.ViewEncapsulation; -const compilerViewEncapsulation: compiler.ViewEncapsulation = null !as core.ViewEncapsulation; +const coreViewEncapsulation: core.ViewEncapsulation = null! as compiler.ViewEncapsulation; +const compilerViewEncapsulation: compiler.ViewEncapsulation = null! as core.ViewEncapsulation; const coreR3QueryMetadataFacade: core.R3QueryMetadataFacade = - null !as compiler.R3QueryMetadataFacade; + null! as compiler.R3QueryMetadataFacade; const compilerR3QueryMetadataFacade: compiler.R3QueryMetadataFacade = - null !as core.R3QueryMetadataFacade; + null! as core.R3QueryMetadataFacade; diff --git a/packages/compiler/test/config_spec.ts b/packages/compiler/test/config_spec.ts index 459e80cf60b11..5126941759011 100644 --- a/packages/compiler/test/config_spec.ts +++ b/packages/compiler/test/config_spec.ts @@ -19,7 +19,9 @@ import {CompilerConfig, preserveWhitespacesDefault} from '../src/config'; describe('preserveWhitespacesDefault', () => { it('should return the default `false` setting when no preserveWhitespacesOption are provided', - () => { expect(preserveWhitespacesDefault(null)).toEqual(false); }); + () => { + expect(preserveWhitespacesDefault(null)).toEqual(false); + }); it('should return the preserveWhitespacesOption when provided as a parameter', () => { expect(preserveWhitespacesDefault(true)).toEqual(true); expect(preserveWhitespacesDefault(false)).toEqual(false); diff --git a/packages/compiler/test/core_spec.ts b/packages/compiler/test/core_spec.ts index f5864584cc5ca..e198db2e8df42 100644 --- a/packages/compiler/test/core_spec.ts +++ b/packages/compiler/test/core_spec.ts @@ -190,7 +190,9 @@ import * as core from '@angular/core'; function compareRuntimeShape(a: any, b: any) { const keys = metadataKeys(a); expect(keys).toEqual(metadataKeys(b)); - keys.forEach(key => { expect(a[key]).toBe(b[key]); }); + keys.forEach(key => { + expect(a[key]).toBe(b[key]); + }); // Need to check 'ngMetadataName' separately, as this is // on the prototype in @angular/core, but a regular property in @angular/compiler. expect(a.ngMetadataName).toBe(b.ngMetadataName); diff --git a/packages/compiler/test/css_parser/css_lexer_spec.ts b/packages/compiler/test/css_parser/css_lexer_spec.ts index 64a44d6c64003..96835c809aceb 100644 --- a/packages/compiler/test/css_parser/css_lexer_spec.ts +++ b/packages/compiler/test/css_parser/css_lexer_spec.ts @@ -7,370 +7,381 @@ */ import {describe, expect, it} from '../../../core/testing/src/testing_internal'; -import {CssLexer, CssLexerMode, CssToken, CssTokenType, cssScannerError, getRawMessage, getToken} from '../../src/css_parser/css_lexer'; +import {CssLexer, CssLexerMode, cssScannerError, CssToken, CssTokenType, getRawMessage, getToken} from '../../src/css_parser/css_lexer'; (function() { - function tokenize( - code: string, trackComments: boolean = false, - mode: CssLexerMode = CssLexerMode.ALL): CssToken[] { - const scanner = new CssLexer().scan(code, trackComments); - scanner.setMode(mode); - - const tokens: CssToken[] = []; - let output = scanner.scan(); - while (output != null) { - const error = output.error; - if (error != null) { - throw cssScannerError(getToken(error), getRawMessage(error)); - } - tokens.push(output.token); - output = scanner.scan(); +function tokenize( + code: string, trackComments: boolean = false, + mode: CssLexerMode = CssLexerMode.ALL): CssToken[] { + const scanner = new CssLexer().scan(code, trackComments); + scanner.setMode(mode); + + const tokens: CssToken[] = []; + let output = scanner.scan(); + while (output != null) { + const error = output.error; + if (error != null) { + throw cssScannerError(getToken(error), getRawMessage(error)); } - - return tokens; + tokens.push(output.token); + output = scanner.scan(); } - describe('CssLexer', () => { - it('should lex newline characters as whitespace when whitespace mode is on', () => { - const newlines = ['\n', '\r\n', '\r', '\f']; - newlines.forEach((line) => { - const token = tokenize(line, false, CssLexerMode.ALL_TRACK_WS)[0]; - expect(token.type).toEqual(CssTokenType.Whitespace); - }); - }); + return tokens; +} - it('should combined newline characters as one newline token when whitespace mode is on', () => { - const newlines = ['\n', '\r\n', '\r', '\f'].join(''); - const tokens = tokenize(newlines, false, CssLexerMode.ALL_TRACK_WS); - expect(tokens.length).toEqual(1); - expect(tokens[0].type).toEqual(CssTokenType.Whitespace); +describe('CssLexer', () => { + it('should lex newline characters as whitespace when whitespace mode is on', () => { + const newlines = ['\n', '\r\n', '\r', '\f']; + newlines.forEach((line) => { + const token = tokenize(line, false, CssLexerMode.ALL_TRACK_WS)[0]; + expect(token.type).toEqual(CssTokenType.Whitespace); }); + }); - it('should not consider whitespace or newline values at all when whitespace mode is off', - () => { - const newlines = ['\n', '\r\n', '\r', '\f'].join(''); - const tokens = tokenize(newlines); - expect(tokens.length).toEqual(0); - }); + it('should combined newline characters as one newline token when whitespace mode is on', () => { + const newlines = ['\n', '\r\n', '\r', '\f'].join(''); + const tokens = tokenize(newlines, false, CssLexerMode.ALL_TRACK_WS); + expect(tokens.length).toEqual(1); + expect(tokens[0].type).toEqual(CssTokenType.Whitespace); + }); - it('should lex simple selectors and their inner properties', () => { - const cssCode = '\n' + - ' .selector { my-prop: my-value; }\n'; - const tokens = tokenize(cssCode); + it('should not consider whitespace or newline values at all when whitespace mode is off', () => { + const newlines = ['\n', '\r\n', '\r', '\f'].join(''); + const tokens = tokenize(newlines); + expect(tokens.length).toEqual(0); + }); - expect(tokens[0].type).toEqual(CssTokenType.Character); - expect(tokens[0].strValue).toEqual('.'); + it('should lex simple selectors and their inner properties', () => { + const cssCode = '\n' + + ' .selector { my-prop: my-value; }\n'; + const tokens = tokenize(cssCode); - expect(tokens[1].type).toEqual(CssTokenType.Identifier); - expect(tokens[1].strValue).toEqual('selector'); + expect(tokens[0].type).toEqual(CssTokenType.Character); + expect(tokens[0].strValue).toEqual('.'); - expect(tokens[2].type).toEqual(CssTokenType.Character); - expect(tokens[2].strValue).toEqual('{'); + expect(tokens[1].type).toEqual(CssTokenType.Identifier); + expect(tokens[1].strValue).toEqual('selector'); - expect(tokens[3].type).toEqual(CssTokenType.Identifier); - expect(tokens[3].strValue).toEqual('my-prop'); + expect(tokens[2].type).toEqual(CssTokenType.Character); + expect(tokens[2].strValue).toEqual('{'); - expect(tokens[4].type).toEqual(CssTokenType.Character); - expect(tokens[4].strValue).toEqual(':'); + expect(tokens[3].type).toEqual(CssTokenType.Identifier); + expect(tokens[3].strValue).toEqual('my-prop'); - expect(tokens[5].type).toEqual(CssTokenType.Identifier); - expect(tokens[5].strValue).toEqual('my-value'); + expect(tokens[4].type).toEqual(CssTokenType.Character); + expect(tokens[4].strValue).toEqual(':'); - expect(tokens[6].type).toEqual(CssTokenType.Character); - expect(tokens[6].strValue).toEqual(';'); + expect(tokens[5].type).toEqual(CssTokenType.Identifier); + expect(tokens[5].strValue).toEqual('my-value'); - expect(tokens[7].type).toEqual(CssTokenType.Character); - expect(tokens[7].strValue).toEqual('}'); - }); + expect(tokens[6].type).toEqual(CssTokenType.Character); + expect(tokens[6].strValue).toEqual(';'); - it('should capture the column and line values for each token', () => { - const cssCode = '#id {\n' + - ' prop:value;\n' + - '}'; - - const tokens = tokenize(cssCode); - - // # - expect(tokens[0].type).toEqual(CssTokenType.Character); - expect(tokens[0].column).toEqual(0); - expect(tokens[0].line).toEqual(0); - - // id - expect(tokens[1].type).toEqual(CssTokenType.Identifier); - expect(tokens[1].column).toEqual(1); - expect(tokens[1].line).toEqual(0); - - // { - expect(tokens[2].type).toEqual(CssTokenType.Character); - expect(tokens[2].column).toEqual(4); - expect(tokens[2].line).toEqual(0); - - // prop - expect(tokens[3].type).toEqual(CssTokenType.Identifier); - expect(tokens[3].column).toEqual(2); - expect(tokens[3].line).toEqual(1); - - // : - expect(tokens[4].type).toEqual(CssTokenType.Character); - expect(tokens[4].column).toEqual(6); - expect(tokens[4].line).toEqual(1); - - // value - expect(tokens[5].type).toEqual(CssTokenType.Identifier); - expect(tokens[5].column).toEqual(7); - expect(tokens[5].line).toEqual(1); - - // ; - expect(tokens[6].type).toEqual(CssTokenType.Character); - expect(tokens[6].column).toEqual(12); - expect(tokens[6].line).toEqual(1); - - // } - expect(tokens[7].type).toEqual(CssTokenType.Character); - expect(tokens[7].column).toEqual(0); - expect(tokens[7].line).toEqual(2); - }); + expect(tokens[7].type).toEqual(CssTokenType.Character); + expect(tokens[7].strValue).toEqual('}'); + }); - it('should lex quoted strings and escape accordingly', () => { - const cssCode = 'prop: \'some { value } \\\' that is quoted\''; - const tokens = tokenize(cssCode); + it('should capture the column and line values for each token', () => { + const cssCode = '#id {\n' + + ' prop:value;\n' + + '}'; + + const tokens = tokenize(cssCode); + + // # + expect(tokens[0].type).toEqual(CssTokenType.Character); + expect(tokens[0].column).toEqual(0); + expect(tokens[0].line).toEqual(0); + + // id + expect(tokens[1].type).toEqual(CssTokenType.Identifier); + expect(tokens[1].column).toEqual(1); + expect(tokens[1].line).toEqual(0); + + // { + expect(tokens[2].type).toEqual(CssTokenType.Character); + expect(tokens[2].column).toEqual(4); + expect(tokens[2].line).toEqual(0); + + // prop + expect(tokens[3].type).toEqual(CssTokenType.Identifier); + expect(tokens[3].column).toEqual(2); + expect(tokens[3].line).toEqual(1); + + // : + expect(tokens[4].type).toEqual(CssTokenType.Character); + expect(tokens[4].column).toEqual(6); + expect(tokens[4].line).toEqual(1); + + // value + expect(tokens[5].type).toEqual(CssTokenType.Identifier); + expect(tokens[5].column).toEqual(7); + expect(tokens[5].line).toEqual(1); + + // ; + expect(tokens[6].type).toEqual(CssTokenType.Character); + expect(tokens[6].column).toEqual(12); + expect(tokens[6].line).toEqual(1); + + // } + expect(tokens[7].type).toEqual(CssTokenType.Character); + expect(tokens[7].column).toEqual(0); + expect(tokens[7].line).toEqual(2); + }); - expect(tokens[0].type).toEqual(CssTokenType.Identifier); - expect(tokens[1].type).toEqual(CssTokenType.Character); - expect(tokens[2].type).toEqual(CssTokenType.String); - expect(tokens[2].strValue).toEqual('\'some { value } \\\' that is quoted\''); - }); + it('should lex quoted strings and escape accordingly', () => { + const cssCode = 'prop: \'some { value } \\\' that is quoted\''; + const tokens = tokenize(cssCode); - it('should treat attribute operators as regular characters', () => { - tokenize('^|~+*').forEach((token) => { expect(token.type).toEqual(CssTokenType.Character); }); + expect(tokens[0].type).toEqual(CssTokenType.Identifier); + expect(tokens[1].type).toEqual(CssTokenType.Character); + expect(tokens[2].type).toEqual(CssTokenType.String); + expect(tokens[2].strValue).toEqual('\'some { value } \\\' that is quoted\''); + }); + + it('should treat attribute operators as regular characters', () => { + tokenize('^|~+*').forEach((token) => { + expect(token.type).toEqual(CssTokenType.Character); }); + }); - it('should lex numbers properly and set them as numbers', () => { - const cssCode = '0 1 -2 3.0 -4.001'; - const tokens = tokenize(cssCode); + it('should lex numbers properly and set them as numbers', () => { + const cssCode = '0 1 -2 3.0 -4.001'; + const tokens = tokenize(cssCode); - expect(tokens[0].type).toEqual(CssTokenType.Number); - expect(tokens[0].strValue).toEqual('0'); + expect(tokens[0].type).toEqual(CssTokenType.Number); + expect(tokens[0].strValue).toEqual('0'); - expect(tokens[1].type).toEqual(CssTokenType.Number); - expect(tokens[1].strValue).toEqual('1'); + expect(tokens[1].type).toEqual(CssTokenType.Number); + expect(tokens[1].strValue).toEqual('1'); - expect(tokens[2].type).toEqual(CssTokenType.Number); - expect(tokens[2].strValue).toEqual('-2'); + expect(tokens[2].type).toEqual(CssTokenType.Number); + expect(tokens[2].strValue).toEqual('-2'); - expect(tokens[3].type).toEqual(CssTokenType.Number); - expect(tokens[3].strValue).toEqual('3.0'); + expect(tokens[3].type).toEqual(CssTokenType.Number); + expect(tokens[3].strValue).toEqual('3.0'); - expect(tokens[4].type).toEqual(CssTokenType.Number); - expect(tokens[4].strValue).toEqual('-4.001'); - }); - - it('should lex @keywords', () => { - const cssCode = '@import()@something'; - const tokens = tokenize(cssCode); + expect(tokens[4].type).toEqual(CssTokenType.Number); + expect(tokens[4].strValue).toEqual('-4.001'); + }); - expect(tokens[0].type).toEqual(CssTokenType.AtKeyword); - expect(tokens[0].strValue).toEqual('@import'); + it('should lex @keywords', () => { + const cssCode = '@import()@something'; + const tokens = tokenize(cssCode); - expect(tokens[1].type).toEqual(CssTokenType.Character); - expect(tokens[1].strValue).toEqual('('); + expect(tokens[0].type).toEqual(CssTokenType.AtKeyword); + expect(tokens[0].strValue).toEqual('@import'); - expect(tokens[2].type).toEqual(CssTokenType.Character); - expect(tokens[2].strValue).toEqual(')'); + expect(tokens[1].type).toEqual(CssTokenType.Character); + expect(tokens[1].strValue).toEqual('('); - expect(tokens[3].type).toEqual(CssTokenType.AtKeyword); - expect(tokens[3].strValue).toEqual('@something'); - }); + expect(tokens[2].type).toEqual(CssTokenType.Character); + expect(tokens[2].strValue).toEqual(')'); - it('should still lex a number even if it has a dimension suffix', () => { - const cssCode = '40% is 40 percent'; - const tokens = tokenize(cssCode); + expect(tokens[3].type).toEqual(CssTokenType.AtKeyword); + expect(tokens[3].strValue).toEqual('@something'); + }); - expect(tokens[0].type).toEqual(CssTokenType.Number); - expect(tokens[0].strValue).toEqual('40'); + it('should still lex a number even if it has a dimension suffix', () => { + const cssCode = '40% is 40 percent'; + const tokens = tokenize(cssCode); - expect(tokens[1].type).toEqual(CssTokenType.Character); - expect(tokens[1].strValue).toEqual('%'); + expect(tokens[0].type).toEqual(CssTokenType.Number); + expect(tokens[0].strValue).toEqual('40'); - expect(tokens[2].type).toEqual(CssTokenType.Identifier); - expect(tokens[2].strValue).toEqual('is'); + expect(tokens[1].type).toEqual(CssTokenType.Character); + expect(tokens[1].strValue).toEqual('%'); - expect(tokens[3].type).toEqual(CssTokenType.Number); - expect(tokens[3].strValue).toEqual('40'); - }); + expect(tokens[2].type).toEqual(CssTokenType.Identifier); + expect(tokens[2].strValue).toEqual('is'); - it('should allow escaped character and unicode character-strings in CSS selectors', () => { - const cssCode = '\\123456 .some\\thing \{\}'; - const tokens = tokenize(cssCode); + expect(tokens[3].type).toEqual(CssTokenType.Number); + expect(tokens[3].strValue).toEqual('40'); + }); - expect(tokens[0].type).toEqual(CssTokenType.Identifier); - expect(tokens[0].strValue).toEqual('\\123456'); + it('should allow escaped character and unicode character-strings in CSS selectors', () => { + const cssCode = '\\123456 .some\\thing \{\}'; + const tokens = tokenize(cssCode); - expect(tokens[1].type).toEqual(CssTokenType.Character); - expect(tokens[2].type).toEqual(CssTokenType.Identifier); - expect(tokens[2].strValue).toEqual('some\\thing'); - }); + expect(tokens[0].type).toEqual(CssTokenType.Identifier); + expect(tokens[0].strValue).toEqual('\\123456'); - it('should distinguish identifiers and numbers from special characters', () => { - const cssCode = 'one*two=-4+three-4-equals_value$'; - const tokens = tokenize(cssCode); + expect(tokens[1].type).toEqual(CssTokenType.Character); + expect(tokens[2].type).toEqual(CssTokenType.Identifier); + expect(tokens[2].strValue).toEqual('some\\thing'); + }); - expect(tokens[0].type).toEqual(CssTokenType.Identifier); - expect(tokens[0].strValue).toEqual('one'); + it('should distinguish identifiers and numbers from special characters', () => { + const cssCode = 'one*two=-4+three-4-equals_value$'; + const tokens = tokenize(cssCode); - expect(tokens[1].type).toEqual(CssTokenType.Character); - expect(tokens[1].strValue).toEqual('*'); + expect(tokens[0].type).toEqual(CssTokenType.Identifier); + expect(tokens[0].strValue).toEqual('one'); - expect(tokens[2].type).toEqual(CssTokenType.Identifier); - expect(tokens[2].strValue).toEqual('two'); + expect(tokens[1].type).toEqual(CssTokenType.Character); + expect(tokens[1].strValue).toEqual('*'); - expect(tokens[3].type).toEqual(CssTokenType.Character); - expect(tokens[3].strValue).toEqual('='); + expect(tokens[2].type).toEqual(CssTokenType.Identifier); + expect(tokens[2].strValue).toEqual('two'); - expect(tokens[4].type).toEqual(CssTokenType.Number); - expect(tokens[4].strValue).toEqual('-4'); + expect(tokens[3].type).toEqual(CssTokenType.Character); + expect(tokens[3].strValue).toEqual('='); - expect(tokens[5].type).toEqual(CssTokenType.Character); - expect(tokens[5].strValue).toEqual('+'); + expect(tokens[4].type).toEqual(CssTokenType.Number); + expect(tokens[4].strValue).toEqual('-4'); - expect(tokens[6].type).toEqual(CssTokenType.Identifier); - expect(tokens[6].strValue).toEqual('three-4-equals_value'); + expect(tokens[5].type).toEqual(CssTokenType.Character); + expect(tokens[5].strValue).toEqual('+'); - expect(tokens[7].type).toEqual(CssTokenType.Character); - expect(tokens[7].strValue).toEqual('$'); - }); + expect(tokens[6].type).toEqual(CssTokenType.Identifier); + expect(tokens[6].strValue).toEqual('three-4-equals_value'); - it('should filter out comments and whitespace by default', () => { - const cssCode = '.selector /* comment */ { /* value */ }'; - const tokens = tokenize(cssCode); + expect(tokens[7].type).toEqual(CssTokenType.Character); + expect(tokens[7].strValue).toEqual('$'); + }); - expect(tokens[0].strValue).toEqual('.'); - expect(tokens[1].strValue).toEqual('selector'); - expect(tokens[2].strValue).toEqual('{'); - expect(tokens[3].strValue).toEqual('}'); - }); + it('should filter out comments and whitespace by default', () => { + const cssCode = '.selector /* comment */ { /* value */ }'; + const tokens = tokenize(cssCode); - it('should track comments when the flag is set to true', () => { - const cssCode = '.selector /* comment */ { /* value */ }'; - const trackComments = true; - const tokens = tokenize(cssCode, trackComments, CssLexerMode.ALL_TRACK_WS); + expect(tokens[0].strValue).toEqual('.'); + expect(tokens[1].strValue).toEqual('selector'); + expect(tokens[2].strValue).toEqual('{'); + expect(tokens[3].strValue).toEqual('}'); + }); - expect(tokens[0].strValue).toEqual('.'); - expect(tokens[1].strValue).toEqual('selector'); - expect(tokens[2].strValue).toEqual(' '); + it('should track comments when the flag is set to true', () => { + const cssCode = '.selector /* comment */ { /* value */ }'; + const trackComments = true; + const tokens = tokenize(cssCode, trackComments, CssLexerMode.ALL_TRACK_WS); - expect(tokens[3].type).toEqual(CssTokenType.Comment); - expect(tokens[3].strValue).toEqual('/* comment */'); + expect(tokens[0].strValue).toEqual('.'); + expect(tokens[1].strValue).toEqual('selector'); + expect(tokens[2].strValue).toEqual(' '); - expect(tokens[4].strValue).toEqual(' '); - expect(tokens[5].strValue).toEqual('{'); - expect(tokens[6].strValue).toEqual(' '); + expect(tokens[3].type).toEqual(CssTokenType.Comment); + expect(tokens[3].strValue).toEqual('/* comment */'); - expect(tokens[7].type).toEqual(CssTokenType.Comment); - expect(tokens[7].strValue).toEqual('/* value */'); - }); + expect(tokens[4].strValue).toEqual(' '); + expect(tokens[5].strValue).toEqual('{'); + expect(tokens[6].strValue).toEqual(' '); - describe('Selector Mode', () => { - it('should throw an error if a selector is being parsed while in the wrong mode', () => { - const cssCode = '.class > tag'; + expect(tokens[7].type).toEqual(CssTokenType.Comment); + expect(tokens[7].strValue).toEqual('/* value */'); + }); - let capturedMessage: string|null = null; - try { - tokenize(cssCode, false, CssLexerMode.STYLE_BLOCK); - } catch (e) { - capturedMessage = getRawMessage(e); - } + describe('Selector Mode', () => { + it('should throw an error if a selector is being parsed while in the wrong mode', () => { + const cssCode = '.class > tag'; - expect(capturedMessage).toMatch(/Unexpected character \[\>\] at column 0:7 in expression/g); + let capturedMessage: string|null = null; + try { + tokenize(cssCode, false, CssLexerMode.STYLE_BLOCK); + } catch (e) { + capturedMessage = getRawMessage(e); + } - capturedMessage = null; - try { - tokenize(cssCode, false, CssLexerMode.SELECTOR); - } catch (e) { - capturedMessage = getRawMessage(e); - } + expect(capturedMessage).toMatch(/Unexpected character \[\>\] at column 0:7 in expression/g); - expect(capturedMessage).toEqual(null); - }); - }); + capturedMessage = null; + try { + tokenize(cssCode, false, CssLexerMode.SELECTOR); + } catch (e) { + capturedMessage = getRawMessage(e); + } - describe('Attribute Mode', () => { - it('should consider attribute selectors as valid input and throw when an invalid modifier is used', - () => { - function tokenizeAttr(modifier: string) { - const cssCode = 'value' + modifier + '=\'something\''; - return tokenize(cssCode, false, CssLexerMode.ATTRIBUTE_SELECTOR); - } - - expect(tokenizeAttr('*').length).toEqual(4); - expect(tokenizeAttr('|').length).toEqual(4); - expect(tokenizeAttr('^').length).toEqual(4); - expect(tokenizeAttr('$').length).toEqual(4); - expect(tokenizeAttr('~').length).toEqual(4); - expect(tokenizeAttr('').length).toEqual(3); - - expect(() => { tokenizeAttr('+'); }).toThrow(); - }); + expect(capturedMessage).toEqual(null); }); + }); - describe('Media Query Mode', () => { - it('should validate media queries with a reduced subset of valid characters', () => { - function tokenizeQuery(code: string) { - return tokenize(code, false, CssLexerMode.MEDIA_QUERY); - } - - // the reason why the numbers are so high is because MediaQueries keep - // track of the whitespace values - expect(tokenizeQuery('(prop: value)').length).toEqual(5); - expect(tokenizeQuery('(prop: value) and (prop2: value2)').length).toEqual(11); - expect(tokenizeQuery('tv and (prop: value)').length).toEqual(7); - expect(tokenizeQuery('print and ((prop: value) or (prop2: value2))').length).toEqual(15); - expect(tokenizeQuery('(content: \'something $ crazy inside &\')').length).toEqual(5); + describe('Attribute Mode', () => { + it('should consider attribute selectors as valid input and throw when an invalid modifier is used', + () => { + function tokenizeAttr(modifier: string) { + const cssCode = 'value' + modifier + '=\'something\''; + return tokenize(cssCode, false, CssLexerMode.ATTRIBUTE_SELECTOR); + } + + expect(tokenizeAttr('*').length).toEqual(4); + expect(tokenizeAttr('|').length).toEqual(4); + expect(tokenizeAttr('^').length).toEqual(4); + expect(tokenizeAttr('$').length).toEqual(4); + expect(tokenizeAttr('~').length).toEqual(4); + expect(tokenizeAttr('').length).toEqual(3); + + expect(() => { + tokenizeAttr('+'); + }).toThrow(); + }); + }); - expect(() => { tokenizeQuery('(max-height: 10 + 20)'); }).toThrow(); + describe('Media Query Mode', () => { + it('should validate media queries with a reduced subset of valid characters', () => { + function tokenizeQuery(code: string) { + return tokenize(code, false, CssLexerMode.MEDIA_QUERY); + } - expect(() => { tokenizeQuery('(max-height: fifty < 100)'); }).toThrow(); - }); + // the reason why the numbers are so high is because MediaQueries keep + // track of the whitespace values + expect(tokenizeQuery('(prop: value)').length).toEqual(5); + expect(tokenizeQuery('(prop: value) and (prop2: value2)').length).toEqual(11); + expect(tokenizeQuery('tv and (prop: value)').length).toEqual(7); + expect(tokenizeQuery('print and ((prop: value) or (prop2: value2))').length).toEqual(15); + expect(tokenizeQuery('(content: \'something $ crazy inside &\')').length).toEqual(5); + + expect(() => { + tokenizeQuery('(max-height: 10 + 20)'); + }).toThrow(); + + expect(() => { + tokenizeQuery('(max-height: fifty < 100)'); + }).toThrow(); }); + }); - describe('Pseudo Selector Mode', () => { - it('should validate pseudo selector identifiers with a reduced subset of valid characters', - () => { - function tokenizePseudo(code: string, withArgs = false): CssToken[] { - const mode = withArgs ? CssLexerMode.PSEUDO_SELECTOR_WITH_ARGUMENTS : - CssLexerMode.PSEUDO_SELECTOR; - return tokenize(code, false, mode); - } - - expect(tokenizePseudo('hover').length).toEqual(1); - expect(tokenizePseudo('focus').length).toEqual(1); - expect(tokenizePseudo('lang(en-us)', true).length).toEqual(4); - - expect(() => { tokenizePseudo('lang(something:broken)', true); }).toThrow(); - - expect(() => { tokenizePseudo('not(.selector)', true); }).toThrow(); - }); - }); + describe('Pseudo Selector Mode', () => { + it('should validate pseudo selector identifiers with a reduced subset of valid characters', + () => { + function tokenizePseudo(code: string, withArgs = false): CssToken[] { + const mode = withArgs ? CssLexerMode.PSEUDO_SELECTOR_WITH_ARGUMENTS : + CssLexerMode.PSEUDO_SELECTOR; + return tokenize(code, false, mode); + } + + expect(tokenizePseudo('hover').length).toEqual(1); + expect(tokenizePseudo('focus').length).toEqual(1); + expect(tokenizePseudo('lang(en-us)', true).length).toEqual(4); + + expect(() => { + tokenizePseudo('lang(something:broken)', true); + }).toThrow(); + + expect(() => { + tokenizePseudo('not(.selector)', true); + }).toThrow(); + }); + }); - describe( - 'Style Block Mode', () => { - it('should style blocks with a reduced subset of valid characters', - () => { - function tokenizeStyles(code: string) { - return tokenize(code, false, CssLexerMode.STYLE_BLOCK); - } + describe( + 'Style Block Mode', () => { + it( + 'should style blocks with a reduced subset of valid characters', () => { + function tokenizeStyles(code: string) { + return tokenize(code, false, CssLexerMode.STYLE_BLOCK); + } - expect(tokenizeStyles(` + expect(tokenizeStyles(` key: value; prop: 100; style: value3!important; `).length).toEqual(14); - expect(() => tokenizeStyles(` key$: value; `)).toThrow(); - expect(() => tokenizeStyles(` key: value$; `)).toThrow(); - expect(() => tokenizeStyles(` key: value + 10; `)).toThrow(); - expect(() => tokenizeStyles(` key: &value; `)).toThrow(); - }); - }); - }); + expect(() => tokenizeStyles(` key$: value; `)).toThrow(); + expect(() => tokenizeStyles(` key: value$; `)).toThrow(); + expect(() => tokenizeStyles(` key: value + 10; `)).toThrow(); + expect(() => tokenizeStyles(` key: &value; `)).toThrow(); + }); + }); +}); })(); diff --git a/packages/compiler/test/css_parser/css_parser_spec.ts b/packages/compiler/test/css_parser/css_parser_spec.ts index 670a48264b3bc..ad8c211ece16b 100644 --- a/packages/compiler/test/css_parser/css_parser_spec.ts +++ b/packages/compiler/test/css_parser/css_parser_spec.ts @@ -111,26 +111,26 @@ export function assertTokens(tokens: CssToken[], valuesArr: string[]) { expect(ast.rules.length).toEqual(1); const rule = <CssKeyframeRuleAst>ast.rules[0]; - expect(rule.name !.strValue).toEqual('rotateMe'); + expect(rule.name!.strValue).toEqual('rotateMe'); const block = <CssBlockAst>rule.block; const fromRule = <CssKeyframeDefinitionAst>block.entries[0]; - expect(fromRule.name !.strValue).toEqual('from'); + expect(fromRule.name!.strValue).toEqual('from'); const fromStyle = <CssDefinitionAst>(<CssBlockAst>fromRule.block).entries[0]; expect(fromStyle.property.strValue).toEqual('transform'); assertTokens(fromStyle.value.tokens, ['rotate', '(', '-360', 'deg', ')']); const midRule = <CssKeyframeDefinitionAst>block.entries[1]; - expect(midRule.name !.strValue).toEqual('50%'); + expect(midRule.name!.strValue).toEqual('50%'); const midStyle = <CssDefinitionAst>(<CssBlockAst>midRule.block).entries[0]; expect(midStyle.property.strValue).toEqual('transform'); assertTokens(midStyle.value.tokens, ['rotate', '(', '0', 'deg', ')']); const toRule = <CssKeyframeDefinitionAst>block.entries[2]; - expect(toRule.name !.strValue).toEqual('to'); + expect(toRule.name!.strValue).toEqual('to'); const toStyle = <CssDefinitionAst>(<CssBlockAst>toRule.block).entries[0]; expect(toStyle.property.strValue).toEqual('transform'); assertTokens(toStyle.value.tokens, ['rotate', '(', '360', 'deg', ')']); @@ -695,7 +695,7 @@ export function assertTokens(tokens: CssToken[], valuesArr: string[]) { const ast = output.ast; assertMatchesOffsetAndChar(ast.location.start, 0, '#'); - assertMatchesOffsetAndChar(ast.location.end, 22, undefined !); + assertMatchesOffsetAndChar(ast.location.end, 22, undefined!); }); }); diff --git a/packages/compiler/test/css_parser/css_visitor_spec.ts b/packages/compiler/test/css_parser/css_visitor_spec.ts index 5a36459264e6e..f7d05a5e5b2a7 100644 --- a/packages/compiler/test/css_parser/css_visitor_spec.ts +++ b/packages/compiler/test/css_parser/css_visitor_spec.ts @@ -8,7 +8,7 @@ import {beforeEach, describe, expect, it} from '../../../core/testing/src/testing_internal'; -import {CssAst, CssAstVisitor, CssAtRulePredicateAst, CssBlockAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStyleSheetAst, CssStyleValueAst, CssStylesBlockAst, CssUnknownRuleAst, CssUnknownTokenListAst} from '../../src/css_parser/css_ast'; +import {CssAst, CssAstVisitor, CssAtRulePredicateAst, CssBlockAst, CssDefinitionAst, CssInlineRuleAst, CssKeyframeDefinitionAst, CssKeyframeRuleAst, CssMediaQueryRuleAst, CssPseudoSelectorAst, CssRuleAst, CssSelectorAst, CssSelectorRuleAst, CssSimpleSelectorAst, CssStylesBlockAst, CssStyleSheetAst, CssStyleValueAst, CssUnknownRuleAst, CssUnknownTokenListAst} from '../../src/css_parser/css_ast'; import {BlockType, CssParseError, CssParser, CssToken} from '../../src/css_parser/css_parser'; function _assertTokens(tokens: CssToken[], valuesArr: string[]): void { @@ -29,7 +29,9 @@ class MyVisitor implements CssAstVisitor { this.captures[method].push([ast, context]); } - constructor(ast: CssStyleSheetAst, context: any) { ast.visit(this, context); } + constructor(ast: CssStyleSheetAst, context: any) { + ast.visit(this, context); + } visitCssValue(ast: CssStyleValueAst, context: any): void { this._capture('visitCssValue', ast, context); @@ -61,20 +63,24 @@ class MyVisitor implements CssAstVisitor { visitCssSelectorRule(ast: CssSelectorRuleAst, context: any): void { this._capture('visitCssSelectorRule', ast, context); - ast.selectors.forEach((selAst: CssSelectorAst) => { selAst.visit(this, context); }); + ast.selectors.forEach((selAst: CssSelectorAst) => { + selAst.visit(this, context); + }); ast.block.visit(this, context); } visitCssSelector(ast: CssSelectorAst, context: any): void { this._capture('visitCssSelector', ast, context); - ast.selectorParts.forEach( - (simpleAst: CssSimpleSelectorAst) => { simpleAst.visit(this, context); }); + ast.selectorParts.forEach((simpleAst: CssSimpleSelectorAst) => { + simpleAst.visit(this, context); + }); } visitCssSimpleSelector(ast: CssSimpleSelectorAst, context: any): void { this._capture('visitCssSimpleSelector', ast, context); - ast.pseudoSelectors.forEach( - (pseudoAst: CssPseudoSelectorAst) => { pseudoAst.visit(this, context); }); + ast.pseudoSelectors.forEach((pseudoAst: CssPseudoSelectorAst) => { + pseudoAst.visit(this, context); + }); } visitCssDefinition(ast: CssDefinitionAst, context: any): void { @@ -84,18 +90,23 @@ class MyVisitor implements CssAstVisitor { visitCssBlock(ast: CssBlockAst, context: any): void { this._capture('visitCssBlock', ast, context); - ast.entries.forEach((entryAst: CssAst) => { entryAst.visit(this, context); }); + ast.entries.forEach((entryAst: CssAst) => { + entryAst.visit(this, context); + }); } visitCssStylesBlock(ast: CssStylesBlockAst, context: any): void { this._capture('visitCssStylesBlock', ast, context); - ast.definitions.forEach( - (definitionAst: CssDefinitionAst) => { definitionAst.visit(this, context); }); + ast.definitions.forEach((definitionAst: CssDefinitionAst) => { + definitionAst.visit(this, context); + }); } visitCssStyleSheet(ast: CssStyleSheetAst, context: any): void { this._capture('visitCssStyleSheet', ast, context); - ast.rules.forEach((ruleAst: CssRuleAst) => { ruleAst.visit(this, context); }); + ast.rules.forEach((ruleAst: CssRuleAst) => { + ruleAst.visit(this, context); + }); } visitCssUnknownRule(ast: CssUnknownRuleAst, context: any): void { @@ -116,21 +127,21 @@ function _getCaptureAst(capture: any[], index = 0): CssAst { } (function() { - function parse(cssCode: string, ignoreErrors: boolean = false) { - const output = new CssParser().parse(cssCode, 'some-fake-css-file.css'); - const errors = output.errors; - if (errors.length > 0 && !ignoreErrors) { - throw new Error(errors.map((error: CssParseError) => error.msg).join(', ')); - } - return output.ast; +function parse(cssCode: string, ignoreErrors: boolean = false) { + const output = new CssParser().parse(cssCode, 'some-fake-css-file.css'); + const errors = output.errors; + if (errors.length > 0 && !ignoreErrors) { + throw new Error(errors.map((error: CssParseError) => error.msg).join(', ')); } + return output.ast; +} - describe('CSS parsing and visiting', () => { - let ast: CssStyleSheetAst; - const context = {}; +describe('CSS parsing and visiting', () => { + let ast: CssStyleSheetAst; + const context = {}; - beforeEach(() => { - const cssCode = ` + beforeEach(() => { + const cssCode = ` .rule1 { prop1: value1 } .rule2 { prop2: value2 } @@ -149,174 +160,174 @@ function _getCaptureAst(capture: any[], index = 0): CssAst { } } `; - ast = parse(cssCode); - }); + ast = parse(cssCode); + }); - it('should parse and visit a stylesheet', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssStyleSheet']; + it('should parse and visit a stylesheet', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssStyleSheet']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const capture = captures[0]; - expect(capture[0]).toEqual(ast); - expect(capture[1]).toEqual(context); - }); + const capture = captures[0]; + expect(capture[0]).toEqual(ast); + expect(capture[1]).toEqual(context); + }); - it('should parse and visit each of the stylesheet selectors', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssSelectorRule']; + it('should parse and visit each of the stylesheet selectors', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssSelectorRule']; - expect(captures.length).toEqual(3); + expect(captures.length).toEqual(3); - const rule1 = <CssSelectorRuleAst>_getCaptureAst(captures, 0); - expect(rule1).toEqual(ast.rules[0] as CssSelectorRuleAst); + const rule1 = <CssSelectorRuleAst>_getCaptureAst(captures, 0); + expect(rule1).toEqual(ast.rules[0] as CssSelectorRuleAst); - const firstSelector = rule1.selectors[0]; - const firstSimpleSelector = firstSelector.selectorParts[0]; - _assertTokens(firstSimpleSelector.tokens, ['.', 'rule1']); + const firstSelector = rule1.selectors[0]; + const firstSimpleSelector = firstSelector.selectorParts[0]; + _assertTokens(firstSimpleSelector.tokens, ['.', 'rule1']); - const rule2 = <CssSelectorRuleAst>_getCaptureAst(captures, 1); - expect(rule2).toEqual(ast.rules[1] as CssSelectorRuleAst); + const rule2 = <CssSelectorRuleAst>_getCaptureAst(captures, 1); + expect(rule2).toEqual(ast.rules[1] as CssSelectorRuleAst); - const secondSelector = rule2.selectors[0]; - const secondSimpleSelector = secondSelector.selectorParts[0]; - _assertTokens(secondSimpleSelector.tokens, ['.', 'rule2']); + const secondSelector = rule2.selectors[0]; + const secondSimpleSelector = secondSelector.selectorParts[0]; + _assertTokens(secondSimpleSelector.tokens, ['.', 'rule2']); - const rule3 = <CssSelectorRuleAst>_getCaptureAst(captures, 2); - expect(rule3).toEqual( - (ast.rules[2] as CssSelectorRuleAst).block.entries[0] as CssSelectorRuleAst); + const rule3 = <CssSelectorRuleAst>_getCaptureAst(captures, 2); + expect(rule3).toEqual( + (ast.rules[2] as CssSelectorRuleAst).block.entries[0] as CssSelectorRuleAst); - const thirdSelector = rule3.selectors[0]; - const thirdSimpleSelector = thirdSelector.selectorParts[0]; - _assertTokens(thirdSimpleSelector.tokens, ['#', 'rule3']); - }); + const thirdSelector = rule3.selectors[0]; + const thirdSimpleSelector = thirdSelector.selectorParts[0]; + _assertTokens(thirdSimpleSelector.tokens, ['#', 'rule3']); + }); - it('should parse and visit each of the stylesheet style key/value definitions', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssDefinition']; + it('should parse and visit each of the stylesheet style key/value definitions', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssDefinition']; - expect(captures.length).toEqual(5); + expect(captures.length).toEqual(5); - const def1 = <CssDefinitionAst>_getCaptureAst(captures, 0); - expect(def1.property.strValue).toEqual('prop1'); - expect(def1.value.tokens[0].strValue).toEqual('value1'); + const def1 = <CssDefinitionAst>_getCaptureAst(captures, 0); + expect(def1.property.strValue).toEqual('prop1'); + expect(def1.value.tokens[0].strValue).toEqual('value1'); - const def2 = <CssDefinitionAst>_getCaptureAst(captures, 1); - expect(def2.property.strValue).toEqual('prop2'); - expect(def2.value.tokens[0].strValue).toEqual('value2'); + const def2 = <CssDefinitionAst>_getCaptureAst(captures, 1); + expect(def2.property.strValue).toEqual('prop2'); + expect(def2.value.tokens[0].strValue).toEqual('value2'); - const def3 = <CssDefinitionAst>_getCaptureAst(captures, 2); - expect(def3.property.strValue).toEqual('prop3'); - expect(def3.value.tokens[0].strValue).toEqual('value3'); + const def3 = <CssDefinitionAst>_getCaptureAst(captures, 2); + expect(def3.property.strValue).toEqual('prop3'); + expect(def3.value.tokens[0].strValue).toEqual('value3'); - const def4 = <CssDefinitionAst>_getCaptureAst(captures, 3); - expect(def4.property.strValue).toEqual('prop4'); - expect(def4.value.tokens[0].strValue).toEqual('value4'); + const def4 = <CssDefinitionAst>_getCaptureAst(captures, 3); + expect(def4.property.strValue).toEqual('prop4'); + expect(def4.value.tokens[0].strValue).toEqual('value4'); - const def5 = <CssDefinitionAst>_getCaptureAst(captures, 4); - expect(def5.property.strValue).toEqual('prop5'); - expect(def5.value.tokens[0].strValue).toEqual('value5'); - }); + const def5 = <CssDefinitionAst>_getCaptureAst(captures, 4); + expect(def5.property.strValue).toEqual('prop5'); + expect(def5.value.tokens[0].strValue).toEqual('value5'); + }); - it('should parse and visit the associated media query values', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssMediaQueryRule']; + it('should parse and visit the associated media query values', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssMediaQueryRule']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const query1 = <CssMediaQueryRuleAst>_getCaptureAst(captures, 0); - _assertTokens(query1.query.tokens, ['all', 'and', '(', 'max-width', '100', 'px', ')']); - expect(query1.block.entries.length).toEqual(1); - }); + const query1 = <CssMediaQueryRuleAst>_getCaptureAst(captures, 0); + _assertTokens(query1.query.tokens, ['all', 'and', '(', 'max-width', '100', 'px', ')']); + expect(query1.block.entries.length).toEqual(1); + }); - it('should capture the media query predicate', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssAtRulePredicate']; + it('should capture the media query predicate', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssAtRulePredicate']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const predicate = <CssAtRulePredicateAst>_getCaptureAst(captures, 0); - expect(predicate.strValue).toEqual('@media all (max-width: 100px)'); - }); + const predicate = <CssAtRulePredicateAst>_getCaptureAst(captures, 0); + expect(predicate.strValue).toEqual('@media all (max-width: 100px)'); + }); - it('should parse and visit the associated "@inline" rule values', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssInlineRule']; + it('should parse and visit the associated "@inline" rule values', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssInlineRule']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const inline1 = <CssInlineRuleAst>_getCaptureAst(captures, 0); - expect(inline1.type).toEqual(BlockType.Import); - _assertTokens(inline1.value.tokens, ['url', '(', 'file.css', ')']); - }); + const inline1 = <CssInlineRuleAst>_getCaptureAst(captures, 0); + expect(inline1.type).toEqual(BlockType.Import); + _assertTokens(inline1.value.tokens, ['url', '(', 'file.css', ')']); + }); - it('should parse and visit the keyframe blocks', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssKeyframeRule']; + it('should parse and visit the keyframe blocks', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssKeyframeRule']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const keyframe1 = <CssKeyframeRuleAst>_getCaptureAst(captures, 0); - expect(keyframe1.name !.strValue).toEqual('rotate'); - expect(keyframe1.block.entries.length).toEqual(2); - }); + const keyframe1 = <CssKeyframeRuleAst>_getCaptureAst(captures, 0); + expect(keyframe1.name!.strValue).toEqual('rotate'); + expect(keyframe1.block.entries.length).toEqual(2); + }); - it('should parse and visit the associated keyframe rules', () => { - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssKeyframeDefinition']; + it('should parse and visit the associated keyframe rules', () => { + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssKeyframeDefinition']; - expect(captures.length).toEqual(2); + expect(captures.length).toEqual(2); - const def1 = <CssKeyframeDefinitionAst>_getCaptureAst(captures, 0); - _assertTokens(def1.steps, ['from']); - expect(def1.block.entries.length).toEqual(1); + const def1 = <CssKeyframeDefinitionAst>_getCaptureAst(captures, 0); + _assertTokens(def1.steps, ['from']); + expect(def1.block.entries.length).toEqual(1); - const def2 = <CssKeyframeDefinitionAst>_getCaptureAst(captures, 1); - _assertTokens(def2.steps, ['50%', '100%']); - expect(def2.block.entries.length).toEqual(1); - }); + const def2 = <CssKeyframeDefinitionAst>_getCaptureAst(captures, 1); + _assertTokens(def2.steps, ['50%', '100%']); + expect(def2.block.entries.length).toEqual(1); + }); - it('should visit an unknown `@` rule', () => { - const cssCode = ` + it('should visit an unknown `@` rule', () => { + const cssCode = ` @someUnknownRule param { one two three } `; - ast = parse(cssCode, true); - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssUnknownRule']; + ast = parse(cssCode, true); + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssUnknownRule']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const rule = <CssUnknownRuleAst>_getCaptureAst(captures, 0); - expect(rule.ruleName).toEqual('@someUnknownRule'); + const rule = <CssUnknownRuleAst>_getCaptureAst(captures, 0); + expect(rule.ruleName).toEqual('@someUnknownRule'); - _assertTokens(rule.tokens, ['param', '{', 'one', 'two', 'three', '}']); - }); + _assertTokens(rule.tokens, ['param', '{', 'one', 'two', 'three', '}']); + }); - it('should collect an invalid list of tokens before a valid selector', () => { - const cssCode = 'one two three four five; selector { }'; - ast = parse(cssCode, true); - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssUnknownTokenList']; + it('should collect an invalid list of tokens before a valid selector', () => { + const cssCode = 'one two three four five; selector { }'; + ast = parse(cssCode, true); + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssUnknownTokenList']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const rule = <CssUnknownTokenListAst>_getCaptureAst(captures, 0); - _assertTokens(rule.tokens, ['one', 'two', 'three', 'four', 'five']); - }); + const rule = <CssUnknownTokenListAst>_getCaptureAst(captures, 0); + _assertTokens(rule.tokens, ['one', 'two', 'three', 'four', 'five']); + }); - it('should collect an invalid list of tokens after a valid selector', () => { - const cssCode = 'selector { } six seven eight'; - ast = parse(cssCode, true); - const visitor = new MyVisitor(ast, context); - const captures = visitor.captures['visitCssUnknownTokenList']; + it('should collect an invalid list of tokens after a valid selector', () => { + const cssCode = 'selector { } six seven eight'; + ast = parse(cssCode, true); + const visitor = new MyVisitor(ast, context); + const captures = visitor.captures['visitCssUnknownTokenList']; - expect(captures.length).toEqual(1); + expect(captures.length).toEqual(1); - const rule = <CssUnknownTokenListAst>_getCaptureAst(captures, 0); - _assertTokens(rule.tokens, ['six', 'seven', 'eight']); - }); + const rule = <CssUnknownTokenListAst>_getCaptureAst(captures, 0); + _assertTokens(rule.tokens, ['six', 'seven', 'eight']); }); +}); })(); diff --git a/packages/compiler/test/directive_lifecycle_spec.ts b/packages/compiler/test/directive_lifecycle_spec.ts index a4bd85928f4b1..4e77bec8065b4 100644 --- a/packages/compiler/test/directive_lifecycle_spec.ts +++ b/packages/compiler/test/directive_lifecycle_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {LifecycleHooks as Hooks, hasLifecycleHook as hasLifecycleHookImpl} from '@angular/compiler/src/lifecycle_reflector'; +import {hasLifecycleHook as hasLifecycleHookImpl, LifecycleHooks as Hooks} from '@angular/compiler/src/lifecycle_reflector'; import {SimpleChanges} from '@angular/core'; import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector'; @@ -17,14 +17,14 @@ function hasLifecycleHook(hook: Hooks, directive: any): boolean { { describe('Create Directive', () => { describe('lifecycle', () => { - describe('ngOnChanges', () => { it('should be true when the directive has the ngOnChanges method', () => { expect(hasLifecycleHook(Hooks.OnChanges, DirectiveWithOnChangesMethod)).toBe(true); }); - it('should be false otherwise', - () => { expect(hasLifecycleHook(Hooks.OnChanges, DirectiveNoHooks)).toBe(false); }); + it('should be false otherwise', () => { + expect(hasLifecycleHook(Hooks.OnChanges, DirectiveNoHooks)).toBe(false); + }); }); describe('ngOnDestroy', () => { @@ -32,16 +32,19 @@ function hasLifecycleHook(hook: Hooks, directive: any): boolean { expect(hasLifecycleHook(Hooks.OnDestroy, DirectiveWithOnDestroyMethod)).toBe(true); }); - it('should be false otherwise', - () => { expect(hasLifecycleHook(Hooks.OnDestroy, DirectiveNoHooks)).toBe(false); }); + it('should be false otherwise', () => { + expect(hasLifecycleHook(Hooks.OnDestroy, DirectiveNoHooks)).toBe(false); + }); }); describe('ngOnInit', () => { - it('should be true when the directive has the ngOnInit method', - () => { expect(hasLifecycleHook(Hooks.OnInit, DirectiveWithOnInitMethod)).toBe(true); }); + it('should be true when the directive has the ngOnInit method', () => { + expect(hasLifecycleHook(Hooks.OnInit, DirectiveWithOnInitMethod)).toBe(true); + }); - it('should be false otherwise', - () => { expect(hasLifecycleHook(Hooks.OnInit, DirectiveNoHooks)).toBe(false); }); + it('should be false otherwise', () => { + expect(hasLifecycleHook(Hooks.OnInit, DirectiveNoHooks)).toBe(false); + }); }); describe('ngDoCheck', () => { @@ -49,8 +52,9 @@ function hasLifecycleHook(hook: Hooks, directive: any): boolean { expect(hasLifecycleHook(Hooks.DoCheck, DirectiveWithOnCheckMethod)).toBe(true); }); - it('should be false otherwise', - () => { expect(hasLifecycleHook(Hooks.DoCheck, DirectiveNoHooks)).toBe(false); }); + it('should be false otherwise', () => { + expect(hasLifecycleHook(Hooks.DoCheck, DirectiveNoHooks)).toBe(false); + }); }); describe('ngAfterContentInit', () => { @@ -83,8 +87,9 @@ function hasLifecycleHook(hook: Hooks, directive: any): boolean { .toBe(true); }); - it('should be false otherwise', - () => { expect(hasLifecycleHook(Hooks.AfterViewInit, DirectiveNoHooks)).toBe(false); }); + it('should be false otherwise', () => { + expect(hasLifecycleHook(Hooks.AfterViewInit, DirectiveNoHooks)).toBe(false); + }); }); describe('ngAfterViewChecked', () => { diff --git a/packages/compiler/test/directive_normalizer_spec.ts b/packages/compiler/test/directive_normalizer_spec.ts index 34bd29d809fc6..4e2c64cc20465 100644 --- a/packages/compiler/test/directive_normalizer_spec.ts +++ b/packages/compiler/test/directive_normalizer_spec.ts @@ -10,7 +10,7 @@ import {CompilerConfig, preserveWhitespacesDefault} from '@angular/compiler/src/ import {DirectiveNormalizer} from '@angular/compiler/src/directive_normalizer'; import {ResourceLoader} from '@angular/compiler/src/resource_loader'; import {ViewEncapsulation} from '@angular/core/src/metadata/view'; -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from '@angular/core/testing'; import {noUndefined} from '../src/util'; @@ -20,7 +20,10 @@ const SOME_MODULE_URL = 'package:some/module/a.js'; const SOME_HTTP_MODULE_URL = 'http://some/module/a.js'; function normalizeTemplate(normalizer: DirectiveNormalizer, o: { - moduleUrl?: string; template?: string | null; templateUrl?: string | null; styles?: string[]; + moduleUrl?: string; + template?: string | null; + templateUrl?: string | null; + styles?: string[]; styleUrls?: string[]; interpolation?: [string, string] | null; encapsulation?: ViewEncapsulation | null; @@ -51,8 +54,7 @@ function normalizeTemplate(normalizer: DirectiveNormalizer, o: { jasmine.createSpy('get').and.callFake((url: string) => `resource(${url})`); const resourceLoader = {get: resourceLoaderSpy}; TestBed.configureCompiler({ - providers: - [...TEST_COMPILER_PROVIDERS, {provide: ResourceLoader, useValue: resourceLoader}] + providers: [...TEST_COMPILER_PROVIDERS, {provide: ResourceLoader, useValue: resourceLoader}] }); }); @@ -64,12 +66,12 @@ function normalizeTemplate(normalizer: DirectiveNormalizer, o: { })); it('should throw if template is not a string', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - expect(() => normalizeTemplate(normalizer, {template: <any>{}})) + expect(() => normalizeTemplate(normalizer, {template: <any> {}})) .toThrowError('The template specified for component SomeComp is not a string'); })); it('should throw if templateUrl is not a string', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - expect(() => normalizeTemplate(normalizer, {templateUrl: <any>{}})) + expect(() => normalizeTemplate(normalizer, {templateUrl: <any> {}})) .toThrowError('The templateUrl specified for component SomeComp is not a string'); })); it('should throw if both template and templateUrl are defined', @@ -89,11 +91,9 @@ function normalizeTemplate(normalizer: DirectiveNormalizer, o: { .toThrowError( 'The preserveWhitespaces option for component SomeComp must be a boolean'); })); - }); describe('inline template', () => { - it('should store the template', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { const template = <CompileTemplateMetadata>normalizeTemplate(normalizer, { @@ -174,7 +174,6 @@ function normalizeTemplate(normalizer: DirectiveNormalizer, o: { })); describe('externalStylesheets', () => { - it('should load an external stylesheet', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { const template = <CompileTemplateMetadata>normalizeTemplate( @@ -222,7 +221,6 @@ function normalizeTemplate(normalizer: DirectiveNormalizer, o: { expect(resourceLoaderSpy).toHaveBeenCalledTimes(1); })); - }); describe('normalizeLoadedTemplate', () => { diff --git a/packages/compiler/test/directive_resolver_mock_spec.ts b/packages/compiler/test/directive_resolver_mock_spec.ts index dc1a82cff98cd..c81dff025a877 100644 --- a/packages/compiler/test/directive_resolver_mock_spec.ts +++ b/packages/compiler/test/directive_resolver_mock_spec.ts @@ -7,7 +7,7 @@ */ import {Component, Directive, Injector} from '@angular/core'; -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from '@angular/core/testing'; import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector'; import {MockDirectiveResolver} from '../testing'; diff --git a/packages/compiler/test/directive_resolver_spec.ts b/packages/compiler/test/directive_resolver_spec.ts index 4d211643f97dd..c0cf0fa394136 100644 --- a/packages/compiler/test/directive_resolver_spec.ts +++ b/packages/compiler/test/directive_resolver_spec.ts @@ -32,13 +32,16 @@ class SomeDirectiveWithOutputs { @Directive({selector: 'someDirective'}) class SomeDirectiveWithSetterProps { @Input('renamed') - set a(value: any) {} + set a(value: any) { + } } @Directive({selector: 'someDirective'}) class SomeDirectiveWithGetterOutputs { @Output('renamed') - get a(): any { return null; } + get a(): any { + return null; + } } @Directive({selector: 'someDirective', host: {'[c]': 'c'}}) @@ -51,9 +54,11 @@ class SomeDirectiveWithHostBindings { @Directive({selector: 'someDirective', host: {'(c)': 'onC()'}}) class SomeDirectiveWithHostListeners { @HostListener('a') - onA() {} + onA() { + } @HostListener('b', ['$event.value']) - onB(value: any) {} + onB(value: any) { + } } @Directive({selector: 'someDirective', queries: {'cs': new ContentChildren('c')}}) @@ -101,13 +106,15 @@ class SomeDirectiveWithSameHostBindingAndInput { @Directive({selector: 'someDirective'}) class SomeDirectiveWithMalformedHostBinding1 { @HostBinding('(a)') - onA() {} + onA() { + } } @Directive({selector: 'someDirective'}) class SomeDirectiveWithMalformedHostBinding2 { @HostBinding('[a]') - onA() {} + onA() { + } } class SomeDirectiveWithoutMetadata {} @@ -116,7 +123,9 @@ class SomeDirectiveWithoutMetadata {} describe('DirectiveResolver', () => { let resolver: DirectiveResolver; - beforeEach(() => { resolver = new DirectiveResolver(new JitReflector()); }); + beforeEach(() => { + resolver = new DirectiveResolver(new JitReflector()); + }); it('should read out the Directive metadata', () => { const directiveMetadata = resolver.resolve(SomeDirective); @@ -204,8 +213,7 @@ class SomeDirectiveWithoutMetadata {} it('should prefer @Input over @Directive.inputs', () => { @Directive({selector: 'someDirective', inputs: ['a']}) class SomeDirectiveWithDuplicateInputs { - @Input('a') - propA: any; + @Input('a') propA: any; } const directiveMetadata = resolver.resolve(SomeDirectiveWithDuplicateInputs); expect(directiveMetadata.inputs).toEqual(['propA: a']); @@ -214,17 +222,13 @@ class SomeDirectiveWithoutMetadata {} it('should support inheriting inputs', () => { @Directive({selector: 'p'}) class Parent { - @Input() - p1: any; - @Input('p21') - p2: any; + @Input() p1: any; + @Input('p21') p2: any; } class Child extends Parent { - @Input('p22') - p2: any; - @Input() - p3: any; + @Input('p22') p2: any; + @Input() p3: any; } const directiveMetadata = resolver.resolve(Child); @@ -264,8 +268,7 @@ class SomeDirectiveWithoutMetadata {} it('should prefer @Output over @Directive.outputs', () => { @Directive({selector: 'someDirective', outputs: ['a']}) class SomeDirectiveWithDuplicateOutputs { - @Output('a') - propA: any; + @Output('a') propA: any; } const directiveMetadata = resolver.resolve(SomeDirectiveWithDuplicateOutputs); expect(directiveMetadata.outputs).toEqual(['propA: a']); @@ -274,17 +277,13 @@ class SomeDirectiveWithoutMetadata {} it('should support inheriting outputs', () => { @Directive({selector: 'p'}) class Parent { - @Output() - p1: any; - @Output('p21') - p2: any; + @Output() p1: any; + @Output('p21') p2: any; } class Child extends Parent { - @Output('p22') - p2: any; - @Output() - p3: any; + @Output('p22') p2: any; + @Output() p3: any; } const directiveMetadata = resolver.resolve(Child); @@ -324,17 +323,13 @@ class SomeDirectiveWithoutMetadata {} it('should support inheriting host bindings', () => { @Directive({selector: 'p'}) class Parent { - @HostBinding() - p1: any; - @HostBinding('p21') - p2: any; + @HostBinding() p1: any; + @HostBinding('p21') p2: any; } class Child extends Parent { - @HostBinding('p22') - p2: any; - @HostBinding() - p3: any; + @HostBinding('p22') p2: any; + @HostBinding() p3: any; } const directiveMetadata = resolver.resolve(Child); @@ -346,16 +341,20 @@ class SomeDirectiveWithoutMetadata {} @Directive({selector: 'p'}) class Parent { @HostListener('p1') - p1() {} + p1() { + } @HostListener('p21') - p2() {} + p2() { + } } class Child extends Parent { @HostListener('p22') - p2() {} + p2() { + } @HostListener('p3') - p3() {} + p3() { + } } const directiveMetadata = resolver.resolve(Child); @@ -366,19 +365,20 @@ class SomeDirectiveWithoutMetadata {} it('should combine host bindings and listeners during inheritance', () => { @Directive({selector: 'p'}) class Parent { - @HostListener('p11') @HostListener('p12') - p1() {} + @HostListener('p11') + @HostListener('p12') + p1() { + } - @HostBinding('p21') @HostBinding('p22') - p2: any; + @HostBinding('p21') @HostBinding('p22') p2: any; } class Child extends Parent { @HostListener('c1') - p1() {} + p1() { + } - @HostBinding('c2') - p2: any; + @HostBinding('c2') p2: any; } const directiveMetadata = resolver.resolve(Child); @@ -421,17 +421,13 @@ class SomeDirectiveWithoutMetadata {} it('should support inheriting queries', () => { @Directive({selector: 'p'}) class Parent { - @ContentChild('p1') - p1: any; - @ContentChild('p21') - p2: any; + @ContentChild('p1') p1: any; + @ContentChild('p21') p2: any; } class Child extends Parent { - @ContentChild('p22') - p2: any; - @ContentChild('p3') - p3: any; + @ContentChild('p22') p2: any; + @ContentChild('p3') p3: any; } const directiveMetadata = resolver.resolve(Child); diff --git a/packages/compiler/test/expression_parser/lexer_spec.ts b/packages/compiler/test/expression_parser/lexer_spec.ts index 3fda05b0a4263..d09d261cf766c 100644 --- a/packages/compiler/test/expression_parser/lexer_spec.ts +++ b/packages/compiler/test/expression_parser/lexer_spec.ts @@ -101,14 +101,17 @@ function expectErrorToken(token: Token, index: any, end: number, message: string expectNumberToken(tokens[0], 0, 2, 88); }); - it('should tokenize numbers within index ops', - () => { expectNumberToken(lex('a[22]')[2], 2, 4, 22); }); + it('should tokenize numbers within index ops', () => { + expectNumberToken(lex('a[22]')[2], 2, 4, 22); + }); - it('should tokenize simple quoted strings', - () => { expectStringToken(lex('"a"')[0], 0, 3, 'a'); }); + it('should tokenize simple quoted strings', () => { + expectStringToken(lex('"a"')[0], 0, 3, 'a'); + }); - it('should tokenize quoted strings with escaped quotes', - () => { expectStringToken(lex('"a\\""')[0], 0, 5, 'a"'); }); + it('should tokenize quoted strings with escaped quotes', () => { + expectStringToken(lex('"a\\""')[0], 0, 5, 'a"'); + }); it('should tokenize a string', () => { const tokens: Token[] = lex('j-a.bc[22]+1.3|f:\'a\\\'c\':"d\\"e"'); @@ -213,7 +216,9 @@ function expectErrorToken(token: Token, index: any, end: number, message: string expectCharacterToken(tokens[13], 16, 17, ')'); }); - it('should tokenize number', () => { expectNumberToken(lex('0.5')[0], 0, 3, 0.5); }); + it('should tokenize number', () => { + expectNumberToken(lex('0.5')[0], 0, 3, 0.5); + }); it('should tokenize number with exponent', () => { let tokens: Token[] = lex('0.5E-10'); @@ -233,8 +238,9 @@ function expectErrorToken(token: Token, index: any, end: number, message: string 'Lexer Error: Invalid exponent at column 4 in expression [0.5E-A]'); }); - it('should tokenize number starting with a dot', - () => { expectNumberToken(lex('.5')[0], 0, 2, 0.5); }); + it('should tokenize number starting with a dot', () => { + expectNumberToken(lex('.5')[0], 0, 2, 0.5); + }); it('should throw error on invalid unicode', () => { expectErrorToken( @@ -242,11 +248,13 @@ function expectErrorToken(token: Token, index: any, end: number, message: string 'Lexer Error: Invalid unicode escape [\\u1\'\'b] at column 2 in expression [\'\\u1\'\'bla\']'); }); - it('should tokenize hash as operator', - () => { expectOperatorToken(lex('#')[0], 0, 1, '#'); }); + it('should tokenize hash as operator', () => { + expectOperatorToken(lex('#')[0], 0, 1, '#'); + }); - it('should tokenize ?. as operator', - () => { expectOperatorToken(lex('?.')[0], 0, 2, '?.'); }); + it('should tokenize ?. as operator', () => { + expectOperatorToken(lex('?.')[0], 0, 2, '?.'); + }); }); }); } diff --git a/packages/compiler/test/expression_parser/parser_spec.ts b/packages/compiler/test/expression_parser/parser_spec.ts index 69fb2a358c19c..f25aab0e40588 100644 --- a/packages/compiler/test/expression_parser/parser_spec.ts +++ b/packages/compiler/test/expression_parser/parser_spec.ts @@ -17,16 +17,22 @@ import {validate} from './utils/validator'; describe('parser', () => { describe('parseAction', () => { - it('should parse numbers', () => { checkAction('1'); }); + it('should parse numbers', () => { + checkAction('1'); + }); it('should parse strings', () => { checkAction('\'1\'', '"1"'); checkAction('"1"'); }); - it('should parse null', () => { checkAction('null'); }); + it('should parse null', () => { + checkAction('null'); + }); - it('should parse undefined', () => { checkAction('undefined'); }); + it('should parse undefined', () => { + checkAction('undefined'); + }); it('should parse unary - expressions', () => { checkAction('-1', '0 - 1'); @@ -47,10 +53,13 @@ describe('parser', () => { checkAction('a!!!!.b'); }); - it('should parse multiplicative expressions', - () => { checkAction('3*4/2%5', '3 * 4 / 2 % 5'); }); + it('should parse multiplicative expressions', () => { + checkAction('3*4/2%5', '3 * 4 / 2 % 5'); + }); - it('should parse additive expressions', () => { checkAction('3 + 6 - 2'); }); + it('should parse additive expressions', () => { + checkAction('3 + 6 - 2'); + }); it('should parse relational expressions', () => { checkAction('2 < 3'); @@ -74,14 +83,21 @@ describe('parser', () => { checkAction('true || false'); }); - it('should parse grouped expressions', () => { checkAction('(1 + 2) * 3', '1 + 2 * 3'); }); + it('should parse grouped expressions', () => { + checkAction('(1 + 2) * 3', '1 + 2 * 3'); + }); - it('should ignore comments in expressions', () => { checkAction('a //comment', 'a'); }); + it('should ignore comments in expressions', () => { + checkAction('a //comment', 'a'); + }); - it('should retain // in string literals', - () => { checkAction(`"http://www.google.com"`, `"http://www.google.com"`); }); + it('should retain // in string literals', () => { + checkAction(`"http://www.google.com"`, `"http://www.google.com"`); + }); - it('should parse an empty string', () => { checkAction(''); }); + it('should parse an empty string', () => { + checkAction(''); + }); describe('literals', () => { it('should parse array', () => { @@ -133,7 +149,9 @@ describe('parser', () => { }); describe('functional calls', () => { - it('should parse function calls', () => { checkAction('fn()(1, 2)'); }); + it('should parse function calls', () => { + checkAction('fn()(1, 2)'); + }); }); describe('conditional', () => { @@ -154,20 +172,26 @@ describe('parser', () => { checkAction('a = 123; b = 234;'); }); - it('should report on safe field assignments', - () => { expectActionError('a?.a = 123', 'cannot be used in the assignment'); }); + it('should report on safe field assignments', () => { + expectActionError('a?.a = 123', 'cannot be used in the assignment'); + }); - it('should support array updates', () => { checkAction('a[0] = 200'); }); + it('should support array updates', () => { + checkAction('a[0] = 200'); + }); }); - it('should error when using pipes', - () => { expectActionError('x|blah', 'Cannot have a pipe'); }); + it('should error when using pipes', () => { + expectActionError('x|blah', 'Cannot have a pipe'); + }); - it('should store the source in the result', - () => { expect(parseAction('someExpr', 'someExpr')); }); + it('should store the source in the result', () => { + expect(parseAction('someExpr', 'someExpr')); + }); - it('should store the passed-in location', - () => { expect(parseAction('someExpr', 'location').location).toBe('location'); }); + it('should store the passed-in location', () => { + expect(parseAction('someExpr', 'location').location).toBe('location'); + }); it('should report when encountering interpolation', () => { expectActionError('{{a()}}', 'Got interpolation ({{}}) where expression was expected'); @@ -175,11 +199,13 @@ describe('parser', () => { }); describe('general error handling', () => { - it('should report an unexpected token', - () => { expectActionError('[1,2] trac', 'Unexpected token \'trac\''); }); + it('should report an unexpected token', () => { + expectActionError('[1,2] trac', 'Unexpected token \'trac\''); + }); - it('should report reasonable error for unconsumed tokens', - () => { expectActionError(')', 'Unexpected token ) at column 1 in [)]'); }); + it('should report reasonable error for unconsumed tokens', () => { + expectActionError(')', 'Unexpected token ) at column 1 in [)]'); + }); it('should report a missing expected token', () => { expectActionError('a(b', 'Missing expected ) at the end of the expression [a(b]'); @@ -206,12 +232,17 @@ describe('parser', () => { expectBindingError('"Foo"|"uppercase"', 'identifier or keyword'); }); - it('should parse quoted expressions', () => { checkBinding('a:b', 'a:b'); }); + it('should parse quoted expressions', () => { + checkBinding('a:b', 'a:b'); + }); - it('should not crash when prefix part is not tokenizable', - () => { checkBinding('"a:b"', '"a:b"'); }); + it('should not crash when prefix part is not tokenizable', () => { + checkBinding('"a:b"', '"a:b"'); + }); - it('should ignore whitespace around quote prefix', () => { checkBinding(' a :b', 'a:b'); }); + it('should ignore whitespace around quote prefix', () => { + checkBinding(' a :b', 'a:b'); + }); it('should refuse prefixes that are not single identifiers', () => { expectBindingError('a + b:c', ''); @@ -219,31 +250,41 @@ describe('parser', () => { }); }); - it('should store the source in the result', - () => { expect(parseBinding('someExpr').source).toBe('someExpr'); }); + it('should store the source in the result', () => { + expect(parseBinding('someExpr').source).toBe('someExpr'); + }); - it('should store the passed-in location', - () => { expect(parseBinding('someExpr', 'location').location).toBe('location'); }); + it('should store the passed-in location', () => { + expect(parseBinding('someExpr', 'location').location).toBe('location'); + }); - it('should report chain expressions', - () => { expectError(parseBinding('1;2'), 'contain chained expression'); }); + it('should report chain expressions', () => { + expectError(parseBinding('1;2'), 'contain chained expression'); + }); - it('should report assignment', - () => { expectError(parseBinding('a=2'), 'contain assignments'); }); + it('should report assignment', () => { + expectError(parseBinding('a=2'), 'contain assignments'); + }); it('should report when encountering interpolation', () => { expectBindingError('{{a.b}}', 'Got interpolation ({{}}) where expression was expected'); }); - it('should parse conditional expression', () => { checkBinding('a < b ? a : b'); }); - - it('should ignore comments in bindings', () => { checkBinding('a //comment', 'a'); }); + it('should parse conditional expression', () => { + checkBinding('a < b ? a : b'); + }); - it('should retain // in string literals', - () => { checkBinding(`"http://www.google.com"`, `"http://www.google.com"`); }); + it('should ignore comments in bindings', () => { + checkBinding('a //comment', 'a'); + }); - it('should retain // in : microsyntax', () => { checkBinding('one:a//b', 'one:a//b'); }); + it('should retain // in string literals', () => { + checkBinding(`"http://www.google.com"`, `"http://www.google.com"`); + }); + it('should retain // in : microsyntax', () => { + checkBinding('one:a//b', 'one:a//b'); + }); }); describe('parseTemplateBindings', () => { @@ -555,11 +596,12 @@ describe('parser', () => { }); describe('parseInterpolation', () => { - it('should return null if no interpolation', - () => { expect(parseInterpolation('nothing')).toBe(null); }); + it('should return null if no interpolation', () => { + expect(parseInterpolation('nothing')).toBe(null); + }); it('should parse no prefix/suffix interpolation', () => { - const ast = parseInterpolation('{{a}}') !.ast as Interpolation; + const ast = parseInterpolation('{{a}}')!.ast as Interpolation; expect(ast.strings).toEqual(['', '']); expect(ast.expressions.length).toEqual(1); expect(ast.expressions[0].name).toEqual('a'); @@ -567,22 +609,23 @@ describe('parser', () => { it('should parse prefix/suffix with multiple interpolation', () => { const originalExp = 'before {{ a }} middle {{ b }} after'; - const ast = parseInterpolation(originalExp) !.ast; + const ast = parseInterpolation(originalExp)!.ast; expect(unparse(ast)).toEqual(originalExp); validate(ast); }); it('should report empty interpolation expressions', () => { expectError( - parseInterpolation('{{}}') !, - 'Blank expressions are not allowed in interpolated strings'); + parseInterpolation('{{}}')!, 'Blank expressions are not allowed in interpolated strings'); expectError( - parseInterpolation('foo {{ }}') !, + parseInterpolation('foo {{ }}')!, 'Parser Error: Blank expressions are not allowed in interpolated strings'); }); - it('should parse conditional expression', () => { checkInterpolation('{{ a < b ? a : b }}'); }); + it('should parse conditional expression', () => { + checkInterpolation('{{ a < b ? a : b }}'); + }); it('should parse expression with newline characters', () => { checkInterpolation(`{{ 'foo' +\n 'bar' +\r 'baz' }}`, `{{ "foo" + "bar" + "baz" }}`); @@ -591,15 +634,16 @@ describe('parser', () => { it('should support custom interpolation', () => { const parser = new Parser(new Lexer()); const ast = - parser.parseInterpolation('{% a %}', null, 0, {start: '{%', end: '%}'}) !.ast as any; + parser.parseInterpolation('{% a %}', null, 0, {start: '{%', end: '%}'})!.ast as any; expect(ast.strings).toEqual(['', '']); expect(ast.expressions.length).toEqual(1); expect(ast.expressions[0].name).toEqual('a'); }); describe('comments', () => { - it('should ignore comments in interpolation expressions', - () => { checkInterpolation('{{a //comment}}', '{{ a }}'); }); + it('should ignore comments in interpolation expressions', () => { + checkInterpolation('{{a //comment}}', '{{ a }}'); + }); it('should retain // in single quote strings', () => { checkInterpolation(`{{ 'http://www.google.com' }}`, `{{ "http://www.google.com" }}`); @@ -609,18 +653,19 @@ describe('parser', () => { checkInterpolation(`{{ "http://www.google.com" }}`, `{{ "http://www.google.com" }}`); }); - it('should ignore comments after string literals', - () => { checkInterpolation(`{{ "a//b" //comment }}`, `{{ "a//b" }}`); }); + it('should ignore comments after string literals', () => { + checkInterpolation(`{{ "a//b" //comment }}`, `{{ "a//b" }}`); + }); it('should retain // in complex strings', () => { checkInterpolation( `{{"//a\'//b\`//c\`//d\'//e" //comment}}`, `{{ "//a\'//b\`//c\`//d\'//e" }}`); }); - it('should retain // in nested, unterminated strings', - () => { checkInterpolation(`{{ "a\'b\`" //comment}}`, `{{ "a\'b\`" }}`); }); + it('should retain // in nested, unterminated strings', () => { + checkInterpolation(`{{ "a\'b\`" //comment}}`, `{{ "a\'b\`" }}`); + }); }); - }); describe('parseSimpleBinding', () => { @@ -670,12 +715,12 @@ describe('parser', () => { describe('offsets', () => { it('should retain the offsets of an interpolation', () => { - const interpolations = splitInterpolation('{{a}} {{b}} {{c}}') !; + const interpolations = splitInterpolation('{{a}} {{b}} {{c}}')!; expect(interpolations.offsets).toEqual([2, 9, 16]); }); it('should retain the offsets into the expression AST of interpolations', () => { - const source = parseInterpolation('{{a}} {{b}} {{c}}') !; + const source = parseInterpolation('{{a}} {{b}} {{c}}')!; const interpolation = source.ast as Interpolation; expect(interpolation.expressions.map(e => e.span.start)).toEqual([2, 9, 16]); }); @@ -722,7 +767,7 @@ function parseSimpleBinding(text: string, location: any = null, offset: number = } function checkInterpolation(exp: string, expected?: string) { - const ast = parseInterpolation(exp) !; + const ast = parseInterpolation(exp)!; if (expected == null) expected = exp; expect(unparse(ast)).toEqual(expected); validate(ast); diff --git a/packages/compiler/test/expression_parser/utils/unparser.ts b/packages/compiler/test/expression_parser/utils/unparser.ts index e5ea2f9f89ba1..fd2574e388848 100644 --- a/packages/compiler/test/expression_parser/utils/unparser.ts +++ b/packages/compiler/test/expression_parser/utils/unparser.ts @@ -12,9 +12,9 @@ import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../src/ml class Unparser implements AstVisitor { private static _quoteRegExp = /"/g; // TODO(issue/24571): remove '!'. - private _expression !: string; + private _expression!: string; // TODO(issue/24571): remove '!'. - private _interpolationConfig !: InterpolationConfig; + private _interpolationConfig!: InterpolationConfig; unparse(ast: AST, interpolationConfig: InterpolationConfig) { this._expression = ''; @@ -69,7 +69,7 @@ class Unparser implements AstVisitor { } visitFunctionCall(ast: FunctionCall, context: any) { - this._visit(ast.target !); + this._visit(ast.target!); this._expression += '('; let isFirst = true; ast.args.forEach(arg => { @@ -137,7 +137,7 @@ class Unparser implements AstVisitor { visitLiteralPrimitive(ast: LiteralPrimitive, context: any) { if (typeof ast.value === 'string') { - this._expression += `"${ast.value.replace( Unparser._quoteRegExp, '\"')}"`; + this._expression += `"${ast.value.replace(Unparser._quoteRegExp, '\"')}"`; } else { this._expression += `${ast.value}`; } @@ -186,7 +186,9 @@ class Unparser implements AstVisitor { this._expression += `${ast.prefix}:${ast.uninterpretedExpression}`; } - private _visit(ast: AST) { ast.visit(this); } + private _visit(ast: AST) { + ast.visit(this); + } } const sharedUnparser = new Unparser(); diff --git a/packages/compiler/test/expression_parser/utils/validator.ts b/packages/compiler/test/expression_parser/utils/validator.ts index cfdc851da5721..2ddbbcd9c080d 100644 --- a/packages/compiler/test/expression_parser/utils/validator.ts +++ b/packages/compiler/test/expression_parser/utils/validator.ts @@ -22,8 +22,8 @@ class ASTValidator extends RecursiveAstVisitor { if (!inSpan(ast.span, this.parentSpan)) { if (this.parentSpan) { const parentSpan = this.parentSpan as ParseSpan; - throw Error( - `Invalid AST span [expected (${ast.span.start}, ${ast.span.end}) to be in (${parentSpan.start}, ${parentSpan.end}) for ${unparse(ast)}`); + throw Error(`Invalid AST span [expected (${ast.span.start}, ${ast.span.end}) to be in (${ + parentSpan.start}, ${parentSpan.end}) for ${unparse(ast)}`); } else { throw Error(`Invalid root AST span for ${unparse(ast)}`); } @@ -111,7 +111,7 @@ class ASTValidator extends RecursiveAstVisitor { } } -function inSpan(span: ParseSpan, parentSpan: ParseSpan | undefined): parentSpan is ParseSpan { +function inSpan(span: ParseSpan, parentSpan: ParseSpan|undefined): parentSpan is ParseSpan { return !parentSpan || (span.start >= parentSpan.start && span.end <= parentSpan.end); } diff --git a/packages/compiler/test/i18n/digest_spec.ts b/packages/compiler/test/i18n/digest_spec.ts index e77e49735f3a5..b37988d8ba024 100644 --- a/packages/compiler/test/i18n/digest_spec.ts +++ b/packages/compiler/test/i18n/digest_spec.ts @@ -27,14 +27,17 @@ import {computeMsgId, digest, sha1} from '../../src/i18n/digest'; }); describe('sha1', () => { - it('should work on empty strings', - () => { expect(sha1('')).toEqual('da39a3ee5e6b4b0d3255bfef95601890afd80709'); }); + it('should work on empty strings', () => { + expect(sha1('')).toEqual('da39a3ee5e6b4b0d3255bfef95601890afd80709'); + }); - it('should returns the sha1 of "hello world"', - () => { expect(sha1('abc')).toEqual('a9993e364706816aba3e25717850c26c9cd0d89d'); }); + it('should returns the sha1 of "hello world"', () => { + expect(sha1('abc')).toEqual('a9993e364706816aba3e25717850c26c9cd0d89d'); + }); - it('should returns the sha1 of unicode strings', - () => { expect(sha1('你好,世界')).toEqual('3becb03b015ed48050611c8d7afe4b88f70d5a20'); }); + it('should returns the sha1 of unicode strings', () => { + expect(sha1('你好,世界')).toEqual('3becb03b015ed48050611c8d7afe4b88f70d5a20'); + }); it('should support arbitrary string size', () => { // node.js reference code: @@ -89,8 +92,9 @@ import {computeMsgId, digest, sha1} from '../../src/i18n/digest'; '': '4416290763660062288', }; - Object.keys(fixtures).forEach( - msg => { expect(computeMsgId(msg, '')).toEqual(fixtures[msg]); }); + Object.keys(fixtures).forEach(msg => { + expect(computeMsgId(msg, '')).toEqual(fixtures[msg]); + }); }); it('should work on well known inputs with meaning', () => { @@ -100,8 +104,9 @@ import {computeMsgId, digest, sha1} from '../../src/i18n/digest'; '3993998469942805487': ['View', 'Gmail UI'], }; - Object.keys(fixtures).forEach( - id => { expect(computeMsgId(fixtures[id][0], fixtures[id][1])).toEqual(id); }); + Object.keys(fixtures).forEach(id => { + expect(computeMsgId(fixtures[id][0], fixtures[id][1])).toEqual(id); + }); }); it('should support arbitrary string size', () => { @@ -116,7 +121,6 @@ import {computeMsgId, digest, sha1} from '../../src/i18n/digest'; } expect(computeMsgId(result, '')).toEqual('2122606631351252558'); }); - }); }); } diff --git a/packages/compiler/test/i18n/extractor_merger_spec.ts b/packages/compiler/test/i18n/extractor_merger_spec.ts index 52eec7c548a25..7ad468fb1ac25 100644 --- a/packages/compiler/test/i18n/extractor_merger_spec.ts +++ b/packages/compiler/test/i18n/extractor_merger_spec.ts @@ -94,8 +94,9 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; ]); }); - it('should not create a message for empty elements', - () => { expect(extract('<div i18n="m|d"></div>')).toEqual([]); }); + it('should not create a message for empty elements', () => { + expect(extract('<div i18n="m|d"></div>')).toEqual([]); + }); it('should ignore implicit elements in translatable elements', () => { expect(extract('<div i18n="m|d"><p></p></div>', ['p'])).toEqual([ @@ -138,7 +139,8 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; ], [ [ - 'text', '<ph tag name="START_PARAGRAPH">html, <ph tag' + + 'text', + '<ph tag name="START_PARAGRAPH">html, <ph tag' + ' name="START_BOLD_TEXT">nested</ph name="CLOSE_BOLD_TEXT"></ph name="CLOSE_PARAGRAPH">', '<ph icu name="ICU">{count, plural, =0 {[<ph tag' + ' name="START_TAG_SPAN">html</ph name="CLOSE_TAG_SPAN">]}}</ph>', @@ -156,8 +158,9 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; ]); }); - it('should not create a message for empty blocks', - () => { expect(extract(`<!-- i18n: meaning1|desc1 --><!-- /i18n -->`)).toEqual([]); }); + it('should not create a message for empty blocks', () => { + expect(extract(`<!-- i18n: meaning1|desc1 --><!-- /i18n -->`)).toEqual([]); + }); }); describe('ICU messages', () => { @@ -199,8 +202,9 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; ]); }); - it('should not extract ICU messages outside of i18n sections', - () => { expect(extract('{count, plural, =0 {text}}')).toEqual([]); }); + it('should not extract ICU messages outside of i18n sections', () => { + expect(extract('{count, plural, =0 {text}}')).toEqual([]); + }); it('should ignore nested ICU messages', () => { expect(extract('<div i18n="m|d">{count, plural, =0 { {sex, select, male {m}} }}</div>')) @@ -280,8 +284,9 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; ]); }); - it('should not create a message for empty attributes', - () => { expect(extract('<div i18n-title="m|d" title></div>')).toEqual([]); }); + it('should not create a message for empty attributes', () => { + expect(extract('<div i18n-title="m|d" title></div>')).toEqual([]); + }); }); describe('implicit elements', () => { @@ -292,7 +297,7 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; }); it('should allow nested implicit elements', () => { - let result: any[] = undefined !; + let result: any[] = undefined!; expect(() => { result = extract('<div>outer<div>inner</div></div>', ['div']); @@ -302,7 +307,6 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; [['outer', '<ph tag name="START_TAG_DIV">inner</ph name="CLOSE_TAG_DIV">'], '', '', ''], ]); }); - }); describe('implicit attributes', () => { @@ -341,7 +345,6 @@ import {serializeNodes as serializeHtmlNodes} from '../ml_parser/util/util'; ['Could not start a block inside a translatable section', '<!--'], ['Trying to close an unopened block', '<!--'], ]); - }); it('should report unclosed blocks', () => { @@ -527,7 +530,7 @@ function fakeTranslate( messages.forEach(message => { const id = digest(message); const text = serializeI18nNodes(message.nodes).join('').replace(/</g, '['); - i18nMsgMap[id] = [new i18n.Text(`**${text}**`, null !)]; + i18nMsgMap[id] = [new i18n.Text(`**${text}**`, null!)]; }); const translationBundle = new TranslationBundle(i18nMsgMap, null, digest); diff --git a/packages/compiler/test/i18n/i18n_html_parser_spec.ts b/packages/compiler/test/i18n/i18n_html_parser_spec.ts index e4edccc85bcb9..a5e0b74223caa 100644 --- a/packages/compiler/test/i18n/i18n_html_parser_spec.ts +++ b/packages/compiler/test/i18n/i18n_html_parser_spec.ts @@ -26,6 +26,5 @@ import {ParseTreeResult} from '@angular/compiler/src/ml_parser/parser'; i18nHtmlParser.parse('source', 'url'); expect(TranslationBundle.load).toHaveBeenCalledTimes(1); }); - }); } diff --git a/packages/compiler/test/i18n/i18n_parser_spec.ts b/packages/compiler/test/i18n/i18n_parser_spec.ts index cc8c9dd3afb3c..7c4c75daf9da9 100644 --- a/packages/compiler/test/i18n/i18n_parser_spec.ts +++ b/packages/compiler/test/i18n/i18n_parser_spec.ts @@ -14,7 +14,6 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/inte { describe('I18nParser', () => { - describe('elements', () => { it('should extract from elements', () => { expect(_humanizeMessages('<div i18n="m|d">text</div>')).toEqual([ @@ -34,11 +33,13 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/inte ]); }); - it('should not create a message for empty elements', - () => { expect(_humanizeMessages('<div i18n="m|d"></div>')).toEqual([]); }); + it('should not create a message for empty elements', () => { + expect(_humanizeMessages('<div i18n="m|d"></div>')).toEqual([]); + }); - it('should not create a message for plain elements', - () => { expect(_humanizeMessages('<div></div>')).toEqual([]); }); + it('should not create a message for plain elements', () => { + expect(_humanizeMessages('<div></div>')).toEqual([]); + }); it('should support void elements', () => { expect(_humanizeMessages('<div i18n="m|d"><p><br></p></div>')).toEqual([ @@ -115,8 +116,9 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/inte ]); }); - it('should not create a message for empty attributes', - () => { expect(_humanizeMessages('<div i18n-title="m|d" title></div>')).toEqual([]); }); + it('should not create a message for empty attributes', () => { + expect(_humanizeMessages('<div i18n-title="m|d" title></div>')).toEqual([]); + }); }); describe('interpolation', () => { @@ -252,7 +254,6 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/inte expect(_humanizePlaceholders(html)).toEqual([ 'START_PARAGRAPH=<p>, CLOSE_PARAGRAPH=</p>, START_PARAGRAPH_1=<p other>', ]); - }); it('should reuse the same placeholder name for interpolations', () => { @@ -302,7 +303,6 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/inte '', '', ]); - }); }); }); diff --git a/packages/compiler/test/i18n/integration_common.ts b/packages/compiler/test/i18n/integration_common.ts index 2b59094aae5f8..65d6e6fb0834b 100644 --- a/packages/compiler/test/i18n/integration_common.ts +++ b/packages/compiler/test/i18n/integration_common.ts @@ -20,11 +20,11 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }) export class I18nComponent { // TODO(issue/24571): remove '!'. - count !: number; + count!: number; // TODO(issue/24571): remove '!'. - sex !: string; + sex!: string; // TODO(issue/24571): remove '!'. - sexB !: string; + sexB!: string; response: any = {getItemsList: (): any[] => []}; } diff --git a/packages/compiler/test/i18n/integration_xliff2_spec.ts b/packages/compiler/test/i18n/integration_xliff2_spec.ts index e7f82d09ccd6d..5feeca415cd56 100644 --- a/packages/compiler/test/i18n/integration_xliff2_spec.ts +++ b/packages/compiler/test/i18n/integration_xliff2_spec.ts @@ -13,7 +13,7 @@ import {Xliff2} from '@angular/compiler/src/i18n/serializers/xliff2'; import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser'; import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config'; import {DebugElement, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {SpyResourceLoader} from '../spies'; @@ -22,7 +22,6 @@ import {FrLocalization, HTML, I18nComponent, validateHtml} from './integration_c { describe('i18n XLIFF 2.0 integration spec', () => { - beforeEach(async(() => { TestBed.configureCompiler({ providers: [ diff --git a/packages/compiler/test/i18n/integration_xliff_spec.ts b/packages/compiler/test/i18n/integration_xliff_spec.ts index 5c8daf498440d..bbbcbd8bf6503 100644 --- a/packages/compiler/test/i18n/integration_xliff_spec.ts +++ b/packages/compiler/test/i18n/integration_xliff_spec.ts @@ -13,7 +13,7 @@ import {Xliff} from '@angular/compiler/src/i18n/serializers/xliff'; import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser'; import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config'; import {DebugElement, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {SpyResourceLoader} from '../spies'; @@ -22,7 +22,6 @@ import {FrLocalization, HTML, I18nComponent, validateHtml} from './integration_c { describe('i18n XLIFF integration spec', () => { - beforeEach(async(() => { TestBed.configureCompiler({ providers: [ diff --git a/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts b/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts index 59853bb233487..7ed6fd92fd1fb 100644 --- a/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts +++ b/packages/compiler/test/i18n/integration_xmb_xtb_spec.ts @@ -13,7 +13,7 @@ import {Xmb} from '@angular/compiler/src/i18n/serializers/xmb'; import {HtmlParser} from '@angular/compiler/src/ml_parser/html_parser'; import {DEFAULT_INTERPOLATION_CONFIG} from '@angular/compiler/src/ml_parser/interpolation_config'; import {DebugElement, TRANSLATIONS, TRANSLATIONS_FORMAT} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {SpyResourceLoader} from '../spies'; @@ -22,7 +22,6 @@ import {FrLocalization, HTML, I18nComponent, validateHtml} from './integration_c { describe('i18n XMB/XTB integration spec', () => { - beforeEach(async(() => { TestBed.configureCompiler({ providers: [ diff --git a/packages/compiler/test/i18n/message_bundle_spec.ts b/packages/compiler/test/i18n/message_bundle_spec.ts index ef9cbde561b70..c01a49fb28c42 100644 --- a/packages/compiler/test/i18n/message_bundle_spec.ts +++ b/packages/compiler/test/i18n/message_bundle_spec.ts @@ -18,7 +18,9 @@ import {DEFAULT_INTERPOLATION_CONFIG} from '../../src/ml_parser/interpolation_co describe('Messages', () => { let messages: MessageBundle; - beforeEach(() => { messages = new MessageBundle(new HtmlParser, [], {}); }); + beforeEach(() => { + messages = new MessageBundle(new HtmlParser, [], {}); + }); it('should extract the message to the catalog', () => { messages.updateFromTemplate( @@ -48,11 +50,13 @@ class _TestSerializer extends Serializer { } load(content: string, url: string): - {locale: string | null, i18nNodesByMsgId: {[id: string]: i18n.Node[]}} { + {locale: string|null, i18nNodesByMsgId: {[id: string]: i18n.Node[]}} { return {locale: null, i18nNodesByMsgId: {}}; } - digest(msg: i18n.Message): string { return msg.id || `default`; } + digest(msg: i18n.Message): string { + return msg.id || `default`; + } } function humanizeMessages(catalog: MessageBundle): string[] { diff --git a/packages/compiler/test/i18n/serializers/i18n_ast_spec.ts b/packages/compiler/test/i18n/serializers/i18n_ast_spec.ts index 3edf6951a5000..298ca1d80b179 100644 --- a/packages/compiler/test/i18n/serializers/i18n_ast_spec.ts +++ b/packages/compiler/test/i18n/serializers/i18n_ast_spec.ts @@ -36,13 +36,13 @@ import {_extractMessages} from '../i18n_parser_spec'; const visitor = new RecurseVisitor(); const container = new i18n.Container( [ - new i18n.Text('', null !), - new i18n.Placeholder('', '', null !), - new i18n.IcuPlaceholder(null !, '', null !), + new i18n.Text('', null!), + new i18n.Placeholder('', '', null!), + new i18n.IcuPlaceholder(null!, '', null!), ], - null !); - const tag = new i18n.TagPlaceholder('', {}, '', '', [container], false, null !); - const icu = new i18n.Icu('', '', {tag}, null !); + null!); + const tag = new i18n.TagPlaceholder('', {}, '', '', [container], false, null!); + const icu = new i18n.Icu('', '', {tag}, null!); icu.visit(visitor); expect(visitor.textCount).toEqual(1); @@ -58,9 +58,15 @@ class RecurseVisitor extends i18n.RecurseVisitor { phCount = 0; icuPhCount = 0; - visitText(text: i18n.Text, context?: any): any { this.textCount++; } + visitText(text: i18n.Text, context?: any): any { + this.textCount++; + } - visitPlaceholder(ph: i18n.Placeholder, context?: any): any { this.phCount++; } + visitPlaceholder(ph: i18n.Placeholder, context?: any): any { + this.phCount++; + } - visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any { this.icuPhCount++; } + visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any { + this.icuPhCount++; + } } diff --git a/packages/compiler/test/i18n/serializers/placeholder_spec.ts b/packages/compiler/test/i18n/serializers/placeholder_spec.ts index e3aa205d176ca..5f5c823aff981 100644 --- a/packages/compiler/test/i18n/serializers/placeholder_spec.ts +++ b/packages/compiler/test/i18n/serializers/placeholder_spec.ts @@ -12,7 +12,9 @@ import {PlaceholderRegistry} from '../../../src/i18n/serializers/placeholder'; describe('PlaceholderRegistry', () => { let reg: PlaceholderRegistry; - beforeEach(() => { reg = new PlaceholderRegistry(); }); + beforeEach(() => { + reg = new PlaceholderRegistry(); + }); describe('tag placeholder', () => { it('should generate names for well known tags', () => { @@ -84,7 +86,6 @@ import {PlaceholderRegistry} from '../../../src/i18n/serializers/placeholder'; expect(reg.getPlaceholderName('name1', 'content')).toEqual('NAME1'); expect(reg.getPlaceholderName('name2', 'content')).toEqual('NAME2'); }); - }); }); } \ No newline at end of file diff --git a/packages/compiler/test/i18n/serializers/xliff2_spec.ts b/packages/compiler/test/i18n/serializers/xliff2_spec.ts index 027bdc5bdce2b..c63146d3bc1ee 100644 --- a/packages/compiler/test/i18n/serializers/xliff2_spec.ts +++ b/packages/compiler/test/i18n/serializers/xliff2_spec.ts @@ -261,65 +261,67 @@ lignes</target> `; (function() { - const serializer = new Xliff2(); +const serializer = new Xliff2(); - function toXliff(html: string, locale: string | null = null): string { - const catalog = new MessageBundle(new HtmlParser, [], {}, locale); - catalog.updateFromTemplate(html, 'file.ts', DEFAULT_INTERPOLATION_CONFIG); - return catalog.write(serializer); - } +function toXliff(html: string, locale: string|null = null): string { + const catalog = new MessageBundle(new HtmlParser, [], {}, locale); + catalog.updateFromTemplate(html, 'file.ts', DEFAULT_INTERPOLATION_CONFIG); + return catalog.write(serializer); +} - function loadAsMap(xliff: string): {[id: string]: string} { - const {i18nNodesByMsgId} = serializer.load(xliff, 'url'); +function loadAsMap(xliff: string): {[id: string]: string} { + const {i18nNodesByMsgId} = serializer.load(xliff, 'url'); - const msgMap: {[id: string]: string} = {}; - Object.keys(i18nNodesByMsgId) - .forEach(id => msgMap[id] = serializeNodes(i18nNodesByMsgId[id]).join('')); + const msgMap: {[id: string]: string} = {}; + Object.keys(i18nNodesByMsgId) + .forEach(id => msgMap[id] = serializeNodes(i18nNodesByMsgId[id]).join('')); - return msgMap; - } + return msgMap; +} - describe('XLIFF 2.0 serializer', () => { - describe('write', () => { - it('should write a valid xliff 2.0 file', - () => { expect(toXliff(HTML)).toEqual(WRITE_XLIFF); }); - it('should write a valid xliff 2.0 file with a source language', - () => { expect(toXliff(HTML, 'fr')).toContain('srcLang="fr"'); }); +describe('XLIFF 2.0 serializer', () => { + describe('write', () => { + it('should write a valid xliff 2.0 file', () => { + expect(toXliff(HTML)).toEqual(WRITE_XLIFF); }); + it('should write a valid xliff 2.0 file with a source language', () => { + expect(toXliff(HTML, 'fr')).toContain('srcLang="fr"'); + }); + }); - describe('load', () => { - it('should load XLIFF files', () => { - expect(loadAsMap(LOAD_XLIFF)).toEqual({ - '1933478729560469763': 'etubirtta elbatalsnart', - '7056919470098446707': - '<ph name="INTERPOLATION"/> <ph name="START_BOLD_TEXT"/>sredlohecalp htiw<ph name="CLOSE_BOLD_TEXT"/> tnemele elbatalsnart', - '2981514368455622387': - '{VAR_PLURAL, plural, =0 {[<ph name="START_PARAGRAPH"/>, TEST, <ph name="CLOSE_PARAGRAPH"/>]}}', - 'i': 'oof', - '6440235004920703622': - '<ph name="START_BOLD_TEXT"/><ph name="START_UNDERLINED_TEXT"/>txeT <ph name="INTERPOLATION"/><ph name="CLOSE_UNDERLINED_TEXT"/><ph name="CLOSE_BOLD_TEXT"/>', - '8779402634269838862': - '<ph name="TAG_IMG_1"/><ph name="TAG_IMG"/><ph name="LINE_BREAK"/>', - '6536355551500405293': '<ph name="START_TAG_SPAN"/><ph name="CLOSE_TAG_SPAN"/> olleh', - 'baz': - '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}', - '6997386649824869937': 'Test: <ph name="ICU"/>', - '5229984852258993423': '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph' + - ' name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}, =other {[beaucoup]}}', - '2340165783990709777': `multi + describe('load', () => { + it('should load XLIFF files', () => { + expect(loadAsMap(LOAD_XLIFF)).toEqual({ + '1933478729560469763': 'etubirtta elbatalsnart', + '7056919470098446707': + '<ph name="INTERPOLATION"/> <ph name="START_BOLD_TEXT"/>sredlohecalp htiw<ph name="CLOSE_BOLD_TEXT"/> tnemele elbatalsnart', + '2981514368455622387': + '{VAR_PLURAL, plural, =0 {[<ph name="START_PARAGRAPH"/>, TEST, <ph name="CLOSE_PARAGRAPH"/>]}}', + 'i': 'oof', + '6440235004920703622': + '<ph name="START_BOLD_TEXT"/><ph name="START_UNDERLINED_TEXT"/>txeT <ph name="INTERPOLATION"/><ph name="CLOSE_UNDERLINED_TEXT"/><ph name="CLOSE_BOLD_TEXT"/>', + '8779402634269838862': '<ph name="TAG_IMG_1"/><ph name="TAG_IMG"/><ph name="LINE_BREAK"/>', + '6536355551500405293': '<ph name="START_TAG_SPAN"/><ph name="CLOSE_TAG_SPAN"/> olleh', + 'baz': + '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}', + '6997386649824869937': 'Test: <ph name="ICU"/>', + '5229984852258993423': '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph' + + ' name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}, =other {[beaucoup]}}', + '2340165783990709777': `multi lignes`, - 'mrk-test': 'Vous pouvez utiliser votre propre namespace.', - 'mrk-test2': 'Vous pouvez utiliser votre propre namespace.' - }); + 'mrk-test': 'Vous pouvez utiliser votre propre namespace.', + 'mrk-test2': 'Vous pouvez utiliser votre propre namespace.' }); + }); - it('should return the target locale', - () => { expect(serializer.load(LOAD_XLIFF, 'url').locale).toEqual('fr'); }); + it('should return the target locale', () => { + expect(serializer.load(LOAD_XLIFF, 'url').locale).toEqual('fr'); }); + }); - describe('structure errors', () => { - it('should throw when a wrong xliff version is used', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + describe('structure errors', () => { + it('should throw when a wrong xliff version is used', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> @@ -331,13 +333,13 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(/The XLIFF file version 1.2 is not compatible with XLIFF 2.0 serializer/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/The XLIFF file version 1.2 is not compatible with XLIFF 2.0 serializer/); + }); - it('should throw when an unit has no translation', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw when an unit has no translation', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en"> <file original="ng.template" id="ngi18n"> <unit id="missingtarget"> @@ -348,14 +350,14 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(/Message missingtarget misses a translation/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/Message missingtarget misses a translation/); + }); - it('should throw when an unit has no id attribute', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw when an unit has no id attribute', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en"> <file original="ng.template" id="ngi18n"> <unit> @@ -367,11 +369,13 @@ lignes`, </file> </xliff>`; - expect(() => { loadAsMap(XLIFF); }).toThrowError(/<unit> misses the "id" attribute/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/<unit> misses the "id" attribute/); + }); - it('should throw on duplicate unit id', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw on duplicate unit id', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en"> <file original="ng.template" id="ngi18n"> <unit id="deadbeef"> @@ -389,15 +393,15 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(/Duplicated translations for msg deadbeef/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/Duplicated translations for msg deadbeef/); }); + }); - describe('message errors', () => { - it('should throw on unknown message tags', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + describe('message errors', () => { + it('should throw on unknown message tags', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en"> <file original="ng.template" id="ngi18n"> <unit id="deadbeef"> @@ -409,13 +413,15 @@ lignes`, </file> </xliff>`; - expect(() => { loadAsMap(XLIFF); }) - .toThrowError(new RegExp( - escapeRegExp(`[ERROR ->]<b>msg should contain only ph and pc tags</b>`))); - }); + expect(() => { + loadAsMap(XLIFF); + }) + .toThrowError( + new RegExp(escapeRegExp(`[ERROR ->]<b>msg should contain only ph and pc tags</b>`))); + }); - it('should throw when a placeholder misses an id attribute', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw when a placeholder misses an id attribute', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="2.0" xmlns="urn:oasis:names:tc:xliff:document:2.0" srcLang="en"> <file original="ng.template" id="ngi18n"> <unit id="deadbeef"> @@ -427,10 +433,10 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(new RegExp(escapeRegExp(`<ph> misses the "equiv" attribute`))); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(new RegExp(escapeRegExp(`<ph> misses the "equiv" attribute`))); }); }); +}); })(); diff --git a/packages/compiler/test/i18n/serializers/xliff_spec.ts b/packages/compiler/test/i18n/serializers/xliff_spec.ts index 99ee251a57713..7a4935a7f0fcf 100644 --- a/packages/compiler/test/i18n/serializers/xliff_spec.ts +++ b/packages/compiler/test/i18n/serializers/xliff_spec.ts @@ -241,63 +241,67 @@ lignes</target> `; (function() { - const serializer = new Xliff(); +const serializer = new Xliff(); - function toXliff(html: string, locale: string | null = null): string { - const catalog = new MessageBundle(new HtmlParser, [], {}, locale); - catalog.updateFromTemplate(html, 'file.ts', DEFAULT_INTERPOLATION_CONFIG); - return catalog.write(serializer); - } +function toXliff(html: string, locale: string|null = null): string { + const catalog = new MessageBundle(new HtmlParser, [], {}, locale); + catalog.updateFromTemplate(html, 'file.ts', DEFAULT_INTERPOLATION_CONFIG); + return catalog.write(serializer); +} - function loadAsMap(xliff: string): {[id: string]: string} { - const {i18nNodesByMsgId} = serializer.load(xliff, 'url'); +function loadAsMap(xliff: string): {[id: string]: string} { + const {i18nNodesByMsgId} = serializer.load(xliff, 'url'); - const msgMap: {[id: string]: string} = {}; - Object.keys(i18nNodesByMsgId) - .forEach(id => msgMap[id] = serializeNodes(i18nNodesByMsgId[id]).join('')); + const msgMap: {[id: string]: string} = {}; + Object.keys(i18nNodesByMsgId) + .forEach(id => msgMap[id] = serializeNodes(i18nNodesByMsgId[id]).join('')); - return msgMap; - } + return msgMap; +} - describe('XLIFF serializer', () => { - describe('write', () => { - it('should write a valid xliff file', () => { expect(toXliff(HTML)).toEqual(WRITE_XLIFF); }); - it('should write a valid xliff file with a source language', - () => { expect(toXliff(HTML, 'fr')).toContain('file source-language="fr"'); }); +describe('XLIFF serializer', () => { + describe('write', () => { + it('should write a valid xliff file', () => { + expect(toXliff(HTML)).toEqual(WRITE_XLIFF); }); + it('should write a valid xliff file with a source language', () => { + expect(toXliff(HTML, 'fr')).toContain('file source-language="fr"'); + }); + }); - describe('load', () => { - it('should load XLIFF files', () => { - expect(loadAsMap(LOAD_XLIFF)).toEqual({ - '983775b9a51ce14b036be72d4cfd65d68d64e231': 'etubirtta elbatalsnart', - 'ec1d033f2436133c14ab038286c4f5df4697484a': - '<ph name="INTERPOLATION"/> footnemele elbatalsnart <ph name="START_BOLD_TEXT"/>sredlohecalp htiw<ph name="CLOSE_BOLD_TEXT"/>', - 'e2ccf3d131b15f54aa1fcf1314b1ca77c14bfcc2': - '{VAR_PLURAL, plural, =0 {[<ph name="START_PARAGRAPH"/>, TEST, <ph name="CLOSE_PARAGRAPH"/>]}}', - 'db3e0a6a5a96481f60aec61d98c3eecddef5ac23': 'oof', - 'i': 'toto', - 'bar': 'tata', - 'd7fa2d59aaedcaa5309f13028c59af8c85b8c49d': - '<ph name="START_TAG_DIV"/><ph name="CLOSE_TAG_DIV"/><ph name="TAG_IMG"/><ph name="LINE_BREAK"/>', - 'empty target': '', - 'baz': - '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}', - '52ffa620dcd76247a56d5331f34e73f340a43cdb': 'Test: <ph name="ICU"/>', - '1503afd0ccc20ff01d5e2266a9157b7b342ba494': - '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph' + - ' name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}, =other {[beaucoup]}}', - 'fcfa109b0e152d4c217dbc02530be0bcb8123ad1': `multi + describe('load', () => { + it('should load XLIFF files', () => { + expect(loadAsMap(LOAD_XLIFF)).toEqual({ + '983775b9a51ce14b036be72d4cfd65d68d64e231': 'etubirtta elbatalsnart', + 'ec1d033f2436133c14ab038286c4f5df4697484a': + '<ph name="INTERPOLATION"/> footnemele elbatalsnart <ph name="START_BOLD_TEXT"/>sredlohecalp htiw<ph name="CLOSE_BOLD_TEXT"/>', + 'e2ccf3d131b15f54aa1fcf1314b1ca77c14bfcc2': + '{VAR_PLURAL, plural, =0 {[<ph name="START_PARAGRAPH"/>, TEST, <ph name="CLOSE_PARAGRAPH"/>]}}', + 'db3e0a6a5a96481f60aec61d98c3eecddef5ac23': 'oof', + 'i': 'toto', + 'bar': 'tata', + 'd7fa2d59aaedcaa5309f13028c59af8c85b8c49d': + '<ph name="START_TAG_DIV"/><ph name="CLOSE_TAG_DIV"/><ph name="TAG_IMG"/><ph name="LINE_BREAK"/>', + 'empty target': '', + 'baz': + '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}}', + '52ffa620dcd76247a56d5331f34e73f340a43cdb': 'Test: <ph name="ICU"/>', + '1503afd0ccc20ff01d5e2266a9157b7b342ba494': + '{VAR_PLURAL, plural, =0 {[{VAR_SELECT, select, other {[<ph' + + ' name="START_PARAGRAPH"/>, profondément imbriqué, <ph name="CLOSE_PARAGRAPH"/>]}}, ]}, =other {[beaucoup]}}', + 'fcfa109b0e152d4c217dbc02530be0bcb8123ad1': `multi lignes`, - 'mrk-test': 'Translated first sentence.', - 'mrk-test2': 'Translated first sentence.' - }); + 'mrk-test': 'Translated first sentence.', + 'mrk-test2': 'Translated first sentence.' }); + }); - it('should return the target locale', - () => { expect(serializer.load(LOAD_XLIFF, 'url').locale).toEqual('fr'); }); + it('should return the target locale', () => { + expect(serializer.load(LOAD_XLIFF, 'url').locale).toEqual('fr'); + }); - it('should ignore alt-trans targets', () => { - const XLIFF = ` + it('should ignore alt-trans targets', () => { + const XLIFF = ` <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" target-language="fr" datatype="plaintext" original="ng2.template"> <body> @@ -318,12 +322,12 @@ lignes`, </file> </xliff>`; - expect(loadAsMap(XLIFF)).toEqual({'registration.submit': 'Weiter'}); - }); + expect(loadAsMap(XLIFF)).toEqual({'registration.submit': 'Weiter'}); + }); - describe('structure errors', () => { - it('should throw when a trans-unit has no translation', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + describe('structure errors', () => { + it('should throw when a trans-unit has no translation', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> @@ -334,14 +338,14 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(/Message missingtarget misses a translation/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/Message missingtarget misses a translation/); + }); - it('should throw when a trans-unit has no id attribute', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw when a trans-unit has no id attribute', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> @@ -353,13 +357,13 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(/<trans-unit> misses the "id" attribute/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/<trans-unit> misses the "id" attribute/); + }); - it('should throw on duplicate trans-unit id', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw on duplicate trans-unit id', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> @@ -375,15 +379,15 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(/Duplicated translations for msg deadbeef/); - }); + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(/Duplicated translations for msg deadbeef/); }); + }); - describe('message errors', () => { - it('should throw on unknown message tags', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + describe('message errors', () => { + it('should throw on unknown message tags', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> @@ -395,13 +399,15 @@ lignes`, </file> </xliff>`; - expect(() => { loadAsMap(XLIFF); }) - .toThrowError( - new RegExp(escapeRegExp(`[ERROR ->]<b>msg should contain only ph tags</b>`))); - }); + expect(() => { + loadAsMap(XLIFF); + }) + .toThrowError( + new RegExp(escapeRegExp(`[ERROR ->]<b>msg should contain only ph tags</b>`))); + }); - it('should throw when a placeholder misses an id attribute', () => { - const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> + it('should throw when a placeholder misses an id attribute', () => { + const XLIFF = `<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> @@ -413,12 +419,11 @@ lignes`, </file> </xliff>`; - expect(() => { - loadAsMap(XLIFF); - }).toThrowError(new RegExp(escapeRegExp(`<x> misses the "id" attribute`))); - }); - + expect(() => { + loadAsMap(XLIFF); + }).toThrowError(new RegExp(escapeRegExp(`<x> misses the "id" attribute`))); }); }); }); +}); })(); diff --git a/packages/compiler/test/i18n/serializers/xmb_spec.ts b/packages/compiler/test/i18n/serializers/xmb_spec.ts index 68a8f47db1335..38605c01129e5 100644 --- a/packages/compiler/test/i18n/serializers/xmb_spec.ts +++ b/packages/compiler/test/i18n/serializers/xmb_spec.ts @@ -76,7 +76,7 @@ lines</msg> }); } -function toXmb(html: string, url: string, locale: string | null = null): string { +function toXmb(html: string, url: string, locale: string|null = null): string { const catalog = new MessageBundle(new HtmlParser, [], {}, locale); const serializer = new Xmb(); diff --git a/packages/compiler/test/i18n/serializers/xml_helper_spec.ts b/packages/compiler/test/i18n/serializers/xml_helper_spec.ts index d8e4016048f5a..6421c089d8082 100644 --- a/packages/compiler/test/i18n/serializers/xml_helper_spec.ts +++ b/packages/compiler/test/i18n/serializers/xml_helper_spec.ts @@ -15,11 +15,13 @@ import * as xml from '../../../src/i18n/serializers/xml_helper'; .toEqual('<?xml version="1.0" ?>'); }); - it('should serialize text node', - () => { expect(xml.serialize([new xml.Text('foo bar')])).toEqual('foo bar'); }); + it('should serialize text node', () => { + expect(xml.serialize([new xml.Text('foo bar')])).toEqual('foo bar'); + }); - it('should escape text nodes', - () => { expect(xml.serialize([new xml.Text('<>')])).toEqual('<>'); }); + it('should escape text nodes', () => { + expect(xml.serialize([new xml.Text('<>')])).toEqual('<>'); + }); it('should serialize xml nodes without children', () => { expect(xml.serialize([new xml.Tag('el', {foo: 'bar'}, [])])).toEqual('<el foo="bar"/>'); @@ -42,6 +44,5 @@ import * as xml from '../../../src/i18n/serializers/xml_helper'; expect(xml.serialize([new xml.Tag('el', {foo: '<">'}, [])])) .toEqual('<el foo="<">"/>'); }); - }); } \ No newline at end of file diff --git a/packages/compiler/test/i18n/serializers/xtb_spec.ts b/packages/compiler/test/i18n/serializers/xtb_spec.ts index d162fc9739b4f..247e4ef7e7f93 100644 --- a/packages/compiler/test/i18n/serializers/xtb_spec.ts +++ b/packages/compiler/test/i18n/serializers/xtb_spec.ts @@ -117,7 +117,7 @@ import {Xtb} from '../../../src/i18n/serializers/xtb'; </translationbundle>`; // Invalid messages should not cause the parser to throw - let i18nNodesByMsgId: {[id: string]: i18n.Node[]} = undefined !; + let i18nNodesByMsgId: {[id: string]: i18n.Node[]} = undefined!; expect(() => { i18nNodesByMsgId = serializer.load(XTB, 'url').i18nNodesByMsgId; }).not.toThrow(); @@ -144,7 +144,9 @@ import {Xtb} from '../../../src/i18n/serializers/xtb'; <translation></translation> </translationbundle>`; - expect(() => { loadAsMap(XTB); }).toThrowError(/<translation> misses the "id" attribute/); + expect(() => { + loadAsMap(XTB); + }).toThrowError(/<translation> misses the "id" attribute/); }); it('should throw when a placeholder has no name attribute', () => { @@ -152,7 +154,9 @@ import {Xtb} from '../../../src/i18n/serializers/xtb'; <translation id="1186013544048295927"><ph /></translation> </translationbundle>`; - expect(() => { loadAsMap(XTB); }).toThrowError(/<ph> misses the "name" attribute/); + expect(() => { + loadAsMap(XTB); + }).toThrowError(/<ph> misses the "name" attribute/); }); it('should throw on unknown xtb tags', () => { @@ -168,7 +172,9 @@ import {Xtb} from '../../../src/i18n/serializers/xtb'; <translation id="1186013544048295927"><b>msg should contain only ph tags</b></translation> </translationbundle>`; - expect(() => { loadAsMap(XTB); }) + expect(() => { + loadAsMap(XTB); + }) .toThrowError( new RegExp(escapeRegExp(`[ERROR ->]<b>msg should contain only ph tags</b>`))); }); @@ -184,9 +190,11 @@ import {Xtb} from '../../../src/i18n/serializers/xtb'; }).toThrowError(/Duplicated translations for msg 1186013544048295927/); }); - it('should throw when trying to save an xtb file', - () => { expect(() => { serializer.write([], null); }).toThrowError(/Unsupported/); }); - + it('should throw when trying to save an xtb file', () => { + expect(() => { + serializer.write([], null); + }).toThrowError(/Unsupported/); + }); }); }); } diff --git a/packages/compiler/test/i18n/translation_bundle_spec.ts b/packages/compiler/test/i18n/translation_bundle_spec.ts index d164d8874fffb..f46a2546ba184 100644 --- a/packages/compiler/test/i18n/translation_bundle_spec.ts +++ b/packages/compiler/test/i18n/translation_bundle_spec.ts @@ -25,14 +25,14 @@ import {_extractMessages} from './i18n_parser_spec'; const srcNode = new i18n.Text('src', span); it('should translate a plain text', () => { - const msgMap = {foo: [new i18n.Text('bar', null !)]}; + const msgMap = {foo: [new i18n.Text('bar', null!)]}; const tb = new TranslationBundle(msgMap, null, (_) => 'foo'); const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i'); expect(serializeNodes(tb.get(msg))).toEqual(['bar']); }); it('should translate html-like plain text', () => { - const msgMap = {foo: [new i18n.Text('<p>bar</p>', null !)]}; + const msgMap = {foo: [new i18n.Text('<p>bar</p>', null!)]}; const tb = new TranslationBundle(msgMap, null, (_) => 'foo'); const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i'); const nodes = tb.get(msg); @@ -45,8 +45,8 @@ import {_extractMessages} from './i18n_parser_spec'; it('should translate a message with placeholder', () => { const msgMap = { foo: [ - new i18n.Text('bar', null !), - new i18n.Placeholder('', 'ph1', null !), + new i18n.Text('bar', null!), + new i18n.Placeholder('', 'ph1', null!), ] }; const phMap = { @@ -60,12 +60,12 @@ import {_extractMessages} from './i18n_parser_spec'; it('should translate a message with placeholder referencing messages', () => { const msgMap = { foo: [ - new i18n.Text('--', null !), - new i18n.Placeholder('', 'ph1', null !), - new i18n.Text('++', null !), + new i18n.Text('--', null!), + new i18n.Placeholder('', 'ph1', null!), + new i18n.Text('++', null!), ], ref: [ - new i18n.Text('*refMsg*', null !), + new i18n.Text('*refMsg*', null!), ], }; const refMsg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i'); @@ -84,13 +84,13 @@ import {_extractMessages} from './i18n_parser_spec'; const digest = (_: any) => `no matching id`; // Empty message map -> use source messages in Ignore mode - let tb = new TranslationBundle({}, null, digest, null !, MissingTranslationStrategy.Ignore); + let tb = new TranslationBundle({}, null, digest, null!, MissingTranslationStrategy.Ignore); expect(serializeNodes(tb.get(messages[0])).join('')).toEqual(src); // Empty message map -> use source messages in Warning mode - tb = new TranslationBundle({}, null, digest, null !, MissingTranslationStrategy.Warning); + tb = new TranslationBundle({}, null, digest, null!, MissingTranslationStrategy.Warning); expect(serializeNodes(tb.get(messages[0])).join('')).toEqual(src); // Empty message map -> throw in Error mode - tb = new TranslationBundle({}, null, digest, null !, MissingTranslationStrategy.Error); + tb = new TranslationBundle({}, null, digest, null!, MissingTranslationStrategy.Error); expect(() => serializeNodes(tb.get(messages[0])).join('')).toThrow(); }); @@ -98,7 +98,7 @@ import {_extractMessages} from './i18n_parser_spec'; it('should report unknown placeholders', () => { const msgMap = { foo: [ - new i18n.Text('bar', null !), + new i18n.Text('bar', null!), new i18n.Placeholder('', 'ph1', span), ] }; @@ -109,7 +109,7 @@ import {_extractMessages} from './i18n_parser_spec'; it('should report missing translation', () => { const tb = - new TranslationBundle({}, null, (_) => 'foo', null !, MissingTranslationStrategy.Error); + new TranslationBundle({}, null, (_) => 'foo', null!, MissingTranslationStrategy.Error); const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i'); expect(() => tb.get(msg)).toThrowError(/Missing translation for message "foo"/); }); @@ -117,12 +117,14 @@ import {_extractMessages} from './i18n_parser_spec'; it('should report missing translation with MissingTranslationStrategy.Warning', () => { const log: string[] = []; const console = { - log: (msg: string) => { throw `unexpected`; }, + log: (msg: string) => { + throw `unexpected`; + }, warn: (msg: string) => log.push(msg), }; const tb = new TranslationBundle( - {}, 'en', (_) => 'foo', null !, MissingTranslationStrategy.Warning, console); + {}, 'en', (_) => 'foo', null!, MissingTranslationStrategy.Warning, console); const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i'); expect(() => tb.get(msg)).not.toThrowError(); @@ -131,8 +133,8 @@ import {_extractMessages} from './i18n_parser_spec'; }); it('should not report missing translation with MissingTranslationStrategy.Ignore', () => { - const tb = new TranslationBundle( - {}, null, (_) => 'foo', null !, MissingTranslationStrategy.Ignore); + const tb = + new TranslationBundle({}, null, (_) => 'foo', null!, MissingTranslationStrategy.Ignore); const msg = new i18n.Message([srcNode], {}, {}, 'm', 'd', 'i'); expect(() => tb.get(msg)).not.toThrowError(); }); @@ -146,15 +148,15 @@ import {_extractMessages} from './i18n_parser_spec'; let count = 0; const digest = (_: any) => count++ ? 'ref' : 'foo'; const tb = - new TranslationBundle(msgMap, null, digest, null !, MissingTranslationStrategy.Error); + new TranslationBundle(msgMap, null, digest, null!, MissingTranslationStrategy.Error); expect(() => tb.get(msg)).toThrowError(/Missing translation for message "ref"/); }); it('should report invalid translated html', () => { const msgMap = { foo: [ - new i18n.Text('text', null !), - new i18n.Placeholder('', 'ph1', null !), + new i18n.Text('text', null!), + new i18n.Placeholder('', 'ph1', null!), ] }; const phMap = { diff --git a/packages/compiler/test/integration_spec.ts b/packages/compiler/test/integration_spec.ts index da7f870600dfb..e43675a57fc5f 100644 --- a/packages/compiler/test/integration_spec.ts +++ b/packages/compiler/test/integration_spec.ts @@ -7,7 +7,7 @@ */ import {Component, Directive, Input} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -21,7 +21,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; @Directive({selector: '[dot.name]'}) class MyDir { // TODO(issue/24571): remove '!'. - @Input('dot.name') value !: string; + @Input('dot.name') value!: string; } TestBed.configureTestingModule({ diff --git a/packages/compiler/test/metadata_resolver_spec.ts b/packages/compiler/test/metadata_resolver_spec.ts index 406b8755b0339..2f853c5bc4238 100644 --- a/packages/compiler/test/metadata_resolver_spec.ts +++ b/packages/compiler/test/metadata_resolver_spec.ts @@ -8,7 +8,7 @@ import {LIFECYCLE_HOOKS_VALUES, LifecycleHooks} from '@angular/compiler/src/lifecycle_reflector'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectionStrategy, Component, Directive, DoCheck, Injectable, NgModule, OnChanges, OnDestroy, OnInit, Pipe, SimpleChanges, ViewEncapsulation, ɵstringify as stringify} from '@angular/core'; -import {TestBed, async, inject} from '@angular/core/testing'; +import {async, inject, TestBed} from '@angular/core/testing'; import {CompileDiDependencyMetadata, identifierName} from '../src/compile_metadata'; import {CompileMetadataResolver} from '../src/metadata_resolver'; @@ -20,7 +20,9 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; { describe('CompileMetadataResolver', () => { - beforeEach(() => { TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); }); + beforeEach(() => { + TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); + }); it('should throw on the getDirectiveMetadata/getPipeMetadata methods if the module has not been loaded yet', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { @@ -70,8 +72,8 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; } expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, true)) - .toThrowError( - `Can't compile synchronously as ${stringify(ComponentWithExternalResources)} is still being loaded!`); + .toThrowError(`Can't compile synchronously as ${ + stringify(ComponentWithExternalResources)} is still being loaded!`); })); it('should read external metadata when sync=false', @@ -106,7 +108,7 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; resolver.loadNgModuleDirectiveAndPipeMetadata(SomeModule, false).then(() => { const value: string = - resolver.getDirectiveMetadata(ComponentWithoutModuleId).template !.templateUrl !; + resolver.getDirectiveMetadata(ComponentWithoutModuleId).template !.templateUrl!; const expectedEndValue = './someUrl'; expect(value.endsWith(expectedEndValue)).toBe(true); }); @@ -217,7 +219,7 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should throw with descriptive error message when null is passed to declarations', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @NgModule({declarations: [null !]}) + @NgModule({declarations: [null!]}) class ModuleWithNullDeclared { } expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithNullDeclared, true)) @@ -227,7 +229,7 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should throw with descriptive error message when null is passed to imports', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @NgModule({imports: [null !]}) + @NgModule({imports: [null!]}) class ModuleWithNullImported { } expect(() => resolver.loadNgModuleDirectiveAndPipeMetadata(ModuleWithNullImported, true)) @@ -248,7 +250,7 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should throw with descriptive error message when encounter invalid provider', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @NgModule({providers: [{provide: SimpleService, useClass: undefined !}]}) + @NgModule({providers: [{provide: SimpleService, useClass: undefined!}]}) class SomeModule { } @@ -258,7 +260,7 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should throw with descriptive error message when provider is undefined', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @NgModule({providers: [undefined !]}) + @NgModule({providers: [undefined!]}) class SomeModule { } @@ -290,10 +292,10 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should throw with descriptive error message when null or undefined is passed to module bootstrap', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @NgModule({bootstrap: [null !]}) + @NgModule({bootstrap: [null!]}) class ModuleWithNullBootstrap { } - @NgModule({bootstrap: [undefined !]}) + @NgModule({bootstrap: [undefined!]}) class ModuleWithUndefinedBootstrap { } @@ -347,7 +349,6 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it(`should throw an error when a Pipe is added to module's bootstrap list`, inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @Pipe({name: 'pipe'}) class MyPipe { } @@ -362,7 +363,6 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it(`should throw an error when a Service is added to module's bootstrap list`, inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @NgModule({declarations: [], bootstrap: [SimpleService]}) class ModuleWithServiceInBootstrap { } @@ -373,7 +373,6 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should generate an error when a dependency could not be resolved', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - // Override the errorCollector so that error gets collected instead of // being thrown. (resolver as any)._errorCollector = (error: Error, type?: any) => { @@ -390,12 +389,11 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; class AppModule { } - const moduleMetadata = resolver.getNgModuleMetadata(AppModule) !; + const moduleMetadata = resolver.getNgModuleMetadata(AppModule)!; expect(moduleMetadata).toBeTruthy(); expect(moduleMetadata.declaredDirectives.length).toBe(1); const directive = moduleMetadata.declaredDirectives[0]; - const directiveMetadata = - resolver.getNonNormalizedDirectiveMetadata(directive.reference) !; + const directiveMetadata = resolver.getNonNormalizedDirectiveMetadata(directive.reference)!; expect(directiveMetadata).toBeTruthy(); const {metadata} = directiveMetadata; const diDeps: CompileDiDependencyMetadata[] = metadata.type.diDeps; @@ -405,7 +403,6 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it(`should throw an error when a Directive is added to module's bootstrap list`, inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @Directive({selector: 'directive'}) class MyDirective { } @@ -420,7 +417,6 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it(`should not throw an error when a Component is added to module's bootstrap list`, inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @Component({template: ''}) class MyComp { } @@ -439,7 +435,9 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; class InvalidModule { } - expect(() => { resolver.getNgModuleMetadata(InvalidModule); }) + expect(() => { + resolver.getNgModuleMetadata(InvalidModule); + }) .toThrowError( `Unexpected value '[object Object]' imported by the module 'InvalidModule'. Please add a @NgModule annotation.`); })); @@ -447,7 +445,6 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; it('should dedupe declarations in NgModule', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { - @Component({template: ''}) class MyComp { } @@ -456,7 +453,7 @@ import {TEST_COMPILER_PROVIDERS} from './test_bindings'; class MyModule { } - const modMeta = resolver.getNgModuleMetadata(MyModule) !; + const modMeta = resolver.getNgModuleMetadata(MyModule)!; expect(modMeta.declaredDirectives.length).toBe(1); expect(modMeta.declaredDirectives[0].reference).toBe(MyComp); })); @@ -495,9 +492,9 @@ class ComponentWithExternalResources { styles: ['someStyle'], interpolation: ['{{', '}}'] }) -class ComponentWithEverythingInline implements OnChanges, - OnInit, DoCheck, OnDestroy, AfterContentInit, AfterContentChecked, AfterViewInit, - AfterViewChecked { +class ComponentWithEverythingInline implements OnChanges, OnInit, DoCheck, OnDestroy, + AfterContentInit, AfterContentChecked, AfterViewInit, + AfterViewChecked { ngOnChanges(changes: SimpleChanges): void {} ngOnInit(): void {} ngDoCheck(): void {} @@ -526,12 +523,12 @@ class MyBrokenComp2 { class SimpleService { } -@Component({selector: 'my-broken-comp', template: '', providers: [SimpleService, null !, [null]]}) +@Component({selector: 'my-broken-comp', template: '', providers: [SimpleService, null!, [null]]}) class MyBrokenComp3 { } @Component( - {selector: 'my-broken-comp', template: '', viewProviders: [null !, SimpleService, [null]]}) + {selector: 'my-broken-comp', template: '', viewProviders: [null!, SimpleService, [null]]}) class MyBrokenComp4 { } diff --git a/packages/compiler/test/ml_parser/ast_serializer_spec.ts b/packages/compiler/test/ml_parser/ast_serializer_spec.ts index 055b0a7a1cb04..e1545821d176b 100644 --- a/packages/compiler/test/ml_parser/ast_serializer_spec.ts +++ b/packages/compiler/test/ml_parser/ast_serializer_spec.ts @@ -13,7 +13,9 @@ import {serializeNodes} from './util/util'; describe('Node serializer', () => { let parser: HtmlParser; - beforeEach(() => { parser = new HtmlParser(); }); + beforeEach(() => { + parser = new HtmlParser(); + }); it('should support element', () => { const html = '<p></p>'; diff --git a/packages/compiler/test/ml_parser/ast_spec_utils.ts b/packages/compiler/test/ml_parser/ast_spec_utils.ts index 4432c2eb98ecf..268fe947007d1 100644 --- a/packages/compiler/test/ml_parser/ast_spec_utils.ts +++ b/packages/compiler/test/ml_parser/ast_spec_utils.ts @@ -78,7 +78,7 @@ class _Humanizer implements html.Visitor { private _appendContext(ast: html.Node, input: any[]): any[] { if (!this.includeSourceSpan) return input; - input.push(ast.sourceSpan !.toString()); + input.push(ast.sourceSpan!.toString()); return input; } } diff --git a/packages/compiler/test/ml_parser/html_parser_spec.ts b/packages/compiler/test/ml_parser/html_parser_spec.ts index 9972bd690e890..a488d827ac06e 100644 --- a/packages/compiler/test/ml_parser/html_parser_spec.ts +++ b/packages/compiler/test/ml_parser/html_parser_spec.ts @@ -17,7 +17,9 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe describe('HtmlParser', () => { let parser: HtmlParser; - beforeEach(() => { parser = new HtmlParser(); }); + beforeEach(() => { + parser = new HtmlParser(); + }); describe('parse', () => { describe('text nodes', () => { @@ -77,11 +79,20 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe // <meta> - it can be present in head only // <command> - obsolete // <keygen> - obsolete - ['<map><area></map>', '<div><br></div>', '<colgroup><col></colgroup>', - '<div><embed></div>', '<div><hr></div>', '<div><img></div>', '<div><input></div>', - '<object><param>/<object>', '<audio><source></audio>', '<audio><track></audio>', + ['<map><area></map>', + '<div><br></div>', + '<colgroup><col></colgroup>', + '<div><embed></div>', + '<div><hr></div>', + '<div><img></div>', + '<div><input></div>', + '<object><param>/<object>', + '<audio><source></audio>', + '<audio><track></audio>', '<p><wbr></p>', - ].forEach((html) => { expect(parser.parse(html, 'TestComp').errors).toEqual([]); }); + ].forEach((html) => { + expect(parser.parse(html, 'TestComp').errors).toEqual([]); + }); }); it('should close void elements on text nodes', () => { @@ -189,7 +200,6 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe [html.Text, '\n', 1], ]); }); - }); describe('attributes', () => { @@ -263,8 +273,9 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe [html.Text, ' messages', 0], ]); - expect(humanizeDom(new ParseTreeResult(cases[1].expression, [ - ]))).toEqual([[html.Text, 'One {{message}}', 0]]); + expect(humanizeDom(new ParseTreeResult(cases[1].expression, []))).toEqual([ + [html.Text, 'One {{message}}', 0] + ]); }); it('should parse out expansion forms', () => { @@ -367,11 +378,11 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe it('should set the start and end source spans', () => { const node = <html.Element>parser.parse('<div>a</div>', 'TestComp').rootNodes[0]; - expect(node.startSourceSpan !.start.offset).toEqual(0); - expect(node.startSourceSpan !.end.offset).toEqual(5); + expect(node.startSourceSpan!.start.offset).toEqual(0); + expect(node.startSourceSpan!.end.offset).toEqual(5); - expect(node.endSourceSpan !.start.offset).toEqual(6); - expect(node.endSourceSpan !.end.offset).toEqual(12); + expect(node.endSourceSpan!.start.offset).toEqual(6); + expect(node.endSourceSpan!.end.offset).toEqual(12); }); it('should support expansion form', () => { @@ -393,15 +404,15 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe it('should report a value span for an attribute with a value', () => { const ast = parser.parse('<div bar="12"></div>', 'TestComp'); const attr = (ast.rootNodes[0] as html.Element).attrs[0]; - expect(attr.valueSpan !.start.offset).toEqual(10); - expect(attr.valueSpan !.end.offset).toEqual(12); + expect(attr.valueSpan!.start.offset).toEqual(10); + expect(attr.valueSpan!.end.offset).toEqual(12); }); it('should report a value span for an unquoted attribute value', () => { const ast = parser.parse('<div bar=12></div>', 'TestComp'); const attr = (ast.rootNodes[0] as html.Element).attrs[0]; - expect(attr.valueSpan !.start.offset).toEqual(9); - expect(attr.valueSpan !.end.offset).toEqual(11); + expect(attr.valueSpan!.start.offset).toEqual(9); + expect(attr.valueSpan!.end.offset).toEqual(11); }); }); @@ -426,7 +437,9 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe parser.parse('<div id="foo"><span id="bar">a</span><span>b</span></div>', 'TestComp'); const accumulator: html.Node[] = []; const visitor = new class { - visit(node: html.Node, context: any) { accumulator.push(node); } + visit(node: html.Node, context: any) { + accumulator.push(node); + } visitElement(element: html.Element, context: any): any { html.visitAll(this, element.attrs); html.visitAll(this, element.children); @@ -449,13 +462,21 @@ import {humanizeDom, humanizeDomSourceSpans, humanizeLineColumn} from './ast_spe it('should skip typed visit if visit() returns a truthy value', () => { const visitor = new class { - visit(node: html.Node, context: any) { return true; } - visitElement(element: html.Element, context: any): any { throw Error('Unexpected'); } + visit(node: html.Node, context: any) { + return true; + } + visitElement(element: html.Element, context: any): any { + throw Error('Unexpected'); + } visitAttribute(attribute: html.Attribute, context: any): any { throw Error('Unexpected'); } - visitText(text: html.Text, context: any): any { throw Error('Unexpected'); } - visitComment(comment: html.Comment, context: any): any { throw Error('Unexpected'); } + visitText(text: html.Text, context: any): any { + throw Error('Unexpected'); + } + visitComment(comment: html.Comment, context: any): any { + throw Error('Unexpected'); + } visitExpansion(expansion: html.Expansion, context: any): any { throw Error('Unexpected'); } diff --git a/packages/compiler/test/ml_parser/html_whitespaces_spec.ts b/packages/compiler/test/ml_parser/html_whitespaces_spec.ts index 3b5c1ddc4eac4..4c22b47801b4c 100644 --- a/packages/compiler/test/ml_parser/html_whitespaces_spec.ts +++ b/packages/compiler/test/ml_parser/html_whitespaces_spec.ts @@ -15,7 +15,6 @@ import {humanizeDom} from './ast_spec_utils'; { describe('removeWhitespaces', () => { - function parseAndRemoveWS(template: string, options?: TokenizeOptions): any[] { return humanizeDom(removeWhitespaces(new HtmlParser().parse(template, 'TestComp', options))); } diff --git a/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts b/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts index 0682030852902..0aab1414d8872 100644 --- a/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts +++ b/packages/compiler/test/ml_parser/icu_ast_expander_spec.ts @@ -8,7 +8,7 @@ import * as html from '../../src/ml_parser/ast'; import {HtmlParser} from '../../src/ml_parser/html_parser'; -import {ExpansionResult, expandNodes} from '../../src/ml_parser/icu_ast_expander'; +import {expandNodes, ExpansionResult} from '../../src/ml_parser/icu_ast_expander'; import {ParseError} from '../../src/parse_util'; import {humanizeNodes} from './ast_spec_utils'; @@ -56,28 +56,28 @@ import {humanizeNodes} from './ast_spec_utils'; const nodes = expand(`{messages.length, plural,=0 {<b>bold</b>}}`).nodes; const container: html.Element = <html.Element>nodes[0]; - expect(container.sourceSpan !.start.col).toEqual(0); - expect(container.sourceSpan !.end.col).toEqual(42); - expect(container.startSourceSpan !.start.col).toEqual(0); - expect(container.startSourceSpan !.end.col).toEqual(42); - expect(container.endSourceSpan !.start.col).toEqual(0); - expect(container.endSourceSpan !.end.col).toEqual(42); + expect(container.sourceSpan!.start.col).toEqual(0); + expect(container.sourceSpan!.end.col).toEqual(42); + expect(container.startSourceSpan!.start.col).toEqual(0); + expect(container.startSourceSpan!.end.col).toEqual(42); + expect(container.endSourceSpan!.start.col).toEqual(0); + expect(container.endSourceSpan!.end.col).toEqual(42); const switchExp = container.attrs[0]; expect(switchExp.sourceSpan.start.col).toEqual(1); expect(switchExp.sourceSpan.end.col).toEqual(16); const template: html.Element = <html.Element>container.children[0]; - expect(template.sourceSpan !.start.col).toEqual(25); - expect(template.sourceSpan !.end.col).toEqual(41); + expect(template.sourceSpan!.start.col).toEqual(25); + expect(template.sourceSpan!.end.col).toEqual(41); const switchCheck = template.attrs[0]; expect(switchCheck.sourceSpan.start.col).toEqual(25); expect(switchCheck.sourceSpan.end.col).toEqual(28); const b: html.Element = <html.Element>template.children[0]; - expect(b.sourceSpan !.start.col).toEqual(29); - expect(b.endSourceSpan !.end.col).toEqual(40); + expect(b.sourceSpan!.start.col).toEqual(29); + expect(b.endSourceSpan!.end.col).toEqual(40); }); it('should handle other special forms', () => { diff --git a/packages/compiler/test/ml_parser/lexer_spec.ts b/packages/compiler/test/ml_parser/lexer_spec.ts index b89734e4f8d57..8874ad83d445b 100644 --- a/packages/compiler/test/ml_parser/lexer_spec.ts +++ b/packages/compiler/test/ml_parser/lexer_spec.ts @@ -232,7 +232,6 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u [lex.TokenType.EOF, ''], ]); }); - }); describe('attributes', () => { @@ -400,7 +399,6 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u [lex.TokenType.ATTR_VALUE, 'Unexpected character "EOF"', '0:8'], ]); }); - }); describe('closing tags', () => { @@ -729,7 +727,6 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u [lex.TokenType.EOF, ''], ]); }); - }); describe('expansion forms', () => { @@ -898,7 +895,7 @@ import {ParseLocation, ParseSourceFile, ParseSourceSpan} from '../../src/parse_u const file = new ParseSourceFile(src, 'file://'); const location = new ParseLocation(file, 12, 123, 456); const span = new ParseSourceSpan(location, location); - const error = new lex.TokenError('**ERROR**', null !, span); + const error = new lex.TokenError('**ERROR**', null!, span); expect(error.toString()) .toEqual(`**ERROR** ("\n222\n333\n[ERROR ->]E\n444\n555\n"): file://@123:456`); }); diff --git a/packages/compiler/test/ml_parser/util/util.ts b/packages/compiler/test/ml_parser/util/util.ts index b61939b501390..d640b6448dca8 100644 --- a/packages/compiler/test/ml_parser/util/util.ts +++ b/packages/compiler/test/ml_parser/util/util.ts @@ -15,16 +15,21 @@ class _SerializerVisitor implements html.Visitor { return `<${element.name}${this._visitAll(element.attrs, ' ')}/>`; } - return `<${element.name}${this._visitAll(element.attrs, ' ')}>${this._visitAll(element.children)}</${element.name}>`; + return `<${element.name}${this._visitAll(element.attrs, ' ')}>${ + this._visitAll(element.children)}</${element.name}>`; } visitAttribute(attribute: html.Attribute, context: any): any { return `${attribute.name}="${attribute.value}"`; } - visitText(text: html.Text, context: any): any { return text.value; } + visitText(text: html.Text, context: any): any { + return text.value; + } - visitComment(comment: html.Comment, context: any): any { return `<!--${comment.value}-->`; } + visitComment(comment: html.Comment, context: any): any { + return `<!--${comment.value}-->`; + } visitExpansion(expansion: html.Expansion, context: any): any { return `{${expansion.switchValue}, ${expansion.type},${this._visitAll(expansion.cases)}}`; diff --git a/packages/compiler/test/ng_module_resolver_spec.ts b/packages/compiler/test/ng_module_resolver_spec.ts index d9b019c520bed..787f5ca93ee25 100644 --- a/packages/compiler/test/ng_module_resolver_spec.ts +++ b/packages/compiler/test/ng_module_resolver_spec.ts @@ -33,7 +33,9 @@ class SimpleClass {} describe('NgModuleResolver', () => { let resolver: NgModuleResolver; - beforeEach(() => { resolver = new NgModuleResolver(new JitReflector()); }); + beforeEach(() => { + resolver = new NgModuleResolver(new JitReflector()); + }); it('should read out the metadata from the class', () => { const moduleMetadata = resolver.resolve(SomeModule); @@ -66,6 +68,5 @@ class SimpleClass {} expect(resolver.resolve(ChildWithDecorator)).toEqual(new NgModule({id: 'c'})); }); - }); } diff --git a/packages/compiler/test/output/abstract_emitter_node_only_spec.ts b/packages/compiler/test/output/abstract_emitter_node_only_spec.ts index d70410d491b22..a95031527d328 100644 --- a/packages/compiler/test/output/abstract_emitter_node_only_spec.ts +++ b/packages/compiler/test/output/abstract_emitter_node_only_spec.ts @@ -18,14 +18,16 @@ import {extractSourceMap, originalPositionFor} from '@angular/compiler/testing/s const fileB = new ParseSourceFile('b0b1b2b3b4b5b6b7b8b9', 'b.js'); let ctx: EmitterVisitorContext; - beforeEach(() => { ctx = EmitterVisitorContext.createRoot(); }); + beforeEach(() => { + ctx = EmitterVisitorContext.createRoot(); + }); it('should add source files to the source map', () => { ctx.print(createSourceSpan(fileA, 0), 'o0'); ctx.print(createSourceSpan(fileA, 1), 'o1'); ctx.print(createSourceSpan(fileB, 0), 'o2'); ctx.print(createSourceSpan(fileB, 1), 'o3'); - const sm = ctx.toSourceMapGenerator('o.ts').toJSON() !; + const sm = ctx.toSourceMapGenerator('o.ts').toJSON()!; expect(sm.sources).toEqual([fileA.url, fileB.url]); expect(sm.sourcesContent).toEqual([fileA.content, fileB.content]); }); @@ -43,7 +45,7 @@ import {extractSourceMap, originalPositionFor} from '@angular/compiler/testing/s it('should be able to shift the content', () => { ctx.print(createSourceSpan(fileA, 0), 'fileA-0'); - const sm = ctx.toSourceMapGenerator('o.ts', 10).toJSON() !; + const sm = ctx.toSourceMapGenerator('o.ts', 10).toJSON()!; expect(originalPositionFor(sm, {line: 11, column: 0})).toEqual({ line: 1, column: 0, @@ -111,9 +113,9 @@ import {extractSourceMap, originalPositionFor} from '@angular/compiler/testing/s // All lines / columns indexes are 0-based // Note: source-map line indexes are 1-based, column 0-based function expectMap( - ctx: EmitterVisitorContext, genLine: number, genCol: number, source: string | null = null, - srcLine: number | null = null, srcCol: number | null = null) { - const sm = ctx.toSourceMapGenerator('o.ts').toJSON() !; + ctx: EmitterVisitorContext, genLine: number, genCol: number, source: string|null = null, + srcLine: number|null = null, srcCol: number|null = null) { + const sm = ctx.toSourceMapGenerator('o.ts').toJSON()!; const genPosition = {line: genLine + 1, column: genCol}; const origPosition = originalPositionFor(sm, genPosition); // TODO: Review use of `any` here (#19904) @@ -124,7 +126,7 @@ function expectMap( // returns the number of segments per line function nbSegmentsPerLine(ctx: EmitterVisitorContext) { - const sm = ctx.toSourceMapGenerator('o.ts').toJSON() !; + const sm = ctx.toSourceMapGenerator('o.ts').toJSON()!; const lines = sm.mappings.split(';'); return lines.map(l => { const m = l.match(/,/g); diff --git a/packages/compiler/test/output/abstract_emitter_spec.ts b/packages/compiler/test/output/abstract_emitter_spec.ts index d28b439ff1b66..6f777c9b6b774 100644 --- a/packages/compiler/test/output/abstract_emitter_spec.ts +++ b/packages/compiler/test/output/abstract_emitter_spec.ts @@ -11,24 +11,34 @@ import {escapeIdentifier} from '@angular/compiler/src/output/abstract_emitter'; { describe('AbstractEmitter', () => { describe('escapeIdentifier', () => { - it('should escape single quotes', - () => { expect(escapeIdentifier(`'`, false)).toEqual(`'\\''`); }); + it('should escape single quotes', () => { + expect(escapeIdentifier(`'`, false)).toEqual(`'\\''`); + }); - it('should escape backslash', - () => { expect(escapeIdentifier('\\', false)).toEqual(`'\\\\'`); }); + it('should escape backslash', () => { + expect(escapeIdentifier('\\', false)).toEqual(`'\\\\'`); + }); - it('should escape newlines', - () => { expect(escapeIdentifier('\n', false)).toEqual(`'\\n'`); }); + it('should escape newlines', () => { + expect(escapeIdentifier('\n', false)).toEqual(`'\\n'`); + }); - it('should escape carriage returns', - () => { expect(escapeIdentifier('\r', false)).toEqual(`'\\r'`); }); + it('should escape carriage returns', () => { + expect(escapeIdentifier('\r', false)).toEqual(`'\\r'`); + }); - it('should escape $', () => { expect(escapeIdentifier('$', true)).toEqual(`'\\$'`); }); - it('should not escape $', () => { expect(escapeIdentifier('$', false)).toEqual(`'$'`); }); - it('should add quotes for non-identifiers', - () => { expect(escapeIdentifier('==', false, false)).toEqual(`'=='`); }); - it('does not escape class (but it probably should)', - () => { expect(escapeIdentifier('class', false, false)).toEqual('class'); }); + it('should escape $', () => { + expect(escapeIdentifier('$', true)).toEqual(`'\\$'`); + }); + it('should not escape $', () => { + expect(escapeIdentifier('$', false)).toEqual(`'$'`); + }); + it('should add quotes for non-identifiers', () => { + expect(escapeIdentifier('==', false, false)).toEqual(`'=='`); + }); + it('does not escape class (but it probably should)', () => { + expect(escapeIdentifier('class', false, false)).toEqual('class'); + }); }); }); } diff --git a/packages/compiler/test/output/js_emitter_node_only_spec.ts b/packages/compiler/test/output/js_emitter_node_only_spec.ts index 1ec2bb4e3ce40..c2b5aac10a60e 100644 --- a/packages/compiler/test/output/js_emitter_node_only_spec.ts +++ b/packages/compiler/test/output/js_emitter_node_only_spec.ts @@ -22,12 +22,14 @@ const someGenFilePath = 'somePackage/someGenFile'; let emitter: JavaScriptEmitter; let someVar: o.ReadVarExpr; - beforeEach(() => { emitter = new JavaScriptEmitter(); }); + beforeEach(() => { + emitter = new JavaScriptEmitter(); + }); - function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap { + function emitSourceMap(stmt: o.Statement|o.Statement[], preamble?: string): SourceMap { const stmts = Array.isArray(stmt) ? stmt : [stmt]; const source = emitter.emitStatements(someGenFilePath, stmts, preamble); - return extractSourceMap(source) !; + return extractSourceMap(source)!; } describe('source maps', () => { diff --git a/packages/compiler/test/output/js_emitter_spec.ts b/packages/compiler/test/output/js_emitter_spec.ts index a60c15c706806..a2f7d11999fe0 100644 --- a/packages/compiler/test/output/js_emitter_spec.ts +++ b/packages/compiler/test/output/js_emitter_spec.ts @@ -171,8 +171,9 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some }); it('should support function statements', () => { - expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [ - ]))).toEqual(['function someFn() {', '}'].join('\n')); + expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], []))).toEqual([ + 'function someFn() {', '}' + ].join('\n')); expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [], null, [o.StmtModifier.Exported]))) .toEqual([ 'function someFn() {', '}', @@ -181,8 +182,9 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [ new o.ReturnStatement(o.literal(1)) ]))).toEqual(['function someFn() {', ' return 1;', '}'].join('\n')); - expect(emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1')], [ - ]))).toEqual(['function someFn(param1) {', '}'].join('\n')); + expect(emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1')], []))).toEqual([ + 'function someFn(param1) {', '}' + ].join('\n')); }); it('should support comments', () => { @@ -219,25 +221,29 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some ].join('\n')); }); - it('should support support throwing', - () => { expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); }); + it('should support support throwing', () => { + expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); + }); describe('classes', () => { let callSomeMethod: o.Statement; - beforeEach(() => { callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); }); + beforeEach(() => { + callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); + }); it('should support declaring classes', () => { - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ - ]))).toEqual(['function SomeClass() {', '}'].join('\n')); + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, []))).toEqual([ + 'function SomeClass() {', '}' + ].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], null !, [], [o.StmtModifier.Exported]))) + 'SomeClass', null!, [], [], null!, [], [o.StmtModifier.Exported]))) .toEqual([ 'function SomeClass() {', '}', `Object.defineProperty(exports, 'SomeClass', { get: function() { return SomeClass; }});` ].join('\n')); - expect(emitStmt( - new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, []))) + expect( + emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null!, []))) .toEqual([ 'function SomeClass() {', '}', 'SomeClass.prototype = Object.create(SomeSuperClass.prototype);' @@ -247,23 +253,22 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some it('should support declaring constructors', () => { const superCall = o.SUPER_EXPR.callFn([o.variable('someParam')]).toStmt(); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], []), []))) + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], []), []))) .toEqual(['function SomeClass() {', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], - new o.ClassMethod(null !, [new o.FnParam('someParam')], []), []))) + 'SomeClass', null!, [], [], + new o.ClassMethod(null!, [new o.FnParam('someParam')], []), []))) .toEqual(['function SomeClass(someParam) {', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( 'SomeClass', o.variable('SomeSuperClass'), [], [], - new o.ClassMethod(null !, [], [superCall]), []))) + new o.ClassMethod(null!, [], [superCall]), []))) .toEqual([ 'function SomeClass() {', ' var self = this;', ' SomeSuperClass.call(this, someParam);', '}', 'SomeClass.prototype = Object.create(SomeSuperClass.prototype);' ].join('\n')); - expect( - emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [callSomeMethod]), []))) + expect(emitStmt(new o.ClassStmt( + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], [callSomeMethod]), []))) .toEqual([ 'function SomeClass() {', ' var self = this;', ' self.someMethod();', '}' ].join('\n')); @@ -271,14 +276,14 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some it('should support declaring getters', () => { expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [])], null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [])], null!, []))) .toEqual([ 'function SomeClass() {', '}', `Object.defineProperty(SomeClass.prototype, 'someGetter', { get: function() {`, `}});` ].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [callSomeMethod])], - null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [callSomeMethod])], + null!, []))) .toEqual([ 'function SomeClass() {', '}', `Object.defineProperty(SomeClass.prototype, 'someGetter', { get: function() {`, @@ -288,19 +293,19 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some it('should support methods', () => { expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], null !, [new o.ClassMethod('someMethod', [], [])]))) + 'SomeClass', null!, [], [], null!, [new o.ClassMethod('someMethod', [], [])]))) .toEqual([ 'function SomeClass() {', '}', 'SomeClass.prototype.someMethod = function() {', '};' ].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], null !, + 'SomeClass', null!, [], [], null!, [new o.ClassMethod('someMethod', [new o.FnParam('someParam')], [])]))) .toEqual([ 'function SomeClass() {', '}', 'SomeClass.prototype.someMethod = function(someParam) {', '};' ].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], null !, + 'SomeClass', null!, [], [], null!, [new o.ClassMethod('someMethod', [], [callSomeMethod])]))) .toEqual([ 'function SomeClass() {', '}', 'SomeClass.prototype.someMethod = function() {', diff --git a/packages/compiler/test/output/output_ast_spec.ts b/packages/compiler/test/output/output_ast_spec.ts index 2af2adaa99e03..41c7fbaca158f 100644 --- a/packages/compiler/test/output/output_ast_spec.ts +++ b/packages/compiler/test/output/output_ast_spec.ts @@ -15,8 +15,8 @@ import * as o from '../../src/output/output_ast'; const ref1 = new o.ExternalReference('aModule', 'name1'); const ref2 = new o.ExternalReference('aModule', 'name2'); const stmt = - o.variable('test').set(o.NULL_EXPR).toDeclStmt(o.importType(ref1, [o.importType( - ref2) !])); + o.variable('test').set(o.NULL_EXPR).toDeclStmt(o.importType(ref1, [o.importType(ref2)! + ])); expect(o.collectExternalReferences([stmt])).toEqual([ref1, ref2]); }); diff --git a/packages/compiler/test/output/output_jit_spec.ts b/packages/compiler/test/output/output_jit_spec.ts index eadc9292c51fa..d978ecda2220e 100644 --- a/packages/compiler/test/output/output_jit_spec.ts +++ b/packages/compiler/test/output/output_jit_spec.ts @@ -57,7 +57,7 @@ const anotherModuleUrl = 'somePackage/someOtherPath'; o.literal('use strict').toStmt(), ], ctx); - const matches = ctx.toSource().match(/'use strict';/g) !; + const matches = ctx.toSource().match(/'use strict';/g)!; expect(matches.length).toBe(1); }); }); diff --git a/packages/compiler/test/output/source_map_spec.ts b/packages/compiler/test/output/source_map_spec.ts index ea76893e115b7..2d80d01e09e2c 100644 --- a/packages/compiler/test/output/source_map_spec.ts +++ b/packages/compiler/test/output/source_map_spec.ts @@ -52,7 +52,7 @@ import {SourceMapGenerator, toBase64String} from '@angular/compiler/src/output/s .addMapping(3, 'a.js', 5, 2); // Generated with https://sokra.github.io/source-map-visualization using a TS source map - expect(map.toJSON() !.mappings) + expect(map.toJSON()!.mappings) .toEqual( 'AAAA,IAAM,CAAC,GAAe,CAAC,CAAC;AACxB,IAAM,CAAC,GAAG,CAAC,CAAC;AAEZ,EAAE,CAAC,OAAO,CAAC,UAAA,CAAC;IACR,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC,CAAC,CAAA'); }); @@ -64,7 +64,7 @@ import {SourceMapGenerator, toBase64String} from '@angular/compiler/src/output/s .addSource('url.ts', null) .addLine() .addMapping(0, 'inline.ts', 0, 0) - .toJSON() !; + .toJSON()!; expect(map.file).toEqual('out.js'); expect(map.sources).toEqual(['inline.ts', 'url.ts']); @@ -81,7 +81,11 @@ import {SourceMapGenerator, toBase64String} from '@angular/compiler/src/output/s describe('encodeB64String', () => { it('should return the b64 encoded value', () => { - [['', ''], ['a', 'YQ=='], ['Foo', 'Rm9v'], ['Foo1', 'Rm9vMQ=='], ['Foo12', 'Rm9vMTI='], + [['', ''], + ['a', 'YQ=='], + ['Foo', 'Rm9v'], + ['Foo1', 'Rm9vMQ=='], + ['Foo12', 'Rm9vMTI='], ['Foo123', 'Rm9vMTIz'], ].forEach(([src, b64]) => expect(toBase64String(src)).toEqual(b64)); }); @@ -113,7 +117,7 @@ import {SourceMapGenerator, toBase64String} from '@angular/compiler/src/output/s it('should throw when adding segments without column', () => { expect(() => { - new SourceMapGenerator('out.js').addSource('in.js').addLine().addMapping(null !); + new SourceMapGenerator('out.js').addSource('in.js').addLine().addMapping(null!); }).toThrowError('The column in the generated code must be provided'); }); diff --git a/packages/compiler/test/output/ts_emitter_node_only_spec.ts b/packages/compiler/test/output/ts_emitter_node_only_spec.ts index b1ce420096ead..0e6c75e457349 100644 --- a/packages/compiler/test/output/ts_emitter_node_only_spec.ts +++ b/packages/compiler/test/output/ts_emitter_node_only_spec.ts @@ -31,10 +31,10 @@ const someGenFilePath = 'somePackage/someGenFile'; someVar = o.variable('someVar'); }); - function emitSourceMap(stmt: o.Statement | o.Statement[], preamble?: string): SourceMap { + function emitSourceMap(stmt: o.Statement|o.Statement[], preamble?: string): SourceMap { const stmts = Array.isArray(stmt) ? stmt : [stmt]; const source = emitter.emitStatements(someGenFilePath, stmts, preamble); - return extractSourceMap(source) !; + return extractSourceMap(source)!; } describe('source maps', () => { diff --git a/packages/compiler/test/output/ts_emitter_spec.ts b/packages/compiler/test/output/ts_emitter_spec.ts index cc287c22a80c5..e499de649bde8 100644 --- a/packages/compiler/test/output/ts_emitter_spec.ts +++ b/packages/compiler/test/output/ts_emitter_spec.ts @@ -35,7 +35,7 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some someVar = o.variable('someVar', null, null); }); - function emitStmt(stmt: o.Statement | o.Statement[], preamble?: string): string { + function emitStmt(stmt: o.Statement|o.Statement[], preamble?: string): string { const stmts = Array.isArray(stmt) ? stmt : [stmt]; const source = emitter.emitStatements(someGenFilePath, stmts, preamble); return stripSourceMapAndNewLine(source); @@ -223,15 +223,17 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some }); it('should support function statements', () => { - expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [ - ]))).toEqual(['function someFn():void {', '}'].join('\n')); + expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], []))).toEqual([ + 'function someFn():void {', '}' + ].join('\n')); expect(emitStmt(new o.DeclareFunctionStmt('someFn', [], [], null, [o.StmtModifier.Exported]))) .toEqual(['export function someFn():void {', '}'].join('\n')); expect(emitStmt(new o.DeclareFunctionStmt( 'someFn', [], [new o.ReturnStatement(o.literal(1))], o.INT_TYPE))) .toEqual(['function someFn():number {', ' return 1;', '}'].join('\n')); - expect(emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1', o.INT_TYPE)], [ - ]))).toEqual(['function someFn(param1:number):void {', '}'].join('\n')); + expect( + emitStmt(new o.DeclareFunctionStmt('someFn', [new o.FnParam('param1', o.INT_TYPE)], []))) + .toEqual(['function someFn(param1:number):void {', '}'].join('\n')); }); it('should support comments', () => { @@ -266,43 +268,47 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some ].join('\n')); }); - it('should support support throwing', - () => { expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); }); + it('should support support throwing', () => { + expect(emitStmt(new o.ThrowStmt(someVar))).toEqual('throw someVar;'); + }); describe('classes', () => { let callSomeMethod: o.Statement; - beforeEach(() => { callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); }); + beforeEach(() => { + callSomeMethod = o.THIS_EXPR.callMethod('someMethod', []).toStmt(); + }); it('should support declaring classes', () => { - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ - ]))).toEqual(['class SomeClass {', '}'].join('\n')); - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [], [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, []))).toEqual([ + 'class SomeClass {', '}' + ].join('\n')); + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [], [ o.StmtModifier.Exported ]))).toEqual(['export class SomeClass {', '}'].join('\n')); - expect(emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null !, [ - ]))).toEqual(['class SomeClass extends SomeSuperClass {', '}'].join('\n')); + expect( + emitStmt(new o.ClassStmt('SomeClass', o.variable('SomeSuperClass'), [], [], null!, []))) + .toEqual(['class SomeClass extends SomeSuperClass {', '}'].join('\n')); }); it('should support declaring constructors', () => { const superCall = o.SUPER_EXPR.callFn([o.variable('someParam')]).toStmt(); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], []), []))) + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], []), []))) .toEqual(['class SomeClass {', ' constructor() {', ' }', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], - new o.ClassMethod(null !, [new o.FnParam('someParam', o.INT_TYPE)], []), []))) + 'SomeClass', null!, [], [], + new o.ClassMethod(null!, [new o.FnParam('someParam', o.INT_TYPE)], []), []))) .toEqual( ['class SomeClass {', ' constructor(someParam:number) {', ' }', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [superCall]), []))) + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], [superCall]), []))) .toEqual([ 'class SomeClass {', ' constructor() {', ' super(someParam);', ' }', '}' ].join('\n')); - expect( - emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], new o.ClassMethod(null !, [], [callSomeMethod]), []))) + expect(emitStmt(new o.ClassStmt( + 'SomeClass', null!, [], [], new o.ClassMethod(null!, [], [callSomeMethod]), []))) .toEqual([ 'class SomeClass {', ' constructor() {', ' this.someMethod();', ' }', '}' ].join('\n')); @@ -310,57 +316,56 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some it('should support declaring fields', () => { expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [new o.ClassField('someField')], [], null !, []))) + 'SomeClass', null!, [new o.ClassField('someField')], [], null!, []))) .toEqual(['class SomeClass {', ' someField:any;', '}'].join('\n')); - expect( - emitStmt(new o.ClassStmt( - 'SomeClass', null !, [new o.ClassField('someField', o.INT_TYPE)], [], null !, []))) + expect(emitStmt(new o.ClassStmt( + 'SomeClass', null!, [new o.ClassField('someField', o.INT_TYPE)], [], null!, []))) .toEqual(['class SomeClass {', ' someField:number;', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, - [new o.ClassField('someField', o.INT_TYPE, [o.StmtModifier.Private])], [], - null !, []))) + 'SomeClass', null!, + [new o.ClassField('someField', o.INT_TYPE, [o.StmtModifier.Private])], [], null!, + []))) .toEqual(['class SomeClass {', ' /*private*/ someField:number;', '}'].join('\n')); }); it('should support declaring getters', () => { expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [])], null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [])], null!, []))) .toEqual(['class SomeClass {', ' get someGetter():any {', ' }', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [], o.INT_TYPE)], - null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [], o.INT_TYPE)], null!, + []))) .toEqual(['class SomeClass {', ' get someGetter():number {', ' }', '}'].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [new o.ClassGetter('someGetter', [callSomeMethod])], - null !, []))) + 'SomeClass', null!, [], [new o.ClassGetter('someGetter', [callSomeMethod])], + null!, []))) .toEqual([ 'class SomeClass {', ' get someGetter():any {', ' this.someMethod();', ' }', '}' ].join('\n')); - expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], - [new o.ClassGetter('someGetter', [], null !, [o.StmtModifier.Private])], null !, - []))) + expect( + emitStmt(new o.ClassStmt( + 'SomeClass', null!, [], + [new o.ClassGetter('someGetter', [], null!, [o.StmtModifier.Private])], null!, []))) .toEqual( ['class SomeClass {', ' private get someGetter():any {', ' }', '}'].join('\n')); }); it('should support methods', () => { - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [ new o.ClassMethod('someMethod', [], []) ]))).toEqual(['class SomeClass {', ' someMethod():void {', ' }', '}'].join('\n')); - expect(emitStmt(new o.ClassStmt('SomeClass', null !, [], [], null !, [ + expect(emitStmt(new o.ClassStmt('SomeClass', null!, [], [], null!, [ new o.ClassMethod('someMethod', [], [], o.INT_TYPE) ]))).toEqual(['class SomeClass {', ' someMethod():number {', ' }', '}'].join('\n')); expect( emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], null !, + 'SomeClass', null!, [], [], null!, [new o.ClassMethod('someMethod', [new o.FnParam('someParam', o.INT_TYPE)], [])]))) .toEqual([ 'class SomeClass {', ' someMethod(someParam:number):void {', ' }', '}' ].join('\n')); expect(emitStmt(new o.ClassStmt( - 'SomeClass', null !, [], [], null !, + 'SomeClass', null!, [], [], null!, [new o.ClassMethod('someMethod', [], [callSomeMethod])]))) .toEqual([ 'class SomeClass {', ' someMethod():void {', ' this.someMethod();', ' }', '}' @@ -412,7 +417,7 @@ const externalModuleIdentifier = new o.ExternalReference(anotherModuleUrl, 'some it('should support combined types', () => { const writeVarExpr = o.variable('a').set(o.NULL_EXPR); - expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(null !)))) + expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(null!)))) .toEqual('var a:any[] = (null as any);'); expect(emitStmt(writeVarExpr.toDeclStmt(new o.ArrayType(o.INT_TYPE)))) .toEqual('var a:number[] = (null as any);'); diff --git a/packages/compiler/test/pipe_resolver_spec.ts b/packages/compiler/test/pipe_resolver_spec.ts index e338973107856..bff6ce12636f7 100644 --- a/packages/compiler/test/pipe_resolver_spec.ts +++ b/packages/compiler/test/pipe_resolver_spec.ts @@ -21,7 +21,9 @@ class SimpleClass {} describe('PipeResolver', () => { let resolver: PipeResolver; - beforeEach(() => { resolver = new PipeResolver(new JitReflector()); }); + beforeEach(() => { + resolver = new PipeResolver(new JitReflector()); + }); it('should read out the metadata from the class', () => { const moduleMetadata = resolver.resolve(SomePipe); @@ -48,6 +50,5 @@ class SimpleClass {} expect(resolver.resolve(ChildWithDecorator)).toEqual(new Pipe({name: 'c'})); }); - }); } diff --git a/packages/compiler/test/render3/r3_ast_spans_spec.ts b/packages/compiler/test/render3/r3_ast_spans_spec.ts index e8e6931c49ee0..f0d65ce50d243 100644 --- a/packages/compiler/test/render3/r3_ast_spans_spec.ts +++ b/packages/compiler/test/render3/r3_ast_spans_spec.ts @@ -74,18 +74,24 @@ class R3AstSourceSpans implements t.Visitor<void> { ['BoundEvent', humanizeSpan(event.sourceSpan), humanizeSpan(event.handlerSpan)]); } - visitText(text: t.Text) { this.result.push(['Text', humanizeSpan(text.sourceSpan)]); } + visitText(text: t.Text) { + this.result.push(['Text', humanizeSpan(text.sourceSpan)]); + } visitBoundText(text: t.BoundText) { this.result.push(['BoundText', humanizeSpan(text.sourceSpan)]); } - visitIcu(icu: t.Icu) { return null; } + visitIcu(icu: t.Icu) { + return null; + } - private visitAll(nodes: t.Node[][]) { nodes.forEach(node => t.visitAll(this, node)); } + private visitAll(nodes: t.Node[][]) { + nodes.forEach(node => t.visitAll(this, node)); + } } -function humanizeSpan(span: ParseSourceSpan | null | undefined): string { +function humanizeSpan(span: ParseSourceSpan|null|undefined): string { if (span === null || span === undefined) { return `<empty>`; } diff --git a/packages/compiler/test/render3/r3_template_transform_spec.ts b/packages/compiler/test/render3/r3_template_transform_spec.ts index 13f5e1b41c4f8..f43177fdcb16b 100644 --- a/packages/compiler/test/render3/r3_template_transform_spec.ts +++ b/packages/compiler/test/render3/r3_template_transform_spec.ts @@ -75,13 +75,21 @@ class R3AstHumanizer implements t.Visitor<void> { ]); } - visitText(text: t.Text) { this.result.push(['Text', text.value]); } + visitText(text: t.Text) { + this.result.push(['Text', text.value]); + } - visitBoundText(text: t.BoundText) { this.result.push(['BoundText', unparse(text.value)]); } + visitBoundText(text: t.BoundText) { + this.result.push(['BoundText', unparse(text.value)]); + } - visitIcu(icu: t.Icu) { return null; } + visitIcu(icu: t.Icu) { + return null; + } - private visitAll(nodes: t.Node[][]) { nodes.forEach(node => t.visitAll(this, node)); } + private visitAll(nodes: t.Node[][]) { + nodes.forEach(node => t.visitAll(this, node)); + } } function expectFromHtml(html: string) { @@ -97,13 +105,14 @@ function expectFromR3Nodes(nodes: t.Node[]) { function expectSpanFromHtml(html: string) { const {nodes} = parse(html); - return expect(nodes[0] !.sourceSpan.toString()); + return expect(nodes[0]!.sourceSpan.toString()); } describe('R3 template transform', () => { describe('ParseSpan on nodes toString', () => { - it('should create valid text span on Element with adjacent start and end tags', - () => { expectSpanFromHtml('<div></div>').toBe('<div></div>'); }); + it('should create valid text span on Element with adjacent start and end tags', () => { + expectSpanFromHtml('<div></div>').toBe('<div></div>'); + }); }); describe('Nodes without binding', () => { diff --git a/packages/compiler/test/render3/style_parser_spec.ts b/packages/compiler/test/render3/style_parser_spec.ts index 4f44f6aebb276..e0d9533bec76f 100644 --- a/packages/compiler/test/render3/style_parser_spec.ts +++ b/packages/compiler/test/render3/style_parser_spec.ts @@ -90,7 +90,8 @@ describe('style parsing', () => { expect(hyphenate('-fooBar-man')).toEqual('-foo-bar-man'); }); - it('should make everything lowercase', - () => { expect(hyphenate('-WebkitAnimation')).toEqual('-webkit-animation'); }); + it('should make everything lowercase', () => { + expect(hyphenate('-WebkitAnimation')).toEqual('-webkit-animation'); + }); }); }); diff --git a/packages/compiler/test/render3/util/expression.ts b/packages/compiler/test/render3/util/expression.ts index 65de317e1f56a..30d7dafa054b8 100644 --- a/packages/compiler/test/render3/util/expression.ts +++ b/packages/compiler/test/render3/util/expression.ts @@ -15,7 +15,9 @@ type HumanizedExpressionSource = [string, AbsoluteSourceSpan]; class ExpressionSourceHumanizer extends e.RecursiveAstVisitor implements t.Visitor { result: HumanizedExpressionSource[] = []; - private recordAst(ast: e.AST) { this.result.push([unparse(ast), ast.sourceSpan]); } + private recordAst(ast: e.AST) { + this.result.push([unparse(ast), ast.sourceSpan]); + } // This method is defined to reconcile the type of ExpressionSourceHumanizer // since both RecursiveAstVisitor and Visitor define the visit() method in @@ -124,11 +126,19 @@ class ExpressionSourceHumanizer extends e.RecursiveAstVisitor implements t.Visit } visitReference(ast: t.Reference) {} visitVariable(ast: t.Variable) {} - visitEvent(ast: t.BoundEvent) { ast.handler.visit(this); } + visitEvent(ast: t.BoundEvent) { + ast.handler.visit(this); + } visitTextAttribute(ast: t.TextAttribute) {} - visitBoundAttribute(ast: t.BoundAttribute) { ast.value.visit(this); } - visitBoundEvent(ast: t.BoundEvent) { ast.handler.visit(this); } - visitBoundText(ast: t.BoundText) { ast.value.visit(this); } + visitBoundAttribute(ast: t.BoundAttribute) { + ast.value.visit(this); + } + visitBoundEvent(ast: t.BoundEvent) { + ast.handler.visit(this); + } + visitBoundText(ast: t.BoundText) { + ast.value.visit(this); + } visitContent(ast: t.Content) {} visitText(ast: t.Text) {} visitIcu(ast: t.Icu) {} diff --git a/packages/compiler/test/render3/view/binding_spec.ts b/packages/compiler/test/render3/view/binding_spec.ts index e47c57d18bb90..15cad85c71302 100644 --- a/packages/compiler/test/render3/view/binding_spec.ts +++ b/packages/compiler/test/render3/view/binding_spec.ts @@ -54,8 +54,9 @@ describe('t2 binding', () => { const binder = new R3TargetBinder(new SelectorMatcher<DirectiveMeta>()); const res = binder.bind({template: template.nodes}); - const itemBinding = (findExpression(template.nodes, '{{item.name}}') !as e.Interpolation) - .expressions[0] as e.PropertyRead; + const itemBinding = + (findExpression(template.nodes, '{{item.name}}')! as e.Interpolation).expressions[0] as + e.PropertyRead; const item = itemBinding.receiver; const itemTarget = res.getExpressionTarget(item); if (!(itemTarget instanceof a.Variable)) { @@ -64,7 +65,7 @@ describe('t2 binding', () => { expect(itemTarget.value).toBe('$implicit'); const itemTemplate = res.getTemplateOfSymbol(itemTarget); expect(itemTemplate).not.toBeNull(); - expect(res.getNestingLevel(itemTemplate !)).toBe(1); + expect(res.getNestingLevel(itemTemplate!)).toBe(1); }); it('should match directives when binding a simple template', () => { @@ -72,7 +73,7 @@ describe('t2 binding', () => { const binder = new R3TargetBinder(makeSelectorMatcher()); const res = binder.bind({template: template.nodes}); const tmpl = template.nodes[0] as a.Template; - const directives = res.getDirectivesOfNode(tmpl) !; + const directives = res.getDirectivesOfNode(tmpl)!; expect(directives).not.toBeNull(); expect(directives.length).toBe(1); expect(directives[0].name).toBe('NgFor'); @@ -92,7 +93,7 @@ describe('t2 binding', () => { const res = binder.bind({template: template.nodes}); const svgNode = template.nodes[0] as a.Element; const textNode = svgNode.children[0] as a.Element; - const directives = res.getDirectivesOfNode(textNode) !; + const directives = res.getDirectivesOfNode(textNode)!; expect(directives).not.toBeNull(); expect(directives.length).toBe(1); expect(directives[0].name).toBe('Dir'); @@ -103,11 +104,11 @@ describe('t2 binding', () => { const binder = new R3TargetBinder(makeSelectorMatcher()); const res = binder.bind({template: template.nodes}); const tmpl = template.nodes[0] as a.Template; - const tmplDirectives = res.getDirectivesOfNode(tmpl) !; + const tmplDirectives = res.getDirectivesOfNode(tmpl)!; expect(tmplDirectives).not.toBeNull(); expect(tmplDirectives.length).toBe(1); expect(tmplDirectives[0].name).toBe('NgFor'); - const elDirectives = res.getDirectivesOfNode(tmpl.children[0] as a.Element) !; + const elDirectives = res.getDirectivesOfNode(tmpl.children[0] as a.Element)!; expect(elDirectives).not.toBeNull(); expect(elDirectives.length).toBe(1); expect(elDirectives[0].name).toBe('Dir'); diff --git a/packages/compiler/test/render3/view/i18n_spec.ts b/packages/compiler/test/render3/view/i18n_spec.ts index afa377807527d..ffdb57fee19fe 100644 --- a/packages/compiler/test/render3/view/i18n_spec.ts +++ b/packages/compiler/test/render3/view/i18n_spec.ts @@ -21,7 +21,7 @@ import {formatI18nPlaceholderName} from '../../../src/render3/view/i18n/util'; import {parseR3 as parse} from './util'; const expressionParser = new Parser(new Lexer()); -const i18nOf = (element: t.Node & {i18n?: i18n.I18nMeta}) => element.i18n !; +const i18nOf = (element: t.Node&{i18n?: i18n.I18nMeta}) => element.i18n!; describe('I18nContext', () => { it('should support i18n content collection', () => { @@ -74,7 +74,7 @@ describe('I18nContext', () => { const [boundTextB, elementC, boundTextC] = (elementB as t.Element).children; // simulate I18nContext for a given template - const ctx = new I18nContext(1, o.variable('ctx'), 0, null, root.i18n !); + const ctx = new I18nContext(1, o.variable('ctx'), 0, null, root.i18n!); // set data for root ctx ctx.appendBoundText(i18nOf(boundTextA)); @@ -87,7 +87,7 @@ describe('I18nContext', () => { expect(ctx.isResolved).toBe(false); // create child context - const childCtx = ctx.forkChildContext(2, 1, (templateA as t.Template).i18n !); + const childCtx = ctx.forkChildContext(2, 1, (templateA as t.Template).i18n!); expect(childCtx.bindings.size).toBe(0); expect(childCtx.isRoot).toBe(false); @@ -116,11 +116,12 @@ describe('I18nContext', () => { const expected = new Map([ ['INTERPOLATION', '�0�'], ['START_TAG_DIV', '�#0�|�#1:1�'], ['START_BOLD_TEXT', '�*1:1��#0:1�'], ['CLOSE_BOLD_TEXT', '�/#0:1��/*1:1�'], - ['CLOSE_TAG_DIV', '�/#0�|�/#1:1�'], ['INTERPOLATION_1', '�0:1�'], - ['INTERPOLATION_2', '�1:1�'] + ['CLOSE_TAG_DIV', '�/#0�|�/#1:1�'], ['INTERPOLATION_1', '�0:1�'], ['INTERPOLATION_2', '�1:1�'] ]); const phs = ctx.getSerializedPlaceholders(); - expected.forEach((value, key) => { expect(phs.get(key) !.join('|')).toEqual(value); }); + expected.forEach((value, key) => { + expect(phs.get(key)!.join('|')).toEqual(value); + }); // placeholders are added into the root ctx expect(phs.size).toBe(expected.size); @@ -152,7 +153,7 @@ describe('I18nContext', () => { const [textC] = (templateB as t.Template).children; // simulate I18nContext for a given template - const ctxLevelA = new I18nContext(0, o.variable('ctx'), 0, null, root.i18n !); + const ctxLevelA = new I18nContext(0, o.variable('ctx'), 0, null, root.i18n!); // create Level A context ctxLevelA.appendTemplate(i18nOf(templateA), 1); @@ -160,12 +161,12 @@ describe('I18nContext', () => { expect(ctxLevelA.isResolved).toBe(false); // create Level B context - const ctxLevelB = ctxLevelA.forkChildContext(0, 1, (templateA as t.Template).i18n !); + const ctxLevelB = ctxLevelA.forkChildContext(0, 1, (templateA as t.Template).i18n!); ctxLevelB.appendTemplate(i18nOf(templateB), 1); expect(ctxLevelB.isRoot).toBe(false); // create Level 2 context - const ctxLevelC = ctxLevelB.forkChildContext(0, 1, (templateB as t.Template).i18n !); + const ctxLevelC = ctxLevelB.forkChildContext(0, 1, (templateB as t.Template).i18n!); expect(ctxLevelC.isRoot).toBe(false); // reconcile @@ -176,7 +177,9 @@ describe('I18nContext', () => { const expected = new Map( [['START_TAG_NG-TEMPLATE', '�*1:1�|�*1:2�'], ['CLOSE_TAG_NG-TEMPLATE', '�/*1:2�|�/*1:1�']]); const phs = ctxLevelA.getSerializedPlaceholders(); - expected.forEach((value, key) => { expect(phs.get(key) !.join('|')).toEqual(value); }); + expected.forEach((value, key) => { + expect(phs.get(key)!.join('|')).toEqual(value); + }); // placeholders are added into the root ctx expect(phs.size).toBe(expected.size); @@ -195,8 +198,9 @@ describe('Utils', () => { ['START_TAG_NG-CONTAINER_1', 'startTagNgContainer_1'], ['CLOSE_TAG_ITALIC', 'closeTagItalic'], ['CLOSE_TAG_BOLD_1', 'closeTagBold_1'] ]; - cases.forEach( - ([input, output]) => { expect(formatI18nPlaceholderName(input)).toEqual(output); }); + cases.forEach(([input, output]) => { + expect(formatI18nPlaceholderName(input)).toEqual(output); + }); }); describe('metadata serialization', () => { @@ -292,8 +296,9 @@ describe('serializeI18nMessageForGetMsg', () => { return serializeI18nMessageForGetMsg(root.i18n as i18n.Message); }; - it('should serialize plain text for `GetMsg()`', - () => { expect(serialize('Some text')).toEqual('Some text'); }); + it('should serialize plain text for `GetMsg()`', () => { + expect(serialize('Some text')).toEqual('Some text'); + }); it('should serialize text with interpolation for `GetMsg()`', () => { expect(serialize('Some text {{ valueA }} and {{ valueB + valueC }}')) diff --git a/packages/compiler/test/render3/view/util.ts b/packages/compiler/test/render3/view/util.ts index df1268fed95ba..0ecf3ab42d0f3 100644 --- a/packages/compiler/test/render3/view/util.ts +++ b/packages/compiler/test/render3/view/util.ts @@ -14,7 +14,7 @@ import {HtmlParser, ParseTreeResult} from '../../../src/ml_parser/html_parser'; import {WhitespaceVisitor} from '../../../src/ml_parser/html_whitespaces'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../src/ml_parser/interpolation_config'; import * as a from '../../../src/render3/r3_ast'; -import {Render3ParseResult, htmlAstToRender3Ast} from '../../../src/render3/r3_template_transform'; +import {htmlAstToRender3Ast, Render3ParseResult} from '../../../src/render3/r3_template_transform'; import {I18nMetaVisitor} from '../../../src/render3/view/i18n/meta'; import {BindingParser} from '../../../src/template_parser/binding_parser'; import {MockSchemaRegistry} from '../../../testing'; diff --git a/packages/compiler/test/resource_loader_mock_spec.ts b/packages/compiler/test/resource_loader_mock_spec.ts index 760ff5fce08d2..8df73f398fc0c 100644 --- a/packages/compiler/test/resource_loader_mock_spec.ts +++ b/packages/compiler/test/resource_loader_mock_spec.ts @@ -13,10 +13,12 @@ import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@ang describe('MockResourceLoader', () => { let resourceLoader: MockResourceLoader; - beforeEach(() => { resourceLoader = new MockResourceLoader(); }); + beforeEach(() => { + resourceLoader = new MockResourceLoader(); + }); function expectResponse( - request: Promise<string>, url: string, response: string, done: () => void = null !) { + request: Promise<string>, url: string, response: string, done: () => void = null!) { function onResponse(text: string): string { if (response === null) { throw `Unexpected response ${url} -> ${text}`; @@ -52,7 +54,7 @@ import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@ang it('should return an error from the definitions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const url = '/foo'; - const response: string = null !; + const response: string = null!; resourceLoader.when(url, response); expectResponse(resourceLoader.get(url), url, response, () => async.done()); resourceLoader.flush(); @@ -70,7 +72,7 @@ import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@ang it('should return an error from the expectations', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const url = '/foo'; - const response: string = null !; + const response: string = null!; resourceLoader.expect(url, response); expectResponse(resourceLoader.get(url), url, response, () => async.done()); resourceLoader.flush(); @@ -82,7 +84,9 @@ import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@ang resourceLoader.expect(url, response); resourceLoader.get(url); resourceLoader.get(url); - expect(() => { resourceLoader.flush(); }).toThrowError('Unexpected request /foo'); + expect(() => { + resourceLoader.flush(); + }).toThrowError('Unexpected request /foo'); }); it('should return expectations before definitions', @@ -97,18 +101,24 @@ import {AsyncTestCompleter, beforeEach, describe, expect, inject, it} from '@ang it('should throw when there is no definitions or expectations', () => { resourceLoader.get('/foo'); - expect(() => { resourceLoader.flush(); }).toThrowError('Unexpected request /foo'); + expect(() => { + resourceLoader.flush(); + }).toThrowError('Unexpected request /foo'); }); it('should throw when flush is called without any pending requests', () => { - expect(() => { resourceLoader.flush(); }).toThrowError('No pending requests to flush'); + expect(() => { + resourceLoader.flush(); + }).toThrowError('No pending requests to flush'); }); it('should throw on unsatisfied expectations', () => { resourceLoader.expect('/foo', 'bar'); resourceLoader.when('/bar', 'foo'); resourceLoader.get('/bar'); - expect(() => { resourceLoader.flush(); }).toThrowError('Unsatisfied requests: /foo'); + expect(() => { + resourceLoader.flush(); + }).toThrowError('Unsatisfied requests: /foo'); }); }); } diff --git a/packages/compiler/test/runtime_compiler_spec.ts b/packages/compiler/test/runtime_compiler_spec.ts index 47423395bd6fc..a66dfb3ccda2c 100644 --- a/packages/compiler/test/runtime_compiler_spec.ts +++ b/packages/compiler/test/runtime_compiler_spec.ts @@ -8,9 +8,11 @@ import {DirectiveResolver, ResourceLoader} from '@angular/compiler'; import {Compiler, Component, Injector, NgModule, NgModuleFactory, ɵstringify as stringify} from '@angular/core'; -import {TestBed, async, fakeAsync, inject, tick} from '@angular/core/testing'; +import {async, fakeAsync, inject, TestBed, tick} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; + import {MockDirectiveResolver} from '../testing'; + import {SpyResourceLoader} from './spies'; @Component({selector: 'child-cmp'}) @@ -27,11 +29,12 @@ class SomeCompWithUrlTemplate { { describe('RuntimeCompiler', () => { - describe('compilerComponentSync', () => { describe('never resolving loader', () => { class StubResourceLoader { - get(url: string) { return new Promise(() => {}); } + get(url: string) { + return new Promise(() => {}); + } } beforeEach(() => { @@ -43,8 +46,8 @@ class SomeCompWithUrlTemplate { TestBed.configureTestingModule({declarations: [SomeCompWithUrlTemplate]}); TestBed.compileComponents().then(() => { expect(() => TestBed.createComponent(SomeCompWithUrlTemplate)) - .toThrowError( - `Can't compile synchronously as ${stringify(SomeCompWithUrlTemplate)} is still being loaded!`); + .toThrowError(`Can't compile synchronously as ${ + stringify(SomeCompWithUrlTemplate)} is still being loaded!`); }); })); @@ -55,15 +58,17 @@ class SomeCompWithUrlTemplate { TestBed.overrideComponent(SomeComp, {set: {template: '<child-cmp></child-cmp>'}}); TestBed.compileComponents().then(() => { expect(() => TestBed.createComponent(SomeComp)) - .toThrowError( - `Can't compile synchronously as ${stringify(ChildComp)} is still being loaded!`); + .toThrowError(`Can't compile synchronously as ${ + stringify(ChildComp)} is still being loaded!`); }); }); }); describe('resolving loader', () => { class StubResourceLoader { - get(url: string) { return Promise.resolve('hello'); } + get(url: string) { + return Promise.resolve('hello'); + } } beforeEach(() => { @@ -88,7 +93,9 @@ class SomeCompWithUrlTemplate { let dirResolver: MockDirectiveResolver; let injector: Injector; - beforeEach(() => { TestBed.configureCompiler({providers: [SpyResourceLoader.PROVIDE]}); }); + beforeEach(() => { + TestBed.configureCompiler({providers: [SpyResourceLoader.PROVIDE]}); + }); beforeEach(fakeAsync(inject( [Compiler, ResourceLoader, DirectiveResolver, Injector], @@ -110,7 +117,7 @@ class SomeCompWithUrlTemplate { } resourceLoader.spy('get').and.callFake(() => Promise.resolve('hello')); - let ngModuleFactory: NgModuleFactory<any> = undefined !; + let ngModuleFactory: NgModuleFactory<any> = undefined!; compiler.compileModuleAsync(SomeModule).then((f) => ngModuleFactory = f); tick(); expect(ngModuleFactory.moduleType).toBe(SomeModule); @@ -126,8 +133,8 @@ class SomeCompWithUrlTemplate { resourceLoader.spy('get').and.callFake(() => Promise.resolve('')); expect(() => compiler.compileModuleSync(SomeModule)) - .toThrowError( - `Can't compile synchronously as ${stringify(SomeCompWithUrlTemplate)} is still being loaded!`); + .toThrowError(`Can't compile synchronously as ${ + stringify(SomeCompWithUrlTemplate)} is still being loaded!`); }); it('should throw when using a templateUrl in a nested component that has not been compiled before', diff --git a/packages/compiler/test/schema/dom_element_schema_registry_spec.ts b/packages/compiler/test/schema/dom_element_schema_registry_spec.ts index 7c6b98c67c4b7..ef2a312633d1f 100644 --- a/packages/compiler/test/schema/dom_element_schema_registry_spec.ts +++ b/packages/compiler/test/schema/dom_element_schema_registry_spec.ts @@ -19,7 +19,9 @@ import {extractSchema} from './schema_extractor'; { describe('DOMElementSchema', () => { let registry: DomElementSchemaRegistry; - beforeEach(() => { registry = new DomElementSchemaRegistry(); }); + beforeEach(() => { + registry = new DomElementSchemaRegistry(); + }); it('should detect elements', () => { expect(registry.hasElement('div', [])).toBeTruthy(); @@ -97,8 +99,9 @@ import {extractSchema} from './schema_extractor'; expect(registry.hasElement('unknown', [NO_ERRORS_SCHEMA])).toBeTruthy(); }); - it('should re-map property names that are specified in DOM facade', - () => { expect(registry.getMappedPropName('readonly')).toEqual('readOnly'); }); + it('should re-map property names that are specified in DOM facade', () => { + expect(registry.getMappedPropName('readonly')).toEqual('readOnly'); + }); it('should not re-map property names that are not specified in DOM facade', () => { expect(registry.getMappedPropName('title')).toEqual('title'); @@ -173,8 +176,9 @@ If 'onAnything' is a directive input, make sure the directive is imported by the }); describe('Angular custom elements', () => { - it('should support <ng-container>', - () => { expect(registry.hasProperty('ng-container', 'id', [])).toBeFalsy(); }); + it('should support <ng-container>', () => { + expect(registry.hasProperty('ng-container', 'id', [])).toBeFalsy(); + }); it('should support <ng-content>', () => { expect(registry.hasProperty('ng-content', 'id', [])).toBeFalsy(); @@ -185,8 +189,9 @@ If 'onAnything' is a directive input, make sure the directive is imported by the if (browserDetection.isChromeDesktop) { it('generate a new schema', () => { let schema = '\n'; - extractSchema() !.forEach( - (props, name) => { schema += `'${name}|${props.join(',')}',\n`; }); + extractSchema()!.forEach((props, name) => { + schema += `'${name}|${props.join(',')}',\n`; + }); // Uncomment this line to see: // the generated schema which can then be pasted to the DomElementSchemaRegistry // console.log(schema); diff --git a/packages/compiler/test/schema/schema_extractor.ts b/packages/compiler/test/schema/schema_extractor.ts index ec25bda11ba3a..27a9650d9161a 100644 --- a/packages/compiler/test/schema/schema_extractor.ts +++ b/packages/compiler/test/schema/schema_extractor.ts @@ -97,7 +97,9 @@ export function extractSchema(): Map<string, string[]>|null { types.sort(); - types.forEach(type => { extractRecursiveProperties(visited, descMap, (window as any)[type]); }); + types.forEach(type => { + extractRecursiveProperties(visited, descMap, (window as any)[type]); + }); // Add elements missed by Chrome auto-detection Object.keys(MISSING_FROM_CHROME).forEach(elHierarchy => { @@ -125,7 +127,7 @@ function assertNoMissingTags(descMap: Map<string, string[]>): void { function extractRecursiveProperties( visited: {[name: string]: boolean}, descMap: Map<string, string[]>, type: Function): string { - const name = extractName(type) !; + const name = extractName(type)!; if (visited[name]) { return name; @@ -181,7 +183,7 @@ function extractProperties( const fullName = name + (superName ? '^' + superName : ''); - const props: string[] = descMap.has(fullName) ? descMap.get(fullName) ! : []; + const props: string[] = descMap.has(fullName) ? descMap.get(fullName)! : []; const prototype = type.prototype; const keys = Object.getOwnPropertyNames(prototype); diff --git a/packages/compiler/test/selector/selector_spec.ts b/packages/compiler/test/selector/selector_spec.ts index b61bc7ad44dd1..33ecbe686a6fd 100644 --- a/packages/compiler/test/selector/selector_spec.ts +++ b/packages/compiler/test/selector/selector_spec.ts @@ -17,13 +17,16 @@ import {el} from '@angular/platform-browser/testing/src/browser_util'; let s1: any[], s2: any[], s3: any[], s4: any[]; let matched: any[]; - function reset() { matched = []; } + function reset() { + matched = []; + } beforeEach(() => { reset(); - s1 = s2 = s3 = s4 = null !; - selectableCollector = - (selector: CssSelector, context: any) => { matched.push(selector, context); }; + s1 = s2 = s3 = s4 = null!; + selectableCollector = (selector: CssSelector, context: any) => { + matched.push(selector, context); + }; matcher = new SelectorMatcher(); }); @@ -128,7 +131,7 @@ import {el} from '@angular/platform-browser/testing/src/browser_util'; const elementSelector = new CssSelector(); const element = el('<div attr></div>'); - const empty = element.getAttribute('attr') !; + const empty = element.getAttribute('attr')!; elementSelector.addAttribute('some-decor', empty); matcher.match(elementSelector, selectableCollector); expect(matched).toEqual([s1[0], 1]); @@ -458,9 +461,13 @@ function getSelectorFor( const selector = new CssSelector(); selector.setElement(tag); - attrs.forEach(nameValue => { selector.addAttribute(nameValue[0], nameValue[1]); }); + attrs.forEach(nameValue => { + selector.addAttribute(nameValue[0], nameValue[1]); + }); - classes.trim().split(/\s+/g).forEach(cName => { selector.addClassName(cName); }); + classes.trim().split(/\s+/g).forEach(cName => { + selector.addClassName(cName); + }); return selector; } diff --git a/packages/compiler/test/shadow_css_spec.ts b/packages/compiler/test/shadow_css_spec.ts index 8bf0cd85e266a..e23e7e28aa52f 100644 --- a/packages/compiler/test/shadow_css_spec.ts +++ b/packages/compiler/test/shadow_css_spec.ts @@ -6,12 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {CssRule, ShadowCss, processRules} from '@angular/compiler/src/shadow_css'; +import {CssRule, processRules, ShadowCss} from '@angular/compiler/src/shadow_css'; import {normalizeCSS} from '@angular/platform-browser/testing/src/browser_util'; { describe('ShadowCss', function() { - function s(css: string, contentAttr: string, hostAttr: string = '') { const shadowCss = new ShadowCss(); const shim = shadowCss.shimCssText(css, contentAttr, hostAttr); @@ -19,7 +18,9 @@ import {normalizeCSS} from '@angular/platform-browser/testing/src/browser_util'; return normalizeCSS(shim.replace(nlRegexp, '')); } - it('should handle empty string', () => { expect(s('', 'contenta')).toEqual(''); }); + it('should handle empty string', () => { + expect(s('', 'contenta')).toEqual(''); + }); it('should add an attribute to every rule', () => { const css = 'one {color: red;}two {color: red;}'; @@ -112,14 +113,17 @@ import {normalizeCSS} from '@angular/platform-browser/testing/src/browser_util'; }); describe((':host'), () => { - it('should handle no context', - () => { expect(s(':host {}', 'contenta', 'a-host')).toEqual('[a-host] {}'); }); + it('should handle no context', () => { + expect(s(':host {}', 'contenta', 'a-host')).toEqual('[a-host] {}'); + }); - it('should handle tag selector', - () => { expect(s(':host(ul) {}', 'contenta', 'a-host')).toEqual('ul[a-host] {}'); }); + it('should handle tag selector', () => { + expect(s(':host(ul) {}', 'contenta', 'a-host')).toEqual('ul[a-host] {}'); + }); - it('should handle class selector', - () => { expect(s(':host(.x) {}', 'contenta', 'a-host')).toEqual('.x[a-host] {}'); }); + it('should handle class selector', () => { + expect(s(':host(.x) {}', 'contenta', 'a-host')).toEqual('.x[a-host] {}'); + }); it('should handle attribute selector', () => { expect(s(':host([a="b"]) {}', 'contenta', 'a-host')).toEqual('[a="b"][a-host] {}'); @@ -285,14 +289,17 @@ import {normalizeCSS} from '@angular/platform-browser/testing/src/browser_util'; expect(css).toEqual('div[contenta] {height:calc(100% - 55px);}'); }); - it('should strip comments', - () => { expect(s('/* x */b {c}', 'contenta')).toEqual('b[contenta] {c}'); }); + it('should strip comments', () => { + expect(s('/* x */b {c}', 'contenta')).toEqual('b[contenta] {c}'); + }); - it('should ignore special characters in comments', - () => { expect(s('/* {;, */b {c}', 'contenta')).toEqual('b[contenta] {c}'); }); + it('should ignore special characters in comments', () => { + expect(s('/* {;, */b {c}', 'contenta')).toEqual('b[contenta] {c}'); + }); - it('should support multiline comments', - () => { expect(s('/* \n */b {c}', 'contenta')).toEqual('b[contenta] {c}'); }); + it('should support multiline comments', () => { + expect(s('/* \n */b {c}', 'contenta')).toEqual('b[contenta] {c}'); + }); it('should keep sourceMappingURL comments', () => { expect(s('b {c}/*# sourceMappingURL=data:x */', 'contenta')) @@ -318,13 +325,17 @@ import {normalizeCSS} from '@angular/platform-browser/testing/src/browser_util'; return result; } - it('should work with empty css', () => { expect(captureRules('')).toEqual([]); }); + it('should work with empty css', () => { + expect(captureRules('')).toEqual([]); + }); - it('should capture a rule without body', - () => { expect(captureRules('a;')).toEqual([new CssRule('a', '')]); }); + it('should capture a rule without body', () => { + expect(captureRules('a;')).toEqual([new CssRule('a', '')]); + }); - it('should capture css rules with body', - () => { expect(captureRules('a {b}')).toEqual([new CssRule('a', 'b')]); }); + it('should capture css rules with body', () => { + expect(captureRules('a {b}')).toEqual([new CssRule('a', 'b')]); + }); it('should capture css rules with nested rules', () => { expect(captureRules('a {b {c}} d {e}')).toEqual([ diff --git a/packages/compiler/test/spies.ts b/packages/compiler/test/spies.ts index 54c2263c4ad9f..a5575dffb2dd7 100644 --- a/packages/compiler/test/spies.ts +++ b/packages/compiler/test/spies.ts @@ -12,5 +12,7 @@ import {SpyObject} from '@angular/core/testing/src/testing_internal'; export class SpyResourceLoader extends SpyObject { public static PROVIDE = {provide: ResourceLoader, useClass: SpyResourceLoader, deps: []}; - constructor() { super(ResourceLoader); } + constructor() { + super(ResourceLoader); + } } diff --git a/packages/compiler/test/style_url_resolver_spec.ts b/packages/compiler/test/style_url_resolver_spec.ts index ef8aebdb5c6ff..c91f3cc6874cf 100644 --- a/packages/compiler/test/style_url_resolver_spec.ts +++ b/packages/compiler/test/style_url_resolver_spec.ts @@ -13,7 +13,9 @@ import {UrlResolver} from '@angular/compiler/src/url_resolver'; describe('extractStyleUrls', () => { let urlResolver: UrlResolver; - beforeEach(() => { urlResolver = new UrlResolver(); }); + beforeEach(() => { + urlResolver = new UrlResolver(); + }); it('should not resolve "url()" urls', () => { const css = ` @@ -104,23 +106,25 @@ import {UrlResolver} from '@angular/compiler/src/url_resolver'; expect(styleWithImports.style.trim()).toEqual(``); expect(styleWithImports.styleUrls).toEqual(['fake_resolved_url']); }); - }); describe('isStyleUrlResolvable', () => { - it('should resolve relative urls', - () => { expect(isStyleUrlResolvable('someUrl.css')).toBe(true); }); + it('should resolve relative urls', () => { + expect(isStyleUrlResolvable('someUrl.css')).toBe(true); + }); - it('should resolve package: urls', - () => { expect(isStyleUrlResolvable('package:someUrl.css')).toBe(true); }); + it('should resolve package: urls', () => { + expect(isStyleUrlResolvable('package:someUrl.css')).toBe(true); + }); it('should not resolve empty urls', () => { - expect(isStyleUrlResolvable(null !)).toBe(false); + expect(isStyleUrlResolvable(null!)).toBe(false); expect(isStyleUrlResolvable('')).toBe(false); }); - it('should not resolve urls with other schema', - () => { expect(isStyleUrlResolvable('http://otherurl')).toBe(false); }); + it('should not resolve urls with other schema', () => { + expect(isStyleUrlResolvable('http://otherurl')).toBe(false); + }); it('should not resolve urls with absolute paths', () => { expect(isStyleUrlResolvable('/otherurl')).toBe(false); @@ -130,7 +134,11 @@ import {UrlResolver} from '@angular/compiler/src/url_resolver'; } class FakeUrlResolver extends UrlResolver { - constructor() { super(); } + constructor() { + super(); + } - resolve(baseUrl: string, url: string): string { return 'fake_resolved_url'; } + resolve(baseUrl: string, url: string): string { + return 'fake_resolved_url'; + } } diff --git a/packages/compiler/test/template_parser/binding_parser_spec.ts b/packages/compiler/test/template_parser/binding_parser_spec.ts index 77656c6bc4884..0d4f737203d82 100644 --- a/packages/compiler/test/template_parser/binding_parser_spec.ts +++ b/packages/compiler/test/template_parser/binding_parser_spec.ts @@ -16,16 +16,18 @@ import {calcPossibleSecurityContexts} from '../../src/template_parser/binding_pa describe('BindingParser', () => { let registry: ElementSchemaRegistry; - beforeEach(inject( - [ElementSchemaRegistry], (_registry: ElementSchemaRegistry) => { registry = _registry; })); + beforeEach(inject([ElementSchemaRegistry], (_registry: ElementSchemaRegistry) => { + registry = _registry; + })); describe('possibleSecurityContexts', () => { function hrefSecurityContexts(selector: string) { return calcPossibleSecurityContexts(registry, selector, 'href', false); } - it('should return a single security context if the selector as an element name', - () => { expect(hrefSecurityContexts('a')).toEqual([SecurityContext.URL]); }); + it('should return a single security context if the selector as an element name', () => { + expect(hrefSecurityContexts('a')).toEqual([SecurityContext.URL]); + }); it('should return the possible security contexts if the selector has no element name', () => { expect(hrefSecurityContexts('[myDir]')).toEqual([ @@ -45,8 +47,9 @@ import {calcPossibleSecurityContexts} from '../../src/template_parser/binding_pa ]); }); - it('should return SecurityContext.NONE if there are no possible elements', - () => { expect(hrefSecurityContexts('img:not(img)')).toEqual([SecurityContext.NONE]); }); + it('should return SecurityContext.NONE if there are no possible elements', () => { + expect(hrefSecurityContexts('img:not(img)')).toEqual([SecurityContext.NONE]); + }); it('should return the union of the possible security contexts if multiple selectors are specified', () => { diff --git a/packages/compiler/test/template_parser/template_parser_absolute_span_spec.ts b/packages/compiler/test/template_parser/template_parser_absolute_span_spec.ts index ca2b1b3ad8a67..7547490e5b44f 100644 --- a/packages/compiler/test/template_parser/template_parser_absolute_span_spec.ts +++ b/packages/compiler/test/template_parser/template_parser_absolute_span_spec.ts @@ -36,7 +36,7 @@ describe('expression AST absolute source spans', () => { beforeEach(inject([TemplateParser], (parser: TemplateParser) => { parse = (template: string, directives: CompileDirectiveSummary[] = [], - pipes: CompilePipeSummary[] | null = null, schemas: SchemaMetadata[] = [], + pipes: CompilePipeSummary[]|null = null, schemas: SchemaMetadata[] = [], preserveWhitespaces = true): TemplateAst[] => { if (pipes === null) { pipes = []; diff --git a/packages/compiler/test/template_parser/template_parser_spec.ts b/packages/compiler/test/template_parser/template_parser_spec.ts index af03ee7ca72c8..2b5c8498e1283 100644 --- a/packages/compiler/test/template_parser/template_parser_spec.ts +++ b/packages/compiler/test/template_parser/template_parser_spec.ts @@ -9,19 +9,20 @@ import {preserveWhitespacesDefault} from '@angular/compiler'; import {CompileDiDependencyMetadata, CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeMetadata, CompilePipeSummary, CompileProviderMetadata, CompileTemplateMetadata, CompileTokenMetadata, tokenReference} from '@angular/compiler/src/compile_metadata'; import {DomElementSchemaRegistry} from '@angular/compiler/src/schema/dom_element_schema_registry'; import {ElementSchemaRegistry} from '@angular/compiler/src/schema/element_schema_registry'; -import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAstType, ReferenceAst, TemplateAst, TemplateAstVisitor, TextAst, VariableAst, templateVisitAll} from '@angular/compiler/src/template_parser/template_ast'; -import {TemplateParser, splitClasses} from '@angular/compiler/src/template_parser/template_parser'; +import {AttrAst, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, DirectiveAst, ElementAst, EmbeddedTemplateAst, NgContentAst, PropertyBindingType, ProviderAstType, ReferenceAst, TemplateAst, TemplateAstVisitor, templateVisitAll, TextAst, VariableAst} from '@angular/compiler/src/template_parser/template_ast'; +import {splitClasses, TemplateParser} from '@angular/compiler/src/template_parser/template_parser'; import {SchemaMetadata, SecurityContext} from '@angular/core'; import {Console} from '@angular/core/src/console'; -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from '@angular/core/testing'; import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector'; -import {Identifiers, createTokenForExternalReference, createTokenForReference} from '../../src/identifiers'; +import {createTokenForExternalReference, createTokenForReference, Identifiers} from '../../src/identifiers'; import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../src/ml_parser/interpolation_config'; import {newArray} from '../../src/util'; import {MockSchemaRegistry} from '../../testing'; import {unparse} from '../expression_parser/utils/unparser'; import {TEST_COMPILER_PROVIDERS} from '../test_bindings'; + import {compileDirectiveMetadataCreate, compileTemplateMetadata, createTypeMeta} from './util/metadata'; const someModuleUrl = 'package:someModule'; @@ -139,7 +140,7 @@ class TemplateHumanizer implements TemplateAstVisitor { private _appendSourceSpan(ast: TemplateAst, input: any[]): any[] { if (!this.includeSourceSpan) return input; - input.push(ast.sourceSpan !.toString()); + input.push(ast.sourceSpan!.toString()); return input; } } @@ -166,11 +167,21 @@ class TemplateContentProjectionHumanizer implements TemplateAstVisitor { templateVisitAll(this, ast.children); return null; } - visitReference(ast: ReferenceAst, context: any): any { return null; } - visitVariable(ast: VariableAst, context: any): any { return null; } - visitEvent(ast: BoundEventAst, context: any): any { return null; } - visitElementProperty(ast: BoundElementPropertyAst, context: any): any { return null; } - visitAttr(ast: AttrAst, context: any): any { return null; } + visitReference(ast: ReferenceAst, context: any): any { + return null; + } + visitVariable(ast: VariableAst, context: any): any { + return null; + } + visitEvent(ast: BoundEventAst, context: any): any { + return null; + } + visitElementProperty(ast: BoundElementPropertyAst, context: any): any { + return null; + } + visitAttr(ast: AttrAst, context: any): any { + return null; + } visitBoundText(ast: BoundTextAst, context: any): any { this.result.push([`#text(${unparse(ast.value)})`, ast.ngContentIndex]); return null; @@ -179,22 +190,48 @@ class TemplateContentProjectionHumanizer implements TemplateAstVisitor { this.result.push([`#text(${ast.value})`, ast.ngContentIndex]); return null; } - visitDirective(ast: DirectiveAst, context: any): any { return null; } - visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { return null; } + visitDirective(ast: DirectiveAst, context: any): any { + return null; + } + visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { + return null; + } } class ThrowingVisitor implements TemplateAstVisitor { - visitNgContent(ast: NgContentAst, context: any): any { throw 'not implemented'; } - visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { throw 'not implemented'; } - visitElement(ast: ElementAst, context: any): any { throw 'not implemented'; } - visitReference(ast: ReferenceAst, context: any): any { throw 'not implemented'; } - visitVariable(ast: VariableAst, context: any): any { throw 'not implemented'; } - visitEvent(ast: BoundEventAst, context: any): any { throw 'not implemented'; } - visitElementProperty(ast: BoundElementPropertyAst, context: any): any { throw 'not implemented'; } - visitAttr(ast: AttrAst, context: any): any { throw 'not implemented'; } - visitBoundText(ast: BoundTextAst, context: any): any { throw 'not implemented'; } - visitText(ast: TextAst, context: any): any { throw 'not implemented'; } - visitDirective(ast: DirectiveAst, context: any): any { throw 'not implemented'; } + visitNgContent(ast: NgContentAst, context: any): any { + throw 'not implemented'; + } + visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { + throw 'not implemented'; + } + visitElement(ast: ElementAst, context: any): any { + throw 'not implemented'; + } + visitReference(ast: ReferenceAst, context: any): any { + throw 'not implemented'; + } + visitVariable(ast: VariableAst, context: any): any { + throw 'not implemented'; + } + visitEvent(ast: BoundEventAst, context: any): any { + throw 'not implemented'; + } + visitElementProperty(ast: BoundElementPropertyAst, context: any): any { + throw 'not implemented'; + } + visitAttr(ast: AttrAst, context: any): any { + throw 'not implemented'; + } + visitBoundText(ast: BoundTextAst, context: any): any { + throw 'not implemented'; + } + visitText(ast: TextAst, context: any): any { + throw 'not implemented'; + } + visitDirective(ast: DirectiveAst, context: any): any { + throw 'not implemented'; + } visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { throw 'not implemented'; } @@ -236,2014 +273,2012 @@ class NullVisitor implements TemplateAstVisitor { class ArrayConsole implements Console { logs: string[] = []; warnings: string[] = []; - log(msg: string) { this.logs.push(msg); } - warn(msg: string) { this.warnings.push(msg); } + log(msg: string) { + this.logs.push(msg); + } + warn(msg: string) { + this.warnings.push(msg); + } } (function() { - let ngIf: CompileDirectiveSummary; - let parse: ( - template: string, directives: CompileDirectiveSummary[], pipes?: CompilePipeSummary[], - schemas?: SchemaMetadata[], preserveWhitespaces?: boolean) => TemplateAst[]; - let console: ArrayConsole; - - function configureCompiler() { - console = new ArrayConsole(); - beforeEach(() => { - TestBed.configureCompiler({ - providers: [ - {provide: Console, useValue: console}, - ], - }); +let ngIf: CompileDirectiveSummary; +let parse: ( + template: string, directives: CompileDirectiveSummary[], pipes?: CompilePipeSummary[], + schemas?: SchemaMetadata[], preserveWhitespaces?: boolean) => TemplateAst[]; +let console: ArrayConsole; + +function configureCompiler() { + console = new ArrayConsole(); + beforeEach(() => { + TestBed.configureCompiler({ + providers: [ + {provide: Console, useValue: console}, + ], }); - } + }); +} - function commonBeforeEach() { - beforeEach(inject([TemplateParser], (parser: TemplateParser) => { - const someAnimation = ['someAnimation']; - const someTemplate = compileTemplateMetadata({animations: [someAnimation]}); - const component = compileDirectiveMetadataCreate({ - isHost: false, - selector: 'root', - template: someTemplate, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Root'}}), - isComponent: true - }); - ngIf = compileDirectiveMetadataCreate({ - selector: '[ngIf]', - template: someTemplate, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'NgIf'}}), - inputs: ['ngIf'] - }).toSummary(); - - parse = - (template: string, directives: CompileDirectiveSummary[], - pipes: CompilePipeSummary[] | null = null, schemas: SchemaMetadata[] = [], - preserveWhitespaces = true): TemplateAst[] => { - if (pipes === null) { - pipes = []; - } - return parser - .parse( - component, template, directives, pipes, schemas, 'TestComp', - preserveWhitespaces) - .template; - }; - })); - } +function commonBeforeEach() { + beforeEach(inject([TemplateParser], (parser: TemplateParser) => { + const someAnimation = ['someAnimation']; + const someTemplate = compileTemplateMetadata({animations: [someAnimation]}); + const component = compileDirectiveMetadataCreate({ + isHost: false, + selector: 'root', + template: someTemplate, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Root'}}), + isComponent: true + }); + ngIf = compileDirectiveMetadataCreate({ + selector: '[ngIf]', + template: someTemplate, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'NgIf'}}), + inputs: ['ngIf'] + }).toSummary(); + + parse = + (template: string, directives: CompileDirectiveSummary[], + pipes: CompilePipeSummary[]|null = null, schemas: SchemaMetadata[] = [], + preserveWhitespaces = true): TemplateAst[] => { + if (pipes === null) { + pipes = []; + } + return parser + .parse( + component, template, directives, pipes, schemas, 'TestComp', preserveWhitespaces) + .template; + }; + })); +} - describe('TemplateAstVisitor', () => { - function expectVisitedNode(visitor: TemplateAstVisitor, node: TemplateAst) { - expect(node.visit(visitor, null)).toEqual(node); - } +describe('TemplateAstVisitor', () => { + function expectVisitedNode(visitor: TemplateAstVisitor, node: TemplateAst) { + expect(node.visit(visitor, null)).toEqual(node); + } - it('should visit NgContentAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitNgContent(ast: NgContentAst, context: any): any{return ast;}}, - new NgContentAst(0, 0, null !)); - }); + it('should visit NgContentAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitNgContent(ast: NgContentAst, context: any): any { + return ast; + } + }, new NgContentAst(0, 0, null!)); + }); - it('should visit EmbeddedTemplateAst', () => { - expectVisitedNode( - new class extends NullVisitor{ - visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any) { return ast; } - }, - new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null !)); - }); + it('should visit EmbeddedTemplateAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any) { + return ast; + } + }, new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null!)); + }); - it('should visit ElementAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitElement(ast: ElementAst, context: any) { return ast; }}, - new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null !, null !)); - }); + it('should visit ElementAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitElement(ast: ElementAst, context: any) { + return ast; + } + }, new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null!, null!)); + }); - it('should visit RefererenceAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitReference(ast: ReferenceAst, context: any): any{return ast;}}, - new ReferenceAst('foo', null !, null !, null !)); - }); + it('should visit RefererenceAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitReference(ast: ReferenceAst, context: any): any { + return ast; + } + }, new ReferenceAst('foo', null!, null!, null!)); + }); - it('should visit VariableAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitVariable(ast: VariableAst, context: any): any{return ast;}}, - new VariableAst('foo', 'bar', null !)); - }); + it('should visit VariableAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitVariable(ast: VariableAst, context: any): any { + return ast; + } + }, new VariableAst('foo', 'bar', null!)); + }); - it('should visit BoundEventAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitEvent(ast: BoundEventAst, context: any): any{return ast;}}, - new BoundEventAst('foo', 'bar', 'goo', null !, null !, null !)); - }); + it('should visit BoundEventAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitEvent(ast: BoundEventAst, context: any): any { + return ast; + } + }, new BoundEventAst('foo', 'bar', 'goo', null!, null!, null!)); + }); - it('should visit BoundElementPropertyAst', () => { - expectVisitedNode( - new class extends NullVisitor{ - visitElementProperty(ast: BoundElementPropertyAst, context: any): any{return ast;} - }, - new BoundElementPropertyAst('foo', null !, null !, null !, 'bar', null !)); - }); + it('should visit BoundElementPropertyAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitElementProperty(ast: BoundElementPropertyAst, context: any): any { + return ast; + } + }, new BoundElementPropertyAst('foo', null!, null!, null!, 'bar', null!)); + }); - it('should visit AttrAst', () => { - expectVisitedNode( - new class extends NullVisitor{visitAttr(ast: AttrAst, context: any): any{return ast;}}, - new AttrAst('foo', 'bar', null !)); - }); + it('should visit AttrAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitAttr(ast: AttrAst, context: any): any { + return ast; + } + }, new AttrAst('foo', 'bar', null!)); + }); - it('should visit BoundTextAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitBoundText(ast: BoundTextAst, context: any): any{return ast;}}, - new BoundTextAst(null !, 0, null !)); - }); + it('should visit BoundTextAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitBoundText(ast: BoundTextAst, context: any): any { + return ast; + } + }, new BoundTextAst(null!, 0, null!)); + }); - it('should visit TextAst', () => { - expectVisitedNode( - new class extends NullVisitor{visitText(ast: TextAst, context: any): any{return ast;}}, - new TextAst('foo', 0, null !)); - }); + it('should visit TextAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitText(ast: TextAst, context: any): any { + return ast; + } + }, new TextAst('foo', 0, null!)); + }); - it('should visit DirectiveAst', () => { - expectVisitedNode( - new class extends - NullVisitor{visitDirective(ast: DirectiveAst, context: any): any{return ast;}}, - new DirectiveAst(null !, [], [], [], 0, null !)); - }); + it('should visit DirectiveAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitDirective(ast: DirectiveAst, context: any): any { + return ast; + } + }, new DirectiveAst(null!, [], [], [], 0, null!)); + }); - it('should visit DirectiveAst', () => { - expectVisitedNode( - new class extends NullVisitor{ - visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any{return ast;} - }, - new BoundDirectivePropertyAst('foo', 'bar', null !, null !)); - }); + it('should visit DirectiveAst', () => { + expectVisitedNode(new class extends NullVisitor { + visitDirectiveProperty(ast: BoundDirectivePropertyAst, context: any): any { + return ast; + } + }, new BoundDirectivePropertyAst('foo', 'bar', null!, null!)); + }); - it('should skip the typed call of a visitor if visit() returns a truthy value', () => { - const visitor = new class extends ThrowingVisitor { - visit(ast: TemplateAst, context: any): any { return true; } - }; - const nodes: TemplateAst[] = [ - new NgContentAst(0, 0, null !), - new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null !), - new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null !, null !), - new ReferenceAst('foo', null !, 'bar', null !), new VariableAst('foo', 'bar', null !), - new BoundEventAst('foo', 'bar', 'goo', null !, null !, null !), - new BoundElementPropertyAst('foo', null !, null !, null !, 'bar', null !), - new AttrAst('foo', 'bar', null !), new BoundTextAst(null !, 0, null !), - new TextAst('foo', 0, null !), new DirectiveAst(null !, [], [], [], 0, null !), - new BoundDirectivePropertyAst('foo', 'bar', null !, null !) - ]; - const result = templateVisitAll(visitor, nodes, null); - expect(result).toEqual(newArray(nodes.length).fill(true)); + it('should skip the typed call of a visitor if visit() returns a truthy value', () => { + const visitor = new class extends ThrowingVisitor { + visit(ast: TemplateAst, context: any): any { + return true; + } + }; + const nodes: TemplateAst[] = [ + new NgContentAst(0, 0, null!), + new EmbeddedTemplateAst([], [], [], [], [], [], false, [], [], 0, null!), + new ElementAst('foo', [], [], [], [], [], [], false, [], [], 0, null!, null!), + new ReferenceAst('foo', null!, 'bar', null!), new VariableAst('foo', 'bar', null!), + new BoundEventAst('foo', 'bar', 'goo', null!, null!, null!), + new BoundElementPropertyAst('foo', null!, null!, null!, 'bar', null!), + new AttrAst('foo', 'bar', null!), new BoundTextAst(null!, 0, null!), + new TextAst('foo', 0, null!), new DirectiveAst(null!, [], [], [], 0, null!), + new BoundDirectivePropertyAst('foo', 'bar', null!, null!) + ]; + const result = templateVisitAll(visitor, nodes, null); + expect(result).toEqual(newArray(nodes.length).fill(true)); + }); +}); + +describe('TemplateParser Security', () => { + // Semi-integration test to make sure TemplateParser properly sets the security context. + // Uses the actual DomElementSchemaRegistry. + beforeEach(() => { + TestBed.configureCompiler({ + providers: [ + TEST_COMPILER_PROVIDERS, + {provide: ElementSchemaRegistry, useClass: DomElementSchemaRegistry, deps: []} + ] }); }); - describe('TemplateParser Security', () => { - // Semi-integration test to make sure TemplateParser properly sets the security context. - // Uses the actual DomElementSchemaRegistry. - beforeEach(() => { - TestBed.configureCompiler({ - providers: [ - TEST_COMPILER_PROVIDERS, - {provide: ElementSchemaRegistry, useClass: DomElementSchemaRegistry, deps: []} - ] - }); + configureCompiler(); + commonBeforeEach(); + + describe('security context', () => { + function secContext(tpl: string): SecurityContext { + const ast = parse(tpl, []); + const propBinding = (<ElementAst>ast[0]).inputs[0]; + return propBinding.securityContext; + } + + it('should set for properties', () => { + expect(secContext('<div [title]="v">')).toBe(SecurityContext.NONE); + expect(secContext('<div [innerHTML]="v">')).toBe(SecurityContext.HTML); + }); + it('should set for property value bindings', () => { + expect(secContext('<div innerHTML="{{v}}">')).toBe(SecurityContext.HTML); + }); + it('should set for attributes', () => { + expect(secContext('<a [attr.href]="v">')).toBe(SecurityContext.URL); + // NB: attributes below need to change case. + expect(secContext('<a [attr.innerHtml]="v">')).toBe(SecurityContext.HTML); + expect(secContext('<a [attr.formaction]="v">')).toBe(SecurityContext.URL); + }); + it('should set for style', () => { + expect(secContext('<a [style.backgroundColor]="v">')).toBe(SecurityContext.STYLE); }); + }); +}); - configureCompiler(); - commonBeforeEach(); +describe('TemplateParser', () => { + beforeEach(() => { + TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]}); + }); - describe('security context', () => { - function secContext(tpl: string): SecurityContext { - const ast = parse(tpl, []); - const propBinding = (<ElementAst>ast[0]).inputs[0]; - return propBinding.securityContext; - } + configureCompiler(); + commonBeforeEach(); - it('should set for properties', () => { - expect(secContext('<div [title]="v">')).toBe(SecurityContext.NONE); - expect(secContext('<div [innerHTML]="v">')).toBe(SecurityContext.HTML); - }); - it('should set for property value bindings', - () => { expect(secContext('<div innerHTML="{{v}}">')).toBe(SecurityContext.HTML); }); - it('should set for attributes', () => { - expect(secContext('<a [attr.href]="v">')).toBe(SecurityContext.URL); - // NB: attributes below need to change case. - expect(secContext('<a [attr.innerHtml]="v">')).toBe(SecurityContext.HTML); - expect(secContext('<a [attr.formaction]="v">')).toBe(SecurityContext.URL); + describe('parse', () => { + describe('nodes without bindings', () => { + it('should parse text nodes', () => { + expect(humanizeTplAst(parse('a', []))).toEqual([[TextAst, 'a']]); }); - it('should set for style', () => { - expect(secContext('<a [style.backgroundColor]="v">')).toBe(SecurityContext.STYLE); + + it('should parse elements with attributes', () => { + expect(humanizeTplAst(parse('<div a=b>', []))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'a', 'b'] + ]); }); }); - }); - describe('TemplateParser', () => { - beforeEach(() => { - TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]}); + it('should parse ngContent', () => { + const parsed = parse('<ng-content select="a"></ng-content>', []); + expect(humanizeTplAst(parsed)).toEqual([[NgContentAst]]); }); - configureCompiler(); - commonBeforeEach(); + it('should parse ngContent when it contains WS only', () => { + const parsed = parse('<ng-content select="a"> \n </ng-content>', []); + expect(humanizeTplAst(parsed)).toEqual([[NgContentAst]]); + }); - describe('parse', () => { - describe('nodes without bindings', () => { + it('should parse ngContent regardless the namespace', () => { + const parsed = parse('<svg><ng-content></ng-content></svg>', []); + expect(humanizeTplAst(parsed)).toEqual([ + [ElementAst, ':svg:svg'], + [NgContentAst], + ]); + }); - it('should parse text nodes', () => { - expect(humanizeTplAst(parse('a', []))).toEqual([[TextAst, 'a']]); - }); + it('should parse bound text nodes', () => { + expect(humanizeTplAst(parse('{{a}}', []))).toEqual([[BoundTextAst, '{{ a }}']]); + }); - it('should parse elements with attributes', () => { - expect(humanizeTplAst(parse('<div a=b>', [ - ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'a', 'b']]); - }); - }); + it('should parse with custom interpolation config', + inject([TemplateParser], (parser: TemplateParser) => { + const component = CompileDirectiveMetadata.create({ + selector: 'test', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Test'}}), + isComponent: true, + template: new CompileTemplateMetadata({ + interpolation: ['{%', '%}'], + isInline: false, + animations: [], + template: null, + templateUrl: null, + htmlAst: null, + ngContentSelectors: [], + externalStylesheets: [], + styleUrls: [], + styles: [], + encapsulation: null, + preserveWhitespaces: preserveWhitespacesDefault(null), + }), + isHost: false, + exportAs: null, + changeDetection: null, + inputs: [], + outputs: [], + host: {}, + providers: [], + viewProviders: [], + queries: [], + guards: {}, + viewQueries: [], + entryComponents: [], + componentViewType: null, + rendererType: null, + componentFactory: null - it('should parse ngContent', () => { - const parsed = parse('<ng-content select="a"></ng-content>', []); - expect(humanizeTplAst(parsed)).toEqual([[NgContentAst]]); + }); + expect(humanizeTplAst( + parser.parse(component, '{%a%}', [], [], [], 'TestComp', true).template, + {start: '{%', end: '%}'})) + .toEqual([[BoundTextAst, '{% a %}']]); + })); + + describe('bound properties', () => { + it('should parse mixed case bound properties', () => { + expect(humanizeTplAst(parse('<div [someProp]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'someProp', 'v', null] + ]); }); - it('should parse ngContent when it contains WS only', () => { - const parsed = parse('<ng-content select="a"> \n </ng-content>', []); - expect(humanizeTplAst(parsed)).toEqual([[NgContentAst]]); + it('should parse dash case bound properties', () => { + expect(humanizeTplAst(parse('<div [some-prop]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'some-prop', 'v', null] + ]); }); - it('should parse ngContent regardless the namespace', () => { - const parsed = parse('<svg><ng-content></ng-content></svg>', []); - expect(humanizeTplAst(parsed)).toEqual([ - [ElementAst, ':svg:svg'], - [NgContentAst], + it('should parse dotted name bound properties', () => { + expect(humanizeTplAst(parse('<div [dot.name]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'dot.name', 'v', null] ]); }); - it('should parse bound text nodes', () => { - expect(humanizeTplAst(parse('{{a}}', []))).toEqual([[BoundTextAst, '{{ a }}']]); - }); - - it('should parse with custom interpolation config', - inject([TemplateParser], (parser: TemplateParser) => { - const component = CompileDirectiveMetadata.create({ - selector: 'test', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Test'}}), - isComponent: true, - template: new CompileTemplateMetadata({ - interpolation: ['{%', '%}'], - isInline: false, - animations: [], - template: null, - templateUrl: null, - htmlAst: null, - ngContentSelectors: [], - externalStylesheets: [], - styleUrls: [], - styles: [], - encapsulation: null, - preserveWhitespaces: preserveWhitespacesDefault(null), - }), - isHost: false, - exportAs: null, - changeDetection: null, - inputs: [], - outputs: [], - host: {}, - providers: [], - viewProviders: [], - queries: [], - guards: {}, - viewQueries: [], - entryComponents: [], - componentViewType: null, - rendererType: null, - componentFactory: null - - }); - expect(humanizeTplAst( - parser.parse(component, '{%a%}', [], [], [], 'TestComp', true).template, - {start: '{%', end: '%}'})) - .toEqual([[BoundTextAst, '{% a %}']]); - })); - - describe('bound properties', () => { - - it('should parse mixed case bound properties', () => { - expect(humanizeTplAst(parse('<div [someProp]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'someProp', 'v', null] - ]); - }); - - it('should parse dash case bound properties', () => { - expect(humanizeTplAst(parse('<div [some-prop]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'some-prop', 'v', null] - ]); - }); - - it('should parse dotted name bound properties', () => { - expect(humanizeTplAst(parse('<div [dot.name]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'dot.name', 'v', null] - ]); - }); - - it('should normalize property names via the element schema', () => { - expect(humanizeTplAst(parse('<div [mappedAttr]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'mappedProp', 'v', null] - ]); - }); + it('should normalize property names via the element schema', () => { + expect(humanizeTplAst(parse('<div [mappedAttr]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'mappedProp', 'v', null] + ]); + }); - it('should parse mixed case bound attributes', () => { - expect(humanizeTplAst(parse('<div [attr.someAttr]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Attribute, 'someAttr', 'v', null] - ]); - }); + it('should parse mixed case bound attributes', () => { + expect(humanizeTplAst(parse('<div [attr.someAttr]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Attribute, 'someAttr', 'v', null] + ]); + }); - it('should parse mixed case bound attributes with dot in the attribute name', () => { - expect(humanizeTplAst(parse('<div [attr.someAttr.someAttrSuffix]="v">', []))).toEqual([ - [ElementAst, 'div'], - [ - BoundElementPropertyAst, PropertyBindingType.Attribute, 'someAttr.someAttrSuffix', - 'v', null - ] - ]); - }); + it('should parse mixed case bound attributes with dot in the attribute name', () => { + expect(humanizeTplAst(parse('<div [attr.someAttr.someAttrSuffix]="v">', []))).toEqual([ + [ElementAst, 'div'], + [ + BoundElementPropertyAst, PropertyBindingType.Attribute, 'someAttr.someAttrSuffix', 'v', + null + ] + ]); + }); - it('should parse and dash case bound classes', () => { - expect(humanizeTplAst(parse('<div [class.some-class]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Class, 'some-class', 'v', null] - ]); - }); + it('should parse and dash case bound classes', () => { + expect(humanizeTplAst(parse('<div [class.some-class]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Class, 'some-class', 'v', null] + ]); + }); - it('should parse mixed case bound classes', () => { - expect(humanizeTplAst(parse('<div [class.someClass]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Class, 'someClass', 'v', null] - ]); - }); + it('should parse mixed case bound classes', () => { + expect(humanizeTplAst(parse('<div [class.someClass]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Class, 'someClass', 'v', null] + ]); + }); - it('should parse mixed case bound styles', () => { - expect(humanizeTplAst(parse('<div [style.someStyle]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Style, 'someStyle', 'v', null] - ]); - }); + it('should parse mixed case bound styles', () => { + expect(humanizeTplAst(parse('<div [style.someStyle]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Style, 'someStyle', 'v', null] + ]); + }); - describe('errors', () => { - it('should throw error when binding to an unknown property', () => { - expect(() => parse('<my-component [invalidProp]="bar"></my-component>', [])) - .toThrowError(`Template parse errors: + describe('errors', () => { + it('should throw error when binding to an unknown property', () => { + expect(() => parse('<my-component [invalidProp]="bar"></my-component>', [])) + .toThrowError(`Template parse errors: Can't bind to 'invalidProp' since it isn't a known property of 'my-component'. 1. If 'my-component' is an Angular component and it has 'invalidProp' input, then verify that it is part of this module. 2. If 'my-component' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. 3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("<my-component [ERROR ->][invalidProp]="bar"></my-component>"): TestComp@0:14`); - }); + }); - it('should throw error when binding to an unknown property of ng-container', () => { - expect(() => parse('<ng-container [invalidProp]="bar"></ng-container>', [])) - .toThrowError( - `Template parse errors: + it('should throw error when binding to an unknown property of ng-container', () => { + expect(() => parse('<ng-container [invalidProp]="bar"></ng-container>', [])) + .toThrowError( + `Template parse errors: Can't bind to 'invalidProp' since it isn't a known property of 'ng-container'. 1. If 'invalidProp' is an Angular directive, then add 'CommonModule' to the '@NgModule.imports' of this component. 2. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.` + - ` ("<ng-container [ERROR ->][invalidProp]="bar"></ng-container>"): TestComp@0:14`); - }); + ` ("<ng-container [ERROR ->][invalidProp]="bar"></ng-container>"): TestComp@0:14`); + }); - it('should throw error when binding to an unknown element w/o bindings', () => { - expect(() => parse('<unknown></unknown>', [])).toThrowError(`Template parse errors: + it('should throw error when binding to an unknown element w/o bindings', () => { + expect(() => parse('<unknown></unknown>', [])).toThrowError(`Template parse errors: 'unknown' is not a known element: 1. If 'unknown' is an Angular component, then verify that it is part of this module. 2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("[ERROR ->]<unknown></unknown>"): TestComp@0:0`); - }); + }); - it('should throw error when binding to an unknown custom element w/o bindings', () => { - expect(() => parse('<un-known></un-known>', [])).toThrowError(`Template parse errors: + it('should throw error when binding to an unknown custom element w/o bindings', () => { + expect(() => parse('<un-known></un-known>', [])).toThrowError(`Template parse errors: 'un-known' is not a known element: 1. If 'un-known' is an Angular component, then verify that it is part of this module. 2. If 'un-known' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message. ("[ERROR ->]<un-known></un-known>"): TestComp@0:0`); - }); + }); - it('should throw error when binding to an invalid property', () => { - expect(() => parse('<my-component [onEvent]="bar"></my-component>', [])) - .toThrowError(`Template parse errors: + it('should throw error when binding to an invalid property', () => { + expect(() => parse('<my-component [onEvent]="bar"></my-component>', [])) + .toThrowError(`Template parse errors: Binding to property 'onEvent' is disallowed for security reasons ("<my-component [ERROR ->][onEvent]="bar"></my-component>"): TestComp@0:14`); - }); + }); - it('should throw error when binding to an invalid attribute', () => { - expect(() => parse('<my-component [attr.onEvent]="bar"></my-component>', [])) - .toThrowError(`Template parse errors: + it('should throw error when binding to an invalid attribute', () => { + expect(() => parse('<my-component [attr.onEvent]="bar"></my-component>', [])) + .toThrowError(`Template parse errors: Binding to attribute 'onEvent' is disallowed for security reasons ("<my-component [ERROR ->][attr.onEvent]="bar"></my-component>"): TestComp@0:14`); - }); }); + }); - it('should parse bound properties via [...] and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div [prop]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null] - ]); - }); + it('should parse bound properties via [...] and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div [prop]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null] + ]); + }); - it('should parse bound properties via bind- and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div bind-prop="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null] - ]); - }); + it('should parse bound properties via bind- and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div bind-prop="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null] + ]); + }); - it('should report missing property names in bind- syntax', () => { - expect(() => parse('<div bind-></div>', [])).toThrowError(`Template parse errors: + it('should report missing property names in bind- syntax', () => { + expect(() => parse('<div bind-></div>', [])).toThrowError(`Template parse errors: Property name is missing in binding ("<div [ERROR ->]bind-></div>"): TestComp@0:5`); - }); + }); - it('should parse bound properties via {{...}} and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div prop="{{v}}">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', '{{ v }}', null] - ]); - }); + it('should parse bound properties via {{...}} and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div prop="{{v}}">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', '{{ v }}', null] + ]); + }); - it('should parse bound properties via bind-animate- and not report them as attributes', - () => { - expect(humanizeTplAst(parse('<div bind-animate-someAnimation="value2">', [], [], []))) - .toEqual([ - [ElementAst, 'div'], - [ - BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation', - 'value2', null - ] - ]); - }); - - it('should throw an error when parsing detects non-bound properties via @ that contain a value', - () => { - expect(() => { parse('<div @someAnimation="value2">', [], [], []); }) - .toThrowError( - /Assigning animation triggers via @prop="exp" attributes with an expression is invalid. Use property bindings \(e.g. \[@prop\]="exp"\) or use an attribute without a value \(e.g. @prop\) instead. \("<div \[ERROR ->\]@someAnimation="value2">"\): TestComp@0:5/); - }); - - it('should report missing animation trigger in @ syntax', () => { - expect(() => parse('<div @></div>', [])).toThrowError(`Template parse errors: -Animation trigger is missing ("<div [ERROR ->]@></div>"): TestComp@0:5`); - }); + it('should parse bound properties via bind-animate- and not report them as attributes', + () => { + expect(humanizeTplAst(parse('<div bind-animate-someAnimation="value2">', [], [], []))) + .toEqual([ + [ElementAst, 'div'], + [ + BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation', + 'value2', null + ] + ]); + }); - it('should not issue a warning when host attributes contain a valid property-bound animation trigger', - () => { - const animationEntries = ['prop']; - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - template: compileTemplateMetadata({animations: animationEntries}), - type: createTypeMeta({ - reference: {filePath: someModuleUrl, name: 'DirA'}, - }), - host: {'[@prop]': 'expr'} - }).toSummary(); - - humanizeTplAst(parse('<div></div>', [dirA])); - expect(console.warnings.length).toEqual(0); - }); - - it('should throw descriptive error when a host binding is not a string expression', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'broken', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - host: {'[class.foo]': null !} - }).toSummary(); + it('should throw an error when parsing detects non-bound properties via @ that contain a value', + () => { + expect(() => { + parse('<div @someAnimation="value2">', [], [], []); + }) + .toThrowError( + /Assigning animation triggers via @prop="exp" attributes with an expression is invalid. Use property bindings \(e.g. \[@prop\]="exp"\) or use an attribute without a value \(e.g. @prop\) instead. \("<div \[ERROR ->\]@someAnimation="value2">"\): TestComp@0:5/); + }); - expect(() => { parse('<broken></broken>', [dirA]); }) - .toThrowError( - `Template parse errors:\nValue of the host property binding "class.foo" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]<broken></broken>"): TestComp@0:0, Directive DirA`); - }); + it('should report missing animation trigger in @ syntax', () => { + expect(() => parse('<div @></div>', [])).toThrowError(`Template parse errors: +Animation trigger is missing ("<div [ERROR ->]@></div>"): TestComp@0:5`); + }); - it('should throw descriptive error when a host event is not a string expression', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'broken', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - host: {'(click)': null !} - }).toSummary(); + it('should not issue a warning when host attributes contain a valid property-bound animation trigger', + () => { + const animationEntries = ['prop']; + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + template: compileTemplateMetadata({animations: animationEntries}), + type: createTypeMeta({ + reference: {filePath: someModuleUrl, name: 'DirA'}, + }), + host: {'[@prop]': 'expr'} + }).toSummary(); + + humanizeTplAst(parse('<div></div>', [dirA])); + expect(console.warnings.length).toEqual(0); + }); - expect(() => { parse('<broken></broken>', [dirA]); }) - .toThrowError( - `Template parse errors:\nValue of the host listener "click" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]<broken></broken>"): TestComp@0:0, Directive DirA`); - }); + it('should throw descriptive error when a host binding is not a string expression', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'broken', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + host: {'[class.foo]': null!} + }).toSummary(); - it('should not issue a warning when an animation property is bound without an expression', - () => { - humanizeTplAst(parse('<div @someAnimation>', [], [], [])); - expect(console.warnings.length).toEqual(0); - }); - - it('should parse bound properties via [@] and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div [@someAnimation]="value2">', [], [], []))).toEqual([ - [ElementAst, 'div'], - [ - BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation', 'value2', - null - ] - ]); - }); + expect(() => { + parse('<broken></broken>', [dirA]); + }) + .toThrowError( + `Template parse errors:\nValue of the host property binding "class.foo" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]<broken></broken>"): TestComp@0:0, Directive DirA`); + }); - it('should support * directives', () => { - expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([ - [EmbeddedTemplateAst], - [DirectiveAst, ngIf], - [BoundDirectivePropertyAst, 'ngIf', 'null'], - [ElementAst, 'div'], - ]); - }); + it('should throw descriptive error when a host event is not a string expression', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'broken', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + host: {'(click)': null!} + }).toSummary(); - it('should support <ng-template>', () => { - expect(humanizeTplAst(parse('<ng-template>', []))).toEqual([ - [EmbeddedTemplateAst], - ]); - }); + expect(() => { + parse('<broken></broken>', [dirA]); + }) + .toThrowError( + `Template parse errors:\nValue of the host listener "click" needs to be a string representing an expression but got "null" (object) ("[ERROR ->]<broken></broken>"): TestComp@0:0, Directive DirA`); + }); - it('should treat <template> as a regular tag', () => { - expect(humanizeTplAst(parse('<template>', []))).toEqual([ - [ElementAst, 'template'], - ]); - }); + it('should not issue a warning when an animation property is bound without an expression', + () => { + humanizeTplAst(parse('<div @someAnimation>', [], [], [])); + expect(console.warnings.length).toEqual(0); + }); - it('should not special case the template attribute', () => { - expect(humanizeTplAst(parse('<p template="ngFor">', []))).toEqual([ - [ElementAst, 'p'], - [AttrAst, 'template', 'ngFor'], - ]); - }); + it('should parse bound properties via [@] and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div [@someAnimation]="value2">', [], [], []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Animation, 'someAnimation', 'value2', null] + ]); + }); + it('should support * directives', () => { + expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([ + [EmbeddedTemplateAst], + [DirectiveAst, ngIf], + [BoundDirectivePropertyAst, 'ngIf', 'null'], + [ElementAst, 'div'], + ]); }); - describe('events', () => { + it('should support <ng-template>', () => { + expect(humanizeTplAst(parse('<ng-template>', []))).toEqual([ + [EmbeddedTemplateAst], + ]); + }); - it('should parse bound events with a target', () => { - expect(humanizeTplAst(parse('<div (window:event)="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundEventAst, 'event', 'window', 'v'], - ]); - }); + it('should treat <template> as a regular tag', () => { + expect(humanizeTplAst(parse('<template>', []))).toEqual([ + [ElementAst, 'template'], + ]); + }); - it('should report an error on empty expression', () => { - expect(() => parse('<div (event)="">', [])) - .toThrowError(/Empty expressions are not allowed/); + it('should not special case the template attribute', () => { + expect(humanizeTplAst(parse('<p template="ngFor">', []))).toEqual([ + [ElementAst, 'p'], + [AttrAst, 'template', 'ngFor'], + ]); + }); + }); - expect(() => parse('<div (event)=" ">', [])) - .toThrowError(/Empty expressions are not allowed/); - }); + describe('events', () => { + it('should parse bound events with a target', () => { + expect(humanizeTplAst(parse('<div (window:event)="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundEventAst, 'event', 'window', 'v'], + ]); + }); - it('should parse bound events via (...) and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div (event)="v">', [ - ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'event', null, 'v']]); - }); + it('should report an error on empty expression', () => { + expect(() => parse('<div (event)="">', [])) + .toThrowError(/Empty expressions are not allowed/); - it('should parse event names case sensitive', () => { - expect(humanizeTplAst(parse('<div (some-event)="v">', [ - ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'some-event', null, 'v']]); - expect(humanizeTplAst(parse('<div (someEvent)="v">', [ - ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'someEvent', null, 'v']]); - }); + expect(() => parse('<div (event)=" ">', [])) + .toThrowError(/Empty expressions are not allowed/); + }); - it('should parse bound events via on- and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div on-event="v">', [ - ]))).toEqual([[ElementAst, 'div'], [BoundEventAst, 'event', null, 'v']]); - }); - - it('should report missing event names in on- syntax', () => { - expect(() => parse('<div on-></div>', [])) - .toThrowError(/Event name is missing in binding/); - }); + it('should parse bound events via (...) and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div (event)="v">', []))).toEqual([ + [ElementAst, 'div'], [BoundEventAst, 'event', null, 'v'] + ]); + }); - it('should allow events on explicit embedded templates that are emitted by a directive', - () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: 'ng-template', - outputs: ['e'], - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - - expect(humanizeTplAst(parse('<ng-template (e)="f"></ng-template>', [dirA]))).toEqual([ - [EmbeddedTemplateAst], - [BoundEventAst, 'e', null, 'f'], - [DirectiveAst, dirA], - ]); - }); + it('should parse event names case sensitive', () => { + expect(humanizeTplAst(parse('<div (some-event)="v">', []))).toEqual([ + [ElementAst, 'div'], [BoundEventAst, 'some-event', null, 'v'] + ]); + expect(humanizeTplAst(parse('<div (someEvent)="v">', []))).toEqual([ + [ElementAst, 'div'], [BoundEventAst, 'someEvent', null, 'v'] + ]); }); - describe('bindon', () => { - it('should parse bound events and properties via [(...)] and not report them as attributes', - () => { - expect(humanizeTplAst(parse('<div [(prop)]="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null], - [BoundEventAst, 'propChange', null, 'v = $event'] - ]); - }); - - it('should parse bound events and properties via bindon- and not report them as attributes', - () => { - expect(humanizeTplAst(parse('<div bindon-prop="v">', []))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null], - [BoundEventAst, 'propChange', null, 'v = $event'] - ]); - }); + it('should parse bound events via on- and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div on-event="v">', []))).toEqual([ + [ElementAst, 'div'], [BoundEventAst, 'event', null, 'v'] + ]); + }); - it('should report missing property names in bindon- syntax', () => { - expect(() => parse('<div bindon-></div>', [])) - .toThrowError(/Property name is missing in binding/); - }); + it('should report missing event names in on- syntax', () => { + expect(() => parse('<div on-></div>', [])).toThrowError(/Event name is missing in binding/); }); - describe('directives', () => { - it('should order directives by the directives array in the View and match them only once', - () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - const dirB = - compileDirectiveMetadataCreate({ - selector: '[b]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) - }).toSummary(); - const dirC = - compileDirectiveMetadataCreate({ - selector: '[c]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirC'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<div a c b a b>', [dirA, dirB, dirC]))).toEqual([ - [ElementAst, 'div'], [AttrAst, 'a', ''], [AttrAst, 'c', ''], [AttrAst, 'b', ''], - [AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA], [DirectiveAst, dirB], - [DirectiveAst, dirC] - ]); - }); + it('should allow events on explicit embedded templates that are emitted by a directive', + () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'ng-template', + outputs: ['e'], + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + + expect(humanizeTplAst(parse('<ng-template (e)="f"></ng-template>', [dirA]))).toEqual([ + [EmbeddedTemplateAst], + [BoundEventAst, 'e', null, 'f'], + [DirectiveAst, dirA], + ]); + }); + }); - it('should parse directive dotted properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: '[dot.name]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['localName: dot.name'], - }).toSummary(); + describe('bindon', () => { + it('should parse bound events and properties via [(...)] and not report them as attributes', + () => { + expect(humanizeTplAst(parse('<div [(prop)]="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null], + [BoundEventAst, 'propChange', null, 'v = $event'] + ]); + }); - expect(humanizeTplAst(parse('<div [dot.name]="expr"></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], - [DirectiveAst, dirA], - [BoundDirectivePropertyAst, 'localName', 'expr'], - ]); - }); + it('should parse bound events and properties via bindon- and not report them as attributes', + () => { + expect(humanizeTplAst(parse('<div bindon-prop="v">', []))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'prop', 'v', null], + [BoundEventAst, 'propChange', null, 'v = $event'] + ]); + }); - it('should locate directives in property bindings', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a=b]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - const dirB = - compileDirectiveMetadataCreate({ - selector: '[b]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<div [a]="b">', [dirA, dirB]))).toEqual([ - [ElementAst, 'div'], - [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'b', null], - [DirectiveAst, dirA] - ]); - }); + it('should report missing property names in bindon- syntax', () => { + expect(() => parse('<div bindon-></div>', [])) + .toThrowError(/Property name is missing in binding/); + }); + }); - it('should locate directives in inline templates', () => { - const dirTemplate = - compileDirectiveMetadataCreate({ - selector: 'ng-template', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'onTemplate'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<div *ngIf="cond">', [ngIf, dirTemplate]))).toEqual([ - [EmbeddedTemplateAst], - [DirectiveAst, ngIf], - [BoundDirectivePropertyAst, 'ngIf', 'cond'], - [DirectiveAst, dirTemplate], - [ElementAst, 'div'], - ]); - }); + describe('directives', () => { + it('should order directives by the directives array in the View and match them only once', + () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + const dirB = compileDirectiveMetadataCreate({ + selector: '[b]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) + }).toSummary(); + const dirC = compileDirectiveMetadataCreate({ + selector: '[c]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirC'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<div a c b a b>', [dirA, dirB, dirC]))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'a', ''], [AttrAst, 'c', ''], [AttrAst, 'b', ''], + [AttrAst, 'a', ''], [AttrAst, 'b', ''], [DirectiveAst, dirA], [DirectiveAst, dirB], + [DirectiveAst, dirC] + ]); + }); - it('should locate directives in event bindings', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) - }).toSummary(); + it('should parse directive dotted properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[dot.name]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['localName: dot.name'], + }).toSummary(); - expect(humanizeTplAst(parse('<div (a)="b">', [dirA]))).toEqual([ - [ElementAst, 'div'], [BoundEventAst, 'a', null, 'b'], [DirectiveAst, dirA] - ]); - }); + expect(humanizeTplAst(parse('<div [dot.name]="expr"></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], + [DirectiveAst, dirA], + [BoundDirectivePropertyAst, 'localName', 'expr'], + ]); + }); - it('should parse directive host properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - host: {'[a]': 'expr'} - }).toSummary(); - expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], [DirectiveAst, dirA], - [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'expr', null] - ]); - }); + it('should locate directives in property bindings', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a=b]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + const dirB = compileDirectiveMetadataCreate({ + selector: '[b]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<div [a]="b">', [dirA, dirB]))).toEqual([ + [ElementAst, 'div'], + [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'b', null], + [DirectiveAst, dirA] + ]); + }); - it('should parse directive host listeners', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - host: {'(a)': 'expr'} - }).toSummary(); - expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], [DirectiveAst, dirA], [BoundEventAst, 'a', null, 'expr'] - ]); - }); + it('should locate directives in inline templates', () => { + const dirTemplate = + compileDirectiveMetadataCreate({ + selector: 'ng-template', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'onTemplate'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<div *ngIf="cond">', [ngIf, dirTemplate]))).toEqual([ + [EmbeddedTemplateAst], + [DirectiveAst, ngIf], + [BoundDirectivePropertyAst, 'ngIf', 'cond'], + [DirectiveAst, dirTemplate], + [ElementAst, 'div'], + ]); + }); - it('should parse directive properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['aProp'] - }).toSummary(); - expect(humanizeTplAst(parse('<div [aProp]="expr"></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], [DirectiveAst, dirA], - [BoundDirectivePropertyAst, 'aProp', 'expr'] - ]); - }); + it('should locate directives in event bindings', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) + }).toSummary(); - it('should parse renamed directive properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['b:a'] - }).toSummary(); - expect(humanizeTplAst(parse('<div [a]="expr"></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'b', 'expr'] - ]); - }); + expect(humanizeTplAst(parse('<div (a)="b">', [dirA]))).toEqual([ + [ElementAst, 'div'], [BoundEventAst, 'a', null, 'b'], [DirectiveAst, dirA] + ]); + }); - it('should parse literal directive properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['a'] - }).toSummary(); - expect(humanizeTplAst(parse('<div a="literal"></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA], - [BoundDirectivePropertyAst, 'a', '"literal"'] - ]); - }); + it('should parse directive host properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + host: {'[a]': 'expr'} + }).toSummary(); + expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], [DirectiveAst, dirA], + [BoundElementPropertyAst, PropertyBindingType.Property, 'a', 'expr', null] + ]); + }); - it('should favor explicit bound properties over literal properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['a'] - }).toSummary(); - expect(humanizeTplAst(parse('<div a="literal" [a]="\'literal2\'"></div>', [dirA]))) - .toEqual([ - [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA], - [BoundDirectivePropertyAst, 'a', '"literal2"'] - ]); - }); + it('should parse directive host listeners', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + host: {'(a)': 'expr'} + }).toSummary(); + expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], [DirectiveAst, dirA], [BoundEventAst, 'a', null, 'expr'] + ]); + }); - it('should support optional directive properties', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['a'] - }).toSummary(); - expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], [DirectiveAst, dirA] - ]); - }); + it('should parse directive properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['aProp'] + }).toSummary(); + expect(humanizeTplAst(parse('<div [aProp]="expr"></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'aProp', 'expr'] + ]); + }); + it('should parse renamed directive properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['b:a'] + }).toSummary(); + expect(humanizeTplAst(parse('<div [a]="expr"></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'b', 'expr'] + ]); }); - describe('providers', () => { - let nextProviderId: number; + it('should parse literal directive properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['a'] + }).toSummary(); + expect(humanizeTplAst(parse('<div a="literal"></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA], + [BoundDirectivePropertyAst, 'a', '"literal"'] + ]); + }); - function createToken(value: string): CompileTokenMetadata { - let token: CompileTokenMetadata; - if (value.startsWith('type:')) { - const name = value.substring(5); - token = {identifier: createTypeMeta({reference: <any>name})}; - } else { - token = {value: value}; - } - return token; - } + it('should favor explicit bound properties over literal properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['a'] + }).toSummary(); + expect(humanizeTplAst(parse('<div a="literal" [a]="\'literal2\'"></div>', [dirA]))) + .toEqual([ + [ElementAst, 'div'], [AttrAst, 'a', 'literal'], [DirectiveAst, dirA], + [BoundDirectivePropertyAst, 'a', '"literal2"'] + ]); + }); - function createDep(value: string): CompileDiDependencyMetadata { - let isOptional = false; - if (value.startsWith('optional:')) { - isOptional = true; - value = value.substring(9); - } - let isSelf = false; - if (value.startsWith('self:')) { - isSelf = true; - value = value.substring(5); - } - let isHost = false; - if (value.startsWith('host:')) { - isHost = true; - value = value.substring(5); - } - return { - token: createToken(value), - isOptional: isOptional, - isSelf: isSelf, - isHost: isHost - }; - } + it('should support optional directive properties', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['a'] + }).toSummary(); + expect(humanizeTplAst(parse('<div></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], [DirectiveAst, dirA] + ]); + }); + }); - function createProvider( - token: string, {multi = false, deps = []}: {multi?: boolean, deps?: string[]} = {}): - CompileProviderMetadata { - const compileToken = createToken(token); - return { - token: compileToken, - multi: multi, - useClass: createTypeMeta({reference: tokenReference(compileToken)}), - deps: deps.map(createDep), - useExisting: undefined, - useFactory: undefined, - useValue: undefined - }; - } + describe('providers', () => { + let nextProviderId: number; - function createDir( - selector: string, - {providers = undefined, viewProviders = undefined, deps = [], queries = []}: { - providers?: CompileProviderMetadata[] | undefined, - viewProviders?: CompileProviderMetadata[] | undefined, - deps?: string[], - queries?: string[] - } = {}): CompileDirectiveSummary { - const isComponent = !selector.startsWith('['); - return compileDirectiveMetadataCreate({ - selector: selector, - type: createTypeMeta({ - reference: <any>selector, - diDeps: deps.map(createDep), - }), - isComponent: isComponent, - template: compileTemplateMetadata({ngContentSelectors: []}), - providers: providers, - viewProviders: viewProviders, - queries: queries.map((value) => { - return { - selectors: [createToken(value)], - descendants: false, - first: false, - propertyName: 'test', - read: undefined ! - }; - }) - }) - .toSummary(); + function createToken(value: string): CompileTokenMetadata { + let token: CompileTokenMetadata; + if (value.startsWith('type:')) { + const name = value.substring(5); + token = {identifier: createTypeMeta({reference: <any>name})}; + } else { + token = {value: value}; } + return token; + } - beforeEach(() => { nextProviderId = 0; }); - - it('should provide a component', () => { - const comp = createDir('my-comp'); - const elAst: ElementAst = <ElementAst>parse('<my-comp>', [comp])[0]; - expect(elAst.providers.length).toBe(1); - expect(elAst.providers[0].providerType).toBe(ProviderAstType.Component); - expect(elAst.providers[0].providers[0].useClass).toBe(comp.type); - }); - - it('should provide a directive', () => { - const dirA = createDir('[dirA]'); - const elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0]; - expect(elAst.providers.length).toBe(1); - expect(elAst.providers[0].providerType).toBe(ProviderAstType.Directive); - expect(elAst.providers[0].providers[0].useClass).toBe(dirA.type); - }); - - it('should use the public providers of a directive', () => { - const provider = createProvider('service'); - const dirA = createDir('[dirA]', {providers: [provider]}); - const elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0]; - expect(elAst.providers.length).toBe(2); - expect(elAst.providers[0].providerType).toBe(ProviderAstType.PublicService); - expect(elAst.providers[0].providers).toEqual([provider]); - }); - - it('should use the private providers of a component', () => { - const provider = createProvider('service'); - const comp = createDir('my-comp', {viewProviders: [provider]}); - const elAst: ElementAst = <ElementAst>parse('<my-comp>', [comp])[0]; - expect(elAst.providers.length).toBe(2); - expect(elAst.providers[0].providerType).toBe(ProviderAstType.PrivateService); - expect(elAst.providers[0].providers).toEqual([provider]); - }); - - it('should support multi providers', () => { - const provider0 = createProvider('service0', {multi: true}); - const provider1 = createProvider('service1', {multi: true}); - const provider2 = createProvider('service0', {multi: true}); - const dirA = createDir('[dirA]', {providers: [provider0, provider1]}); - const dirB = createDir('[dirB]', {providers: [provider2]}); - const elAst: ElementAst = <ElementAst>parse('<div dirA dirB>', [dirA, dirB])[0]; - expect(elAst.providers.length).toBe(4); - expect(elAst.providers[0].providers).toEqual([provider0, provider2]); - expect(elAst.providers[1].providers).toEqual([provider1]); - }); - - it('should overwrite non multi providers', () => { - const provider1 = createProvider('service0'); - const provider2 = createProvider('service1'); - const provider3 = createProvider('service0'); - const dirA = createDir('[dirA]', {providers: [provider1, provider2]}); - const dirB = createDir('[dirB]', {providers: [provider3]}); - const elAst: ElementAst = <ElementAst>parse('<div dirA dirB>', [dirA, dirB])[0]; - expect(elAst.providers.length).toBe(4); - expect(elAst.providers[0].providers).toEqual([provider3]); - expect(elAst.providers[1].providers).toEqual([provider2]); - }); - - it('should overwrite component providers by directive providers', () => { - const compProvider = createProvider('service0'); - const dirProvider = createProvider('service0'); - const comp = createDir('my-comp', {providers: [compProvider]}); - const dirA = createDir('[dirA]', {providers: [dirProvider]}); - const elAst: ElementAst = <ElementAst>parse('<my-comp dirA>', [dirA, comp])[0]; - expect(elAst.providers.length).toBe(3); - expect(elAst.providers[0].providers).toEqual([dirProvider]); - }); - - it('should overwrite view providers by directive providers', () => { - const viewProvider = createProvider('service0'); - const dirProvider = createProvider('service0'); - const comp = createDir('my-comp', {viewProviders: [viewProvider]}); - const dirA = createDir('[dirA]', {providers: [dirProvider]}); - const elAst: ElementAst = <ElementAst>parse('<my-comp dirA>', [dirA, comp])[0]; - expect(elAst.providers.length).toBe(3); - expect(elAst.providers[0].providers).toEqual([dirProvider]); - }); - - it('should overwrite directives by providers', () => { - const dirProvider = createProvider('type:my-comp'); - const comp = createDir('my-comp', {providers: [dirProvider]}); - const elAst: ElementAst = <ElementAst>parse('<my-comp>', [comp])[0]; - expect(elAst.providers.length).toBe(1); - expect(elAst.providers[0].providers).toEqual([dirProvider]); - }); - - it('if mixing multi and non multi providers', () => { - const provider0 = createProvider('service0'); - const provider1 = createProvider('service0', {multi: true}); - const dirA = createDir('[dirA]', {providers: [provider0]}); - const dirB = createDir('[dirB]', {providers: [provider1]}); - expect(() => parse('<div dirA dirB>', [dirA, dirB])) - .toThrowError( - `Template parse errors:\n` + - `Mixing multi and non multi provider is not possible for token service0 ("[ERROR ->]<div dirA dirB>"): TestComp@0:0`); - }); - - it('should sort providers by their DI order, lazy providers first', () => { - const provider0 = createProvider('service0', {deps: ['type:[dir2]']}); - const provider1 = createProvider('service1'); - const dir2 = createDir('[dir2]', {deps: ['service1']}); - const comp = createDir('my-comp', {providers: [provider0, provider1]}); - const elAst: ElementAst = <ElementAst>parse('<my-comp dir2>', [comp, dir2])[0]; - expect(elAst.providers.length).toBe(4); - expect(elAst.providers[1].providers[0].useClass).toEqual(comp.type); - expect(elAst.providers[2].providers).toEqual([provider1]); - expect(elAst.providers[3].providers[0].useClass).toEqual(dir2.type); - expect(elAst.providers[0].providers).toEqual([provider0]); - }); - - it('should sort directives by their DI order', () => { - const dir0 = createDir('[dir0]', {deps: ['type:my-comp']}); - const dir1 = createDir('[dir1]', {deps: ['type:[dir0]']}); - const dir2 = createDir('[dir2]', {deps: ['type:[dir1]']}); - const comp = createDir('my-comp'); - const elAst: ElementAst = - <ElementAst>parse('<my-comp dir2 dir0 dir1>', [comp, dir2, dir0, dir1])[0]; - expect(elAst.providers.length).toBe(4); - expect(elAst.directives[0].directive).toBe(comp); - expect(elAst.directives[1].directive).toBe(dir0); - expect(elAst.directives[2].directive).toBe(dir1); - expect(elAst.directives[3].directive).toBe(dir2); - }); - - it('should mark directives and dependencies of directives as eager', () => { - const provider0 = createProvider('service0'); - const provider1 = createProvider('service1'); - const dirA = createDir('[dirA]', {providers: [provider0, provider1], deps: ['service0']}); - const elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0]; - expect(elAst.providers.length).toBe(3); - expect(elAst.providers[1].providers).toEqual([provider0]); - expect(elAst.providers[1].eager).toBe(true); - expect(elAst.providers[2].providers[0].useClass).toEqual(dirA.type); - expect(elAst.providers[2].eager).toBe(true); - expect(elAst.providers[0].providers).toEqual([provider1]); - expect(elAst.providers[0].eager).toBe(false); - }); + function createDep(value: string): CompileDiDependencyMetadata { + let isOptional = false; + if (value.startsWith('optional:')) { + isOptional = true; + value = value.substring(9); + } + let isSelf = false; + if (value.startsWith('self:')) { + isSelf = true; + value = value.substring(5); + } + let isHost = false; + if (value.startsWith('host:')) { + isHost = true; + value = value.substring(5); + } + return {token: createToken(value), isOptional: isOptional, isSelf: isSelf, isHost: isHost}; + } - it('should mark dependencies on parent elements as eager', () => { - const provider0 = createProvider('service0'); - const provider1 = createProvider('service1'); - const dirA = createDir('[dirA]', {providers: [provider0, provider1]}); - const dirB = createDir('[dirB]', {deps: ['service0']}); - const elAst: ElementAst = - <ElementAst>parse('<div dirA><div dirB></div></div>', [dirA, dirB])[0]; - expect(elAst.providers.length).toBe(3); - expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type); - expect(elAst.providers[1].eager).toBe(true); - expect(elAst.providers[2].providers).toEqual([provider0]); - expect(elAst.providers[2].eager).toBe(true); - expect(elAst.providers[0].providers).toEqual([provider1]); - expect(elAst.providers[0].eager).toBe(false); - }); + function createProvider( + token: string, {multi = false, deps = []}: {multi?: boolean, deps?: string[]} = {}): + CompileProviderMetadata { + const compileToken = createToken(token); + return { + token: compileToken, + multi: multi, + useClass: createTypeMeta({reference: tokenReference(compileToken)}), + deps: deps.map(createDep), + useExisting: undefined, + useFactory: undefined, + useValue: undefined + }; + } - it('should mark queried providers as eager', () => { - const provider0 = createProvider('service0'); - const provider1 = createProvider('service1'); - const dirA = - createDir('[dirA]', {providers: [provider0, provider1], queries: ['service0']}); - const elAst: ElementAst = <ElementAst>parse('<div dirA></div>', [dirA])[0]; - expect(elAst.providers.length).toBe(3); - expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type); - expect(elAst.providers[1].eager).toBe(true); - expect(elAst.providers[2].providers).toEqual([provider0]); - expect(elAst.providers[2].eager).toBe(true); - expect(elAst.providers[0].providers).toEqual([provider1]); - expect(elAst.providers[0].eager).toBe(false); - }); + function createDir( + selector: string, + {providers = undefined, viewProviders = undefined, deps = [], queries = []}: { + providers?: CompileProviderMetadata[]|undefined, + viewProviders?: CompileProviderMetadata[]|undefined, + deps?: string[], + queries?: string[] + } = {}): CompileDirectiveSummary { + const isComponent = !selector.startsWith('['); + return compileDirectiveMetadataCreate({ + selector: selector, + type: createTypeMeta({ + reference: <any>selector, + diDeps: deps.map(createDep), + }), + isComponent: isComponent, + template: compileTemplateMetadata({ngContentSelectors: []}), + providers: providers, + viewProviders: viewProviders, + queries: queries.map((value) => { + return { + selectors: [createToken(value)], + descendants: false, + first: false, + propertyName: 'test', + read: undefined! + }; + }) + }) + .toSummary(); + } - it('should not mark dependencies across embedded views as eager', () => { - const provider0 = createProvider('service0'); - const dirA = createDir('[dirA]', {providers: [provider0]}); - const dirB = createDir('[dirB]', {deps: ['service0']}); - const elAst: ElementAst = - <ElementAst>parse('<div dirA><div *ngIf dirB></div></div>', [dirA, dirB])[0]; - expect(elAst.providers.length).toBe(2); - expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type); - expect(elAst.providers[1].eager).toBe(true); - expect(elAst.providers[0].providers).toEqual([provider0]); - expect(elAst.providers[0].eager).toBe(false); - }); + beforeEach(() => { + nextProviderId = 0; + }); + + it('should provide a component', () => { + const comp = createDir('my-comp'); + const elAst: ElementAst = <ElementAst>parse('<my-comp>', [comp])[0]; + expect(elAst.providers.length).toBe(1); + expect(elAst.providers[0].providerType).toBe(ProviderAstType.Component); + expect(elAst.providers[0].providers[0].useClass).toBe(comp.type); + }); + + it('should provide a directive', () => { + const dirA = createDir('[dirA]'); + const elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0]; + expect(elAst.providers.length).toBe(1); + expect(elAst.providers[0].providerType).toBe(ProviderAstType.Directive); + expect(elAst.providers[0].providers[0].useClass).toBe(dirA.type); + }); + + it('should use the public providers of a directive', () => { + const provider = createProvider('service'); + const dirA = createDir('[dirA]', {providers: [provider]}); + const elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0]; + expect(elAst.providers.length).toBe(2); + expect(elAst.providers[0].providerType).toBe(ProviderAstType.PublicService); + expect(elAst.providers[0].providers).toEqual([provider]); + }); + + it('should use the private providers of a component', () => { + const provider = createProvider('service'); + const comp = createDir('my-comp', {viewProviders: [provider]}); + const elAst: ElementAst = <ElementAst>parse('<my-comp>', [comp])[0]; + expect(elAst.providers.length).toBe(2); + expect(elAst.providers[0].providerType).toBe(ProviderAstType.PrivateService); + expect(elAst.providers[0].providers).toEqual([provider]); + }); + + it('should support multi providers', () => { + const provider0 = createProvider('service0', {multi: true}); + const provider1 = createProvider('service1', {multi: true}); + const provider2 = createProvider('service0', {multi: true}); + const dirA = createDir('[dirA]', {providers: [provider0, provider1]}); + const dirB = createDir('[dirB]', {providers: [provider2]}); + const elAst: ElementAst = <ElementAst>parse('<div dirA dirB>', [dirA, dirB])[0]; + expect(elAst.providers.length).toBe(4); + expect(elAst.providers[0].providers).toEqual([provider0, provider2]); + expect(elAst.providers[1].providers).toEqual([provider1]); + }); + + it('should overwrite non multi providers', () => { + const provider1 = createProvider('service0'); + const provider2 = createProvider('service1'); + const provider3 = createProvider('service0'); + const dirA = createDir('[dirA]', {providers: [provider1, provider2]}); + const dirB = createDir('[dirB]', {providers: [provider3]}); + const elAst: ElementAst = <ElementAst>parse('<div dirA dirB>', [dirA, dirB])[0]; + expect(elAst.providers.length).toBe(4); + expect(elAst.providers[0].providers).toEqual([provider3]); + expect(elAst.providers[1].providers).toEqual([provider2]); + }); + + it('should overwrite component providers by directive providers', () => { + const compProvider = createProvider('service0'); + const dirProvider = createProvider('service0'); + const comp = createDir('my-comp', {providers: [compProvider]}); + const dirA = createDir('[dirA]', {providers: [dirProvider]}); + const elAst: ElementAst = <ElementAst>parse('<my-comp dirA>', [dirA, comp])[0]; + expect(elAst.providers.length).toBe(3); + expect(elAst.providers[0].providers).toEqual([dirProvider]); + }); + + it('should overwrite view providers by directive providers', () => { + const viewProvider = createProvider('service0'); + const dirProvider = createProvider('service0'); + const comp = createDir('my-comp', {viewProviders: [viewProvider]}); + const dirA = createDir('[dirA]', {providers: [dirProvider]}); + const elAst: ElementAst = <ElementAst>parse('<my-comp dirA>', [dirA, comp])[0]; + expect(elAst.providers.length).toBe(3); + expect(elAst.providers[0].providers).toEqual([dirProvider]); + }); + + it('should overwrite directives by providers', () => { + const dirProvider = createProvider('type:my-comp'); + const comp = createDir('my-comp', {providers: [dirProvider]}); + const elAst: ElementAst = <ElementAst>parse('<my-comp>', [comp])[0]; + expect(elAst.providers.length).toBe(1); + expect(elAst.providers[0].providers).toEqual([dirProvider]); + }); + + it('if mixing multi and non multi providers', () => { + const provider0 = createProvider('service0'); + const provider1 = createProvider('service0', {multi: true}); + const dirA = createDir('[dirA]', {providers: [provider0]}); + const dirB = createDir('[dirB]', {providers: [provider1]}); + expect(() => parse('<div dirA dirB>', [dirA, dirB])) + .toThrowError( + `Template parse errors:\n` + + `Mixing multi and non multi provider is not possible for token service0 ("[ERROR ->]<div dirA dirB>"): TestComp@0:0`); + }); + + it('should sort providers by their DI order, lazy providers first', () => { + const provider0 = createProvider('service0', {deps: ['type:[dir2]']}); + const provider1 = createProvider('service1'); + const dir2 = createDir('[dir2]', {deps: ['service1']}); + const comp = createDir('my-comp', {providers: [provider0, provider1]}); + const elAst: ElementAst = <ElementAst>parse('<my-comp dir2>', [comp, dir2])[0]; + expect(elAst.providers.length).toBe(4); + expect(elAst.providers[1].providers[0].useClass).toEqual(comp.type); + expect(elAst.providers[2].providers).toEqual([provider1]); + expect(elAst.providers[3].providers[0].useClass).toEqual(dir2.type); + expect(elAst.providers[0].providers).toEqual([provider0]); + }); + + it('should sort directives by their DI order', () => { + const dir0 = createDir('[dir0]', {deps: ['type:my-comp']}); + const dir1 = createDir('[dir1]', {deps: ['type:[dir0]']}); + const dir2 = createDir('[dir2]', {deps: ['type:[dir1]']}); + const comp = createDir('my-comp'); + const elAst: ElementAst = + <ElementAst>parse('<my-comp dir2 dir0 dir1>', [comp, dir2, dir0, dir1])[0]; + expect(elAst.providers.length).toBe(4); + expect(elAst.directives[0].directive).toBe(comp); + expect(elAst.directives[1].directive).toBe(dir0); + expect(elAst.directives[2].directive).toBe(dir1); + expect(elAst.directives[3].directive).toBe(dir2); + }); + + it('should mark directives and dependencies of directives as eager', () => { + const provider0 = createProvider('service0'); + const provider1 = createProvider('service1'); + const dirA = createDir('[dirA]', {providers: [provider0, provider1], deps: ['service0']}); + const elAst: ElementAst = <ElementAst>parse('<div dirA>', [dirA])[0]; + expect(elAst.providers.length).toBe(3); + expect(elAst.providers[1].providers).toEqual([provider0]); + expect(elAst.providers[1].eager).toBe(true); + expect(elAst.providers[2].providers[0].useClass).toEqual(dirA.type); + expect(elAst.providers[2].eager).toBe(true); + expect(elAst.providers[0].providers).toEqual([provider1]); + expect(elAst.providers[0].eager).toBe(false); + }); + + it('should mark dependencies on parent elements as eager', () => { + const provider0 = createProvider('service0'); + const provider1 = createProvider('service1'); + const dirA = createDir('[dirA]', {providers: [provider0, provider1]}); + const dirB = createDir('[dirB]', {deps: ['service0']}); + const elAst: ElementAst = + <ElementAst>parse('<div dirA><div dirB></div></div>', [dirA, dirB])[0]; + expect(elAst.providers.length).toBe(3); + expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type); + expect(elAst.providers[1].eager).toBe(true); + expect(elAst.providers[2].providers).toEqual([provider0]); + expect(elAst.providers[2].eager).toBe(true); + expect(elAst.providers[0].providers).toEqual([provider1]); + expect(elAst.providers[0].eager).toBe(false); + }); + + it('should mark queried providers as eager', () => { + const provider0 = createProvider('service0'); + const provider1 = createProvider('service1'); + const dirA = + createDir('[dirA]', {providers: [provider0, provider1], queries: ['service0']}); + const elAst: ElementAst = <ElementAst>parse('<div dirA></div>', [dirA])[0]; + expect(elAst.providers.length).toBe(3); + expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type); + expect(elAst.providers[1].eager).toBe(true); + expect(elAst.providers[2].providers).toEqual([provider0]); + expect(elAst.providers[2].eager).toBe(true); + expect(elAst.providers[0].providers).toEqual([provider1]); + expect(elAst.providers[0].eager).toBe(false); + }); + + it('should not mark dependencies across embedded views as eager', () => { + const provider0 = createProvider('service0'); + const dirA = createDir('[dirA]', {providers: [provider0]}); + const dirB = createDir('[dirB]', {deps: ['service0']}); + const elAst: ElementAst = + <ElementAst>parse('<div dirA><div *ngIf dirB></div></div>', [dirA, dirB])[0]; + expect(elAst.providers.length).toBe(2); + expect(elAst.providers[1].providers[0].useClass).toEqual(dirA.type); + expect(elAst.providers[1].eager).toBe(true); + expect(elAst.providers[0].providers).toEqual([provider0]); + expect(elAst.providers[0].eager).toBe(false); + }); + + it('should report missing @Self() deps as errors', () => { + const dirA = createDir('[dirA]', {deps: ['self:provider0']}); + expect(() => parse('<div dirA></div>', [dirA])) + .toThrowError( + 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]<div dirA></div>"): TestComp@0:0'); + }); - it('should report missing @Self() deps as errors', () => { - const dirA = createDir('[dirA]', {deps: ['self:provider0']}); - expect(() => parse('<div dirA></div>', [dirA])) - .toThrowError( - 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]<div dirA></div>"): TestComp@0:0'); - }); + it('should change missing @Self() that are optional to nulls', () => { + const dirA = createDir('[dirA]', {deps: ['optional:self:provider0']}); + const elAst: ElementAst = <ElementAst>parse('<div dirA></div>', [dirA])[0]; + expect(elAst.providers[0].providers[0].deps![0].isValue).toBe(true); + expect(elAst.providers[0].providers[0].deps![0].value).toBe(null); + }); - it('should change missing @Self() that are optional to nulls', () => { - const dirA = createDir('[dirA]', {deps: ['optional:self:provider0']}); - const elAst: ElementAst = <ElementAst>parse('<div dirA></div>', [dirA])[0]; - expect(elAst.providers[0].providers[0].deps ![0].isValue).toBe(true); - expect(elAst.providers[0].providers[0].deps ![0].value).toBe(null); - }); + it('should report missing @Host() deps as errors', () => { + const dirA = createDir('[dirA]', {deps: ['host:provider0']}); + expect(() => parse('<div dirA></div>', [dirA])) + .toThrowError( + 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]<div dirA></div>"): TestComp@0:0'); + }); - it('should report missing @Host() deps as errors', () => { - const dirA = createDir('[dirA]', {deps: ['host:provider0']}); - expect(() => parse('<div dirA></div>', [dirA])) - .toThrowError( - 'Template parse errors:\nNo provider for provider0 ("[ERROR ->]<div dirA></div>"): TestComp@0:0'); - }); + it('should change missing @Host() that are optional to nulls', () => { + const dirA = createDir('[dirA]', {deps: ['optional:host:provider0']}); + const elAst: ElementAst = <ElementAst>parse('<div dirA></div>', [dirA])[0]; + expect(elAst.providers[0].providers[0].deps![0].isValue).toBe(true); + expect(elAst.providers[0].providers[0].deps![0].value).toBe(null); + }); + }); - it('should change missing @Host() that are optional to nulls', () => { - const dirA = createDir('[dirA]', {deps: ['optional:host:provider0']}); - const elAst: ElementAst = <ElementAst>parse('<div dirA></div>', [dirA])[0]; - expect(elAst.providers[0].providers[0].deps ![0].isValue).toBe(true); - expect(elAst.providers[0].providers[0].deps ![0].value).toBe(null); - }); + describe('references', () => { + it('should parse references via #... and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div #a>', []))).toEqual([ + [ElementAst, 'div'], [ReferenceAst, 'a', null] + ]); }); - describe('references', () => { + it('should parse references via ref-... and not report them as attributes', () => { + expect(humanizeTplAst(parse('<div ref-a>', []))).toEqual([ + [ElementAst, 'div'], [ReferenceAst, 'a', null] + ]); + }); - it('should parse references via #... and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div #a>', [ - ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]); - }); + it('should parse camel case references', () => { + expect(humanizeTplAst(parse('<div ref-someA>', []))).toEqual([ + [ElementAst, 'div'], [ReferenceAst, 'someA', null] + ]); + }); - it('should parse references via ref-... and not report them as attributes', () => { - expect(humanizeTplAst(parse('<div ref-a>', [ - ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]); - }); + it('should assign references with empty value to the element', () => { + expect(humanizeTplAst(parse('<div #a></div>', []))).toEqual([ + [ElementAst, 'div'], [ReferenceAst, 'a', null] + ]); + }); - it('should parse camel case references', () => { - expect(humanizeTplAst(parse('<div ref-someA>', [ - ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'someA', null]]); - }); + it('should assign references to directives via exportAs', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + exportAs: 'dirA' + }).toSummary(); + expect(humanizeTplAst(parse('<div a #a="dirA"></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], + [AttrAst, 'a', ''], + [ReferenceAst, 'a', createTokenForReference(dirA.type.reference)], + [DirectiveAst, dirA], + ]); + }); - it('should assign references with empty value to the element', () => { - expect(humanizeTplAst(parse('<div #a></div>', [ - ]))).toEqual([[ElementAst, 'div'], [ReferenceAst, 'a', null]]); - }); + it('should assign references to directives via exportAs with multiple names', () => { + const pizzaTestDirective = + compileDirectiveMetadataCreate({ + selector: 'pizza-test', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Pizza'}}), + exportAs: 'pizza, cheeseSauceBread' + }).toSummary(); - it('should assign references to directives via exportAs', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - exportAs: 'dirA' - }).toSummary(); - expect(humanizeTplAst(parse('<div a #a="dirA"></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], - [AttrAst, 'a', ''], - [ReferenceAst, 'a', createTokenForReference(dirA.type.reference)], - [DirectiveAst, dirA], - ]); - }); + const template = '<pizza-test #food="pizza" #yum="cheeseSauceBread"></pizza-test>'; - it('should assign references to directives via exportAs with multiple names', () => { - const pizzaTestDirective = - compileDirectiveMetadataCreate({ - selector: 'pizza-test', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Pizza'}}), - exportAs: 'pizza, cheeseSauceBread' - }).toSummary(); - - const template = '<pizza-test #food="pizza" #yum="cheeseSauceBread"></pizza-test>'; - - expect(humanizeTplAst(parse(template, [pizzaTestDirective]))).toEqual([ - [ElementAst, 'pizza-test'], - [ReferenceAst, 'food', createTokenForReference(pizzaTestDirective.type.reference)], - [ReferenceAst, 'yum', createTokenForReference(pizzaTestDirective.type.reference)], - [DirectiveAst, pizzaTestDirective], - ]); - }); + expect(humanizeTplAst(parse(template, [pizzaTestDirective]))).toEqual([ + [ElementAst, 'pizza-test'], + [ReferenceAst, 'food', createTokenForReference(pizzaTestDirective.type.reference)], + [ReferenceAst, 'yum', createTokenForReference(pizzaTestDirective.type.reference)], + [DirectiveAst, pizzaTestDirective], + ]); + }); - it('should report references with values that don\'t match a directive as errors', () => { - expect(() => parse('<div #a="dirA"></div>', [])).toThrowError(`Template parse errors: + it('should report references with values that don\'t match a directive as errors', () => { + expect(() => parse('<div #a="dirA"></div>', [])).toThrowError(`Template parse errors: There is no directive with "exportAs" set to "dirA" ("<div [ERROR ->]#a="dirA"></div>"): TestComp@0:5`); - }); + }); - it('should report invalid reference names', () => { - expect(() => parse('<div #a-b></div>', [])).toThrowError(`Template parse errors: + it('should report invalid reference names', () => { + expect(() => parse('<div #a-b></div>', [])).toThrowError(`Template parse errors: "-" is not allowed in reference names ("<div [ERROR ->]#a-b></div>"): TestComp@0:5`); - }); + }); - it('should report missing reference names', () => { - expect(() => parse('<div #></div>', [])).toThrowError(`Template parse errors: + it('should report missing reference names', () => { + expect(() => parse('<div #></div>', [])).toThrowError(`Template parse errors: Reference does not have a name ("<div [ERROR ->]#></div>"): TestComp@0:5`); - }); + }); - it('should report variables as errors', () => { - expect(() => parse('<div let-a></div>', [])).toThrowError(`Template parse errors: + it('should report variables as errors', () => { + expect(() => parse('<div let-a></div>', [])).toThrowError(`Template parse errors: "let-" is only supported on ng-template elements. ("<div [ERROR ->]let-a></div>"): TestComp@0:5`); - }); + }); - it('should report missing variable names', () => { - expect(() => parse('<ng-template let-></ng-template>', [])) - .toThrowError(`Template parse errors: + it('should report missing variable names', () => { + expect(() => parse('<ng-template let-></ng-template>', [])) + .toThrowError(`Template parse errors: Variable does not have a name ("<ng-template [ERROR ->]let-></ng-template>"): TestComp@0:13`); - }); + }); - it('should report duplicate reference names', () => { - expect(() => parse('<div #a></div><div #a></div>', [])) - .toThrowError(`Template parse errors: + it('should report duplicate reference names', () => { + expect(() => parse('<div #a></div><div #a></div>', [])).toThrowError(`Template parse errors: Reference "#a" is defined several times ("<div #a></div><div [ERROR ->]#a></div>"): TestComp@0:19`); - - }); - - it('should report duplicate reference names when using multiple exportAs names', () => { - const pizzaDirective = - compileDirectiveMetadataCreate({ - selector: '[dessert-pizza]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Pizza'}}), - exportAs: 'dessertPizza, chocolate' - }).toSummary(); - - const chocolateDirective = - compileDirectiveMetadataCreate({ - selector: '[chocolate]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Chocolate'}}), - exportAs: 'chocolate' - }).toSummary(); - - const template = '<div dessert-pizza chocolate #snack="chocolate"></div>'; - const compileTemplate = () => parse(template, [pizzaDirective, chocolateDirective]); - const duplicateReferenceError = 'Template parse errors:\n' + - 'Reference "#snack" is defined several times ' + - '("<div dessert-pizza chocolate [ERROR ->]#snack="chocolate"></div>")' + - ': TestComp@0:29'; - - expect(compileTemplate).toThrowError(duplicateReferenceError); - }); - - it('should not throw error when there is same reference name in different templates', - () => { - expect(() => parse('<div #a><ng-template #a><span>OK</span></ng-template></div>', [])) - .not.toThrowError(); - }); - - it('should assign references with empty value to components', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: '[a]', - isComponent: true, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - exportAs: 'dirA', - template: compileTemplateMetadata({ngContentSelectors: []}) - }).toSummary(); - expect(humanizeTplAst(parse('<div a #a></div>', [dirA]))).toEqual([ - [ElementAst, 'div'], - [AttrAst, 'a', ''], - [ReferenceAst, 'a', createTokenForReference(dirA.type.reference)], - [DirectiveAst, dirA], - ]); - }); - - it('should not locate directives in references', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<div ref-a>', [dirA]))).toEqual([ - [ElementAst, 'div'], [ReferenceAst, 'a', null] - ]); - }); }); - describe('explicit templates', () => { - let reflector: JitReflector; - - beforeEach(() => { reflector = new JitReflector(); }); - - it('should create embedded templates for <ng-template> elements', () => { - expect(humanizeTplAst(parse('<ng-template></ng-template>', [ - ]))).toEqual([[EmbeddedTemplateAst]]); - }); - - it('should create embedded templates for <ng-template> elements regardless the namespace', - () => { - expect(humanizeTplAst(parse('<svg><ng-template></ng-template></svg>', []))).toEqual([ - [ElementAst, ':svg:svg'], - [EmbeddedTemplateAst], - ]); - }); - - it('should support references via #...', () => { - expect(humanizeTplAst(parse('<ng-template #a>', []))).toEqual([ - [EmbeddedTemplateAst], - [ - ReferenceAst, 'a', createTokenForExternalReference(reflector, Identifiers.TemplateRef) - ], - ]); - }); - - it('should support references via ref-...', () => { - expect(humanizeTplAst(parse('<ng-template ref-a>', []))).toEqual([ - [EmbeddedTemplateAst], - [ - ReferenceAst, 'a', createTokenForExternalReference(reflector, Identifiers.TemplateRef) - ] - ]); - }); + it('should report duplicate reference names when using multiple exportAs names', () => { + const pizzaDirective = + compileDirectiveMetadataCreate({ + selector: '[dessert-pizza]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Pizza'}}), + exportAs: 'dessertPizza, chocolate' + }).toSummary(); - it('should parse variables via let-...', () => { - expect(humanizeTplAst(parse('<ng-template let-a="b">', []))).toEqual([ - [EmbeddedTemplateAst], - [VariableAst, 'a', 'b'], - ]); - }); + const chocolateDirective = + compileDirectiveMetadataCreate({ + selector: '[chocolate]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'Chocolate'}}), + exportAs: 'chocolate' + }).toSummary(); - it('should not locate directives in variables', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<ng-template let-a="b"></ng-template>', [dirA]))).toEqual([ - [EmbeddedTemplateAst], - [VariableAst, 'a', 'b'], - ]); - }); + const template = '<div dessert-pizza chocolate #snack="chocolate"></div>'; + const compileTemplate = () => parse(template, [pizzaDirective, chocolateDirective]); + const duplicateReferenceError = 'Template parse errors:\n' + + 'Reference "#snack" is defined several times ' + + '("<div dessert-pizza chocolate [ERROR ->]#snack="chocolate"></div>")' + + ': TestComp@0:29'; + expect(compileTemplate).toThrowError(duplicateReferenceError); }); - describe('inline templates', () => { - it('should report an error on variables declared with #', () => { - expect(() => humanizeTplAst(parse('<div *ngIf="#a=b">', []))) - .toThrowError(/Parser Error: Unexpected token # at column 1/); - }); - - it('should parse variables via let ...', () => { - const targetAst = [ - [EmbeddedTemplateAst], - [VariableAst, 'a', 'b'], - [ElementAst, 'div'], - ]; - - expect(humanizeTplAst(parse('<div *ngIf="let a=b">', []))).toEqual(targetAst); - - expect(humanizeTplAst(parse('<div data-*ngIf="let a=b">', []))).toEqual(targetAst); - }); - - it('should parse variables via as ...', () => { - const targetAst = [ - [EmbeddedTemplateAst], - [VariableAst, 'local', 'ngIf'], - [DirectiveAst, ngIf], - [BoundDirectivePropertyAst, 'ngIf', 'expr'], - [ElementAst, 'div'], - ]; - - expect(humanizeTplAst(parse('<div *ngIf="expr as local">', [ngIf]))).toEqual(targetAst); - }); - - describe('directives', () => { - it('should locate directives in property bindings', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a=b]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['a'] - }).toSummary(); - const dirB = - compileDirectiveMetadataCreate({ - selector: '[b]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<div *a="b" b>', [dirA, dirB]))).toEqual([ - [EmbeddedTemplateAst], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'a', 'b'], - [ElementAst, 'div'], [AttrAst, 'b', ''], [DirectiveAst, dirB] - ]); - }); - - it('should not locate directives in variables', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - expect( - humanizeTplAst(parse('<ng-template let-a="b"><div></div></ng-template>', [dirA]))) - .toEqual([ - [EmbeddedTemplateAst], - [VariableAst, 'a', 'b'], - [ElementAst, 'div'], - ]); - }); - - it('should not locate directives in references', () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - expect(humanizeTplAst(parse('<div ref-a>', [dirA]))).toEqual([ - [ElementAst, 'div'], [ReferenceAst, 'a', null] - ]); - }); - - }); - - - it('should work with *... and use the attribute name as property binding name', () => { - expect(humanizeTplAst(parse('<div *ngIf="test">', [ngIf]))).toEqual([ - [EmbeddedTemplateAst], - [DirectiveAst, ngIf], - [BoundDirectivePropertyAst, 'ngIf', 'test'], - [ElementAst, 'div'], - - ]); + it('should not throw error when there is same reference name in different templates', () => { + expect(() => parse('<div #a><ng-template #a><span>OK</span></ng-template></div>', [])) + .not.toThrowError(); + }); - // https://github.com/angular/angular/issues/13800 - expect(humanizeTplAst(parse('<div *ngIf="-1">', [ngIf]))).toEqual([ - [EmbeddedTemplateAst], - [DirectiveAst, ngIf], - [BoundDirectivePropertyAst, 'ngIf', '0 - 1'], - [ElementAst, 'div'], - ]); - }); + it('should assign references with empty value to components', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + isComponent: true, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + exportAs: 'dirA', + template: compileTemplateMetadata({ngContentSelectors: []}) + }).toSummary(); + expect(humanizeTplAst(parse('<div a #a></div>', [dirA]))).toEqual([ + [ElementAst, 'div'], + [AttrAst, 'a', ''], + [ReferenceAst, 'a', createTokenForReference(dirA.type.reference)], + [DirectiveAst, dirA], + ]); + }); - it('should work with *... and empty value', () => { - expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([ - [EmbeddedTemplateAst], - [DirectiveAst, ngIf], - [BoundDirectivePropertyAst, 'ngIf', 'null'], - [ElementAst, 'div'], - ]); - }); + it('should not locate directives in references', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<div ref-a>', [dirA]))).toEqual([ + [ElementAst, 'div'], [ReferenceAst, 'a', null] + ]); }); }); - describe('content projection', () => { - let compCounter: number; - beforeEach(() => { compCounter = 0; }); + describe('explicit templates', () => { + let reflector: JitReflector; - function createComp(selector: string, ngContentSelectors: string[]): CompileDirectiveSummary { - return compileDirectiveMetadataCreate({ - selector: selector, - isComponent: true, - type: createTypeMeta( - {reference: {filePath: someModuleUrl, name: `SomeComp${compCounter++}`}}), - template: compileTemplateMetadata({ngContentSelectors: ngContentSelectors}) - }) - .toSummary(); - } - - function createDir(selector: string): CompileDirectiveSummary { - return compileDirectiveMetadataCreate({ - selector: selector, - type: createTypeMeta( - {reference: {filePath: someModuleUrl, name: `SomeDir${compCounter++}`}}) - }) - .toSummary(); - } - - describe('project text nodes', () => { - it('should project text nodes with wildcard selector', () => { - expect(humanizeContentProjection(parse('<div>hello</div>', [createComp('div', ['*'])]))) - .toEqual([ - ['div', null], - ['#text(hello)', 0], - ]); - }); + beforeEach(() => { + reflector = new JitReflector(); }); - describe('project elements', () => { - it('should project elements with wildcard selector', () => { - expect(humanizeContentProjection(parse('<div><span></span></div>', [ - createComp('div', ['*']) - ]))).toEqual([['div', null], ['span', 0]]); - }); - - it('should project elements with css selector', () => { - expect(humanizeContentProjection( - parse('<div><a x></a><b></b></div>', [createComp('div', ['a[x]'])]))) - .toEqual([ - ['div', null], - ['a', 0], - ['b', null], - ]); - }); + it('should create embedded templates for <ng-template> elements', () => { + expect(humanizeTplAst(parse('<ng-template></ng-template>', []))).toEqual([ + [EmbeddedTemplateAst] + ]); }); - describe('embedded templates', () => { - it('should project embedded templates with wildcard selector', () => { - expect(humanizeContentProjection( - parse('<div><ng-template></ng-template></div>', [createComp('div', ['*'])]))) - .toEqual([ - ['div', null], - ['template', 0], - ]); - }); + it('should create embedded templates for <ng-template> elements regardless the namespace', + () => { + expect(humanizeTplAst(parse('<svg><ng-template></ng-template></svg>', []))).toEqual([ + [ElementAst, ':svg:svg'], + [EmbeddedTemplateAst], + ]); + }); - it('should project embedded templates with css selector', () => { - expect(humanizeContentProjection(parse( - '<div><ng-template x></ng-template><ng-template></ng-template></div>', - [createComp('div', ['ng-template[x]'])]))) - .toEqual([ - ['div', null], - ['template', 0], - ['template', null], - ]); - }); + it('should support references via #...', () => { + expect(humanizeTplAst(parse('<ng-template #a>', []))).toEqual([ + [EmbeddedTemplateAst], + [ReferenceAst, 'a', createTokenForExternalReference(reflector, Identifiers.TemplateRef)], + ]); }); - describe('ng-content', () => { - it('should project ng-content with wildcard selector', () => { - expect(humanizeContentProjection(parse('<div><ng-content></ng-content></div>', [ - createComp('div', ['*']) - ]))).toEqual([['div', null], ['ng-content', 0]]); - }); - - it('should project ng-content with css selector', () => { - expect(humanizeContentProjection(parse( - '<div><ng-content x></ng-content><ng-content></ng-content></div>', - [createComp('div', ['ng-content[x]'])]))) - .toEqual([['div', null], ['ng-content', 0], ['ng-content', null]]); - }); + it('should support references via ref-...', () => { + expect(humanizeTplAst(parse('<ng-template ref-a>', []))).toEqual([ + [EmbeddedTemplateAst], + [ReferenceAst, 'a', createTokenForExternalReference(reflector, Identifiers.TemplateRef)] + ]); }); - it('should project into the first matching ng-content', () => { - expect(humanizeContentProjection(parse('<div>hello<b></b><a></a></div>', [ - createComp('div', ['a', 'b', '*']) - ]))).toEqual([['div', null], ['#text(hello)', 2], ['b', 1], ['a', 0]]); + it('should parse variables via let-...', () => { + expect(humanizeTplAst(parse('<ng-template let-a="b">', []))).toEqual([ + [EmbeddedTemplateAst], + [VariableAst, 'a', 'b'], + ]); }); - it('should project into wildcard ng-content last', () => { - expect(humanizeContentProjection(parse('<div>hello<a></a></div>', [ - createComp('div', ['*', 'a']) - ]))).toEqual([['div', null], ['#text(hello)', 0], ['a', 1]]); + it('should not locate directives in variables', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<ng-template let-a="b"></ng-template>', [dirA]))).toEqual([ + [EmbeddedTemplateAst], + [VariableAst, 'a', 'b'], + ]); }); + }); - it('should only project direct child nodes', () => { - expect(humanizeContentProjection(parse('<div><span><a></a></span><a></a></div>', [ - createComp('div', ['a']) - ]))).toEqual([['div', null], ['span', null], ['a', null], ['a', 0]]); + describe('inline templates', () => { + it('should report an error on variables declared with #', () => { + expect(() => humanizeTplAst(parse('<div *ngIf="#a=b">', []))) + .toThrowError(/Parser Error: Unexpected token # at column 1/); }); - it('should project nodes of nested components', () => { - expect(humanizeContentProjection(parse('<a><b>hello</b></a>', [ - createComp('a', ['*']), createComp('b', ['*']) - ]))).toEqual([['a', null], ['b', 0], ['#text(hello)', 0]]); - }); + it('should parse variables via let ...', () => { + const targetAst = [ + [EmbeddedTemplateAst], + [VariableAst, 'a', 'b'], + [ElementAst, 'div'], + ]; - it('should project children of components with ngNonBindable', () => { - expect(humanizeContentProjection(parse('<div ngNonBindable>{{hello}}<span></span></div>', [ - createComp('div', ['*']) - ]))).toEqual([['div', null], ['#text({{hello}})', 0], ['span', 0]]); - }); + expect(humanizeTplAst(parse('<div *ngIf="let a=b">', []))).toEqual(targetAst); - it('should match the element when there is an inline template', () => { - expect(humanizeContentProjection(parse('<div><b *ngIf="cond"></b></div>', [ - createComp('div', ['a', 'b']), ngIf - ]))).toEqual([['div', null], ['template', 1], ['b', null]]); + expect(humanizeTplAst(parse('<div data-*ngIf="let a=b">', []))).toEqual(targetAst); }); - describe('ngProjectAs', () => { - it('should override elements', () => { - expect(humanizeContentProjection(parse('<div><a ngProjectAs="b"></a></div>', [ - createComp('div', ['a', 'b']) - ]))).toEqual([['div', null], ['a', 1]]); - }); + it('should parse variables via as ...', () => { + const targetAst = [ + [EmbeddedTemplateAst], + [VariableAst, 'local', 'ngIf'], + [DirectiveAst, ngIf], + [BoundDirectivePropertyAst, 'ngIf', 'expr'], + [ElementAst, 'div'], + ]; + + expect(humanizeTplAst(parse('<div *ngIf="expr as local">', [ngIf]))).toEqual(targetAst); + }); - it('should override <ng-content>', () => { - expect(humanizeContentProjection(parse( - '<div><ng-content ngProjectAs="b"></ng-content></div>', - [createComp('div', ['ng-content', 'b'])]))) - .toEqual([['div', null], ['ng-content', 1]]); + describe('directives', () => { + it('should locate directives in property bindings', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a=b]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['a'] + }).toSummary(); + const dirB = compileDirectiveMetadataCreate({ + selector: '[b]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<div *a="b" b>', [dirA, dirB]))).toEqual([ + [EmbeddedTemplateAst], [DirectiveAst, dirA], [BoundDirectivePropertyAst, 'a', 'b'], + [ElementAst, 'div'], [AttrAst, 'b', ''], [DirectiveAst, dirB] + ]); }); - it('should override <ng-template>', () => { - expect(humanizeContentProjection(parse( - '<div><ng-template ngProjectAs="b"></ng-template></div>', - [createComp('div', ['template', 'b'])]))) + it('should not locate directives in variables', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<ng-template let-a="b"><div></div></ng-template>', [dirA]))) .toEqual([ - ['div', null], - ['template', 1], + [EmbeddedTemplateAst], + [VariableAst, 'a', 'b'], + [ElementAst, 'div'], ]); }); - it('should override inline templates', () => { - expect(humanizeContentProjection(parse( - '<div><a *ngIf="cond" ngProjectAs="b"></a></div>', - [createComp('div', ['a', 'b']), ngIf]))) - .toEqual([ - ['div', null], - ['template', 1], - ['a', null], - ]); + it('should not locate directives in references', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + expect(humanizeTplAst(parse('<div ref-a>', [dirA]))).toEqual([ + [ElementAst, 'div'], [ReferenceAst, 'a', null] + ]); }); }); - it('should support other directives before the component', () => { - expect(humanizeContentProjection(parse('<div>hello</div>', [ - createDir('div'), createComp('div', ['*']) - ]))).toEqual([['div', null], ['#text(hello)', 0]]); - }); - }); - describe('splitClasses', () => { - it('should keep an empty class', () => { expect(splitClasses('a')).toEqual(['a']); }); + it('should work with *... and use the attribute name as property binding name', () => { + expect(humanizeTplAst(parse('<div *ngIf="test">', [ngIf]))).toEqual([ + [EmbeddedTemplateAst], + [DirectiveAst, ngIf], + [BoundDirectivePropertyAst, 'ngIf', 'test'], + [ElementAst, 'div'], - it('should split 2 classes', () => { expect(splitClasses('a b')).toEqual(['a', 'b']); }); + ]); - it('should trim classes', () => { expect(splitClasses(' a b ')).toEqual(['a', 'b']); }); - }); + // https://github.com/angular/angular/issues/13800 + expect(humanizeTplAst(parse('<div *ngIf="-1">', [ngIf]))).toEqual([ + [EmbeddedTemplateAst], + [DirectiveAst, ngIf], + [BoundDirectivePropertyAst, 'ngIf', '0 - 1'], + [ElementAst, 'div'], + ]); + }); - describe('error cases', () => { - it('should report when ng-content has non WS content', () => { - expect(() => parse('<ng-content>content</ng-content>', [])) - .toThrowError( - `Template parse errors:\n` + - `<ng-content> element cannot have content. ("[ERROR ->]<ng-content>content</ng-content>"): TestComp@0:0`); + it('should work with *... and empty value', () => { + expect(humanizeTplAst(parse('<div *ngIf>', [ngIf]))).toEqual([ + [EmbeddedTemplateAst], + [DirectiveAst, ngIf], + [BoundDirectivePropertyAst, 'ngIf', 'null'], + [ElementAst, 'div'], + ]); }); + }); + }); - it('should treat *attr on a template element as valid', - () => { expect(() => parse('<ng-template *ngIf>', [])).not.toThrowError(); }); + describe('content projection', () => { + let compCounter: number; + beforeEach(() => { + compCounter = 0; + }); - it('should report when multiple *attrs are used on the same element', () => { - expect(() => parse('<div *ngIf *ngFor>', [])).toThrowError(`Template parse errors: -Can't have multiple template bindings on one element. Use only one attribute prefixed with * ("<div *ngIf [ERROR ->]*ngFor>"): TestComp@0:11`); - }); + function createComp(selector: string, ngContentSelectors: string[]): CompileDirectiveSummary { + return compileDirectiveMetadataCreate({ + selector: selector, + isComponent: true, + type: createTypeMeta( + {reference: {filePath: someModuleUrl, name: `SomeComp${compCounter++}`}}), + template: compileTemplateMetadata({ngContentSelectors: ngContentSelectors}) + }) + .toSummary(); + } + function createDir(selector: string): CompileDirectiveSummary { + return compileDirectiveMetadataCreate({ + selector: selector, + type: createTypeMeta( + {reference: {filePath: someModuleUrl, name: `SomeDir${compCounter++}`}}) + }) + .toSummary(); + } - it('should report invalid property names', () => { - expect(() => parse('<div [invalidProp]></div>', [])).toThrowError(`Template parse errors: -Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("<div [ERROR ->][invalidProp]></div>"): TestComp@0:5`); + describe('project text nodes', () => { + it('should project text nodes with wildcard selector', () => { + expect(humanizeContentProjection(parse('<div>hello</div>', [createComp('div', ['*'])]))) + .toEqual([ + ['div', null], + ['#text(hello)', 0], + ]); }); + }); - it('should report invalid host property names', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - host: {'[invalidProp]': 'someProp'} - }).toSummary(); - expect(() => parse('<div></div>', [dirA])).toThrowError(`Template parse errors: -Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("[ERROR ->]<div></div>"): TestComp@0:0, Directive DirA`); + describe('project elements', () => { + it('should project elements with wildcard selector', () => { + expect(humanizeContentProjection(parse('<div><span></span></div>', [ + createComp('div', ['*']) + ]))).toEqual([['div', null], ['span', 0]]); }); - it('should report errors in expressions', () => { - expect(() => parse('<div [prop]="a b"></div>', [])).toThrowError(`Template parse errors: -Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp@0:13 ("<div [prop]="[ERROR ->]a b"></div>"): TestComp@0:13`); + it('should project elements with css selector', () => { + expect(humanizeContentProjection( + parse('<div><a x></a><b></b></div>', [createComp('div', ['a[x]'])]))) + .toEqual([ + ['div', null], + ['a', 0], + ['b', null], + ]); }); + }); - it('should not throw on invalid property names if the property is used by a directive', - () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['invalidProp'] - }).toSummary(); - expect(() => parse('<div [invalid-prop]></div>', [dirA])).not.toThrow(); - }); - - it('should not allow more than 1 component per element', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - isComponent: true, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - template: compileTemplateMetadata({ngContentSelectors: []}) - }).toSummary(); - const dirB = compileDirectiveMetadataCreate({ - selector: 'div', - isComponent: true, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}), - template: compileTemplateMetadata({ngContentSelectors: []}) - }).toSummary(); - expect(() => parse('<div>', [dirB, dirA])) - .toThrowError( - `Template parse errors:\n` + - `More than one component matched on this element.\n` + - `Make sure that only one component's selector can match a given element.\n` + - `Conflicting components: DirB,DirA ("[ERROR ->]<div>"): TestComp@0:0`); + describe('embedded templates', () => { + it('should project embedded templates with wildcard selector', () => { + expect(humanizeContentProjection( + parse('<div><ng-template></ng-template></div>', [createComp('div', ['*'])]))) + .toEqual([ + ['div', null], + ['template', 0], + ]); }); - it('should not allow components or element bindings nor dom events on explicit embedded templates', - () => { - const dirA = - compileDirectiveMetadataCreate({ - selector: '[a]', - isComponent: true, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - template: compileTemplateMetadata({ngContentSelectors: []}) - }).toSummary(); - - expect(() => parse('<ng-template [a]="b" (e)="f"></ng-template>', [dirA])) - .toThrowError(`Template parse errors: -Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("<ng-template [a]="b" [ERROR ->](e)="f"></ng-template>"): TestComp@0:21 -Components on an embedded template: DirA ("[ERROR ->]<ng-template [a]="b" (e)="f"></ng-template>"): TestComp@0:0 -Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("[ERROR ->]<ng-template [a]="b" (e)="f"></ng-template>"): TestComp@0:0`); - }); - - it('should not allow components or element bindings on inline embedded templates', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: '[a]', - isComponent: true, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - template: compileTemplateMetadata({ngContentSelectors: []}) - }).toSummary(); - expect(() => parse('<div *a="b"></div>', [dirA])).toThrowError(`Template parse errors: -Components on an embedded template: DirA ("[ERROR ->]<div *a="b"></div>"): TestComp@0:0 -Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("[ERROR ->]<div *a="b"></div>"): TestComp@0:0`); + it('should project embedded templates with css selector', () => { + expect(humanizeContentProjection(parse( + '<div><ng-template x></ng-template><ng-template></ng-template></div>', + [createComp('div', ['ng-template[x]'])]))) + .toEqual([ + ['div', null], + ['template', 0], + ['template', null], + ]); }); }); - describe('ignore elements', () => { - it('should ignore <script> elements', () => { - expect(humanizeTplAst(parse('<script></script>a', []))).toEqual([[TextAst, 'a']]); - + describe('ng-content', () => { + it('should project ng-content with wildcard selector', () => { + expect(humanizeContentProjection(parse('<div><ng-content></ng-content></div>', [ + createComp('div', ['*']) + ]))).toEqual([['div', null], ['ng-content', 0]]); }); - it('should ignore <style> elements', () => { - expect(humanizeTplAst(parse('<style></style>a', []))).toEqual([[TextAst, 'a']]); + it('should project ng-content with css selector', () => { + expect(humanizeContentProjection(parse( + '<div><ng-content x></ng-content><ng-content></ng-content></div>', + [createComp('div', ['ng-content[x]'])]))) + .toEqual([['div', null], ['ng-content', 0], ['ng-content', null]]); }); + }); - describe('<link rel="stylesheet">', () => { + it('should project into the first matching ng-content', () => { + expect(humanizeContentProjection(parse('<div>hello<b></b><a></a></div>', [ + createComp('div', ['a', 'b', '*']) + ]))).toEqual([['div', null], ['#text(hello)', 2], ['b', 1], ['a', 0]]); + }); - it('should keep <link rel="stylesheet"> elements if they have an absolute url', () => { - expect(humanizeTplAst(parse('<link rel="stylesheet" href="http://someurl">a', []))) - .toEqual([ - [ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'], - [AttrAst, 'href', 'http://someurl'], [TextAst, 'a'] - ]); - }); + it('should project into wildcard ng-content last', () => { + expect(humanizeContentProjection(parse('<div>hello<a></a></div>', [ + createComp('div', ['*', 'a']) + ]))).toEqual([['div', null], ['#text(hello)', 0], ['a', 1]]); + }); - it('should keep <link rel="stylesheet"> elements if they have no uri', () => { - expect(humanizeTplAst(parse('<link rel="stylesheet">a', [ - ]))).toEqual([[ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'], [TextAst, 'a']]); - expect(humanizeTplAst(parse('<link REL="stylesheet">a', [ - ]))).toEqual([[ElementAst, 'link'], [AttrAst, 'REL', 'stylesheet'], [TextAst, 'a']]); - }); + it('should only project direct child nodes', () => { + expect(humanizeContentProjection(parse('<div><span><a></a></span><a></a></div>', [ + createComp('div', ['a']) + ]))).toEqual([['div', null], ['span', null], ['a', null], ['a', 0]]); + }); - it('should ignore <link rel="stylesheet"> elements if they have a relative uri', () => { - expect(humanizeTplAst(parse('<link rel="stylesheet" href="./other.css">a', [ - ]))).toEqual([[TextAst, 'a']]); - expect(humanizeTplAst(parse('<link rel="stylesheet" HREF="./other.css">a', [ - ]))).toEqual([[TextAst, 'a']]); - }); + it('should project nodes of nested components', () => { + expect(humanizeContentProjection(parse('<a><b>hello</b></a>', [ + createComp('a', ['*']), createComp('b', ['*']) + ]))).toEqual([['a', null], ['b', 0], ['#text(hello)', 0]]); + }); - it('should ignore <link rel="stylesheet"> elements if they have a package: uri', () => { - expect(humanizeTplAst(parse('<link rel="stylesheet" href="package:somePackage">a', [ - ]))).toEqual([[TextAst, 'a']]); - }); + it('should project children of components with ngNonBindable', () => { + expect(humanizeContentProjection(parse('<div ngNonBindable>{{hello}}<span></span></div>', [ + createComp('div', ['*']) + ]))).toEqual([['div', null], ['#text({{hello}})', 0], ['span', 0]]); + }); - }); + it('should match the element when there is an inline template', () => { + expect(humanizeContentProjection(parse('<div><b *ngIf="cond"></b></div>', [ + createComp('div', ['a', 'b']), ngIf + ]))).toEqual([['div', null], ['template', 1], ['b', null]]); + }); - it('should ignore bindings on children of elements with ngNonBindable', () => { - expect(humanizeTplAst(parse('<div ngNonBindable>{{b}}</div>', [ - ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, '{{b}}']]); + describe('ngProjectAs', () => { + it('should override elements', () => { + expect(humanizeContentProjection(parse('<div><a ngProjectAs="b"></a></div>', [ + createComp('div', ['a', 'b']) + ]))).toEqual([['div', null], ['a', 1]]); }); - it('should keep nested children of elements with ngNonBindable', () => { - expect(humanizeTplAst(parse('<div ngNonBindable><span>{{b}}</span></div>', []))).toEqual([ - [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [ElementAst, 'span'], - [TextAst, '{{b}}'] - ]); + it('should override <ng-content>', () => { + expect(humanizeContentProjection(parse( + '<div><ng-content ngProjectAs="b"></ng-content></div>', + [createComp('div', ['ng-content', 'b'])]))) + .toEqual([['div', null], ['ng-content', 1]]); }); - it('should ignore <script> elements inside of elements with ngNonBindable', () => { - expect(humanizeTplAst(parse('<div ngNonBindable><script></script>a</div>', [ - ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, 'a']]); + it('should override <ng-template>', () => { + expect(humanizeContentProjection(parse( + '<div><ng-template ngProjectAs="b"></ng-template></div>', + [createComp('div', ['template', 'b'])]))) + .toEqual([ + ['div', null], + ['template', 1], + ]); }); - it('should ignore <style> elements inside of elements with ngNonBindable', () => { - expect(humanizeTplAst(parse('<div ngNonBindable><style></style>a</div>', [ - ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, 'a']]); + it('should override inline templates', () => { + expect(humanizeContentProjection(parse( + '<div><a *ngIf="cond" ngProjectAs="b"></a></div>', + [createComp('div', ['a', 'b']), ngIf]))) + .toEqual([ + ['div', null], + ['template', 1], + ['a', null], + ]); }); + }); - it('should ignore <link rel="stylesheet"> elements inside of elements with ngNonBindable', - () => { - expect(humanizeTplAst(parse('<div ngNonBindable><link rel="stylesheet">a</div>', [ - ]))).toEqual([[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, 'a']]); - }); + it('should support other directives before the component', () => { + expect(humanizeContentProjection(parse('<div>hello</div>', [ + createDir('div'), createComp('div', ['*']) + ]))).toEqual([['div', null], ['#text(hello)', 0]]); + }); + }); - it('should convert <ng-content> elements into regular elements inside of elements with ngNonBindable', - () => { - expect(humanizeTplAst(parse('<div ngNonBindable><ng-content></ng-content>a</div>', []))) - .toEqual([ - [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [ElementAst, 'ng-content'], - [TextAst, 'a'] - ]); - }); + describe('splitClasses', () => { + it('should keep an empty class', () => { + expect(splitClasses('a')).toEqual(['a']); + }); + it('should split 2 classes', () => { + expect(splitClasses('a b')).toEqual(['a', 'b']); }); - describe('source spans', () => { - it('should support ng-content', () => { - const parsed = parse('<ng-content select="a">', []); - expect(humanizeTplAstSourceSpans(parsed)).toEqual([ - [NgContentAst, '<ng-content select="a">'] - ]); - }); + it('should trim classes', () => { + expect(splitClasses(' a b ')).toEqual(['a', 'b']); + }); + }); - it('should support embedded template', () => { - expect(humanizeTplAstSourceSpans(parse('<ng-template></ng-template>', [ - ]))).toEqual([[EmbeddedTemplateAst, '<ng-template>']]); - }); + describe('error cases', () => { + it('should report when ng-content has non WS content', () => { + expect(() => parse('<ng-content>content</ng-content>', [])) + .toThrowError( + `Template parse errors:\n` + + `<ng-content> element cannot have content. ("[ERROR ->]<ng-content>content</ng-content>"): TestComp@0:0`); + }); - it('should support element and attributes', () => { - expect(humanizeTplAstSourceSpans(parse('<div key=value>', []))).toEqual([ - [ElementAst, 'div', '<div key=value>'], [AttrAst, 'key', 'value', 'key=value'] - ]); + it('should treat *attr on a template element as valid', () => { + expect(() => parse('<ng-template *ngIf>', [])).not.toThrowError(); + }); - }); + it('should report when multiple *attrs are used on the same element', () => { + expect(() => parse('<div *ngIf *ngFor>', [])).toThrowError(`Template parse errors: +Can't have multiple template bindings on one element. Use only one attribute prefixed with * ("<div *ngIf [ERROR ->]*ngFor>"): TestComp@0:11`); + }); - it('should support references', () => { - expect(humanizeTplAstSourceSpans(parse('<div #a></div>', [ - ]))).toEqual([[ElementAst, 'div', '<div #a>'], [ReferenceAst, 'a', null, '#a']]); - }); - it('should support variables', () => { - expect(humanizeTplAstSourceSpans(parse('<ng-template let-a="b"></ng-template>', []))) - .toEqual([ - [EmbeddedTemplateAst, '<ng-template let-a="b">'], - [VariableAst, 'a', 'b', 'let-a="b"'], - ]); - }); + it('should report invalid property names', () => { + expect(() => parse('<div [invalidProp]></div>', [])).toThrowError(`Template parse errors: +Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("<div [ERROR ->][invalidProp]></div>"): TestComp@0:5`); + }); - it('should support events', () => { - expect(humanizeTplAstSourceSpans(parse('<div (window:event)="v">', []))).toEqual([ - [ElementAst, 'div', '<div (window:event)="v">'], - [BoundEventAst, 'event', 'window', 'v', '(window:event)="v"'] - ]); + it('should report invalid host property names', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + host: {'[invalidProp]': 'someProp'} + }).toSummary(); + expect(() => parse('<div></div>', [dirA])).toThrowError(`Template parse errors: +Can't bind to 'invalidProp' since it isn't a known property of 'div'. ("[ERROR ->]<div></div>"): TestComp@0:0, Directive DirA`); + }); - }); + it('should report errors in expressions', () => { + expect(() => parse('<div [prop]="a b"></div>', [])).toThrowError(`Template parse errors: +Parser Error: Unexpected token 'b' at column 3 in [a b] in TestComp@0:13 ("<div [prop]="[ERROR ->]a b"></div>"): TestComp@0:13`); + }); - it('should support element property', () => { - expect(humanizeTplAstSourceSpans(parse('<div [someProp]="v">', []))).toEqual([ - [ElementAst, 'div', '<div [someProp]="v">'], - [ - BoundElementPropertyAst, PropertyBindingType.Property, 'someProp', 'v', null, - '[someProp]="v"' - ] - ]); - }); + it('should not throw on invalid property names if the property is used by a directive', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['invalidProp'] + }).toSummary(); + expect(() => parse('<div [invalid-prop]></div>', [dirA])).not.toThrow(); + }); - it('should support bound text', () => { - expect(humanizeTplAstSourceSpans(parse('{{a}}', [ - ]))).toEqual([[BoundTextAst, '{{ a }}', '{{a}}']]); - }); + it('should not allow more than 1 component per element', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + isComponent: true, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + template: compileTemplateMetadata({ngContentSelectors: []}) + }).toSummary(); + const dirB = compileDirectiveMetadataCreate({ + selector: 'div', + isComponent: true, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirB'}}), + template: compileTemplateMetadata({ngContentSelectors: []}) + }).toSummary(); + expect(() => parse('<div>', [dirB, dirA])) + .toThrowError( + `Template parse errors:\n` + + `More than one component matched on this element.\n` + + `Make sure that only one component's selector can match a given element.\n` + + `Conflicting components: DirB,DirA ("[ERROR ->]<div>"): TestComp@0:0`); + }); - it('should support text nodes', () => { - expect(humanizeTplAstSourceSpans(parse('a', []))).toEqual([[TextAst, 'a', 'a']]); - }); + it('should not allow components or element bindings nor dom events on explicit embedded templates', + () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + isComponent: true, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + template: compileTemplateMetadata({ngContentSelectors: []}) + }).toSummary(); + + expect(() => parse('<ng-template [a]="b" (e)="f"></ng-template>', [dirA])) + .toThrowError(`Template parse errors: +Event binding e not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("<ng-template [a]="b" [ERROR ->](e)="f"></ng-template>"): TestComp@0:21 +Components on an embedded template: DirA ("[ERROR ->]<ng-template [a]="b" (e)="f"></ng-template>"): TestComp@0:0 +Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("[ERROR ->]<ng-template [a]="b" (e)="f"></ng-template>"): TestComp@0:0`); + }); + + it('should not allow components or element bindings on inline embedded templates', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + isComponent: true, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + template: compileTemplateMetadata({ngContentSelectors: []}) + }).toSummary(); + expect(() => parse('<div *a="b"></div>', [dirA])).toThrowError(`Template parse errors: +Components on an embedded template: DirA ("[ERROR ->]<div *a="b"></div>"): TestComp@0:0 +Property binding a not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations". ("[ERROR ->]<div *a="b"></div>"): TestComp@0:0`); + }); + }); - it('should support directive', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: '[a]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) - }).toSummary(); - const comp = compileDirectiveMetadataCreate({ - selector: 'div', - isComponent: true, - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'ZComp'}}), - template: compileTemplateMetadata({ngContentSelectors: []}) - }).toSummary(); - expect(humanizeTplAstSourceSpans(parse('<div a>', [dirA, comp]))).toEqual([ - [ElementAst, 'div', '<div a>'], [AttrAst, 'a', '', 'a'], [DirectiveAst, dirA, '<div a>'], - [DirectiveAst, comp, '<div a>'] - ]); - }); + describe('ignore elements', () => { + it('should ignore <script> elements', () => { + expect(humanizeTplAst(parse('<script></script>a', []))).toEqual([[TextAst, 'a']]); + }); - it('should support directive in namespace', () => { - const tagSel = - compileDirectiveMetadataCreate({ - selector: 'circle', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'elDir'}}) - }).toSummary(); - const attrSel = - compileDirectiveMetadataCreate({ - selector: '[href]', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'attrDir'}}) - }).toSummary(); + it('should ignore <style> elements', () => { + expect(humanizeTplAst(parse('<style></style>a', []))).toEqual([[TextAst, 'a']]); + }); - expect(humanizeTplAstSourceSpans( - parse('<svg><circle /><use xlink:href="Port" /></svg>', [tagSel, attrSel]))) + describe('<link rel="stylesheet">', () => { + it('should keep <link rel="stylesheet"> elements if they have an absolute url', () => { + expect(humanizeTplAst(parse('<link rel="stylesheet" href="http://someurl">a', []))) .toEqual([ - [ElementAst, ':svg:svg', '<svg>'], - [ElementAst, ':svg:circle', '<circle />'], - [DirectiveAst, tagSel, '<circle />'], - [ElementAst, ':svg:use', '<use xlink:href="Port" />'], - [AttrAst, ':xlink:href', 'Port', 'xlink:href="Port"'], - [DirectiveAst, attrSel, '<use xlink:href="Port" />'], + [ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'], + [AttrAst, 'href', 'http://someurl'], [TextAst, 'a'] ]); }); - it('should support directive property', () => { - const dirA = compileDirectiveMetadataCreate({ - selector: 'div', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - inputs: ['aProp'] - }).toSummary(); - expect(humanizeTplAstSourceSpans(parse('<div [aProp]="foo"></div>', [dirA]))).toEqual([ - [ElementAst, 'div', '<div [aProp]="foo">'], [DirectiveAst, dirA, '<div [aProp]="foo">'], - [BoundDirectivePropertyAst, 'aProp', 'foo', '[aProp]="foo"'] + it('should keep <link rel="stylesheet"> elements if they have no uri', () => { + expect(humanizeTplAst(parse('<link rel="stylesheet">a', []))).toEqual([ + [ElementAst, 'link'], [AttrAst, 'rel', 'stylesheet'], [TextAst, 'a'] + ]); + expect(humanizeTplAst(parse('<link REL="stylesheet">a', []))).toEqual([ + [ElementAst, 'link'], [AttrAst, 'REL', 'stylesheet'], [TextAst, 'a'] ]); }); - it('should support endSourceSpan for elements', () => { - const tagSel = - compileDirectiveMetadataCreate({ - selector: 'circle', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'elDir'}}) - }).toSummary(); - const result = parse('<circle></circle>', [tagSel]); - const circle = result[0] as ElementAst; - expect(circle.endSourceSpan).toBeDefined(); - expect(circle.endSourceSpan !.start.offset).toBe(8); - expect(circle.endSourceSpan !.end.offset).toBe(17); + it('should ignore <link rel="stylesheet"> elements if they have a relative uri', () => { + expect(humanizeTplAst(parse('<link rel="stylesheet" href="./other.css">a', []))).toEqual([ + [TextAst, 'a'] + ]); + expect(humanizeTplAst(parse('<link rel="stylesheet" HREF="./other.css">a', []))).toEqual([ + [TextAst, 'a'] + ]); }); - it('should report undefined for endSourceSpan for elements without an end-tag', () => { - const ulSel = - compileDirectiveMetadataCreate({ - selector: 'ul', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'ulDir'}}) - }).toSummary(); - const liSel = - compileDirectiveMetadataCreate({ - selector: 'li', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'liDir'}}) - }).toSummary(); - const result = parse('<ul><li><li></ul>', [ulSel, liSel]); - const ul = result[0] as ElementAst; - const li = ul.children[0] as ElementAst; - expect(li.endSourceSpan).toBe(null); + it('should ignore <link rel="stylesheet"> elements if they have a package: uri', () => { + expect(humanizeTplAst(parse('<link rel="stylesheet" href="package:somePackage">a', []))) + .toEqual([[TextAst, 'a']]); }); }); - describe('pipes', () => { - it('should allow pipes that have been defined as dependencies', () => { - const testPipe = - new CompilePipeMetadata({ - name: 'test', - type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), - pure: false - }).toSummary(); - expect(() => parse('{{a | test}}', [], [testPipe])).not.toThrow(); - }); + it('should ignore bindings on children of elements with ngNonBindable', () => { + expect(humanizeTplAst(parse('<div ngNonBindable>{{b}}</div>', []))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, '{{b}}'] + ]); + }); - it('should report pipes as error that have not been defined as dependencies', () => { - expect(() => parse('{{a | test}}', [])).toThrowError(`Template parse errors: -The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`); - }); + it('should keep nested children of elements with ngNonBindable', () => { + expect(humanizeTplAst(parse('<div ngNonBindable><span>{{b}}</span></div>', []))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [ElementAst, 'span'], + [TextAst, '{{b}}'] + ]); + }); + it('should ignore <script> elements inside of elements with ngNonBindable', () => { + expect(humanizeTplAst(parse('<div ngNonBindable><script></script>a</div>', []))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, 'a'] + ]); }); - describe('ICU messages', () => { - it('should expand plural messages', () => { - const shortForm = '{ count, plural, =0 {small} many {big} }'; - const expandedForm = '<ng-container [ngPlural]="count">' + - '<ng-template ngPluralCase="=0">small</ng-template>' + - '<ng-template ngPluralCase="many">big</ng-template>' + - '</ng-container>'; + it('should ignore <style> elements inside of elements with ngNonBindable', () => { + expect(humanizeTplAst(parse('<div ngNonBindable><style></style>a</div>', []))).toEqual([ + [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, 'a'] + ]); + }); - expect(humanizeTplAst(parse(shortForm, []))).toEqual(humanizeTplAst(parse(expandedForm, [ - ]))); - }); + it('should ignore <link rel="stylesheet"> elements inside of elements with ngNonBindable', + () => { + expect(humanizeTplAst(parse('<div ngNonBindable><link rel="stylesheet">a</div>', []))) + .toEqual([[ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [TextAst, 'a']]); + }); + + it('should convert <ng-content> elements into regular elements inside of elements with ngNonBindable', + () => { + expect(humanizeTplAst(parse('<div ngNonBindable><ng-content></ng-content>a</div>', []))) + .toEqual([ + [ElementAst, 'div'], [AttrAst, 'ngNonBindable', ''], [ElementAst, 'ng-content'], + [TextAst, 'a'] + ]); + }); + }); - it('should expand select messages', () => { - const shortForm = '{ sex, select, female {foo} other {bar} }'; - const expandedForm = '<ng-container [ngSwitch]="sex">' + - '<ng-template ngSwitchCase="female">foo</ng-template>' + - '<ng-template ngSwitchDefault>bar</ng-template>' + - '</ng-container>'; + describe('source spans', () => { + it('should support ng-content', () => { + const parsed = parse('<ng-content select="a">', []); + expect(humanizeTplAstSourceSpans(parsed)).toEqual([ + [NgContentAst, '<ng-content select="a">'] + ]); + }); - expect(humanizeTplAst(parse(shortForm, []))).toEqual(humanizeTplAst(parse(expandedForm, [ - ]))); - }); + it('should support embedded template', () => { + expect(humanizeTplAstSourceSpans(parse('<ng-template></ng-template>', []))).toEqual([ + [EmbeddedTemplateAst, '<ng-template>'] + ]); + }); - it('should be possible to escape ICU messages', () => { - const escapedForm = 'escaped {{ "{" }} }'; + it('should support element and attributes', () => { + expect(humanizeTplAstSourceSpans(parse('<div key=value>', []))).toEqual([ + [ElementAst, 'div', '<div key=value>'], [AttrAst, 'key', 'value', 'key=value'] + ]); + }); - expect(humanizeTplAst(parse(escapedForm, []))).toEqual([ - [BoundTextAst, 'escaped {{ "{" }} }'], - ]); - }); + it('should support references', () => { + expect(humanizeTplAstSourceSpans(parse('<div #a></div>', []))).toEqual([ + [ElementAst, 'div', '<div #a>'], [ReferenceAst, 'a', null, '#a'] + ]); }); - }); - describe('whitespaces removal', () => { + it('should support variables', () => { + expect(humanizeTplAstSourceSpans(parse('<ng-template let-a="b"></ng-template>', []))) + .toEqual([ + [EmbeddedTemplateAst, '<ng-template let-a="b">'], + [VariableAst, 'a', 'b', 'let-a="b"'], + ]); + }); - beforeEach(() => { - TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]}); - }); - - commonBeforeEach(); - - it('should not remove whitespaces by default', () => { - expect(humanizeTplAst(parse(' <br> <br>\t<br>\n<br> ', []))).toEqual([ - [TextAst, ' '], - [ElementAst, 'br'], - [TextAst, ' '], - [ElementAst, 'br'], - [TextAst, '\t'], - [ElementAst, 'br'], - [TextAst, '\n'], - [ElementAst, 'br'], - [TextAst, ' '], + it('should support events', () => { + expect(humanizeTplAstSourceSpans(parse('<div (window:event)="v">', []))).toEqual([ + [ElementAst, 'div', '<div (window:event)="v">'], + [BoundEventAst, 'event', 'window', 'v', '(window:event)="v"'] + ]); + }); + + it('should support element property', () => { + expect(humanizeTplAstSourceSpans(parse('<div [someProp]="v">', []))).toEqual([ + [ElementAst, 'div', '<div [someProp]="v">'], + [ + BoundElementPropertyAst, PropertyBindingType.Property, 'someProp', 'v', null, + '[someProp]="v"' + ] ]); }); - it('should replace each &ngsp; with a space when preserveWhitespaces is true', () => { - expect(humanizeTplAst(parse('foo&ngsp;&ngsp;&ngsp;bar', [], [], [], true))).toEqual([ - [TextAst, 'foo bar'], + it('should support bound text', () => { + expect(humanizeTplAstSourceSpans(parse('{{a}}', []))).toEqual([ + [BoundTextAst, '{{ a }}', '{{a}}'] ]); }); - it('should replace every &ngsp; with a single space when preserveWhitespaces is false', () => { - expect(humanizeTplAst(parse('foo&ngsp;&ngsp;&ngsp;bar', [], [], [], false))).toEqual([ - [TextAst, 'foo bar'], + it('should support text nodes', () => { + expect(humanizeTplAstSourceSpans(parse('a', []))).toEqual([[TextAst, 'a', 'a']]); + }); + + it('should support directive', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: '[a]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}) + }).toSummary(); + const comp = compileDirectiveMetadataCreate({ + selector: 'div', + isComponent: true, + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'ZComp'}}), + template: compileTemplateMetadata({ngContentSelectors: []}) + }).toSummary(); + expect(humanizeTplAstSourceSpans(parse('<div a>', [dirA, comp]))).toEqual([ + [ElementAst, 'div', '<div a>'], [AttrAst, 'a', '', 'a'], [DirectiveAst, dirA, '<div a>'], + [DirectiveAst, comp, '<div a>'] ]); }); - it('should remove whitespaces when explicitly requested', () => { - expect(humanizeTplAst(parse(' <br> <br>\t<br>\n<br> ', [], [], [], false))).toEqual([ - [ElementAst, 'br'], - [ElementAst, 'br'], - [ElementAst, 'br'], - [ElementAst, 'br'], + it('should support directive in namespace', () => { + const tagSel = compileDirectiveMetadataCreate({ + selector: 'circle', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'elDir'}}) + }).toSummary(); + const attrSel = + compileDirectiveMetadataCreate({ + selector: '[href]', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'attrDir'}}) + }).toSummary(); + + expect(humanizeTplAstSourceSpans( + parse('<svg><circle /><use xlink:href="Port" /></svg>', [tagSel, attrSel]))) + .toEqual([ + [ElementAst, ':svg:svg', '<svg>'], + [ElementAst, ':svg:circle', '<circle />'], + [DirectiveAst, tagSel, '<circle />'], + [ElementAst, ':svg:use', '<use xlink:href="Port" />'], + [AttrAst, ':xlink:href', 'Port', 'xlink:href="Port"'], + [DirectiveAst, attrSel, '<use xlink:href="Port" />'], + ]); + }); + + it('should support directive property', () => { + const dirA = compileDirectiveMetadataCreate({ + selector: 'div', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + inputs: ['aProp'] + }).toSummary(); + expect(humanizeTplAstSourceSpans(parse('<div [aProp]="foo"></div>', [dirA]))).toEqual([ + [ElementAst, 'div', '<div [aProp]="foo">'], [DirectiveAst, dirA, '<div [aProp]="foo">'], + [BoundDirectivePropertyAst, 'aProp', 'foo', '[aProp]="foo"'] ]); }); - it('should remove whitespace between ICU expansions when not preserving whitespaces', () => { + it('should support endSourceSpan for elements', () => { + const tagSel = compileDirectiveMetadataCreate({ + selector: 'circle', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'elDir'}}) + }).toSummary(); + const result = parse('<circle></circle>', [tagSel]); + const circle = result[0] as ElementAst; + expect(circle.endSourceSpan).toBeDefined(); + expect(circle.endSourceSpan!.start.offset).toBe(8); + expect(circle.endSourceSpan!.end.offset).toBe(17); + }); + + it('should report undefined for endSourceSpan for elements without an end-tag', () => { + const ulSel = compileDirectiveMetadataCreate({ + selector: 'ul', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'ulDir'}}) + }).toSummary(); + const liSel = compileDirectiveMetadataCreate({ + selector: 'li', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'liDir'}}) + }).toSummary(); + const result = parse('<ul><li><li></ul>', [ulSel, liSel]); + const ul = result[0] as ElementAst; + const li = ul.children[0] as ElementAst; + expect(li.endSourceSpan).toBe(null); + }); + }); + + describe('pipes', () => { + it('should allow pipes that have been defined as dependencies', () => { + const testPipe = new CompilePipeMetadata({ + name: 'test', + type: createTypeMeta({reference: {filePath: someModuleUrl, name: 'DirA'}}), + pure: false + }).toSummary(); + expect(() => parse('{{a | test}}', [], [testPipe])).not.toThrow(); + }); + + it('should report pipes as error that have not been defined as dependencies', () => { + expect(() => parse('{{a | test}}', [])).toThrowError(`Template parse errors: +The pipe 'test' could not be found ("{{[ERROR ->]a | test}}"): TestComp@0:2`); + }); + }); + + describe('ICU messages', () => { + it('should expand plural messages', () => { const shortForm = '{ count, plural, =0 {small} many {big} }'; const expandedForm = '<ng-container [ngPlural]="count">' + '<ng-template ngPluralCase="=0">small</ng-template>' + '<ng-template ngPluralCase="many">big</ng-template>' + '</ng-container>'; - const humanizedExpandedForm = humanizeTplAst(parse(expandedForm, [])); - // ICU expansions are converted to `<ng-container>` tags and all blank text nodes are reomved - // so any whitespace between ICU exansions are removed as well - expect(humanizeTplAst(parse(`${shortForm} ${shortForm}`, [], [], [], false))).toEqual([ - ...humanizedExpandedForm, ...humanizedExpandedForm + expect(humanizeTplAst(parse(shortForm, []))).toEqual(humanizeTplAst(parse(expandedForm, []))); + }); + + it('should expand select messages', () => { + const shortForm = '{ sex, select, female {foo} other {bar} }'; + const expandedForm = '<ng-container [ngSwitch]="sex">' + + '<ng-template ngSwitchCase="female">foo</ng-template>' + + '<ng-template ngSwitchDefault>bar</ng-template>' + + '</ng-container>'; + + expect(humanizeTplAst(parse(shortForm, []))).toEqual(humanizeTplAst(parse(expandedForm, []))); + }); + + it('should be possible to escape ICU messages', () => { + const escapedForm = 'escaped {{ "{" }} }'; + + expect(humanizeTplAst(parse(escapedForm, []))).toEqual([ + [BoundTextAst, 'escaped {{ "{" }} }'], ]); }); }); +}); + +describe('whitespaces removal', () => { + beforeEach(() => { + TestBed.configureCompiler({providers: [TEST_COMPILER_PROVIDERS, MOCK_SCHEMA_REGISTRY]}); + }); + + commonBeforeEach(); + + it('should not remove whitespaces by default', () => { + expect(humanizeTplAst(parse(' <br> <br>\t<br>\n<br> ', []))).toEqual([ + [TextAst, ' '], + [ElementAst, 'br'], + [TextAst, ' '], + [ElementAst, 'br'], + [TextAst, '\t'], + [ElementAst, 'br'], + [TextAst, '\n'], + [ElementAst, 'br'], + [TextAst, ' '], + ]); + }); + + it('should replace each &ngsp; with a space when preserveWhitespaces is true', () => { + expect(humanizeTplAst(parse('foo&ngsp;&ngsp;&ngsp;bar', [], [], [], true))).toEqual([ + [TextAst, 'foo bar'], + ]); + }); + + it('should replace every &ngsp; with a single space when preserveWhitespaces is false', () => { + expect(humanizeTplAst(parse('foo&ngsp;&ngsp;&ngsp;bar', [], [], [], false))).toEqual([ + [TextAst, 'foo bar'], + ]); + }); + + it('should remove whitespaces when explicitly requested', () => { + expect(humanizeTplAst(parse(' <br> <br>\t<br>\n<br> ', [], [], [], false))).toEqual([ + [ElementAst, 'br'], + [ElementAst, 'br'], + [ElementAst, 'br'], + [ElementAst, 'br'], + ]); + }); + it('should remove whitespace between ICU expansions when not preserving whitespaces', () => { + const shortForm = '{ count, plural, =0 {small} many {big} }'; + const expandedForm = '<ng-container [ngPlural]="count">' + + '<ng-template ngPluralCase="=0">small</ng-template>' + + '<ng-template ngPluralCase="many">big</ng-template>' + + '</ng-container>'; + const humanizedExpandedForm = humanizeTplAst(parse(expandedForm, [])); + + // ICU expansions are converted to `<ng-container>` tags and all blank text nodes are reomved + // so any whitespace between ICU exansions are removed as well + expect(humanizeTplAst(parse(`${shortForm} ${shortForm}`, [], [], [], false))).toEqual([ + ...humanizedExpandedForm, ...humanizedExpandedForm + ]); + }); +}); })(); diff --git a/packages/compiler/test/template_parser/template_preparser_spec.ts b/packages/compiler/test/template_parser/template_preparser_spec.ts index a5fd04163263c..27d9ebba4f949 100644 --- a/packages/compiler/test/template_parser/template_preparser_spec.ts +++ b/packages/compiler/test/template_parser/template_preparser_spec.ts @@ -14,7 +14,9 @@ import {PreparsedElement, PreparsedElementType, preparseElement} from '../../src { describe('preparseElement', () => { let htmlParser: HtmlParser; - beforeEach(inject([HtmlParser], (_htmlParser: HtmlParser) => { htmlParser = _htmlParser; })); + beforeEach(inject([HtmlParser], (_htmlParser: HtmlParser) => { + htmlParser = _htmlParser; + })); function preparse(html: string): PreparsedElement { return preparseElement(htmlParser.parse(html, 'TestComp').rootNodes[0] as Element); diff --git a/packages/compiler/test/template_parser/util/expression.ts b/packages/compiler/test/template_parser/util/expression.ts index a74b60f26add3..281d86eb4a365 100644 --- a/packages/compiler/test/template_parser/util/expression.ts +++ b/packages/compiler/test/template_parser/util/expression.ts @@ -15,12 +15,16 @@ type HumanizedExpressionSource = [string, AbsoluteSourceSpan]; class ExpressionSourceHumanizer extends e.RecursiveAstVisitor implements t.TemplateAstVisitor { result: HumanizedExpressionSource[] = []; - private recordAst(ast: e.AST) { this.result.push([unparse(ast), ast.sourceSpan]); } + private recordAst(ast: e.AST) { + this.result.push([unparse(ast), ast.sourceSpan]); + } // This method is defined to reconcile the type of ExpressionSourceHumanizer // since both RecursiveAstVisitor and TemplateAstVisitor define the visit() // method in their interfaces. - visit(node: e.AST|t.TemplateAst, context?: any) { node.visit(this, context); } + visit(node: e.AST|t.TemplateAst, context?: any) { + node.visit(this, context); + } visitASTWithSource(ast: e.ASTWithSource) { this.recordAst(ast); @@ -128,17 +132,25 @@ class ExpressionSourceHumanizer extends e.RecursiveAstVisitor implements t.Templ } visitReference(ast: t.ReferenceAst) {} visitVariable(ast: t.VariableAst) {} - visitEvent(ast: t.BoundEventAst) { ast.handler.visit(this); } - visitElementProperty(ast: t.BoundElementPropertyAst) { ast.value.visit(this); } + visitEvent(ast: t.BoundEventAst) { + ast.handler.visit(this); + } + visitElementProperty(ast: t.BoundElementPropertyAst) { + ast.value.visit(this); + } visitAttr(ast: t.AttrAst) {} - visitBoundText(ast: t.BoundTextAst) { ast.value.visit(this); } + visitBoundText(ast: t.BoundTextAst) { + ast.value.visit(this); + } visitText(ast: t.TextAst) {} visitDirective(ast: t.DirectiveAst) { t.templateVisitAll(this, ast.hostEvents); t.templateVisitAll(this, ast.hostProperties); t.templateVisitAll(this, ast.inputs); } - visitDirectiveProperty(ast: t.BoundDirectivePropertyAst) { ast.value.visit(this); } + visitDirectiveProperty(ast: t.BoundDirectivePropertyAst) { + ast.value.visit(this); + } } /** diff --git a/packages/compiler/test/template_parser/util/metadata.ts b/packages/compiler/test/template_parser/util/metadata.ts index 433f3485a9f0b..8da54abd9eb41 100644 --- a/packages/compiler/test/template_parser/util/metadata.ts +++ b/packages/compiler/test/template_parser/util/metadata.ts @@ -5,8 +5,9 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {CompileDirectiveMetadata, CompileEntryComponentMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileStylesheetMetadata, CompileTemplateMetadata, CompileTypeMetadata, ProxyClass, StaticSymbol, preserveWhitespacesDefault} from '@angular/compiler'; +import {CompileDirectiveMetadata, CompileEntryComponentMetadata, CompileProviderMetadata, CompileQueryMetadata, CompileStylesheetMetadata, CompileTemplateMetadata, CompileTypeMetadata, preserveWhitespacesDefault, ProxyClass, StaticSymbol} from '@angular/compiler'; import {ChangeDetectionStrategy, RendererType2, ViewEncapsulation} from '@angular/core'; + import {noUndefined} from '../../../src/util'; export function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: any[]}): @@ -14,13 +15,28 @@ export function createTypeMeta({reference, diDeps}: {reference: any, diDeps?: an return {reference: reference, diDeps: diDeps || [], lifecycleHooks: []}; } -export function compileDirectiveMetadataCreate( - {isHost, type, isComponent, selector, exportAs, inputs, outputs, host, providers, viewProviders, - queries, guards, viewQueries, entryComponents, template, componentViewType, - rendererType}: Partial<Parameters<typeof CompileDirectiveMetadata.create>[0]>) { +export function compileDirectiveMetadataCreate({ + isHost, + type, + isComponent, + selector, + exportAs, + inputs, + outputs, + host, + providers, + viewProviders, + queries, + guards, + viewQueries, + entryComponents, + template, + componentViewType, + rendererType +}: Partial<Parameters<typeof CompileDirectiveMetadata.create>[0]>) { return CompileDirectiveMetadata.create({ isHost: !!isHost, - type: noUndefined(type) !, + type: noUndefined(type)!, isComponent: !!isComponent, selector: noUndefined(selector), exportAs: noUndefined(exportAs), @@ -34,17 +50,26 @@ export function compileDirectiveMetadataCreate( guards: guards || {}, viewQueries: viewQueries || [], entryComponents: entryComponents || [], - template: noUndefined(template) !, + template: noUndefined(template)!, componentViewType: noUndefined(componentViewType), rendererType: noUndefined(rendererType), componentFactory: null, }); } -export function compileTemplateMetadata( - {encapsulation, template, templateUrl, styles, styleUrls, externalStylesheets, animations, - ngContentSelectors, interpolation, isInline, - preserveWhitespaces}: Partial<CompileTemplateMetadata>): CompileTemplateMetadata { +export function compileTemplateMetadata({ + encapsulation, + template, + templateUrl, + styles, + styleUrls, + externalStylesheets, + animations, + ngContentSelectors, + interpolation, + isInline, + preserveWhitespaces +}: Partial<CompileTemplateMetadata>): CompileTemplateMetadata { return new CompileTemplateMetadata({ encapsulation: noUndefined(encapsulation), template: noUndefined(template), diff --git a/packages/compiler/test/url_resolver_spec.ts b/packages/compiler/test/url_resolver_spec.ts index c6dc97c8a36fc..04f295dde3bed 100644 --- a/packages/compiler/test/url_resolver_spec.ts +++ b/packages/compiler/test/url_resolver_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {UrlResolver, createOfflineCompileUrlResolver} from '@angular/compiler/src/url_resolver'; +import {createOfflineCompileUrlResolver, UrlResolver} from '@angular/compiler/src/url_resolver'; import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal'; { @@ -65,7 +65,6 @@ import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/sr expect(resolver.resolve('foo/', './bar')).toEqual('foo/bar'); expect(resolver.resolve('foo/baz', './bar')).toEqual('foo/bar'); expect(resolver.resolve('foo/baz', 'bar')).toEqual('foo/bar'); - }); it('should support ".." in the path', () => { @@ -89,14 +88,14 @@ import {beforeEach, describe, expect, inject, it} from '@angular/core/testing/sr describe('packages', () => { it('should resolve a url based on the application package', () => { resolver = new UrlResolver('my_packages_dir'); - expect(resolver.resolve(null !, 'package:some/dir/file.txt')) + expect(resolver.resolve(null!, 'package:some/dir/file.txt')) .toEqual('my_packages_dir/some/dir/file.txt'); - expect(resolver.resolve(null !, 'some/dir/file.txt')).toEqual('some/dir/file.txt'); + expect(resolver.resolve(null!, 'some/dir/file.txt')).toEqual('some/dir/file.txt'); }); it('should contain a default value of "/" when nothing is provided', inject([UrlResolver], (resolver: UrlResolver) => { - expect(resolver.resolve(null !, 'package:file')).toEqual('/file'); + expect(resolver.resolve(null!, 'package:file')).toEqual('/file'); })); it('should resolve a package value when present within the baseurl', () => { diff --git a/packages/compiler/test/util_spec.ts b/packages/compiler/test/util_spec.ts index 5f082f04f9793..aa8423df2af47 100644 --- a/packages/compiler/test/util_spec.ts +++ b/packages/compiler/test/util_spec.ts @@ -15,7 +15,9 @@ import {escapeRegExp, splitAtColon, stringify, utf8Encode} from '../src/util'; expect(splitAtColon('a:b', [])).toEqual(['a', 'b']); }); - it('should trim parts', () => { expect(splitAtColon(' a : b ', [])).toEqual(['a', 'b']); }); + it('should trim parts', () => { + expect(splitAtColon(' a : b ', [])).toEqual(['a', 'b']); + }); it('should support multiple ":"', () => { expect(splitAtColon('a:b:c', [])).toEqual(['a', 'b:c']); @@ -70,13 +72,16 @@ import {escapeRegExp, splitAtColon, stringify, utf8Encode} from '../src/util'; ['\uDEEE', '\xED\xBB\xAE'], ['\uDFFF', '\xED\xBF\xBF'], ]; - tests.forEach(([input, output]) => { expect(utf8Encode(input)).toEqual(output); }); + tests.forEach(([input, output]) => { + expect(utf8Encode(input)).toEqual(output); + }); }); }); describe('stringify()', () => { - it('should handle objects with no prototype.', - () => { expect(stringify(Object.create(null))).toEqual('object'); }); + it('should handle objects with no prototype.', () => { + expect(stringify(Object.create(null))).toEqual('object'); + }); }); }); } diff --git a/packages/compiler/testing/src/directive_resolver_mock.ts b/packages/compiler/testing/src/directive_resolver_mock.ts index f3de0fe888c76..cfb91dc3c2c72 100644 --- a/packages/compiler/testing/src/directive_resolver_mock.ts +++ b/packages/compiler/testing/src/directive_resolver_mock.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {CompileReflector, DirectiveResolver, core} from '@angular/compiler'; +import {CompileReflector, core, DirectiveResolver} from '@angular/compiler'; /** * An implementation of {@link DirectiveResolver} that allows overriding @@ -14,7 +14,9 @@ import {CompileReflector, DirectiveResolver, core} from '@angular/compiler'; export class MockDirectiveResolver extends DirectiveResolver { private _directives = new Map<core.Type, core.Directive>(); - constructor(reflector: CompileReflector) { super(reflector); } + constructor(reflector: CompileReflector) { + super(reflector); + } resolve(type: core.Type): core.Directive; resolve(type: core.Type, throwIfNotFound: true): core.Directive; diff --git a/packages/compiler/testing/src/ng_module_resolver_mock.ts b/packages/compiler/testing/src/ng_module_resolver_mock.ts index 619435c9e4424..609ae27947896 100644 --- a/packages/compiler/testing/src/ng_module_resolver_mock.ts +++ b/packages/compiler/testing/src/ng_module_resolver_mock.ts @@ -6,12 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileReflector, NgModuleResolver, core} from '@angular/compiler'; +import {CompileReflector, core, NgModuleResolver} from '@angular/compiler'; export class MockNgModuleResolver extends NgModuleResolver { private _ngModules = new Map<core.Type, core.NgModule>(); - constructor(reflector: CompileReflector) { super(reflector); } + constructor(reflector: CompileReflector) { + super(reflector); + } /** * Overrides the {@link NgModule} for a module. @@ -27,6 +29,6 @@ export class MockNgModuleResolver extends NgModuleResolver { * `NgModuleResolver`, see `setNgModule`. */ resolve(type: core.Type, throwIfNotFound = true): core.NgModule { - return this._ngModules.get(type) || super.resolve(type, throwIfNotFound) !; + return this._ngModules.get(type) || super.resolve(type, throwIfNotFound)!; } } diff --git a/packages/compiler/testing/src/output/source_map_util.ts b/packages/compiler/testing/src/output/source_map_util.ts index 941a735c29ea1..e07d599c4fac2 100644 --- a/packages/compiler/testing/src/output/source_map_util.ts +++ b/packages/compiler/testing/src/output/source_map_util.ts @@ -17,8 +17,7 @@ export interface SourceLocation { } export function originalPositionFor( - sourceMap: SourceMap, - genPosition: {line: number | null, column: number | null}): SourceLocation { + sourceMap: SourceMap, genPosition: {line: number|null, column: number|null}): SourceLocation { const smc = new SourceMapConsumer(sourceMap); // Note: We don't return the original object as it also contains a `name` property // which is always null and we don't want to include that in our assertions... diff --git a/packages/compiler/testing/src/pipe_resolver_mock.ts b/packages/compiler/testing/src/pipe_resolver_mock.ts index 36fb91667a606..5fa1396e0bf19 100644 --- a/packages/compiler/testing/src/pipe_resolver_mock.ts +++ b/packages/compiler/testing/src/pipe_resolver_mock.ts @@ -6,17 +6,21 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileReflector, PipeResolver, core} from '@angular/compiler'; +import {CompileReflector, core, PipeResolver} from '@angular/compiler'; export class MockPipeResolver extends PipeResolver { private _pipes = new Map<core.Type, core.Pipe>(); - constructor(refector: CompileReflector) { super(refector); } + constructor(refector: CompileReflector) { + super(refector); + } /** * Overrides the {@link Pipe} for a pipe. */ - setPipe(type: core.Type, metadata: core.Pipe): void { this._pipes.set(type, metadata); } + setPipe(type: core.Type, metadata: core.Pipe): void { + this._pipes.set(type, metadata); + } /** * Returns the {@link Pipe} for a pipe: @@ -27,7 +31,7 @@ export class MockPipeResolver extends PipeResolver { resolve(type: core.Type, throwIfNotFound = true): core.Pipe { let metadata = this._pipes.get(type); if (!metadata) { - metadata = super.resolve(type, throwIfNotFound) !; + metadata = super.resolve(type, throwIfNotFound)!; } return metadata; } diff --git a/packages/compiler/testing/src/resource_loader_mock.ts b/packages/compiler/testing/src/resource_loader_mock.ts index e64c744960483..7d9f281e3d559 100644 --- a/packages/compiler/testing/src/resource_loader_mock.ts +++ b/packages/compiler/testing/src/resource_loader_mock.ts @@ -23,7 +23,9 @@ export class MockResourceLoader extends ResourceLoader { return request.getPromise(); } - hasPendingRequests() { return !!this._requests.length; } + hasPendingRequests() { + return !!this._requests.length; + } /** * Add an expectation for the given URL. Incoming requests will be checked against @@ -43,7 +45,9 @@ export class MockResourceLoader extends ResourceLoader { * unlike expectations, unused definitions do not cause `verifyNoOutstandingExpectations` * to return an error. */ - when(url: string, response: string) { this._definitions.set(url, response); } + when(url: string, response: string) { + this._definitions.set(url, response); + } /** * Process pending requests and verify there are no outstanding expectations. Also fails @@ -55,7 +59,7 @@ export class MockResourceLoader extends ResourceLoader { } do { - this._processRequest(this._requests.shift() !); + this._processRequest(this._requests.shift()!); } while (this._requests.length > 0); this.verifyNoOutstandingExpectations(); @@ -100,9 +104,9 @@ export class MockResourceLoader extends ResourceLoader { class _PendingRequest { // TODO(issue/24571): remove '!'. - resolve !: (result: string) => void; + resolve!: (result: string) => void; // TODO(issue/24571): remove '!'. - reject !: (error: any) => void; + reject!: (error: any) => void; promise: Promise<string>; constructor(public url: string) { @@ -120,7 +124,9 @@ class _PendingRequest { } } - getPromise(): Promise<string> { return this.promise; } + getPromise(): Promise<string> { + return this.promise; + } } class _Expectation { diff --git a/packages/compiler/testing/src/schema_registry_mock.ts b/packages/compiler/testing/src/schema_registry_mock.ts index b1c5b25ccfe07..485a1dde5a5e5 100644 --- a/packages/compiler/testing/src/schema_registry_mock.ts +++ b/packages/compiler/testing/src/schema_registry_mock.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementSchemaRegistry, core} from '@angular/compiler'; +import {core, ElementSchemaRegistry} from '@angular/compiler'; export class MockSchemaRegistry implements ElementSchemaRegistry { constructor( @@ -25,15 +25,21 @@ export class MockSchemaRegistry implements ElementSchemaRegistry { return value === void 0 ? true : value; } - allKnownElementNames(): string[] { return Object.keys(this.existingElements); } + allKnownElementNames(): string[] { + return Object.keys(this.existingElements); + } securityContext(selector: string, property: string, isAttribute: boolean): core.SecurityContext { return core.SecurityContext.NONE; } - getMappedPropName(attrName: string): string { return this.attrPropMapping[attrName] || attrName; } + getMappedPropName(attrName: string): string { + return this.attrPropMapping[attrName] || attrName; + } - getDefaultComponentElementName(): string { return 'ng-component'; } + getDefaultComponentElementName(): string { + return 'ng-component'; + } validateProperty(name: string): {error: boolean, msg?: string} { if (this.invalidProperties.indexOf(name) > -1) { @@ -54,9 +60,11 @@ export class MockSchemaRegistry implements ElementSchemaRegistry { } } - normalizeAnimationStyleProperty(propName: string): string { return propName; } + normalizeAnimationStyleProperty(propName: string): string { + return propName; + } normalizeAnimationStyleValue(camelCaseProp: string, userProvidedProp: string, val: string|number): {error: string, value: string} { - return {error: null !, value: val.toString()}; + return {error: null!, value: val.toString()}; } } From e92fce1c27eb04de697bc7331ae1c4648796b119 Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 6 Apr 2020 14:45:13 -0700 Subject: [PATCH 162/262] fix(language-service): remove circular dependency instance (#36463) PR Close #36463 --- goldens/packages-circular-deps.json | 4 ---- packages/language-service/src/completions.ts | 4 ++-- .../language-service/src/expression_diagnostics.ts | 14 ++++++++++++++ packages/language-service/src/locate_symbol.ts | 4 ++-- packages/language-service/src/utils.ts | 13 ------------- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/goldens/packages-circular-deps.json b/goldens/packages-circular-deps.json index 669637271dfd1..92e8e0aabda3a 100644 --- a/goldens/packages-circular-deps.json +++ b/goldens/packages-circular-deps.json @@ -1966,10 +1966,6 @@ "packages/language-service/src/typescript_host.ts", "packages/language-service/src/language_service.ts" ], - [ - "packages/language-service/src/expression_diagnostics.ts", - "packages/language-service/src/utils.ts" - ], [ "packages/language-service/src/template.ts", "packages/language-service/src/typescript_host.ts" diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index 80f7b363bee58..8c139042dbb81 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -11,12 +11,12 @@ import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; import {ATTR, getBindingDescriptor} from './binding_utils'; import {AstResult} from './common'; -import {getExpressionScope} from './expression_diagnostics'; +import {diagnosticInfoFromTemplateInfo, getExpressionScope} from './expression_diagnostics'; import {getExpressionCompletions} from './expressions'; import {attributeNames, elementNames, eventNames, propertyNames} from './html_info'; import {InlineTemplate} from './template'; import * as ng from './types'; -import {diagnosticInfoFromTemplateInfo, findTemplateAstAt, getPathToNodeAtPosition, getSelectors, inSpan, isStructuralDirective, spanOf} from './utils'; +import {findTemplateAstAt, getPathToNodeAtPosition, getSelectors, inSpan, isStructuralDirective, spanOf} from './utils'; const HIDDEN_HTML_ELEMENTS: ReadonlySet<string> = new Set(['html', 'script', 'noscript', 'base', 'body', 'title', 'head', 'link']); diff --git a/packages/language-service/src/expression_diagnostics.ts b/packages/language-service/src/expression_diagnostics.ts index 61e62ec6180be..81950b5798946 100644 --- a/packages/language-service/src/expression_diagnostics.ts +++ b/packages/language-service/src/expression_diagnostics.ts @@ -8,6 +8,7 @@ import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, identifierName, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableAst} from '@angular/compiler'; +import {AstResult} from './common'; import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {AstType} from './expression_type'; import {BuiltinType, Definition, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; @@ -385,3 +386,16 @@ function hasTemplateReference(type: CompileTypeMetadata): boolean { function spanOf(sourceSpan: ParseSourceSpan): Span { return {start: sourceSpan.start.offset, end: sourceSpan.end.offset}; } + + +export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTemplateInfo { + return { + fileName: info.template.fileName, + offset: info.template.span.start, + query: info.template.query, + members: info.template.members, + htmlAst: info.htmlAst, + templateAst: info.templateAst, + source: info.template.source, + }; +} diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index fba5d1a812ec0..97475ab27bd90 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -10,10 +10,10 @@ import {AST, Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, El import * as tss from 'typescript/lib/tsserverlibrary'; import {AstResult} from './common'; -import {getExpressionScope} from './expression_diagnostics'; +import {diagnosticInfoFromTemplateInfo, getExpressionScope} from './expression_diagnostics'; import {getExpressionSymbol} from './expressions'; import {Definition, DirectiveKind, Span, Symbol} from './types'; -import {diagnosticInfoFromTemplateInfo, findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; +import {findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; export interface SymbolInfo { symbol: Symbol; diff --git a/packages/language-service/src/utils.ts b/packages/language-service/src/utils.ts index e2f9de8bab97d..36fa25c71ccc4 100644 --- a/packages/language-service/src/utils.ts +++ b/packages/language-service/src/utils.ts @@ -10,7 +10,6 @@ import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, Cs import * as ts from 'typescript'; import {AstResult, SelectorInfo} from './common'; -import {DiagnosticTemplateInfo} from './expression_diagnostics'; import {Span, Symbol, SymbolQuery} from './types'; export interface SpanHolder { @@ -91,18 +90,6 @@ export function isTypescriptVersion(low: string, high?: string) { return true; } -export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTemplateInfo { - return { - fileName: info.template.fileName, - offset: info.template.span.start, - query: info.template.query, - members: info.template.members, - htmlAst: info.htmlAst, - templateAst: info.templateAst, - source: info.template.source, - }; -} - export function findTemplateAstAt(ast: TemplateAst[], position: number): TemplateAstPath { const path: TemplateAst[] = []; const visitor = new class extends RecursiveTemplateAstVisitor { From 92c4f3d5085b0fa1c30cd5c9d658d20871419320 Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Mon, 6 Apr 2020 21:32:44 -0700 Subject: [PATCH 163/262] refactor(bazel): use runfiles helper in ts-api-guardian (#36471) Pre-fractor for future rules_nodejs release when require.resolve patches are removed. PR Close #36471 --- tools/ts-api-guardian/lib/cli.ts | 41 ++++++++++++++------------------ 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/tools/ts-api-guardian/lib/cli.ts b/tools/ts-api-guardian/lib/cli.ts index 0b2c525268354..e460525e7bdb2 100644 --- a/tools/ts-api-guardian/lib/cli.ts +++ b/tools/ts-api-guardian/lib/cli.ts @@ -19,20 +19,6 @@ import {SerializationOptions, generateGoldenFile, verifyAgainstGoldenFile, disco /** Name of the CLI */ const CMD = 'ts-api-guardian'; -/** Name of the Bazel workspace that runs the CLI. */ -const bazelWorkspaceName = process.env.BAZEL_WORKSPACE; -/** - * Path to the Bazel workspace directory. Only set if the CLI is run with `bazel run`. - * https://docs.bazel.build/versions/master/user-manual.html#run. - */ -const bazelWorkspaceDirectory = process.env.BUILD_WORKSPACE_DIRECTORY; -/** - * Regular expression that matches Bazel manifest paths that start with the - * current Bazel workspace, followed by a path delimiter. - */ -const bazelWorkspaceManifestPathRegex = - bazelWorkspaceName ? new RegExp(`^${bazelWorkspaceName}[/\\\\]`) : null; - export function startCli() { const {argv, mode, errors} = parseArguments(process.argv.slice(2)); @@ -95,8 +81,8 @@ export function startCli() { lines.pop(); // Remove trailing newline } for (const line of lines) { - const chalkMap: {[key: string]: - any} = {'-': chalk.red, '+': chalk.green, '@': chalk.cyan}; + const chalkMap: + {[key: string]: any} = {'-': chalk.red, '+': chalk.green, '@': chalk.cyan}; const chalkFunc = chalkMap[line[0]] || chalk.reset; console.log(chalkFunc(line)); } @@ -109,7 +95,7 @@ export function startCli() { if (bazelTarget) { console.error('\n\nIf you modify a public API, you must accept the new golden file.'); console.error('\n\nTo do so, execute the following Bazel target:'); - console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, "")}.accept`); + console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, '')}.accept`); if (process.env['TEST_WORKSPACE'] === 'angular') { console.error('\n\nFor more information, see'); console.error( @@ -235,20 +221,29 @@ function resolveFilePath(fileName: string): string { if (path.isAbsolute(fileName)) { return fileName; } + const runfilesHelperPath = process.env['BAZEL_NODE_RUNFILES_HELPER']; // Outside of Bazel, file paths are resolved based on the current working directory. - if (!bazelWorkspaceName) { + if (!runfilesHelperPath) { return path.resolve(fileName); } // In Bazel, we first try to resolve the file through the runfiles. We do this by calling - // the `require.resolve` function that is patched by the Bazel NodeJS rules. Note that we - // need to catch errors because files inside tree artifacts cannot be resolved through - // runfile manifests. Hence, we need to have alternative resolution logic when resolving - // file paths. Additionally, it could happen that manifest paths which aren't part of the + // the `runfiles.resolve` function that is supplied by the Bazel NodeJS rules. Note that we + // need to catch errors because it could happen that manifest paths which aren't part of the // runfiles are specified (i.e. golden is approved but does not exist in the workspace yet). + const runfiles = require(runfilesHelperPath); try { - return require.resolve(fileName); + return runfiles.resolve(fileName); } catch { } + // Path to the Bazel workspace directory. Only set if the CLI is run with `bazel run`. + // https://docs.bazel.build/versions/master/user-manual.html#run. + const bazelWorkspaceDirectory = process.env.BUILD_WORKSPACE_DIRECTORY; + // Name of the Bazel workspace that runs the CLI. + const bazelWorkspaceName = runfiles.workspace; + // Regular expression that matches Bazel manifest paths that start with the + // current Bazel workspace, followed by a path delimiter. + const bazelWorkspaceManifestPathRegex = + bazelWorkspaceName ? new RegExp(`^${bazelWorkspaceName}[/\\\\]`) : null; // This handles cases where file paths cannot be resolved through runfiles. This happens // commonly when goldens are approved while the golden does not exist in the workspace yet. // In those cases, we want to build up a relative path based on the manifest path, and join From f1731d807e5514781fbe6fbb5a7eda90fb80092e Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Wed, 8 Apr 2020 17:25:54 -0700 Subject: [PATCH 164/262] Revert "refactor(bazel): use runfiles helper in ts-api-guardian (#36471)" (#36531) This reverts commit 92c4f3d5085b0fa1c30cd5c9d658d20871419320. PR Close #36531 --- tools/ts-api-guardian/lib/cli.ts | 41 ++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/tools/ts-api-guardian/lib/cli.ts b/tools/ts-api-guardian/lib/cli.ts index e460525e7bdb2..0b2c525268354 100644 --- a/tools/ts-api-guardian/lib/cli.ts +++ b/tools/ts-api-guardian/lib/cli.ts @@ -19,6 +19,20 @@ import {SerializationOptions, generateGoldenFile, verifyAgainstGoldenFile, disco /** Name of the CLI */ const CMD = 'ts-api-guardian'; +/** Name of the Bazel workspace that runs the CLI. */ +const bazelWorkspaceName = process.env.BAZEL_WORKSPACE; +/** + * Path to the Bazel workspace directory. Only set if the CLI is run with `bazel run`. + * https://docs.bazel.build/versions/master/user-manual.html#run. + */ +const bazelWorkspaceDirectory = process.env.BUILD_WORKSPACE_DIRECTORY; +/** + * Regular expression that matches Bazel manifest paths that start with the + * current Bazel workspace, followed by a path delimiter. + */ +const bazelWorkspaceManifestPathRegex = + bazelWorkspaceName ? new RegExp(`^${bazelWorkspaceName}[/\\\\]`) : null; + export function startCli() { const {argv, mode, errors} = parseArguments(process.argv.slice(2)); @@ -81,8 +95,8 @@ export function startCli() { lines.pop(); // Remove trailing newline } for (const line of lines) { - const chalkMap: - {[key: string]: any} = {'-': chalk.red, '+': chalk.green, '@': chalk.cyan}; + const chalkMap: {[key: string]: + any} = {'-': chalk.red, '+': chalk.green, '@': chalk.cyan}; const chalkFunc = chalkMap[line[0]] || chalk.reset; console.log(chalkFunc(line)); } @@ -95,7 +109,7 @@ export function startCli() { if (bazelTarget) { console.error('\n\nIf you modify a public API, you must accept the new golden file.'); console.error('\n\nTo do so, execute the following Bazel target:'); - console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, '')}.accept`); + console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, "")}.accept`); if (process.env['TEST_WORKSPACE'] === 'angular') { console.error('\n\nFor more information, see'); console.error( @@ -221,29 +235,20 @@ function resolveFilePath(fileName: string): string { if (path.isAbsolute(fileName)) { return fileName; } - const runfilesHelperPath = process.env['BAZEL_NODE_RUNFILES_HELPER']; // Outside of Bazel, file paths are resolved based on the current working directory. - if (!runfilesHelperPath) { + if (!bazelWorkspaceName) { return path.resolve(fileName); } // In Bazel, we first try to resolve the file through the runfiles. We do this by calling - // the `runfiles.resolve` function that is supplied by the Bazel NodeJS rules. Note that we - // need to catch errors because it could happen that manifest paths which aren't part of the + // the `require.resolve` function that is patched by the Bazel NodeJS rules. Note that we + // need to catch errors because files inside tree artifacts cannot be resolved through + // runfile manifests. Hence, we need to have alternative resolution logic when resolving + // file paths. Additionally, it could happen that manifest paths which aren't part of the // runfiles are specified (i.e. golden is approved but does not exist in the workspace yet). - const runfiles = require(runfilesHelperPath); try { - return runfiles.resolve(fileName); + return require.resolve(fileName); } catch { } - // Path to the Bazel workspace directory. Only set if the CLI is run with `bazel run`. - // https://docs.bazel.build/versions/master/user-manual.html#run. - const bazelWorkspaceDirectory = process.env.BUILD_WORKSPACE_DIRECTORY; - // Name of the Bazel workspace that runs the CLI. - const bazelWorkspaceName = runfiles.workspace; - // Regular expression that matches Bazel manifest paths that start with the - // current Bazel workspace, followed by a path delimiter. - const bazelWorkspaceManifestPathRegex = - bazelWorkspaceName ? new RegExp(`^${bazelWorkspaceName}[/\\\\]`) : null; // This handles cases where file paths cannot be resolved through runfiles. This happens // commonly when goldens are approved while the golden does not exist in the workspace yet. // In those cases, we want to build up a relative path based on the manifest path, and join From 9e78f55c3275299d5b3da35d8d08875332a7180a Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Wed, 8 Apr 2020 17:37:04 -0700 Subject: [PATCH 165/262] style: typescript lint fix (#36531) PR Close #36531 --- tools/ts-api-guardian/lib/cli.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ts-api-guardian/lib/cli.ts b/tools/ts-api-guardian/lib/cli.ts index 0b2c525268354..d6e8e5605e451 100644 --- a/tools/ts-api-guardian/lib/cli.ts +++ b/tools/ts-api-guardian/lib/cli.ts @@ -95,8 +95,8 @@ export function startCli() { lines.pop(); // Remove trailing newline } for (const line of lines) { - const chalkMap: {[key: string]: - any} = {'-': chalk.red, '+': chalk.green, '@': chalk.cyan}; + const chalkMap: + {[key: string]: any} = {'-': chalk.red, '+': chalk.green, '@': chalk.cyan}; const chalkFunc = chalkMap[line[0]] || chalk.reset; console.log(chalkFunc(line)); } @@ -109,7 +109,7 @@ export function startCli() { if (bazelTarget) { console.error('\n\nIf you modify a public API, you must accept the new golden file.'); console.error('\n\nTo do so, execute the following Bazel target:'); - console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, "")}.accept`); + console.error(` yarn bazel run ${bazelTarget.replace(/_bin$/, '')}.accept`); if (process.env['TEST_WORKSPACE'] === 'angular') { console.error('\n\nFor more information, see'); console.error( From e526f74dfdfeadb903b448c4a733bb4a561a2c08 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Wed, 1 Apr 2020 10:02:26 +0100 Subject: [PATCH 166/262] refactor(compiler): create a new root `BindingScope` for each template (#36362) Previously we had a singleton `ROOT_SCOPE` object, from which all `BindingScope`s derived. But this caused ngcc to produce non-deterministic output when running multiple workers in parallel, since each process had its own `ROOT_SCOPE`. In reality there is no need for `BindingScope` reference names to be unique across an entire application (or in the case of ngcc across all the libraries). Instead we just need uniqueness within a template. This commit changes the compiler to create a new root `BindingScope` each time it compiles a component's template. Resolves #35180 PR Close #36362 --- packages/compiler/src/render3/view/compiler.ts | 2 +- packages/compiler/src/render3/view/template.ts | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index 08b6344011341..eb1b14ba6d224 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -177,7 +177,7 @@ export function compileComponentFromMetadata( const template = meta.template; const templateBuilder = new TemplateDefinitionBuilder( - constantPool, BindingScope.ROOT_SCOPE, 0, templateTypeName, null, null, templateName, + constantPool, BindingScope.createRootScope(), 0, templateTypeName, null, null, templateName, directiveMatcher, directivesUsed, meta.pipes, pipesUsed, R3.namespaceHTML, meta.relativeContextFilePath, meta.i18nUseExternalIds); diff --git a/packages/compiler/src/render3/view/template.ts b/packages/compiler/src/render3/view/template.ts index f92a3904ceaf6..b75e162fe7718 100644 --- a/packages/compiler/src/render3/view/template.ts +++ b/packages/compiler/src/render3/view/template.ts @@ -1605,13 +1605,8 @@ export class BindingScope implements LocalResolver { private map = new Map<string, BindingData>(); private referenceNameIndex = 0; private restoreViewVariable: o.ReadVarExpr|null = null; - private static _ROOT_SCOPE: BindingScope; - - static get ROOT_SCOPE(): BindingScope { - if (!BindingScope._ROOT_SCOPE) { - BindingScope._ROOT_SCOPE = new BindingScope().set(0, '$event', o.variable('$event')); - } - return BindingScope._ROOT_SCOPE; + static createRootScope(): BindingScope { + return new BindingScope().set(0, '$event', o.variable('$event')); } private constructor(public bindingLevel: number = 0, private parent: BindingScope|null = null) {} From 34aa5570edf4ac89d3b54875cfb31299175dec98 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Wed, 8 Apr 2020 23:56:05 +0300 Subject: [PATCH 167/262] fix(dev-infra): fix commit message validation in git worktrees (#36507) Previously, the `pre-commit-validate` command (used in the `commit-msg` git hook) assumed that the commit message was stored in `.git/COMMIT_EDITMSG` file. This is usually true, but not when using [git worktrees](https://git-scm.com/docs/git-worktree), where `.git` is a file containing the path to the actual git directory. This commit fixes it by taking advantage of the fact that git passes the actual path of the file holding the commit message to the `commit-msg` hook and husky exposes the arguments passed by git as `$HUSKY_GIT_PARAMS`. NOTE: We cannot use the environment variable directly in the `commit-msg` hook command, because environment variables need to be referenced differently on Windows (`%VAR_NAME%`) vs macOS/Linux (`$VAR_NAME`). Instead, we pass the name of the environment variable and the validation script reads the variable's value off of `process.env`. PR Close #36507 --- dev-infra/commit-message/cli.ts | 26 ++++++++++++++++++++--- dev-infra/commit-message/validate-file.ts | 4 ++-- package.json | 2 +- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/dev-infra/commit-message/cli.ts b/dev-infra/commit-message/cli.ts index aada6a317818e..6e459d19d2558 100644 --- a/dev-infra/commit-message/cli.ts +++ b/dev-infra/commit-message/cli.ts @@ -14,9 +14,29 @@ export function buildCommitMessageParser(localYargs: yargs.Argv) { return localYargs.help() .strict() .command( - 'pre-commit-validate', 'Validate the most recent commit message', {}, - () => { - validateFile('.git/COMMIT_EDITMSG'); + 'pre-commit-validate', 'Validate the most recent commit message', { + 'file': { + type: 'string', + conflicts: ['file-env-variable'], + description: 'The path of the commit message file.', + }, + 'file-env-variable': { + type: 'string', + conflicts: ['file'], + description: + 'The key of the environment variable for the path of the commit message file.', + coerce: arg => { + const file = process.env[arg]; + if (!file) { + throw new Error(`Provided environment variable "${arg}" was not found.`); + } + return file; + }, + } + }, + args => { + const file = args.file || args.fileEnvVariable || '.git/COMMIT_EDITMSG'; + validateFile(file); }) .command( 'validate-range', 'Validate a range of commit messages', { diff --git a/dev-infra/commit-message/validate-file.ts b/dev-infra/commit-message/validate-file.ts index b5c02555a971d..9769caa33bf0e 100644 --- a/dev-infra/commit-message/validate-file.ts +++ b/dev-infra/commit-message/validate-file.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {readFileSync} from 'fs'; -import {join} from 'path'; +import {resolve} from 'path'; import {getRepoBaseDir} from '../utils/config'; @@ -14,7 +14,7 @@ import {validateCommitMessage} from './validate'; /** Validate commit message at the provided file path. */ export function validateFile(filePath: string) { - const commitMessage = readFileSync(join(getRepoBaseDir(), filePath), 'utf8'); + const commitMessage = readFileSync(resolve(getRepoBaseDir(), filePath), 'utf8'); if (validateCommitMessage(commitMessage)) { console.info('√ Valid commit message'); return; diff --git a/package.json b/package.json index 0f2589f78967f..647c82bbb3358 100644 --- a/package.json +++ b/package.json @@ -199,7 +199,7 @@ "cldr-data-coverage": "full", "husky": { "hooks": { - "commit-msg": "yarn -s ng-dev commit-message pre-commit-validate" + "commit-msg": "yarn -s ng-dev commit-message pre-commit-validate --file-env-variable HUSKY_GIT_PARAMS" } } } From 80e6c07d89d74d71956fb1299c54f5353e255370 Mon Sep 17 00:00:00 2001 From: Martin Sikora <martin.sikora.ahoj@gmail.com> Date: Sun, 29 Mar 2020 11:13:27 +0200 Subject: [PATCH 168/262] fix(router): pass correct component to canDeactivate checks when using two or more sibling router-outlets (#36302) fixes #34614 There's an edge case where if I use two (or more) sibling <router-outlet>s in two (or more) child routes where their parent route doesn't have a component then preactivation will trigger all canDeactivate checks with the same component because it will use wrong OutletContext. PR Close #36302 --- packages/router/src/utils/preactivation.ts | 34 ++++++++++--------- packages/router/test/integration.spec.ts | 38 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/packages/router/src/utils/preactivation.ts b/packages/router/src/utils/preactivation.ts index 1899a0575b7f7..a3624a152f0c9 100644 --- a/packages/router/src/utils/preactivation.ts +++ b/packages/router/src/utils/preactivation.ts @@ -10,10 +10,10 @@ import {Injector} from '@angular/core'; import {LoadedRouterConfig, RunGuardsAndResolvers} from '../config'; import {ChildrenOutletContexts, OutletContext} from '../router_outlet_context'; -import {ActivatedRouteSnapshot, RouterStateSnapshot, equalParamsAndUrlSegments} from '../router_state'; +import {ActivatedRouteSnapshot, equalParamsAndUrlSegments, RouterStateSnapshot} from '../router_state'; import {equalPath} from '../url_tree'; import {forEach, shallowEqual} from '../utils/collection'; -import {TreeNode, nodeChildrenAsMap} from '../utils/tree'; +import {nodeChildrenAsMap, TreeNode} from '../utils/tree'; export class CanActivate { readonly route: ActivatedRouteSnapshot; @@ -66,9 +66,8 @@ function getClosestLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterC } function getChildRouteGuards( - futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>| null, - contexts: ChildrenOutletContexts | null, futurePath: ActivatedRouteSnapshot[], - checks: Checks = { + futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>|null, + contexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[], checks: Checks = { canDeactivateChecks: [], canActivateChecks: [] }): Checks { @@ -82,15 +81,16 @@ function getChildRouteGuards( // Process any children left from the current route (not active for the future route) forEach( - prevChildren, (v: TreeNode<ActivatedRouteSnapshot>, k: string) => - deactivateRouteAndItsChildren(v, contexts !.getContext(k), checks)); + prevChildren, + (v: TreeNode<ActivatedRouteSnapshot>, k: string) => + deactivateRouteAndItsChildren(v, contexts!.getContext(k), contexts, checks)); return checks; } function getRouteGuards( futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>, - parentContexts: ChildrenOutletContexts | null, futurePath: ActivatedRouteSnapshot[], + parentContexts: ChildrenOutletContexts|null, futurePath: ActivatedRouteSnapshot[], checks: Checks = { canDeactivateChecks: [], canActivateChecks: [] @@ -102,7 +102,7 @@ function getRouteGuards( // reusing the node if (curr && future.routeConfig === curr.routeConfig) { const shouldRun = - shouldRunGuardsAndResolvers(curr, future, future.routeConfig !.runGuardsAndResolvers); + shouldRunGuardsAndResolvers(curr, future, future.routeConfig!.runGuardsAndResolvers); if (shouldRun) { checks.canActivateChecks.push(new CanActivate(futurePath)); } else { @@ -127,7 +127,7 @@ function getRouteGuards( } } else { if (curr) { - deactivateRouteAndItsChildren(currNode, context, checks); + deactivateRouteAndItsChildren(currNode, context, parentContexts, checks); } checks.canActivateChecks.push(new CanActivate(futurePath)); @@ -146,7 +146,7 @@ function getRouteGuards( function shouldRunGuardsAndResolvers( curr: ActivatedRouteSnapshot, future: ActivatedRouteSnapshot, - mode: RunGuardsAndResolvers | undefined): boolean { + mode: RunGuardsAndResolvers|undefined): boolean { if (typeof mode === 'function') { return mode(curr, future); } @@ -172,17 +172,21 @@ function shouldRunGuardsAndResolvers( } function deactivateRouteAndItsChildren( - route: TreeNode<ActivatedRouteSnapshot>, context: OutletContext | null, checks: Checks): void { + route: TreeNode<ActivatedRouteSnapshot>, context: OutletContext|null, + parentContexts: ChildrenOutletContexts|null, checks: Checks): void { const children = nodeChildrenAsMap(route); const r = route.value; forEach(children, (node: TreeNode<ActivatedRouteSnapshot>, childName: string) => { if (!r.component) { - deactivateRouteAndItsChildren(node, context, checks); + deactivateRouteAndItsChildren( + node, parentContexts ? parentContexts.getContext(childName) : context, parentContexts, + checks); } else if (context) { - deactivateRouteAndItsChildren(node, context.children.getContext(childName), checks); + deactivateRouteAndItsChildren( + node, context.children.getContext(childName), parentContexts, checks); } else { - deactivateRouteAndItsChildren(node, null, checks); + deactivateRouteAndItsChildren(node, null, parentContexts, checks); } }); diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 358f4ccc46469..1dcf40ecf9a71 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -3046,6 +3046,44 @@ describe('Integration', () => { expect(location.path()).toEqual('/two-outlets/(a)'); }))); + it('should call canDeactivate handler with each deactivated component', + fakeAsync(inject([Router, Location], (router: Router, location: Location) => { + const fixture = createRoot(router, TwoOutletsCmp); + + router.resetConfig([ + { + path: 'a', + children: [ + { + path: 'b1', + component: BlankCmp, + canDeactivate: ['RecordingDeactivate'], + }, + { + path: 'b2', + canDeactivate: ['RecordingDeactivate'], + component: SimpleCmp, + outlet: 'aux', + }, + ], + }, + { + path: 'c', + component: BlankCmp, + }, + ]); + + router.navigate(['/a', {outlets: {primary: ['b1'], aux: ['b2']}}]); + advance(fixture); + expect(location.path()).toEqual('/a/(b1//aux:b2)'); + + router.navigate(['/c']); + advance(fixture); + + expect(log[0].component).toBeAnInstanceOf(BlankCmp); + expect(log[1].component).toBeAnInstanceOf(SimpleCmp); + }))); + it('works with a nested route', fakeAsync(inject([Router, Location], (router: Router, location: Location) => { const fixture = createRoot(router, RootCmp); From 99b93e55cbbbf3e865349ef3be7f105c48aec9d2 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Sat, 28 Mar 2020 09:59:40 -0400 Subject: [PATCH 169/262] docs(forms): clarify the description of `minLength` and `maxLength` (#36297) Previously, it was not clear that the `minLength` and `maxLength` validators can only be used with objects that contain a `length` property. This commit clarifies this. PR Close #36297 --- packages/forms/src/validators.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/forms/src/validators.ts b/packages/forms/src/validators.ts index 51bc05f4380d2..ccb37f76fd259 100644 --- a/packages/forms/src/validators.ts +++ b/packages/forms/src/validators.ts @@ -267,7 +267,11 @@ export class Validators { * @description * Validator that requires the length of the control's value to be greater than or equal * to the provided minimum length. This validator is also provided by default if you use the - * the HTML5 `minlength` attribute. + * the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used + * only for types that have a numeric `length` property, such as strings or arrays. The `minLength` + * validator logic is also not invoked for values when their `length` property is 0 (for example in + * case of an empty string or an empty array), to support optional controls. You can use + * the standard `required` validator if empty values should not be considered valid. * * @usageNotes * @@ -305,7 +309,8 @@ export class Validators { * @description * Validator that requires the length of the control's value to be less than or equal * to the provided maximum length. This validator is also provided by default if you use the - * the HTML5 `maxlength` attribute. + * the HTML5 `maxlength` attribute. Note that the `maxLength` validator is intended to be used + * only for types that have a numeric `length` property, such as strings or arrays. * * @usageNotes * From 13ae2d72717ca204df8ea743155676862bba36df Mon Sep 17 00:00:00 2001 From: Andrew Scott <atscott01@gmail.com> Date: Thu, 9 Apr 2020 10:54:59 -0700 Subject: [PATCH 170/262] style: format forms validators to fix lint error (#36546) PR Close #36546 --- packages/forms/src/validators.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/forms/src/validators.ts b/packages/forms/src/validators.ts index ccb37f76fd259..a1e8f8a157e8e 100644 --- a/packages/forms/src/validators.ts +++ b/packages/forms/src/validators.ts @@ -268,10 +268,10 @@ export class Validators { * Validator that requires the length of the control's value to be greater than or equal * to the provided minimum length. This validator is also provided by default if you use the * the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used - * only for types that have a numeric `length` property, such as strings or arrays. The `minLength` - * validator logic is also not invoked for values when their `length` property is 0 (for example in - * case of an empty string or an empty array), to support optional controls. You can use - * the standard `required` validator if empty values should not be considered valid. + * only for types that have a numeric `length` property, such as strings or arrays. The + * `minLength` validator logic is also not invoked for values when their `length` property is 0 + * (for example in case of an empty string or an empty array), to support optional controls. You + * can use the standard `required` validator if empty values should not be considered valid. * * @usageNotes * From 078b0be4dc69ef4a8cdf4eb15caedde1114950c7 Mon Sep 17 00:00:00 2001 From: "Terence D. Honles" <terence@honles.com> Date: Mon, 30 Mar 2020 16:02:19 -0700 Subject: [PATCH 171/262] fix(common): `locales/global/*.js` are not ES5 compliant (#36342) Although this code has been part of Angular 9.x I only noticed this error when upgrading to Angular 9.1.x because historically the source locale data was not injected when localizing, but as of angular/angular-cli#16394 (9.1.0) it is now included. This tipped me off that my other bundles were not being built properly, and this change allows me to build a valid ES5 bundle (I have also added a verification step to my build pipeline to alert me if this error appears again in any of my bundles). I found the `locales/global/*.js` file paths being referenced by the `I18nOptions` in @angular-devkit/build-angular/src/utils/i18n-options.ts, and following that it looks like it is actually loaded and used in @angular-devkit/build-angular/src/utils/process-bundle.ts. I saw the function `terserMangle` does appear that it is likely aware of the build being ES5, but I'm not sure why this is not producing a valid ES5 bundle. This change updates `tools/gulp-tasks/cldr/extract.js` to produce ES5 compliant `locales/global/*.js` and that fixes my issue. However, I am not sure if @angular-devkit/build-angular should be modified to produce a valid ES5 bundle instead or if the files could be TypeScript rather than JavaScript files. A test that a valid ES5 bundle is produced would be helpful, and I hope this is reproducible and not some issue with my config. PR Close #36342 --- packages/common/locales/global/af-NA.js | 2 +- packages/common/locales/global/af.js | 2 +- packages/common/locales/global/agq.js | 2 +- packages/common/locales/global/ak.js | 2 +- packages/common/locales/global/am.js | 4 ++-- packages/common/locales/global/ar-AE.js | 2 +- packages/common/locales/global/ar-BH.js | 2 +- packages/common/locales/global/ar-DJ.js | 2 +- packages/common/locales/global/ar-DZ.js | 2 +- packages/common/locales/global/ar-EG.js | 2 +- packages/common/locales/global/ar-EH.js | 2 +- packages/common/locales/global/ar-ER.js | 2 +- packages/common/locales/global/ar-IL.js | 2 +- packages/common/locales/global/ar-IQ.js | 2 +- packages/common/locales/global/ar-JO.js | 2 +- packages/common/locales/global/ar-KM.js | 2 +- packages/common/locales/global/ar-KW.js | 2 +- packages/common/locales/global/ar-LB.js | 2 +- packages/common/locales/global/ar-LY.js | 2 +- packages/common/locales/global/ar-MA.js | 2 +- packages/common/locales/global/ar-MR.js | 2 +- packages/common/locales/global/ar-OM.js | 2 +- packages/common/locales/global/ar-PS.js | 2 +- packages/common/locales/global/ar-QA.js | 2 +- packages/common/locales/global/ar-SA.js | 2 +- packages/common/locales/global/ar-SD.js | 2 +- packages/common/locales/global/ar-SO.js | 2 +- packages/common/locales/global/ar-SS.js | 2 +- packages/common/locales/global/ar-SY.js | 2 +- packages/common/locales/global/ar-TD.js | 2 +- packages/common/locales/global/ar-TN.js | 2 +- packages/common/locales/global/ar-YE.js | 2 +- packages/common/locales/global/ar.js | 2 +- packages/common/locales/global/as.js | 4 ++-- packages/common/locales/global/asa.js | 2 +- packages/common/locales/global/ast.js | 4 ++-- packages/common/locales/global/az-Cyrl.js | 2 +- packages/common/locales/global/az-Latn.js | 2 +- packages/common/locales/global/az.js | 2 +- packages/common/locales/global/bas.js | 2 +- packages/common/locales/global/be.js | 2 +- packages/common/locales/global/bem.js | 2 +- packages/common/locales/global/bez.js | 2 +- packages/common/locales/global/bg.js | 2 +- packages/common/locales/global/bm.js | 2 +- packages/common/locales/global/bn-IN.js | 4 ++-- packages/common/locales/global/bn.js | 4 ++-- packages/common/locales/global/bo-IN.js | 2 +- packages/common/locales/global/bo.js | 2 +- packages/common/locales/global/br.js | 2 +- packages/common/locales/global/brx.js | 2 +- packages/common/locales/global/bs-Cyrl.js | 2 +- packages/common/locales/global/bs-Latn.js | 4 ++-- packages/common/locales/global/bs.js | 4 ++-- packages/common/locales/global/ca-AD.js | 4 ++-- packages/common/locales/global/ca-ES-VALENCIA.js | 4 ++-- packages/common/locales/global/ca-FR.js | 4 ++-- packages/common/locales/global/ca-IT.js | 4 ++-- packages/common/locales/global/ca.js | 4 ++-- packages/common/locales/global/ccp-IN.js | 2 +- packages/common/locales/global/ccp.js | 2 +- packages/common/locales/global/ce.js | 2 +- packages/common/locales/global/ceb.js | 2 +- packages/common/locales/global/cgg.js | 2 +- packages/common/locales/global/chr.js | 2 +- packages/common/locales/global/ckb-IR.js | 2 +- packages/common/locales/global/ckb.js | 2 +- packages/common/locales/global/cs.js | 4 ++-- packages/common/locales/global/cu.js | 2 +- packages/common/locales/global/cy.js | 2 +- packages/common/locales/global/da-GL.js | 4 ++-- packages/common/locales/global/da.js | 4 ++-- packages/common/locales/global/dav.js | 2 +- packages/common/locales/global/de-AT.js | 4 ++-- packages/common/locales/global/de-BE.js | 4 ++-- packages/common/locales/global/de-CH.js | 4 ++-- packages/common/locales/global/de-IT.js | 4 ++-- packages/common/locales/global/de-LI.js | 4 ++-- packages/common/locales/global/de-LU.js | 4 ++-- packages/common/locales/global/de.js | 4 ++-- packages/common/locales/global/dje.js | 2 +- packages/common/locales/global/dsb.js | 4 ++-- packages/common/locales/global/dua.js | 2 +- packages/common/locales/global/dyo.js | 2 +- packages/common/locales/global/dz.js | 2 +- packages/common/locales/global/ebu.js | 2 +- packages/common/locales/global/ee-TG.js | 2 +- packages/common/locales/global/ee.js | 2 +- packages/common/locales/global/el-CY.js | 2 +- packages/common/locales/global/el.js | 2 +- packages/common/locales/global/en-001.js | 4 ++-- packages/common/locales/global/en-150.js | 4 ++-- packages/common/locales/global/en-AE.js | 4 ++-- packages/common/locales/global/en-AG.js | 4 ++-- packages/common/locales/global/en-AI.js | 4 ++-- packages/common/locales/global/en-AS.js | 4 ++-- packages/common/locales/global/en-AT.js | 4 ++-- packages/common/locales/global/en-AU.js | 4 ++-- packages/common/locales/global/en-BB.js | 4 ++-- packages/common/locales/global/en-BE.js | 4 ++-- packages/common/locales/global/en-BI.js | 4 ++-- packages/common/locales/global/en-BM.js | 4 ++-- packages/common/locales/global/en-BS.js | 4 ++-- packages/common/locales/global/en-BW.js | 4 ++-- packages/common/locales/global/en-BZ.js | 4 ++-- packages/common/locales/global/en-CA.js | 4 ++-- packages/common/locales/global/en-CC.js | 4 ++-- packages/common/locales/global/en-CH.js | 4 ++-- packages/common/locales/global/en-CK.js | 4 ++-- packages/common/locales/global/en-CM.js | 4 ++-- packages/common/locales/global/en-CX.js | 4 ++-- packages/common/locales/global/en-CY.js | 4 ++-- packages/common/locales/global/en-DE.js | 4 ++-- packages/common/locales/global/en-DG.js | 4 ++-- packages/common/locales/global/en-DK.js | 4 ++-- packages/common/locales/global/en-DM.js | 4 ++-- packages/common/locales/global/en-ER.js | 4 ++-- packages/common/locales/global/en-FI.js | 4 ++-- packages/common/locales/global/en-FJ.js | 4 ++-- packages/common/locales/global/en-FK.js | 4 ++-- packages/common/locales/global/en-FM.js | 4 ++-- packages/common/locales/global/en-GB.js | 4 ++-- packages/common/locales/global/en-GD.js | 4 ++-- packages/common/locales/global/en-GG.js | 4 ++-- packages/common/locales/global/en-GH.js | 4 ++-- packages/common/locales/global/en-GI.js | 4 ++-- packages/common/locales/global/en-GM.js | 4 ++-- packages/common/locales/global/en-GU.js | 4 ++-- packages/common/locales/global/en-GY.js | 4 ++-- packages/common/locales/global/en-HK.js | 4 ++-- packages/common/locales/global/en-IE.js | 4 ++-- packages/common/locales/global/en-IL.js | 4 ++-- packages/common/locales/global/en-IM.js | 4 ++-- packages/common/locales/global/en-IN.js | 4 ++-- packages/common/locales/global/en-IO.js | 4 ++-- packages/common/locales/global/en-JE.js | 4 ++-- packages/common/locales/global/en-JM.js | 4 ++-- packages/common/locales/global/en-KE.js | 4 ++-- packages/common/locales/global/en-KI.js | 4 ++-- packages/common/locales/global/en-KN.js | 4 ++-- packages/common/locales/global/en-KY.js | 4 ++-- packages/common/locales/global/en-LC.js | 4 ++-- packages/common/locales/global/en-LR.js | 4 ++-- packages/common/locales/global/en-LS.js | 4 ++-- packages/common/locales/global/en-MG.js | 4 ++-- packages/common/locales/global/en-MH.js | 4 ++-- packages/common/locales/global/en-MO.js | 4 ++-- packages/common/locales/global/en-MP.js | 4 ++-- packages/common/locales/global/en-MS.js | 4 ++-- packages/common/locales/global/en-MT.js | 4 ++-- packages/common/locales/global/en-MU.js | 4 ++-- packages/common/locales/global/en-MW.js | 4 ++-- packages/common/locales/global/en-MY.js | 4 ++-- packages/common/locales/global/en-NA.js | 4 ++-- packages/common/locales/global/en-NF.js | 4 ++-- packages/common/locales/global/en-NG.js | 4 ++-- packages/common/locales/global/en-NL.js | 4 ++-- packages/common/locales/global/en-NR.js | 4 ++-- packages/common/locales/global/en-NU.js | 4 ++-- packages/common/locales/global/en-NZ.js | 4 ++-- packages/common/locales/global/en-PG.js | 4 ++-- packages/common/locales/global/en-PH.js | 4 ++-- packages/common/locales/global/en-PK.js | 4 ++-- packages/common/locales/global/en-PN.js | 4 ++-- packages/common/locales/global/en-PR.js | 4 ++-- packages/common/locales/global/en-PW.js | 4 ++-- packages/common/locales/global/en-RW.js | 4 ++-- packages/common/locales/global/en-SB.js | 4 ++-- packages/common/locales/global/en-SC.js | 4 ++-- packages/common/locales/global/en-SD.js | 4 ++-- packages/common/locales/global/en-SE.js | 4 ++-- packages/common/locales/global/en-SG.js | 4 ++-- packages/common/locales/global/en-SH.js | 4 ++-- packages/common/locales/global/en-SI.js | 4 ++-- packages/common/locales/global/en-SL.js | 4 ++-- packages/common/locales/global/en-SS.js | 4 ++-- packages/common/locales/global/en-SX.js | 4 ++-- packages/common/locales/global/en-SZ.js | 4 ++-- packages/common/locales/global/en-TC.js | 4 ++-- packages/common/locales/global/en-TK.js | 4 ++-- packages/common/locales/global/en-TO.js | 4 ++-- packages/common/locales/global/en-TT.js | 4 ++-- packages/common/locales/global/en-TV.js | 4 ++-- packages/common/locales/global/en-TZ.js | 4 ++-- packages/common/locales/global/en-UG.js | 4 ++-- packages/common/locales/global/en-UM.js | 4 ++-- packages/common/locales/global/en-US-POSIX.js | 4 ++-- packages/common/locales/global/en-VC.js | 4 ++-- packages/common/locales/global/en-VG.js | 4 ++-- packages/common/locales/global/en-VI.js | 4 ++-- packages/common/locales/global/en-VU.js | 4 ++-- packages/common/locales/global/en-WS.js | 4 ++-- packages/common/locales/global/en-ZA.js | 4 ++-- packages/common/locales/global/en-ZM.js | 4 ++-- packages/common/locales/global/en-ZW.js | 4 ++-- packages/common/locales/global/en.js | 4 ++-- packages/common/locales/global/eo.js | 2 +- packages/common/locales/global/es-419.js | 2 +- packages/common/locales/global/es-AR.js | 2 +- packages/common/locales/global/es-BO.js | 2 +- packages/common/locales/global/es-BR.js | 2 +- packages/common/locales/global/es-BZ.js | 2 +- packages/common/locales/global/es-CL.js | 2 +- packages/common/locales/global/es-CO.js | 2 +- packages/common/locales/global/es-CR.js | 2 +- packages/common/locales/global/es-CU.js | 2 +- packages/common/locales/global/es-DO.js | 2 +- packages/common/locales/global/es-EA.js | 2 +- packages/common/locales/global/es-EC.js | 2 +- packages/common/locales/global/es-GQ.js | 2 +- packages/common/locales/global/es-GT.js | 2 +- packages/common/locales/global/es-HN.js | 2 +- packages/common/locales/global/es-IC.js | 2 +- packages/common/locales/global/es-MX.js | 2 +- packages/common/locales/global/es-NI.js | 2 +- packages/common/locales/global/es-PA.js | 2 +- packages/common/locales/global/es-PE.js | 2 +- packages/common/locales/global/es-PH.js | 2 +- packages/common/locales/global/es-PR.js | 2 +- packages/common/locales/global/es-PY.js | 2 +- packages/common/locales/global/es-SV.js | 2 +- packages/common/locales/global/es-US.js | 2 +- packages/common/locales/global/es-UY.js | 2 +- packages/common/locales/global/es-VE.js | 2 +- packages/common/locales/global/es.js | 2 +- packages/common/locales/global/et.js | 4 ++-- packages/common/locales/global/eu.js | 2 +- packages/common/locales/global/ewo.js | 2 +- packages/common/locales/global/fa-AF.js | 4 ++-- packages/common/locales/global/fa.js | 4 ++-- packages/common/locales/global/ff-Latn-BF.js | 4 ++-- packages/common/locales/global/ff-Latn-CM.js | 4 ++-- packages/common/locales/global/ff-Latn-GH.js | 4 ++-- packages/common/locales/global/ff-Latn-GM.js | 4 ++-- packages/common/locales/global/ff-Latn-GN.js | 4 ++-- packages/common/locales/global/ff-Latn-GW.js | 4 ++-- packages/common/locales/global/ff-Latn-LR.js | 4 ++-- packages/common/locales/global/ff-Latn-MR.js | 4 ++-- packages/common/locales/global/ff-Latn-NE.js | 4 ++-- packages/common/locales/global/ff-Latn-NG.js | 4 ++-- packages/common/locales/global/ff-Latn-SL.js | 4 ++-- packages/common/locales/global/ff-Latn.js | 4 ++-- packages/common/locales/global/ff.js | 4 ++-- packages/common/locales/global/fi.js | 4 ++-- packages/common/locales/global/fil.js | 4 ++-- packages/common/locales/global/fo-DK.js | 2 +- packages/common/locales/global/fo.js | 2 +- packages/common/locales/global/fr-BE.js | 4 ++-- packages/common/locales/global/fr-BF.js | 4 ++-- packages/common/locales/global/fr-BI.js | 4 ++-- packages/common/locales/global/fr-BJ.js | 4 ++-- packages/common/locales/global/fr-BL.js | 4 ++-- packages/common/locales/global/fr-CA.js | 4 ++-- packages/common/locales/global/fr-CD.js | 4 ++-- packages/common/locales/global/fr-CF.js | 4 ++-- packages/common/locales/global/fr-CG.js | 4 ++-- packages/common/locales/global/fr-CH.js | 4 ++-- packages/common/locales/global/fr-CI.js | 4 ++-- packages/common/locales/global/fr-CM.js | 4 ++-- packages/common/locales/global/fr-DJ.js | 4 ++-- packages/common/locales/global/fr-DZ.js | 4 ++-- packages/common/locales/global/fr-GA.js | 4 ++-- packages/common/locales/global/fr-GF.js | 4 ++-- packages/common/locales/global/fr-GN.js | 4 ++-- packages/common/locales/global/fr-GP.js | 4 ++-- packages/common/locales/global/fr-GQ.js | 4 ++-- packages/common/locales/global/fr-HT.js | 4 ++-- packages/common/locales/global/fr-KM.js | 4 ++-- packages/common/locales/global/fr-LU.js | 4 ++-- packages/common/locales/global/fr-MA.js | 4 ++-- packages/common/locales/global/fr-MC.js | 4 ++-- packages/common/locales/global/fr-MF.js | 4 ++-- packages/common/locales/global/fr-MG.js | 4 ++-- packages/common/locales/global/fr-ML.js | 4 ++-- packages/common/locales/global/fr-MQ.js | 4 ++-- packages/common/locales/global/fr-MR.js | 4 ++-- packages/common/locales/global/fr-MU.js | 4 ++-- packages/common/locales/global/fr-NC.js | 4 ++-- packages/common/locales/global/fr-NE.js | 4 ++-- packages/common/locales/global/fr-PF.js | 4 ++-- packages/common/locales/global/fr-PM.js | 4 ++-- packages/common/locales/global/fr-RE.js | 4 ++-- packages/common/locales/global/fr-RW.js | 4 ++-- packages/common/locales/global/fr-SC.js | 4 ++-- packages/common/locales/global/fr-SN.js | 4 ++-- packages/common/locales/global/fr-SY.js | 4 ++-- packages/common/locales/global/fr-TD.js | 4 ++-- packages/common/locales/global/fr-TG.js | 4 ++-- packages/common/locales/global/fr-TN.js | 4 ++-- packages/common/locales/global/fr-VU.js | 4 ++-- packages/common/locales/global/fr-WF.js | 4 ++-- packages/common/locales/global/fr-YT.js | 4 ++-- packages/common/locales/global/fr.js | 4 ++-- packages/common/locales/global/fur.js | 2 +- packages/common/locales/global/fy.js | 4 ++-- packages/common/locales/global/ga-GB.js | 2 +- packages/common/locales/global/ga.js | 2 +- packages/common/locales/global/gd.js | 2 +- packages/common/locales/global/gl.js | 4 ++-- packages/common/locales/global/gsw-FR.js | 2 +- packages/common/locales/global/gsw-LI.js | 2 +- packages/common/locales/global/gsw.js | 2 +- packages/common/locales/global/gu.js | 4 ++-- packages/common/locales/global/guz.js | 2 +- packages/common/locales/global/gv.js | 4 ++-- packages/common/locales/global/ha-GH.js | 2 +- packages/common/locales/global/ha-NE.js | 2 +- packages/common/locales/global/ha.js | 2 +- packages/common/locales/global/haw.js | 2 +- packages/common/locales/global/he.js | 4 ++-- packages/common/locales/global/hi.js | 4 ++-- packages/common/locales/global/hr-BA.js | 4 ++-- packages/common/locales/global/hr.js | 4 ++-- packages/common/locales/global/hsb.js | 4 ++-- packages/common/locales/global/hu.js | 2 +- packages/common/locales/global/hy.js | 4 ++-- packages/common/locales/global/ia.js | 2 +- packages/common/locales/global/id.js | 2 +- packages/common/locales/global/ig.js | 2 +- packages/common/locales/global/ii.js | 2 +- packages/common/locales/global/is.js | 4 ++-- packages/common/locales/global/it-CH.js | 4 ++-- packages/common/locales/global/it-SM.js | 4 ++-- packages/common/locales/global/it-VA.js | 4 ++-- packages/common/locales/global/it.js | 4 ++-- packages/common/locales/global/ja.js | 2 +- packages/common/locales/global/jgo.js | 2 +- packages/common/locales/global/jmc.js | 2 +- packages/common/locales/global/jv.js | 2 +- packages/common/locales/global/ka.js | 2 +- packages/common/locales/global/kab.js | 4 ++-- packages/common/locales/global/kam.js | 2 +- packages/common/locales/global/kde.js | 2 +- packages/common/locales/global/kea.js | 2 +- packages/common/locales/global/khq.js | 2 +- packages/common/locales/global/ki.js | 2 +- packages/common/locales/global/kk.js | 2 +- packages/common/locales/global/kkj.js | 2 +- packages/common/locales/global/kl.js | 2 +- packages/common/locales/global/kln.js | 2 +- packages/common/locales/global/km.js | 2 +- packages/common/locales/global/kn.js | 4 ++-- packages/common/locales/global/ko-KP.js | 2 +- packages/common/locales/global/ko.js | 2 +- packages/common/locales/global/kok.js | 2 +- packages/common/locales/global/ks.js | 2 +- packages/common/locales/global/ksb.js | 2 +- packages/common/locales/global/ksf.js | 2 +- packages/common/locales/global/ksh.js | 2 +- packages/common/locales/global/ku.js | 2 +- packages/common/locales/global/kw.js | 2 +- packages/common/locales/global/ky.js | 2 +- packages/common/locales/global/lag.js | 4 ++-- packages/common/locales/global/lb.js | 2 +- packages/common/locales/global/lg.js | 2 +- packages/common/locales/global/lkt.js | 2 +- packages/common/locales/global/ln-AO.js | 2 +- packages/common/locales/global/ln-CF.js | 2 +- packages/common/locales/global/ln-CG.js | 2 +- packages/common/locales/global/ln.js | 2 +- packages/common/locales/global/lo.js | 2 +- packages/common/locales/global/lrc-IQ.js | 2 +- packages/common/locales/global/lrc.js | 2 +- packages/common/locales/global/lt.js | 4 ++-- packages/common/locales/global/lu.js | 2 +- packages/common/locales/global/luo.js | 2 +- packages/common/locales/global/luy.js | 2 +- packages/common/locales/global/lv.js | 4 ++-- packages/common/locales/global/mas-TZ.js | 2 +- packages/common/locales/global/mas.js | 2 +- packages/common/locales/global/mer.js | 2 +- packages/common/locales/global/mfe.js | 2 +- packages/common/locales/global/mg.js | 2 +- packages/common/locales/global/mgh.js | 2 +- packages/common/locales/global/mgo.js | 2 +- packages/common/locales/global/mi.js | 2 +- packages/common/locales/global/mk.js | 4 ++-- packages/common/locales/global/ml.js | 2 +- packages/common/locales/global/mn.js | 2 +- packages/common/locales/global/mr.js | 4 ++-- packages/common/locales/global/ms-BN.js | 2 +- packages/common/locales/global/ms-SG.js | 2 +- packages/common/locales/global/ms.js | 2 +- packages/common/locales/global/mt.js | 2 +- packages/common/locales/global/mua.js | 2 +- packages/common/locales/global/my.js | 2 +- packages/common/locales/global/mzn.js | 2 +- packages/common/locales/global/naq.js | 2 +- packages/common/locales/global/nb-SJ.js | 2 +- packages/common/locales/global/nb.js | 2 +- packages/common/locales/global/nd.js | 2 +- packages/common/locales/global/nds-NL.js | 2 +- packages/common/locales/global/nds.js | 2 +- packages/common/locales/global/ne-IN.js | 2 +- packages/common/locales/global/ne.js | 2 +- packages/common/locales/global/nl-AW.js | 4 ++-- packages/common/locales/global/nl-BE.js | 4 ++-- packages/common/locales/global/nl-BQ.js | 4 ++-- packages/common/locales/global/nl-CW.js | 4 ++-- packages/common/locales/global/nl-SR.js | 4 ++-- packages/common/locales/global/nl-SX.js | 4 ++-- packages/common/locales/global/nl.js | 4 ++-- packages/common/locales/global/nmg.js | 2 +- packages/common/locales/global/nn.js | 2 +- packages/common/locales/global/nnh.js | 2 +- packages/common/locales/global/nus.js | 2 +- packages/common/locales/global/nyn.js | 2 +- packages/common/locales/global/om-KE.js | 2 +- packages/common/locales/global/om.js | 2 +- packages/common/locales/global/or.js | 2 +- packages/common/locales/global/os-RU.js | 2 +- packages/common/locales/global/os.js | 2 +- packages/common/locales/global/pa-Arab.js | 2 +- packages/common/locales/global/pa-Guru.js | 2 +- packages/common/locales/global/pa.js | 2 +- packages/common/locales/global/pl.js | 4 ++-- packages/common/locales/global/prg.js | 4 ++-- packages/common/locales/global/ps-PK.js | 2 +- packages/common/locales/global/ps.js | 2 +- packages/common/locales/global/pt-AO.js | 4 ++-- packages/common/locales/global/pt-CH.js | 4 ++-- packages/common/locales/global/pt-CV.js | 4 ++-- packages/common/locales/global/pt-GQ.js | 4 ++-- packages/common/locales/global/pt-GW.js | 4 ++-- packages/common/locales/global/pt-LU.js | 4 ++-- packages/common/locales/global/pt-MO.js | 4 ++-- packages/common/locales/global/pt-MZ.js | 4 ++-- packages/common/locales/global/pt-PT.js | 4 ++-- packages/common/locales/global/pt-ST.js | 4 ++-- packages/common/locales/global/pt-TL.js | 4 ++-- packages/common/locales/global/pt.js | 4 ++-- packages/common/locales/global/qu-BO.js | 2 +- packages/common/locales/global/qu-EC.js | 2 +- packages/common/locales/global/qu.js | 2 +- packages/common/locales/global/rm.js | 2 +- packages/common/locales/global/rn.js | 2 +- packages/common/locales/global/ro-MD.js | 4 ++-- packages/common/locales/global/ro.js | 4 ++-- packages/common/locales/global/rof.js | 2 +- packages/common/locales/global/root.js | 2 +- packages/common/locales/global/ru-BY.js | 4 ++-- packages/common/locales/global/ru-KG.js | 4 ++-- packages/common/locales/global/ru-KZ.js | 4 ++-- packages/common/locales/global/ru-MD.js | 4 ++-- packages/common/locales/global/ru-UA.js | 4 ++-- packages/common/locales/global/ru.js | 4 ++-- packages/common/locales/global/rw.js | 2 +- packages/common/locales/global/rwk.js | 2 +- packages/common/locales/global/sah.js | 2 +- packages/common/locales/global/saq.js | 2 +- packages/common/locales/global/sbp.js | 2 +- packages/common/locales/global/sd.js | 2 +- packages/common/locales/global/se-FI.js | 2 +- packages/common/locales/global/se-SE.js | 2 +- packages/common/locales/global/se.js | 2 +- packages/common/locales/global/seh.js | 2 +- packages/common/locales/global/ses.js | 2 +- packages/common/locales/global/sg.js | 2 +- packages/common/locales/global/shi-Latn.js | 2 +- packages/common/locales/global/shi-Tfng.js | 4 ++-- packages/common/locales/global/shi.js | 4 ++-- packages/common/locales/global/si.js | 4 ++-- packages/common/locales/global/sk.js | 4 ++-- packages/common/locales/global/sl.js | 4 ++-- packages/common/locales/global/smn.js | 2 +- packages/common/locales/global/sn.js | 2 +- packages/common/locales/global/so-DJ.js | 2 +- packages/common/locales/global/so-ET.js | 2 +- packages/common/locales/global/so-KE.js | 2 +- packages/common/locales/global/so.js | 2 +- packages/common/locales/global/sq-MK.js | 2 +- packages/common/locales/global/sq-XK.js | 2 +- packages/common/locales/global/sq.js | 2 +- packages/common/locales/global/sr-Cyrl-BA.js | 4 ++-- packages/common/locales/global/sr-Cyrl-ME.js | 4 ++-- packages/common/locales/global/sr-Cyrl-XK.js | 4 ++-- packages/common/locales/global/sr-Cyrl.js | 4 ++-- packages/common/locales/global/sr-Latn-BA.js | 2 +- packages/common/locales/global/sr-Latn-ME.js | 2 +- packages/common/locales/global/sr-Latn-XK.js | 2 +- packages/common/locales/global/sr-Latn.js | 2 +- packages/common/locales/global/sr.js | 4 ++-- packages/common/locales/global/sv-AX.js | 4 ++-- packages/common/locales/global/sv-FI.js | 4 ++-- packages/common/locales/global/sv.js | 4 ++-- packages/common/locales/global/sw-CD.js | 4 ++-- packages/common/locales/global/sw-KE.js | 4 ++-- packages/common/locales/global/sw-UG.js | 4 ++-- packages/common/locales/global/sw.js | 4 ++-- packages/common/locales/global/ta-LK.js | 2 +- packages/common/locales/global/ta-MY.js | 2 +- packages/common/locales/global/ta-SG.js | 2 +- packages/common/locales/global/ta.js | 2 +- packages/common/locales/global/te.js | 2 +- packages/common/locales/global/teo-KE.js | 2 +- packages/common/locales/global/teo.js | 2 +- packages/common/locales/global/tg.js | 2 +- packages/common/locales/global/th.js | 2 +- packages/common/locales/global/ti-ER.js | 2 +- packages/common/locales/global/ti.js | 2 +- packages/common/locales/global/tk.js | 2 +- packages/common/locales/global/to.js | 2 +- packages/common/locales/global/tr-CY.js | 2 +- packages/common/locales/global/tr.js | 2 +- packages/common/locales/global/tt.js | 2 +- packages/common/locales/global/twq.js | 2 +- packages/common/locales/global/tzm.js | 2 +- packages/common/locales/global/ug.js | 2 +- packages/common/locales/global/uk.js | 4 ++-- packages/common/locales/global/ur-IN.js | 4 ++-- packages/common/locales/global/ur.js | 4 ++-- packages/common/locales/global/uz-Arab.js | 2 +- packages/common/locales/global/uz-Cyrl.js | 2 +- packages/common/locales/global/uz-Latn.js | 2 +- packages/common/locales/global/uz.js | 2 +- packages/common/locales/global/vai-Latn.js | 2 +- packages/common/locales/global/vai-Vaii.js | 2 +- packages/common/locales/global/vai.js | 2 +- packages/common/locales/global/vi.js | 2 +- packages/common/locales/global/vo.js | 2 +- packages/common/locales/global/vun.js | 2 +- packages/common/locales/global/wae.js | 2 +- packages/common/locales/global/wo.js | 2 +- packages/common/locales/global/xh.js | 2 +- packages/common/locales/global/xog.js | 2 +- packages/common/locales/global/yav.js | 2 +- packages/common/locales/global/yi.js | 4 ++-- packages/common/locales/global/yo-BJ.js | 2 +- packages/common/locales/global/yo.js | 2 +- packages/common/locales/global/yue-Hans.js | 2 +- packages/common/locales/global/yue-Hant.js | 2 +- packages/common/locales/global/yue.js | 2 +- packages/common/locales/global/zgh.js | 2 +- packages/common/locales/global/zh-Hans-HK.js | 2 +- packages/common/locales/global/zh-Hans-MO.js | 2 +- packages/common/locales/global/zh-Hans-SG.js | 2 +- packages/common/locales/global/zh-Hans.js | 2 +- packages/common/locales/global/zh-Hant-HK.js | 2 +- packages/common/locales/global/zh-Hant-MO.js | 2 +- packages/common/locales/global/zh-Hant.js | 2 +- packages/common/locales/global/zh.js | 2 +- packages/common/locales/global/zu.js | 4 ++-- tools/gulp-tasks/cldr/extract.js | 11 +++++++---- 543 files changed, 815 insertions(+), 812 deletions(-) diff --git a/packages/common/locales/global/af-NA.js b/packages/common/locales/global/af-NA.js index 471a48f7e9b90..d83b3a73e5124 100644 --- a/packages/common/locales/global/af-NA.js +++ b/packages/common/locales/global/af-NA.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/af.js b/packages/common/locales/global/af.js index ee0f963abbc6f..402ed13ea5dd1 100644 --- a/packages/common/locales/global/af.js +++ b/packages/common/locales/global/af.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/agq.js b/packages/common/locales/global/agq.js index bd7afe2bf6c8c..4d5aeb2e694e8 100644 --- a/packages/common/locales/global/agq.js +++ b/packages/common/locales/global/agq.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['agq'] = [ 'agq', diff --git a/packages/common/locales/global/ak.js b/packages/common/locales/global/ak.js index 60e5be2218c5e..fdecc3ee7913e 100644 --- a/packages/common/locales/global/ak.js +++ b/packages/common/locales/global/ak.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/am.js b/packages/common/locales/global/am.js index 0f597a4f75b75..9c0eaed2a5eae 100644 --- a/packages/common/locales/global/am.js +++ b/packages/common/locales/global/am.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ar-AE.js b/packages/common/locales/global/ar-AE.js index 37e655b58772c..515bbf54c7083 100644 --- a/packages/common/locales/global/ar-AE.js +++ b/packages/common/locales/global/ar-AE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-BH.js b/packages/common/locales/global/ar-BH.js index e190d93b54c05..aa0136eba1692 100644 --- a/packages/common/locales/global/ar-BH.js +++ b/packages/common/locales/global/ar-BH.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-DJ.js b/packages/common/locales/global/ar-DJ.js index e8d43396a23f9..53614895a2c19 100644 --- a/packages/common/locales/global/ar-DJ.js +++ b/packages/common/locales/global/ar-DJ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-DZ.js b/packages/common/locales/global/ar-DZ.js index 0177a246858a2..1eec6b1979576 100644 --- a/packages/common/locales/global/ar-DZ.js +++ b/packages/common/locales/global/ar-DZ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-EG.js b/packages/common/locales/global/ar-EG.js index 974b5c95bc277..46859d63e3cd1 100644 --- a/packages/common/locales/global/ar-EG.js +++ b/packages/common/locales/global/ar-EG.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-EH.js b/packages/common/locales/global/ar-EH.js index fa2269483f6cd..daf650c6f01c7 100644 --- a/packages/common/locales/global/ar-EH.js +++ b/packages/common/locales/global/ar-EH.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-ER.js b/packages/common/locales/global/ar-ER.js index feacf13a10bb1..eab142ba56c19 100644 --- a/packages/common/locales/global/ar-ER.js +++ b/packages/common/locales/global/ar-ER.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-IL.js b/packages/common/locales/global/ar-IL.js index c8c839612eeda..b0d8526cf0b6e 100644 --- a/packages/common/locales/global/ar-IL.js +++ b/packages/common/locales/global/ar-IL.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-IQ.js b/packages/common/locales/global/ar-IQ.js index 9e8ce9047f9c5..5c93d987280f1 100644 --- a/packages/common/locales/global/ar-IQ.js +++ b/packages/common/locales/global/ar-IQ.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-JO.js b/packages/common/locales/global/ar-JO.js index df04d870be6d9..d5fd78159abb2 100644 --- a/packages/common/locales/global/ar-JO.js +++ b/packages/common/locales/global/ar-JO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-KM.js b/packages/common/locales/global/ar-KM.js index 62150af6f4ebb..8d95e74be034d 100644 --- a/packages/common/locales/global/ar-KM.js +++ b/packages/common/locales/global/ar-KM.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-KW.js b/packages/common/locales/global/ar-KW.js index b0f491938656e..c781df26a1577 100644 --- a/packages/common/locales/global/ar-KW.js +++ b/packages/common/locales/global/ar-KW.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-LB.js b/packages/common/locales/global/ar-LB.js index 6d808580ff7b8..d3761299bf578 100644 --- a/packages/common/locales/global/ar-LB.js +++ b/packages/common/locales/global/ar-LB.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-LY.js b/packages/common/locales/global/ar-LY.js index 3493caa11bb24..e6970e4ce1aee 100644 --- a/packages/common/locales/global/ar-LY.js +++ b/packages/common/locales/global/ar-LY.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-MA.js b/packages/common/locales/global/ar-MA.js index 1147e34b1135c..0bceb9db7ece5 100644 --- a/packages/common/locales/global/ar-MA.js +++ b/packages/common/locales/global/ar-MA.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-MR.js b/packages/common/locales/global/ar-MR.js index 1aabaeb4a6c3c..be90d064767e3 100644 --- a/packages/common/locales/global/ar-MR.js +++ b/packages/common/locales/global/ar-MR.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-OM.js b/packages/common/locales/global/ar-OM.js index fae36199b8e88..1014d858d0710 100644 --- a/packages/common/locales/global/ar-OM.js +++ b/packages/common/locales/global/ar-OM.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-PS.js b/packages/common/locales/global/ar-PS.js index 4d26adce61102..ad28e1b41b2df 100644 --- a/packages/common/locales/global/ar-PS.js +++ b/packages/common/locales/global/ar-PS.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-QA.js b/packages/common/locales/global/ar-QA.js index d2eab7bbeadee..59f7075db98ac 100644 --- a/packages/common/locales/global/ar-QA.js +++ b/packages/common/locales/global/ar-QA.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-SA.js b/packages/common/locales/global/ar-SA.js index c1b189ca85237..f23111056fe9d 100644 --- a/packages/common/locales/global/ar-SA.js +++ b/packages/common/locales/global/ar-SA.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-SD.js b/packages/common/locales/global/ar-SD.js index 6b7060f6a71d9..920139b554ebf 100644 --- a/packages/common/locales/global/ar-SD.js +++ b/packages/common/locales/global/ar-SD.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-SO.js b/packages/common/locales/global/ar-SO.js index 489a94418f615..51a3ab99f418d 100644 --- a/packages/common/locales/global/ar-SO.js +++ b/packages/common/locales/global/ar-SO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-SS.js b/packages/common/locales/global/ar-SS.js index 007be5fddb78e..2fd060efd6dc1 100644 --- a/packages/common/locales/global/ar-SS.js +++ b/packages/common/locales/global/ar-SS.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-SY.js b/packages/common/locales/global/ar-SY.js index d800ae164504e..1bf501363e95f 100644 --- a/packages/common/locales/global/ar-SY.js +++ b/packages/common/locales/global/ar-SY.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-TD.js b/packages/common/locales/global/ar-TD.js index 2ae8956f318b3..f21b155096988 100644 --- a/packages/common/locales/global/ar-TD.js +++ b/packages/common/locales/global/ar-TD.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-TN.js b/packages/common/locales/global/ar-TN.js index a139f1aa4861f..da5dae7613932 100644 --- a/packages/common/locales/global/ar-TN.js +++ b/packages/common/locales/global/ar-TN.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar-YE.js b/packages/common/locales/global/ar-YE.js index a424bfeec63d5..6c9b815486cf9 100644 --- a/packages/common/locales/global/ar-YE.js +++ b/packages/common/locales/global/ar-YE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ar.js b/packages/common/locales/global/ar.js index a3b36fc52c1c8..b65f325b52645 100644 --- a/packages/common/locales/global/ar.js +++ b/packages/common/locales/global/ar.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/as.js b/packages/common/locales/global/as.js index 9ee490fd81d6a..dd8aa3d57048b 100644 --- a/packages/common/locales/global/as.js +++ b/packages/common/locales/global/as.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/asa.js b/packages/common/locales/global/asa.js index fbb1bfeb4eee3..21911ea9ab8a9 100644 --- a/packages/common/locales/global/asa.js +++ b/packages/common/locales/global/asa.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ast.js b/packages/common/locales/global/ast.js index 0a9c664f00490..3de7e90594274 100644 --- a/packages/common/locales/global/ast.js +++ b/packages/common/locales/global/ast.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/az-Cyrl.js b/packages/common/locales/global/az-Cyrl.js index b89692d60fedc..4ca3c74bcc4dc 100644 --- a/packages/common/locales/global/az-Cyrl.js +++ b/packages/common/locales/global/az-Cyrl.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['az-cyrl'] = [ 'az-Cyrl', diff --git a/packages/common/locales/global/az-Latn.js b/packages/common/locales/global/az-Latn.js index c001130b9e71f..e0ce8088de3f2 100644 --- a/packages/common/locales/global/az-Latn.js +++ b/packages/common/locales/global/az-Latn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/az.js b/packages/common/locales/global/az.js index 334cd9dd20cb9..1a12802797ae2 100644 --- a/packages/common/locales/global/az.js +++ b/packages/common/locales/global/az.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/bas.js b/packages/common/locales/global/bas.js index aceccdc63c73f..1c6ed80228cd3 100644 --- a/packages/common/locales/global/bas.js +++ b/packages/common/locales/global/bas.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['bas'] = [ 'bas', diff --git a/packages/common/locales/global/be.js b/packages/common/locales/global/be.js index 618da2dbffa66..40050693d93e7 100644 --- a/packages/common/locales/global/be.js +++ b/packages/common/locales/global/be.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n % 10 === 1 && !(n % 100 === 11)) return 1; if (n % 10 === Math.floor(n % 10) && n % 10 >= 2 && n % 10 <= 4 && diff --git a/packages/common/locales/global/bem.js b/packages/common/locales/global/bem.js index 55d87dbeef4c2..1de04e1f2c4fe 100644 --- a/packages/common/locales/global/bem.js +++ b/packages/common/locales/global/bem.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/bez.js b/packages/common/locales/global/bez.js index 10172145da912..edbaf6cce320e 100644 --- a/packages/common/locales/global/bez.js +++ b/packages/common/locales/global/bez.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/bg.js b/packages/common/locales/global/bg.js index e5bb8ce111b43..fab3b0d9f63fd 100644 --- a/packages/common/locales/global/bg.js +++ b/packages/common/locales/global/bg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/bm.js b/packages/common/locales/global/bm.js index 72375841f7cfd..eadad1af0e676 100644 --- a/packages/common/locales/global/bm.js +++ b/packages/common/locales/global/bm.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['bm'] = [ 'bm', diff --git a/packages/common/locales/global/bn-IN.js b/packages/common/locales/global/bn-IN.js index b0acd076849d3..389895fe77311 100644 --- a/packages/common/locales/global/bn-IN.js +++ b/packages/common/locales/global/bn-IN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/bn.js b/packages/common/locales/global/bn.js index feecae00052bc..a5153fa4c0ee7 100644 --- a/packages/common/locales/global/bn.js +++ b/packages/common/locales/global/bn.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/bo-IN.js b/packages/common/locales/global/bo-IN.js index e72f00df2af2e..53bfabab61a3f 100644 --- a/packages/common/locales/global/bo-IN.js +++ b/packages/common/locales/global/bo-IN.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['bo-in'] = [ 'bo-IN', diff --git a/packages/common/locales/global/bo.js b/packages/common/locales/global/bo.js index 9eef9ff0c34f3..15084c7a55b14 100644 --- a/packages/common/locales/global/bo.js +++ b/packages/common/locales/global/bo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['bo'] = [ 'bo', diff --git a/packages/common/locales/global/br.js b/packages/common/locales/global/br.js index 42bc652c2e454..cb7a420b113b1 100644 --- a/packages/common/locales/global/br.js +++ b/packages/common/locales/global/br.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n % 10 === 1 && !(n % 100 === 11 || n % 100 === 71 || n % 100 === 91)) return 1; if (n % 10 === 2 && !(n % 100 === 12 || n % 100 === 72 || n % 100 === 92)) return 2; diff --git a/packages/common/locales/global/brx.js b/packages/common/locales/global/brx.js index 80445432a8120..9b13ab4219f39 100644 --- a/packages/common/locales/global/brx.js +++ b/packages/common/locales/global/brx.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/bs-Cyrl.js b/packages/common/locales/global/bs-Cyrl.js index 224c86112c393..095e60c3a6929 100644 --- a/packages/common/locales/global/bs-Cyrl.js +++ b/packages/common/locales/global/bs-Cyrl.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['bs-cyrl'] = [ 'bs-Cyrl', diff --git a/packages/common/locales/global/bs-Latn.js b/packages/common/locales/global/bs-Latn.js index d53e41a4e5ae4..7aba924f48929 100644 --- a/packages/common/locales/global/bs-Latn.js +++ b/packages/common/locales/global/bs-Latn.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; diff --git a/packages/common/locales/global/bs.js b/packages/common/locales/global/bs.js index fac88cea2feb9..c72ed50e2b99d 100644 --- a/packages/common/locales/global/bs.js +++ b/packages/common/locales/global/bs.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; diff --git a/packages/common/locales/global/ca-AD.js b/packages/common/locales/global/ca-AD.js index 2ba18a2495476..e2981f16c99fa 100644 --- a/packages/common/locales/global/ca-AD.js +++ b/packages/common/locales/global/ca-AD.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ca-ES-VALENCIA.js b/packages/common/locales/global/ca-ES-VALENCIA.js index 4a7def3856714..ce3a023e2a0f9 100644 --- a/packages/common/locales/global/ca-ES-VALENCIA.js +++ b/packages/common/locales/global/ca-ES-VALENCIA.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ca-FR.js b/packages/common/locales/global/ca-FR.js index c3a416eaec4f6..660abfab6b5c2 100644 --- a/packages/common/locales/global/ca-FR.js +++ b/packages/common/locales/global/ca-FR.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ca-IT.js b/packages/common/locales/global/ca-IT.js index 81c1a67557cfa..4dd3f9c2f2931 100644 --- a/packages/common/locales/global/ca-IT.js +++ b/packages/common/locales/global/ca-IT.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ca.js b/packages/common/locales/global/ca.js index 47a968af35cf9..6ed04c1a78983 100644 --- a/packages/common/locales/global/ca.js +++ b/packages/common/locales/global/ca.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ccp-IN.js b/packages/common/locales/global/ccp-IN.js index edc58143559bf..babc86723bd9b 100644 --- a/packages/common/locales/global/ccp-IN.js +++ b/packages/common/locales/global/ccp-IN.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ccp-in'] = [ 'ccp-IN', diff --git a/packages/common/locales/global/ccp.js b/packages/common/locales/global/ccp.js index 658bae826e89a..5bd0feb50f90e 100644 --- a/packages/common/locales/global/ccp.js +++ b/packages/common/locales/global/ccp.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ccp'] = [ 'ccp', diff --git a/packages/common/locales/global/ce.js b/packages/common/locales/global/ce.js index cffb72067302b..6e3b8962c6195 100644 --- a/packages/common/locales/global/ce.js +++ b/packages/common/locales/global/ce.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ceb.js b/packages/common/locales/global/ceb.js index 22a96dbfee848..737eea647a728 100644 --- a/packages/common/locales/global/ceb.js +++ b/packages/common/locales/global/ceb.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ceb'] = [ 'ceb', diff --git a/packages/common/locales/global/cgg.js b/packages/common/locales/global/cgg.js index 4eb7401e232f7..2471a2ea5b2c4 100644 --- a/packages/common/locales/global/cgg.js +++ b/packages/common/locales/global/cgg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/chr.js b/packages/common/locales/global/chr.js index 761f06bfc4944..f81e889428396 100644 --- a/packages/common/locales/global/chr.js +++ b/packages/common/locales/global/chr.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ckb-IR.js b/packages/common/locales/global/ckb-IR.js index d565245c9f9a1..2860f055e56f3 100644 --- a/packages/common/locales/global/ckb-IR.js +++ b/packages/common/locales/global/ckb-IR.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ckb.js b/packages/common/locales/global/ckb.js index a185b9ecfa042..c232db19a3005 100644 --- a/packages/common/locales/global/ckb.js +++ b/packages/common/locales/global/ckb.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/cs.js b/packages/common/locales/global/cs.js index aa9946508cf53..a09dfa2e3036a 100644 --- a/packages/common/locales/global/cs.js +++ b/packages/common/locales/global/cs.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; if (i === Math.floor(i) && i >= 2 && i <= 4 && v === 0) return 3; if (!(v === 0)) return 4; diff --git a/packages/common/locales/global/cu.js b/packages/common/locales/global/cu.js index 0e413ac445f82..359ecb9fffa59 100644 --- a/packages/common/locales/global/cu.js +++ b/packages/common/locales/global/cu.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['cu'] = [ 'cu', diff --git a/packages/common/locales/global/cy.js b/packages/common/locales/global/cy.js index 0f502e5b9b883..532bac65eaf42 100644 --- a/packages/common/locales/global/cy.js +++ b/packages/common/locales/global/cy.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/da-GL.js b/packages/common/locales/global/da-GL.js index cdf3c8d2731cc..93f35e6ea2245 100644 --- a/packages/common/locales/global/da-GL.js +++ b/packages/common/locales/global/da-GL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), + var i = Math.floor(Math.abs(n)), t = parseInt(n.toString().replace(/^[^.]*\.?|0+$/g, ''), 10) || 0; if (n === 1 || !(t === 0) && (i === 0 || i === 1)) return 1; return 5; diff --git a/packages/common/locales/global/da.js b/packages/common/locales/global/da.js index 0046ebb7670b0..1dd4851be9583 100644 --- a/packages/common/locales/global/da.js +++ b/packages/common/locales/global/da.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), + var i = Math.floor(Math.abs(n)), t = parseInt(n.toString().replace(/^[^.]*\.?|0+$/g, ''), 10) || 0; if (n === 1 || !(t === 0) && (i === 0 || i === 1)) return 1; return 5; diff --git a/packages/common/locales/global/dav.js b/packages/common/locales/global/dav.js index 8be697e5bdd06..9aec360d245aa 100644 --- a/packages/common/locales/global/dav.js +++ b/packages/common/locales/global/dav.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['dav'] = [ 'dav', diff --git a/packages/common/locales/global/de-AT.js b/packages/common/locales/global/de-AT.js index bf064c7b5cc92..8e87c852c4d05 100644 --- a/packages/common/locales/global/de-AT.js +++ b/packages/common/locales/global/de-AT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/de-BE.js b/packages/common/locales/global/de-BE.js index b6b6cde58a6ed..65facda5220c9 100644 --- a/packages/common/locales/global/de-BE.js +++ b/packages/common/locales/global/de-BE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/de-CH.js b/packages/common/locales/global/de-CH.js index 7d73241a07c39..1f16eebf6ec2d 100644 --- a/packages/common/locales/global/de-CH.js +++ b/packages/common/locales/global/de-CH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/de-IT.js b/packages/common/locales/global/de-IT.js index b90769e392ce5..d7439e75f4875 100644 --- a/packages/common/locales/global/de-IT.js +++ b/packages/common/locales/global/de-IT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/de-LI.js b/packages/common/locales/global/de-LI.js index 7d82d5a35d502..b65dc65e6c315 100644 --- a/packages/common/locales/global/de-LI.js +++ b/packages/common/locales/global/de-LI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/de-LU.js b/packages/common/locales/global/de-LU.js index a9e844a0108d5..70c110441e532 100644 --- a/packages/common/locales/global/de-LU.js +++ b/packages/common/locales/global/de-LU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/de.js b/packages/common/locales/global/de.js index 1379bbaacfdc6..f814dda8f512d 100644 --- a/packages/common/locales/global/de.js +++ b/packages/common/locales/global/de.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/dje.js b/packages/common/locales/global/dje.js index 82a7c7ff403a3..b7d5dd6161b7a 100644 --- a/packages/common/locales/global/dje.js +++ b/packages/common/locales/global/dje.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['dje'] = [ 'dje', diff --git a/packages/common/locales/global/dsb.js b/packages/common/locales/global/dsb.js index 736887461d20d..c2706f54f7186 100644 --- a/packages/common/locales/global/dsb.js +++ b/packages/common/locales/global/dsb.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 100 === 1 || f % 100 === 1) return 1; if (v === 0 && i % 100 === 2 || f % 100 === 2) return 2; diff --git a/packages/common/locales/global/dua.js b/packages/common/locales/global/dua.js index b145567edea91..c4bc66472dc9b 100644 --- a/packages/common/locales/global/dua.js +++ b/packages/common/locales/global/dua.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['dua'] = [ 'dua', diff --git a/packages/common/locales/global/dyo.js b/packages/common/locales/global/dyo.js index 80c4e69119dcc..e85f82dd7f485 100644 --- a/packages/common/locales/global/dyo.js +++ b/packages/common/locales/global/dyo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['dyo'] = [ 'dyo', diff --git a/packages/common/locales/global/dz.js b/packages/common/locales/global/dz.js index a7383c10aa97c..9caf02222f0df 100644 --- a/packages/common/locales/global/dz.js +++ b/packages/common/locales/global/dz.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['dz'] = [ 'dz', diff --git a/packages/common/locales/global/ebu.js b/packages/common/locales/global/ebu.js index 3b93c21ef848e..7313d8e4d8790 100644 --- a/packages/common/locales/global/ebu.js +++ b/packages/common/locales/global/ebu.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ebu'] = [ 'ebu', diff --git a/packages/common/locales/global/ee-TG.js b/packages/common/locales/global/ee-TG.js index 29176223bf9a7..e87277ac9c502 100644 --- a/packages/common/locales/global/ee-TG.js +++ b/packages/common/locales/global/ee-TG.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ee.js b/packages/common/locales/global/ee.js index 57c5d0a879e02..1abd568f96ae6 100644 --- a/packages/common/locales/global/ee.js +++ b/packages/common/locales/global/ee.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/el-CY.js b/packages/common/locales/global/el-CY.js index 37f97c384dae0..17d7e4e5d726b 100644 --- a/packages/common/locales/global/el-CY.js +++ b/packages/common/locales/global/el-CY.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/el.js b/packages/common/locales/global/el.js index 1ab2d32cdb835..25489cb6006c9 100644 --- a/packages/common/locales/global/el.js +++ b/packages/common/locales/global/el.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/en-001.js b/packages/common/locales/global/en-001.js index 5b6c65bb389ec..8fd3949e9734d 100644 --- a/packages/common/locales/global/en-001.js +++ b/packages/common/locales/global/en-001.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-150.js b/packages/common/locales/global/en-150.js index 3e9dc483fa300..867145db9d2a7 100644 --- a/packages/common/locales/global/en-150.js +++ b/packages/common/locales/global/en-150.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-AE.js b/packages/common/locales/global/en-AE.js index e6c14527c844b..787d49eafba2c 100644 --- a/packages/common/locales/global/en-AE.js +++ b/packages/common/locales/global/en-AE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-AG.js b/packages/common/locales/global/en-AG.js index 078f168fe542d..6ea845f9d08b2 100644 --- a/packages/common/locales/global/en-AG.js +++ b/packages/common/locales/global/en-AG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-AI.js b/packages/common/locales/global/en-AI.js index 8e1057e1bdcc5..d6e812bf58e56 100644 --- a/packages/common/locales/global/en-AI.js +++ b/packages/common/locales/global/en-AI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-AS.js b/packages/common/locales/global/en-AS.js index 6b288707dd0b7..48244d48c3b2c 100644 --- a/packages/common/locales/global/en-AS.js +++ b/packages/common/locales/global/en-AS.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-AT.js b/packages/common/locales/global/en-AT.js index 765b638621afe..be6c364c5625d 100644 --- a/packages/common/locales/global/en-AT.js +++ b/packages/common/locales/global/en-AT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-AU.js b/packages/common/locales/global/en-AU.js index 5cc7523db9c3a..8267849b66d7c 100644 --- a/packages/common/locales/global/en-AU.js +++ b/packages/common/locales/global/en-AU.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BB.js b/packages/common/locales/global/en-BB.js index 3476054b26109..3065020a7b280 100644 --- a/packages/common/locales/global/en-BB.js +++ b/packages/common/locales/global/en-BB.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BE.js b/packages/common/locales/global/en-BE.js index 0e5e65193d6f7..4390985a6f68d 100644 --- a/packages/common/locales/global/en-BE.js +++ b/packages/common/locales/global/en-BE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BI.js b/packages/common/locales/global/en-BI.js index 8de64318bb805..90f3e5703b031 100644 --- a/packages/common/locales/global/en-BI.js +++ b/packages/common/locales/global/en-BI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BM.js b/packages/common/locales/global/en-BM.js index 5b322c8867ea2..5f3f7faca0b79 100644 --- a/packages/common/locales/global/en-BM.js +++ b/packages/common/locales/global/en-BM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BS.js b/packages/common/locales/global/en-BS.js index 60618313a353d..97b3180b95774 100644 --- a/packages/common/locales/global/en-BS.js +++ b/packages/common/locales/global/en-BS.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BW.js b/packages/common/locales/global/en-BW.js index 4f4c5a99ab62b..7818fb4b691ab 100644 --- a/packages/common/locales/global/en-BW.js +++ b/packages/common/locales/global/en-BW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-BZ.js b/packages/common/locales/global/en-BZ.js index 64e8e8f066d4c..772d4cb68bcf7 100644 --- a/packages/common/locales/global/en-BZ.js +++ b/packages/common/locales/global/en-BZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CA.js b/packages/common/locales/global/en-CA.js index 3c31c19e20d00..6916729dff62e 100644 --- a/packages/common/locales/global/en-CA.js +++ b/packages/common/locales/global/en-CA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CC.js b/packages/common/locales/global/en-CC.js index 17ee2e3fd80dc..eefcb89a80fce 100644 --- a/packages/common/locales/global/en-CC.js +++ b/packages/common/locales/global/en-CC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CH.js b/packages/common/locales/global/en-CH.js index d04abb05fdbc2..bf1a12853edf0 100644 --- a/packages/common/locales/global/en-CH.js +++ b/packages/common/locales/global/en-CH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CK.js b/packages/common/locales/global/en-CK.js index 9d93825802438..f62a60d017961 100644 --- a/packages/common/locales/global/en-CK.js +++ b/packages/common/locales/global/en-CK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CM.js b/packages/common/locales/global/en-CM.js index efcafac9f1cf3..5316414ea92ce 100644 --- a/packages/common/locales/global/en-CM.js +++ b/packages/common/locales/global/en-CM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CX.js b/packages/common/locales/global/en-CX.js index f62312d48c5d4..e14db9b2118be 100644 --- a/packages/common/locales/global/en-CX.js +++ b/packages/common/locales/global/en-CX.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-CY.js b/packages/common/locales/global/en-CY.js index f2bc8bef4c9d5..d6fcdaec44fa6 100644 --- a/packages/common/locales/global/en-CY.js +++ b/packages/common/locales/global/en-CY.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-DE.js b/packages/common/locales/global/en-DE.js index f80a3d7347c31..e9e4a8dc4f611 100644 --- a/packages/common/locales/global/en-DE.js +++ b/packages/common/locales/global/en-DE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-DG.js b/packages/common/locales/global/en-DG.js index 34256c3fe0ba3..4ba8a399d1868 100644 --- a/packages/common/locales/global/en-DG.js +++ b/packages/common/locales/global/en-DG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-DK.js b/packages/common/locales/global/en-DK.js index 78fa0c61463f0..d961d1850a582 100644 --- a/packages/common/locales/global/en-DK.js +++ b/packages/common/locales/global/en-DK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-DM.js b/packages/common/locales/global/en-DM.js index c850ef2dc44b2..65db91f4b101f 100644 --- a/packages/common/locales/global/en-DM.js +++ b/packages/common/locales/global/en-DM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-ER.js b/packages/common/locales/global/en-ER.js index 993c85bc39c9b..f409d4a2e1b08 100644 --- a/packages/common/locales/global/en-ER.js +++ b/packages/common/locales/global/en-ER.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-FI.js b/packages/common/locales/global/en-FI.js index ff6c12041b245..c3a167b8c8ab1 100644 --- a/packages/common/locales/global/en-FI.js +++ b/packages/common/locales/global/en-FI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-FJ.js b/packages/common/locales/global/en-FJ.js index a7c0b92fd3268..fa308c4e58dfa 100644 --- a/packages/common/locales/global/en-FJ.js +++ b/packages/common/locales/global/en-FJ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-FK.js b/packages/common/locales/global/en-FK.js index 4af4727e15e12..ba2a20423493d 100644 --- a/packages/common/locales/global/en-FK.js +++ b/packages/common/locales/global/en-FK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-FM.js b/packages/common/locales/global/en-FM.js index 97c0f85e604e9..8eedaf8013fb0 100644 --- a/packages/common/locales/global/en-FM.js +++ b/packages/common/locales/global/en-FM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GB.js b/packages/common/locales/global/en-GB.js index c174fd35d4141..0ea0f2ba0e648 100644 --- a/packages/common/locales/global/en-GB.js +++ b/packages/common/locales/global/en-GB.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GD.js b/packages/common/locales/global/en-GD.js index 4eb58a1b49bee..bfe1243d68dd9 100644 --- a/packages/common/locales/global/en-GD.js +++ b/packages/common/locales/global/en-GD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GG.js b/packages/common/locales/global/en-GG.js index 4ad6f137f5552..10ccd23bad5b9 100644 --- a/packages/common/locales/global/en-GG.js +++ b/packages/common/locales/global/en-GG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GH.js b/packages/common/locales/global/en-GH.js index e7e30f5ad72a6..b5616663b7d3a 100644 --- a/packages/common/locales/global/en-GH.js +++ b/packages/common/locales/global/en-GH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GI.js b/packages/common/locales/global/en-GI.js index f37963fb4cce6..869406aeb4d97 100644 --- a/packages/common/locales/global/en-GI.js +++ b/packages/common/locales/global/en-GI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GM.js b/packages/common/locales/global/en-GM.js index eb6316c2d5048..7c95f7b983586 100644 --- a/packages/common/locales/global/en-GM.js +++ b/packages/common/locales/global/en-GM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GU.js b/packages/common/locales/global/en-GU.js index 6a58f2de19f37..df95318b37364 100644 --- a/packages/common/locales/global/en-GU.js +++ b/packages/common/locales/global/en-GU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-GY.js b/packages/common/locales/global/en-GY.js index 9293f01435e30..3f3ace051246e 100644 --- a/packages/common/locales/global/en-GY.js +++ b/packages/common/locales/global/en-GY.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-HK.js b/packages/common/locales/global/en-HK.js index bb3c267a7ff33..40c633851a6ca 100644 --- a/packages/common/locales/global/en-HK.js +++ b/packages/common/locales/global/en-HK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-IE.js b/packages/common/locales/global/en-IE.js index ebbfdbabbbe9b..635ea996ada0e 100644 --- a/packages/common/locales/global/en-IE.js +++ b/packages/common/locales/global/en-IE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-IL.js b/packages/common/locales/global/en-IL.js index 08f452f6d2a8a..a209031d17282 100644 --- a/packages/common/locales/global/en-IL.js +++ b/packages/common/locales/global/en-IL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-IM.js b/packages/common/locales/global/en-IM.js index f7eb39104033f..bd8451132ee8b 100644 --- a/packages/common/locales/global/en-IM.js +++ b/packages/common/locales/global/en-IM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-IN.js b/packages/common/locales/global/en-IN.js index 931d9864492ce..6a17e174c66e3 100644 --- a/packages/common/locales/global/en-IN.js +++ b/packages/common/locales/global/en-IN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-IO.js b/packages/common/locales/global/en-IO.js index 7be7cb49c55fe..b10813580626d 100644 --- a/packages/common/locales/global/en-IO.js +++ b/packages/common/locales/global/en-IO.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-JE.js b/packages/common/locales/global/en-JE.js index 93c24c5dea30d..3d65847087aa5 100644 --- a/packages/common/locales/global/en-JE.js +++ b/packages/common/locales/global/en-JE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-JM.js b/packages/common/locales/global/en-JM.js index 408a1dd8420f1..ab67b90b091d1 100644 --- a/packages/common/locales/global/en-JM.js +++ b/packages/common/locales/global/en-JM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-KE.js b/packages/common/locales/global/en-KE.js index b050ba9242a75..97b2e0bf02246 100644 --- a/packages/common/locales/global/en-KE.js +++ b/packages/common/locales/global/en-KE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-KI.js b/packages/common/locales/global/en-KI.js index c0033bddba8be..2123207f48349 100644 --- a/packages/common/locales/global/en-KI.js +++ b/packages/common/locales/global/en-KI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-KN.js b/packages/common/locales/global/en-KN.js index 39da662be4b98..8d35e569d5272 100644 --- a/packages/common/locales/global/en-KN.js +++ b/packages/common/locales/global/en-KN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-KY.js b/packages/common/locales/global/en-KY.js index 74499ae2804b2..353fd0ab3ff69 100644 --- a/packages/common/locales/global/en-KY.js +++ b/packages/common/locales/global/en-KY.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-LC.js b/packages/common/locales/global/en-LC.js index fe549aff2cdba..8e47aedcd3e99 100644 --- a/packages/common/locales/global/en-LC.js +++ b/packages/common/locales/global/en-LC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-LR.js b/packages/common/locales/global/en-LR.js index 3890a885cac82..c449b257b0f67 100644 --- a/packages/common/locales/global/en-LR.js +++ b/packages/common/locales/global/en-LR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-LS.js b/packages/common/locales/global/en-LS.js index 4e28db09a9b8e..9b7e006b98dfe 100644 --- a/packages/common/locales/global/en-LS.js +++ b/packages/common/locales/global/en-LS.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MG.js b/packages/common/locales/global/en-MG.js index ca6ce4e4d6cfd..5fe68b25420cc 100644 --- a/packages/common/locales/global/en-MG.js +++ b/packages/common/locales/global/en-MG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MH.js b/packages/common/locales/global/en-MH.js index 499e8a6bd5cb0..26a41b4cb90d4 100644 --- a/packages/common/locales/global/en-MH.js +++ b/packages/common/locales/global/en-MH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MO.js b/packages/common/locales/global/en-MO.js index 4a7457d478859..6145393a5c62e 100644 --- a/packages/common/locales/global/en-MO.js +++ b/packages/common/locales/global/en-MO.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MP.js b/packages/common/locales/global/en-MP.js index 8afe11c18e7ea..74fe1fb9f6de5 100644 --- a/packages/common/locales/global/en-MP.js +++ b/packages/common/locales/global/en-MP.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MS.js b/packages/common/locales/global/en-MS.js index eefe032f5ab2b..ab0b23eb3178e 100644 --- a/packages/common/locales/global/en-MS.js +++ b/packages/common/locales/global/en-MS.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MT.js b/packages/common/locales/global/en-MT.js index 4e88841ac26c3..cc5092755a476 100644 --- a/packages/common/locales/global/en-MT.js +++ b/packages/common/locales/global/en-MT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MU.js b/packages/common/locales/global/en-MU.js index 0c5f51a0a0a10..dab8c42b541b5 100644 --- a/packages/common/locales/global/en-MU.js +++ b/packages/common/locales/global/en-MU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MW.js b/packages/common/locales/global/en-MW.js index d936b75bf63e8..c2862d90922ea 100644 --- a/packages/common/locales/global/en-MW.js +++ b/packages/common/locales/global/en-MW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-MY.js b/packages/common/locales/global/en-MY.js index 3102a86043af3..d47adfb7bf329 100644 --- a/packages/common/locales/global/en-MY.js +++ b/packages/common/locales/global/en-MY.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NA.js b/packages/common/locales/global/en-NA.js index dee551b0c88cd..48d735c09dd31 100644 --- a/packages/common/locales/global/en-NA.js +++ b/packages/common/locales/global/en-NA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NF.js b/packages/common/locales/global/en-NF.js index 1cce502afa797..065515038b946 100644 --- a/packages/common/locales/global/en-NF.js +++ b/packages/common/locales/global/en-NF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NG.js b/packages/common/locales/global/en-NG.js index 2d339ef24bb11..bef60e4bcd346 100644 --- a/packages/common/locales/global/en-NG.js +++ b/packages/common/locales/global/en-NG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NL.js b/packages/common/locales/global/en-NL.js index fcde4a243c3ad..e7f73520b87d0 100644 --- a/packages/common/locales/global/en-NL.js +++ b/packages/common/locales/global/en-NL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NR.js b/packages/common/locales/global/en-NR.js index b6f9732968181..c86c1b095cb43 100644 --- a/packages/common/locales/global/en-NR.js +++ b/packages/common/locales/global/en-NR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NU.js b/packages/common/locales/global/en-NU.js index 466ef028a79a6..bf03bc8508838 100644 --- a/packages/common/locales/global/en-NU.js +++ b/packages/common/locales/global/en-NU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-NZ.js b/packages/common/locales/global/en-NZ.js index 15229a37a5fbf..218a2846ee610 100644 --- a/packages/common/locales/global/en-NZ.js +++ b/packages/common/locales/global/en-NZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-PG.js b/packages/common/locales/global/en-PG.js index ff6edcad39135..414f957be97db 100644 --- a/packages/common/locales/global/en-PG.js +++ b/packages/common/locales/global/en-PG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-PH.js b/packages/common/locales/global/en-PH.js index 38c481b481b88..4a04e833dbee4 100644 --- a/packages/common/locales/global/en-PH.js +++ b/packages/common/locales/global/en-PH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-PK.js b/packages/common/locales/global/en-PK.js index a1526e78b51ce..1e79df18af4a9 100644 --- a/packages/common/locales/global/en-PK.js +++ b/packages/common/locales/global/en-PK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-PN.js b/packages/common/locales/global/en-PN.js index c8fa0348dd530..cc3d71c036b26 100644 --- a/packages/common/locales/global/en-PN.js +++ b/packages/common/locales/global/en-PN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-PR.js b/packages/common/locales/global/en-PR.js index ca573c7075cc3..2113a349db707 100644 --- a/packages/common/locales/global/en-PR.js +++ b/packages/common/locales/global/en-PR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-PW.js b/packages/common/locales/global/en-PW.js index 0de86f3573489..4e1f90d25d387 100644 --- a/packages/common/locales/global/en-PW.js +++ b/packages/common/locales/global/en-PW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-RW.js b/packages/common/locales/global/en-RW.js index 12a60eb6cc301..c33b44b50212e 100644 --- a/packages/common/locales/global/en-RW.js +++ b/packages/common/locales/global/en-RW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SB.js b/packages/common/locales/global/en-SB.js index d4a5f27874edd..412a512364c4b 100644 --- a/packages/common/locales/global/en-SB.js +++ b/packages/common/locales/global/en-SB.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SC.js b/packages/common/locales/global/en-SC.js index 6b25fd1bbd480..b2cbc120e612b 100644 --- a/packages/common/locales/global/en-SC.js +++ b/packages/common/locales/global/en-SC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SD.js b/packages/common/locales/global/en-SD.js index ae72a66cecda4..69c22cb2ac49e 100644 --- a/packages/common/locales/global/en-SD.js +++ b/packages/common/locales/global/en-SD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SE.js b/packages/common/locales/global/en-SE.js index eddb4e1578511..a764302c3f480 100644 --- a/packages/common/locales/global/en-SE.js +++ b/packages/common/locales/global/en-SE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SG.js b/packages/common/locales/global/en-SG.js index 8e9de3572bdce..2b37772595a57 100644 --- a/packages/common/locales/global/en-SG.js +++ b/packages/common/locales/global/en-SG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SH.js b/packages/common/locales/global/en-SH.js index c66dbb29a97d7..479bbf4ff9fdb 100644 --- a/packages/common/locales/global/en-SH.js +++ b/packages/common/locales/global/en-SH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SI.js b/packages/common/locales/global/en-SI.js index 4aad71c3f9002..f73435935b980 100644 --- a/packages/common/locales/global/en-SI.js +++ b/packages/common/locales/global/en-SI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SL.js b/packages/common/locales/global/en-SL.js index 2ee48417ad5a4..118586b56652b 100644 --- a/packages/common/locales/global/en-SL.js +++ b/packages/common/locales/global/en-SL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SS.js b/packages/common/locales/global/en-SS.js index 12202ac75a072..136bb1372406d 100644 --- a/packages/common/locales/global/en-SS.js +++ b/packages/common/locales/global/en-SS.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SX.js b/packages/common/locales/global/en-SX.js index 25b0237a2f365..c58b46b98b89e 100644 --- a/packages/common/locales/global/en-SX.js +++ b/packages/common/locales/global/en-SX.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-SZ.js b/packages/common/locales/global/en-SZ.js index 755d49edad513..dfbe74fd8dd22 100644 --- a/packages/common/locales/global/en-SZ.js +++ b/packages/common/locales/global/en-SZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-TC.js b/packages/common/locales/global/en-TC.js index 4615c0ee70148..26cebc4138e57 100644 --- a/packages/common/locales/global/en-TC.js +++ b/packages/common/locales/global/en-TC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-TK.js b/packages/common/locales/global/en-TK.js index 4e02f43a3de15..fe64bad456b92 100644 --- a/packages/common/locales/global/en-TK.js +++ b/packages/common/locales/global/en-TK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-TO.js b/packages/common/locales/global/en-TO.js index 4bc3f20af9dbc..2af3d9f0c208f 100644 --- a/packages/common/locales/global/en-TO.js +++ b/packages/common/locales/global/en-TO.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-TT.js b/packages/common/locales/global/en-TT.js index 7197069cd3ebe..991d9427c5792 100644 --- a/packages/common/locales/global/en-TT.js +++ b/packages/common/locales/global/en-TT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-TV.js b/packages/common/locales/global/en-TV.js index cb6ce847ec980..ef8d73190d9d8 100644 --- a/packages/common/locales/global/en-TV.js +++ b/packages/common/locales/global/en-TV.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-TZ.js b/packages/common/locales/global/en-TZ.js index 67094aecbe760..f5bc5c77dd727 100644 --- a/packages/common/locales/global/en-TZ.js +++ b/packages/common/locales/global/en-TZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-UG.js b/packages/common/locales/global/en-UG.js index ca7f59b1c003a..2d2e3dfa379a5 100644 --- a/packages/common/locales/global/en-UG.js +++ b/packages/common/locales/global/en-UG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-UM.js b/packages/common/locales/global/en-UM.js index 382278a1663f7..535af1eef1bb5 100644 --- a/packages/common/locales/global/en-UM.js +++ b/packages/common/locales/global/en-UM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-US-POSIX.js b/packages/common/locales/global/en-US-POSIX.js index 228879be926af..7688ba7b621bf 100644 --- a/packages/common/locales/global/en-US-POSIX.js +++ b/packages/common/locales/global/en-US-POSIX.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-VC.js b/packages/common/locales/global/en-VC.js index a436135deb71c..2b18cf2b41137 100644 --- a/packages/common/locales/global/en-VC.js +++ b/packages/common/locales/global/en-VC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-VG.js b/packages/common/locales/global/en-VG.js index 3b3ddb8d2bb5f..f174fff3b5f03 100644 --- a/packages/common/locales/global/en-VG.js +++ b/packages/common/locales/global/en-VG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-VI.js b/packages/common/locales/global/en-VI.js index 84f9c115e18cf..dc8e37ef7a14c 100644 --- a/packages/common/locales/global/en-VI.js +++ b/packages/common/locales/global/en-VI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-VU.js b/packages/common/locales/global/en-VU.js index 65232c1f5b09b..ce62bd1589613 100644 --- a/packages/common/locales/global/en-VU.js +++ b/packages/common/locales/global/en-VU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-WS.js b/packages/common/locales/global/en-WS.js index 3b0d4be8d2f6f..27ae7e44f43a1 100644 --- a/packages/common/locales/global/en-WS.js +++ b/packages/common/locales/global/en-WS.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-ZA.js b/packages/common/locales/global/en-ZA.js index f9e330d69af77..fe1a34f07f036 100644 --- a/packages/common/locales/global/en-ZA.js +++ b/packages/common/locales/global/en-ZA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-ZM.js b/packages/common/locales/global/en-ZM.js index 75ecaa50ed329..a9582c2e38a6a 100644 --- a/packages/common/locales/global/en-ZM.js +++ b/packages/common/locales/global/en-ZM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en-ZW.js b/packages/common/locales/global/en-ZW.js index f408a964041cc..66b6f0456e4de 100644 --- a/packages/common/locales/global/en-ZW.js +++ b/packages/common/locales/global/en-ZW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/en.js b/packages/common/locales/global/en.js index e4f3e8830a63a..544e78f017cf5 100644 --- a/packages/common/locales/global/en.js +++ b/packages/common/locales/global/en.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/eo.js b/packages/common/locales/global/eo.js index 62e1a1d1eabdf..3031c75833699 100644 --- a/packages/common/locales/global/eo.js +++ b/packages/common/locales/global/eo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-419.js b/packages/common/locales/global/es-419.js index 89716bbf05f03..f2a5ee7db2510 100644 --- a/packages/common/locales/global/es-419.js +++ b/packages/common/locales/global/es-419.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-AR.js b/packages/common/locales/global/es-AR.js index ba96bc05d2efb..45961e3ce78d1 100644 --- a/packages/common/locales/global/es-AR.js +++ b/packages/common/locales/global/es-AR.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-BO.js b/packages/common/locales/global/es-BO.js index 86a30a2c68290..7f39ddf1cc041 100644 --- a/packages/common/locales/global/es-BO.js +++ b/packages/common/locales/global/es-BO.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-BR.js b/packages/common/locales/global/es-BR.js index 65dc00aba85f0..8391fc6e1d408 100644 --- a/packages/common/locales/global/es-BR.js +++ b/packages/common/locales/global/es-BR.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-BZ.js b/packages/common/locales/global/es-BZ.js index ff53cc45c4f68..ac1fa76933e77 100644 --- a/packages/common/locales/global/es-BZ.js +++ b/packages/common/locales/global/es-BZ.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-CL.js b/packages/common/locales/global/es-CL.js index 7ddf2309d3fa2..023dfddc63066 100644 --- a/packages/common/locales/global/es-CL.js +++ b/packages/common/locales/global/es-CL.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-CO.js b/packages/common/locales/global/es-CO.js index c4cc34c392e57..3f4194c632796 100644 --- a/packages/common/locales/global/es-CO.js +++ b/packages/common/locales/global/es-CO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-CR.js b/packages/common/locales/global/es-CR.js index d16216b8fbd7c..d981452c0bc13 100644 --- a/packages/common/locales/global/es-CR.js +++ b/packages/common/locales/global/es-CR.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-CU.js b/packages/common/locales/global/es-CU.js index c4c4d1dbb96da..6fb30a3dd6acb 100644 --- a/packages/common/locales/global/es-CU.js +++ b/packages/common/locales/global/es-CU.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-DO.js b/packages/common/locales/global/es-DO.js index 88dbf09caf49f..9b3f267f384db 100644 --- a/packages/common/locales/global/es-DO.js +++ b/packages/common/locales/global/es-DO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-EA.js b/packages/common/locales/global/es-EA.js index ad22653f6db7b..52b35b3921cb8 100644 --- a/packages/common/locales/global/es-EA.js +++ b/packages/common/locales/global/es-EA.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-EC.js b/packages/common/locales/global/es-EC.js index 5f9f691db3ce0..d9353e7447199 100644 --- a/packages/common/locales/global/es-EC.js +++ b/packages/common/locales/global/es-EC.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-GQ.js b/packages/common/locales/global/es-GQ.js index 65d5cfdbfe867..803a813ff7a0e 100644 --- a/packages/common/locales/global/es-GQ.js +++ b/packages/common/locales/global/es-GQ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-GT.js b/packages/common/locales/global/es-GT.js index 7e3d07e20f38c..b83a21c541f6e 100644 --- a/packages/common/locales/global/es-GT.js +++ b/packages/common/locales/global/es-GT.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-HN.js b/packages/common/locales/global/es-HN.js index 4ad92812efb19..d1b8e3457ac92 100644 --- a/packages/common/locales/global/es-HN.js +++ b/packages/common/locales/global/es-HN.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-IC.js b/packages/common/locales/global/es-IC.js index b8c513415f4f2..5535f02a00753 100644 --- a/packages/common/locales/global/es-IC.js +++ b/packages/common/locales/global/es-IC.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-MX.js b/packages/common/locales/global/es-MX.js index 7f17449cba01e..8dcb6e7787889 100644 --- a/packages/common/locales/global/es-MX.js +++ b/packages/common/locales/global/es-MX.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-NI.js b/packages/common/locales/global/es-NI.js index 392716545700b..c216dfb3ea6c6 100644 --- a/packages/common/locales/global/es-NI.js +++ b/packages/common/locales/global/es-NI.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-PA.js b/packages/common/locales/global/es-PA.js index 15b395b39a7f9..bed4212d9f6a9 100644 --- a/packages/common/locales/global/es-PA.js +++ b/packages/common/locales/global/es-PA.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-PE.js b/packages/common/locales/global/es-PE.js index 1370da88694b7..cfb7331841f2c 100644 --- a/packages/common/locales/global/es-PE.js +++ b/packages/common/locales/global/es-PE.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-PH.js b/packages/common/locales/global/es-PH.js index 2565a82b135b5..8427dc80b4d2a 100644 --- a/packages/common/locales/global/es-PH.js +++ b/packages/common/locales/global/es-PH.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-PR.js b/packages/common/locales/global/es-PR.js index 50bd9b60e35dd..70a0d70847636 100644 --- a/packages/common/locales/global/es-PR.js +++ b/packages/common/locales/global/es-PR.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-PY.js b/packages/common/locales/global/es-PY.js index 1f035aacf1520..b671b83733caa 100644 --- a/packages/common/locales/global/es-PY.js +++ b/packages/common/locales/global/es-PY.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-SV.js b/packages/common/locales/global/es-SV.js index 8cfda5a099d53..82f63a368b9f7 100644 --- a/packages/common/locales/global/es-SV.js +++ b/packages/common/locales/global/es-SV.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-US.js b/packages/common/locales/global/es-US.js index 62048686b5f9e..40372f8a82760 100644 --- a/packages/common/locales/global/es-US.js +++ b/packages/common/locales/global/es-US.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-UY.js b/packages/common/locales/global/es-UY.js index 82e44cfd0dc5c..33f7acfccbe09 100644 --- a/packages/common/locales/global/es-UY.js +++ b/packages/common/locales/global/es-UY.js @@ -14,7 +14,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es-VE.js b/packages/common/locales/global/es-VE.js index 4e247a1ec525b..dedf77c07dbcf 100644 --- a/packages/common/locales/global/es-VE.js +++ b/packages/common/locales/global/es-VE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/es.js b/packages/common/locales/global/es.js index 403be2819b2e4..559aab8805491 100644 --- a/packages/common/locales/global/es.js +++ b/packages/common/locales/global/es.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/et.js b/packages/common/locales/global/et.js index df789d76d2756..ca8487034bdb8 100644 --- a/packages/common/locales/global/et.js +++ b/packages/common/locales/global/et.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/eu.js b/packages/common/locales/global/eu.js index 9605e1e58fb33..9e0364b86ad6e 100644 --- a/packages/common/locales/global/eu.js +++ b/packages/common/locales/global/eu.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ewo.js b/packages/common/locales/global/ewo.js index e7d6ce2be8940..be06cd5c0ff94 100644 --- a/packages/common/locales/global/ewo.js +++ b/packages/common/locales/global/ewo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ewo'] = [ 'ewo', diff --git a/packages/common/locales/global/fa-AF.js b/packages/common/locales/global/fa-AF.js index d39cdecac6472..da0a228e43d3a 100644 --- a/packages/common/locales/global/fa-AF.js +++ b/packages/common/locales/global/fa-AF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fa.js b/packages/common/locales/global/fa.js index da637bf95295e..021c376a490d4 100644 --- a/packages/common/locales/global/fa.js +++ b/packages/common/locales/global/fa.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-BF.js b/packages/common/locales/global/ff-Latn-BF.js index b2450efe235ba..b723d5890b7a3 100644 --- a/packages/common/locales/global/ff-Latn-BF.js +++ b/packages/common/locales/global/ff-Latn-BF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-CM.js b/packages/common/locales/global/ff-Latn-CM.js index cde16b99e0d0e..7f86c1dfc9b36 100644 --- a/packages/common/locales/global/ff-Latn-CM.js +++ b/packages/common/locales/global/ff-Latn-CM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-GH.js b/packages/common/locales/global/ff-Latn-GH.js index 040449270f837..db526ab7d3018 100644 --- a/packages/common/locales/global/ff-Latn-GH.js +++ b/packages/common/locales/global/ff-Latn-GH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-GM.js b/packages/common/locales/global/ff-Latn-GM.js index 7a7c14b48c144..1118933960a14 100644 --- a/packages/common/locales/global/ff-Latn-GM.js +++ b/packages/common/locales/global/ff-Latn-GM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-GN.js b/packages/common/locales/global/ff-Latn-GN.js index e79d8f8fce7ec..dc4621c6e238f 100644 --- a/packages/common/locales/global/ff-Latn-GN.js +++ b/packages/common/locales/global/ff-Latn-GN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-GW.js b/packages/common/locales/global/ff-Latn-GW.js index 143eb1e0ebb24..90553e5b682fe 100644 --- a/packages/common/locales/global/ff-Latn-GW.js +++ b/packages/common/locales/global/ff-Latn-GW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-LR.js b/packages/common/locales/global/ff-Latn-LR.js index 2f7a9abe55474..e3d7b52b15087 100644 --- a/packages/common/locales/global/ff-Latn-LR.js +++ b/packages/common/locales/global/ff-Latn-LR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-MR.js b/packages/common/locales/global/ff-Latn-MR.js index 0eeddd3ca70d2..366e09d9bfc0b 100644 --- a/packages/common/locales/global/ff-Latn-MR.js +++ b/packages/common/locales/global/ff-Latn-MR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-NE.js b/packages/common/locales/global/ff-Latn-NE.js index fdd359832568a..0ed91f71640fc 100644 --- a/packages/common/locales/global/ff-Latn-NE.js +++ b/packages/common/locales/global/ff-Latn-NE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-NG.js b/packages/common/locales/global/ff-Latn-NG.js index b3379cd49fced..f39ea71d02048 100644 --- a/packages/common/locales/global/ff-Latn-NG.js +++ b/packages/common/locales/global/ff-Latn-NG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn-SL.js b/packages/common/locales/global/ff-Latn-SL.js index 09635ebc384e7..4c322e5b6641f 100644 --- a/packages/common/locales/global/ff-Latn-SL.js +++ b/packages/common/locales/global/ff-Latn-SL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff-Latn.js b/packages/common/locales/global/ff-Latn.js index 47a9da1709774..9805c6c963d81 100644 --- a/packages/common/locales/global/ff-Latn.js +++ b/packages/common/locales/global/ff-Latn.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ff.js b/packages/common/locales/global/ff.js index 8255730de33ab..fbd7e9efd63fa 100644 --- a/packages/common/locales/global/ff.js +++ b/packages/common/locales/global/ff.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fi.js b/packages/common/locales/global/fi.js index e6296457d2f24..e4a414dec1bfe 100644 --- a/packages/common/locales/global/fi.js +++ b/packages/common/locales/global/fi.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/fil.js b/packages/common/locales/global/fil.js index cb59ad85c3e70..9b8dc667ef615 100644 --- a/packages/common/locales/global/fil.js +++ b/packages/common/locales/global/fil.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && (i === 1 || i === 2 || i === 3) || v === 0 && !(i % 10 === 4 || i % 10 === 6 || i % 10 === 9) || diff --git a/packages/common/locales/global/fo-DK.js b/packages/common/locales/global/fo-DK.js index c0f93453f9f8a..f6373174fdae7 100644 --- a/packages/common/locales/global/fo-DK.js +++ b/packages/common/locales/global/fo-DK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/fo.js b/packages/common/locales/global/fo.js index 809712a01c169..e8902eed84174 100644 --- a/packages/common/locales/global/fo.js +++ b/packages/common/locales/global/fo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/fr-BE.js b/packages/common/locales/global/fr-BE.js index 391249f601a2f..c0f3254eb044d 100644 --- a/packages/common/locales/global/fr-BE.js +++ b/packages/common/locales/global/fr-BE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-BF.js b/packages/common/locales/global/fr-BF.js index 103371a94a161..b0609a3b528bd 100644 --- a/packages/common/locales/global/fr-BF.js +++ b/packages/common/locales/global/fr-BF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-BI.js b/packages/common/locales/global/fr-BI.js index f4311189e2c23..3751f226bda79 100644 --- a/packages/common/locales/global/fr-BI.js +++ b/packages/common/locales/global/fr-BI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-BJ.js b/packages/common/locales/global/fr-BJ.js index 114f6d3bd79ef..e25ccd8fb1b16 100644 --- a/packages/common/locales/global/fr-BJ.js +++ b/packages/common/locales/global/fr-BJ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-BL.js b/packages/common/locales/global/fr-BL.js index a95b8a8190c72..ded4107230e6a 100644 --- a/packages/common/locales/global/fr-BL.js +++ b/packages/common/locales/global/fr-BL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CA.js b/packages/common/locales/global/fr-CA.js index 4f1b1e8950b93..f1b5b55af551c 100644 --- a/packages/common/locales/global/fr-CA.js +++ b/packages/common/locales/global/fr-CA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CD.js b/packages/common/locales/global/fr-CD.js index 3c40538fd666e..40638cef5210f 100644 --- a/packages/common/locales/global/fr-CD.js +++ b/packages/common/locales/global/fr-CD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CF.js b/packages/common/locales/global/fr-CF.js index e71ad662378ae..9f703e6c8125b 100644 --- a/packages/common/locales/global/fr-CF.js +++ b/packages/common/locales/global/fr-CF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CG.js b/packages/common/locales/global/fr-CG.js index f3711b2bde897..44e51b790b994 100644 --- a/packages/common/locales/global/fr-CG.js +++ b/packages/common/locales/global/fr-CG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CH.js b/packages/common/locales/global/fr-CH.js index 36728bb5a65ca..f96967ab5a4c2 100644 --- a/packages/common/locales/global/fr-CH.js +++ b/packages/common/locales/global/fr-CH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CI.js b/packages/common/locales/global/fr-CI.js index ac0362af1d825..10aeb8f7055ae 100644 --- a/packages/common/locales/global/fr-CI.js +++ b/packages/common/locales/global/fr-CI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-CM.js b/packages/common/locales/global/fr-CM.js index 8b8372f2cae06..65d849945999c 100644 --- a/packages/common/locales/global/fr-CM.js +++ b/packages/common/locales/global/fr-CM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-DJ.js b/packages/common/locales/global/fr-DJ.js index 09098da1db6c3..222a90992e897 100644 --- a/packages/common/locales/global/fr-DJ.js +++ b/packages/common/locales/global/fr-DJ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-DZ.js b/packages/common/locales/global/fr-DZ.js index 2fdf877eaa850..c8628ab966c3d 100644 --- a/packages/common/locales/global/fr-DZ.js +++ b/packages/common/locales/global/fr-DZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-GA.js b/packages/common/locales/global/fr-GA.js index 3b3fcd8c28bec..6f0e16f1dc533 100644 --- a/packages/common/locales/global/fr-GA.js +++ b/packages/common/locales/global/fr-GA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-GF.js b/packages/common/locales/global/fr-GF.js index 89284fc2c1c1a..26ad4a6794a26 100644 --- a/packages/common/locales/global/fr-GF.js +++ b/packages/common/locales/global/fr-GF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-GN.js b/packages/common/locales/global/fr-GN.js index 75a480d7a76d6..013bd0546f39f 100644 --- a/packages/common/locales/global/fr-GN.js +++ b/packages/common/locales/global/fr-GN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-GP.js b/packages/common/locales/global/fr-GP.js index e75c673580d43..7066ff121346b 100644 --- a/packages/common/locales/global/fr-GP.js +++ b/packages/common/locales/global/fr-GP.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-GQ.js b/packages/common/locales/global/fr-GQ.js index 11deee8d51e35..05b3ab3e45d64 100644 --- a/packages/common/locales/global/fr-GQ.js +++ b/packages/common/locales/global/fr-GQ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-HT.js b/packages/common/locales/global/fr-HT.js index 1b436b12bd515..ffde1040112ec 100644 --- a/packages/common/locales/global/fr-HT.js +++ b/packages/common/locales/global/fr-HT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-KM.js b/packages/common/locales/global/fr-KM.js index 4954b27880629..0dce2cadc2eb3 100644 --- a/packages/common/locales/global/fr-KM.js +++ b/packages/common/locales/global/fr-KM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-LU.js b/packages/common/locales/global/fr-LU.js index 4edd776e0524c..1a54b654ac121 100644 --- a/packages/common/locales/global/fr-LU.js +++ b/packages/common/locales/global/fr-LU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MA.js b/packages/common/locales/global/fr-MA.js index a93d9821fb551..e5a6845cd9436 100644 --- a/packages/common/locales/global/fr-MA.js +++ b/packages/common/locales/global/fr-MA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MC.js b/packages/common/locales/global/fr-MC.js index ae9bde399d005..8020f51a5e14c 100644 --- a/packages/common/locales/global/fr-MC.js +++ b/packages/common/locales/global/fr-MC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MF.js b/packages/common/locales/global/fr-MF.js index df342fd9a64d8..a25c821682ef5 100644 --- a/packages/common/locales/global/fr-MF.js +++ b/packages/common/locales/global/fr-MF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MG.js b/packages/common/locales/global/fr-MG.js index 72891a999b885..2872552f8279c 100644 --- a/packages/common/locales/global/fr-MG.js +++ b/packages/common/locales/global/fr-MG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-ML.js b/packages/common/locales/global/fr-ML.js index 3eff899b9d514..4ece63c30375a 100644 --- a/packages/common/locales/global/fr-ML.js +++ b/packages/common/locales/global/fr-ML.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MQ.js b/packages/common/locales/global/fr-MQ.js index 256902f232aba..d5562f91249fc 100644 --- a/packages/common/locales/global/fr-MQ.js +++ b/packages/common/locales/global/fr-MQ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MR.js b/packages/common/locales/global/fr-MR.js index c90be32699566..715bc7c29f09d 100644 --- a/packages/common/locales/global/fr-MR.js +++ b/packages/common/locales/global/fr-MR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-MU.js b/packages/common/locales/global/fr-MU.js index 437271ae5136c..38b98b60a33a8 100644 --- a/packages/common/locales/global/fr-MU.js +++ b/packages/common/locales/global/fr-MU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-NC.js b/packages/common/locales/global/fr-NC.js index 622525f99acd0..6287da8063b19 100644 --- a/packages/common/locales/global/fr-NC.js +++ b/packages/common/locales/global/fr-NC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-NE.js b/packages/common/locales/global/fr-NE.js index d97c8c510c8aa..9a095717eacbd 100644 --- a/packages/common/locales/global/fr-NE.js +++ b/packages/common/locales/global/fr-NE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-PF.js b/packages/common/locales/global/fr-PF.js index 8e18925250f1e..512ddcc0ef036 100644 --- a/packages/common/locales/global/fr-PF.js +++ b/packages/common/locales/global/fr-PF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-PM.js b/packages/common/locales/global/fr-PM.js index 200be437d5d81..e2420c6544a4e 100644 --- a/packages/common/locales/global/fr-PM.js +++ b/packages/common/locales/global/fr-PM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-RE.js b/packages/common/locales/global/fr-RE.js index aac33e3a0d478..5f112c1604e10 100644 --- a/packages/common/locales/global/fr-RE.js +++ b/packages/common/locales/global/fr-RE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-RW.js b/packages/common/locales/global/fr-RW.js index be31eef96fa1e..430bf137acc4e 100644 --- a/packages/common/locales/global/fr-RW.js +++ b/packages/common/locales/global/fr-RW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-SC.js b/packages/common/locales/global/fr-SC.js index 66d1b20a6c215..0fd0b73eb2e5a 100644 --- a/packages/common/locales/global/fr-SC.js +++ b/packages/common/locales/global/fr-SC.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-SN.js b/packages/common/locales/global/fr-SN.js index 7f84ea9704d26..950a4ad89f97d 100644 --- a/packages/common/locales/global/fr-SN.js +++ b/packages/common/locales/global/fr-SN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-SY.js b/packages/common/locales/global/fr-SY.js index 5404df5ce07ca..7dcb9fe2f094e 100644 --- a/packages/common/locales/global/fr-SY.js +++ b/packages/common/locales/global/fr-SY.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-TD.js b/packages/common/locales/global/fr-TD.js index 4c379d8741978..878b33c6d5afd 100644 --- a/packages/common/locales/global/fr-TD.js +++ b/packages/common/locales/global/fr-TD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-TG.js b/packages/common/locales/global/fr-TG.js index cb3a8a965832f..9fd3865665f73 100644 --- a/packages/common/locales/global/fr-TG.js +++ b/packages/common/locales/global/fr-TG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-TN.js b/packages/common/locales/global/fr-TN.js index 8e58e32880a8a..accfefa05ead0 100644 --- a/packages/common/locales/global/fr-TN.js +++ b/packages/common/locales/global/fr-TN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-VU.js b/packages/common/locales/global/fr-VU.js index c5a6e715b0bdd..1a3c68ec61a7d 100644 --- a/packages/common/locales/global/fr-VU.js +++ b/packages/common/locales/global/fr-VU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-WF.js b/packages/common/locales/global/fr-WF.js index effd70cb60398..37ae6b86750de 100644 --- a/packages/common/locales/global/fr-WF.js +++ b/packages/common/locales/global/fr-WF.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr-YT.js b/packages/common/locales/global/fr-YT.js index 4842c78851699..3e89351346ab9 100644 --- a/packages/common/locales/global/fr-YT.js +++ b/packages/common/locales/global/fr-YT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fr.js b/packages/common/locales/global/fr.js index 41852a1be6d5c..c7e8b2c8dc1b0 100644 --- a/packages/common/locales/global/fr.js +++ b/packages/common/locales/global/fr.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/fur.js b/packages/common/locales/global/fur.js index 2d2590bb1a6c6..d52a19b2f13b9 100644 --- a/packages/common/locales/global/fur.js +++ b/packages/common/locales/global/fur.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/fy.js b/packages/common/locales/global/fy.js index 0ba917deefcc3..d6d127bcd78a0 100644 --- a/packages/common/locales/global/fy.js +++ b/packages/common/locales/global/fy.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ga-GB.js b/packages/common/locales/global/ga-GB.js index 0deb9569419da..a8d279c30b19b 100644 --- a/packages/common/locales/global/ga-GB.js +++ b/packages/common/locales/global/ga-GB.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/ga.js b/packages/common/locales/global/ga.js index 222542f3d7e4e..1e87f526d92ac 100644 --- a/packages/common/locales/global/ga.js +++ b/packages/common/locales/global/ga.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/gd.js b/packages/common/locales/global/gd.js index c809a0e86bec6..467226eec5b69 100644 --- a/packages/common/locales/global/gd.js +++ b/packages/common/locales/global/gd.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1 || n === 11) return 1; if (n === 2 || n === 12) return 2; diff --git a/packages/common/locales/global/gl.js b/packages/common/locales/global/gl.js index befcf63be65f4..7c3687f3874e8 100644 --- a/packages/common/locales/global/gl.js +++ b/packages/common/locales/global/gl.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/gsw-FR.js b/packages/common/locales/global/gsw-FR.js index 51288964b1fe9..ef742f2e078df 100644 --- a/packages/common/locales/global/gsw-FR.js +++ b/packages/common/locales/global/gsw-FR.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/gsw-LI.js b/packages/common/locales/global/gsw-LI.js index 3a1f56fae106a..b2b09e01073ec 100644 --- a/packages/common/locales/global/gsw-LI.js +++ b/packages/common/locales/global/gsw-LI.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/gsw.js b/packages/common/locales/global/gsw.js index 35616f29c0b98..e03051b10b863 100644 --- a/packages/common/locales/global/gsw.js +++ b/packages/common/locales/global/gsw.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/gu.js b/packages/common/locales/global/gu.js index df4d1bacf15b5..ca3a420d4fe30 100644 --- a/packages/common/locales/global/gu.js +++ b/packages/common/locales/global/gu.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/guz.js b/packages/common/locales/global/guz.js index 514c3a6ab6d46..24b7136df207f 100644 --- a/packages/common/locales/global/guz.js +++ b/packages/common/locales/global/guz.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['guz'] = [ 'guz', diff --git a/packages/common/locales/global/gv.js b/packages/common/locales/global/gv.js index ef367547bbcdc..510de7c3522d8 100644 --- a/packages/common/locales/global/gv.js +++ b/packages/common/locales/global/gv.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1) return 1; if (v === 0 && i % 10 === 2) return 2; if (v === 0 && diff --git a/packages/common/locales/global/ha-GH.js b/packages/common/locales/global/ha-GH.js index a6a745d9b2081..590f8fa09cb37 100644 --- a/packages/common/locales/global/ha-GH.js +++ b/packages/common/locales/global/ha-GH.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ha-NE.js b/packages/common/locales/global/ha-NE.js index 4c9fb10ae4ce0..5dda225cfa24e 100644 --- a/packages/common/locales/global/ha-NE.js +++ b/packages/common/locales/global/ha-NE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ha.js b/packages/common/locales/global/ha.js index 4200a66969324..32b7c07d82a6d 100644 --- a/packages/common/locales/global/ha.js +++ b/packages/common/locales/global/ha.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/haw.js b/packages/common/locales/global/haw.js index 22f10d6bd54ff..c7f72dc04053c 100644 --- a/packages/common/locales/global/haw.js +++ b/packages/common/locales/global/haw.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/he.js b/packages/common/locales/global/he.js index d6eee2ce34e41..6b793c8f04750 100644 --- a/packages/common/locales/global/he.js +++ b/packages/common/locales/global/he.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; if (i === 2 && v === 0) return 2; if (v === 0 && !(n >= 0 && n <= 10) && n % 10 === 0) return 4; diff --git a/packages/common/locales/global/hi.js b/packages/common/locales/global/hi.js index ef335a399a020..da5351351f63c 100644 --- a/packages/common/locales/global/hi.js +++ b/packages/common/locales/global/hi.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/hr-BA.js b/packages/common/locales/global/hr-BA.js index 9777b0fe95984..2392c17e60d18 100644 --- a/packages/common/locales/global/hr-BA.js +++ b/packages/common/locales/global/hr-BA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/hr.js b/packages/common/locales/global/hr.js index 51ca643469efe..54244d0645903 100644 --- a/packages/common/locales/global/hr.js +++ b/packages/common/locales/global/hr.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/hsb.js b/packages/common/locales/global/hsb.js index 90c97a1ee7aa7..3781817b24b3e 100644 --- a/packages/common/locales/global/hsb.js +++ b/packages/common/locales/global/hsb.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 100 === 1 || f % 100 === 1) return 1; if (v === 0 && i % 100 === 2 || f % 100 === 2) return 2; diff --git a/packages/common/locales/global/hu.js b/packages/common/locales/global/hu.js index 15df0a9c181a2..52a851b421136 100644 --- a/packages/common/locales/global/hu.js +++ b/packages/common/locales/global/hu.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/hy.js b/packages/common/locales/global/hy.js index fac06183abe07..607cf165cad9f 100644 --- a/packages/common/locales/global/hy.js +++ b/packages/common/locales/global/hy.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ia.js b/packages/common/locales/global/ia.js index 101aef6dd2a8b..370a429c3c1f2 100644 --- a/packages/common/locales/global/ia.js +++ b/packages/common/locales/global/ia.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ia'] = [ 'ia', diff --git a/packages/common/locales/global/id.js b/packages/common/locales/global/id.js index 6e380a6de55da..7e8aa13eb0bf8 100644 --- a/packages/common/locales/global/id.js +++ b/packages/common/locales/global/id.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['id'] = [ 'id', diff --git a/packages/common/locales/global/ig.js b/packages/common/locales/global/ig.js index 572c257013860..ceb2690542f66 100644 --- a/packages/common/locales/global/ig.js +++ b/packages/common/locales/global/ig.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ig'] = [ 'ig', diff --git a/packages/common/locales/global/ii.js b/packages/common/locales/global/ii.js index d20f7048862cb..9d396ff693269 100644 --- a/packages/common/locales/global/ii.js +++ b/packages/common/locales/global/ii.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ii'] = [ 'ii', diff --git a/packages/common/locales/global/is.js b/packages/common/locales/global/is.js index 10b8f3f605566..408f85584b83a 100644 --- a/packages/common/locales/global/is.js +++ b/packages/common/locales/global/is.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), + var i = Math.floor(Math.abs(n)), t = parseInt(n.toString().replace(/^[^.]*\.?|0+$/g, ''), 10) || 0; if (t === 0 && i % 10 === 1 && !(i % 100 === 11) || !(t === 0)) return 1; return 5; diff --git a/packages/common/locales/global/it-CH.js b/packages/common/locales/global/it-CH.js index 52d74c13dfdef..bc03f610d6f99 100644 --- a/packages/common/locales/global/it-CH.js +++ b/packages/common/locales/global/it-CH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/it-SM.js b/packages/common/locales/global/it-SM.js index 0e462cce36200..45c4a4d5d4c3d 100644 --- a/packages/common/locales/global/it-SM.js +++ b/packages/common/locales/global/it-SM.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/it-VA.js b/packages/common/locales/global/it-VA.js index 76d23d169fe4f..23c045c40dbb3 100644 --- a/packages/common/locales/global/it-VA.js +++ b/packages/common/locales/global/it-VA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/it.js b/packages/common/locales/global/it.js index 4f0bdb452185d..2ab57e6f59084 100644 --- a/packages/common/locales/global/it.js +++ b/packages/common/locales/global/it.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ja.js b/packages/common/locales/global/ja.js index 94d6f90814a47..a743f680f7273 100644 --- a/packages/common/locales/global/ja.js +++ b/packages/common/locales/global/ja.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ja'] = [ 'ja', diff --git a/packages/common/locales/global/jgo.js b/packages/common/locales/global/jgo.js index c742e0cb5d5c7..c811bc4446375 100644 --- a/packages/common/locales/global/jgo.js +++ b/packages/common/locales/global/jgo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/jmc.js b/packages/common/locales/global/jmc.js index 504f88a41b452..5aba3e2f3cb91 100644 --- a/packages/common/locales/global/jmc.js +++ b/packages/common/locales/global/jmc.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/jv.js b/packages/common/locales/global/jv.js index dd1c37fa1aa5b..b9554151745bc 100644 --- a/packages/common/locales/global/jv.js +++ b/packages/common/locales/global/jv.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['jv'] = [ 'jv', diff --git a/packages/common/locales/global/ka.js b/packages/common/locales/global/ka.js index d3e1892a25625..80744fa4aba48 100644 --- a/packages/common/locales/global/ka.js +++ b/packages/common/locales/global/ka.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/kab.js b/packages/common/locales/global/kab.js index 787cb64ea4f4d..7cfb9c125313f 100644 --- a/packages/common/locales/global/kab.js +++ b/packages/common/locales/global/kab.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || i === 1) return 1; return 5; } diff --git a/packages/common/locales/global/kam.js b/packages/common/locales/global/kam.js index 010a0cad91af8..3c4f32277451b 100644 --- a/packages/common/locales/global/kam.js +++ b/packages/common/locales/global/kam.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['kam'] = [ 'kam', diff --git a/packages/common/locales/global/kde.js b/packages/common/locales/global/kde.js index 6bea04324b0de..4a592adbdd99a 100644 --- a/packages/common/locales/global/kde.js +++ b/packages/common/locales/global/kde.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['kde'] = [ 'kde', diff --git a/packages/common/locales/global/kea.js b/packages/common/locales/global/kea.js index 47e7efa8985fd..ff7f8ce72b601 100644 --- a/packages/common/locales/global/kea.js +++ b/packages/common/locales/global/kea.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['kea'] = [ 'kea', diff --git a/packages/common/locales/global/khq.js b/packages/common/locales/global/khq.js index f4507dce5b444..48c1d6f6a9937 100644 --- a/packages/common/locales/global/khq.js +++ b/packages/common/locales/global/khq.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['khq'] = [ 'khq', diff --git a/packages/common/locales/global/ki.js b/packages/common/locales/global/ki.js index dae343a7667ac..11113135f5447 100644 --- a/packages/common/locales/global/ki.js +++ b/packages/common/locales/global/ki.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ki'] = [ 'ki', diff --git a/packages/common/locales/global/kk.js b/packages/common/locales/global/kk.js index ecdb24f2d6916..77986a9f11e20 100644 --- a/packages/common/locales/global/kk.js +++ b/packages/common/locales/global/kk.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/kkj.js b/packages/common/locales/global/kkj.js index a7e22d62d580a..5ca5c43e1a668 100644 --- a/packages/common/locales/global/kkj.js +++ b/packages/common/locales/global/kkj.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/kl.js b/packages/common/locales/global/kl.js index c0df8b1c780f8..c722b41e3e349 100644 --- a/packages/common/locales/global/kl.js +++ b/packages/common/locales/global/kl.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/kln.js b/packages/common/locales/global/kln.js index 7a6580d8a2726..b0105c29f0f8f 100644 --- a/packages/common/locales/global/kln.js +++ b/packages/common/locales/global/kln.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['kln'] = [ 'kln', diff --git a/packages/common/locales/global/km.js b/packages/common/locales/global/km.js index a5242dd4e25a3..f76e5e68ecb9d 100644 --- a/packages/common/locales/global/km.js +++ b/packages/common/locales/global/km.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['km'] = [ 'km', diff --git a/packages/common/locales/global/kn.js b/packages/common/locales/global/kn.js index aed3529b37eb4..f38e47f728856 100644 --- a/packages/common/locales/global/kn.js +++ b/packages/common/locales/global/kn.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ko-KP.js b/packages/common/locales/global/ko-KP.js index 3dffa782bb1a7..ca80712149500 100644 --- a/packages/common/locales/global/ko-KP.js +++ b/packages/common/locales/global/ko-KP.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ko-kp'] = [ 'ko-KP', diff --git a/packages/common/locales/global/ko.js b/packages/common/locales/global/ko.js index 1283b78118699..a35a38b109d70 100644 --- a/packages/common/locales/global/ko.js +++ b/packages/common/locales/global/ko.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ko'] = [ 'ko', diff --git a/packages/common/locales/global/kok.js b/packages/common/locales/global/kok.js index 1a9f317ebf7cb..81aface29f0b6 100644 --- a/packages/common/locales/global/kok.js +++ b/packages/common/locales/global/kok.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['kok'] = [ 'kok', diff --git a/packages/common/locales/global/ks.js b/packages/common/locales/global/ks.js index b92b49fc944bd..ccbf3bb543f59 100644 --- a/packages/common/locales/global/ks.js +++ b/packages/common/locales/global/ks.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ksb.js b/packages/common/locales/global/ksb.js index dfaaa3b3a50c6..e4c2ae41d46a3 100644 --- a/packages/common/locales/global/ksb.js +++ b/packages/common/locales/global/ksb.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ksf.js b/packages/common/locales/global/ksf.js index 2248835c00f39..c67c4c0a10b3c 100644 --- a/packages/common/locales/global/ksf.js +++ b/packages/common/locales/global/ksf.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ksf'] = [ 'ksf', diff --git a/packages/common/locales/global/ksh.js b/packages/common/locales/global/ksh.js index 755939b7a9d8c..1c587755dfa38 100644 --- a/packages/common/locales/global/ksh.js +++ b/packages/common/locales/global/ksh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 0) return 0; if (n === 1) return 1; diff --git a/packages/common/locales/global/ku.js b/packages/common/locales/global/ku.js index 2fc30a4848208..9428e846f4abb 100644 --- a/packages/common/locales/global/ku.js +++ b/packages/common/locales/global/ku.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/kw.js b/packages/common/locales/global/kw.js index b55445a906542..f16c1272eb092 100644 --- a/packages/common/locales/global/kw.js +++ b/packages/common/locales/global/kw.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/ky.js b/packages/common/locales/global/ky.js index fa62c3f68ab6e..25bd6c66310d0 100644 --- a/packages/common/locales/global/ky.js +++ b/packages/common/locales/global/ky.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/lag.js b/packages/common/locales/global/lag.js index f81cdf7edd35f..b32490f0c6643 100644 --- a/packages/common/locales/global/lag.js +++ b/packages/common/locales/global/lag.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (n === 0) return 0; if ((i === 0 || i === 1) && !(n === 0)) return 1; return 5; diff --git a/packages/common/locales/global/lb.js b/packages/common/locales/global/lb.js index 59fdf08faebe0..c543a108abd64 100644 --- a/packages/common/locales/global/lb.js +++ b/packages/common/locales/global/lb.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/lg.js b/packages/common/locales/global/lg.js index e7ac188d99bd6..2ac9a3884f30f 100644 --- a/packages/common/locales/global/lg.js +++ b/packages/common/locales/global/lg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/lkt.js b/packages/common/locales/global/lkt.js index 52163af6dbc96..34f0884e80f8f 100644 --- a/packages/common/locales/global/lkt.js +++ b/packages/common/locales/global/lkt.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['lkt'] = [ 'lkt', diff --git a/packages/common/locales/global/ln-AO.js b/packages/common/locales/global/ln-AO.js index 09732287e5ee4..4a7a4301ebe87 100644 --- a/packages/common/locales/global/ln-AO.js +++ b/packages/common/locales/global/ln-AO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/ln-CF.js b/packages/common/locales/global/ln-CF.js index bcead109e5aa9..e6aacf67b36c4 100644 --- a/packages/common/locales/global/ln-CF.js +++ b/packages/common/locales/global/ln-CF.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/ln-CG.js b/packages/common/locales/global/ln-CG.js index 4b8b33eb55854..c8425432a03b4 100644 --- a/packages/common/locales/global/ln-CG.js +++ b/packages/common/locales/global/ln-CG.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/ln.js b/packages/common/locales/global/ln.js index 9fc4e74df0e66..5c036d6b54043 100644 --- a/packages/common/locales/global/ln.js +++ b/packages/common/locales/global/ln.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/lo.js b/packages/common/locales/global/lo.js index ed97e65fe8436..889d6a59b311f 100644 --- a/packages/common/locales/global/lo.js +++ b/packages/common/locales/global/lo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['lo'] = [ 'lo', diff --git a/packages/common/locales/global/lrc-IQ.js b/packages/common/locales/global/lrc-IQ.js index 359477d9e0c7f..30d7898c6f95d 100644 --- a/packages/common/locales/global/lrc-IQ.js +++ b/packages/common/locales/global/lrc-IQ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['lrc-iq'] = [ 'lrc-IQ', diff --git a/packages/common/locales/global/lrc.js b/packages/common/locales/global/lrc.js index 091746c2ead5e..94a15d761d5d0 100644 --- a/packages/common/locales/global/lrc.js +++ b/packages/common/locales/global/lrc.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['lrc'] = [ 'lrc', diff --git a/packages/common/locales/global/lt.js b/packages/common/locales/global/lt.js index ac683f5183198..d7435afd81dbb 100644 --- a/packages/common/locales/global/lt.js +++ b/packages/common/locales/global/lt.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; + var f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (n % 10 === 1 && !(n % 100 >= 11 && n % 100 <= 19)) return 1; if (n % 10 === Math.floor(n % 10) && n % 10 >= 2 && n % 10 <= 9 && !(n % 100 >= 11 && n % 100 <= 19)) diff --git a/packages/common/locales/global/lu.js b/packages/common/locales/global/lu.js index cb390fc2f6476..cadf639177da4 100644 --- a/packages/common/locales/global/lu.js +++ b/packages/common/locales/global/lu.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['lu'] = [ 'lu', diff --git a/packages/common/locales/global/luo.js b/packages/common/locales/global/luo.js index 920718cede0db..68b96295742ec 100644 --- a/packages/common/locales/global/luo.js +++ b/packages/common/locales/global/luo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['luo'] = [ 'luo', diff --git a/packages/common/locales/global/luy.js b/packages/common/locales/global/luy.js index 2b0eabb48dbe2..ef91edf16083d 100644 --- a/packages/common/locales/global/luy.js +++ b/packages/common/locales/global/luy.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['luy'] = [ 'luy', diff --git a/packages/common/locales/global/lv.js b/packages/common/locales/global/lv.js index d7828a1705907..8e5b418e53326 100644 --- a/packages/common/locales/global/lv.js +++ b/packages/common/locales/global/lv.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let v = n.toString().replace(/^[^.]*\.?/, '').length, + var v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (n % 10 === 0 || n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 19 || v === 2 && f % 100 === Math.floor(f % 100) && f % 100 >= 11 && f % 100 <= 19) diff --git a/packages/common/locales/global/mas-TZ.js b/packages/common/locales/global/mas-TZ.js index 7b75972a5f9ca..fb49169af10df 100644 --- a/packages/common/locales/global/mas-TZ.js +++ b/packages/common/locales/global/mas-TZ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/mas.js b/packages/common/locales/global/mas.js index ae15b235c500b..d4a55660baf74 100644 --- a/packages/common/locales/global/mas.js +++ b/packages/common/locales/global/mas.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/mer.js b/packages/common/locales/global/mer.js index 315db7e742fe7..8e93b43fd75ab 100644 --- a/packages/common/locales/global/mer.js +++ b/packages/common/locales/global/mer.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['mer'] = [ 'mer', diff --git a/packages/common/locales/global/mfe.js b/packages/common/locales/global/mfe.js index 7e4d5d267cfe9..af0f79416dd49 100644 --- a/packages/common/locales/global/mfe.js +++ b/packages/common/locales/global/mfe.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['mfe'] = [ 'mfe', diff --git a/packages/common/locales/global/mg.js b/packages/common/locales/global/mg.js index 97a35f3152be8..76cfebde3bab8 100644 --- a/packages/common/locales/global/mg.js +++ b/packages/common/locales/global/mg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/mgh.js b/packages/common/locales/global/mgh.js index 305c34958920c..8b5ef09c8d91e 100644 --- a/packages/common/locales/global/mgh.js +++ b/packages/common/locales/global/mgh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['mgh'] = [ 'mgh', diff --git a/packages/common/locales/global/mgo.js b/packages/common/locales/global/mgo.js index 01d1a6b6edad5..d8d8d5eb18bbd 100644 --- a/packages/common/locales/global/mgo.js +++ b/packages/common/locales/global/mgo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/mi.js b/packages/common/locales/global/mi.js index 429dfc3e17fee..d91f4ac463652 100644 --- a/packages/common/locales/global/mi.js +++ b/packages/common/locales/global/mi.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['mi'] = [ 'mi', diff --git a/packages/common/locales/global/mk.js b/packages/common/locales/global/mk.js index 4c2a48b1d6a61..1468035ce5004 100644 --- a/packages/common/locales/global/mk.js +++ b/packages/common/locales/global/mk.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; return 5; diff --git a/packages/common/locales/global/ml.js b/packages/common/locales/global/ml.js index a8062bf890da6..6fd9cf5db8e84 100644 --- a/packages/common/locales/global/ml.js +++ b/packages/common/locales/global/ml.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/mn.js b/packages/common/locales/global/mn.js index 392d0ff90d80e..8d9814cc11b99 100644 --- a/packages/common/locales/global/mn.js +++ b/packages/common/locales/global/mn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/mr.js b/packages/common/locales/global/mr.js index 918bc65de8c76..baef20ea52d6d 100644 --- a/packages/common/locales/global/mr.js +++ b/packages/common/locales/global/mr.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/packages/common/locales/global/ms-BN.js b/packages/common/locales/global/ms-BN.js index eda717c9d5ddd..e5de76a2eb56b 100644 --- a/packages/common/locales/global/ms-BN.js +++ b/packages/common/locales/global/ms-BN.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ms-bn'] = [ 'ms-BN', diff --git a/packages/common/locales/global/ms-SG.js b/packages/common/locales/global/ms-SG.js index 6e47535da499d..749eca2d62f63 100644 --- a/packages/common/locales/global/ms-SG.js +++ b/packages/common/locales/global/ms-SG.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ms-sg'] = [ 'ms-SG', diff --git a/packages/common/locales/global/ms.js b/packages/common/locales/global/ms.js index 9a22871e8dd5c..887e6efd11a33 100644 --- a/packages/common/locales/global/ms.js +++ b/packages/common/locales/global/ms.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ms'] = [ 'ms', diff --git a/packages/common/locales/global/mt.js b/packages/common/locales/global/mt.js index de28fb3c60462..9a1af96c5f747 100644 --- a/packages/common/locales/global/mt.js +++ b/packages/common/locales/global/mt.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 0 || n % 100 === Math.floor(n % 100) && n % 100 >= 2 && n % 100 <= 10) return 3; diff --git a/packages/common/locales/global/mua.js b/packages/common/locales/global/mua.js index afa6520a6958f..dccc53caeaa3f 100644 --- a/packages/common/locales/global/mua.js +++ b/packages/common/locales/global/mua.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['mua'] = [ 'mua', diff --git a/packages/common/locales/global/my.js b/packages/common/locales/global/my.js index 357fe87ae7305..f5e5a361e1971 100644 --- a/packages/common/locales/global/my.js +++ b/packages/common/locales/global/my.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['my'] = [ 'my', diff --git a/packages/common/locales/global/mzn.js b/packages/common/locales/global/mzn.js index bb09a4e8af644..2d7da9552d722 100644 --- a/packages/common/locales/global/mzn.js +++ b/packages/common/locales/global/mzn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['mzn'] = [ 'mzn', diff --git a/packages/common/locales/global/naq.js b/packages/common/locales/global/naq.js index 75aed02896e05..af3fc813d9dba 100644 --- a/packages/common/locales/global/naq.js +++ b/packages/common/locales/global/naq.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/nb-SJ.js b/packages/common/locales/global/nb-SJ.js index 8318ae5a42bbb..070de2368c525 100644 --- a/packages/common/locales/global/nb-SJ.js +++ b/packages/common/locales/global/nb-SJ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/nb.js b/packages/common/locales/global/nb.js index 0acc2d7b066f5..32992448a2ff8 100644 --- a/packages/common/locales/global/nb.js +++ b/packages/common/locales/global/nb.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/nd.js b/packages/common/locales/global/nd.js index 29506c7e6ac75..46cbb61a7b0af 100644 --- a/packages/common/locales/global/nd.js +++ b/packages/common/locales/global/nd.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/nds-NL.js b/packages/common/locales/global/nds-NL.js index 90cb3d38fb290..750748b3de245 100644 --- a/packages/common/locales/global/nds-NL.js +++ b/packages/common/locales/global/nds-NL.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['nds-nl'] = [ 'nds-NL', diff --git a/packages/common/locales/global/nds.js b/packages/common/locales/global/nds.js index 79c4b1f13449a..ccd1690daa3e9 100644 --- a/packages/common/locales/global/nds.js +++ b/packages/common/locales/global/nds.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['nds'] = [ 'nds', diff --git a/packages/common/locales/global/ne-IN.js b/packages/common/locales/global/ne-IN.js index 505bdd3360555..78d62b243655a 100644 --- a/packages/common/locales/global/ne-IN.js +++ b/packages/common/locales/global/ne-IN.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ne.js b/packages/common/locales/global/ne.js index 59ea879fd00c6..d31ac419a1f6d 100644 --- a/packages/common/locales/global/ne.js +++ b/packages/common/locales/global/ne.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/nl-AW.js b/packages/common/locales/global/nl-AW.js index 16097d539b53d..c7885eb90c49f 100644 --- a/packages/common/locales/global/nl-AW.js +++ b/packages/common/locales/global/nl-AW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nl-BE.js b/packages/common/locales/global/nl-BE.js index 20588592b3fb9..8861caa38ec92 100644 --- a/packages/common/locales/global/nl-BE.js +++ b/packages/common/locales/global/nl-BE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nl-BQ.js b/packages/common/locales/global/nl-BQ.js index 241e1e53d8c9b..77c12f71ca8b6 100644 --- a/packages/common/locales/global/nl-BQ.js +++ b/packages/common/locales/global/nl-BQ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nl-CW.js b/packages/common/locales/global/nl-CW.js index d11ae5dc3a734..d7816b6761fd8 100644 --- a/packages/common/locales/global/nl-CW.js +++ b/packages/common/locales/global/nl-CW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nl-SR.js b/packages/common/locales/global/nl-SR.js index 8d5b154012fee..92728e33d5773 100644 --- a/packages/common/locales/global/nl-SR.js +++ b/packages/common/locales/global/nl-SR.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nl-SX.js b/packages/common/locales/global/nl-SX.js index e8c4c77e83386..eae12e5fd7ca9 100644 --- a/packages/common/locales/global/nl-SX.js +++ b/packages/common/locales/global/nl-SX.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nl.js b/packages/common/locales/global/nl.js index c4556ce50c096..604ba904caee8 100644 --- a/packages/common/locales/global/nl.js +++ b/packages/common/locales/global/nl.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/nmg.js b/packages/common/locales/global/nmg.js index c0144eb2b8cb6..a2338929e1aad 100644 --- a/packages/common/locales/global/nmg.js +++ b/packages/common/locales/global/nmg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['nmg'] = [ 'nmg', diff --git a/packages/common/locales/global/nn.js b/packages/common/locales/global/nn.js index 8e8c3b8846ca6..80dd2897f3b14 100644 --- a/packages/common/locales/global/nn.js +++ b/packages/common/locales/global/nn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/nnh.js b/packages/common/locales/global/nnh.js index 3c160fb8992e2..d756bda4754eb 100644 --- a/packages/common/locales/global/nnh.js +++ b/packages/common/locales/global/nnh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/nus.js b/packages/common/locales/global/nus.js index 4efa858c3a059..83e9f98224908 100644 --- a/packages/common/locales/global/nus.js +++ b/packages/common/locales/global/nus.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['nus'] = [ 'nus', diff --git a/packages/common/locales/global/nyn.js b/packages/common/locales/global/nyn.js index 1d216526a4dba..f88d0f19133f4 100644 --- a/packages/common/locales/global/nyn.js +++ b/packages/common/locales/global/nyn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/om-KE.js b/packages/common/locales/global/om-KE.js index ab9ca6dba3678..0e73e19504ec7 100644 --- a/packages/common/locales/global/om-KE.js +++ b/packages/common/locales/global/om-KE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/om.js b/packages/common/locales/global/om.js index 3e86164662bce..8745efb4e22e9 100644 --- a/packages/common/locales/global/om.js +++ b/packages/common/locales/global/om.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/or.js b/packages/common/locales/global/or.js index 5c4bda9b8fe78..c2754a9329d97 100644 --- a/packages/common/locales/global/or.js +++ b/packages/common/locales/global/or.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/os-RU.js b/packages/common/locales/global/os-RU.js index fdcf71000e509..4015617984954 100644 --- a/packages/common/locales/global/os-RU.js +++ b/packages/common/locales/global/os-RU.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/os.js b/packages/common/locales/global/os.js index 33e4b2a616bfa..710e3d48f2480 100644 --- a/packages/common/locales/global/os.js +++ b/packages/common/locales/global/os.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/pa-Arab.js b/packages/common/locales/global/pa-Arab.js index b8c51f6edef31..01905ce14c335 100644 --- a/packages/common/locales/global/pa-Arab.js +++ b/packages/common/locales/global/pa-Arab.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['pa-arab'] = [ 'pa-Arab', diff --git a/packages/common/locales/global/pa-Guru.js b/packages/common/locales/global/pa-Guru.js index 134b60e9540a6..ff8e0064a3d04 100644 --- a/packages/common/locales/global/pa-Guru.js +++ b/packages/common/locales/global/pa-Guru.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/pa.js b/packages/common/locales/global/pa.js index c4ef9eb6b31fb..69db152fe2d71 100644 --- a/packages/common/locales/global/pa.js +++ b/packages/common/locales/global/pa.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/pl.js b/packages/common/locales/global/pl.js index 1d8172ceb3da5..acb09c7053774 100644 --- a/packages/common/locales/global/pl.js +++ b/packages/common/locales/global/pl.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/prg.js b/packages/common/locales/global/prg.js index 484561bb4cd1c..ae10b438d4edc 100644 --- a/packages/common/locales/global/prg.js +++ b/packages/common/locales/global/prg.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let v = n.toString().replace(/^[^.]*\.?/, '').length, + var v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (n % 10 === 0 || n % 100 === Math.floor(n % 100) && n % 100 >= 11 && n % 100 <= 19 || v === 2 && f % 100 === Math.floor(f % 100) && f % 100 >= 11 && f % 100 <= 19) diff --git a/packages/common/locales/global/ps-PK.js b/packages/common/locales/global/ps-PK.js index a3761cb53f26a..d049ca367d244 100644 --- a/packages/common/locales/global/ps-PK.js +++ b/packages/common/locales/global/ps-PK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ps.js b/packages/common/locales/global/ps.js index 7d39173443964..60c37ead86dd4 100644 --- a/packages/common/locales/global/ps.js +++ b/packages/common/locales/global/ps.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/pt-AO.js b/packages/common/locales/global/pt-AO.js index 6ee0d7c8f54fe..85c9ab962be1d 100644 --- a/packages/common/locales/global/pt-AO.js +++ b/packages/common/locales/global/pt-AO.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-CH.js b/packages/common/locales/global/pt-CH.js index 67b22c5970787..e140320450d06 100644 --- a/packages/common/locales/global/pt-CH.js +++ b/packages/common/locales/global/pt-CH.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-CV.js b/packages/common/locales/global/pt-CV.js index 798bf7001618a..4ae0125e406fb 100644 --- a/packages/common/locales/global/pt-CV.js +++ b/packages/common/locales/global/pt-CV.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-GQ.js b/packages/common/locales/global/pt-GQ.js index f17a8fbae7e5c..9a3df826a984c 100644 --- a/packages/common/locales/global/pt-GQ.js +++ b/packages/common/locales/global/pt-GQ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-GW.js b/packages/common/locales/global/pt-GW.js index e9d90527d57d0..0c792ca14fd35 100644 --- a/packages/common/locales/global/pt-GW.js +++ b/packages/common/locales/global/pt-GW.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-LU.js b/packages/common/locales/global/pt-LU.js index 49163460cb666..7b021dcbb643d 100644 --- a/packages/common/locales/global/pt-LU.js +++ b/packages/common/locales/global/pt-LU.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-MO.js b/packages/common/locales/global/pt-MO.js index c9a83a9e2d651..484f7088ed2e5 100644 --- a/packages/common/locales/global/pt-MO.js +++ b/packages/common/locales/global/pt-MO.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-MZ.js b/packages/common/locales/global/pt-MZ.js index a4c6e3d2533c7..27b589c957d31 100644 --- a/packages/common/locales/global/pt-MZ.js +++ b/packages/common/locales/global/pt-MZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-PT.js b/packages/common/locales/global/pt-PT.js index 554a67d39dae6..57e20ba3d79fa 100644 --- a/packages/common/locales/global/pt-PT.js +++ b/packages/common/locales/global/pt-PT.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-ST.js b/packages/common/locales/global/pt-ST.js index f8ede4438c523..971e5463f5326 100644 --- a/packages/common/locales/global/pt-ST.js +++ b/packages/common/locales/global/pt-ST.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt-TL.js b/packages/common/locales/global/pt-TL.js index 039e8e1ba4a63..cc7800f1ca7da 100644 --- a/packages/common/locales/global/pt-TL.js +++ b/packages/common/locales/global/pt-TL.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/pt.js b/packages/common/locales/global/pt.js index 97e269601a29d..438dd6b880473 100644 --- a/packages/common/locales/global/pt.js +++ b/packages/common/locales/global/pt.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === Math.floor(i) && i >= 0 && i <= 1) return 1; return 5; } diff --git a/packages/common/locales/global/qu-BO.js b/packages/common/locales/global/qu-BO.js index 27f69478c12da..694ba844b00e9 100644 --- a/packages/common/locales/global/qu-BO.js +++ b/packages/common/locales/global/qu-BO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['qu-bo'] = [ 'qu-BO', diff --git a/packages/common/locales/global/qu-EC.js b/packages/common/locales/global/qu-EC.js index b1de706c62018..6d40e49098265 100644 --- a/packages/common/locales/global/qu-EC.js +++ b/packages/common/locales/global/qu-EC.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['qu-ec'] = [ 'qu-EC', diff --git a/packages/common/locales/global/qu.js b/packages/common/locales/global/qu.js index ac4f263fd2891..c925692f10c5c 100644 --- a/packages/common/locales/global/qu.js +++ b/packages/common/locales/global/qu.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['qu'] = [ 'qu', diff --git a/packages/common/locales/global/rm.js b/packages/common/locales/global/rm.js index d51cf6f8ee059..7cb7d0dbf6ad7 100644 --- a/packages/common/locales/global/rm.js +++ b/packages/common/locales/global/rm.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/rn.js b/packages/common/locales/global/rn.js index 52ff5e00758e3..dd9215791f02c 100644 --- a/packages/common/locales/global/rn.js +++ b/packages/common/locales/global/rn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['rn'] = [ 'rn', diff --git a/packages/common/locales/global/ro-MD.js b/packages/common/locales/global/ro-MD.js index 69d5f85fdde02..6e9cef1d5a263 100644 --- a/packages/common/locales/global/ro-MD.js +++ b/packages/common/locales/global/ro-MD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; if (!(v === 0) || n === 0 || !(n === 1) && n % 100 === Math.floor(n % 100) && n % 100 >= 1 && n % 100 <= 19) diff --git a/packages/common/locales/global/ro.js b/packages/common/locales/global/ro.js index e23796db5adef..ad31168f8c061 100644 --- a/packages/common/locales/global/ro.js +++ b/packages/common/locales/global/ro.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; if (!(v === 0) || n === 0 || !(n === 1) && n % 100 === Math.floor(n % 100) && n % 100 >= 1 && n % 100 <= 19) diff --git a/packages/common/locales/global/rof.js b/packages/common/locales/global/rof.js index f37a0d1b792dd..ebfa465a97f68 100644 --- a/packages/common/locales/global/rof.js +++ b/packages/common/locales/global/rof.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/root.js b/packages/common/locales/global/root.js index 64788dbc0e439..dac95ce130d63 100644 --- a/packages/common/locales/global/root.js +++ b/packages/common/locales/global/root.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['root'] = [ 'root', diff --git a/packages/common/locales/global/ru-BY.js b/packages/common/locales/global/ru-BY.js index 9b5adef61ac63..c579803898cab 100644 --- a/packages/common/locales/global/ru-BY.js +++ b/packages/common/locales/global/ru-BY.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/ru-KG.js b/packages/common/locales/global/ru-KG.js index 241ad8734e193..aa385a53fb03d 100644 --- a/packages/common/locales/global/ru-KG.js +++ b/packages/common/locales/global/ru-KG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/ru-KZ.js b/packages/common/locales/global/ru-KZ.js index 0660885b26be6..f0bf29c806dae 100644 --- a/packages/common/locales/global/ru-KZ.js +++ b/packages/common/locales/global/ru-KZ.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/ru-MD.js b/packages/common/locales/global/ru-MD.js index e90b2b770d030..665592c479c1c 100644 --- a/packages/common/locales/global/ru-MD.js +++ b/packages/common/locales/global/ru-MD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/ru-UA.js b/packages/common/locales/global/ru-UA.js index b761fa6269b90..742a167587f59 100644 --- a/packages/common/locales/global/ru-UA.js +++ b/packages/common/locales/global/ru-UA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/ru.js b/packages/common/locales/global/ru.js index 63c9a13c7fd78..370c567b2a433 100644 --- a/packages/common/locales/global/ru.js +++ b/packages/common/locales/global/ru.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/rw.js b/packages/common/locales/global/rw.js index bd63081879d8e..58a07b7d5d2ba 100644 --- a/packages/common/locales/global/rw.js +++ b/packages/common/locales/global/rw.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['rw'] = [ 'rw', diff --git a/packages/common/locales/global/rwk.js b/packages/common/locales/global/rwk.js index 57800d3ab3070..504311fd9fb25 100644 --- a/packages/common/locales/global/rwk.js +++ b/packages/common/locales/global/rwk.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/sah.js b/packages/common/locales/global/sah.js index edb48091a4ab5..ec1dccec0c22b 100644 --- a/packages/common/locales/global/sah.js +++ b/packages/common/locales/global/sah.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sah'] = [ 'sah', diff --git a/packages/common/locales/global/saq.js b/packages/common/locales/global/saq.js index 8a597173b2527..01402b7c15fc5 100644 --- a/packages/common/locales/global/saq.js +++ b/packages/common/locales/global/saq.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/sbp.js b/packages/common/locales/global/sbp.js index e7ad1f645bc30..c79fa96999446 100644 --- a/packages/common/locales/global/sbp.js +++ b/packages/common/locales/global/sbp.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sbp'] = [ 'sbp', diff --git a/packages/common/locales/global/sd.js b/packages/common/locales/global/sd.js index dce74785b5390..3341337fbb23d 100644 --- a/packages/common/locales/global/sd.js +++ b/packages/common/locales/global/sd.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/se-FI.js b/packages/common/locales/global/se-FI.js index 7da2b23c99370..ddc2c300fbf3f 100644 --- a/packages/common/locales/global/se-FI.js +++ b/packages/common/locales/global/se-FI.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/se-SE.js b/packages/common/locales/global/se-SE.js index 5b76de30073d3..8e6078e66cb67 100644 --- a/packages/common/locales/global/se-SE.js +++ b/packages/common/locales/global/se-SE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/se.js b/packages/common/locales/global/se.js index 27203c21ea3e8..8dfc06179cca1 100644 --- a/packages/common/locales/global/se.js +++ b/packages/common/locales/global/se.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/seh.js b/packages/common/locales/global/seh.js index 8bf3bcf335893..0043a3cf7684e 100644 --- a/packages/common/locales/global/seh.js +++ b/packages/common/locales/global/seh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ses.js b/packages/common/locales/global/ses.js index cec8a6d8ffc15..ec5cc87f63067 100644 --- a/packages/common/locales/global/ses.js +++ b/packages/common/locales/global/ses.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['ses'] = [ 'ses', diff --git a/packages/common/locales/global/sg.js b/packages/common/locales/global/sg.js index 9282f7ab9d57c..2a1ecb5afd17c 100644 --- a/packages/common/locales/global/sg.js +++ b/packages/common/locales/global/sg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sg'] = [ 'sg', diff --git a/packages/common/locales/global/shi-Latn.js b/packages/common/locales/global/shi-Latn.js index 791eab3e0bbde..3d311f8e3cf43 100644 --- a/packages/common/locales/global/shi-Latn.js +++ b/packages/common/locales/global/shi-Latn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['shi-latn'] = [ 'shi-Latn', diff --git a/packages/common/locales/global/shi-Tfng.js b/packages/common/locales/global/shi-Tfng.js index b4fd43257ea72..defda17b600a2 100644 --- a/packages/common/locales/global/shi-Tfng.js +++ b/packages/common/locales/global/shi-Tfng.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; if (n === Math.floor(n) && n >= 2 && n <= 10) return 3; return 5; diff --git a/packages/common/locales/global/shi.js b/packages/common/locales/global/shi.js index 747ce4fb8433c..03fcff3cfbc69 100644 --- a/packages/common/locales/global/shi.js +++ b/packages/common/locales/global/shi.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; if (n === Math.floor(n) && n >= 2 && n <= 10) return 3; return 5; diff --git a/packages/common/locales/global/si.js b/packages/common/locales/global/si.js index 98a0c668c1328..03e8ad6daa57c 100644 --- a/packages/common/locales/global/si.js +++ b/packages/common/locales/global/si.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; + var i = Math.floor(Math.abs(n)), f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (n === 0 || n === 1 || i === 0 && f === 1) return 1; return 5; } diff --git a/packages/common/locales/global/sk.js b/packages/common/locales/global/sk.js index d23f3f853d9b9..398f862781737 100644 --- a/packages/common/locales/global/sk.js +++ b/packages/common/locales/global/sk.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; if (i === Math.floor(i) && i >= 2 && i <= 4 && v === 0) return 3; if (!(v === 0)) return 4; diff --git a/packages/common/locales/global/sl.js b/packages/common/locales/global/sl.js index 5316a375d5263..5455ef2b9cd96 100644 --- a/packages/common/locales/global/sl.js +++ b/packages/common/locales/global/sl.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 100 === 1) return 1; if (v === 0 && i % 100 === 2) return 2; if (v === 0 && i % 100 === Math.floor(i % 100) && i % 100 >= 3 && i % 100 <= 4 || !(v === 0)) diff --git a/packages/common/locales/global/smn.js b/packages/common/locales/global/smn.js index 4f3ea04500930..55f015a31ac79 100644 --- a/packages/common/locales/global/smn.js +++ b/packages/common/locales/global/smn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; if (n === 2) return 2; diff --git a/packages/common/locales/global/sn.js b/packages/common/locales/global/sn.js index ad23df4910788..3a94ee0c7d101 100644 --- a/packages/common/locales/global/sn.js +++ b/packages/common/locales/global/sn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/so-DJ.js b/packages/common/locales/global/so-DJ.js index c09ddff2d9e9d..581c99dd21f80 100644 --- a/packages/common/locales/global/so-DJ.js +++ b/packages/common/locales/global/so-DJ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/so-ET.js b/packages/common/locales/global/so-ET.js index be8180f81b70b..268a155ff4dea 100644 --- a/packages/common/locales/global/so-ET.js +++ b/packages/common/locales/global/so-ET.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/so-KE.js b/packages/common/locales/global/so-KE.js index a8f48871ceffe..6e78e636c9253 100644 --- a/packages/common/locales/global/so-KE.js +++ b/packages/common/locales/global/so-KE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/so.js b/packages/common/locales/global/so.js index e5bfebc21e9a3..5117ad613a4d9 100644 --- a/packages/common/locales/global/so.js +++ b/packages/common/locales/global/so.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/sq-MK.js b/packages/common/locales/global/sq-MK.js index 34277d3cbd77a..37bb80a2a6eaf 100644 --- a/packages/common/locales/global/sq-MK.js +++ b/packages/common/locales/global/sq-MK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/sq-XK.js b/packages/common/locales/global/sq-XK.js index 9fce09b66c2f3..80f379044fe0f 100644 --- a/packages/common/locales/global/sq-XK.js +++ b/packages/common/locales/global/sq-XK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/sq.js b/packages/common/locales/global/sq.js index d441c6ded5345..d7c2359f8a5c6 100644 --- a/packages/common/locales/global/sq.js +++ b/packages/common/locales/global/sq.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/sr-Cyrl-BA.js b/packages/common/locales/global/sr-Cyrl-BA.js index ac28a2cb34858..fa6d1168e2d88 100644 --- a/packages/common/locales/global/sr-Cyrl-BA.js +++ b/packages/common/locales/global/sr-Cyrl-BA.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/sr-Cyrl-ME.js b/packages/common/locales/global/sr-Cyrl-ME.js index 815d2f72adad1..e97d553bf81d8 100644 --- a/packages/common/locales/global/sr-Cyrl-ME.js +++ b/packages/common/locales/global/sr-Cyrl-ME.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/sr-Cyrl-XK.js b/packages/common/locales/global/sr-Cyrl-XK.js index c2ab9caf3c523..150fc42852116 100644 --- a/packages/common/locales/global/sr-Cyrl-XK.js +++ b/packages/common/locales/global/sr-Cyrl-XK.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/sr-Cyrl.js b/packages/common/locales/global/sr-Cyrl.js index e13f483b9009f..c17f14ece5f62 100644 --- a/packages/common/locales/global/sr-Cyrl.js +++ b/packages/common/locales/global/sr-Cyrl.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/sr-Latn-BA.js b/packages/common/locales/global/sr-Latn-BA.js index 4ecdab6a888d5..de940ac87d54d 100644 --- a/packages/common/locales/global/sr-Latn-BA.js +++ b/packages/common/locales/global/sr-Latn-BA.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sr-latn-ba'] = [ 'sr-Latn-BA', diff --git a/packages/common/locales/global/sr-Latn-ME.js b/packages/common/locales/global/sr-Latn-ME.js index 9a01bc4fb5cc7..7897cf3e7e39a 100644 --- a/packages/common/locales/global/sr-Latn-ME.js +++ b/packages/common/locales/global/sr-Latn-ME.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sr-latn-me'] = [ 'sr-Latn-ME', diff --git a/packages/common/locales/global/sr-Latn-XK.js b/packages/common/locales/global/sr-Latn-XK.js index bf2acb6b688c5..2970550206c06 100644 --- a/packages/common/locales/global/sr-Latn-XK.js +++ b/packages/common/locales/global/sr-Latn-XK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sr-latn-xk'] = [ 'sr-Latn-XK', diff --git a/packages/common/locales/global/sr-Latn.js b/packages/common/locales/global/sr-Latn.js index 2130a6a1f676e..b625cdf1b7d0d 100644 --- a/packages/common/locales/global/sr-Latn.js +++ b/packages/common/locales/global/sr-Latn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['sr-latn'] = [ 'sr-Latn', diff --git a/packages/common/locales/global/sr.js b/packages/common/locales/global/sr.js index cd8085f52f708..9a48f3aeaa6cb 100644 --- a/packages/common/locales/global/sr.js +++ b/packages/common/locales/global/sr.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length, f = parseInt(n.toString().replace(/^[^.]*\.?/, ''), 10) || 0; if (v === 0 && i % 10 === 1 && !(i % 100 === 11) || f % 10 === 1 && !(f % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && diff --git a/packages/common/locales/global/sv-AX.js b/packages/common/locales/global/sv-AX.js index 0fa55b18cc20d..d486b55213dab 100644 --- a/packages/common/locales/global/sv-AX.js +++ b/packages/common/locales/global/sv-AX.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/sv-FI.js b/packages/common/locales/global/sv-FI.js index 5d417d6e00965..808772672b200 100644 --- a/packages/common/locales/global/sv-FI.js +++ b/packages/common/locales/global/sv-FI.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/sv.js b/packages/common/locales/global/sv.js index b40fbf2770597..f07e46a397b70 100644 --- a/packages/common/locales/global/sv.js +++ b/packages/common/locales/global/sv.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/sw-CD.js b/packages/common/locales/global/sw-CD.js index 1c97c85d306c0..4bc2f0ad5f840 100644 --- a/packages/common/locales/global/sw-CD.js +++ b/packages/common/locales/global/sw-CD.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/sw-KE.js b/packages/common/locales/global/sw-KE.js index ff6930a26e3b6..1be4455ced99e 100644 --- a/packages/common/locales/global/sw-KE.js +++ b/packages/common/locales/global/sw-KE.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/sw-UG.js b/packages/common/locales/global/sw-UG.js index 36e249702515b..520baac7d9d57 100644 --- a/packages/common/locales/global/sw-UG.js +++ b/packages/common/locales/global/sw-UG.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/sw.js b/packages/common/locales/global/sw.js index 293c306a4421e..fd810d4db6864 100644 --- a/packages/common/locales/global/sw.js +++ b/packages/common/locales/global/sw.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ta-LK.js b/packages/common/locales/global/ta-LK.js index 07f32a2f06f44..3ef2d3c861964 100644 --- a/packages/common/locales/global/ta-LK.js +++ b/packages/common/locales/global/ta-LK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ta-MY.js b/packages/common/locales/global/ta-MY.js index 42b8c2fc5f4e9..2aef753310b4c 100644 --- a/packages/common/locales/global/ta-MY.js +++ b/packages/common/locales/global/ta-MY.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ta-SG.js b/packages/common/locales/global/ta-SG.js index 4a90c2565ed18..f071266197d36 100644 --- a/packages/common/locales/global/ta-SG.js +++ b/packages/common/locales/global/ta-SG.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/ta.js b/packages/common/locales/global/ta.js index 7049c828d71d8..c25933149c979 100644 --- a/packages/common/locales/global/ta.js +++ b/packages/common/locales/global/ta.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/te.js b/packages/common/locales/global/te.js index b0265c5338863..0b520c9088622 100644 --- a/packages/common/locales/global/te.js +++ b/packages/common/locales/global/te.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/teo-KE.js b/packages/common/locales/global/teo-KE.js index b423928838cfb..60ad4a597b9ba 100644 --- a/packages/common/locales/global/teo-KE.js +++ b/packages/common/locales/global/teo-KE.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/teo.js b/packages/common/locales/global/teo.js index 7c439f141e210..b9163b9b50166 100644 --- a/packages/common/locales/global/teo.js +++ b/packages/common/locales/global/teo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/tg.js b/packages/common/locales/global/tg.js index 652481b69a69b..85c6f1afe26e9 100644 --- a/packages/common/locales/global/tg.js +++ b/packages/common/locales/global/tg.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['tg'] = [ 'tg', diff --git a/packages/common/locales/global/th.js b/packages/common/locales/global/th.js index 199d0b01b5e8f..147489bf63076 100644 --- a/packages/common/locales/global/th.js +++ b/packages/common/locales/global/th.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['th'] = [ 'th', diff --git a/packages/common/locales/global/ti-ER.js b/packages/common/locales/global/ti-ER.js index a0e2b874a414e..c45f8527c4e6f 100644 --- a/packages/common/locales/global/ti-ER.js +++ b/packages/common/locales/global/ti-ER.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/ti.js b/packages/common/locales/global/ti.js index d9645991dc27c..2d6e95bd22cd5 100644 --- a/packages/common/locales/global/ti.js +++ b/packages/common/locales/global/ti.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1) return 1; return 5; diff --git a/packages/common/locales/global/tk.js b/packages/common/locales/global/tk.js index 673fbe5d72869..c7354f999b79d 100644 --- a/packages/common/locales/global/tk.js +++ b/packages/common/locales/global/tk.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/to.js b/packages/common/locales/global/to.js index d3218d4b20e5e..46ca4cf9fd44a 100644 --- a/packages/common/locales/global/to.js +++ b/packages/common/locales/global/to.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['to'] = [ 'to', diff --git a/packages/common/locales/global/tr-CY.js b/packages/common/locales/global/tr-CY.js index eb0799e4a0226..3bc6bdfe9d6b1 100644 --- a/packages/common/locales/global/tr-CY.js +++ b/packages/common/locales/global/tr-CY.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/tr.js b/packages/common/locales/global/tr.js index 55de148b02d21..235e786b34b83 100644 --- a/packages/common/locales/global/tr.js +++ b/packages/common/locales/global/tr.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/tt.js b/packages/common/locales/global/tt.js index 8187af7484915..a9168d1d8944d 100644 --- a/packages/common/locales/global/tt.js +++ b/packages/common/locales/global/tt.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['tt'] = [ 'tt', diff --git a/packages/common/locales/global/twq.js b/packages/common/locales/global/twq.js index 4f1358379cd1c..ba27abb534ec7 100644 --- a/packages/common/locales/global/twq.js +++ b/packages/common/locales/global/twq.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['twq'] = [ 'twq', diff --git a/packages/common/locales/global/tzm.js b/packages/common/locales/global/tzm.js index a5144d97f939b..8b13668830fe9 100644 --- a/packages/common/locales/global/tzm.js +++ b/packages/common/locales/global/tzm.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === Math.floor(n) && n >= 0 && n <= 1 || n === Math.floor(n) && n >= 11 && n <= 99) return 1; diff --git a/packages/common/locales/global/ug.js b/packages/common/locales/global/ug.js index 502d59e565326..3e49901a68654 100644 --- a/packages/common/locales/global/ug.js +++ b/packages/common/locales/global/ug.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/uk.js b/packages/common/locales/global/uk.js index 58087a9c37bd5..e71da851d6b53 100644 --- a/packages/common/locales/global/uk.js +++ b/packages/common/locales/global/uk.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (v === 0 && i % 10 === 1 && !(i % 100 === 11)) return 1; if (v === 0 && i % 10 === Math.floor(i % 10) && i % 10 >= 2 && i % 10 <= 4 && !(i % 100 >= 12 && i % 100 <= 14)) diff --git a/packages/common/locales/global/ur-IN.js b/packages/common/locales/global/ur-IN.js index d6ad633597754..54e472eafd15e 100644 --- a/packages/common/locales/global/ur-IN.js +++ b/packages/common/locales/global/ur-IN.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/ur.js b/packages/common/locales/global/ur.js index 2e05ce7dccee8..6cfb4c254c613 100644 --- a/packages/common/locales/global/ur.js +++ b/packages/common/locales/global/ur.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/uz-Arab.js b/packages/common/locales/global/uz-Arab.js index c091a19a736ff..3855cc475013b 100644 --- a/packages/common/locales/global/uz-Arab.js +++ b/packages/common/locales/global/uz-Arab.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['uz-arab'] = [ 'uz-Arab', diff --git a/packages/common/locales/global/uz-Cyrl.js b/packages/common/locales/global/uz-Cyrl.js index 57cf0689ddf7e..5c3bd1bc2f443 100644 --- a/packages/common/locales/global/uz-Cyrl.js +++ b/packages/common/locales/global/uz-Cyrl.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['uz-cyrl'] = [ 'uz-Cyrl', diff --git a/packages/common/locales/global/uz-Latn.js b/packages/common/locales/global/uz-Latn.js index 3d66b9cd300e0..0b03252a2f59e 100644 --- a/packages/common/locales/global/uz-Latn.js +++ b/packages/common/locales/global/uz-Latn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/uz.js b/packages/common/locales/global/uz.js index 275707d6042ac..1fc4eb355fff4 100644 --- a/packages/common/locales/global/uz.js +++ b/packages/common/locales/global/uz.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/vai-Latn.js b/packages/common/locales/global/vai-Latn.js index c6eb75aa35a61..8764ae5d325dd 100644 --- a/packages/common/locales/global/vai-Latn.js +++ b/packages/common/locales/global/vai-Latn.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['vai-latn'] = [ 'vai-Latn', diff --git a/packages/common/locales/global/vai-Vaii.js b/packages/common/locales/global/vai-Vaii.js index ae4fd662eadd2..ec335cb2ddf0d 100644 --- a/packages/common/locales/global/vai-Vaii.js +++ b/packages/common/locales/global/vai-Vaii.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['vai-vaii'] = [ 'vai-Vaii', diff --git a/packages/common/locales/global/vai.js b/packages/common/locales/global/vai.js index e6f3dc9b175bc..0637290929e90 100644 --- a/packages/common/locales/global/vai.js +++ b/packages/common/locales/global/vai.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['vai'] = [ 'vai', diff --git a/packages/common/locales/global/vi.js b/packages/common/locales/global/vi.js index 5a4642ba3121e..b93521473baac 100644 --- a/packages/common/locales/global/vi.js +++ b/packages/common/locales/global/vi.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['vi'] = [ 'vi', diff --git a/packages/common/locales/global/vo.js b/packages/common/locales/global/vo.js index 67d04b9a87d3d..95cb582c47fff 100644 --- a/packages/common/locales/global/vo.js +++ b/packages/common/locales/global/vo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/vun.js b/packages/common/locales/global/vun.js index c33a46a54bdc3..d0f73a01d2b7a 100644 --- a/packages/common/locales/global/vun.js +++ b/packages/common/locales/global/vun.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/wae.js b/packages/common/locales/global/wae.js index 62f9c53005456..db4289b914a54 100644 --- a/packages/common/locales/global/wae.js +++ b/packages/common/locales/global/wae.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/wo.js b/packages/common/locales/global/wo.js index 8cec261b21206..07ad8d0b5ee14 100644 --- a/packages/common/locales/global/wo.js +++ b/packages/common/locales/global/wo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['wo'] = [ 'wo', diff --git a/packages/common/locales/global/xh.js b/packages/common/locales/global/xh.js index b33c08d7a37a2..2662348f93bed 100644 --- a/packages/common/locales/global/xh.js +++ b/packages/common/locales/global/xh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/xog.js b/packages/common/locales/global/xog.js index e883cca213d49..3bc11a75aaf9f 100644 --- a/packages/common/locales/global/xog.js +++ b/packages/common/locales/global/xog.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { if (n === 1) return 1; return 5; diff --git a/packages/common/locales/global/yav.js b/packages/common/locales/global/yav.js index ce0534be67fa4..c90769e3f55c1 100644 --- a/packages/common/locales/global/yav.js +++ b/packages/common/locales/global/yav.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['yav'] = [ 'yav', diff --git a/packages/common/locales/global/yi.js b/packages/common/locales/global/yi.js index f0b7880b2e75a..20f6674ace2a2 100644 --- a/packages/common/locales/global/yi.js +++ b/packages/common/locales/global/yi.js @@ -13,9 +13,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; + var i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; } diff --git a/packages/common/locales/global/yo-BJ.js b/packages/common/locales/global/yo-BJ.js index 09cb6be215bce..aedd908e95e4a 100644 --- a/packages/common/locales/global/yo-BJ.js +++ b/packages/common/locales/global/yo-BJ.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['yo-bj'] = [ 'yo-BJ', diff --git a/packages/common/locales/global/yo.js b/packages/common/locales/global/yo.js index bf10dbdb0b747..00fb2ebb70eb4 100644 --- a/packages/common/locales/global/yo.js +++ b/packages/common/locales/global/yo.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['yo'] = [ 'yo', diff --git a/packages/common/locales/global/yue-Hans.js b/packages/common/locales/global/yue-Hans.js index d92a63b3e4632..53bb9832829a2 100644 --- a/packages/common/locales/global/yue-Hans.js +++ b/packages/common/locales/global/yue-Hans.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['yue-hans'] = [ 'yue-Hans', diff --git a/packages/common/locales/global/yue-Hant.js b/packages/common/locales/global/yue-Hant.js index ada7a41c13963..09e152818009e 100644 --- a/packages/common/locales/global/yue-Hant.js +++ b/packages/common/locales/global/yue-Hant.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['yue-hant'] = [ 'yue-Hant', diff --git a/packages/common/locales/global/yue.js b/packages/common/locales/global/yue.js index 99a450fe4f957..9521859e3f1e7 100644 --- a/packages/common/locales/global/yue.js +++ b/packages/common/locales/global/yue.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['yue'] = [ 'yue', diff --git a/packages/common/locales/global/zgh.js b/packages/common/locales/global/zgh.js index d431e438cfcb0..eeaa8a91fc374 100644 --- a/packages/common/locales/global/zgh.js +++ b/packages/common/locales/global/zgh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zgh'] = [ 'zgh', diff --git a/packages/common/locales/global/zh-Hans-HK.js b/packages/common/locales/global/zh-Hans-HK.js index 5ac2fe792b9c4..7291b9f2674ba 100644 --- a/packages/common/locales/global/zh-Hans-HK.js +++ b/packages/common/locales/global/zh-Hans-HK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hans-hk'] = [ 'zh-Hans-HK', diff --git a/packages/common/locales/global/zh-Hans-MO.js b/packages/common/locales/global/zh-Hans-MO.js index 7252f091add03..0ae9fecf2a7dd 100644 --- a/packages/common/locales/global/zh-Hans-MO.js +++ b/packages/common/locales/global/zh-Hans-MO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hans-mo'] = [ 'zh-Hans-MO', diff --git a/packages/common/locales/global/zh-Hans-SG.js b/packages/common/locales/global/zh-Hans-SG.js index fdeecc45ebad4..7d9471db26553 100644 --- a/packages/common/locales/global/zh-Hans-SG.js +++ b/packages/common/locales/global/zh-Hans-SG.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hans-sg'] = [ 'zh-Hans-SG', diff --git a/packages/common/locales/global/zh-Hans.js b/packages/common/locales/global/zh-Hans.js index 8d8f46ac99200..6524fed35f8e7 100644 --- a/packages/common/locales/global/zh-Hans.js +++ b/packages/common/locales/global/zh-Hans.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hans'] = [ 'zh-Hans', diff --git a/packages/common/locales/global/zh-Hant-HK.js b/packages/common/locales/global/zh-Hant-HK.js index 728e970fc2b04..a8f823ebbc7ed 100644 --- a/packages/common/locales/global/zh-Hant-HK.js +++ b/packages/common/locales/global/zh-Hant-HK.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hant-hk'] = [ 'zh-Hant-HK', diff --git a/packages/common/locales/global/zh-Hant-MO.js b/packages/common/locales/global/zh-Hant-MO.js index b020eecc2b762..7ab0d249298e1 100644 --- a/packages/common/locales/global/zh-Hant-MO.js +++ b/packages/common/locales/global/zh-Hant-MO.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hant-mo'] = [ 'zh-Hant-MO', diff --git a/packages/common/locales/global/zh-Hant.js b/packages/common/locales/global/zh-Hant.js index 922ed5cdfd6f4..f0d01a206ea46 100644 --- a/packages/common/locales/global/zh-Hant.js +++ b/packages/common/locales/global/zh-Hant.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh-hant'] = [ 'zh-Hant', diff --git a/packages/common/locales/global/zh.js b/packages/common/locales/global/zh.js index d5e867ce76899..7e73b32d79aa6 100644 --- a/packages/common/locales/global/zh.js +++ b/packages/common/locales/global/zh.js @@ -13,7 +13,7 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { return 5; } global.ng.common.locales['zh'] = [ 'zh', diff --git a/packages/common/locales/global/zu.js b/packages/common/locales/global/zu.js index 99afd55abfd44..1fcbbf4766e53 100644 --- a/packages/common/locales/global/zu.js +++ b/packages/common/locales/global/zu.js @@ -14,9 +14,9 @@ global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; function plural(n) { - let i = Math.floor(Math.abs(n)); + var i = Math.floor(Math.abs(n)); if (i === 0 || n === 1) return 1; return 5; } diff --git a/tools/gulp-tasks/cldr/extract.js b/tools/gulp-tasks/cldr/extract.js index 084c50e21c3a0..e3cb1f1e081d3 100644 --- a/tools/gulp-tasks/cldr/extract.js +++ b/tools/gulp-tasks/cldr/extract.js @@ -138,7 +138,7 @@ function generateGlobalLocale(locale, localeData, baseCurrencies) { global.ng = global.ng || {}; global.ng.common = global.ng.common || {}; global.ng.common.locales = global.ng.common.locales || {}; - const u = undefined; + var u = undefined; ${getPluralFunction(locale, false)} global.ng.common.locales['${normalizeLocale(locale)}'] = ${data}; })(typeof globalThis !== 'undefined' && globalThis || typeof global !== 'undefined' && global || typeof window !== 'undefined' && window); @@ -559,19 +559,22 @@ function toRegExp(s) { * todo(ocombe): replace "cldr" extractPluralRuleFunction with our own extraction using "CldrJS" * because the 2 libs can become out of sync if they use different versions of the cldr database */ -function getPluralFunction(locale, withTypes = true) { +function getPluralFunction(locale, typescript = true) { let fn = cldr.extractPluralRuleFunction(locale).toString(); if (fn === EMPTY_RULE) { fn = DEFAULT_RULE; } - const numberType = withTypes ? ': number' : ''; + const numberType = typescript ? ': number' : ''; fn = fn.replace(/function anonymous\(n[^}]+{/g, `function plural(n${numberType})${numberType} {`) - .replace(toRegExp('var'), 'let') .replace(toRegExp('if(typeof n==="string")n=parseInt(n,10);'), '') .replace(toRegExp('\n}'), ';\n}'); + if (typescript) { + fn = fn.replace(toRegExp('var'), 'let'); + } + // The replacement values must match the `Plural` enum from common. // We do not use the enum directly to avoid depending on that package. return fn.replace(toRegExp('"zero"'), ' 0') From 4aa4e6fd03469c270ed9e293c1e0e48fc474ce12 Mon Sep 17 00:00:00 2001 From: JoostK <joost.koehoorn@gmail.com> Date: Tue, 17 Mar 2020 16:23:46 +0100 Subject: [PATCH 172/262] fix(compiler): handle type references to namespaced symbols correctly (#36106) When the compiler needs to convert a type reference to a value expression, it may encounter a type that refers to a namespaced symbol. Such namespaces need to be handled specially as there's various forms available. Consider a namespace named "ns": 1. One can refer to a namespace by itself: `ns`. A namespace is only allowed to be used in a type position if it has been merged with a class, but even if this is the case it may not be possible to convert that type into a value expression depending on the import form. More on this later (case a below) 2. One can refer to a type within the namespace: `ns.Foo`. An import needs to be generated to `ns`, from which the `Foo` property can then be read. 3. One can refer to a type in a nested namespace within `ns`: `ns.Foo.Bar` and possibly even deeper nested. The value representation is similar to case 2, but includes additional property accesses. The exact strategy of how to deal with these cases depends on the type of import used. There's two flavors available: a. A namespaced import like `import * as ns from 'ns';` that creates a local namespace that is irrelevant to the import that needs to be generated (as said import would be used instead of the original import). If the local namespace "ns" itself is referred to in a type position, it is invalid to convert it into a value expression. Some JavaScript libraries publish a value as default export using `export = MyClass;` syntax, however it is illegal to refer to that value using "ns". Consequently, such usage in a type position *must* be accompanied by an `@Inject` decorator to provide an explicit token. b. An explicit namespace declaration within a module, that can be imported using a named import like `import {ns} from 'ns';` where the "ns" module declares a namespace using `declare namespace ns {}`. In this case, it's the namespace itself that needs to be imported, after which any qualified references into the namespace are converted into property accesses. Before this change, support for namespaces in the type-to-value conversion was limited and only worked correctly for a single qualified name using a namespace import (case 2a). All other cases were either producing incorrect code or would crash the compiler (case 1a). Crashing the compiler is not desirable as it does not indicate where the issue is. Moreover, the result of a type-to-value conversion is irrelevant when an explicit injection token is provided using `@Inject`, so referring to a namespace in a type position (case 1) could still be valid. This commit introduces logic to the type-to-value conversion to be able to properly deal with all type references to namespaced symbols. Fixes #36006 Resolves FW-1995 PR Close #36106 --- .../ngcc/src/host/esm2015_host.ts | 3 +- packages/compiler-cli/ngcc/test/host/util.ts | 2 +- .../src/ngtsc/annotations/src/util.ts | 16 +- .../src/ngtsc/reflection/src/host.ts | 18 +- .../src/ngtsc/reflection/src/type_to_value.ts | 168 ++++++++++-------- .../src/ngtsc/reflection/test/ts_host_spec.ts | 2 +- .../compiler-cli/test/ngtsc/ngtsc_spec.ts | 134 ++++++++++++++ 7 files changed, 263 insertions(+), 80 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts index 4cb8b5087011b..23fdfeacb0952 100644 --- a/packages/compiler-cli/ngcc/src/host/esm2015_host.ts +++ b/packages/compiler-cli/ngcc/src/host/esm2015_host.ts @@ -1436,7 +1436,8 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N local: false, valueDeclaration: decl.node, moduleName: decl.viaModule, - name: decl.node.name.text, + importedName: decl.node.name.text, + nestedPath: null, }; } else { typeValueReference = { diff --git a/packages/compiler-cli/ngcc/test/host/util.ts b/packages/compiler-cli/ngcc/test/host/util.ts index 1214e90cf4246..f461a85a040b4 100644 --- a/packages/compiler-cli/ngcc/test/host/util.ts +++ b/packages/compiler-cli/ngcc/test/host/util.ts @@ -32,7 +32,7 @@ export function expectTypeValueReferencesForParameters( } } else if (param.typeValueReference !== null) { expect(param.typeValueReference.moduleName).toBe(fromModule!); - expect(param.typeValueReference.name).toBe(expected); + expect(param.typeValueReference.importedName).toBe(expected); } } }); diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts index 78cd8d995baae..d160bdf2b562c 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/util.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/util.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Expression, ExternalExpr, LiteralExpr, ParseLocation, ParseSourceFile, ParseSourceSpan, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler'; +import {Expression, ExternalExpr, LiteralExpr, ParseLocation, ParseSourceFile, ParseSourceSpan, R3DependencyMetadata, R3Reference, R3ResolvedDependencyType, ReadPropExpr, WrappedNodeExpr} from '@angular/compiler'; import * as ts from 'typescript'; import {ErrorCode, FatalDiagnosticError, makeDiagnostic} from '../../diagnostics'; @@ -138,7 +138,19 @@ export function valueReferenceToExpression( return new WrappedNodeExpr(valueRef.expression); } else { // TODO(alxhub): this cast is necessary because the g3 typescript version doesn't narrow here. - return new ExternalExpr(valueRef as {moduleName: string, name: string}); + const ref = valueRef as { + moduleName: string; + importedName: string; + nestedPath: string[]|null; + }; + let importExpr: Expression = + new ExternalExpr({moduleName: ref.moduleName, name: ref.importedName}); + if (ref.nestedPath !== null) { + for (const property of ref.nestedPath) { + importExpr = new ReadPropExpr(importExpr, property); + } + } + return importExpr; } } diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/host.ts b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts index 6a5940d93c997..55cff19104355 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/host.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/host.ts @@ -243,8 +243,24 @@ export type TypeValueReference = { local: true; expression: ts.Expression; defaultImportStatement: ts.ImportDeclaration | null; }|{ local: false; - name: string; + + /** + * The module specifier from which the `importedName` symbol should be imported. + */ moduleName: string; + + /** + * The name of the top-level symbol that is imported from `moduleName`. If `nestedPath` is also + * present, a nested object is being referenced from the top-level symbol. + */ + importedName: string; + + /** + * If present, represents the symbol names that are referenced from the top-level import. + * When `null` or empty, the `importedName` itself is the symbol being referenced. + */ + nestedPath: string[]|null; + valueDeclaration: ts.Declaration; }; diff --git a/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts b/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts index ca930904d0535..4b1ecb5f68e3f 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts @@ -42,31 +42,76 @@ export function typeToValue( // Look at the local `ts.Symbol`'s declarations and see if it comes from an import // statement. If so, extract the module specifier and the name of the imported type. const firstDecl = local.declarations && local.declarations[0]; + if (firstDecl !== undefined) { + if (ts.isImportClause(firstDecl) && firstDecl.name !== undefined) { + // This is a default import. + // import Foo from 'foo'; - if (firstDecl && ts.isImportClause(firstDecl) && firstDecl.name !== undefined) { - // This is a default import. - return { - local: true, - // Copying the name here ensures the generated references will be correctly transformed along - // with the import. - expression: ts.updateIdentifier(firstDecl.name), - defaultImportStatement: firstDecl.parent, - }; - } else if (firstDecl && isImportSource(firstDecl)) { - const origin = extractModuleAndNameFromImport(firstDecl, symbols.importName); - return {local: false, valueDeclaration: decl.valueDeclaration, ...origin}; - } else { - const expression = typeNodeToValueExpr(typeNode); - if (expression !== null) { return { local: true, - expression, - defaultImportStatement: null, + // Copying the name here ensures the generated references will be correctly transformed + // along with the import. + expression: ts.updateIdentifier(firstDecl.name), + defaultImportStatement: firstDecl.parent, + }; + } else if (ts.isImportSpecifier(firstDecl)) { + // The symbol was imported by name + // import {Foo} from 'foo'; + // or + // import {Foo as Bar} from 'foo'; + + // Determine the name to import (`Foo`) from the import specifier, as the symbol names of + // the imported type could refer to a local alias (like `Bar` in the example above). + const importedName = (firstDecl.propertyName || firstDecl.name).text; + + // The first symbol name refers to the local name, which is replaced by `importedName` above. + // Any remaining symbol names make up the complete path to the value. + const [_localName, ...nestedPath] = symbols.symbolNames; + + const moduleName = extractModuleName(firstDecl.parent.parent.parent); + return { + local: false, + valueDeclaration: decl.valueDeclaration, + moduleName, + importedName, + nestedPath + }; + } else if (ts.isNamespaceImport(firstDecl)) { + // The import is a namespace import + // import * as Foo from 'foo'; + + if (symbols.symbolNames.length === 1) { + // The type refers to the namespace itself, which cannot be represented as a value. + return null; + } + + // The first symbol name refers to the local name of the namespace, which is is discarded + // as a new namespace import will be generated. This is followed by the symbol name that needs + // to be imported and any remaining names that constitute the complete path to the value. + const [_ns, importedName, ...nestedPath] = symbols.symbolNames; + + const moduleName = extractModuleName(firstDecl.parent.parent); + return { + local: false, + valueDeclaration: decl.valueDeclaration, + moduleName, + importedName, + nestedPath }; - } else { - return null; } } + + // If the type is not imported, the type reference can be converted into an expression as is. + const expression = typeNodeToValueExpr(typeNode); + if (expression !== null) { + return { + local: true, + expression, + defaultImportStatement: null, + }; + } else { + return null; + } } /** @@ -88,14 +133,14 @@ export function typeNodeToValueExpr(node: ts.TypeNode): ts.Expression|null { * * In the event that the `TypeReference` refers to a locally declared symbol, these will be the * same. If the `TypeReference` refers to an imported symbol, then `decl` will be the fully resolved - * `ts.Symbol` of the referenced symbol. `local` will be the `ts.Symbol` of the `ts.Identifer` which - * points to the import statement by which the symbol was imported. + * `ts.Symbol` of the referenced symbol. `local` will be the `ts.Symbol` of the `ts.Identifier` + * which points to the import statement by which the symbol was imported. * - * In the event `typeRef` refers to a default import, an `importName` will also be returned to - * give the identifier name within the current file by which the import is known. + * All symbol names that make up the type reference are returned left-to-right into the + * `symbolNames` array, which is guaranteed to include at least one entry. */ function resolveTypeSymbols(typeRef: ts.TypeReferenceNode, checker: ts.TypeChecker): - {local: ts.Symbol, decl: ts.Symbol, importName: string|null}|null { + {local: ts.Symbol, decl: ts.Symbol, symbolNames: string[]}|null { const typeName = typeRef.typeName; // typeRefSymbol is the ts.Symbol of the entire type reference. const typeRefSymbol: ts.Symbol|undefined = checker.getSymbolAtLocation(typeName); @@ -103,32 +148,36 @@ function resolveTypeSymbols(typeRef: ts.TypeReferenceNode, checker: ts.TypeCheck return null; } - // local is the ts.Symbol for the local ts.Identifier for the type. + // `local` is the `ts.Symbol` for the local `ts.Identifier` for the type. // If the type is actually locally declared or is imported by name, for example: // import {Foo} from './foo'; - // then it'll be the same as top. If the type is imported via a namespace import, for example: + // then it'll be the same as `typeRefSymbol`. + // + // If the type is imported via a namespace import, for example: // import * as foo from './foo'; // and then referenced as: // constructor(f: foo.Foo) - // then local will be the ts.Symbol of `foo`, whereas top will be the ts.Symbol of `foo.Foo`. - // This allows tracking of the import behind whatever type reference exists. + // then `local` will be the `ts.Symbol` of `foo`, whereas `typeRefSymbol` will be the `ts.Symbol` + // of `foo.Foo`. This allows tracking of the import behind whatever type reference exists. let local = typeRefSymbol; - let importName: string|null = null; - // TODO(alxhub): this is technically not correct. The user could have any import type with any - // amount of qualification following the imported type: - // - // import * as foo from 'foo' - // constructor(inject: foo.X.Y.Z) - // - // What we really want is the ability to express the arbitrary operation of `.X.Y.Z` on top of - // whatever import we generate for 'foo'. This logic is sufficient for now, though. - if (ts.isQualifiedName(typeName) && ts.isIdentifier(typeName.left) && - ts.isIdentifier(typeName.right)) { - const localTmp = checker.getSymbolAtLocation(typeName.left); + // Destructure a name like `foo.X.Y.Z` as follows: + // - in `leftMost`, the `ts.Identifier` of the left-most name (`foo`) in the qualified name. + // This identifier is used to resolve the `ts.Symbol` for `local`. + // - in `symbolNames`, all names involved in the qualified path, or a single symbol name if the + // type is not qualified. + let leftMost = typeName; + const symbolNames: string[] = []; + while (ts.isQualifiedName(leftMost)) { + symbolNames.unshift(leftMost.right.text); + leftMost = leftMost.left; + } + symbolNames.unshift(leftMost.text); + + if (leftMost !== typeName) { + const localTmp = checker.getSymbolAtLocation(leftMost); if (localTmp !== undefined) { local = localTmp; - importName = typeName.right.text; } } @@ -137,7 +186,7 @@ function resolveTypeSymbols(typeRef: ts.TypeReferenceNode, checker: ts.TypeCheck if (typeRefSymbol.flags & ts.SymbolFlags.Alias) { decl = checker.getAliasedSymbol(typeRefSymbol); } - return {local, decl, importName}; + return {local, decl, symbolNames}; } function entityNameToValue(node: ts.EntityName): ts.Expression|null { @@ -151,38 +200,9 @@ function entityNameToValue(node: ts.EntityName): ts.Expression|null { } } -function isImportSource(node: ts.Declaration): node is(ts.ImportSpecifier | ts.NamespaceImport) { - return ts.isImportSpecifier(node) || ts.isNamespaceImport(node); -} - -function extractModuleAndNameFromImport( - node: ts.ImportSpecifier|ts.NamespaceImport|ts.ImportClause, - localName: string|null): {name: string, moduleName: string} { - let name: string; - let moduleSpecifier: ts.Expression; - switch (node.kind) { - case ts.SyntaxKind.ImportSpecifier: - // The symbol was imported by name, in a ts.ImportSpecifier. - name = (node.propertyName || node.name).text; - moduleSpecifier = node.parent.parent.parent.moduleSpecifier; - break; - case ts.SyntaxKind.NamespaceImport: - // The symbol was imported via a namespace import. In this case, the name to use when - // importing it was extracted by resolveTypeSymbols. - if (localName === null) { - // resolveTypeSymbols() should have extracted the correct local name for the import. - throw new Error(`Debug failure: no local name provided for NamespaceImport`); - } - name = localName; - moduleSpecifier = node.parent.parent.moduleSpecifier; - break; - default: - throw new Error(`Unreachable: ${ts.SyntaxKind[(node as ts.Node).kind]}`); - } - - if (!ts.isStringLiteral(moduleSpecifier)) { +function extractModuleName(node: ts.ImportDeclaration): string { + if (!ts.isStringLiteral(node.moduleSpecifier)) { throw new Error('not a module specifier'); } - const moduleName = moduleSpecifier.text; - return {moduleName, name}; + return node.moduleSpecifier.text; } diff --git a/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts index 30eb1c551a235..0c072f24512e6 100644 --- a/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts +++ b/packages/compiler-cli/src/ngtsc/reflection/test/ts_host_spec.ts @@ -464,7 +464,7 @@ runInEachFileSystem(() => { expect(argExpressionToString(param.typeValueReference.expression)).toEqual(type); } else if (!param.typeValueReference.local && typeof type !== 'string') { expect(param.typeValueReference.moduleName).toEqual(type.moduleName); - expect(param.typeValueReference.name).toEqual(type.name); + expect(param.typeValueReference.importedName).toEqual(type.name); } else { return fail(`Mismatch between typeValueReference and expected type: ${param.name} / ${ param.typeValueReference.local}`); diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts index 288d9c4c04340..53fff99df4f09 100644 --- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts +++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts @@ -3880,6 +3880,140 @@ runInEachFileSystem(os => { expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.Other')); }); + describe('namespace support', () => { + it('should generate correct imports for type references to namespaced symbols using a namespace import', + () => { + env.write(`/node_modules/ns/index.d.ts`, ` + export declare class Zero {} + export declare namespace one { + export declare class One {} + } + export declare namespace one.two { + export declare class Two {} + } + `); + env.write(`test.ts`, ` + import {Inject, Injectable, InjectionToken} from '@angular/core'; + import * as ns from 'ns'; + + @Injectable() + export class MyService { + constructor( + zero: ns.Zero, + one: ns.one.One, + two: ns.one.two.Two, + ) {} + } + `); + + env.driveMain(); + const jsContents = trim(env.getContents('test.js')); + expect(jsContents).toContain(`import * as i1 from "ns";`); + expect(jsContents).toContain('i0.ɵɵinject(i1.Zero)'); + expect(jsContents).toContain('i0.ɵɵinject(i1.one.One)'); + expect(jsContents).toContain('i0.ɵɵinject(i1.one.two.Two)'); + expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.Zero')); + expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.one.One')); + expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.one.two.Two')); + }); + + it('should generate correct imports for type references to namespaced symbols using named imports', + () => { + env.write(`/node_modules/ns/index.d.ts`, ` + export namespace ns { + export declare class Zero {} + export declare namespace one { + export declare class One {} + } + export declare namespace one.two { + export declare class Two {} + } + } + `); + env.write(`test.ts`, ` + import {Inject, Injectable, InjectionToken} from '@angular/core'; + import {ns} from 'ns'; + import {ns as alias} from 'ns'; + + @Injectable() + export class MyService { + constructor( + zero: ns.Zero, + one: ns.one.One, + two: ns.one.two.Two, + aliasedZero: alias.Zero, + aliasedOne: alias.one.One, + aliasedTwo: alias.one.two.Two, + ) {} + } + `); + + env.driveMain(); + const jsContents = trim(env.getContents('test.js')); + expect(jsContents).toContain(`import * as i1 from "ns";`); + expect(jsContents) + .toContain( + 'i0.ɵɵinject(i1.ns.Zero), ' + + 'i0.ɵɵinject(i1.ns.one.One), ' + + 'i0.ɵɵinject(i1.ns.one.two.Two), ' + + 'i0.ɵɵinject(i1.ns.Zero), ' + + 'i0.ɵɵinject(i1.ns.one.One), ' + + 'i0.ɵɵinject(i1.ns.one.two.Two)'); + expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.ns.Zero')); + expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.ns.one.One')); + expect(jsContents).toMatch(setClassMetadataRegExp('type: i1.ns.one.two.Two')); + }); + + it('should not error for a namespace import as parameter type when @Inject is used', () => { + env.tsconfig({'strictInjectionParameters': true}); + env.write(`/node_modules/foo/index.d.ts`, ` + export = Foo; + declare class Foo {} + declare namespace Foo {} + `); + env.write(`test.ts`, ` + import {Inject, Injectable, InjectionToken} from '@angular/core'; + import * as Foo from 'foo'; + + export const TOKEN = new InjectionToken<Foo>('Foo'); + + @Injectable() + export class MyService { + constructor(@Inject(TOKEN) foo: Foo) {} + } + `); + + env.driveMain(); + const jsContents = trim(env.getContents('test.js')); + expect(jsContents).toContain('i0.ɵɵinject(TOKEN)'); + expect(jsContents).toMatch(setClassMetadataRegExp('type: undefined')); + }); + + it('should error for a namespace import as parameter type used for DI', () => { + env.tsconfig({'strictInjectionParameters': true}); + env.write(`/node_modules/foo/index.d.ts`, ` + export = Foo; + declare class Foo {} + declare namespace Foo {} + `); + env.write(`test.ts`, ` + import {Injectable} from '@angular/core'; + import * as Foo from 'foo'; + + @Injectable() + export class MyService { + constructor(foo: Foo) {} + } + `); + + const diags = env.driveDiagnostics(); + expect(diags.length).toBe(1); + expect(diags[0].messageText) + .toBe( + `No suitable injection token for parameter 'foo' of class 'MyService'.\nFound Foo`); + }); + }); + it('should use `undefined` in setClassMetadata if types can\'t be represented as values', () => { env.write(`types.ts`, ` From a185efbd603d6173ea186f3f2444e4fb628a3a8a Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Tue, 7 Apr 2020 17:47:46 +0100 Subject: [PATCH 173/262] perf(ngcc): read dependencies from entry-point manifest (#36486) Previously, even if an entry-point did not need to be processed, ngcc would always parse the files of the entry-point to compute its dependencies. This can take a lot of time for large node_modules. Now these dependencies are cached in the entry-point manifest, and read from there rather than computing them every time. See https://github.com/angular/angular/issues/36414\#issuecomment-608401834 FW-2047 PR Close #36486 --- .../ngcc/src/dependencies/dependency_host.ts | 6 + .../src/dependencies/dependency_resolver.ts | 39 +++---- .../directory_walker_entry_point_finder.ts | 25 +++-- .../targeted_entry_point_finder.ts | 11 +- .../ngcc/src/packages/entry_point_manifest.ts | 40 +++++-- .../dependencies/dependency_resolver_spec.ts | 58 ++++++---- .../ngcc/test/integration/ngcc_spec.ts | 7 +- .../packages/entry_point_manifest_spec.ts | 106 ++++++++++++++---- 8 files changed, 203 insertions(+), 89 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/dependencies/dependency_host.ts b/packages/compiler-cli/ngcc/src/dependencies/dependency_host.ts index d71beca388393..e086d71772b6c 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/dependency_host.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/dependency_host.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {AbsoluteFsPath, FileSystem, PathSegment} from '../../../src/ngtsc/file_system'; +import {EntryPoint} from '../packages/entry_point'; import {resolveFileWithPostfixes} from '../utils'; import {ModuleResolver} from './module_resolver'; @@ -21,6 +22,11 @@ export interface DependencyInfo { deepImports: Set<AbsoluteFsPath>; } +export interface EntryPointWithDependencies { + entryPoint: EntryPoint; + depInfo: DependencyInfo; +} + export function createDependencyInfo(): DependencyInfo { return {dependencies: new Set(), missing: new Set(), deepImports: new Set()}; } diff --git a/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts b/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts index 9570ddcf4ab9e..06e544791d098 100644 --- a/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts +++ b/packages/compiler-cli/ngcc/src/dependencies/dependency_resolver.ts @@ -14,7 +14,7 @@ import {NgccConfiguration} from '../packages/configuration'; import {EntryPoint, EntryPointFormat, getEntryPointFormat, SUPPORTED_FORMAT_PROPERTIES} from '../packages/entry_point'; import {PartiallyOrderedList} from '../utils'; -import {createDependencyInfo, DependencyHost, DependencyInfo} from './dependency_host'; +import {createDependencyInfo, DependencyHost, EntryPointWithDependencies} from './dependency_host'; const builtinNodeJsModules = new Set<string>(require('module').builtinModules); @@ -94,7 +94,7 @@ export class DependencyResolver { * @param target If provided, only return entry-points depended on by this entry-point. * @returns the result of sorting the entry points by dependency. */ - sortEntryPointsByDependency(entryPoints: EntryPoint[], target?: EntryPoint): + sortEntryPointsByDependency(entryPoints: EntryPointWithDependencies[], target?: EntryPoint): SortedEntryPointsInfo { const {invalidEntryPoints, ignoredDependencies, graph} = this.computeDependencyGraph(entryPoints); @@ -120,18 +120,21 @@ export class DependencyResolver { }; } - getEntryPointDependencies(entryPoint: EntryPoint): DependencyInfo { - const formatInfo = this.getEntryPointFormatInfo(entryPoint); - const host = this.hosts[formatInfo.format]; - if (!host) { - throw new Error( - `Could not find a suitable format for computing dependencies of entry-point: '${ - entryPoint.path}'.`); + getEntryPointWithDependencies(entryPoint: EntryPoint): EntryPointWithDependencies { + const dependencies = createDependencyInfo(); + if (entryPoint.compiledByAngular) { + // Only bother to compute dependencies of entry-points that have been compiled by Angular + const formatInfo = this.getEntryPointFormatInfo(entryPoint); + const host = this.hosts[formatInfo.format]; + if (!host) { + throw new Error( + `Could not find a suitable format for computing dependencies of entry-point: '${ + entryPoint.path}'.`); + } + host.collectDependencies(formatInfo.path, dependencies); + this.typingsHost.collectDependencies(entryPoint.typings, dependencies); } - const depInfo = createDependencyInfo(); - host.collectDependencies(formatInfo.path, depInfo); - this.typingsHost.collectDependencies(entryPoint.typings, depInfo); - return depInfo; + return {entryPoint, depInfo: dependencies}; } /** @@ -140,20 +143,18 @@ export class DependencyResolver { * The graph only holds entry-points that ngcc cares about and whose dependencies * (direct and transitive) all exist. */ - private computeDependencyGraph(entryPoints: EntryPoint[]): DependencyGraph { + private computeDependencyGraph(entryPoints: EntryPointWithDependencies[]): DependencyGraph { const invalidEntryPoints: InvalidEntryPoint[] = []; const ignoredDependencies: IgnoredDependency[] = []; const graph = new DepGraph<EntryPoint>(); - const angularEntryPoints = entryPoints.filter(entryPoint => entryPoint.compiledByAngular); + const angularEntryPoints = entryPoints.filter(e => e.entryPoint.compiledByAngular); // Add the Angular compiled entry points to the graph as nodes - angularEntryPoints.forEach(entryPoint => graph.addNode(entryPoint.path, entryPoint)); + angularEntryPoints.forEach(e => graph.addNode(e.entryPoint.path, e.entryPoint)); // Now add the dependencies between them - angularEntryPoints.forEach(entryPoint => { - const {dependencies, missing, deepImports} = this.getEntryPointDependencies(entryPoint); - + angularEntryPoints.forEach(({entryPoint, depInfo: {dependencies, missing, deepImports}}) => { const missingDependencies = Array.from(missing).filter(dep => !builtinNodeJsModules.has(dep)); if (missingDependencies.length > 0 && !entryPoint.ignoreMissingDependencies) { diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts index 4e238a576e285..c4b7843231406 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/directory_walker_entry_point_finder.ts @@ -6,10 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ import {AbsoluteFsPath, FileSystem, PathSegment} from '../../../src/ngtsc/file_system'; +import {EntryPointWithDependencies} from '../dependencies/dependency_host'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; import {NgccConfiguration} from '../packages/configuration'; -import {EntryPoint, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from '../packages/entry_point'; +import {getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from '../packages/entry_point'; import {EntryPointManifest} from '../packages/entry_point_manifest'; import {PathMappings} from '../utils'; import {NGCC_DIRECTORY} from '../writing/new_entry_point_file_writer'; @@ -32,11 +33,11 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { * all package entry-points. */ findEntryPoints(): SortedEntryPointsInfo { - const unsortedEntryPoints: EntryPoint[] = []; + const unsortedEntryPoints: EntryPointWithDependencies[] = []; for (const basePath of this.basePaths) { const entryPoints = this.entryPointManifest.readEntryPointsUsingManifest(basePath) || this.walkBasePathForPackages(basePath); - unsortedEntryPoints.push(...entryPoints); + entryPoints.forEach(e => unsortedEntryPoints.push(e)); } return this.resolver.sortEntryPointsByDependency(unsortedEntryPoints); } @@ -47,10 +48,10 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { * @param basePath The path at which to start the search * @returns an array of `EntryPoint`s that were found within `basePath`. */ - walkBasePathForPackages(basePath: AbsoluteFsPath): EntryPoint[] { + walkBasePathForPackages(basePath: AbsoluteFsPath): EntryPointWithDependencies[] { this.logger.debug( `No manifest found for ${basePath} so walking the directories for entry-points.`); - const entryPoints: EntryPoint[] = trackDuration( + const entryPoints = trackDuration( () => this.walkDirectoryForPackages(basePath), duration => this.logger.debug(`Walking ${basePath} for entry-points took ${duration}s.`)); this.entryPointManifest.writeEntryPointManifest(basePath, entryPoints); @@ -64,7 +65,7 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { * @param sourceDirectory An absolute path to the root directory where searching begins. * @returns an array of `EntryPoint`s that were found within `sourceDirectory`. */ - walkDirectoryForPackages(sourceDirectory: AbsoluteFsPath): EntryPoint[] { + walkDirectoryForPackages(sourceDirectory: AbsoluteFsPath): EntryPointWithDependencies[] { // Try to get a primary entry point from this directory const primaryEntryPoint = getEntryPointInfo(this.fs, this.config, this.logger, sourceDirectory, sourceDirectory); @@ -76,15 +77,15 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { return []; } - const entryPoints: EntryPoint[] = []; + const entryPoints: EntryPointWithDependencies[] = []; if (primaryEntryPoint !== NO_ENTRY_POINT) { - entryPoints.push(primaryEntryPoint); + entryPoints.push(this.resolver.getEntryPointWithDependencies(primaryEntryPoint)); this.collectSecondaryEntryPoints( entryPoints, sourceDirectory, sourceDirectory, this.fs.readdir(sourceDirectory)); // Also check for any nested node_modules in this package but only if at least one of the // entry-points was compiled by Angular. - if (entryPoints.some(e => e.compiledByAngular)) { + if (entryPoints.some(e => e.entryPoint.compiledByAngular)) { const nestedNodeModulesPath = this.fs.join(sourceDirectory, 'node_modules'); if (this.fs.exists(nestedNodeModulesPath)) { entryPoints.push(...this.walkDirectoryForPackages(nestedNodeModulesPath)); @@ -125,8 +126,8 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { * @param paths The paths contained in the current `directory`. */ private collectSecondaryEntryPoints( - entryPoints: EntryPoint[], packagePath: AbsoluteFsPath, directory: AbsoluteFsPath, - paths: PathSegment[]): void { + entryPoints: EntryPointWithDependencies[], packagePath: AbsoluteFsPath, + directory: AbsoluteFsPath, paths: PathSegment[]): void { for (const path of paths) { if (isIgnorablePath(path)) { // Ignore hidden files, node_modules and ngcc directory @@ -153,7 +154,7 @@ export class DirectoryWalkerEntryPointFinder implements EntryPointFinder { const subEntryPoint = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, possibleEntryPointPath); if (subEntryPoint !== NO_ENTRY_POINT && subEntryPoint !== INCOMPATIBLE_ENTRY_POINT) { - entryPoints.push(subEntryPoint); + entryPoints.push(this.resolver.getEntryPointWithDependencies(subEntryPoint)); isEntryPoint = true; } diff --git a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts index 3258561805a3c..0a5ef883ebdeb 100644 --- a/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts +++ b/packages/compiler-cli/ngcc/src/entry_point_finder/targeted_entry_point_finder.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {AbsoluteFsPath, FileSystem, join, PathSegment, relative, relativeFrom} from '../../../src/ngtsc/file_system'; +import {EntryPointWithDependencies} from '../dependencies/dependency_host'; import {DependencyResolver, SortedEntryPointsInfo} from '../dependencies/dependency_resolver'; import {Logger} from '../logging/logger'; import {hasBeenProcessed} from '../packages/build_marker'; @@ -25,7 +26,7 @@ import {getBasePaths} from './utils'; */ export class TargetedEntryPointFinder implements EntryPointFinder { private unprocessedPaths: AbsoluteFsPath[] = []; - private unsortedEntryPoints = new Map<AbsoluteFsPath, EntryPoint>(); + private unsortedEntryPoints = new Map<AbsoluteFsPath, EntryPointWithDependencies>(); private basePaths = getBasePaths(this.logger, this.basePath, this.pathMappings); constructor( @@ -40,7 +41,7 @@ export class TargetedEntryPointFinder implements EntryPointFinder { } const targetEntryPoint = this.unsortedEntryPoints.get(this.targetPath); const entryPoints = this.resolver.sortEntryPointsByDependency( - Array.from(this.unsortedEntryPoints.values()), targetEntryPoint); + Array.from(this.unsortedEntryPoints.values()), targetEntryPoint?.entryPoint); const invalidTarget = entryPoints.invalidEntryPoints.find(i => i.entryPoint.path === this.targetPath); @@ -82,9 +83,9 @@ export class TargetedEntryPointFinder implements EntryPointFinder { if (entryPoint === null || !entryPoint.compiledByAngular) { return; } - this.unsortedEntryPoints.set(entryPoint.path, entryPoint); - const deps = this.resolver.getEntryPointDependencies(entryPoint); - deps.dependencies.forEach(dep => { + const entryPointWithDeps = this.resolver.getEntryPointWithDependencies(entryPoint); + this.unsortedEntryPoints.set(entryPoint.path, entryPointWithDeps); + entryPointWithDeps.depInfo.dependencies.forEach(dep => { if (!this.unsortedEntryPoints.has(dep)) { this.unprocessedPaths.push(dep); } diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts index 60d78df97e670..30dbf4f255c56 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts @@ -7,12 +7,13 @@ */ import {createHash} from 'crypto'; -import {AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system'; +import {AbsoluteFsPath, FileSystem, PathSegment} from '../../../src/ngtsc/file_system'; +import {EntryPointWithDependencies} from '../dependencies/dependency_host'; import {Logger} from '../logging/logger'; import {NGCC_VERSION} from './build_marker'; import {NgccConfiguration} from './configuration'; -import {EntryPoint, getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from './entry_point'; +import {getEntryPointInfo, INCOMPATIBLE_ENTRY_POINT, NO_ENTRY_POINT} from './entry_point'; /** * Manages reading and writing a manifest file that contains a list of all the entry-points that @@ -40,7 +41,7 @@ export class EntryPointManifest { * @returns an array of entry-point information for all entry-points found below the given * `basePath` or `null` if the manifest was out of date. */ - readEntryPointsUsingManifest(basePath: AbsoluteFsPath): EntryPoint[]|null { + readEntryPointsUsingManifest(basePath: AbsoluteFsPath): EntryPointWithDependencies[]|null { try { if (this.fs.basename(basePath) !== 'node_modules') { return null; @@ -67,8 +68,9 @@ export class EntryPointManifest { basePath} so loading entry-point information directly.`); const startTime = Date.now(); - const entryPoints: EntryPoint[] = []; - for (const [packagePath, entryPointPath] of entryPointPaths) { + const entryPoints: EntryPointWithDependencies[] = []; + for (const [packagePath, entryPointPath, dependencyPaths, missingPaths, deepImportPaths] of + entryPointPaths) { const result = getEntryPointInfo(this.fs, this.config, this.logger, packagePath, entryPointPath); if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { @@ -76,7 +78,14 @@ export class EntryPointManifest { manifestPath} contained an invalid pair of package paths: [${packagePath}, ${ entryPointPath}]`); } else { - entryPoints.push(result); + entryPoints.push({ + entryPoint: result, + depInfo: { + dependencies: new Set(dependencyPaths), + missing: new Set(missingPaths), + deepImports: new Set(deepImportPaths), + } + }); } } const duration = Math.round((Date.now() - startTime) / 100) / 10; @@ -99,7 +108,8 @@ export class EntryPointManifest { * @param basePath The path where the manifest file is to be written. * @param entryPoints A collection of entry-points to record in the manifest. */ - writeEntryPointManifest(basePath: AbsoluteFsPath, entryPoints: EntryPoint[]): void { + writeEntryPointManifest(basePath: AbsoluteFsPath, entryPoints: EntryPointWithDependencies[]): + void { if (this.fs.basename(basePath) !== 'node_modules') { return; } @@ -112,7 +122,14 @@ export class EntryPointManifest { ngccVersion: NGCC_VERSION, configFileHash: this.config.hash, lockFileHash: lockFileHash, - entryPointPaths: entryPoints.map(entryPoint => [entryPoint.package, entryPoint.path]), + entryPointPaths: entryPoints.map( + e => + [e.entryPoint.package, + e.entryPoint.path, + Array.from(e.depInfo.dependencies), + Array.from(e.depInfo.missing), + Array.from(e.depInfo.deepImports), + ]), }; this.fs.writeFile(this.getEntryPointManifestPath(basePath), JSON.stringify(manifest)); } @@ -143,7 +160,7 @@ export class EntryPointManifest { * called. */ export class InvalidatingEntryPointManifest extends EntryPointManifest { - readEntryPointsUsingManifest(basePath: AbsoluteFsPath): EntryPoint[]|null { + readEntryPointsUsingManifest(_basePath: AbsoluteFsPath): EntryPointWithDependencies[]|null { return null; } } @@ -155,5 +172,8 @@ export interface EntryPointManifestFile { ngccVersion: string; configFileHash: string; lockFileHash: string; - entryPointPaths: Array<[AbsoluteFsPath, AbsoluteFsPath]>; + entryPointPaths: Array<[ + AbsoluteFsPath, AbsoluteFsPath, AbsoluteFsPath[], (AbsoluteFsPath | PathSegment)[], + AbsoluteFsPath[] + ]>; } diff --git a/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts b/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts index 0fffdbcf9071f..d418618d191e6 100644 --- a/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts +++ b/packages/compiler-cli/ngcc/test/dependencies/dependency_resolver_spec.ts @@ -10,7 +10,7 @@ import {DepGraph} from 'dependency-graph'; import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem, relativeFrom} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; -import {DependencyInfo} from '../../src/dependencies/dependency_host'; +import {DependencyInfo, EntryPointWithDependencies} from '../../src/dependencies/dependency_host'; import {DependencyResolver, SortedEntryPointsInfo} from '../../src/dependencies/dependency_resolver'; import {DtsDependencyHost} from '../../src/dependencies/dts_dependency_host'; import {EsmDependencyHost} from '../../src/dependencies/esm_dependency_host'; @@ -131,7 +131,8 @@ runInEachFileSystem(() => { .and.callFake(createFakeComputeDependencies(dependencies)); spyOn(dtsHost, 'collectDependencies') .and.callFake(createFakeComputeDependencies(dtsDependencies)); - const result = resolver.sortEntryPointsByDependency([fifth, first, fourth, second, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third])); expect(result.entryPoints).toEqual([fifth, fourth, third, second, first]); }); @@ -144,7 +145,8 @@ runInEachFileSystem(() => { [_('/first/index.d.ts')]: {resolved: [], missing: [_('/missing')]}, [_('/second/sub/index.d.ts')]: {resolved: [], missing: []}, })); - const result = resolver.sortEntryPointsByDependency([first, second]); + const result = + resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [first, second])); expect(result.entryPoints).toEqual([second]); expect(result.invalidEntryPoints).toEqual([ {entryPoint: first, missingDependencies: [_('/missing')]}, @@ -163,7 +165,8 @@ runInEachFileSystem(() => { [_('/third/index.d.ts')]: {resolved: [], missing: []}, })); // Note that we will process `first` before `second`, which has the missing dependency. - const result = resolver.sortEntryPointsByDependency([first, second, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [first, second, third])); expect(result.entryPoints).toEqual([third]); expect(result.invalidEntryPoints).toEqual([ {entryPoint: second, missingDependencies: [_('/missing')]}, @@ -183,7 +186,8 @@ runInEachFileSystem(() => { [_('/third/index.d.ts')]: {resolved: [], missing: []}, })); // Note that we will process `first` after `second`, which has the missing dependency. - const result = resolver.sortEntryPointsByDependency([second, first, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [second, first, third])); expect(result.entryPoints).toEqual([third]); expect(result.invalidEntryPoints).toEqual([ {entryPoint: second, missingDependencies: [_('/missing')]}, @@ -202,7 +206,8 @@ runInEachFileSystem(() => { [_('/sixth/index.d.ts')]: {resolved: [], missing: [_('/missing')]}, })); // Note that we will process `first` after `second`, which has the missing dependency. - const result = resolver.sortEntryPointsByDependency([sixthIgnoreMissing, first]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [sixthIgnoreMissing, first])); expect(result.entryPoints).toEqual([sixthIgnoreMissing, first]); expect(result.invalidEntryPoints).toEqual([]); }); @@ -218,7 +223,8 @@ runInEachFileSystem(() => { [_('/second/sub/index.d.ts')]: {resolved: [first.path], missing: []}, [_('/sixth/index.d.ts')]: {resolved: [second.path], missing: []}, })); - const result = resolver.sortEntryPointsByDependency([first, second, sixthIgnoreMissing]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [first, second, sixthIgnoreMissing])); // sixth has no missing dependencies, but it has _invalid_ dependencies, so it's not // compiled. expect(result.entryPoints).toEqual([]); @@ -235,7 +241,8 @@ runInEachFileSystem(() => { [_('/second/sub/index.d.ts')]: {resolved: [], missing: [_('/missing2')]}, [_('/third/index.d.ts')]: {resolved: [first.path, second.path], missing: []}, })); - const result = resolver.sortEntryPointsByDependency([first, second, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [first, second, third])); expect(result.entryPoints).toEqual([]); expect(result.invalidEntryPoints).toEqual([ {entryPoint: first, missingDependencies: [_('/missing1')]}, @@ -251,7 +258,8 @@ runInEachFileSystem(() => { spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({ [_('/first/index.d.ts')]: {resolved: [], missing: []}, })); - const result = resolver.sortEntryPointsByDependency([first]); + const result = + resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [first])); expect(result.entryPoints).toEqual([first]); expect(logger.logs.warn).toEqual([[ `Entry point 'first' contains deep imports into '${ @@ -290,7 +298,8 @@ runInEachFileSystem(() => { typings: _('/project/node_modules/test-package/index.d.ts'), } as EntryPoint; - const result = resolver.sortEntryPointsByDependency([testEntryPoint]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [testEntryPoint])); expect(result.entryPoints).toEqual([testEntryPoint]); expect(logger.logs.warn).toEqual([[ `Entry point 'test-package' contains deep imports into '${ @@ -299,14 +308,15 @@ runInEachFileSystem(() => { }); it('should error if the entry point does not have a suitable format', () => { - expect(() => resolver.sortEntryPointsByDependency([ + expect(() => resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [ {path: '/first', packageJson: {}, compiledByAngular: true} as EntryPoint - ])).toThrowError(`There is no appropriate source code format in '/first' entry-point.`); + ]))).toThrowError(`There is no appropriate source code format in '/first' entry-point.`); }); it('should error if there is no appropriate DependencyHost for the given formats', () => { resolver = new DependencyResolver(fs, new MockLogger(), config, {esm2015: host}, host); - expect(() => resolver.sortEntryPointsByDependency([first])) + expect( + () => resolver.sortEntryPointsByDependency(getEntryPointsWithDeps(resolver, [first]))) .toThrowError( `Could not find a suitable format for computing dependencies of entry-point: '${ first.path}'.`); @@ -317,7 +327,8 @@ runInEachFileSystem(() => { .and.callFake(createFakeComputeDependencies(dependencies)); spyOn(dtsHost, 'collectDependencies') .and.callFake(createFakeComputeDependencies(dtsDependencies)); - const result = resolver.sortEntryPointsByDependency([fifth, first, fourth, second, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third])); expect(result.ignoredDependencies).toEqual([ {entryPoint: first, dependencyPath: _('/ignored-1')}, {entryPoint: third, dependencyPath: _('/ignored-2')}, @@ -329,7 +340,8 @@ runInEachFileSystem(() => { .and.callFake(createFakeComputeDependencies(dependencies)); spyOn(dtsHost, 'collectDependencies') .and.callFake(createFakeComputeDependencies(dtsDependencies)); - const result = resolver.sortEntryPointsByDependency([fifth, first, fourth, second, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third])); expect(result.graph).toEqual(jasmine.any(DepGraph)); expect(result.graph.size()).toBe(5); @@ -341,7 +353,7 @@ runInEachFileSystem(() => { .and.callFake(createFakeComputeDependencies(dependencies)); spyOn(dtsHost, 'collectDependencies') .and.callFake(createFakeComputeDependencies(dtsDependencies)); - const entryPoints = [fifth, first, fourth, second, third]; + const entryPoints = getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third]); let sorted: SortedEntryPointsInfo; sorted = resolver.sortEntryPointsByDependency(entryPoints, first); @@ -363,7 +375,7 @@ runInEachFileSystem(() => { spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({ [_('/first/index.d.ts')]: {resolved: [], missing: [_('/missing')]}, })); - const entryPoints = [first]; + const entryPoints = getEntryPointsWithDeps(resolver, [first]); let sorted: SortedEntryPointsInfo; sorted = resolver.sortEntryPointsByDependency(entryPoints, first); @@ -379,7 +391,7 @@ runInEachFileSystem(() => { spyOn(dtsHost, 'collectDependencies').and.callFake(createFakeComputeDependencies({ [_('/first/index.d.ts')]: {resolved: [], missing: ['fs']}, })); - const entryPoints = [first]; + const entryPoints = getEntryPointsWithDeps(resolver, [first]); let sorted: SortedEntryPointsInfo; sorted = resolver.sortEntryPointsByDependency(entryPoints, first); @@ -400,7 +412,8 @@ runInEachFileSystem(() => { .and.callFake(createFakeComputeDependencies(dependencies)); spyOn(dtsHost, 'collectDependencies') .and.callFake(createFakeComputeDependencies(dtsDependencies)); - const result = resolver.sortEntryPointsByDependency([fifth, first, fourth, second, third]); + const result = resolver.sortEntryPointsByDependency( + getEntryPointsWithDeps(resolver, [fifth, first, fourth, second, third])); expect(result.entryPoints).toEqual([fifth, fourth, third, second, first]); expect(esm5Host.collectDependencies) @@ -449,7 +462,7 @@ runInEachFileSystem(() => { [_('/second/sub/index.d.ts')]: {resolved: [], missing: [_('/missing2')]}, [_('/third/index.d.ts')]: {resolved: [second.path], missing: []}, })); - const entryPoints = [first, second, third]; + const entryPoints = getEntryPointsWithDeps(resolver, [first, second, third]); const sorted = resolver.sortEntryPointsByDependency(entryPoints); expect(sorted.entryPoints).toEqual([first]); expect(sorted.invalidEntryPoints).toEqual([ @@ -469,6 +482,11 @@ runInEachFileSystem(() => { return {dependencies, missing, deepImports}; }; } + + function getEntryPointsWithDeps( + resolver: DependencyResolver, entryPoints: EntryPoint[]): EntryPointWithDependencies[] { + return entryPoints.map(entryPoint => resolver.getEntryPointWithDependencies(entryPoint)); + } }); }); }); diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index cab8b9852d9a1..e9a8d26e6ef47 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -1107,7 +1107,12 @@ runInEachFileSystem(() => { // had removed earlier. manifest = JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json'))); expect(manifest.entryPointPaths).toContain([ - _('/node_modules/@angular/common'), _('/node_modules/@angular/common/testing') + _('/node_modules/@angular/common'), _('/node_modules/@angular/common/testing'), + [ + _('/node_modules/@angular/core'), _('/node_modules/@angular/common'), + _('/node_modules/rxjs') + ], + [], [] ]); }); }); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts index 12debe0965011..968b0eb1f2bfb 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts @@ -7,12 +7,12 @@ */ import {createHash} from 'crypto'; -import {absoluteFrom, FileSystem, getFileSystem} from '../../../src/ngtsc/file_system'; +import {absoluteFrom, FileSystem, getFileSystem, relativeFrom} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; +import {EntryPointWithDependencies} from '../../src/dependencies/dependency_host'; import {NGCC_VERSION} from '../../src/packages/build_marker'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {EntryPoint} from '../../src/packages/entry_point'; import {EntryPointManifest, EntryPointManifestFile} from '../../src/packages/entry_point_manifest'; import {MockLogger} from '../helpers/mock_logger'; @@ -129,22 +129,48 @@ runInEachFileSystem(() => { ]); manifestFile.entryPointPaths.push([ _Abs('/project/node_modules/some_package'), - _Abs('/project/node_modules/some_package/valid_entry_point') + _Abs('/project/node_modules/some_package/valid_entry_point'), + [ + _Abs('/project/node_modules/other_package_1'), + _Abs('/project/node_modules/other_package_2'), + ], + [ + _Abs('/project/node_modules/missing_1'), + relativeFrom('missing_2'), + ], + [ + _Abs('/project/node_modules/deep/import/path'), + ], ]); fs.writeFile( _Abs('/project/node_modules/__ngcc_entry_points__.json'), JSON.stringify(manifestFile)); const entryPoints = manifest.readEntryPointsUsingManifest(_Abs('/project/node_modules')); expect(entryPoints).toEqual([{ - name: 'some_package/valid_entry_point', - packageJson: jasmine.any(Object), - package: _Abs('/project/node_modules/some_package'), - path: _Abs('/project/node_modules/some_package/valid_entry_point'), - typings: - _Abs('/project/node_modules/some_package/valid_entry_point/valid_entry_point.d.ts'), - compiledByAngular: true, - ignoreMissingDependencies: false, - generateDeepReexports: false, - } as any]); + entryPoint: { + name: 'some_package/valid_entry_point', + packageJson: jasmine.any(Object), + package: _Abs('/project/node_modules/some_package'), + path: _Abs('/project/node_modules/some_package/valid_entry_point'), + typings: + _Abs('/project/node_modules/some_package/valid_entry_point/valid_entry_point.d.ts'), + compiledByAngular: true, + ignoreMissingDependencies: false, + generateDeepReexports: false, + } as any, + depInfo: { + dependencies: new Set([ + _Abs('/project/node_modules/other_package_1'), + _Abs('/project/node_modules/other_package_2'), + ]), + missing: new Set([ + _Abs('/project/node_modules/missing_1'), + relativeFrom('missing_2'), + ]), + deepImports: new Set([ + _Abs('/project/node_modules/deep/import/path'), + ]) + } + }]); }); it('should return null if any of the entry-points are not valid', () => { @@ -152,7 +178,7 @@ runInEachFileSystem(() => { fs.writeFile(_Abs('/project/yarn.lock'), 'LOCK FILE CONTENTS'); manifestFile.entryPointPaths.push([ _Abs('/project/node_modules/some_package'), - _Abs('/project/node_modules/some_package/valid_entry_point') + _Abs('/project/node_modules/some_package/valid_entry_point'), [], [], [] ]); fs.writeFile( _Abs('/project/node_modules/__ngcc_entry_points__.json'), JSON.stringify(manifestFile)); @@ -223,14 +249,36 @@ runInEachFileSystem(() => { it('should write the package path and entry-point path of each entry-point provided', () => { fs.writeFile(_Abs('/project/package-lock.json'), 'LOCK FILE CONTENTS'); - const entryPoint1 = { - package: _Abs('/project/node_modules/package-1/'), - path: _Abs('/project/node_modules/package-1/'), - } as unknown as EntryPoint; - const entryPoint2 = { - package: _Abs('/project/node_modules/package-2/'), - path: _Abs('/project/node_modules/package-2/entry-point'), - } as unknown as EntryPoint; + const entryPoint1: EntryPointWithDependencies = { + entryPoint: { + package: _Abs('/project/node_modules/package-1/'), + path: _Abs('/project/node_modules/package-1/'), + } as any, + depInfo: { + dependencies: new Set([ + _Abs('/project/node_modules/other_package_1'), + _Abs('/project/node_modules/other_package_2'), + ]), + missing: new Set(), + deepImports: new Set() + } + }; + const entryPoint2: EntryPointWithDependencies = { + entryPoint: { + package: _Abs('/project/node_modules/package-2/'), + path: _Abs('/project/node_modules/package-2/entry-point'), + } as any, + depInfo: { + dependencies: new Set(), + missing: new Set([ + _Abs('/project/node_modules/missing_1'), + relativeFrom('missing_2'), + ]), + deepImports: new Set([ + _Abs('/project/node_modules/deep/import/path'), + ]) + } + }; manifest.writeEntryPointManifest(_Abs('/project/node_modules'), [entryPoint1, entryPoint2]); const file: EntryPointManifestFile = JSON.parse(fs.readFile(_Abs('/project/node_modules/__ngcc_entry_points__.json'))); @@ -238,10 +286,24 @@ runInEachFileSystem(() => { [ _Abs('/project/node_modules/package-1/'), _Abs('/project/node_modules/package-1/'), + [ + _Abs('/project/node_modules/other_package_1'), + _Abs('/project/node_modules/other_package_2'), + ], + [], + [], ], [ _Abs('/project/node_modules/package-2/'), _Abs('/project/node_modules/package-2/entry-point'), + [], + [ + _Abs('/project/node_modules/missing_1'), + relativeFrom('missing_2'), + ], + [ + _Abs('/project/node_modules/deep/import/path'), + ], ] ]); }); From ec0ce6005a26779e7e7c1f65ac373ebf02da1efe Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Thu, 9 Apr 2020 14:56:28 +0100 Subject: [PATCH 174/262] perf(ngcc): reduce the size of the entry-point manifest file (#36486) The base path for package and entry-points is known so there is no need to store these in the file. Also this commit avoids storing empty arrays unnecessarily. PR Close #36486 --- .../ngcc/src/packages/entry_point_manifest.ts | 56 +++++++++++++------ .../ngcc/test/integration/ngcc_spec.ts | 10 ++-- .../packages/entry_point_manifest_spec.ts | 10 ++-- 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts index 30dbf4f255c56..9321ad594001c 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point_manifest.ts @@ -69,10 +69,12 @@ export class EntryPointManifest { const startTime = Date.now(); const entryPoints: EntryPointWithDependencies[] = []; - for (const [packagePath, entryPointPath, dependencyPaths, missingPaths, deepImportPaths] of - entryPointPaths) { - const result = - getEntryPointInfo(this.fs, this.config, this.logger, packagePath, entryPointPath); + for (const + [packagePath, entryPointPath, dependencyPaths = [], missingPaths = [], + deepImportPaths = []] of entryPointPaths) { + const result = getEntryPointInfo( + this.fs, this.config, this.logger, this.fs.resolve(basePath, packagePath), + this.fs.resolve(basePath, entryPointPath)); if (result === NO_ENTRY_POINT || result === INCOMPATIBLE_ENTRY_POINT) { throw new Error(`The entry-point manifest at ${ manifestPath} contained an invalid pair of package paths: [${packagePath}, ${ @@ -122,14 +124,27 @@ export class EntryPointManifest { ngccVersion: NGCC_VERSION, configFileHash: this.config.hash, lockFileHash: lockFileHash, - entryPointPaths: entryPoints.map( - e => - [e.entryPoint.package, - e.entryPoint.path, - Array.from(e.depInfo.dependencies), - Array.from(e.depInfo.missing), - Array.from(e.depInfo.deepImports), - ]), + entryPointPaths: entryPoints.map(e => { + const entryPointPaths: EntryPointPaths = [ + this.fs.relative(basePath, e.entryPoint.package), + this.fs.relative(basePath, e.entryPoint.path), + ]; + // Only add depInfo arrays if needed. + if (e.depInfo.dependencies.size > 0) { + entryPointPaths[2] = Array.from(e.depInfo.dependencies); + } else if (e.depInfo.missing.size > 0 || e.depInfo.deepImports.size > 0) { + entryPointPaths[2] = []; + } + if (e.depInfo.missing.size > 0) { + entryPointPaths[3] = Array.from(e.depInfo.missing); + } else if (e.depInfo.deepImports.size > 0) { + entryPointPaths[3] = []; + } + if (e.depInfo.deepImports.size > 0) { + entryPointPaths[4] = Array.from(e.depInfo.deepImports); + } + return entryPointPaths; + }), }; this.fs.writeFile(this.getEntryPointManifestPath(basePath), JSON.stringify(manifest)); } @@ -156,8 +171,8 @@ export class EntryPointManifest { * current manifest file. * * It always returns `null` from the `readEntryPointsUsingManifest()` method, which forces a new - * manifest to be created, which will overwrite the current file when `writeEntryPointManifest()` is - * called. + * manifest to be created, which will overwrite the current file when `writeEntryPointManifest()` + * is called. */ export class InvalidatingEntryPointManifest extends EntryPointManifest { readEntryPointsUsingManifest(_basePath: AbsoluteFsPath): EntryPointWithDependencies[]|null { @@ -165,6 +180,14 @@ export class InvalidatingEntryPointManifest extends EntryPointManifest { } } +export type EntryPointPaths = [ + string, + string, + Array<AbsoluteFsPath>?, + Array<AbsoluteFsPath|PathSegment>?, + Array<AbsoluteFsPath>?, +]; + /** * The JSON format of the manifest file that is written to disk. */ @@ -172,8 +195,5 @@ export interface EntryPointManifestFile { ngccVersion: string; configFileHash: string; lockFileHash: string; - entryPointPaths: Array<[ - AbsoluteFsPath, AbsoluteFsPath, AbsoluteFsPath[], (AbsoluteFsPath | PathSegment)[], - AbsoluteFsPath[] - ]>; + entryPointPaths: EntryPointPaths[]; } diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index e9a8d26e6ef47..a4c6ae2d31e3e 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -1079,7 +1079,7 @@ runInEachFileSystem(() => { // Populate the manifest file mainNgcc( {basePath: '/node_modules', propertiesToConsider: ['esm5'], logger: new MockLogger()}); - // Check that common/testings ES5 was processed + // Check that common/testing ES5 was processed let commonTesting = JSON.parse(fs.readFile(_('/node_modules/@angular/common/testing/package.json'))); expect(hasBeenProcessed(commonTesting, 'esm5')).toBe(true); @@ -1087,8 +1087,8 @@ runInEachFileSystem(() => { // Modify the manifest to test that is has no effect let manifest: EntryPointManifestFile = JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json'))); - manifest.entryPointPaths = manifest.entryPointPaths.filter( - paths => paths[1] !== _('/node_modules/@angular/common/testing')); + manifest.entryPointPaths = + manifest.entryPointPaths.filter(paths => paths[1] !== '@angular/common/testing'); fs.writeFile(_('/node_modules/__ngcc_entry_points__.json'), JSON.stringify(manifest)); // Now run ngcc again ignoring this manifest but trying to process ES2015, which are not yet // processed. @@ -1107,12 +1107,12 @@ runInEachFileSystem(() => { // had removed earlier. manifest = JSON.parse(fs.readFile(_('/node_modules/__ngcc_entry_points__.json'))); expect(manifest.entryPointPaths).toContain([ - _('/node_modules/@angular/common'), _('/node_modules/@angular/common/testing'), + '@angular/common', + '@angular/common/testing', [ _('/node_modules/@angular/core'), _('/node_modules/@angular/common'), _('/node_modules/rxjs') ], - [], [] ]); }); }); diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts index 968b0eb1f2bfb..afed5fe6b134d 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_manifest_spec.ts @@ -284,18 +284,16 @@ runInEachFileSystem(() => { JSON.parse(fs.readFile(_Abs('/project/node_modules/__ngcc_entry_points__.json'))); expect(file.entryPointPaths).toEqual([ [ - _Abs('/project/node_modules/package-1/'), - _Abs('/project/node_modules/package-1/'), + 'package-1', + 'package-1', [ _Abs('/project/node_modules/other_package_1'), _Abs('/project/node_modules/other_package_2'), ], - [], - [], ], [ - _Abs('/project/node_modules/package-2/'), - _Abs('/project/node_modules/package-2/entry-point'), + 'package-2', + 'package-2/entry-point', [], [ _Abs('/project/node_modules/missing_1'), From 3bedfdac9d3ce8583c58eeb5641460c021b720e3 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin <pete@bacondarwin.com> Date: Thu, 9 Apr 2020 16:02:57 +0100 Subject: [PATCH 175/262] perf(ngcc): only load if it is needed (#36486) PR Close #36486 --- packages/compiler-cli/ngcc/src/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index e0565b4c5b865..1f63a029bbbf7 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -44,7 +44,6 @@ import {NgccConfiguration} from './packages/configuration'; import {EntryPoint, EntryPointJsonProperty, EntryPointPackageJson, getEntryPointFormat, SUPPORTED_FORMAT_PROPERTIES} from './packages/entry_point'; import {makeEntryPointBundle} from './packages/entry_point_bundle'; import {EntryPointManifest, InvalidatingEntryPointManifest} from './packages/entry_point_manifest'; -import {Transformer} from './packages/transformer'; import {PathMappings} from './utils'; import {cleanOutdatedPackages} from './writing/cleaning/package_cleaner'; import {FileWriter} from './writing/file_writer'; @@ -315,6 +314,7 @@ export function mainNgcc({ const createCompileFn: CreateCompileFn = onTaskCompleted => { const fileWriter = getFileWriter( fileSystem, logger, pkgJsonUpdater, createNewEntryPointFormats, errorOnFailedEntryPoint); + const {Transformer} = require('./packages/transformer'); const transformer = new Transformer(fileSystem, logger, tsConfig); return (task: Task) => { From 2e4244d521f68dcfd66245ba32c6a1124f6dbaf3 Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Thu, 9 Apr 2020 11:42:19 +0300 Subject: [PATCH 176/262] fix(docs-infra): fix `elements` example when used with ES5 (#36536) Previously, the `elements` docs example only worked in browsers that natively supported Custom Elements and ES2015 modules. Furthermore, it didn't work on StackBlitz, because StackBlitz ignores the specified `target` in `tsconfig.json` and uses the UMD bundles (i.e. ES5 code) even on browsers that do support ES2015. (NOTE: In the past, this was not a problem, because we explicitly did not provide a StackBlitz example. This has changed in #36067.) This commit ensures the example works on all browsers and also on StackBlitz by providing the necessary Custom Elements polyfills. Fixes #36532 PR Close #36536 --- .../customizer/package-json/elements.json | 3 +- aio/tools/examples/example-boilerplate.js | 4 +- .../shared/boilerplate/elements/package.json | 1 + .../boilerplate/elements/src/polyfills.ts | 70 +++++++++++++++++++ aio/tools/examples/shared/package.json | 1 + aio/tools/examples/shared/yarn.lock | 5 ++ 6 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 aio/tools/examples/shared/boilerplate/elements/src/polyfills.ts diff --git a/aio/tools/example-zipper/customizer/package-json/elements.json b/aio/tools/example-zipper/customizer/package-json/elements.json index ac3d25cd1f8b1..1732dc9ae8a05 100644 --- a/aio/tools/example-zipper/customizer/package-json/elements.json +++ b/aio/tools/example-zipper/customizer/package-json/elements.json @@ -8,7 +8,8 @@ { "name": "e2e", "command": "ng e2e" } ], "dependencies": [ - "@angular/elements" + "@angular/elements", + "@webcomponents/custom-elements" ], "devDependencies": [ "@angular-devkit/build-angular", diff --git a/aio/tools/examples/example-boilerplate.js b/aio/tools/examples/example-boilerplate.js index 3899f4509bced..7292a43568f0d 100644 --- a/aio/tools/examples/example-boilerplate.js +++ b/aio/tools/examples/example-boilerplate.js @@ -30,7 +30,7 @@ const BOILERPLATE_PATHS = { // This maps the CLI files that exists in a parent folder const cliRelativePath = BOILERPLATE_PATHS.cli.map(file => `../cli/${file}`); -BOILERPLATE_PATHS.elements = [...cliRelativePath, 'package.json']; +BOILERPLATE_PATHS.elements = [...cliRelativePath, 'package.json', 'src/polyfills.ts']; BOILERPLATE_PATHS.i18n = [...cliRelativePath, 'angular.json', 'package.json']; @@ -79,7 +79,7 @@ class ExampleBoilerPlate { if (!fs.existsSync(SHARED_NODE_MODULES_PATH)) { throw new Error( `The shared node_modules folder for the examples (${SHARED_NODE_MODULES_PATH}) is missing.\n` + - `Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?`); + 'Perhaps you need to run "yarn example-use-npm" or "yarn example-use-local" to install the dependencies?'); } if (!viewengine) { diff --git a/aio/tools/examples/shared/boilerplate/elements/package.json b/aio/tools/examples/shared/boilerplate/elements/package.json index 6403a57603c9d..da89168bc8b31 100644 --- a/aio/tools/examples/shared/boilerplate/elements/package.json +++ b/aio/tools/examples/shared/boilerplate/elements/package.json @@ -21,6 +21,7 @@ "@angular/platform-browser": "~9.0.6", "@angular/platform-browser-dynamic": "~9.0.6", "@angular/router": "~9.0.6", + "@webcomponents/custom-elements": "^1.4.1", "angular-in-memory-web-api": "~0.9.0", "rxjs": "~6.5.4", "tslib": "^1.10.0", diff --git a/aio/tools/examples/shared/boilerplate/elements/src/polyfills.ts b/aio/tools/examples/shared/boilerplate/elements/src/polyfills.ts new file mode 100644 index 0000000000000..031fc3d0c083a --- /dev/null +++ b/aio/tools/examples/shared/boilerplate/elements/src/polyfills.ts @@ -0,0 +1,70 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch + * requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch + * specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ +// Custom Elements polyfill. Required for browsers that do not natively support Custom Elements. +import '@webcomponents/custom-elements'; +// Custom Elements ES5 shim. Required when using ES5 bundles on browsers that natively support +// Custom Elements (either because the browser does not support ES2015 modules or because the app +// is explicitly configured to generate ES5 only bundles). +import '@webcomponents/custom-elements/src/native-shim'; diff --git a/aio/tools/examples/shared/package.json b/aio/tools/examples/shared/package.json index 0447962c96b5d..2a7544e0d5b58 100644 --- a/aio/tools/examples/shared/package.json +++ b/aio/tools/examples/shared/package.json @@ -34,6 +34,7 @@ "@nguniversal/common": "~9.0.1", "@nguniversal/express-engine": "~9.0.1", "@nguniversal/module-map-ngfactory-loader": "~9.0.0-next.9", + "@webcomponents/custom-elements": "^1.4.1", "angular": "1.7.9", "angular-in-memory-web-api": "~0.9.0", "angular-route": "1.7.9", diff --git a/aio/tools/examples/shared/yarn.lock b/aio/tools/examples/shared/yarn.lock index 6c52802b0bda2..b6b707f088be7 100644 --- a/aio/tools/examples/shared/yarn.lock +++ b/aio/tools/examples/shared/yarn.lock @@ -1425,6 +1425,11 @@ "@webassemblyjs/wast-parser" "1.8.5" "@xtuc/long" "4.2.2" +"@webcomponents/custom-elements@^1.4.1": + version "1.4.1" + resolved "https://registry.yarnpkg.com/@webcomponents/custom-elements/-/custom-elements-1.4.1.tgz#9803aaa2286a13a4ba200a7a2ea767871598eb60" + integrity sha512-vNCS1+3sxJOpoIsBjUQiXjGLngakEAGOD5Ale+6ikg6OZG5qI5O39frm3raPhud/IwnF4vec5ags05YBsgzcuA== + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" From fee316161d5de6d5b8f77dc13278db779ea5b4c5 Mon Sep 17 00:00:00 2001 From: Andrew Kushnir <akushnir@google.com> Date: Thu, 9 Apr 2020 12:07:18 -0700 Subject: [PATCH 177/262] build: update `REQUIRED_BASE_SHA` in merge script to clang 1.4.0 upgrade commit (#36547) Updating `REQUIRED_BASE_SHA` for master and patch branches to make sure PRs that we merge are rebased after clang 1.4.0 upgrade. PR Close #36547 --- scripts/github/merge-pr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/github/merge-pr b/scripts/github/merge-pr index 5d81c093bf69c..c3a67f5d46ff0 100755 --- a/scripts/github/merge-pr +++ b/scripts/github/merge-pr @@ -131,8 +131,8 @@ CHERRY_PICK_PR="git cherry-pick merge_pr_base..merge_pr" # # This check is used to enforce that we don't merge PRs that have not been rebased recently and could result in merging # of non-approved or otherwise bad changes. -REQUIRED_BASE_SHA_MASTER="296dc0622f0e8c4e803ff4f19a5c6fe02a2ae66e" # CODEOWNERS => PullApprove migration -REQUIRED_BASE_SHA_PATCH="110f6c91b904819cab639861b54b6a989e176942" # CODEOWNERS => PullApprove migration +REQUIRED_BASE_SHA_MASTER="c5c57f673745e9b66a771c49e778a7d2e8d8c56a" # clang 1.4.0 update +REQUIRED_BASE_SHA_PATCH="f4681b6e407c0f518bc4a27ca04ca60d8eff8a69" # clang 1.4.0 update if [[ $MERGE_MASTER == 1 ]]; then REQUIRED_BASE_SHA="$REQUIRED_BASE_SHA_MASTER" # check patch only if patch-only PR From 6ab43d73359adf38c70d9085e591acc88e6c257d Mon Sep 17 00:00:00 2001 From: George Kalpakas <kalpakas.g@gmail.com> Date: Fri, 10 Apr 2020 15:13:20 +0300 Subject: [PATCH 178/262] fix(ngcc): correctly detect external files from nested `node_modules/` (#36559) Previously, when we needed to detect whether a file is external to a package, we only checked whether the relative path to the file from the package's root started with `..`. This would detect external imports when the packages were siblings (e.g. peer dependencies or hoisted to the top of `node_modules/` by the package manager), but would fail to detect imports from packages located in nested `node_modules/` as external. For example, importing `node_modules/foo/node_modules/bar` from a file in `node_modules/foo/` would be considered internal to the `foo` package. This could result in processing/analyzing more files than necessary. More importantly it could lead to errors due to trying to analyze non-Angular packages that were direct dependencies of Angular packages. This commit fixes it by also verifying that the relative path to a file does not start with `node_modules/`. Jira issue: [FW-2068](https://angular-team.atlassian.net/browse/FW-2068) Fixes #36526 PR Close #36559 --- .../compiler-cli/ngcc/src/analysis/util.ts | 3 +- .../test/analysis/decoration_analyzer_spec.ts | 28 ++++++--- .../ngcc/test/analysis/migration_host_spec.ts | 28 ++++++++- .../analysis/switch_marker_analyzer_spec.ts | 59 +++++++++++++------ .../ngcc/test/analysis/util_spec.ts | 24 ++++++-- 5 files changed, 108 insertions(+), 34 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/analysis/util.ts b/packages/compiler-cli/ngcc/src/analysis/util.ts index ef4a3931da5f7..fb51a2c7ebfa6 100644 --- a/packages/compiler-cli/ngcc/src/analysis/util.ts +++ b/packages/compiler-cli/ngcc/src/analysis/util.ts @@ -11,7 +11,8 @@ import {absoluteFromSourceFile, AbsoluteFsPath, relative} from '../../../src/ngt import {DependencyTracker} from '../../../src/ngtsc/incremental/api'; export function isWithinPackage(packagePath: AbsoluteFsPath, sourceFile: ts.SourceFile): boolean { - return !relative(packagePath, absoluteFromSourceFile(sourceFile)).startsWith('..'); + const relativePath = relative(packagePath, absoluteFromSourceFile(sourceFile)); + return !relativePath.startsWith('..') && !relativePath.startsWith('node_modules/'); } class NoopDependencyTracker implements DependencyTracker { diff --git a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts index 8ec0130a959ec..014eb81d9a26e 100644 --- a/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/decoration_analyzer_spec.ts @@ -313,31 +313,39 @@ runInEachFileSystem(() => { contents: ` import {Component, NgModule} from '@angular/core'; import {ImportedComponent} from 'other/component'; + import {NestedDependencyComponent} from 'nested/component'; export class LocalComponent {} LocalComponent.decorators = [{type: Component}]; export class MyModule {} MyModule.decorators = [{type: NgModule, args: [{ - declarations: [ImportedComponent, LocalComponent], - exports: [ImportedComponent, LocalComponent], + declarations: [ImportedComponent, NestedDependencyComponent, LocalComponent], + exports: [ImportedComponent, NestedDependencyComponent, LocalComponent], },] }]; ` }, + // Do not define a `.d.ts` file to ensure that the `.js` file will be part of the TS + // program. { - name: _('/node_modules/other/component.js'), + name: _('/node_modules/test-package/node_modules/nested/component.js'), contents: ` import {Component} from '@angular/core'; - export class ImportedComponent {} - ImportedComponent.decorators = [{type: Component}]; + export class NestedDependencyComponent {} + NestedDependencyComponent.decorators = [{type: Component}]; `, isRoot: false, }, + // Do not define a `.d.ts` file to ensure that the `.js` file will be part of the TS + // program. { - name: _('/node_modules/other/component.d.ts'), + name: _('/node_modules/other/component.js'), contents: ` import {Component} from '@angular/core'; - export class ImportedComponent {}` + export class ImportedComponent {} + ImportedComponent.decorators = [{type: Component}]; + `, + isRoot: false, }, ]; @@ -349,6 +357,12 @@ runInEachFileSystem(() => { const file = program.getSourceFile(_('/node_modules/other/component.js'))!; expect(result.has(file)).toBe(false); }); + + it('should ignore classes from a file imported from a nested `node_modules/`', () => { + const file = program.getSourceFile( + _('/node_modules/test-package/node_modules/nested/component.js'))!; + expect(result.has(file)).toBe(false); + }); }); describe('diagnostic handling', () => { diff --git a/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts b/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts index 57c3da663f80f..3598496c1198a 100644 --- a/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/migration_host_spec.ts @@ -92,8 +92,6 @@ runInEachFileSystem(() => { }); }); - - describe('getAllDecorators', () => { it('should include injected decorators', () => { const directiveHandler = new DetectDecoratorHandler('Directive', HandlerPrecedence.WEAK); @@ -143,7 +141,7 @@ runInEachFileSystem(() => { expect(host.isInScope(internalClass)).toBe(true); }); - it('should be false for nodes outside the entry-point', () => { + it('should be false for nodes outside the entry-point (in sibling package)', () => { loadTestFiles([ {name: _('/node_modules/external/index.js'), contents: `export class ExternalClass {}`}, { @@ -163,6 +161,30 @@ runInEachFileSystem(() => { expect(host.isInScope(externalClass)).toBe(false); }); + + it('should be false for nodes outside the entry-point (in nested `node_modules/`)', () => { + loadTestFiles([ + { + name: _('/node_modules/test/index.js'), + contents: ` + export {NestedDependencyClass} from 'nested'; + export class InternalClass {} + `, + }, + { + name: _('/node_modules/test/node_modules/nested/index.js'), + contents: `export class NestedDependencyClass {}`, + }, + ]); + const entryPoint = + makeTestEntryPointBundle('test', 'esm2015', false, [_('/node_modules/test/index.js')]); + const {host} = createMigrationHost({entryPoint, handlers: []}); + const nestedDepClass = getDeclaration( + entryPoint.src.program, _('/node_modules/test/node_modules/nested/index.js'), + 'NestedDependencyClass', isNamedClassDeclaration); + + expect(host.isInScope(nestedDepClass)).toBe(false); + }); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts b/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts index 53f91a7d46734..403877d50c80e 100644 --- a/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/switch_marker_analyzer_spec.ts @@ -24,45 +24,53 @@ runInEachFileSystem(() => { { name: _('/node_modules/test/entrypoint.js'), contents: ` - import {a} from './a'; - import {b} from './b'; - import {x} from '../other/x'; - ` + import {a} from './a'; + import {b} from './b'; + import {x} from '../other/x'; + import {e} from 'nested/e'; + `, }, { name: _('/node_modules/test/a.js'), contents: ` - import {c} from './c'; - export const a = 1; - ` + import {c} from './c'; + export const a = 1; + `, }, { name: _('/node_modules/test/b.js'), contents: ` - export const b = 42; - var factoryB = factory__PRE_R3__; - ` + export const b = 42; + var factoryB = factory__PRE_R3__; + `, }, { name: _('/node_modules/test/c.js'), contents: ` - export const c = 'So long, and thanks for all the fish!'; - var factoryC = factory__PRE_R3__; - var factoryD = factory__PRE_R3__; - ` + export const c = 'So long, and thanks for all the fish!'; + var factoryC = factory__PRE_R3__; + var factoryD = factory__PRE_R3__; + `, + }, + { + name: _('/node_modules/test/node_modules/nested/e.js'), + contents: ` + export const e = 1337; + var factoryE = factory__PRE_R3__; + `, }, { name: _('/node_modules/other/x.js'), contents: ` - export const x = 3.142; - var factoryX = factory__PRE_R3__; - ` + export const x = 3.142; + var factoryX = factory__PRE_R3__; + `, }, { name: _('/node_modules/other/x.d.ts'), contents: ` - export const x: number; - ` + export const x: number; + `, }, ]; }); @@ -111,6 +119,19 @@ runInEachFileSystem(() => { const x = getSourceFileOrError(program, _('/node_modules/other/x.js')); expect(analysis.has(x)).toBe(false); }); + + it('should ignore files that are inside the package\'s `node_modules/`', () => { + loadTestFiles(TEST_PROGRAM); + const bundle = makeTestEntryPointBundle( + 'test', 'esm2015', false, [_('/node_modules/test/entrypoint.js')]); + const program = bundle.src.program; + const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle.src); + const analyzer = new SwitchMarkerAnalyzer(host, bundle.entryPoint.package); + const analysis = analyzer.analyzeProgram(program); + + const x = getSourceFileOrError(program, _('/node_modules/test/node_modules/nested/e.js')); + expect(analysis.has(x)).toBe(false); + }); }); }); }); diff --git a/packages/compiler-cli/ngcc/test/analysis/util_spec.ts b/packages/compiler-cli/ngcc/test/analysis/util_spec.ts index fd6ee82409c33..048deb0efe651 100644 --- a/packages/compiler-cli/ngcc/test/analysis/util_spec.ts +++ b/packages/compiler-cli/ngcc/test/analysis/util_spec.ts @@ -12,20 +12,36 @@ import {isWithinPackage} from '../../src/analysis/util'; runInEachFileSystem(() => { describe('isWithinPackage', () => { + let _: typeof absoluteFrom; + + beforeEach(() => _ = absoluteFrom); + it('should return true if the source-file is contained in the package', () => { - const _ = absoluteFrom; + const packagePath = _('/node_modules/test'); const file = ts.createSourceFile(_('/node_modules/test/src/index.js'), '', ts.ScriptTarget.ES2015); - const packagePath = _('/node_modules/test'); expect(isWithinPackage(packagePath, file)).toBe(true); }); it('should return false if the source-file is not contained in the package', () => { - const _ = absoluteFrom; + const packagePath = _('/node_modules/test'); const file = ts.createSourceFile(_('/node_modules/other/src/index.js'), '', ts.ScriptTarget.ES2015); - const packagePath = _('/node_modules/test'); expect(isWithinPackage(packagePath, file)).toBe(false); }); + + it('should return false if the source-file is inside the package\'s `node_modules/`', () => { + const packagePath = _('/node_modules/test'); + + // An external file inside the package's `node_modules/`. + const file1 = ts.createSourceFile( + _('/node_modules/test/node_modules/other/src/index.js'), '', ts.ScriptTarget.ES2015); + expect(isWithinPackage(packagePath, file1)).toBe(false); + + // An internal file starting with `node_modules`. + const file2 = ts.createSourceFile( + _('/node_modules/test/node_modules_optimizer.js'), '', ts.ScriptTarget.ES2015); + expect(isWithinPackage(packagePath, file2)).toBe(true); + }); }); }); From ca677481a2ac3675b84698e2d16fd379e1799e2c Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner <paulgschwendtner@gmail.com> Date: Thu, 9 Apr 2020 18:27:07 +0200 Subject: [PATCH 179/262] fix(core): undecorated-classes-with-decorated-fields migration should avoid error if base class has no value declaration (#36543) The undecorated-classes-with-decorated-fields migration relies on the type checker to resolve base classes of individual classes. It could happen that resolved base classes have no value declaration. e.g. if they are declared through an interface in the default types. Currently the migration will throw in such situations because it assumes that `ts.Symbol#valueDeclaration` is always present. This is not the case, but we don't get good type-checking here due to a bug in the TypeScript types. See: https://github.com/microsoft/TypeScript/issues/24706. Fixes #36522. PR Close #36543 --- ...es_with_decorated_fields_migration_spec.ts | 64 +++++++++++++------ .../utils/typescript/find_base_classes.ts | 4 +- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts b/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts index 27c7ac65f2d12..e82adc24627b0 100644 --- a/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts +++ b/packages/core/schematics/test/undecorated_classes_with_decorated_fields_migration_spec.ts @@ -42,7 +42,7 @@ describe('Undecorated classes with decorated fields migration', () => { shx.rm('-r', tmpDirPath); }); - it(`should add an import for Directive if there isn't one already`, async() => { + it(`should add an import for Directive if there isn't one already`, async () => { writeFile('/index.ts', ` import { Input } from '@angular/core'; @@ -56,7 +56,7 @@ describe('Undecorated classes with decorated fields migration', () => { .toContain(`import { Input, Directive } from '@angular/core';`); }); - it('should not change the imports if there is an import for Directive already', async() => { + it('should not change the imports if there is an import for Directive already', async () => { writeFile('/index.ts', ` import { Directive, Input } from '@angular/core'; @@ -74,8 +74,9 @@ describe('Undecorated classes with decorated fields migration', () => { .toContain(`import { Directive, Input } from '@angular/core';`); }); - it('should not generate conflicting imports there is a different `Directive` symbol', async() => { - writeFile('/index.ts', ` + it('should not generate conflicting imports there is a different `Directive` symbol', + async () => { + writeFile('/index.ts', ` import { HostBinding } from '@angular/core'; export class Directive { @@ -88,14 +89,14 @@ describe('Undecorated classes with decorated fields migration', () => { } `); - await runMigration(); - const fileContent = tree.readContent('/index.ts'); - expect(fileContent) - .toContain(`import { HostBinding, Directive as Directive_1 } from '@angular/core';`); - expect(fileContent).toMatch(/@Directive_1\(\)\s+export class MyLibrarySharedBaseClass/); - }); + await runMigration(); + const fileContent = tree.readContent('/index.ts'); + expect(fileContent) + .toContain(`import { HostBinding, Directive as Directive_1 } from '@angular/core';`); + expect(fileContent).toMatch(/@Directive_1\(\)\s+export class MyLibrarySharedBaseClass/); + }); - it('should add @Directive to undecorated classes that have @Input', async() => { + it('should add @Directive to undecorated classes that have @Input', async () => { writeFile('/index.ts', ` import { Input } from '@angular/core'; @@ -108,7 +109,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should not change decorated classes', async() => { + it('should not change decorated classes', async () => { writeFile('/index.ts', ` import { Input, Component, Output, EventEmitter } from '@angular/core'; @@ -130,7 +131,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(content).toContain(`@Directive()\nexport class Child extends Base {`); }); - it('should add @Directive to undecorated classes that have @Output', async() => { + it('should add @Directive to undecorated classes that have @Output', async () => { writeFile('/index.ts', ` import { Output, EventEmitter } from '@angular/core'; @@ -143,7 +144,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated classes that have a host binding', async() => { + it('should add @Directive to undecorated classes that have a host binding', async () => { writeFile('/index.ts', ` import { HostBinding } from '@angular/core'; @@ -159,7 +160,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated classes that have a host listener', async() => { + it('should add @Directive to undecorated classes that have a host listener', async () => { writeFile('/index.ts', ` import { HostListener } from '@angular/core'; @@ -175,7 +176,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated classes that have a ViewChild query', async() => { + it('should add @Directive to undecorated classes that have a ViewChild query', async () => { writeFile('/index.ts', ` import { ViewChild, ElementRef } from '@angular/core'; @@ -188,7 +189,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated classes that have a ViewChildren query', async() => { + it('should add @Directive to undecorated classes that have a ViewChildren query', async () => { writeFile('/index.ts', ` import { ViewChildren, ElementRef } from '@angular/core'; @@ -201,7 +202,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated classes that have a ContentChild query', async() => { + it('should add @Directive to undecorated classes that have a ContentChild query', async () => { writeFile('/index.ts', ` import { ContentChild, ElementRef } from '@angular/core'; @@ -214,7 +215,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated classes that have a ContentChildren query', async() => { + it('should add @Directive to undecorated classes that have a ContentChildren query', async () => { writeFile('/index.ts', ` import { ContentChildren, ElementRef } from '@angular/core'; @@ -227,7 +228,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(tree.readContent('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated derived classes of a migrated class', async() => { + it('should add @Directive to undecorated derived classes of a migrated class', async () => { writeFile('/index.ts', ` import { Input, Directive, NgModule } from '@angular/core'; @@ -259,7 +260,7 @@ describe('Undecorated classes with decorated fields migration', () => { expect(fileContent).toMatch(/}\s+export class MyCompWrapped/); }); - it('should add @Directive to derived undecorated classes of abstract directives', async() => { + it('should add @Directive to derived undecorated classes of abstract directives', async () => { writeFile('/index.ts', ` import { Input, Directive, NgModule } from '@angular/core'; @@ -292,6 +293,27 @@ describe('Undecorated classes with decorated fields migration', () => { expect(fileContent).toMatch(/}\s+export class MyCompWrapped/); }); + it('should not throw if undecorated class extends from unresolved declaration', async () => { + writeFile('/lib.d.ts', ` + // Fakes the ES5 error default lib types. Since we are in a virtual tree, + // the default lib types from TypeScript are not available. + interface ErrorConstructor {} + declare var Error: ErrorConstructor; + `); + writeFile('/index.ts', ` + export class MyCustomErrorClass extends Error {} + `); + + let error: any = null; + try { + await runMigration(); + } catch (e) { + error = e; + } + + expect(error).toBe(null); + }); + function writeFile(filePath: string, contents: string) { host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents)); } diff --git a/packages/core/schematics/utils/typescript/find_base_classes.ts b/packages/core/schematics/utils/typescript/find_base_classes.ts index ae075bce15bb2..f6a16c120a49d 100644 --- a/packages/core/schematics/utils/typescript/find_base_classes.ts +++ b/packages/core/schematics/utils/typescript/find_base_classes.ts @@ -20,7 +20,9 @@ export function findBaseClassDeclarations(node: ts.ClassDeclaration, typeChecker break; } const symbol = typeChecker.getTypeAtLocation(baseTypes[0]).getSymbol(); - if (!symbol || !ts.isClassDeclaration(symbol.valueDeclaration)) { + // Note: `ts.Symbol#valueDeclaration` can be undefined. TypeScript has an incorrect type + // for this: https://github.com/microsoft/TypeScript/issues/24706. + if (!symbol || !symbol.valueDeclaration || !ts.isClassDeclaration(symbol.valueDeclaration)) { break; } result.push({identifier: baseTypes[0], node: symbol.valueDeclaration}); From 5737e657006912711307477953d49e910b27e70b Mon Sep 17 00:00:00 2001 From: Mansour Fall <fallmansour19@yahoo.fr> Date: Sun, 12 Apr 2020 20:21:37 +0200 Subject: [PATCH 180/262] docs(zone.js): fix typos in NgZone guide code example (#36597) Fixes #36594 PR Close #36597 --- aio/content/guide/zone.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aio/content/guide/zone.md b/aio/content/guide/zone.md index 68aa2faec1b5b..7b17ef9b8a28c 100644 --- a/aio/content/guide/zone.md +++ b/aio/content/guide/zone.md @@ -29,8 +29,8 @@ To clarify how changes are detected and values updated, consider the following c ```javascript <html> <div id="dataDiv"></div> - <button id="btn">updateData<btn> - <canvas id="canvas"><canvas> + <button id="btn">updateData</button> + <canvas id="canvas"></canvas> <script> let value = 'initialValue'; // initial rendering From 9181b73e5ac7da7be3ad3a59b594c738ce14b4da Mon Sep 17 00:00:00 2001 From: Rajat Soni <rajatsoni9@outlook.com> Date: Sun, 12 Apr 2020 22:10:27 +0530 Subject: [PATCH 181/262] docs: fix typo in Tests guide (#36592) PR Close #36592 --- aio/content/guide/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/content/guide/testing.md b/aio/content/guide/testing.md index 9052d2513be33..a42f78a4e4b4d 100644 --- a/aio/content/guide/testing.md +++ b/aio/content/guide/testing.md @@ -1277,7 +1277,7 @@ In this example, we have a new macro task (nested setTimeout), by default, when region="fake-async-test-tick-new-macro-task-async"> </code-example> -And in some case, we don't want to trigger the new macro task when ticking, we can use `tick(milliseconds, {processNewMacroTasksSynchronously: false})` to not invoke new maco task. +And in some case, we don't want to trigger the new macro task when ticking, we can use `tick(milliseconds, {processNewMacroTasksSynchronously: false})` to not invoke new macro task. #### Comparing dates inside fakeAsync() From 2d16b4711e41dac60352c57ffc50ae9f7d846850 Mon Sep 17 00:00:00 2001 From: ajitsinghkaler <ajitsinghkaler0@gmail.com> Date: Sun, 12 Apr 2020 17:28:28 +0530 Subject: [PATCH 182/262] fix(docs-infra): fix About page button text being truncated on small screens (#36576) On small screens (e.g. on mobile), the text on some of the buttons in the About page was truncated. Changed the text size, margin and padding so that the the whole text is visible on such screens (320px to 480px). PR Close #36576 --- aio/src/styles/2-modules/_contributor.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/aio/src/styles/2-modules/_contributor.scss b/aio/src/styles/2-modules/_contributor.scss index 4cd9fad6b316a..5df3383e1852e 100644 --- a/aio/src/styles/2-modules/_contributor.scss +++ b/aio/src/styles/2-modules/_contributor.scss @@ -19,6 +19,14 @@ aio-contributor-list { .group-buttons { margin: 32px auto; + @media (max-width: 480px) { + .filter-button.button { + font-size: 1.2rem; + padding: 0; + margin: 0; + } + } + a { &.selected { background-color: $blue; From d9728218893ba775e32fc5feffaaf5f83cb6b9f8 Mon Sep 17 00:00:00 2001 From: ajitsinghkaler <ajitsinghkaler0@gmail.com> Date: Sat, 11 Apr 2020 11:06:37 +0530 Subject: [PATCH 183/262] fix(docs-infra): contribute page not visible correctly on mobile devices (#36573) on mobile devices screen size < 600px the contribute page is not visible in correct form changed styles to make it visible correctly PR Close #36573 --- aio/src/styles/2-modules/_contribute.scss | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/aio/src/styles/2-modules/_contribute.scss b/aio/src/styles/2-modules/_contribute.scss index 73cf429502734..c6ab9bcc04ef1 100644 --- a/aio/src/styles/2-modules/_contribute.scss +++ b/aio/src/styles/2-modules/_contribute.scss @@ -7,13 +7,26 @@ justify-content: space-between; max-width: 880px; + @media (max-width: 600px) { + flex-direction: column; + } + > :first-child { margin-right: 2rem; width: 60%; + @media (max-width: 600px) { + width: 100%; + } } &:last-child { margin-bottom: 0; } + + .button { + @media (max-width: 600px) { + margin-top: 14px; + } + } } } From 713bce19f42ca58271113789ecd092a7839887e0 Mon Sep 17 00:00:00 2001 From: Sonu Kapoor <sonukapoor@gmail.com> Date: Fri, 3 Apr 2020 05:49:16 -0400 Subject: [PATCH 184/262] docs: move ng-conf 2020 to the already presented section (#36413) PR Close #36413 --- aio/content/marketing/events.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aio/content/marketing/events.html b/aio/content/marketing/events.html index d4b8bf40ab320..eeed40cea4f99 100755 --- a/aio/content/marketing/events.html +++ b/aio/content/marketing/events.html @@ -13,12 +13,6 @@ <h1 class="banner-headline no-toc no-anchor">Events</h1> </tr> </thead> <tbody> - <!-- ng-conf 2020 --> - <tr> - <th><a href="https://ng-conf.org/" title="ng-conf">ng-conf</a></th> - <td>Salt Lake City, Utah</td> - <td>April 1-3, 2020</td> - </tr> <tr> <th><a href="https://ngvikings.org/" title="ngVikings">ngVikings</a></th> <td>Oslo, Norway</td> @@ -37,6 +31,12 @@ <h1 class="banner-headline no-toc no-anchor">Events</h1> </tr> </thead> <tbody> + <!-- ng-conf 2020 --> + <tr> + <th><a href="https://ng-conf.org/" title="ng-conf">ng-conf</a></th> + <td>Salt Lake City, Utah</td> + <td>April 1-3, 2020</td> + </tr> <!-- ngIndia 2020 --> <tr> <th><a href="https://www.ng-ind.com/" title="ngIndia">ngIndia</a></th> From 0cc53fb39871b6193ac1852d420d22bfebf821a2 Mon Sep 17 00:00:00 2001 From: Alison Gale <agale@google.com> Date: Tue, 7 Apr 2020 16:44:28 -0700 Subject: [PATCH 185/262] fix(upgrade): update $locationShim to handle Location changes before initialization (#36498) Updates the $locationShim to receive the most recent Location change made, even if it happened before initialize() is called. This is important when AngularJS bootstrapping is deferred and there is a delay between when $locationShim is constructed and when it is initialized. With this change, the $locationShim will correctly reflect any redirects that occurred between construction and initialization. Closes #36492 PR Close #36498 --- packages/common/upgrade/src/location_shim.ts | 40 ++++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/packages/common/upgrade/src/location_shim.ts b/packages/common/upgrade/src/location_shim.ts index 7f03b46c0b360..de4d3f3a8aa1c 100644 --- a/packages/common/upgrade/src/location_shim.ts +++ b/packages/common/upgrade/src/location_shim.ts @@ -8,6 +8,7 @@ import {Location, LocationStrategy, PlatformLocation} from '@angular/common'; import {UpgradeModule} from '@angular/upgrade/static'; +import {ReplaySubject} from 'rxjs'; import {UrlCodec} from './params'; import {deepEqual, isAnchor, isPromise} from './utils'; @@ -50,7 +51,7 @@ export class $locationShim { private cachedState: unknown = null; - + private urlChanges = new ReplaySubject<{newUrl: string, newState: unknown}>(1); constructor( $injector: any, private location: Location, private platformLocation: PlatformLocation, @@ -71,6 +72,10 @@ export class $locationShim { this.cacheState(); this.$$state = this.browserState(); + this.location.onUrlChange((newUrl, newState) => { + this.urlChanges.next({newUrl, newState}); + }); + if (isPromise($injector)) { $injector.then($i => this.initialize($i)); } else { @@ -88,7 +93,7 @@ export class $locationShim { return; } - let elm: (Node & ParentNode)|null = event.target; + let elm: (Node&ParentNode)|null = event.target; // traverse the DOM up to find first A tag while (elm && elm.nodeName.toLowerCase() !== 'a') { @@ -124,9 +129,9 @@ export class $locationShim { } }); - this.location.onUrlChange((newUrl, newState) => { - let oldUrl = this.absUrl(); - let oldState = this.$$state; + this.urlChanges.subscribe(({newUrl, newState}) => { + const oldUrl = this.absUrl(); + const oldState = this.$$state; this.$$parse(newUrl); newUrl = this.absUrl(); this.$$state = newState; @@ -286,7 +291,9 @@ export class $locationShim { * This function emulates the $browser.state() function from AngularJS. It will cause * history.state to be cached unless changed with deep equality check. */ - private browserState(): unknown { return this.cachedState; } + private browserState(): unknown { + return this.cachedState; + } private stripBaseUrl(base: string, url: string) { if (url.startsWith(base)) { @@ -446,7 +453,9 @@ export class $locationShim { * // => "http://example.com/#/some/path?foo=bar&baz=xoxo" * ``` */ - absUrl(): string { return this.$$absUrl; } + absUrl(): string { + return this.$$absUrl; + } /** * Retrieves the current URL, or sets a new URL. When setting a URL, @@ -488,7 +497,9 @@ export class $locationShim { * // => "http" * ``` */ - protocol(): string { return this.$$protocol; } + protocol(): string { + return this.$$protocol; + } /** * Retrieves the protocol of the current URL. @@ -509,7 +520,9 @@ export class $locationShim { * // => "example.com:8080" * ``` */ - host(): string { return this.$$host; } + host(): string { + return this.$$host; + } /** * Retrieves the port of the current URL. @@ -520,7 +533,9 @@ export class $locationShim { * // => 80 * ``` */ - port(): number|null { return this.$$port; } + port(): number|null { + return this.$$port; + } /** * Retrieves the path of the current URL, or changes the path and returns a reference to its own @@ -553,7 +568,7 @@ export class $locationShim { } /** - * Retrieves a map of the search parameters of the current URL, or changes a search + * Retrieves a map of the search parameters of the current URL, or changes a search * part and returns a reference to its own instance. * * @@ -576,7 +591,8 @@ export class $locationShim { * If the argument is a hash object containing an array of values, these values will be encoded * as duplicate search parameters in the URL. * - * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue` + * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, + * then `paramValue` * will override only a single search property. * * If `paramValue` is an array, it will override the property of the `search` component of From f88e63519a3289f84e8c122ebbdd8c916b2ef018 Mon Sep 17 00:00:00 2001 From: Tony Bove <rockument69@gmail.com> Date: Fri, 20 Mar 2020 05:58:26 -1000 Subject: [PATCH 186/262] docs: edit to setup-local (#36168) PR Close #36168 --- aio/content/guide/setup-local.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/aio/content/guide/setup-local.md b/aio/content/guide/setup-local.md index 1287bd8f29e09..1f7e9281c6bd5 100644 --- a/aio/content/guide/setup-local.md +++ b/aio/content/guide/setup-local.md @@ -18,11 +18,19 @@ If you are new to Angular, see [Getting Started](start). Getting Started helps y {@a prerequisites} ## Prerequisites -Before you begin, make sure your development environment includes `Node.js®` and an npm package manager. +To use the Angular framework, you should be familiar with the following: + +* [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) +* [HTML](https://developer.mozilla.org/docs/Learn/HTML/Introduction_to_HTML) +* [CSS](https://developer.mozilla.org/docs/Learn/CSS/First_steps) + +Knowledge of [TypeScript](https://www.typescriptlang.org/) is helpful, but not required. {@a nodejs} ### Node.js +Make sure your development environment includes `Node.js®` and an npm package manager. + Angular requires a [current, active LTS, or maintenance LTS](https://nodejs.org/about/releases/) version of `Node.js`. See the `engines` key for the specific version requirements in our [package.json](https://unpkg.com/@angular/cli/package.json). * To check your version, run `node -v` in a terminal/console window. From 58e175318c5fe0605d098c73092d247ee6ebbb5f Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Sat, 11 Apr 2020 09:15:16 -0700 Subject: [PATCH 187/262] build: update to rules_nodejs 1.6.0 (#36580) Lots of bug fixes and stability fixes. Last 1.x release for rules_nodejs. PR Close #36580 --- WORKSPACE | 6 +- integration/bazel/WORKSPACE | 4 +- integration/bazel/package.json | 10 +-- integration/bazel/yarn.lock | 64 +++++++++---------- package.json | 12 ++-- .../src/builders/files/WORKSPACE.template | 4 +- packages/bazel/src/schematics/ng-add/index.ts | 10 +-- yarn.lock | 48 +++++++------- 8 files changed, 79 insertions(+), 79 deletions(-) diff --git a/WORKSPACE b/WORKSPACE index f5a55ddde0e70..15fc0c3b37b1b 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -8,8 +8,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Fetch rules_nodejs so we can install our npm dependencies http_archive( name = "build_bazel_rules_nodejs", - sha256 = "d0c4bb8b902c1658f42eb5563809c70a06e46015d64057d25560b0eb4bdc9007", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.5.0/rules_nodejs-1.5.0.tar.gz"], + sha256 = "f9e7b9f42ae202cc2d2ce6d698ccb49a9f7f7ea572a78fd451696d03ef2ee116", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.6.0/rules_nodejs-1.6.0.tar.gz"], ) # Check the rules_nodejs version and download npm dependencies @@ -17,7 +17,7 @@ http_archive( # assert on that. load("@build_bazel_rules_nodejs//:index.bzl", "check_rules_nodejs_version", "node_repositories", "yarn_install") -check_rules_nodejs_version(minimum_version_string = "1.5.0") +check_rules_nodejs_version(minimum_version_string = "1.6.0") # Setup the Node.js toolchain node_repositories( diff --git a/integration/bazel/WORKSPACE b/integration/bazel/WORKSPACE index b0148cd3f6b46..38cfce17a63a2 100644 --- a/integration/bazel/WORKSPACE +++ b/integration/bazel/WORKSPACE @@ -5,8 +5,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") # Fetch rules_nodejs so we can install our npm dependencies http_archive( name = "build_bazel_rules_nodejs", - sha256 = "d0c4bb8b902c1658f42eb5563809c70a06e46015d64057d25560b0eb4bdc9007", - urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.5.0/rules_nodejs-1.5.0.tar.gz"], + sha256 = "f9e7b9f42ae202cc2d2ce6d698ccb49a9f7f7ea572a78fd451696d03ef2ee116", + urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/1.6.0/rules_nodejs-1.6.0.tar.gz"], ) # Fetch sass rules for compiling sass files diff --git a/integration/bazel/package.json b/integration/bazel/package.json index 2ec53ac0a4e75..ed91345527953 100644 --- a/integration/bazel/package.json +++ b/integration/bazel/package.json @@ -23,11 +23,11 @@ "@angular/compiler": "file:../../dist/packages-dist/compiler", "@angular/compiler-cli": "file:../../dist/packages-dist/compiler-cli", "@bazel/bazelisk": "file:../../node_modules/@bazel/bazelisk", - "@bazel/karma": "1.5.0", - "@bazel/protractor": "1.5.0", - "@bazel/rollup": "1.5.0", - "@bazel/terser": "1.5.0", - "@bazel/typescript": "1.5.0", + "@bazel/karma": "1.6.0", + "@bazel/protractor": "1.6.0", + "@bazel/rollup": "1.6.0", + "@bazel/terser": "1.6.0", + "@bazel/typescript": "1.6.0", "@types/jasmine": "2.8.8", "http-server": "0.12.0", "karma": "4.4.1", diff --git a/integration/bazel/yarn.lock b/integration/bazel/yarn.lock index 3234081c24381..a87a6e1478df6 100644 --- a/integration/bazel/yarn.lock +++ b/integration/bazel/yarn.lock @@ -3,10 +3,10 @@ "@angular/animations@file:../../dist/packages-dist/animations": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/bazel@file:../../dist/packages-dist/bazel": - version "9.1.0-rc.0" + version "10.0.0-next.1" dependencies: "@microsoft/api-extractor" "^7.3.9" shelljs "0.8.2" @@ -22,10 +22,10 @@ parse5 "^5.0.0" "@angular/common@file:../../dist/packages-dist/common": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/compiler-cli@file:../../dist/packages-dist/compiler-cli": - version "9.1.0-rc.0" + version "10.0.0-next.1" dependencies: canonical-path "1.0.0" chokidar "^3.0.0" @@ -41,13 +41,13 @@ yargs "15.3.0" "@angular/compiler@file:../../dist/packages-dist/compiler": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/core@file:../../dist/packages-dist/core": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/forms@file:../../dist/packages-dist/forms": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/material@8.0.1": version "8.0.1" @@ -57,43 +57,43 @@ tslib "^1.7.1" "@angular/platform-browser-dynamic@file:../../dist/packages-dist/platform-browser-dynamic": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/platform-browser@file:../../dist/packages-dist/platform-browser": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@angular/router@file:../../dist/packages-dist/router": - version "9.1.0-rc.0" + version "10.0.0-next.1" "@bazel/bazelisk@file:../../node_modules/@bazel/bazelisk": version "1.3.0" -"@bazel/karma@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.5.0.tgz#75ea27c3c2a8a7fadbb5c5ab644c3acd3bc22702" - integrity sha512-j5S2Xya4Rr7vK0DzTaZ8FKDHBydtTNldwlx+rihjKJgbEBt76wQM7ucXD6aSA23lC+JM/dPRSKkpIIGeWf2JdQ== +"@bazel/karma@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.6.0.tgz#98950b71114dd9ec169e6778a35d31ae1f578655" + integrity sha512-9cX0E1SiMWwA70ZMFnMzeqSRn3biduGx03bGV77FSUYKocZpyfU2cOEygYGfxAqHnyM7x4cS8nflRv3+ZE0Aqg== dependencies: tmp "0.1.0" -"@bazel/protractor@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.5.0.tgz#ac92442bf38f5cd718812e4cca41ba2e5ebf1fa5" - integrity sha512-nUwOOUjNGJUU18JiE3sPOBzIul0jvGApEEikntKTLLwQ7w7/1TnOdXDWvHXrXRW3nwit6flWIzEUoFtWgwtCeg== +"@bazel/protractor@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.6.0.tgz#cf095a1dbc038def7031c513a3b87f4e79bedb00" + integrity sha512-gPiRv0oUJbVPpQ9nrwe5vjkffAc8VsYJhpTGgG+8aPdOaTLWgmBP/sy4BdfijU9O1Z/mNYojQCZgMzQz6kAvdg== -"@bazel/rollup@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.5.0.tgz#d0933d167e682470b90f8149eecf4c5bd7511369" - integrity sha512-/FEJfNi9dbbH8oQbf7LHyd0uhGSB0CQQhOpz8d4b2WLnYLhK0NZhoNF4afFjju5kQkrbrOfKaho64BfVxvNppA== +"@bazel/rollup@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.6.0.tgz#c0bdad0ad0ba5c5b2e21d1634dc2ce48840ca044" + integrity sha512-MLF7laHX3CSAJH+RbIEVWgnQdz3U8dPkdJWJqiX/z9mUSEgC47LNsMBPKlRy1TpOJOpw1j0vLaJv0qN/bgq9NQ== -"@bazel/terser@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.5.0.tgz#141e1492043231001da3f3ef67b575dd9c2df0be" - integrity sha512-ajT2roE+tiW+xm2YOSfUG55MaUHv0hHYlQneNV1GI3lZoowWPbToOaZiuVza90ulHFHP7lDXn/5MC4UF5/piOQ== +"@bazel/terser@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.6.0.tgz#63ccd20dd6c9793e7b3b23fb5ea82b55b3ef6eb2" + integrity sha512-csBrN4XfX/hYTtDVcH/ulVO9K4Ca/IlrCWk5o/l7JBJq/cHoTj5AWIA7PKJ4QgnxXeEjso4CmLFgUMEVKVYV3Q== -"@bazel/typescript@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.5.0.tgz#d69324c08e7dbfe10b21a6fcb7b4d66c71c8d171" - integrity sha512-Vi8n1p35EhxGC22TEnmnVPlyakrALyH2ccVN5J6YeZXE1oWlSMSqQEhXKTjqUfQ3FT76nW1K91AdH4TG3me5nQ== +"@bazel/typescript@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.6.0.tgz#8dfd29e71bcf917d5f9cb67f19ac4dcfc9082439" + integrity sha512-vAKuwy1Hgl+t3M3sH/G0oqHRYN35TdENj+0lsCI3x7EbSzyI6cbA3YQrLrlyvdScksqOpZa3PZ3UBGqfJJq2DA== dependencies: protobufjs "6.8.8" semver "5.6.0" @@ -2084,7 +2084,7 @@ rollup@1.27.5: acorn "^7.1.0" "rxjs@file:../../node_modules/rxjs": - version "6.5.3" + version "6.5.4" dependencies: tslib "^1.9.0" @@ -2437,7 +2437,7 @@ tslib@^1.7.1, tslib@^1.8.1, tslib@^1.9.0: integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== "tslib@file:../../node_modules/tslib": - version "1.10.0" + version "1.11.1" tsutils@2.27.2: version "2.27.2" diff --git a/package.json b/package.json index 647c82bbb3358..08a37a96d87a3 100644 --- a/package.json +++ b/package.json @@ -51,12 +51,12 @@ "@babel/template": "^7.8.6", "@babel/traverse": "^7.8.6", "@babel/types": "^7.8.6", - "@bazel/jasmine": "1.5.0", - "@bazel/karma": "1.5.0", - "@bazel/protractor": "1.5.0", - "@bazel/rollup": "1.5.0", - "@bazel/terser": "1.5.0", - "@bazel/typescript": "1.5.0", + "@bazel/jasmine": "1.6.0", + "@bazel/karma": "1.6.0", + "@bazel/protractor": "1.6.0", + "@bazel/rollup": "1.6.0", + "@bazel/terser": "1.6.0", + "@bazel/typescript": "1.6.0", "@microsoft/api-extractor": "~7.6.0", "@schematics/angular": "9.0.3", "@types/angular": "^1.6.47", diff --git a/packages/bazel/src/builders/files/WORKSPACE.template b/packages/bazel/src/builders/files/WORKSPACE.template index 4648ee555430a..85bb2ef5dd535 100644 --- a/packages/bazel/src/builders/files/WORKSPACE.template +++ b/packages/bazel/src/builders/files/WORKSPACE.template @@ -15,8 +15,8 @@ workspace( load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -RULES_NODEJS_VERSION = "1.5.0" -RULES_NODEJS_SHA256 = "d0c4bb8b902c1658f42eb5563809c70a06e46015d64057d25560b0eb4bdc9007" +RULES_NODEJS_VERSION = "1.6.0" +RULES_NODEJS_SHA256 = "f9e7b9f42ae202cc2d2ce6d698ccb49a9f7f7ea572a78fd451696d03ef2ee116" http_archive( name = "build_bazel_rules_nodejs", sha256 = RULES_NODEJS_SHA256, diff --git a/packages/bazel/src/schematics/ng-add/index.ts b/packages/bazel/src/schematics/ng-add/index.ts index 5b72330363cfd..95c50a495af28 100644 --- a/packages/bazel/src/schematics/ng-add/index.ts +++ b/packages/bazel/src/schematics/ng-add/index.ts @@ -40,11 +40,11 @@ function addDevDependenciesToPackageJson(options: Schema) { ['@angular/bazel', angularCore.version], ['@bazel/bazel', '2.1.0'], ['@bazel/ibazel', '0.12.3'], - ['@bazel/karma', '1.5.0'], - ['@bazel/protractor', '1.5.0'], - ['@bazel/rollup', '1.5.0'], - ['@bazel/terser', '1.5.0'], - ['@bazel/typescript', '1.5.0'], + ['@bazel/karma', '1.6.0'], + ['@bazel/protractor', '1.6.0'], + ['@bazel/rollup', '1.6.0'], + ['@bazel/terser', '1.6.0'], + ['@bazel/typescript', '1.6.0'], ['history-server', '1.3.1'], ['html-insert-assets', '0.5.0'], ['karma', '4.4.1'], diff --git a/yarn.lock b/yarn.lock index 69ef6520dda2d..ee3a72bc339fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -872,42 +872,42 @@ resolved "https://registry.yarnpkg.com/@bazel/ibazel/-/ibazel-0.12.3.tgz#c8c82647f920cd529c7793c50e087e1a754a5973" integrity sha512-dyx62Uo5kogrxFmqFNpGvbavfr8yjmuQlOyZczOuA60piULwlUsO7Oh3/1OUWKDSXaMMqHhFQfpdl+z0HjI6TQ== -"@bazel/jasmine@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.5.0.tgz#be980cb8e9f82a87036e27f86278bd7a54d74c43" - integrity sha512-r06GTWKxZYs6msPTbIJ+vcHLQke6wMULo3p4w3ecDybRzKq54syjSzlmejIm9wJ8OHrVyRRSvHgvygxCGJfhTA== +"@bazel/jasmine@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-1.6.0.tgz#c469ab8725d9a2e48c0c3c965861ff8add9272ac" + integrity sha512-WtOQDtIMHKTxlp0+FcdrADV6LMrpJV7eEGZippSNFPL5YhwwrPfCSOs5WkooatsrjL5YEszswzqQXFjvC7EZKQ== dependencies: jasmine "~3.5.0" jasmine-core "~3.5.0" jasmine-reporters "~2.3.2" v8-coverage "1.0.9" -"@bazel/karma@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.5.0.tgz#75ea27c3c2a8a7fadbb5c5ab644c3acd3bc22702" - integrity sha512-j5S2Xya4Rr7vK0DzTaZ8FKDHBydtTNldwlx+rihjKJgbEBt76wQM7ucXD6aSA23lC+JM/dPRSKkpIIGeWf2JdQ== +"@bazel/karma@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/karma/-/karma-1.6.0.tgz#98950b71114dd9ec169e6778a35d31ae1f578655" + integrity sha512-9cX0E1SiMWwA70ZMFnMzeqSRn3biduGx03bGV77FSUYKocZpyfU2cOEygYGfxAqHnyM7x4cS8nflRv3+ZE0Aqg== dependencies: tmp "0.1.0" -"@bazel/protractor@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.5.0.tgz#ac92442bf38f5cd718812e4cca41ba2e5ebf1fa5" - integrity sha512-nUwOOUjNGJUU18JiE3sPOBzIul0jvGApEEikntKTLLwQ7w7/1TnOdXDWvHXrXRW3nwit6flWIzEUoFtWgwtCeg== +"@bazel/protractor@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/protractor/-/protractor-1.6.0.tgz#cf095a1dbc038def7031c513a3b87f4e79bedb00" + integrity sha512-gPiRv0oUJbVPpQ9nrwe5vjkffAc8VsYJhpTGgG+8aPdOaTLWgmBP/sy4BdfijU9O1Z/mNYojQCZgMzQz6kAvdg== -"@bazel/rollup@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.5.0.tgz#d0933d167e682470b90f8149eecf4c5bd7511369" - integrity sha512-/FEJfNi9dbbH8oQbf7LHyd0uhGSB0CQQhOpz8d4b2WLnYLhK0NZhoNF4afFjju5kQkrbrOfKaho64BfVxvNppA== +"@bazel/rollup@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-1.6.0.tgz#c0bdad0ad0ba5c5b2e21d1634dc2ce48840ca044" + integrity sha512-MLF7laHX3CSAJH+RbIEVWgnQdz3U8dPkdJWJqiX/z9mUSEgC47LNsMBPKlRy1TpOJOpw1j0vLaJv0qN/bgq9NQ== -"@bazel/terser@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.5.0.tgz#141e1492043231001da3f3ef67b575dd9c2df0be" - integrity sha512-ajT2roE+tiW+xm2YOSfUG55MaUHv0hHYlQneNV1GI3lZoowWPbToOaZiuVza90ulHFHP7lDXn/5MC4UF5/piOQ== +"@bazel/terser@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-1.6.0.tgz#63ccd20dd6c9793e7b3b23fb5ea82b55b3ef6eb2" + integrity sha512-csBrN4XfX/hYTtDVcH/ulVO9K4Ca/IlrCWk5o/l7JBJq/cHoTj5AWIA7PKJ4QgnxXeEjso4CmLFgUMEVKVYV3Q== -"@bazel/typescript@1.5.0": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.5.0.tgz#d69324c08e7dbfe10b21a6fcb7b4d66c71c8d171" - integrity sha512-Vi8n1p35EhxGC22TEnmnVPlyakrALyH2ccVN5J6YeZXE1oWlSMSqQEhXKTjqUfQ3FT76nW1K91AdH4TG3me5nQ== +"@bazel/typescript@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-1.6.0.tgz#8dfd29e71bcf917d5f9cb67f19ac4dcfc9082439" + integrity sha512-vAKuwy1Hgl+t3M3sH/G0oqHRYN35TdENj+0lsCI3x7EbSzyI6cbA3YQrLrlyvdScksqOpZa3PZ3UBGqfJJq2DA== dependencies: protobufjs "6.8.8" semver "5.6.0" From 29122c518b52d4878e243dbb0f2b75163623c979 Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Sat, 11 Apr 2020 09:34:23 -0700 Subject: [PATCH 188/262] style: lint (#36580) PR Close #36580 --- packages/bazel/src/schematics/ng-add/index.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/bazel/src/schematics/ng-add/index.ts b/packages/bazel/src/schematics/ng-add/index.ts index 95c50a495af28..b5bdd6dad0661 100644 --- a/packages/bazel/src/schematics/ng-add/index.ts +++ b/packages/bazel/src/schematics/ng-add/index.ts @@ -9,10 +9,10 @@ */ import {JsonAstObject, parseJsonAst} from '@angular-devkit/core'; -import {Rule, SchematicContext, SchematicsException, Tree, apply, applyTemplates, chain, mergeWith, url} from '@angular-devkit/schematics'; +import {apply, applyTemplates, chain, mergeWith, Rule, SchematicContext, SchematicsException, Tree, url} from '@angular-devkit/schematics'; import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks'; import {getWorkspace, getWorkspacePath} from '@schematics/angular/utility/config'; -import {NodeDependencyType, addPackageJsonDependency, getPackageJsonDependency, removePackageJsonDependency} from '@schematics/angular/utility/dependencies'; +import {addPackageJsonDependency, getPackageJsonDependency, NodeDependencyType, removePackageJsonDependency} from '@schematics/angular/utility/dependencies'; import {findPropertyInAstObject, insertPropertyInAstObjectInOrder} from '@schematics/angular/utility/json-utils'; import {validateProjectName} from '@schematics/angular/utility/validation'; @@ -137,7 +137,7 @@ function updateGitignore() { */ function updateAngularJsonToUseBazelBuilder(options: Schema): Rule { return (host: Tree) => { - const name = options.name !; + const name = options.name!; const workspacePath = getWorkspacePath(host); if (!workspacePath) { throw new Error('Could not find angular.json'); @@ -235,7 +235,8 @@ function backupAngularJson(): Rule { return; } host.create( - `${workspacePath}.bak`, '// This is a backup file of the original angular.json. ' + + `${workspacePath}.bak`, + '// This is a backup file of the original angular.json. ' + 'This file is needed in case you want to revert to the workflow without Bazel.\n\n' + host.read(workspacePath)); }; From d50cb3044355d13dcaf1812e55bc624d771ebddf Mon Sep 17 00:00:00 2001 From: Greg Magolan <gmagolan@gmail.com> Date: Tue, 14 Apr 2020 07:24:17 -0700 Subject: [PATCH 189/262] test: disable failing saucelabs tests (#36620) PR Close #36620 --- packages/elements/test/BUILD.bazel | 11 +++++++++++ packages/forms/test/BUILD.bazel | 9 +++++++++ packages/platform-browser/test/BUILD.bazel | 11 +++++++++++ packages/router/test/BUILD.bazel | 15 +++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/packages/elements/test/BUILD.bazel b/packages/elements/test/BUILD.bazel index c73f50e5bc1c3..29565ccc704cd 100644 --- a/packages/elements/test/BUILD.bazel +++ b/packages/elements/test/BUILD.bazel @@ -43,6 +43,17 @@ karma_web_test_suite( bootstrap = [ ":elements_test_bootstrap_scripts", ], + tags = [ + # disabled on 2020-04-14 due to failure on saucelabs monitor job + # https://app.circleci.com/pipelines/github/angular/angular/13320/workflows/9ca3527a-d448-4a64-880a-fb4de9d1fece/jobs/680645 + # ``` + # IE 10.0.0 (Windows 8.0.0) ERROR + # An error was thrown in afterAll + # Syntax error + # ``` + "fixme-saucelabs-ve", + "fixme-saucelabs-ivy", + ], deps = [ ":test_lib", ], diff --git a/packages/forms/test/BUILD.bazel b/packages/forms/test/BUILD.bazel index f9a3325516b2f..8be33e239ce48 100644 --- a/packages/forms/test/BUILD.bazel +++ b/packages/forms/test/BUILD.bazel @@ -35,6 +35,15 @@ jasmine_node_test( karma_web_test_suite( name = "test_web", + tags = [ + # disabled on 2020-04-14 due to failure on saucelabs monitor job + # https://app.circleci.com/pipelines/github/angular/angular/13320/workflows/9ca3527a-d448-4a64-880a-fb4de9d1fece/jobs/680645 + # ``` + # IE 11.0.0 (Windows 8.1.0.0) template-driven forms integration tests basic functionality should report properties which are written outside of template bindings FAILED + # InvalidStateError: InvalidStateError + # ``` + "fixme-saucelabs-ivy", + ], deps = [ ":test_lib", ], diff --git a/packages/platform-browser/test/BUILD.bazel b/packages/platform-browser/test/BUILD.bazel index 901e3f6c94f4e..0f518dcf68b36 100644 --- a/packages/platform-browser/test/BUILD.bazel +++ b/packages/platform-browser/test/BUILD.bazel @@ -53,6 +53,17 @@ karma_web_test_suite( static_files = [ ":static_assets/test.html", ], + tags = [ + # disabled on 2020-04-14 due to failure on saucelabs monitor job + # https://app.circleci.com/pipelines/github/angular/angular/13320/workflows/9ca3527a-d448-4a64-880a-fb4de9d1fece/jobs/680645 + # ``` + # Chrome 73.0.3683 (Windows 7.0.0) public testing API using the test injector with modules components with template url should allow to createSync components with templateUrl after explicit async compilation FAILED + # Error: Component 'CompWithUrlTemplate' is not resolved: + # IE 10.0.0 (Windows 8.0.0) ERROR: 'Unhandled Promise rejection:', 'Failed to load ./sometemplate.html', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', 'Failed to load ./sometemplate.html', undefined + # Chrome Mobile 74.0.3729 (Android 0.0.0) ERROR: 'Unhandled Promise rejection:', 'Failed to load ./sometemplate.html', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', 'Failed to load ./sometemplate.html', undefined + # ``` + "fixme-saucelabs-ivy", + ], deps = [ ":test_lib", ], diff --git a/packages/router/test/BUILD.bazel b/packages/router/test/BUILD.bazel index bbadc0ccba9c7..20191085f192c 100644 --- a/packages/router/test/BUILD.bazel +++ b/packages/router/test/BUILD.bazel @@ -44,6 +44,21 @@ jasmine_node_test( karma_web_test_suite( name = "test_web", + tags = [ + # disabled on 2020-04-14 due to failure on saucelabs monitor job + # https://app.circleci.com/pipelines/github/angular/angular/13320/workflows/9ca3527a-d448-4a64-880a-fb4de9d1fece/jobs/680645 + # ``` + # Chrome 73.0.3683 (Windows 7.0.0) ERROR: 'ERROR', Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'aa' + # Error: Cannot match any routes. URL Segment: 'aa' + # IE 11.0.0 (Windows 8.1.0.0) ERROR: 'ERROR', Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'aa' + # Error: Cannot match any routes. URL Segment: 'aa' + # Firefox 65.0.0 (Windows 7.0.0) ERROR: 'ERROR', Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'aa' + # IE 10.0.0 (Windows 8.0.0) ERROR: 'ERROR', Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'aa' + # Error: Cannot match any routes. URL Segment: 'aa' + # ``` + "fixme-saucelabs-ve", + "fixme-saucelabs-ivy", + ], deps = [ ":test_lib", ], From 5e80e7e216f2409fac017843e1dd757275c2e8d0 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz <ayazhafiz@lyft.com> Date: Wed, 8 Apr 2020 20:05:32 -0700 Subject: [PATCH 190/262] refactor(language-service): clean up and exports and consolidate types (#36533) PR Close #36533 --- goldens/packages-circular-deps.json | 4 - packages/language-service/language-service.ts | 3 +- packages/language-service/src/common.ts | 27 --- packages/language-service/src/completions.ts | 26 +-- packages/language-service/src/definitions.ts | 7 +- packages/language-service/src/diagnostics.ts | 5 +- .../src/expression_diagnostics.ts | 42 +---- .../language-service/src/expression_type.ts | 10 +- packages/language-service/src/expressions.ts | 58 +++---- packages/language-service/src/hover.ts | 4 +- packages/language-service/src/html_info.ts | 4 - .../language-service/src/language_service.ts | 2 +- .../language-service/src/locate_symbol.ts | 21 +-- packages/language-service/src/template.ts | 59 ------- packages/language-service/src/types.ts | 156 +++++------------- .../language-service/src/typescript_host.ts | 17 +- .../src/typescript_symbols.ts | 35 ++-- packages/language-service/src/utils.ts | 84 ++++++++-- packages/language-service/src/version.ts | 17 -- packages/language-service/test/BUILD.bazel | 1 - packages/language-service/test/mocks.ts | 2 +- .../language-service/test/template_spec.ts | 50 ------ .../test/typescript_symbols_spec.ts | 10 +- packages/language-service/test/utils_spec.ts | 42 ++++- 24 files changed, 252 insertions(+), 434 deletions(-) delete mode 100644 packages/language-service/src/common.ts delete mode 100644 packages/language-service/src/version.ts delete mode 100644 packages/language-service/test/template_spec.ts diff --git a/goldens/packages-circular-deps.json b/goldens/packages-circular-deps.json index 92e8e0aabda3a..aed337abef890 100644 --- a/goldens/packages-circular-deps.json +++ b/goldens/packages-circular-deps.json @@ -1956,10 +1956,6 @@ "packages/forms/src/directives/validators.ts", "packages/forms/src/validators.ts" ], - [ - "packages/language-service/src/common.ts", - "packages/language-service/src/types.ts" - ], [ "packages/language-service/src/completions.ts", "packages/language-service/src/template.ts", diff --git a/packages/language-service/language-service.ts b/packages/language-service/language-service.ts index 1fa65563fca4b..3ddd039a9b365 100644 --- a/packages/language-service/language-service.ts +++ b/packages/language-service/language-service.ts @@ -15,6 +15,5 @@ */ export {createLanguageService} from './src/language_service'; export * from './src/ts_plugin'; -export {Completion, Completions, Declaration, Declarations, Definition, Diagnostic, Diagnostics, Hover, HoverTextSection, LanguageService, LanguageServiceHost, Location, Span, TemplateSource, TemplateSources} from './src/types'; +export {Declaration, Definition, Diagnostic, LanguageService, LanguageServiceHost, Span, TemplateSource} from './src/types'; export {TypeScriptServiceHost, createLanguageServiceFromTypescript} from './src/typescript_host'; -export {VERSION} from './src/version'; diff --git a/packages/language-service/src/common.ts b/packages/language-service/src/common.ts deleted file mode 100644 index 9da46502e5b0b..0000000000000 --- a/packages/language-service/src/common.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CssSelector, Node as HtmlAst, ParseError, Parser, TemplateAst} from '@angular/compiler'; - -import {TemplateSource} from './types'; - -export interface AstResult { - htmlAst: HtmlAst[]; - templateAst: TemplateAst[]; - directive: CompileDirectiveMetadata; - directives: CompileDirectiveSummary[]; - pipes: CompilePipeSummary[]; - parseErrors?: ParseError[]; - expressionParser: Parser; - template: TemplateSource; -} - -export type SelectorInfo = { - selectors: CssSelector[], - map: Map<CssSelector, CompileDirectiveSummary> -}; diff --git a/packages/language-service/src/completions.ts b/packages/language-service/src/completions.ts index 8c139042dbb81..a637eba1da54b 100644 --- a/packages/language-service/src/completions.ts +++ b/packages/language-service/src/completions.ts @@ -10,13 +10,12 @@ import {AbsoluteSourceSpan, AST, AstPath, AttrAst, Attribute, BoundDirectiveProp import {$$, $_, isAsciiLetter, isDigit} from '@angular/compiler/src/chars'; import {ATTR, getBindingDescriptor} from './binding_utils'; -import {AstResult} from './common'; -import {diagnosticInfoFromTemplateInfo, getExpressionScope} from './expression_diagnostics'; +import {getExpressionScope} from './expression_diagnostics'; import {getExpressionCompletions} from './expressions'; import {attributeNames, elementNames, eventNames, propertyNames} from './html_info'; import {InlineTemplate} from './template'; import * as ng from './types'; -import {findTemplateAstAt, getPathToNodeAtPosition, getSelectors, inSpan, isStructuralDirective, spanOf} from './utils'; +import {diagnosticInfoFromTemplateInfo, findTemplateAstAt, getPathToNodeAtPosition, getSelectors, inSpan, isStructuralDirective, spanOf} from './utils'; const HIDDEN_HTML_ELEMENTS: ReadonlySet<string> = new Set(['html', 'script', 'noscript', 'base', 'body', 'title', 'head', 'link']); @@ -56,7 +55,7 @@ function isIdentifierPart(code: number) { * `position`, nothing is returned. */ function getBoundedWordSpan( - templateInfo: AstResult, position: number, ast: HtmlAst|undefined): ts.TextSpan|undefined { + templateInfo: ng.AstResult, position: number, ast: HtmlAst|undefined): ts.TextSpan|undefined { const {template} = templateInfo; const templateSrc = template.source; @@ -127,7 +126,7 @@ function getBoundedWordSpan( } export function getTemplateCompletions( - templateInfo: AstResult, position: number): ng.CompletionEntry[] { + templateInfo: ng.AstResult, position: number): ng.CompletionEntry[] { let result: ng.CompletionEntry[] = []; const {htmlAst, template} = templateInfo; // The templateNode starts at the delimiter character so we add 1 to skip it. @@ -204,7 +203,7 @@ export function getTemplateCompletions( }); } -function attributeCompletions(info: AstResult, path: AstPath<HtmlAst>): ng.CompletionEntry[] { +function attributeCompletions(info: ng.AstResult, path: AstPath<HtmlAst>): ng.CompletionEntry[] { const attr = path.tail; const elem = path.parentOf(attr); if (!(attr instanceof Attribute) || !(elem instanceof Element)) { @@ -258,7 +257,7 @@ function attributeCompletions(info: AstResult, path: AstPath<HtmlAst>): ng.Compl } function attributeCompletionsForElement( - info: AstResult, elementName: string): ng.CompletionEntry[] { + info: ng.AstResult, elementName: string): ng.CompletionEntry[] { const results: ng.CompletionEntry[] = []; if (info.template instanceof InlineTemplate) { @@ -292,7 +291,8 @@ function attributeCompletionsForElement( * @param info Object that contains the template AST * @param htmlPath Path to the HTML node */ -function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.CompletionEntry[] { +function attributeValueCompletions( + info: ng.AstResult, htmlPath: HtmlAstPath): ng.CompletionEntry[] { // Find the corresponding Template AST path. const templatePath = findTemplateAstAt(info.templateAst, htmlPath.position); const visitor = new ExpressionVisitor(info, htmlPath.position, () => { @@ -334,7 +334,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C return visitor.results; } -function elementCompletions(info: AstResult): ng.CompletionEntry[] { +function elementCompletions(info: ng.AstResult): ng.CompletionEntry[] { const results: ng.CompletionEntry[] = [...ANGULAR_ELEMENTS]; if (info.template instanceof InlineTemplate) { @@ -380,7 +380,7 @@ function entityCompletions(value: string, position: number): ng.CompletionEntry[ return result; } -function interpolationCompletions(info: AstResult, position: number): ng.CompletionEntry[] { +function interpolationCompletions(info: ng.AstResult, position: number): ng.CompletionEntry[] { // Look for an interpolation in at the position. const templatePath = findTemplateAstAt(info.templateAst, position); if (!templatePath.tail) { @@ -399,7 +399,7 @@ function interpolationCompletions(info: AstResult, position: number): ng.Complet // code checks for this case and returns element completions if it is detected or undefined // if it is not. function voidElementAttributeCompletions( - info: AstResult, path: AstPath<HtmlAst>): ng.CompletionEntry[] { + info: ng.AstResult, path: AstPath<HtmlAst>): ng.CompletionEntry[] { const tail = path.tail; if (tail instanceof Text) { const match = tail.value.match(/<(\w(\w|\d|-)*:)?(\w(\w|\d|-)*)\s/); @@ -417,7 +417,7 @@ class ExpressionVisitor extends NullTemplateVisitor { private readonly completions = new Map<string, ng.CompletionEntry>(); constructor( - private readonly info: AstResult, private readonly position: number, + private readonly info: ng.AstResult, private readonly position: number, private readonly getExpressionScope: () => ng.SymbolTable) { super(); } @@ -619,7 +619,7 @@ interface AngularAttributes { * @param info * @param elementName */ -function angularAttributes(info: AstResult, elementName: string): AngularAttributes { +function angularAttributes(info: ng.AstResult, elementName: string): AngularAttributes { const {selectors, map: selectorMap} = getSelectors(info); const templateRefs = new Set<string>(); const inputs = new Set<string>(); diff --git a/packages/language-service/src/definitions.ts b/packages/language-service/src/definitions.ts index 417df1f1e1e1d..0164ce2b248e0 100644 --- a/packages/language-service/src/definitions.ts +++ b/packages/language-service/src/definitions.ts @@ -8,11 +8,10 @@ import * as path from 'path'; import * as ts from 'typescript'; // used as value and is provided at runtime -import {AstResult} from './common'; + import {locateSymbols} from './locate_symbol'; -import {getPropertyAssignmentFromValue, isClassDecoratorProperty} from './template'; -import {Span} from './types'; -import {findTightestNode} from './utils'; +import {AstResult, Span} from './types'; +import {findTightestNode, getPropertyAssignmentFromValue, isClassDecoratorProperty} from './utils'; /** * Convert Angular Span to TypeScript TextSpan. Angular Span has 'start' and diff --git a/packages/language-service/src/diagnostics.ts b/packages/language-service/src/diagnostics.ts index 646086c5ef0ce..f5c55ecd82884 100644 --- a/packages/language-service/src/diagnostics.ts +++ b/packages/language-service/src/diagnostics.ts @@ -10,20 +10,17 @@ import {NgAnalyzedModules} from '@angular/compiler'; import * as path from 'path'; import * as ts from 'typescript'; -import {AstResult} from './common'; import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {getTemplateExpressionDiagnostics} from './expression_diagnostics'; import * as ng from './types'; import {TypeScriptServiceHost} from './typescript_host'; import {findPropertyValueOfType, findTightestNode, offsetSpan, spanOf} from './utils'; - - /** * Return diagnostic information for the parsed AST of the template. * @param ast contains HTML and template AST */ -export function getTemplateDiagnostics(ast: AstResult): ng.Diagnostic[] { +export function getTemplateDiagnostics(ast: ng.AstResult): ng.Diagnostic[] { const {parseErrors, templateAst, htmlAst, template} = ast; if (parseErrors && parseErrors.length) { return parseErrors.map(e => { diff --git a/packages/language-service/src/expression_diagnostics.ts b/packages/language-service/src/expression_diagnostics.ts index 81950b5798946..1baa12c50ba21 100644 --- a/packages/language-service/src/expression_diagnostics.ts +++ b/packages/language-service/src/expression_diagnostics.ts @@ -6,33 +6,22 @@ * found in the LICENSE file at https://angular.io/license */ -import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, identifierName, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableAst} from '@angular/compiler'; +import {AST, AstPath, Attribute, BoundDirectivePropertyAst, BoundElementPropertyAst, BoundEventAst, BoundTextAst, CompileDirectiveSummary, CompileTypeMetadata, DirectiveAst, ElementAst, EmbeddedTemplateAst, identifierName, ParseSourceSpan, RecursiveTemplateAstVisitor, ReferenceAst, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableAst} from '@angular/compiler'; -import {AstResult} from './common'; import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {AstType} from './expression_type'; import {BuiltinType, Definition, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; import {findOutputBinding, getPathToNodeAtPosition} from './utils'; -export interface DiagnosticTemplateInfo { - fileName?: string; - offset: number; - query: SymbolQuery; - members: SymbolTable; - htmlAst: Node[]; - templateAst: TemplateAst[]; - source: string; -} - -export function getTemplateExpressionDiagnostics(info: DiagnosticTemplateInfo): ng.Diagnostic[] { +export function getTemplateExpressionDiagnostics(info: ng.DiagnosticTemplateInfo): ng.Diagnostic[] { const visitor = new ExpressionDiagnosticsVisitor( info, (path: TemplateAstPath) => getExpressionScope(info, path)); templateVisitAll(visitor, info.templateAst); return visitor.diagnostics; } -function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { +function getReferences(info: ng.DiagnosticTemplateInfo): SymbolDeclaration[] { const result: SymbolDeclaration[] = []; function processReferences(references: ReferenceAst[]) { @@ -68,7 +57,7 @@ function getReferences(info: DiagnosticTemplateInfo): SymbolDeclaration[] { return result; } -function getDefinitionOf(info: DiagnosticTemplateInfo, ast: TemplateAst): Definition|undefined { +function getDefinitionOf(info: ng.DiagnosticTemplateInfo, ast: TemplateAst): Definition|undefined { if (info.fileName) { const templateOffset = info.offset; return [{ @@ -88,7 +77,7 @@ function getDefinitionOf(info: DiagnosticTemplateInfo, ast: TemplateAst): Defini * @param path template AST path */ function getVarDeclarations( - info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration[] { + info: ng.DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration[] { const results: SymbolDeclaration[] = []; for (let current = path.head; current; current = path.childOf(current)) { if (!(current instanceof EmbeddedTemplateAst)) { @@ -154,7 +143,7 @@ function getVariableTypeFromDirectiveContext( * @param templateElement */ function refinedVariableType( - value: string, mergedTable: SymbolTable, info: DiagnosticTemplateInfo, + value: string, mergedTable: SymbolTable, info: ng.DiagnosticTemplateInfo, templateElement: EmbeddedTemplateAst): Symbol { if (value === '$implicit') { // Special case: ngFor directive @@ -206,7 +195,7 @@ function refinedVariableType( } function getEventDeclaration( - info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration|undefined { + info: ng.DiagnosticTemplateInfo, path: TemplateAstPath): SymbolDeclaration|undefined { const event = path.tail; if (!(event instanceof BoundEventAst)) { // No event available in this context. @@ -241,7 +230,7 @@ function getEventDeclaration( * derived for. */ export function getExpressionScope( - info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolTable { + info: ng.DiagnosticTemplateInfo, path: TemplateAstPath): SymbolTable { let result = info.members; const references = getReferences(info); const variables = getVarDeclarations(info, path); @@ -262,7 +251,7 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor { diagnostics: ng.Diagnostic[] = []; constructor( - private info: DiagnosticTemplateInfo, + private info: ng.DiagnosticTemplateInfo, private getExpressionScope: (path: TemplateAstPath, includeEvent: boolean) => SymbolTable) { super(); this.path = new AstPath<TemplateAst>([]); @@ -386,16 +375,3 @@ function hasTemplateReference(type: CompileTypeMetadata): boolean { function spanOf(sourceSpan: ParseSourceSpan): Span { return {start: sourceSpan.start.offset, end: sourceSpan.end.offset}; } - - -export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTemplateInfo { - return { - fileName: info.template.fileName, - offset: info.template.span.start, - query: info.template.query, - members: info.template.members, - htmlAst: info.htmlAst, - templateAst: info.templateAst, - source: info.template.source, - }; -} diff --git a/packages/language-service/src/expression_type.ts b/packages/language-service/src/expression_type.ts index 8b2b5caeb2a6e..9364d07c52162 100644 --- a/packages/language-service/src/expression_type.ts +++ b/packages/language-service/src/expression_type.ts @@ -12,7 +12,7 @@ import {createDiagnostic, Diagnostic} from './diagnostic_messages'; import {BuiltinType, Signature, Symbol, SymbolQuery, SymbolTable} from './symbols'; import * as ng from './types'; -export interface ExpressionDiagnosticsContext { +interface ExpressionDiagnosticsContext { inEvent?: boolean; } @@ -225,7 +225,7 @@ export class AstType implements AstVisitor { return this.anyType; } - visitImplicitReceiver(ast: ImplicitReceiver): Symbol { + visitImplicitReceiver(_ast: ImplicitReceiver): Symbol { const _this = this; // Return a pseudo-symbol for the implicit receiver. // The members of the implicit receiver are what is defined by the @@ -247,11 +247,11 @@ export class AstType implements AstVisitor { signatures(): Signature[] { return []; }, - selectSignature(types): Signature | + selectSignature(_types): Signature | undefined { return undefined; }, - indexed(argument): Symbol | + indexed(_argument): Symbol | undefined { return undefined; }, @@ -366,7 +366,7 @@ export class AstType implements AstVisitor { return this.getType(ast.value); } - visitQuote(ast: Quote) { + visitQuote(_ast: Quote) { // The type of a quoted expression is any. return this.query.getBuiltinType(BuiltinType.Any); } diff --git a/packages/language-service/src/expressions.ts b/packages/language-service/src/expressions.ts index bc33a1650a3ec..1d27b209ab95f 100644 --- a/packages/language-service/src/expressions.ts +++ b/packages/language-service/src/expressions.ts @@ -53,20 +53,20 @@ export function getExpressionCompletions( // (that is the scope of the implicit receiver) is the right scope as the user is typing the // beginning of an expression. tail.visit({ - visitBinary(ast) {}, - visitChain(ast) {}, - visitConditional(ast) {}, - visitFunctionCall(ast) {}, - visitImplicitReceiver(ast) {}, - visitInterpolation(ast) { + visitBinary(_ast) {}, + visitChain(_ast) {}, + visitConditional(_ast) {}, + visitFunctionCall(_ast) {}, + visitImplicitReceiver(_ast) {}, + visitInterpolation(_ast) { result = undefined; }, - visitKeyedRead(ast) {}, - visitKeyedWrite(ast) {}, - visitLiteralArray(ast) {}, - visitLiteralMap(ast) {}, - visitLiteralPrimitive(ast) {}, - visitMethodCall(ast) {}, + visitKeyedRead(_ast) {}, + visitKeyedWrite(_ast) {}, + visitLiteralArray(_ast) {}, + visitLiteralMap(_ast) {}, + visitLiteralPrimitive(_ast) {}, + visitMethodCall(_ast) {}, visitPipe(ast) { if (position >= ast.exp.span.end && (!ast.args || !ast.args.length || position < (<AST>ast.args[0]).span.start)) { @@ -74,8 +74,8 @@ export function getExpressionCompletions( result = templateInfo.query.getPipes(); } }, - visitPrefixNot(ast) {}, - visitNonNullAssert(ast) {}, + visitPrefixNot(_ast) {}, + visitNonNullAssert(_ast) {}, visitPropertyRead(ast) { const receiverType = getType(ast.receiver); result = receiverType ? receiverType.members() : scope; @@ -84,7 +84,7 @@ export function getExpressionCompletions( const receiverType = getType(ast.receiver); result = receiverType ? receiverType.members() : scope; }, - visitQuote(ast) { + visitQuote(_ast) { // For a quote, return the members of any (if there are any). result = templateInfo.query.getBuiltinType(BuiltinType.Any).members(); }, @@ -127,17 +127,17 @@ export function getExpressionSymbol( // (that is the scope of the implicit receiver) is the right scope as the user is typing the // beginning of an expression. tail.visit({ - visitBinary(ast) {}, - visitChain(ast) {}, - visitConditional(ast) {}, - visitFunctionCall(ast) {}, - visitImplicitReceiver(ast) {}, - visitInterpolation(ast) {}, - visitKeyedRead(ast) {}, - visitKeyedWrite(ast) {}, - visitLiteralArray(ast) {}, - visitLiteralMap(ast) {}, - visitLiteralPrimitive(ast) {}, + visitBinary(_ast) {}, + visitChain(_ast) {}, + visitConditional(_ast) {}, + visitFunctionCall(_ast) {}, + visitImplicitReceiver(_ast) {}, + visitInterpolation(_ast) {}, + visitKeyedRead(_ast) {}, + visitKeyedWrite(_ast) {}, + visitLiteralArray(_ast) {}, + visitLiteralMap(_ast) {}, + visitLiteralPrimitive(_ast) {}, visitMethodCall(ast) { const receiverType = getType(ast.receiver); symbol = receiverType && receiverType.members().get(ast.name); @@ -159,8 +159,8 @@ export function getExpressionSymbol( }; } }, - visitPrefixNot(ast) {}, - visitNonNullAssert(ast) {}, + visitPrefixNot(_ast) {}, + visitNonNullAssert(_ast) {}, visitPropertyRead(ast) { const receiverType = getType(ast.receiver); symbol = receiverType && receiverType.members().get(ast.name); @@ -177,7 +177,7 @@ export function getExpressionSymbol( // ^^^^^^ value; visited separately as a nested AST span = {start, end: start + ast.name.length}; }, - visitQuote(ast) {}, + visitQuote(_ast) {}, visitSafeMethodCall(ast) { const receiverType = getType(ast.receiver); symbol = receiverType && receiverType.members().get(ast.name); diff --git a/packages/language-service/src/hover.ts b/packages/language-service/src/hover.ts index 9d60e13554947..9e30ac861478b 100644 --- a/packages/language-service/src/hover.ts +++ b/packages/language-service/src/hover.ts @@ -8,7 +8,6 @@ import {NgAnalyzedModules} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstResult} from './common'; import {locateSymbols} from './locate_symbol'; import * as ng from './types'; import {inSpan} from './utils'; @@ -27,7 +26,8 @@ const SYMBOL_INTERFACE = ts.SymbolDisplayPartKind[ts.SymbolDisplayPartKind.inter * @param analyzedModules all NgModules in the program. */ export function getTemplateHover( - info: AstResult, position: number, analyzedModules: NgAnalyzedModules): ts.QuickInfo|undefined { + info: ng.AstResult, position: number, analyzedModules: NgAnalyzedModules): ts.QuickInfo| + undefined { const symbolInfo = locateSymbols(info, position)[0]; if (!symbolInfo) { return; diff --git a/packages/language-service/src/html_info.ts b/packages/language-service/src/html_info.ts index dc5315c0c3aca..934c9889813f0 100644 --- a/packages/language-service/src/html_info.ts +++ b/packages/language-service/src/html_info.ts @@ -453,7 +453,3 @@ export function eventNames(elementName: string): string[] { export function propertyNames(elementName: string): string[] { return SchemaInformation.instance.propertiesOf(elementName); } - -export function propertyType(elementName: string, propertyName: string): string { - return SchemaInformation.instance.typeOf(elementName, propertyName); -} diff --git a/packages/language-service/src/language_service.ts b/packages/language-service/src/language_service.ts index c6d1faacfec0b..375a6f39d0abe 100644 --- a/packages/language-service/src/language_service.ts +++ b/packages/language-service/src/language_service.ts @@ -49,7 +49,7 @@ class LanguageServiceImpl implements ng.LanguageService { getCompletionsAtPosition( fileName: string, position: number, - options?: tss.GetCompletionsAtPositionOptions): tss.CompletionInfo|undefined { + _options?: tss.GetCompletionsAtPositionOptions): tss.CompletionInfo|undefined { this.host.getAnalyzedModules(); // same role as 'synchronizeHostData' const ast = this.host.getTemplateAstAtPosition(fileName, position); if (!ast) { diff --git a/packages/language-service/src/locate_symbol.ts b/packages/language-service/src/locate_symbol.ts index 97475ab27bd90..3b6e4024dc55f 100644 --- a/packages/language-service/src/locate_symbol.ts +++ b/packages/language-service/src/locate_symbol.ts @@ -9,17 +9,10 @@ import {AST, Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference, VariableBinding} from '@angular/compiler'; import * as tss from 'typescript/lib/tsserverlibrary'; -import {AstResult} from './common'; -import {diagnosticInfoFromTemplateInfo, getExpressionScope} from './expression_diagnostics'; +import {getExpressionScope} from './expression_diagnostics'; import {getExpressionSymbol} from './expressions'; -import {Definition, DirectiveKind, Span, Symbol} from './types'; -import {findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; - -export interface SymbolInfo { - symbol: Symbol; - span: tss.TextSpan; - staticSymbol?: StaticSymbol; -} +import {AstResult, Definition, DirectiveKind, Span, Symbol, SymbolInfo} from './types'; +import {diagnosticInfoFromTemplateInfo, findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils'; /** * Traverses a template AST and locates symbol(s) at a specified position. @@ -86,8 +79,8 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): }; ast.visit( { - visitNgContent(ast) {}, - visitEmbeddedTemplate(ast) {}, + visitNgContent(_ast) {}, + visitEmbeddedTemplate(_ast) {}, visitElement(ast) { const component = ast.directives.find(d => d.directive.isComponent); if (component) { @@ -113,7 +106,7 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): symbol = ast.value && info.template.query.getTypeSymbol(tokenReference(ast.value)); span = spanOf(ast); }, - visitVariable(ast) {}, + visitVariable(_ast) {}, visitEvent(ast) { if (!attributeValueSymbol(ast.handler)) { symbol = findOutputBinding(ast, path, info.template.query); @@ -158,7 +151,7 @@ function locateSymbol(ast: TemplateAst, path: TemplateAstPath, info: AstResult): } } }, - visitText(ast) {}, + visitText(_ast) {}, visitDirective(ast) { // Need to cast because 'reference' is typed as any staticSymbol = ast.directive.type.reference as StaticSymbol; diff --git a/packages/language-service/src/template.ts b/packages/language-service/src/template.ts index c5f3924bead0b..5e88bf97243d4 100644 --- a/packages/language-service/src/template.ts +++ b/packages/language-service/src/template.ts @@ -132,62 +132,3 @@ export class ExternalTemplate extends BaseTemplate { }; } } - -/** - * Returns a property assignment from the assignment value, or `undefined` if there is no - * assignment. - */ -export function getPropertyAssignmentFromValue(value: ts.Node): ts.PropertyAssignment|undefined { - if (!value.parent || !ts.isPropertyAssignment(value.parent)) { - return; - } - return value.parent; -} - -/** - * Given a decorator property assignment, return the ClassDeclaration node that corresponds to the - * directive class the property applies to. - * If the property assignment is not on a class decorator, no declaration is returned. - * - * For example, - * - * @Component({ - * template: '<div></div>' - * ^^^^^^^^^^^^^^^^^^^^^^^---- property assignment - * }) - * class AppComponent {} - * ^---- class declaration node - * - * @param propAsgn property assignment - */ -export function getClassDeclFromDecoratorProp(propAsgnNode: ts.PropertyAssignment): - ts.ClassDeclaration|undefined { - if (!propAsgnNode.parent || !ts.isObjectLiteralExpression(propAsgnNode.parent)) { - return; - } - const objLitExprNode = propAsgnNode.parent; - if (!objLitExprNode.parent || !ts.isCallExpression(objLitExprNode.parent)) { - return; - } - const callExprNode = objLitExprNode.parent; - if (!callExprNode.parent || !ts.isDecorator(callExprNode.parent)) { - return; - } - const decorator = callExprNode.parent; - if (!decorator.parent || !ts.isClassDeclaration(decorator.parent)) { - return; - } - const classDeclNode = decorator.parent; - return classDeclNode; -} - -/** - * Determines if a property assignment is on a class decorator. - * See `getClassDeclFromDecoratorProperty`, which gets the class the decorator is applied to, for - * more details. - * - * @param prop property assignment - */ -export function isClassDecoratorProperty(propAsgn: ts.PropertyAssignment): boolean { - return !!getClassDeclFromDecoratorProp(propAsgn); -} diff --git a/packages/language-service/src/types.ts b/packages/language-service/src/types.ts index 804a3fbc08d85..c76d83a373815 100644 --- a/packages/language-service/src/types.ts +++ b/packages/language-service/src/types.ts @@ -6,26 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileDirectiveMetadata, NgAnalyzedModules, StaticSymbol} from '@angular/compiler'; +import {CompileDirectiveMetadata, CompileDirectiveSummary, CompilePipeSummary, CssSelector, NgAnalyzedModules, Node as HtmlAst, ParseError, Parser, StaticSymbol, TemplateAst} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstResult} from './common'; -import {BuiltinType, DeclarationKind, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; - -export { - BuiltinType, - DeclarationKind, - Definition, - PipeInfo, - Pipes, - Signature, - Span, - StaticSymbol, - Symbol, - SymbolDeclaration, - SymbolQuery, - SymbolTable -}; +import {Span, Symbol, SymbolQuery, SymbolTable} from './symbols'; + +export {StaticSymbol} from '@angular/compiler'; +export {BuiltinType, Definition, PipeInfo, Pipes, Signature, Span, Symbol, SymbolDeclaration, SymbolQuery, SymbolTable} from './symbols'; /** * The information `LanguageService` needs from the `LanguageServiceHost` to describe the content of @@ -67,15 +54,6 @@ export interface TemplateSource { readonly fileName: string; } -/** - * A sequence of template sources. - * - * A host type; see `LanguageServiceHost`. - * - * @publicApi - */ -export type TemplateSources = TemplateSource[]|undefined; - /** * Error information found getting declaration information * @@ -132,15 +110,6 @@ export interface Declaration { readonly errors: DeclarationError[]; } -/** - * A sequence of declarations. - * - * A host type; see `LanguageServiceHost`. - * - * @publicApi - */ -export type Declarations = Declaration[]; - /** * The host for a `LanguageService`. This provides all the `LanguageService` requires to respond * to the `LanguageService` requests. @@ -178,7 +147,7 @@ export interface LanguageServiceHost { /** * Returns the Angular declarations in the given file. */ - getDeclarations(fileName: string): Declarations; + getDeclarations(fileName: string): Declaration[]; /** * Return a summary of all Angular modules in the project. @@ -196,45 +165,6 @@ export interface LanguageServiceHost { getTemplateAstAtPosition(fileName: string, position: number): AstResult|undefined; } -/** - * An item of the completion result to be displayed by an editor. - * - * A `LanguageService` interface. - * - * @publicApi - */ -export interface Completion { - /** - * The kind of completion. - */ - kind: DeclarationKind; - - /** - * The name of the completion to be displayed - */ - name: string; - - /** - * The key to use to sort the completions for display. - */ - sort: string; -} - -/** - * A sequence of completions. - * - * @deprecated - */ -export type Completions = Completion[]; - -/** - * A file and span. - */ -export interface Location { - fileName: string; - span: Span; -} - /** * The type of Angular directive. Used for QuickInfo in template. */ @@ -312,45 +242,6 @@ export interface Diagnostic { message: string|DiagnosticMessageChain; } -/** - * A sequence of diagnostic message. - * - * @deprecated - */ -export type Diagnostics = Diagnostic[]; - -/** - * A section of hover text. If the text is code then language should be provided. - * Otherwise the text is assumed to be Markdown text that will be sanitized. - */ -export interface HoverTextSection { - /** - * Source code or markdown text describing the symbol a the hover location. - */ - readonly text: string; - - /** - * The language of the source if `text` is a source code fragment. - */ - readonly language?: string; -} - -/** - * Hover information for a symbol at the hover location. - */ -export interface Hover { - /** - * The hover text to display for the symbol at the hover location. If the text includes - * source code, the section will specify which language it should be interpreted as. - */ - readonly text: HoverTextSection[]; - - /** - * The span of source the hover covers. - */ - readonly span: Span; -} - /** * An instance of an Angular language service created by `createLanguageService()`. * @@ -364,3 +255,38 @@ export type LanguageService = Pick< ts.LanguageService, 'getCompletionsAtPosition'|'getDefinitionAndBoundSpan'|'getQuickInfoAtPosition'| 'getSemanticDiagnostics'>; + +/** Information about an Angular template AST. */ +export interface AstResult { + htmlAst: HtmlAst[]; + templateAst: TemplateAst[]; + directive: CompileDirectiveMetadata; + directives: CompileDirectiveSummary[]; + pipes: CompilePipeSummary[]; + parseErrors?: ParseError[]; + expressionParser: Parser; + template: TemplateSource; +} + +/** Information about a directive's selectors. */ +export type SelectorInfo = { + selectors: CssSelector[], + map: Map<CssSelector, CompileDirectiveSummary> +}; + +export interface SymbolInfo { + symbol: Symbol; + span: ts.TextSpan; + staticSymbol?: StaticSymbol; +} + +/** TODO: this should probably be merged with AstResult */ +export interface DiagnosticTemplateInfo { + fileName?: string; + offset: number; + query: SymbolQuery; + members: SymbolTable; + htmlAst: HtmlAst[]; + templateAst: TemplateAst[]; + source: string; +} diff --git a/packages/language-service/src/typescript_host.ts b/packages/language-service/src/typescript_host.ts index 20602d028cef9..836b8cc9569b8 100644 --- a/packages/language-service/src/typescript_host.ts +++ b/packages/language-service/src/typescript_host.ts @@ -6,16 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {analyzeNgModules, AotSummaryResolver, CompileDirectiveSummary, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, I18NHtmlParser, isFormattedError, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser} from '@angular/compiler'; +import {analyzeNgModules, AotSummaryResolver, CompileDirectiveSummary, CompileMetadataResolver, CompileNgModuleMetadata, CompilePipeSummary, CompilerConfig, createOfflineCompileUrlResolver, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, FormattedError, FormattedMessageChain, HtmlParser, isFormattedError, JitSummaryResolver, Lexer, NgAnalyzedModules, NgModuleResolver, Parser, ParseTreeResult, PipeResolver, ResourceLoader, StaticReflector, StaticSymbol, StaticSymbolCache, StaticSymbolResolver, TemplateParser} from '@angular/compiler'; import {SchemaMetadata, ViewEncapsulation, ɵConsole as Console} from '@angular/core'; import * as tss from 'typescript/lib/tsserverlibrary'; -import {AstResult} from './common'; import {createLanguageService} from './language_service'; import {ReflectorHost} from './reflector_host'; -import {ExternalTemplate, getClassDeclFromDecoratorProp, getPropertyAssignmentFromValue, InlineTemplate} from './template'; -import {Declaration, DeclarationError, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types'; -import {findTightestNode, getDirectiveClassLike} from './utils'; +import {ExternalTemplate, InlineTemplate} from './template'; +import {AstResult, Declaration, DeclarationError, DiagnosticMessageChain, LanguageService, LanguageServiceHost, Span, TemplateSource} from './types'; +import {findTightestNode, getClassDeclFromDecoratorProp, getDirectiveClassLike, getPropertyAssignmentFromValue} from './utils'; /** @@ -44,7 +43,7 @@ export class DummyHtmlParser extends HtmlParser { * Avoid loading resources in the language servcie by using a dummy loader. */ export class DummyResourceLoader extends ResourceLoader { - get(url: string): Promise<string> { + get(_url: string): Promise<string> { return Promise.resolve(''); } } @@ -78,10 +77,10 @@ export class TypeScriptServiceHost implements LanguageServiceHost { readonly tsLsHost: tss.LanguageServiceHost, private readonly tsLS: tss.LanguageService) { this.summaryResolver = new AotSummaryResolver( { - loadSummary(filePath: string) { + loadSummary(_filePath: string) { return null; }, - isSourceFile(sourceFilePath: string) { + isSourceFile(_sourceFilePath: string) { return true; }, toSummaryFileName(sourceFilePath: string) { @@ -172,7 +171,7 @@ export class TypeScriptServiceHost implements LanguageServiceHost { this.resolver.clearCache(); const analyzeHost = { - isSourceFile(filePath: string) { + isSourceFile(_filePath: string) { return true; } }; diff --git a/packages/language-service/src/typescript_symbols.ts b/packages/language-service/src/typescript_symbols.ts index 19e5464c444bf..b09cbb8bc79cf 100644 --- a/packages/language-service/src/typescript_symbols.ts +++ b/packages/language-service/src/typescript_symbols.ts @@ -57,8 +57,14 @@ export function getClassMembersFromDeclaration( return new TypeWrapper(type, {node: source, program, checker}).members(); } -export function getClassFromStaticSymbol( - program: ts.Program, type: StaticSymbol): ts.ClassDeclaration|undefined { +export function getPipesTable( + source: ts.SourceFile, program: ts.Program, checker: ts.TypeChecker, + pipes: CompilePipeSummary[]): SymbolTable { + return new PipesTable(pipes, {program, checker, node: source}); +} + +function getClassFromStaticSymbol(program: ts.Program, type: StaticSymbol): ts.ClassDeclaration| + undefined { const source = program.getSourceFile(type.filePath); if (source) { return ts.forEachChild(source, child => { @@ -74,12 +80,6 @@ export function getClassFromStaticSymbol( return undefined; } -export function getPipesTable( - source: ts.SourceFile, program: ts.Program, checker: ts.TypeChecker, - pipes: CompilePipeSummary[]): SymbolTable { - return new PipesTable(pipes, {program, checker, node: source}); -} - class TypeScriptSymbolQuery implements SymbolQuery { private typeCache = new Map<BuiltinType, Symbol>(); private pipesCache: SymbolTable|undefined; @@ -123,7 +123,7 @@ class TypeScriptSymbolQuery implements SymbolQuery { return result || this.getBuiltinType(BuiltinType.Any); } - getArrayType(type: Symbol): Symbol { + getArrayType(_type: Symbol): Symbol { return this.getBuiltinType(BuiltinType.Any); } @@ -222,7 +222,7 @@ function signaturesOf(type: ts.Type, context: TypeContext): Signature[] { return type.getCallSignatures().map(s => new SignatureWrapper(s, context)); } -function selectSignature(type: ts.Type, context: TypeContext, types: Symbol[]): Signature| +function selectSignature(type: ts.Type, context: TypeContext, _types: Symbol[]): Signature| undefined { // TODO: Do a better job of selecting the right signature. TypeScript does not currently support a // Type Relationship API (see https://github.com/angular/vscode-ng-language-service/issues/143). @@ -404,7 +404,7 @@ class SymbolWrapper implements Symbol { return selectSignature(this.tsType, this.context, types); } - indexed(argument: Symbol): Symbol|undefined { + indexed(_argument: Symbol): Symbol|undefined { return undefined; } @@ -475,7 +475,7 @@ class DeclaredSymbol implements Symbol { return this.type.typeArguments(); } - indexed(argument: Symbol): Symbol|undefined { + indexed(_argument: Symbol): Symbol|undefined { return undefined; } } @@ -504,7 +504,7 @@ class SignatureResultOverride implements Signature { } } -export function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { +function toSymbolTableFactory(symbols: ts.Symbol[]): ts.SymbolTable { // ∀ Typescript version >= 2.2, `SymbolTable` is implemented as an ES6 `Map` const result = new Map<string, ts.Symbol>(); for (const symbol of symbols) { @@ -548,8 +548,7 @@ class SymbolTableWrapper implements SymbolTable { * @param context program context * @param type original TypeScript type of entity owning the symbols, if known */ - constructor( - symbols: ts.SymbolTable|ts.Symbol[], private context: TypeContext, private type?: ts.Type) { + constructor(symbols: ts.SymbolTable|ts.Symbol[], private context: TypeContext, type?: ts.Type) { symbols = symbols || []; if (Array.isArray(symbols)) { @@ -727,7 +726,7 @@ class PipeSymbol implements Symbol { return signature; } - indexed(argument: Symbol): Symbol|undefined { + indexed(_argument: Symbol): Symbol|undefined { return undefined; } @@ -786,10 +785,10 @@ function findClassSymbolInContext(type: StaticSymbol, context: TypeContext): ts. class EmptyTable implements SymbolTable { public readonly size: number = 0; - get(key: string): Symbol|undefined { + get(_key: string): Symbol|undefined { return undefined; } - has(key: string): boolean { + has(_key: string): boolean { return false; } values(): Symbol[] { diff --git a/packages/language-service/src/utils.ts b/packages/language-service/src/utils.ts index 36fa25c71ccc4..a73fac69a6bb7 100644 --- a/packages/language-service/src/utils.ts +++ b/packages/language-service/src/utils.ts @@ -9,16 +9,15 @@ import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, identifierName, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, templateVisitAll, visitAll} from '@angular/compiler'; import * as ts from 'typescript'; -import {AstResult, SelectorInfo} from './common'; -import {Span, Symbol, SymbolQuery} from './types'; +import {AstResult, DiagnosticTemplateInfo, SelectorInfo, Span, Symbol, SymbolQuery} from './types'; -export interface SpanHolder { +interface SpanHolder { sourceSpan: ParseSourceSpan; endSourceSpan?: ParseSourceSpan|null; children?: SpanHolder[]; } -export function isParseSourceSpan(value: any): value is ParseSourceSpan { +function isParseSourceSpan(value: any): value is ParseSourceSpan { return value && !!value.start; } @@ -80,14 +79,16 @@ export function getSelectors(info: AstResult): SelectorInfo { return {selectors: results, map}; } -export function isTypescriptVersion(low: string, high?: string) { - const version = ts.version; - - if (version.substring(0, low.length) < low) return false; - - if (high && (version.substring(0, high.length) > high)) return false; - - return true; +export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTemplateInfo { + return { + fileName: info.template.fileName, + offset: info.template.span.start, + query: info.template.query, + members: info.template.members, + htmlAst: info.htmlAst, + templateAst: info.templateAst, + source: info.template.source, + }; } export function findTemplateAstAt(ast: TemplateAst[], position: number): TemplateAstPath { @@ -276,3 +277,62 @@ export function findOutputBinding( } } } + +/** + * Returns a property assignment from the assignment value, or `undefined` if there is no + * assignment. + */ +export function getPropertyAssignmentFromValue(value: ts.Node): ts.PropertyAssignment|undefined { + if (!value.parent || !ts.isPropertyAssignment(value.parent)) { + return; + } + return value.parent; +} + +/** + * Given a decorator property assignment, return the ClassDeclaration node that corresponds to the + * directive class the property applies to. + * If the property assignment is not on a class decorator, no declaration is returned. + * + * For example, + * + * @Component({ + * template: '<div></div>' + * ^^^^^^^^^^^^^^^^^^^^^^^---- property assignment + * }) + * class AppComponent {} + * ^---- class declaration node + * + * @param propAsgn property assignment + */ +export function getClassDeclFromDecoratorProp(propAsgnNode: ts.PropertyAssignment): + ts.ClassDeclaration|undefined { + if (!propAsgnNode.parent || !ts.isObjectLiteralExpression(propAsgnNode.parent)) { + return; + } + const objLitExprNode = propAsgnNode.parent; + if (!objLitExprNode.parent || !ts.isCallExpression(objLitExprNode.parent)) { + return; + } + const callExprNode = objLitExprNode.parent; + if (!callExprNode.parent || !ts.isDecorator(callExprNode.parent)) { + return; + } + const decorator = callExprNode.parent; + if (!decorator.parent || !ts.isClassDeclaration(decorator.parent)) { + return; + } + const classDeclNode = decorator.parent; + return classDeclNode; +} + +/** + * Determines if a property assignment is on a class decorator. + * See `getClassDeclFromDecoratorProperty`, which gets the class the decorator is applied to, for + * more details. + * + * @param prop property assignment + */ +export function isClassDecoratorProperty(propAsgn: ts.PropertyAssignment): boolean { + return !!getClassDeclFromDecoratorProp(propAsgn); +} diff --git a/packages/language-service/src/version.ts b/packages/language-service/src/version.ts deleted file mode 100644 index af66f0fa278a8..0000000000000 --- a/packages/language-service/src/version.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * @module - * @description - * Entry point for all public APIs of the common package. - */ - -import {Version} from '@angular/core'; - -export const VERSION = new Version('0.0.0-PLACEHOLDER'); diff --git a/packages/language-service/test/BUILD.bazel b/packages/language-service/test/BUILD.bazel index c033a2006701c..4dcdc45adb1e5 100644 --- a/packages/language-service/test/BUILD.bazel +++ b/packages/language-service/test/BUILD.bazel @@ -47,7 +47,6 @@ ts_library( "html_info_spec.ts", "language_service_spec.ts", "reflector_host_spec.ts", - "template_spec.ts", "ts_plugin_spec.ts", "typescript_host_spec.ts", "utils_spec.ts", diff --git a/packages/language-service/test/mocks.ts b/packages/language-service/test/mocks.ts index 4fdcc66d12151..4046ae37ad3b9 100644 --- a/packages/language-service/test/mocks.ts +++ b/packages/language-service/test/mocks.ts @@ -14,7 +14,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as ts from 'typescript'; -import {DiagnosticTemplateInfo} from '../src/expression_diagnostics'; +import {DiagnosticTemplateInfo} from '../src/types'; import {getClassMembers, getPipesTable, getSymbolQuery} from '../src/typescript_symbols'; const realFiles = new Map<string, string>(); diff --git a/packages/language-service/test/template_spec.ts b/packages/language-service/test/template_spec.ts deleted file mode 100644 index 1574e3ef34248..0000000000000 --- a/packages/language-service/test/template_spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as ts from 'typescript'; -import {getClassDeclFromDecoratorProp} from '../src/template'; -import {MockTypescriptHost} from './test_utils'; - -describe('getClassDeclFromTemplateNode', () => { - it('should find class declaration in syntax-only mode', () => { - const sourceFile = ts.createSourceFile( - 'foo.ts', ` - @Component({ - template: '<div></div>' - }) - class MyComponent {}`, - ts.ScriptTarget.ES2015, true /* setParentNodes */); - function visit(node: ts.Node): ts.ClassDeclaration|undefined { - if (ts.isPropertyAssignment(node)) { - return getClassDeclFromDecoratorProp(node); - } - return node.forEachChild(visit); - } - const classDecl = sourceFile.forEachChild(visit); - expect(classDecl).toBeTruthy(); - expect(classDecl!.kind).toBe(ts.SyntaxKind.ClassDeclaration); - expect((classDecl as ts.ClassDeclaration).name!.text).toBe('MyComponent'); - }); - - - it('should return class declaration for AppComponent', () => { - const host = new MockTypescriptHost(['/app/app.component.ts']); - const tsLS = ts.createLanguageService(host); - const sourceFile = tsLS.getProgram()!.getSourceFile('/app/app.component.ts'); - expect(sourceFile).toBeTruthy(); - const classDecl = sourceFile!.forEachChild(function visit(node): ts.Node|undefined { - if (ts.isPropertyAssignment(node)) { - return getClassDeclFromDecoratorProp(node); - } - return node.forEachChild(visit); - }); - expect(classDecl).toBeTruthy(); - expect(ts.isClassDeclaration(classDecl!)).toBe(true); - expect((classDecl as ts.ClassDeclaration).name!.text).toBe('AppComponent'); - }); -}); diff --git a/packages/language-service/test/typescript_symbols_spec.ts b/packages/language-service/test/typescript_symbols_spec.ts index 058d49a0dc3f6..7c901f9edaea6 100644 --- a/packages/language-service/test/typescript_symbols_spec.ts +++ b/packages/language-service/test/typescript_symbols_spec.ts @@ -11,7 +11,7 @@ import {ReflectorHost} from '@angular/language-service/src/reflector_host'; import * as ts from 'typescript'; import {BuiltinType, Symbol, SymbolQuery, SymbolTable} from '../src/symbols'; -import {getSymbolQuery, toSymbolTableFactory} from '../src/typescript_symbols'; +import {getSymbolQuery} from '../src/typescript_symbols'; import {DiagnosticContext, MockLanguageServiceHost} from './mocks'; @@ -79,14 +79,6 @@ describe('symbol query', () => { }); }); -describe('toSymbolTableFactory(tsVersion)', () => { - it('should return a Map for versions of TypeScript >= 2.2', () => { - const a = {name: 'a'} as ts.Symbol; - const b = {name: 'b'} as ts.Symbol; - expect(toSymbolTableFactory([a, b]) instanceof Map).toEqual(true); - }); -}); - function appComponentSource(template: string): string { return ` import {Component} from '@angular/core'; diff --git a/packages/language-service/test/utils_spec.ts b/packages/language-service/test/utils_spec.ts index 3d940c36dab93..c4d2159a99df3 100644 --- a/packages/language-service/test/utils_spec.ts +++ b/packages/language-service/test/utils_spec.ts @@ -9,7 +9,8 @@ import * as ng from '@angular/compiler'; import * as ts from 'typescript'; -import {getDirectiveClassLike, getPathToNodeAtPosition} from '../src/utils'; +import {getClassDeclFromDecoratorProp, getDirectiveClassLike, getPathToNodeAtPosition} from '../src/utils'; +import {MockTypescriptHost} from './test_utils'; describe('getDirectiveClassLike', () => { it('should return a directive class', () => { @@ -80,3 +81,42 @@ describe('getPathToNodeAtPosition', () => { expect(path.tail instanceof ng.Attribute).toBe(true); }); }); + +describe('getClassDeclFromTemplateNode', () => { + it('should find class declaration in syntax-only mode', () => { + const sourceFile = ts.createSourceFile( + 'foo.ts', ` + @Component({ + template: '<div></div>' + }) + class MyComponent {}`, + ts.ScriptTarget.ES2015, true /* setParentNodes */); + function visit(node: ts.Node): ts.ClassDeclaration|undefined { + if (ts.isPropertyAssignment(node)) { + return getClassDeclFromDecoratorProp(node); + } + return node.forEachChild(visit); + } + const classDecl = sourceFile.forEachChild(visit); + expect(classDecl).toBeTruthy(); + expect(classDecl!.kind).toBe(ts.SyntaxKind.ClassDeclaration); + expect((classDecl as ts.ClassDeclaration).name!.text).toBe('MyComponent'); + }); + + + it('should return class declaration for AppComponent', () => { + const host = new MockTypescriptHost(['/app/app.component.ts']); + const tsLS = ts.createLanguageService(host); + const sourceFile = tsLS.getProgram()!.getSourceFile('/app/app.component.ts'); + expect(sourceFile).toBeTruthy(); + const classDecl = sourceFile!.forEachChild(function visit(node): ts.Node|undefined { + if (ts.isPropertyAssignment(node)) { + return getClassDeclFromDecoratorProp(node); + } + return node.forEachChild(visit); + }); + expect(classDecl).toBeTruthy(); + expect(ts.isClassDeclaration(classDecl!)).toBe(true); + expect((classDecl as ts.ClassDeclaration).name!.text).toBe('AppComponent'); + }); +}); From 698b0288bee60b8c5926148b79b5b93f454098db Mon Sep 17 00:00:00 2001 From: Joey Perrott <josephperrott@gmail.com> Date: Mon, 13 Apr 2020 16:40:21 -0700 Subject: [PATCH 191/262] build: reformat repo to new clang@1.4.0 (#36613) PR Close #36613 --- .../ts-circular-dependencies/analyzer.ts | 6 +- dev-infra/utils/config.ts | 4 +- goldens/public-api/core/core.d.ts | 2 +- modules/benchmarks/src/bootstrap_ng2.ts | 138 +- modules/benchmarks/src/bootstrap_plain.ts | 32 +- .../change_detection.e2e-spec.ts | 2 +- .../change_detection.perf-spec.ts | 5 +- .../transplanted_views/init.ts | 4 +- .../transplanted_views/transplanted_views.ts | 8 +- .../benchmarks/src/change_detection/util.ts | 2 +- .../src/class_bindings/app.component.ts | 8 +- .../class_bindings.perf-spec.ts | 6 +- .../src/expanding_rows/benchmark.ts | 29 +- .../src/expanding_rows/benchmark_module.ts | 4 +- .../benchmarkable_expanding_row.ts | 6 +- .../src/expanding_rows/expanding_row.ts | 37 +- .../expanding_row_details_caption.ts | 4 +- .../expanding_row_details_content.ts | 9 +- .../src/expanding_rows/expanding_row_host.ts | 39 +- .../expanding_rows/expanding_row_summary.ts | 17 +- .../expanding_rows.perf-spec.ts | 4 +- .../src/expanding_rows/index_aot.ts | 2 +- .../js-web-frameworks.perf-spec.ts | 17 +- .../src/js-web-frameworks/ng2/rows.ts | 6 +- .../src/largeform/largeform.e2e-spec.ts | 3 +- .../src/largeform/largeform.perf-spec.ts | 3 +- .../src/largetable/incremental_dom/table.ts | 4 +- .../src/largetable/largetable.e2e-spec.ts | 2 +- .../src/largetable/largetable.perf-spec.ts | 5 +- .../benchmarks/src/largetable/ng2/table.ts | 13 +- .../src/largetable/ng2_switch/table.ts | 9 +- .../src/largetable/render3/index_aot.ts | 2 +- .../src/largetable/render3/table.ts | 13 +- .../src/old/compiler/compiler_benchmark.ts | 23 +- .../src/old/compiler/selector_benchmark.ts | 4 +- modules/benchmarks/src/old/costs/index.ts | 6 +- modules/benchmarks/src/old/di/di_benchmark.ts | 24 +- .../src/old/naive_infinite_scroll/app.ts | 12 +- .../src/old/naive_infinite_scroll/cells.ts | 8 +- .../src/old/naive_infinite_scroll/common.ts | 120 +- .../old/naive_infinite_scroll/scroll_area.ts | 2 +- .../old/naive_infinite_scroll/scroll_item.ts | 50 +- modules/benchmarks/src/styling/ng2/init.ts | 6 +- modules/benchmarks/src/styling/ng2/styling.ts | 4 +- .../src/styling/styling_perf.spec.ts | 10 +- modules/benchmarks/src/tree/baseline/tree.ts | 2 +- .../src/tree/incremental_dom/tree.ts | 4 +- modules/benchmarks/src/tree/ng1/index.ts | 10 +- modules/benchmarks/src/tree/ng1/tree.ts | 5 +- modules/benchmarks/src/tree/ng2/init.ts | 2 +- modules/benchmarks/src/tree/ng2/tree.ts | 6 +- modules/benchmarks/src/tree/ng2_next/tree.ts | 24 +- .../benchmarks/src/tree/ng2_static/tree.ts | 18 +- .../benchmarks/src/tree/ng2_switch/tree.ts | 5 +- .../benchmarks/src/tree/render3/index_aot.ts | 4 +- modules/benchmarks/src/tree/render3/tree.ts | 6 +- .../src/tree/render3_function/index.ts | 15 +- modules/benchmarks/src/tree/tree.e2e-spec.ts | 4 +- modules/benchmarks/src/tree/tree.perf-spec.ts | 8 +- .../src/tree/tree_detect_changes.e2e-spec.ts | 2 +- .../src/tree/tree_detect_changes.perf-spec.ts | 2 +- modules/benchmarks/src/tree/util.ts | 8 +- modules/benchmarks/src/util.ts | 5 +- .../benchmarks/src/views/views-benchmark.ts | 12 +- .../e2e_test/hello_world/hello_world_spec.ts | 2 - modules/playground/e2e_test/http/http_spec.ts | 5 +- .../playground/e2e_test/jsonp/jsonp_spec.ts | 5 +- .../e2e_test/key_events/key_events_spec.ts | 6 +- .../model_driven_forms_spec.ts | 1 - .../e2e_test/relative_assets/assets_spec.ts | 3 +- .../e2e_test/routing/routing_spec.ts | 3 +- modules/playground/e2e_test/svg/svg_spec.ts | 6 +- .../template_driven_forms_spec.ts | 1 - .../e2e_test/web_workers/input/input_spec.ts | 2 +- .../kitchen_sink/kitchen_sink_spec.ts | 3 +- .../message_broker/message_broker_spec.ts | 3 +- .../web_workers/router/router_spec.ts | 9 +- .../e2e_test/web_workers/todo/todo_spec.ts | 1 - .../e2e_test/zippy_component/zippy_spec.ts | 5 +- .../playground/src/animate/app/animate-app.ts | 4 +- modules/playground/src/async/index.ts | 4 +- modules/playground/src/gestures/index.ts | 12 +- modules/playground/src/hello_world/index.ts | 8 +- modules/playground/src/key_events/index.ts | 4 +- .../src/model_driven_forms/index.ts | 4 +- .../playground/src/order_management/index.ts | 40 +- .../playground/src/person_management/index.ts | 36 +- .../playground/src/routing/app/inbox-app.ts | 6 +- .../src/routing/app/inbox-detail.ts | 7 +- modules/playground/src/sourcemap/index.ts | 4 +- .../src/template_driven_forms/index.ts | 4 +- modules/playground/src/todo/app/TodoStore.ts | 16 +- modules/playground/src/todo/index.ts | 24 +- modules/playground/src/upgrade/index.ts | 6 +- .../src/web_workers/input/index_common.ts | 8 +- .../web_workers/kitchen_sink/index_common.ts | 12 +- .../src/web_workers/message_broker/index.ts | 2 +- .../message_broker/index_common.ts | 4 +- .../src/web_workers/router/index.ts | 2 +- .../src/web_workers/todo/index_common.ts | 24 +- .../web_workers/todo/services/TodoStore.ts | 12 +- .../playground/src/zippy_component/index.ts | 4 +- .../animations/browser/src/dsl/animation.ts | 4 +- .../browser/src/dsl/animation_ast.ts | 4 +- .../browser/src/dsl/animation_ast_builder.ts | 63 +- .../src/dsl/animation_timeline_builder.ts | 62 +- .../src/dsl/animation_timeline_instruction.ts | 6 +- .../src/dsl/animation_transition_expr.ts | 2 +- .../src/dsl/animation_transition_factory.ts | 13 +- .../browser/src/dsl/animation_trigger.ts | 8 +- .../src/dsl/element_instruction_map.ts | 8 +- .../animation_style_normalizer.ts | 4 +- .../animations/browser/src/private_export.ts | 2 +- .../browser/src/render/animation_driver.ts | 12 +- .../render/animation_engine_instruction.ts | 9 +- .../src/render/animation_engine_next.ts | 12 +- .../css_keyframes/css_keyframes_driver.ts | 14 +- .../css_keyframes/css_keyframes_player.ts | 37 +- .../css_keyframes/direct_style_player.ts | 4 +- .../element_animation_style_handler.ts | 17 +- .../animations/browser/src/render/shared.ts | 18 +- .../src/render/special_cased_styles.ts | 4 +- .../src/render/timeline_animation_engine.ts | 11 +- .../src/render/transition_animation_engine.ts | 141 +- .../web_animations/web_animations_driver.ts | 14 +- .../web_animations/web_animations_player.ts | 42 +- packages/animations/browser/src/util.ts | 26 +- .../browser/test/dsl/animation_spec.ts | 49 +- .../test/dsl/animation_trigger_spec.ts | 51 +- .../web_animations_style_normalizer_spec.ts | 6 +- .../css_keyframes_driver_spec.ts | 10 +- .../css_keyframes/direct_style_player_spec.ts | 2 +- .../element_animation_style_handler_spec.ts | 2 +- .../test/render/css_keyframes/shared.ts | 2 +- .../render/timeline_animation_engine_spec.ts | 169 +- .../transition_animation_engine_spec.ts | 1207 ++-- .../web_animations_player_spec.ts | 24 +- packages/animations/browser/test/shared.ts | 4 +- .../testing/src/mock_animation_driver.ts | 24 +- packages/animations/src/animation_metadata.ts | 70 +- packages/animations/src/animations.ts | 2 +- .../src/players/animation_group_player.ts | 32 +- .../src/players/animation_player.ts | 38 +- .../animations/test/animation_player_spec.ts | 4 +- packages/bazel/src/api-extractor/index.ts | 6 +- packages/bazel/src/builders/bazel.ts | 6 +- packages/bazel/src/builders/index.ts | 42 +- packages/bazel/src/ng_package/packager.ts | 34 +- packages/bazel/src/ngc-wrapped/index.ts | 47 +- .../bazel/src/schematics/ng-add/index_spec.ts | 44 +- packages/bazel/src/schematics/ng-new/index.ts | 3 +- .../bazel/src/schematics/ng-new/index_spec.ts | 10 +- .../bazel/src/schematics/ng-new/schema.d.ts | 12 +- .../src/schematics/utility/json-utils.ts | 4 +- .../src/schematics/utility/json-utils_spec.ts | 5 +- .../test/ng_package/common_package.spec.ts | 10 +- .../test/ng_package/core_package.spec.ts | 138 +- .../test/ngc-wrapped/flat_module_test.ts | 7 +- packages/bazel/test/ngc-wrapped/index_test.ts | 1 - .../bazel/test/ngc-wrapped/test_support.ts | 36 +- packages/benchpress/index.ts | 2 +- packages/benchpress/src/metric.ts | 12 +- .../benchpress/src/metric/multi_metric.ts | 10 +- .../benchpress/src/metric/perflog_metric.ts | 41 +- packages/benchpress/src/metric/user_metric.ts | 11 +- packages/benchpress/src/reporter.ts | 4 +- .../src/reporter/console_reporter.ts | 13 +- .../src/reporter/json_file_reporter.ts | 4 +- .../benchpress/src/reporter/multi_reporter.ts | 4 +- packages/benchpress/src/runner.ts | 2 +- packages/benchpress/src/sample_description.ts | 17 +- packages/benchpress/src/sampler.ts | 8 +- packages/benchpress/src/validator.ts | 8 +- .../src/validator/size_validator.ts | 8 +- packages/benchpress/src/web_driver_adapter.ts | 20 +- .../benchpress/src/web_driver_extension.ts | 28 +- .../src/webdriver/chrome_driver_extension.ts | 10 +- .../src/webdriver/firefox_driver_extension.ts | 8 +- .../src/webdriver/ios_driver_extension.ts | 25 +- .../webdriver/selenium_webdriver_adapter.ts | 24 +- .../test/metric/multi_metric_spec.ts | 68 +- .../test/metric/perflog_metric_spec.ts | 1192 ++-- .../test/metric/user_metric_spec.ts | 86 +- .../test/reporter/console_reporter_spec.ts | 11 +- .../test/reporter/json_file_reporter_spec.ts | 8 +- .../test/reporter/multi_reporter_spec.ts | 74 +- packages/benchpress/test/runner_spec.ts | 38 +- packages/benchpress/test/sampler_spec.ts | 38 +- packages/benchpress/test/statistic_spec.ts | 2 - .../benchpress/test/trace_event_factory.ts | 16 +- .../regression_slope_validator_spec.ts | 1 - .../test/validator/size_validator_spec.ts | 1 - .../test/web_driver_extension_spec.ts | 69 +- .../webdriver/chrome_driver_extension_spec.ts | 42 +- .../webdriver/ios_driver_extension_spec.ts | 15 +- packages/common/http/src/client.ts | 739 +- packages/common/http/src/headers.ts | 16 +- packages/common/http/src/interceptor.ts | 4 +- packages/common/http/src/jsonp.ts | 14 +- packages/common/http/src/module.ts | 2 +- packages/common/http/src/params.ts | 65 +- packages/common/http/src/request.ts | 25 +- packages/common/http/src/response.ts | 40 +- packages/common/http/src/xhr.ts | 12 +- packages/common/http/test/client_spec.ts | 8 +- packages/common/http/test/headers_spec.ts | 1 - packages/common/http/test/jsonp_mock.ts | 18 +- packages/common/http/test/module_spec.ts | 12 +- packages/common/http/test/request_spec.ts | 28 +- packages/common/http/test/xhr_mock.ts | 35 +- packages/common/http/test/xsrf_spec.ts | 21 +- packages/common/http/testing/src/backend.ts | 14 +- packages/common/http/testing/src/request.ts | 31 +- .../common/http/testing/test/request_spec.ts | 20 +- packages/common/src/directives/ng_class.ts | 8 +- .../src/directives/ng_component_outlet.ts | 8 +- packages/common/src/directives/ng_for_of.ts | 38 +- packages/common/src/directives/ng_if.ts | 6 +- packages/common/src/directives/ng_plural.ts | 10 +- packages/common/src/directives/ng_style.ts | 2 +- packages/common/src/directives/ng_switch.ts | 13 +- .../src/directives/ng_template_outlet.ts | 2 +- packages/common/src/dom_adapter.ts | 2 +- packages/common/src/i18n/format_date.ts | 8 +- packages/common/src/i18n/format_number.ts | 8 +- packages/common/src/i18n/locale_data.ts | 2 +- packages/common/src/i18n/locale_data_api.ts | 23 +- packages/common/src/i18n/localization.ts | 7 +- .../src/location/hash_location_strategy.ts | 12 +- packages/common/src/location/location.ts | 16 +- .../common/src/location/location_strategy.ts | 16 +- .../common/src/location/platform_location.ts | 58 +- packages/common/src/pipes/async_pipe.ts | 23 +- packages/common/src/pipes/i18n_plural_pipe.ts | 4 +- packages/common/src/pipes/index.ts | 4 +- packages/common/src/pipes/json_pipe.ts | 4 +- packages/common/src/pipes/keyvalue_pipe.ts | 4 +- packages/common/src/pipes/number_pipe.ts | 2 +- packages/common/src/pipes/slice_pipe.ts | 4 +- packages/common/src/viewport_scroller.ts | 4 +- packages/common/test/cookie_spec.ts | 12 +- .../common/test/directives/ng_class_spec.ts | 52 +- .../directives/ng_component_outlet_spec.ts | 38 +- .../common/test/directives/ng_for_spec.ts | 28 +- packages/common/test/directives/ng_if_spec.ts | 10 +- .../common/test/directives/ng_plural_spec.ts | 10 +- .../common/test/directives/ng_style_spec.ts | 12 +- .../common/test/directives/ng_switch_spec.ts | 18 +- .../directives/ng_template_outlet_spec.ts | 25 +- .../test/directives/non_bindable_spec.ts | 11 +- packages/common/test/i18n/format_date_spec.ts | 57 +- .../common/test/i18n/format_number_spec.ts | 11 +- .../common/test/i18n/locale_data_api_spec.ts | 29 +- .../common/test/i18n/localization_spec.ts | 8 +- .../common/test/location/location_spec.ts | 26 +- packages/common/test/pipes/async_pipe_spec.ts | 21 +- .../test/pipes/case_conversion_pipes_spec.ts | 58 +- packages/common/test/pipes/date_pipe_spec.ts | 41 +- .../test/pipes/i18n_plural_pipe_spec.ts | 14 +- .../test/pipes/i18n_select_pipe_spec.ts | 13 +- packages/common/test/pipes/json_pipe_spec.ts | 12 +- .../common/test/pipes/keyvalue_pipe_spec.ts | 6 +- .../common/test/pipes/number_pipe_spec.ts | 22 +- packages/common/test/pipes/slice_pipe_spec.ts | 32 +- packages/common/test/spies.ts | 4 +- .../common/test/viewport_scroller_spec.ts | 14 +- packages/common/testing/src/location_mock.ts | 28 +- .../testing/src/mock_location_strategy.ts | 24 +- .../testing/src/mock_platform_location.ts | 54 +- .../upgrade/src/location_upgrade_module.ts | 2 +- packages/common/upgrade/src/params.ts | 8 +- packages/common/upgrade/src/utils.ts | 2 +- packages/common/upgrade/test/upgrade.spec.ts | 84 +- .../test/upgrade_location_test_module.ts | 2 +- packages/compiler-cli/integrationtest/test.js | 4 +- .../google3/explicitQueryTimingRule.ts | 4 +- .../google3/noMissingInjectableRule.ts | 4 +- .../google3/rendererToRenderer2Rule.ts | 4 +- ...decoratedClassesWithDecoratedFieldsRule.ts | 4 +- .../definition_collector.ts | 2 +- .../google3/tslint_update_recorder.ts | 3 +- .../missing-injectable/transform.ts | 23 +- .../module-with-providers/collector.ts | 3 +- .../module-with-providers/transform.ts | 10 +- .../renderer-to-renderer2/helpers.ts | 20 +- .../renderer-to-renderer2/migration.ts | 8 +- .../migrations/renderer-to-renderer2/util.ts | 5 +- .../angular/directive_inputs.ts | 2 +- .../template_strategy/template_strategy.ts | 20 +- .../strategies/timing-strategy.ts | 3 +- .../declaration_usage_visitor.ts | 8 +- .../usage_strategy/super_class_context.ts | 2 +- .../usage_strategy/template_usage_visitor.ts | 12 +- .../usage_strategy/usage_strategy.ts | 8 +- .../migrations/static-queries/transform.ts | 9 +- .../google3/tslint_update_recorder.ts | 3 +- .../transform.ts | 16 +- .../convert_directive_metadata.ts | 2 +- .../decorator_rewrite/decorator_rewriter.ts | 2 +- .../import_rewrite_visitor.ts | 6 +- .../undecorated-classes-with-di/index.ts | 6 +- .../ng_declaration_collector.ts | 2 +- .../undecorated-classes-with-di/transform.ts | 6 +- .../test/dynamic_queries_migration_spec.ts | 14 +- .../test/google3/dynamic_queries_spec.ts | 9 +- .../explicit_query_timing_rule_spec.ts | 5 +- .../google3/missing_injectable_rule_spec.ts | 12 +- ..._template_variable_assignment_rule_spec.ts | 4 +- .../google3/renderer_to_renderer2_spec.ts | 13 +- ...ated_classes_with_decorated_fields_spec.ts | 27 +- .../schematics/test/line_mappings_spec.ts | 1 - .../test/missing_injectable_migration_spec.ts | 64 +- .../module_with_providers_migration_spec.ts | 16 +- .../test/move_document_migration_spec.ts | 12 +- .../test/project_tsconfig_paths_spec.ts | 10 +- .../renderer_to_renderer2_migration_spec.ts | 120 +- .../static_queries_migration_template_spec.ts | 85 +- .../static_queries_migration_usage_spec.ts | 176 +- .../template_var_assignment_migration_spec.ts | 22 +- ...ecorated_classes_with_di_migration_spec.ts | 243 +- .../core/schematics/utils/import_manager.ts | 16 +- .../schematics/utils/ng_component_template.ts | 8 +- .../core/schematics/utils/ng_decorators.ts | 8 +- .../utils/project_tsconfig_paths.ts | 2 +- .../schematics/utils/schematics_prompt.ts | 2 +- .../schematics/utils/typescript/decorators.ts | 3 +- .../schematics/utils/typescript/functions.ts | 2 +- packages/core/src/application_init.ts | 14 +- packages/core/src/application_module.ts | 11 +- packages/core/src/application_ref.ts | 70 +- .../src/change_detection/change_detection.ts | 16 +- .../change_detection/change_detection_util.ts | 16 +- .../differs/default_iterable_differ.ts | 43 +- .../differs/default_keyvalue_differ.ts | 14 +- .../differs/iterable_differs.ts | 20 +- .../differs/keyvalue_differs.ts | 4 +- .../src/change_detection/pipe_transform.ts | 4 +- packages/core/src/codegen_private_exports.ts | 2 +- .../src/compiler/compiler_facade_interface.ts | 14 +- packages/core/src/core_private_export.ts | 4 +- .../core/src/core_render3_private_export.ts | 437 +- packages/core/src/debug/debug_node.ts | 109 +- packages/core/src/di/forward_ref.ts | 8 +- packages/core/src/di/injectable.ts | 22 +- packages/core/src/di/injection_token.ts | 11 +- packages/core/src/di/injector.ts | 17 +- .../core/src/di/injector_compatibility.ts | 47 +- packages/core/src/di/interface/defs.ts | 25 +- packages/core/src/di/interface/provider.ts | 8 +- packages/core/src/di/jit/environment.ts | 6 +- packages/core/src/di/jit/injectable.ts | 4 +- packages/core/src/di/jit/util.ts | 4 +- packages/core/src/di/metadata.ts | 12 +- packages/core/src/di/r3_injector.ts | 54 +- packages/core/src/di/reflective_errors.ts | 5 +- packages/core/src/di/reflective_injector.ts | 10 +- packages/core/src/di/reflective_key.ts | 10 +- packages/core/src/di/reflective_provider.ts | 8 +- packages/core/src/di/util.ts | 7 +- packages/core/src/event_emitter.ts | 43 +- packages/core/src/i18n/locale_data_api.ts | 11 +- .../core/src/interface/lifecycle_hooks.ts | 12 +- packages/core/src/interface/simple_change.ts | 8 +- packages/core/src/interface/type.ts | 10 +- packages/core/src/linker.ts | 4 +- packages/core/src/linker/compiler.ts | 6 +- .../src/linker/component_factory_resolver.ts | 8 +- packages/core/src/linker/element_ref.ts | 4 +- .../src/linker/ng_module_factory_loader.ts | 4 +- .../linker/ng_module_factory_registration.ts | 2 +- packages/core/src/linker/query_list.ts | 40 +- .../system_js_ng_module_factory_loader.ts | 4 +- packages/core/src/metadata/di.ts | 25 +- packages/core/src/metadata/directives.ts | 138 +- packages/core/src/metadata/ng_module.ts | 8 +- .../core/src/metadata/resource_loading.ts | 2 +- packages/core/src/metadata/schema.ts | 4 +- packages/core/src/platform_core_providers.ts | 2 +- packages/core/src/r3_symbols.ts | 2 +- .../src/reflection/reflection_capabilities.ts | 31 +- packages/core/src/reflection/reflector.ts | 28 +- packages/core/src/render/api.ts | 2 +- packages/core/src/render3/assert.ts | 11 +- packages/core/src/render3/component.ts | 24 +- packages/core/src/render3/component_ref.ts | 23 +- .../core/src/render3/context_discovery.ts | 9 +- packages/core/src/render3/definition.ts | 324 +- packages/core/src/render3/di.ts | 54 +- packages/core/src/render3/empty.ts | 12 +- packages/core/src/render3/errors.ts | 3 +- .../features/copy_definition_feature.ts | 8 +- .../features/inherit_definition_feature.ts | 2 +- .../render3/features/ng_onchanges_feature.ts | 12 +- packages/core/src/render3/global_utils_api.ts | 2 +- packages/core/src/render3/hooks.ts | 28 +- packages/core/src/render3/i18n.ts | 78 +- packages/core/src/render3/index.ts | 97 +- .../core/src/render3/instructions/advance.ts | 30 +- .../src/render3/instructions/attribute.ts | 2 +- .../instructions/attribute_interpolation.ts | 42 +- .../render3/instructions/change_detection.ts | 2 +- .../src/render3/instructions/container.ts | 26 +- packages/core/src/render3/instructions/di.ts | 6 +- .../core/src/render3/instructions/element.ts | 30 +- .../render3/instructions/element_container.ts | 19 +- .../src/render3/instructions/embedded_view.ts | 6 +- .../src/render3/instructions/host_property.ts | 6 +- .../src/render3/instructions/interpolation.ts | 32 +- .../core/src/render3/instructions/listener.ts | 50 +- .../src/render3/instructions/projection.ts | 10 +- .../core/src/render3/instructions/property.ts | 4 +- .../instructions/property_interpolation.ts | 29 +- .../instructions/style_prop_interpolation.ts | 18 +- .../core/src/render3/instructions/styling.ts | 71 +- .../core/src/render3/instructions/text.ts | 7 +- .../core/src/render3/interfaces/definition.ts | 42 +- .../core/src/render3/interfaces/document.ts | 4 +- packages/core/src/render3/interfaces/i18n.ts | 8 +- .../core/src/render3/interfaces/injector.ts | 35 +- packages/core/src/render3/interfaces/node.ts | 48 +- .../core/src/render3/interfaces/player.ts | 16 +- .../core/src/render3/interfaces/projection.ts | 4 +- packages/core/src/render3/interfaces/query.ts | 2 +- .../core/src/render3/interfaces/renderer.ts | 21 +- .../core/src/render3/interfaces/styling.ts | 30 +- .../src/render3/interfaces/type_checks.ts | 10 +- packages/core/src/render3/jit/directive.ts | 18 +- packages/core/src/render3/jit/module.ts | 70 +- packages/core/src/render3/jit/pipe.ts | 2 +- packages/core/src/render3/metadata.ts | 75 +- packages/core/src/render3/ng_module_ref.ts | 33 +- .../core/src/render3/node_selector_matcher.ts | 11 +- packages/core/src/render3/node_util.ts | 2 +- packages/core/src/render3/pipe.ts | 29 +- packages/core/src/render3/pure_function.ts | 23 +- packages/core/src/render3/query.ts | 78 +- packages/core/src/render3/state.ts | 61 +- .../core/src/render3/styling/class_differ.ts | 12 +- .../src/render3/styling/static_styling.ts | 12 +- .../src/render3/styling/style_binding_list.ts | 26 +- .../src/render3/styling/styling_parser.ts | 2 +- packages/core/src/render3/util/attrs_utils.ts | 12 +- .../core/src/render3/util/discovery_utils.ts | 19 +- .../core/src/render3/util/injector_utils.ts | 2 +- packages/core/src/render3/util/misc_utils.ts | 18 +- .../src/render3/util/view_traversal_utils.ts | 10 +- packages/core/src/render3/util/view_utils.ts | 13 +- .../src/render3/view_engine_compatibility.ts | 50 +- packages/core/src/render3/view_ref.ts | 60 +- packages/core/src/sanitization/bypass.ts | 22 +- .../core/src/sanitization/html_sanitizer.ts | 30 +- packages/core/src/sanitization/inert_body.ts | 12 +- .../core/src/sanitization/sanitization.ts | 11 +- packages/core/src/testability/testability.ts | 30 +- packages/core/src/util/WrappedValue.ts | 16 +- packages/core/src/util/array_utils.ts | 20 +- packages/core/src/util/char_code.ts | 12 +- packages/core/src/util/decorators.ts | 7 +- packages/core/src/util/empty.ts | 12 +- packages/core/src/util/errors.ts | 4 +- packages/core/src/util/lang.ts | 2 +- packages/core/src/util/microtask.ts | 4 +- packages/core/src/util/stringify.ts | 2 +- packages/core/src/view/element.ts | 62 +- packages/core/src/view/entrypoint.ts | 5 +- packages/core/src/view/errors.ts | 3 +- packages/core/src/view/index.ts | 4 +- packages/core/src/view/ng_content.ts | 9 +- packages/core/src/view/ng_module.ts | 16 +- packages/core/src/view/provider.ts | 84 +- packages/core/src/view/pure_expression.ts | 27 +- packages/core/src/view/query.ts | 27 +- packages/core/src/view/refs.ts | 94 +- packages/core/src/view/services.ts | 115 +- packages/core/src/view/text.ts | 16 +- packages/core/src/view/types.ts | 98 +- packages/core/src/view/util.ts | 66 +- packages/core/src/view/view.ts | 89 +- packages/core/src/view/view_attach.ts | 23 +- packages/core/src/zone/ng_zone.ts | 56 +- .../core/test/acceptance/bootstrap_spec.ts | 37 +- .../test/acceptance/change_detection_spec.ts | 227 +- .../acceptance/common_integration_spec.ts | 6 +- .../core/test/acceptance/component_spec.ts | 32 +- packages/core/test/acceptance/content_spec.ts | 36 +- .../copy_definition_feature_spec.ts | 10 +- packages/core/test/acceptance/debug_spec.ts | 8 +- packages/core/test/acceptance/di_spec.ts | 325 +- .../core/test/acceptance/directive_spec.ts | 82 +- .../test/acceptance/discover_utils_spec.ts | 64 +- .../test/acceptance/embedded_views_spec.ts | 10 +- packages/core/test/acceptance/exports_spec.ts | 12 +- .../core/test/acceptance/host_binding_spec.ts | 167 +- packages/core/test/acceptance/i18n_spec.ts | 114 +- .../inherit_definition_feature_spec.ts | 952 ++- .../core/test/acceptance/integration_spec.ts | 191 +- .../core/test/acceptance/lifecycle_spec.ts | 951 ++- .../core/test/acceptance/listener_spec.ts | 53 +- .../core/test/acceptance/ng_module_spec.ts | 28 +- .../test/acceptance/ngdevmode_debug_spec.ts | 3 +- packages/core/test/acceptance/outputs_spec.ts | 84 +- packages/core/test/acceptance/pipe_spec.ts | 99 +- .../test/acceptance/property_binding_spec.ts | 4 - .../acceptance/property_interpolation_spec.ts | 10 +- .../test/acceptance/pure_function_spec.ts | 44 +- packages/core/test/acceptance/query_spec.ts | 189 +- .../test/acceptance/renderer_factory_spec.ts | 24 +- packages/core/test/acceptance/styling_spec.ts | 202 +- .../core/test/acceptance/template_ref_spec.ts | 6 +- packages/core/test/acceptance/text_spec.ts | 6 +- .../acceptance/view_container_ref_spec.ts | 215 +- .../test/acceptance/view_insertion_spec.ts | 100 +- .../core/test/acceptance/view_ref_spec.ts | 7 +- .../animation/animation_integration_spec.ts | 6008 ++++++++--------- .../animation_router_integration_spec.ts | 931 +-- ...s_keyframes_animations_integration_spec.ts | 619 +- ...ns_with_web_animations_integration_spec.ts | 783 ++- packages/core/test/application_init_spec.ts | 16 +- packages/core/test/application_module_spec.ts | 5 +- .../test/application_ref_integration_spec.ts | 15 +- packages/core/test/application_ref_spec.ts | 124 +- .../test/bundling/animation_world/index.ts | 19 +- .../cyclic_import/integration_spec.ts | 5 +- .../bundling/hello_world/treeshaking_spec.ts | 15 +- .../hello_world_r2/treeshaking_spec.ts | 10 +- .../bundling/injection/treeshaking_spec.ts | 5 +- packages/core/test/bundling/todo/index.ts | 42 +- .../core/test/bundling/todo/todo_e2e_spec.ts | 6 +- .../core/test/bundling/todo_i18n/index.ts | 54 +- .../test/bundling/todo_i18n/todo_e2e_spec.ts | 8 +- packages/core/test/bundling/todo_r2/index.ts | 70 +- .../test/bundling/todo_r2/todo_e2e_spec.ts | 4 +- .../change_detector_util_spec.ts | 5 +- .../differs/default_iterable_differ_spec.ts | 91 +- .../differs/default_keyvalue_differ_spec.ts | 7 +- .../core/test/change_detection/iterable.ts | 8 +- packages/core/test/change_detection/util.ts | 11 +- packages/core/test/component_fixture_spec.ts | 49 +- packages/core/test/debug/debug_node_spec.ts | 133 +- packages/core/test/dev_mode_spec.ts | 4 +- packages/core/test/di/injector_spec.ts | 5 +- packages/core/test/di/r3_injector_spec.ts | 122 +- .../core/test/di/reflective_injector_spec.ts | 723 +- packages/core/test/di/reflective_key_spec.ts | 20 +- packages/core/test/di/static_injector_spec.ts | 55 +- .../directive_lifecycle_integration_spec.ts | 42 +- packages/core/test/dom/dom_adapter_spec.ts | 9 +- packages/core/test/dom/shim_spec.ts | 2 - packages/core/test/error_handler_spec.ts | 97 +- packages/core/test/event_emitter_spec.ts | 45 +- packages/core/test/fake_async_spec.ts | 104 +- .../core/test/forward_ref_integration_spec.ts | 12 +- .../core/test/i18n/locale_data_api_spec.ts | 38 +- .../entry_components_integration_spec.ts | 29 +- .../linker/inheritance_integration_spec.ts | 6 +- packages/core/test/linker/integration_spec.ts | 266 +- .../linker/jit_summaries_integration_spec.ts | 12 +- .../linker/ng_container_integration_spec.ts | 33 +- .../test/linker/ng_module_integration_spec.ts | 151 +- .../linker/projection_integration_spec.ts | 50 +- .../test/linker/query_integration_spec.ts | 220 +- packages/core/test/linker/query_list_spec.ts | 20 +- .../linker/regression_integration_spec.ts | 96 +- .../test/linker/security_integration_spec.ts | 28 +- .../source_map_integration_node_only_spec.ts | 72 +- .../system_ng_module_factory_loader_spec.ts | 18 +- .../linker/view_injector_integration_spec.ts | 96 +- packages/core/test/metadata/di_spec.ts | 11 +- .../test/metadata/resource_loading_spec.ts | 34 +- .../core/test/reflection/reflector_spec.ts | 70 +- packages/core/test/render3/basic_perf.ts | 36 +- .../test/render3/change_detection_spec.ts | 194 +- packages/core/test/render3/common_with_def.ts | 5 +- .../core/test/render3/component_ref_spec.ts | 12 +- packages/core/test/render3/component_spec.ts | 256 +- .../core/test/render3/control_flow_spec.ts | 168 +- packages/core/test/render3/di_spec.ts | 36 +- packages/core/test/render3/i18n_spec.ts | 69 +- .../core/test/render3/imported_renderer2.ts | 8 +- .../render3/instructions/lview_debug_spec.ts | 8 +- .../test/render3/instructions/shared_spec.ts | 2 +- .../test/render3/instructions/styling_spec.ts | 97 +- .../core/test/render3/instructions_spec.ts | 192 +- .../core/test/render3/integration_spec.ts | 530 +- packages/core/test/render3/ivy/jit_spec.ts | 27 +- .../core/test/render3/jit/directive_spec.ts | 10 +- .../core/test/render3/jit_environment_spec.ts | 4 +- packages/core/test/render3/lifecycle_spec.ts | 12 +- packages/core/test/render3/listeners_spec.ts | 536 +- packages/core/test/render3/metadata_spec.ts | 10 +- packages/core/test/render3/outputs_spec.ts | 17 +- .../perf/directive_instantiate/index.ts | 2 +- .../index.ts | 12 +- .../render3/perf/element_text_create/index.ts | 2 +- .../test/render3/perf/host_binding/index.ts | 23 +- .../core/test/render3/perf/listeners/index.ts | 2 +- .../core/test/render3/perf/micro_bench.ts | 17 +- .../test/render3/perf/ng_template/index.ts | 2 +- .../core/test/render3/perf/noop_renderer.ts | 38 +- .../test/render3/perf/noop_renderer_spec.ts | 2 +- packages/core/test/render3/perf/setup.ts | 14 +- packages/core/test/render3/perf/shared.ts | 4 +- .../render3/perf/view_destroy_hook/index.ts | 2 +- packages/core/test/render3/pipe_spec.ts | 31 +- packages/core/test/render3/providers_spec.ts | 907 ++- .../core/test/render3/pure_function_spec.ts | 11 +- packages/core/test/render3/query_spec.ts | 419 +- packages/core/test/render3/render_util.ts | 86 +- .../test/render3/renderer_factory_spec.ts | 46 +- .../styling_next/static_styling_spec.ts | 4 +- .../styling_next/style_binding_list_spec.ts | 26 +- packages/core/test/render3/testing_spec.ts | 2 +- .../test/render3/view_container_ref_spec.ts | 192 +- packages/core/test/render3/view_utils_spec.ts | 2 +- .../test/sanitization/html_sanitizer_spec.ts | 25 +- .../test/sanitization/sanitization_spec.ts | 6 +- .../test/sanitization/style_sanitizer_spec.ts | 25 +- .../test/sanitization/url_sanitizer_spec.ts | 5 +- packages/core/test/spies.ts | 4 +- .../test/strict_types/inheritance_spec.ts | 4 +- packages/core/test/test_bed_async_spec.ts | 9 +- packages/core/test/test_bed_spec.ts | 67 +- .../core/test/testability/testability_spec.ts | 50 +- packages/core/test/testing_internal_spec.ts | 34 +- packages/core/test/util/array_utils_spec.ts | 14 +- packages/core/test/util/decorators_spec.ts | 3 +- packages/core/test/util/global_spec.ts | 4 +- packages/core/test/util/lang_spec.ts | 4 +- packages/core/test/util/stringify_spec.ts | 5 +- packages/core/test/view/anchor_spec.ts | 5 +- .../core/test/view/component_view_spec.ts | 67 +- packages/core/test/view/element_spec.ts | 19 +- packages/core/test/view/embedded_view_spec.ts | 25 +- packages/core/test/view/helper.ts | 20 +- packages/core/test/view/ng_content_spec.ts | 36 +- packages/core/test/view/ng_module_spec.ts | 108 +- packages/core/test/view/provider_spec.ts | 111 +- .../core/test/view/pure_expression_spec.ts | 14 +- packages/core/test/view/query_spec.ts | 35 +- packages/core/test/view/services_spec.ts | 3 +- packages/core/test/view/text_spec.ts | 9 +- packages/core/test/view/view_def_spec.ts | 8 +- packages/core/test/zone/ng_zone_spec.ts | 163 +- packages/core/testing/src/async_fallback.ts | 6 +- .../core/testing/src/async_test_completer.ts | 16 +- .../core/testing/src/component_fixture.ts | 38 +- packages/core/testing/src/logger.ts | 16 +- .../core/testing/src/metadata_overrider.ts | 7 +- packages/core/testing/src/ng_zone_mock.ts | 16 +- packages/core/testing/src/r3_test_bed.ts | 32 +- .../core/testing/src/r3_test_bed_compiler.ts | 49 +- packages/core/testing/src/resolvers.ts | 22 +- packages/core/testing/src/styling.ts | 10 +- packages/core/testing/src/test_bed.ts | 48 +- packages/core/testing/src/test_bed_common.ts | 2 +- packages/core/testing/src/test_compiler.ts | 16 +- packages/core/testing/src/testing_internal.ts | 26 +- packages/elements/public_api.ts | 2 +- packages/elements/schematics/ng-add/index.ts | 6 +- .../elements/schematics/ng-add/index_spec.ts | 10 +- .../src/component-factory-strategy.ts | 14 +- .../elements/src/create-custom-element.ts | 30 +- packages/elements/src/utils.ts | 10 +- .../test/component-factory-strategy_spec.ts | 35 +- .../test/create-custom-element_spec.ts | 26 +- packages/elements/test/slots_spec.ts | 28 +- .../location/ts/hash_location_component.ts | 4 +- .../location/ts/path_location_component.ts | 4 +- .../ts/e2e_test/ngComponentOutlet_spec.ts | 2 +- .../common/ngIf/ts/e2e_test/ngIf_spec.ts | 3 +- packages/examples/common/ngIf/ts/module.ts | 10 +- .../ts/e2e_test/ngTemplateOutlet_spec.ts | 3 +- .../examples/common/pipes/ts/async_pipe.ts | 14 +- .../common/pipes/ts/e2e_test/pipe_spec.ts | 3 +- .../common/pipes/ts/lowerupper_pipe.ts | 6 +- .../animation/ts/dsl/animation_example.ts | 17 +- .../ts/dsl/e2e_test/animation_example_spec.ts | 3 +- .../debug/ts/debug_element/debug_element.ts | 2 +- .../ts/contentChild/content_child_example.ts | 8 +- .../di/ts/contentChild/content_child_howto.ts | 2 +- .../e2e_test/content_child_spec.ts | 3 +- .../content_children_example.ts | 10 +- .../contentChildren/content_children_howto.ts | 2 +- .../e2e_test/content_children_spec.ts | 3 +- packages/examples/core/di/ts/injector_spec.ts | 2 +- packages/examples/core/di/ts/metadata_spec.ts | 12 +- packages/examples/core/di/ts/provider_spec.ts | 9 +- .../ts/viewChild/e2e_test/view_child_spec.ts | 3 +- .../di/ts/viewChild/view_child_example.ts | 10 +- .../core/di/ts/viewChild/view_child_howto.ts | 2 +- .../e2e_test/view_children_spec.ts | 3 +- .../ts/viewChildren/view_children_example.ts | 16 +- .../di/ts/viewChildren/view_children_howto.ts | 2 +- .../e2e_test/testability_example_spec.ts | 8 +- .../ts/whenStable/testability_example.ts | 4 +- .../examples/core/testing/ts/fake_async.ts | 4 +- .../core/ts/change_detect/change-detection.ts | 12 +- .../examples/core/ts/metadata/directives.ts | 8 +- .../core/ts/metadata/lifecycle_hooks_spec.ts | 247 +- .../examples/core/ts/metadata/metadata.ts | 8 +- .../core/ts/prod_mode/prod_mode_example.ts | 3 +- .../formBuilder/e2e_test/form_builder_spec.ts | 4 +- .../e2e_test/nested_form_array_spec.ts | 4 +- .../nested_form_array_example.ts | 12 +- .../e2e_test/nested_form_group_spec.ts | 4 +- .../forms/ts/nestedFormGroup/module.ts | 12 +- .../nested_form_group_example.ts | 12 +- .../e2e_test/ng_model_group_spec.ts | 4 +- .../ts/ngModelGroup/ng_model_group_example.ts | 4 +- .../e2e_test/radio_button_spec.ts | 3 +- .../e2e_test/reactive_radio_button_spec.ts | 3 +- .../e2e_test/reactive_select_control_spec.ts | 4 +- .../e2e_test/select_control_spec.ts | 9 +- .../simpleForm/e2e_test/simple_form_spec.ts | 4 +- .../e2e_test/simple_form_control_spec.ts | 4 +- .../simple_form_control_example.ts | 4 +- .../e2e_test/simple_form_group_spec.ts | 4 +- .../simple_form_group_example.ts | 8 +- .../e2e_test/simple_ng_model_spec.ts | 3 +- .../simpleNgModel/simple_ng_model_example.ts | 4 +- .../platform-browser/dom/debug/ts/by/by.ts | 2 +- packages/examples/test-utils/index.ts | 2 +- packages/examples/testing/ts/testing.ts | 78 +- .../upgrade/static/ts/full/module.spec.ts | 8 +- .../examples/upgrade/static/ts/full/module.ts | 21 +- .../e2e_test/static_lite_multi_shared_spec.ts | 5 +- .../static/ts/lite-multi-shared/module.ts | 6 +- .../upgrade/static/ts/lite-multi/module.ts | 22 +- .../static/ts/lite/e2e_test/e2e_util.ts | 74 +- .../ts/lite/e2e_test/static_lite_spec.ts | 3 +- .../examples/upgrade/static/ts/lite/module.ts | 8 +- packages/http/src/backends/browser_jsonp.ts | 12 +- packages/http/src/backends/browser_xhr.ts | 4 +- packages/http/src/backends/jsonp_backend.ts | 7 +- packages/http/src/backends/xhr_backend.ts | 4 +- packages/http/src/base_request_options.ts | 14 +- packages/http/src/body.ts | 4 +- packages/http/src/headers.ts | 20 +- packages/http/src/http.ts | 4 +- packages/http/src/http_utils.ts | 2 +- packages/http/src/interfaces.ts | 16 +- packages/http/src/static_request.ts | 8 +- packages/http/src/static_response.ts | 10 +- packages/http/src/url_search_params.ts | 20 +- .../http/test/backends/jsonp_backend_spec.ts | 23 +- .../http/test/backends/mock_backend_spec.ts | 33 +- .../http/test/backends/xhr_backend_spec.ts | 109 +- packages/http/test/headers_spec.ts | 6 +- packages/http/test/http_spec.ts | 31 +- packages/http/test/static_request_spec.ts | 73 +- packages/http/test/url_search_params_spec.ts | 30 +- packages/http/testing/src/mock_backend.ts | 4 +- packages/localize/init/index.ts | 2 +- packages/localize/private.ts | 2 +- packages/localize/schematics/ng-add/index.ts | 9 +- .../localize/schematics/ng-add/index_spec.ts | 15 +- .../src/localize/test/localize_spec.ts | 68 +- .../localize/src/tools/src/diagnostics.ts | 18 +- packages/localize/src/tools/src/file_utils.ts | 10 +- .../asset_files/asset_translation_handler.ts | 4 +- .../localize/src/tools/src/translate/main.ts | 25 +- .../src/tools/src/translate/output_path.ts | 4 +- .../source_files/es2015_translate_plugin.ts | 4 +- .../source_files/es5_translate_plugin.ts | 4 +- .../translate/source_files/locale_plugin.ts | 2 +- .../source_files/source_file_utils.ts | 71 +- .../message_serializer.ts | 8 +- .../target_message_renderer.ts | 27 +- .../translation_files/translation_loader.ts | 7 +- .../simple_json_translation_parser.ts | 4 +- .../translation_parsers/translation_parser.ts | 4 +- .../translation_parsers/translation_utils.ts | 4 +- .../xliff1_translation_parser.ts | 5 +- .../xliff2_translation_parser.ts | 2 +- .../xtb_translation_parser.ts | 5 +- .../test/translate/integration/main_spec.ts | 25 +- .../translate/integration/test_files/test.js | 2 +- .../es2015_translate_plugin_spec.ts | 52 +- .../source_files/es5_translate_plugin_spec.ts | 44 +- .../source_files/locale_plugin_spec.ts | 30 +- .../source_file_translation_handler_spec.ts | 4 +- .../source_files/source_file_utils_spec.ts | 36 +- .../translation_loader_spec.ts | 13 +- .../xliff2_translation_parser_spec.ts | 2 - .../tools/test/translate/translator_spec.ts | 1 - packages/localize/src/translate.ts | 2 +- packages/localize/src/utils/src/messages.ts | 11 +- .../localize/src/utils/src/translations.ts | 8 +- .../localize/src/utils/test/messages_spec.ts | 6 +- .../src/utils/test/translations_spec.ts | 50 +- packages/localize/test/translate_spec.ts | 42 +- .../src/compiler_factory.ts | 104 +- .../src/compiler_reflector.ts | 15 +- .../src/platform-browser-dynamic.ts | 2 +- .../src/platform_core_dynamic.ts | 3 +- .../resource_loader/resource_loader_impl.ts | 4 +- .../test/metadata_overrider_spec.ts | 14 +- .../resource_loader_cache_spec.ts | 6 +- .../resource_loader_impl_spec.ts | 4 +- .../test/testing_public_browser_spec.ts | 38 +- .../testing/src/compiler_factory.ts | 24 +- .../src/dom_test_component_renderer.ts | 4 +- .../src/platform_core_dynamic_testing.ts | 2 +- .../testing/src/testing.ts | 2 +- .../animations/src/animation_builder.ts | 61 +- .../animations/src/animation_renderer.ts | 46 +- .../animations/src/providers.ts | 2 +- .../test/animation_renderer_spec.ts | 517 +- .../test/browser_animation_builder_spec.ts | 4 +- .../test/noop_animations_module_spec.ts | 20 +- packages/platform-browser/src/browser.ts | 3 +- .../src/browser/browser_adapter.ts | 58 +- .../src/browser/generic_browser_adapter.ts | 8 +- packages/platform-browser/src/browser/meta.ts | 21 +- .../src/browser/testability.ts | 6 +- .../platform-browser/src/browser/title.ts | 8 +- .../src/browser/tools/common_tools.ts | 4 +- .../src/browser/transfer_state.ts | 16 +- packages/platform-browser/src/dom/debug/by.ts | 6 +- .../platform-browser/src/dom/dom_renderer.ts | 50 +- .../src/dom/events/dom_events.ts | 8 +- .../src/dom/events/event_manager.ts | 6 +- .../src/dom/events/hammer_gestures.ts | 52 +- .../src/dom/events/key_events.ts | 20 +- .../src/dom/shared_styles_host.ts | 12 +- packages/platform-browser/src/dom/util.ts | 2 +- .../platform-browser/src/platform-browser.ts | 2 +- .../platform-browser/src/private_export.ts | 4 +- .../src/security/dom_sanitization_service.ts | 18 +- .../test/browser/bootstrap_spec.ts | 57 +- .../test/browser/meta_spec.ts | 28 +- .../test/browser/title_spec.ts | 17 +- .../test/browser/tools/spies.ts | 4 +- .../test/browser/tools/tools_spec.ts | 19 +- .../test/browser/transfer_state_spec.ts | 206 +- .../test/browser_util_spec.ts | 3 +- .../test/dom/events/event_manager_spec.ts | 672 +- .../test/dom/shadow_dom_spec.ts | 29 +- .../test/testing_public_spec.ts | 108 +- .../platform-browser/testing/src/browser.ts | 3 +- .../testing/src/browser_util.ts | 38 +- .../platform-browser/testing/src/matchers.ts | 40 +- .../platform-server/src/domino_adapter.ts | 40 +- packages/platform-server/src/http.ts | 21 +- packages/platform-server/src/location.ts | 36 +- .../platform-server/src/platform-server.ts | 2 +- .../platform-server/src/platform_state.ts | 8 +- packages/platform-server/src/server.ts | 10 +- packages/platform-server/src/server_events.ts | 4 +- .../platform-server/src/server_renderer.ts | 36 +- packages/platform-server/src/styles_host.ts | 4 +- packages/platform-server/src/utils.ts | 5 +- .../platform-server/test/integration_spec.ts | 881 +-- .../platform-server/testing/src/server.ts | 2 +- .../src/platform-webworker-dynamic.ts | 4 +- .../src/platform-webworker.ts | 4 +- .../shared/client_message_broker.ts | 12 +- .../web_workers/shared/post_message_bus.ts | 33 +- .../src/web_workers/shared/render_store.ts | 4 +- .../src/web_workers/shared/serializer.ts | 2 +- .../shared/service_message_broker.ts | 4 +- .../src/web_workers/ui/location_providers.ts | 6 +- .../src/web_workers/ui/platform_location.ts | 4 +- .../src/web_workers/ui/renderer.ts | 48 +- .../web_workers/worker/location_providers.ts | 2 +- .../web_workers/worker/platform_location.ts | 46 +- .../src/web_workers/worker/renderer.ts | 24 +- .../src/web_workers/worker/worker_adapter.ts | 80 +- packages/platform-webworker/src/worker_app.ts | 4 +- .../platform-webworker/src/worker_render.ts | 12 +- .../web_workers/shared/message_bus_spec.ts | 22 +- .../web_workers/shared/message_bus_util.ts | 6 +- .../web_workers/shared/mock_event_emitter.ts | 8 +- .../web_workers/shared/render_store_spec.ts | 5 +- .../shared/web_worker_test_util.ts | 30 +- .../worker/platform_location_spec.ts | 26 +- .../worker/renderer_v2_integration_spec.ts | 13 +- .../test/web_workers/worker/spies.ts | 4 +- packages/private/testing/src/render3.ts | 56 +- packages/router/karma-test-shim.js | 10 +- packages/router/src/apply_redirects.ts | 63 +- packages/router/src/create_url_tree.ts | 4 +- .../src/directives/router_link_active.ts | 18 +- .../router/src/directives/router_outlet.ts | 10 +- packages/router/src/events.ts | 40 +- packages/router/src/index.ts | 6 +- packages/router/src/interfaces.ts | 8 +- .../router/src/operators/activate_routes.ts | 6 +- packages/router/src/operators/check_guards.ts | 72 +- .../src/operators/prioritized_guard_value.ts | 64 +- packages/router/src/operators/recognize.ts | 6 +- packages/router/src/operators/resolve_data.ts | 24 +- packages/router/src/operators/switch_tap.ts | 2 +- packages/router/src/recognize.ts | 48 +- packages/router/src/route_reuse_strategy.ts | 12 +- packages/router/src/router.ts | 803 +-- packages/router/src/router_config_loader.ts | 7 +- packages/router/src/router_module.ts | 26 +- packages/router/src/router_outlet_context.ts | 8 +- packages/router/src/router_preloader.ts | 26 +- packages/router/src/router_scroller.ts | 6 +- packages/router/src/router_state.ts | 88 +- packages/router/src/shared.ts | 14 +- packages/router/src/url_handling_strategy.ts | 12 +- packages/router/src/url_tree.ts | 45 +- packages/router/src/utils/collection.ts | 14 +- packages/router/src/utils/tree.ts | 18 +- packages/router/test/apply_redirects.spec.ts | 257 +- packages/router/test/bootstrap.spec.ts | 26 +- packages/router/test/config.spec.ts | 56 +- .../router/test/create_router_state.spec.ts | 32 +- packages/router/test/create_url_tree.spec.ts | 14 +- packages/router/test/helpers.ts | 15 +- .../operators/prioritized_guard_value.spec.ts | 64 +- packages/router/test/recognize.spec.ts | 195 +- .../test/regression_integration.spec.ts | 13 +- packages/router/test/router.spec.ts | 127 +- packages/router/test/router_preloader.spec.ts | 120 +- packages/router/test/router_scroller.spec.ts | 8 +- packages/router/test/router_state.spec.ts | 37 +- packages/router/test/shared.spec.ts | 2 +- packages/router/test/url_serializer.spec.ts | 15 +- packages/router/test/url_tree.spec.ts | 6 +- packages/router/test/utils/tree.spec.ts | 8 +- .../testing/src/router_testing_module.ts | 14 +- packages/router/upgrade/src/upgrade.ts | 8 +- packages/router/upgrade/test/upgrade.spec.ts | 3 +- packages/service-worker/cli/filesystem.ts | 6 +- packages/service-worker/cli/main.ts | 2 +- packages/service-worker/cli/sha1.ts | 4 +- .../service-worker/config/src/generator.ts | 13 +- packages/service-worker/config/src/glob.ts | 2 +- packages/service-worker/config/src/in.ts | 4 +- .../config/test/generator_spec.ts | 6 +- .../service-worker/config/testing/mock.ts | 16 +- packages/service-worker/safety-worker.js | 9 +- packages/service-worker/src/index.ts | 12 +- packages/service-worker/src/low_level.ts | 23 +- packages/service-worker/src/module.ts | 6 +- packages/service-worker/src/push.ts | 42 +- packages/service-worker/src/update.ts | 4 +- .../service-worker/test/integration_spec.ts | 225 +- packages/service-worker/testing/mock.ts | 22 +- packages/service-worker/worker/src/adapter.ts | 20 +- packages/service-worker/worker/src/api.ts | 4 +- .../service-worker/worker/src/app-version.ts | 20 +- packages/service-worker/worker/src/assets.ts | 48 +- packages/service-worker/worker/src/data.ts | 27 +- .../service-worker/worker/src/db-cache.ts | 10 +- packages/service-worker/worker/src/debug.ts | 6 +- packages/service-worker/worker/src/driver.ts | 107 +- packages/service-worker/worker/src/error.ts | 4 +- packages/service-worker/worker/src/idle.ts | 14 +- packages/service-worker/worker/src/msg.ts | 4 +- .../worker/src/service-worker.d.ts | 6 +- packages/service-worker/worker/src/sha1.ts | 4 +- .../service-worker/worker/test/data_spec.ts | 543 +- .../service-worker/worker/test/idle_spec.ts | 212 +- .../worker/test/prefetch_spec.ts | 125 +- .../service-worker/worker/testing/cache.ts | 39 +- .../service-worker/worker/testing/fetch.ts | 78 +- .../service-worker/worker/testing/mock.ts | 61 +- .../service-worker/worker/testing/scope.ts | 108 +- packages/types.d.ts | 8 +- packages/upgrade/src/common/src/angular1.ts | 42 +- .../upgrade/src/common/src/component_info.ts | 16 +- .../src/common/src/downgrade_component.ts | 18 +- .../common/src/downgrade_component_adapter.ts | 30 +- .../upgrade/src/common/src/promise_util.ts | 6 +- .../upgrade/src/common/src/upgrade_helper.ts | 24 +- packages/upgrade/src/common/src/util.ts | 8 +- .../test/downgrade_component_adapter_spec.ts | 21 +- .../test/helpers/common_test_helpers.ts | 2 +- .../src/common/test/promise_util_spec.ts | 10 +- .../src/dynamic/src/upgrade_adapter.ts | 71 +- .../src/dynamic/src/upgrade_ng1_adapter.ts | 24 +- .../upgrade/static/src/downgrade_module.ts | 7 +- .../upgrade/static/src/upgrade_component.ts | 18 +- packages/upgrade/static/src/upgrade_module.ts | 22 +- .../test/integration/change_detection_spec.ts | 17 +- .../integration/content_projection_spec.ts | 13 +- .../integration/downgrade_component_spec.ts | 94 +- .../test/integration/downgrade_module_spec.ts | 134 +- .../static/test/integration/examples_spec.ts | 10 +- .../static/test/integration/injection_spec.ts | 5 +- .../test/integration/static_test_helpers.ts | 4 +- .../test/integration/testability_spec.ts | 27 +- .../integration/upgrade_component_spec.ts | 418 +- .../src/create_angular_testing_module.ts | 4 +- .../create_angular_testing_module_spec.ts | 2 +- .../create_angularjs_testing_module_spec.ts | 6 +- packages/zone.js/check-file-size.js | 4 +- .../example/benchmarks/event_emitter.js | 6 +- packages/zone.js/example/js/counting-zone.js | 4 +- packages/zone.js/lib/browser/api-util.ts | 18 +- .../zone.js/lib/browser/browser-legacy.ts | 34 +- packages/zone.js/lib/browser/browser.ts | 18 +- .../zone.js/lib/browser/custom-elements.ts | 2 +- .../zone.js/lib/browser/define-property.ts | 4 +- .../lib/browser/event-target-legacy.ts | 2 +- packages/zone.js/lib/browser/event-target.ts | 2 +- .../lib/browser/property-descriptor-legacy.ts | 34 +- .../lib/browser/property-descriptor.ts | 2 +- .../zone.js/lib/browser/register-element.ts | 2 +- .../lib/browser/webapis-resize-observer.ts | 4 +- packages/zone.js/lib/browser/websocket.ts | 2 +- packages/zone.js/lib/closure/zone_externs.js | 20 +- packages/zone.js/lib/common/error-rewrite.ts | 38 +- packages/zone.js/lib/common/events.ts | 9 +- packages/zone.js/lib/common/fetch.ts | 2 +- packages/zone.js/lib/common/timers.ts | 8 +- packages/zone.js/lib/common/utils.ts | 39 +- packages/zone.js/lib/extra/cordova.ts | 6 +- packages/zone.js/lib/extra/jsonp.ts | 6 +- packages/zone.js/lib/extra/socket-io.ts | 4 +- packages/zone.js/lib/jasmine/jasmine.ts | 18 +- packages/zone.js/lib/mocha/mocha.ts | 39 +- packages/zone.js/lib/rxjs/rxjs-fake-async.ts | 2 +- packages/zone.js/lib/rxjs/rxjs.ts | 14 +- packages/zone.js/lib/testing/async-testing.ts | 14 +- packages/zone.js/lib/testing/fake-async.ts | 12 +- packages/zone.js/lib/zone-spec/async-test.ts | 230 +- .../zone.js/lib/zone-spec/fake-async-test.ts | 1042 +-- .../zone.js/lib/zone-spec/long-stack-trace.ts | 2 +- packages/zone.js/lib/zone-spec/proxy.ts | 18 +- packages/zone.js/lib/zone-spec/sync-test.ts | 4 +- .../zone.js/lib/zone-spec/task-tracking.ts | 4 +- packages/zone.js/lib/zone-spec/wtf.ts | 256 +- packages/zone.js/lib/zone.ts | 180 +- packages/zone.js/sauce-evergreen.conf.js | 6 +- packages/zone.js/sauce.conf.js | 6 +- packages/zone.js/sauce.es2015.conf.js | 6 +- packages/zone.js/simple-server.js | 4 +- .../zone.js/test/browser/HTMLImports.spec.ts | 6 +- .../test/browser/MutationObserver.spec.ts | 20 +- .../zone.js/test/browser/WebSocket.spec.ts | 12 +- .../test/browser/XMLHttpRequest.spec.ts | 47 +- packages/zone.js/test/browser/browser.spec.ts | 997 ++- .../test/browser/custom-element.spec.js | 24 +- packages/zone.js/test/browser/element.spec.ts | 52 +- .../test/browser/registerElement.spec.ts | 21 +- .../browser/requestAnimationFrame.spec.ts | 12 +- .../zone.js/test/browser/shadydom.spec.ts | 7 +- packages/zone.js/test/closure/zone.closure.ts | 35 +- packages/zone.js/test/common/Error.spec.ts | 99 +- packages/zone.js/test/common/Promise.spec.ts | 223 +- packages/zone.js/test/common/fetch.spec.ts | 31 +- .../zone.js/test/common/microtasks.spec.ts | 16 +- ...le-wrap-uncaught-promise-rejection.spec.ts | 20 +- packages/zone.js/test/common/task.spec.ts | 258 +- packages/zone.js/test/common/toString.spec.ts | 5 +- packages/zone.js/test/common/util.spec.ts | 132 +- packages/zone.js/test/common/zone.spec.ts | 94 +- packages/zone.js/test/extra/bluebird.spec.ts | 252 +- packages/zone.js/test/extra/cordova.spec.ts | 9 +- packages/zone.js/test/extra/electron.js | 18 +- packages/zone.js/test/jasmine-patch.spec.ts | 12 +- packages/zone.js/test/main.ts | 12 +- packages/zone.js/test/mocha-patch.spec.ts | 50 +- packages/zone.js/test/node/Error.spec.ts | 8 +- packages/zone.js/test/node/console.spec.ts | 4 +- packages/zone.js/test/node/events.spec.ts | 36 +- packages/zone.js/test/node/fs.spec.ts | 20 +- packages/zone.js/test/node/http.spec.ts | 12 +- packages/zone.js/test/node/process.spec.ts | 52 +- packages/zone.js/test/node/timer.spec.ts | 8 +- .../test/npm_package/npm_package.spec.ts | 58 +- packages/zone.js/test/patch/IndexedDB.spec.js | 8 +- .../zone.js/test/performance/eventTarget.js | 138 +- .../test/performance/performance_setup.js | 473 +- .../test/performance/performance_ui.js | 282 +- packages/zone.js/test/performance/promise.js | 96 +- .../test/performance/requestAnimationFrame.js | 99 +- packages/zone.js/test/performance/timeout.js | 98 +- packages/zone.js/test/performance/xhr.js | 78 +- .../test/promise/promise.finally.spec.js | 74 +- .../test/rxjs/rxjs.Observable.audit.spec.ts | 14 +- .../test/rxjs/rxjs.Observable.buffer.spec.ts | 28 +- .../test/rxjs/rxjs.Observable.catch.spec.ts | 16 +- .../rxjs/rxjs.Observable.collection.spec.ts | 203 +- .../test/rxjs/rxjs.Observable.combine.spec.ts | 42 +- .../test/rxjs/rxjs.Observable.concat.spec.ts | 55 +- .../test/rxjs/rxjs.Observable.count.spec.ts | 8 +- .../rxjs/rxjs.Observable.debounce.spec.ts | 20 +- .../test/rxjs/rxjs.Observable.default.spec.ts | 15 +- .../test/rxjs/rxjs.Observable.delay.spec.ts | 25 +- .../rxjs/rxjs.Observable.distinct.spec.ts | 32 +- .../test/rxjs/rxjs.Observable.do.spec.ts | 14 +- .../test/rxjs/rxjs.Observable.map.spec.ts | 35 +- .../test/rxjs/rxjs.Observable.merge.spec.ts | 86 +- .../rxjs/rxjs.Observable.multicast.spec.ts | 26 +- .../rxjs/rxjs.Observable.notification.spec.ts | 8 +- .../test/rxjs/rxjs.Observable.race.spec.ts | 15 +- .../test/rxjs/rxjs.Observable.retry.spec.ts | 12 +- .../test/rxjs/rxjs.Observable.sample.spec.ts | 19 +- .../test/rxjs/rxjs.Observable.take.spec.ts | 39 +- .../test/rxjs/rxjs.Observable.timeout.spec.ts | 22 +- .../test/rxjs/rxjs.Observable.window.spec.ts | 30 +- packages/zone.js/test/rxjs/rxjs.asap.spec.ts | 23 +- .../test/rxjs/rxjs.bindCallback.spec.ts | 4 +- .../test/rxjs/rxjs.bindNodeCallback.spec.ts | 10 +- .../test/rxjs/rxjs.combineLatest.spec.ts | 10 +- .../zone.js/test/rxjs/rxjs.common.spec.ts | 8 +- .../zone.js/test/rxjs/rxjs.concat.spec.ts | 27 +- packages/zone.js/test/rxjs/rxjs.defer.spec.ts | 6 +- packages/zone.js/test/rxjs/rxjs.empty.spec.ts | 22 +- .../zone.js/test/rxjs/rxjs.forkjoin.spec.ts | 18 +- packages/zone.js/test/rxjs/rxjs.from.spec.ts | 33 +- .../zone.js/test/rxjs/rxjs.fromEvent.spec.ts | 22 +- .../test/rxjs/rxjs.fromPromise.spec.ts | 20 +- .../zone.js/test/rxjs/rxjs.interval.spec.ts | 15 +- packages/zone.js/test/rxjs/rxjs.merge.spec.ts | 25 +- packages/zone.js/test/rxjs/rxjs.never.spec.ts | 15 +- packages/zone.js/test/rxjs/rxjs.of.spec.ts | 14 +- packages/zone.js/test/rxjs/rxjs.range.spec.ts | 22 +- packages/zone.js/test/rxjs/rxjs.throw.spec.ts | 30 +- packages/zone.js/test/rxjs/rxjs.timer.spec.ts | 12 +- packages/zone.js/test/rxjs/rxjs.util.ts | 4 +- packages/zone.js/test/rxjs/rxjs.zip.spec.ts | 18 +- packages/zone.js/test/test-util.ts | 13 +- packages/zone.js/test/test_fake_polyfill.ts | 126 +- .../test/webdriver/test.sauce.es2015.js | 16 +- packages/zone.js/test/webdriver/test.sauce.js | 16 +- packages/zone.js/test/ws-webworker-context.ts | 6 +- packages/zone.js/test/wtf_mock.ts | 132 +- .../zone.js/test/zone-spec/async-test.spec.ts | 206 +- .../test/zone-spec/fake-async-test.spec.ts | 337 +- .../zone-spec/long-stack-trace-zone.spec.ts | 53 +- packages/zone.js/test/zone-spec/proxy.spec.ts | 77 +- .../zone.js/test/zone-spec/sync-test.spec.ts | 4 +- .../test/zone-spec/task-tracking.spec.ts | 38 +- protractor-perf.conf.js | 10 +- test-main.js | 97 +- tools/check-environment.js | 8 +- tools/contributing-stats/get-data.ts | 20 +- tools/gulp-tasks/cldr/closure.js | 4 +- tools/gulp-tasks/cldr/util.js | 7 +- tools/npm_integration_test/test_runner.js | 32 +- tools/postinstall-patches.js | 2 +- tools/rebase-pr.js | 8 +- tools/rxjs/rxjs_shims.js | 40 +- tools/size-tracking/file_size_compare.ts | 2 +- tools/size-tracking/file_size_compare_spec.ts | 1 - tools/size-tracking/file_size_data.ts | 20 +- tools/size-tracking/index.ts | 14 +- tools/size-tracking/size_tracking_spec.ts | 6 +- tools/source-map-test/parseMap.js | 9 +- tools/symbol-extractor/cli.ts | 8 +- tools/symbol-extractor/symbol_extractor.ts | 6 +- .../dont_pick_up_inner_symbols.js | 8 +- .../hello_world_min_debug.js | 447 +- .../symbol_extractor_spec/iife_with_export.js | 4 +- .../symbol_extractor_spec/simple.js | 4 +- .../two_symbols_per_var.js | 8 +- tools/ts-api-guardian/lib/main.ts | 5 +- tools/ts-api-guardian/lib/serializer.ts | 10 +- tools/ts-api-guardian/test/cli_e2e_test.ts | 4 +- .../ts-api-guardian/test/integration_test.ts | 19 +- tools/ts-api-guardian/test/unit_test.ts | 9 +- tools/utils/get-refs-and-shas-for-target.js | 10 +- 1160 files changed, 31240 insertions(+), 23573 deletions(-) diff --git a/dev-infra/ts-circular-dependencies/analyzer.ts b/dev-infra/ts-circular-dependencies/analyzer.ts index 76aa7ab0d324f..079602bebabe2 100644 --- a/dev-infra/ts-circular-dependencies/analyzer.ts +++ b/dev-infra/ts-circular-dependencies/analyzer.ts @@ -13,7 +13,7 @@ import * as ts from 'typescript'; import {getFileStatus} from './file_system'; import {getModuleReferences} from './parser'; -export type ModuleResolver = (specifier: string) => string | null; +export type ModuleResolver = (specifier: string) => string|null; /** * Reference chains describe a sequence of source files which are connected through imports. @@ -69,7 +69,7 @@ export class Analyzer { getSourceFile(filePath: string): ts.SourceFile { const resolvedPath = resolve(filePath); if (this._sourceFileCache.has(resolvedPath)) { - return this._sourceFileCache.get(resolvedPath) !; + return this._sourceFileCache.get(resolvedPath)!; } const fileContent = readFileSync(resolvedPath, 'utf8'); const sourceFile = @@ -105,7 +105,7 @@ export class Analyzer { if (!this.unresolvedFiles.has(originFilePath)) { this.unresolvedFiles.set(originFilePath, [specifier]); } - this.unresolvedFiles.get(originFilePath) !.push(specifier); + this.unresolvedFiles.get(originFilePath)!.push(specifier); } /** Resolves the given import specifier to the corresponding source file. */ diff --git a/dev-infra/utils/config.ts b/dev-infra/utils/config.ts index 78b165d223419..d3893d404c556 100644 --- a/dev-infra/utils/config.ts +++ b/dev-infra/utils/config.ts @@ -44,4 +44,6 @@ export function getAngularDevConfig<K, T>(): DevInfraConfig<K, T> { * Interface exressing the expected structure of the DevInfraConfig. * Allows for providing a typing for a part of the config to read. */ -export interface DevInfraConfig<K, T> { [K: string]: T; } +export interface DevInfraConfig<K, T> { + [K: string]: T; +} diff --git a/goldens/public-api/core/core.d.ts b/goldens/public-api/core/core.d.ts index bdb2bf34df06f..b123b36d35284 100644 --- a/goldens/public-api/core/core.d.ts +++ b/goldens/public-api/core/core.d.ts @@ -1064,7 +1064,7 @@ export declare function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): v export declare function ɵɵtemplate(index: number, templateFn: ComponentTemplate<any> | null, decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, localRefExtractor?: LocalRefExtractor): void; -export declare function ɵɵtemplateRefExtractor(tNode: TNode, currentView: ɵangular_packages_core_core_bp): TemplateRef<unknown> | null; +export declare function ɵɵtemplateRefExtractor(tNode: TNode, currentView: ɵangular_packages_core_core_bo): TemplateRef<unknown> | null; export declare function ɵɵtext(index: number, value?: string): void; diff --git a/modules/benchmarks/src/bootstrap_ng2.ts b/modules/benchmarks/src/bootstrap_ng2.ts index ff8eb4d105ff6..5bd0a5c803424 100644 --- a/modules/benchmarks/src/bootstrap_ng2.ts +++ b/modules/benchmarks/src/bootstrap_ng2.ts @@ -8,77 +8,79 @@ (function(global: any) { - writeScriptTag('/all/benchmarks/vendor/core.js'); - writeScriptTag('/all/benchmarks/vendor/zone.js'); - writeScriptTag('/all/benchmarks/vendor/long-stack-trace-zone.js'); - writeScriptTag('/all/benchmarks/vendor/system.src.js'); - writeScriptTag('/all/benchmarks/vendor/Reflect.js', 'benchmarksBootstrap()'); +writeScriptTag('/all/benchmarks/vendor/core.js'); +writeScriptTag('/all/benchmarks/vendor/zone.js'); +writeScriptTag('/all/benchmarks/vendor/long-stack-trace-zone.js'); +writeScriptTag('/all/benchmarks/vendor/system.src.js'); +writeScriptTag('/all/benchmarks/vendor/Reflect.js', 'benchmarksBootstrap()'); - (<any>global).benchmarksBootstrap = benchmarksBootstrap; +(<any>global).benchmarksBootstrap = benchmarksBootstrap; - function benchmarksBootstrap() { - // check query param - const useBundles = location.search.indexOf('bundles=false') == -1; - if (useBundles) { - System.config({ - defaultJSExtensions: true, - map: { - '@angular/core': '/packages-dist/core/bundles/core.umd.js', - '@angular/animations': '/packages-dist/common/bundles/animations.umd.js', - '@angular/platform-browser/animations': - '/packages-dist/platform-browser/bundles/platform-browser-animations.umd.js', - '@angular/common': '/packages-dist/common/bundles/common.umd.js', - '@angular/forms': '/packages-dist/forms/bundles/forms.umd.js', - '@angular/compiler': '/packages-dist/compiler/bundles/compiler.umd.js', - '@angular/platform-browser': - '/packages-dist/platform-browser/bundles/platform-browser.umd.js', - '@angular/platform-browser-dynamic': - '/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', - '@angular/http': '/packages-dist/http/bundles/http.umd.js', - '@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js', - '@angular/router': '/packages-dist/router/bundles/router.umd.js', - 'rxjs': '/all/benchmarks/vendor/rxjs', - }, - packages: { - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - } - }); - } else { - console.warn( - 'Not using the Angular bundles. Don\'t use this configuration for e2e/performance tests!'); +function benchmarksBootstrap() { + // check query param + const useBundles = location.search.indexOf('bundles=false') == -1; + if (useBundles) { + System.config({ + defaultJSExtensions: true, + map: { + '@angular/core': '/packages-dist/core/bundles/core.umd.js', + '@angular/animations': '/packages-dist/common/bundles/animations.umd.js', + '@angular/platform-browser/animations': + '/packages-dist/platform-browser/bundles/platform-browser-animations.umd.js', + '@angular/common': '/packages-dist/common/bundles/common.umd.js', + '@angular/forms': '/packages-dist/forms/bundles/forms.umd.js', + '@angular/compiler': '/packages-dist/compiler/bundles/compiler.umd.js', + '@angular/platform-browser': + '/packages-dist/platform-browser/bundles/platform-browser.umd.js', + '@angular/platform-browser-dynamic': + '/packages-dist/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', + '@angular/http': '/packages-dist/http/bundles/http.umd.js', + '@angular/upgrade': '/packages-dist/upgrade/bundles/upgrade.umd.js', + '@angular/router': '/packages-dist/router/bundles/router.umd.js', + 'rxjs': '/all/benchmarks/vendor/rxjs', + }, + packages: { + 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs': {main: 'index.js', defaultExtension: 'js'}, + } + }); + } else { + console.warn( + 'Not using the Angular bundles. Don\'t use this configuration for e2e/performance tests!'); - System.config({ - defaultJSExtensions: true, - map: {'@angular': '/all/@angular', 'rxjs': '/all/benchmarks/vendor/rxjs'}, - packages: { - '@angular/core': {main: 'index.js', defaultExtension: 'js'}, - '@angular/animations': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser/animations': {main: 'index.js', defaultExtension: 'js'}, - '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, - '@angular/router': {main: 'index.js', defaultExtension: 'js'}, - '@angular/common': {main: 'index.js', defaultExtension: 'js'}, - '@angular/forms': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, - '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, - '@angular/upgrade': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, - 'rxjs': {main: 'index.js', defaultExtension: 'js'}, - } - }); - } - - // BOOTSTRAP the app! - System.import('index').then(function(m: any) { m.main(); }, console.error.bind(console)); + System.config({ + defaultJSExtensions: true, + map: {'@angular': '/all/@angular', 'rxjs': '/all/benchmarks/vendor/rxjs'}, + packages: { + '@angular/core': {main: 'index.js', defaultExtension: 'js'}, + '@angular/animations': {main: 'index.js', defaultExtension: 'js'}, + '@angular/platform-browser/animations': {main: 'index.js', defaultExtension: 'js'}, + '@angular/compiler': {main: 'index.js', defaultExtension: 'js'}, + '@angular/router': {main: 'index.js', defaultExtension: 'js'}, + '@angular/common': {main: 'index.js', defaultExtension: 'js'}, + '@angular/forms': {main: 'index.js', defaultExtension: 'js'}, + '@angular/platform-browser': {main: 'index.js', defaultExtension: 'js'}, + '@angular/platform-browser-dynamic': {main: 'index.js', defaultExtension: 'js'}, + '@angular/upgrade': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/ajax': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/operators': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/testing': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs/websocket': {main: 'index.js', defaultExtension: 'js'}, + 'rxjs': {main: 'index.js', defaultExtension: 'js'}, + } + }); } - function writeScriptTag(scriptUrl: string, onload?: string) { - document.write(`<script src="${scriptUrl}" onload="${onload}"></script>`); - } + // BOOTSTRAP the app! + System.import('index').then(function(m: any) { + m.main(); + }, console.error.bind(console)); +} + +function writeScriptTag(scriptUrl: string, onload?: string) { + document.write(`<script src="${scriptUrl}" onload="${onload}"></script>`); +} }(window)); diff --git a/modules/benchmarks/src/bootstrap_plain.ts b/modules/benchmarks/src/bootstrap_plain.ts index b2c62c53ae679..dcc711f93273c 100644 --- a/modules/benchmarks/src/bootstrap_plain.ts +++ b/modules/benchmarks/src/bootstrap_plain.ts @@ -8,24 +8,24 @@ (function(global: any) { - writeScriptTag('/all/benchmarks/vendor/core.js'); - writeScriptTag('/all/benchmarks/vendor/system.src.js', 'benchmarksBootstrap()'); +writeScriptTag('/all/benchmarks/vendor/core.js'); +writeScriptTag('/all/benchmarks/vendor/system.src.js', 'benchmarksBootstrap()'); - (<any>global).benchmarksBootstrap = benchmarksBootstrap; +(<any>global).benchmarksBootstrap = benchmarksBootstrap; - function benchmarksBootstrap() { - System.config({ - defaultJSExtensions: true, - map: {'incremental-dom': '/all/benchmarks/vendor/incremental-dom-cjs.js'} - }); +function benchmarksBootstrap() { + System.config({ + defaultJSExtensions: true, + map: {'incremental-dom': '/all/benchmarks/vendor/incremental-dom-cjs.js'} + }); - // BOOTSTRAP the app! - System.import('index').then(function(m: any) { - m.main && m.main(); - }, console.error.bind(console)); - } + // BOOTSTRAP the app! + System.import('index').then(function(m: any) { + m.main && m.main(); + }, console.error.bind(console)); +} - function writeScriptTag(scriptUrl: string, onload?: string) { - document.write(`<script src="${scriptUrl}" onload="${onload}"></script>`); - } +function writeScriptTag(scriptUrl: string, onload?: string) { + document.write(`<script src="${scriptUrl}" onload="${onload}"></script>`); +} }(window)); diff --git a/modules/benchmarks/src/change_detection/change_detection.e2e-spec.ts b/modules/benchmarks/src/change_detection/change_detection.e2e-spec.ts index 4872bfee5352a..33ba44bce599f 100644 --- a/modules/benchmarks/src/change_detection/change_detection.e2e-spec.ts +++ b/modules/benchmarks/src/change_detection/change_detection.e2e-spec.ts @@ -13,7 +13,7 @@ import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('change detection benchmark', () => { afterEach(verifyNoBrowserErrors); - it(`should render and update`, async() => { + it(`should render and update`, async () => { openBrowser({ url: '', ignoreBrowserSynchronization: true, diff --git a/modules/benchmarks/src/change_detection/change_detection.perf-spec.ts b/modules/benchmarks/src/change_detection/change_detection.perf-spec.ts index 6251659446592..f450dc5bc8e1c 100644 --- a/modules/benchmarks/src/change_detection/change_detection.perf-spec.ts +++ b/modules/benchmarks/src/change_detection/change_detection.perf-spec.ts @@ -31,15 +31,14 @@ const UpdateWorker: Worker = { // name. We determine the name of the Bazel package where this test runs from the current test // target. The Bazel target // looks like: "//modules/benchmarks/src/change_detection/{pkg_name}:{target_name}". -const testPackageName = process.env['BAZEL_TARGET'] !.split(':')[0].split('/').pop(); +const testPackageName = process.env['BAZEL_TARGET']!.split(':')[0].split('/').pop(); describe('change detection benchmark perf', () => { - afterEach(verifyNoBrowserErrors); [UpdateWorker].forEach((worker) => { describe(worker.id, () => { - it(`should run benchmark for ${testPackageName}`, async() => { + it(`should run benchmark for ${testPackageName}`, async () => { await runChangeDetectionBenchmark({ id: `change_detection.${testPackageName}.${worker.id}`, url: '/', diff --git a/modules/benchmarks/src/change_detection/transplanted_views/init.ts b/modules/benchmarks/src/change_detection/transplanted_views/init.ts index 600d862438194..53b6ef336a004 100644 --- a/modules/benchmarks/src/change_detection/transplanted_views/init.ts +++ b/modules/benchmarks/src/change_detection/transplanted_views/init.ts @@ -35,7 +35,9 @@ export function init(moduleRef: NgModuleRef<TransplantedViewsModule>) { appRef.tick(); } - function detectChanges() { appRef.tick(); } + function detectChanges() { + appRef.tick(); + } function noop() {} } diff --git a/modules/benchmarks/src/change_detection/transplanted_views/transplanted_views.ts b/modules/benchmarks/src/change_detection/transplanted_views/transplanted_views.ts index b74e47b8c7089..da7746640c267 100644 --- a/modules/benchmarks/src/change_detection/transplanted_views/transplanted_views.ts +++ b/modules/benchmarks/src/change_detection/transplanted_views/transplanted_views.ts @@ -40,10 +40,14 @@ export class InsertionComponent { @Input() template !: TemplateRef<{}>; views: any[] = []; @Input() - set viewCount(n: number) { this.views = n > 0 ? newArray<any>(n) : []; } + set viewCount(n: number) { + this.views = n > 0 ? newArray<any>(n) : []; + } // use trackBy to ensure profile isn't affected by the cost to refresh ngFor. - trackByIndex(index: number, item: any) { return index; } + trackByIndex(index: number, item: any) { + return index; + } } @NgModule({ diff --git a/modules/benchmarks/src/change_detection/util.ts b/modules/benchmarks/src/change_detection/util.ts index 7205f7245479d..25944f727c16c 100644 --- a/modules/benchmarks/src/change_detection/util.ts +++ b/modules/benchmarks/src/change_detection/util.ts @@ -15,7 +15,7 @@ export function newArray<T>(size: number, value: T): T[]; export function newArray<T>(size: number, value?: T): T[] { const list: T[] = []; for (let i = 0; i < size; i++) { - list.push(value !); + list.push(value!); } return list; } diff --git a/modules/benchmarks/src/class_bindings/app.component.ts b/modules/benchmarks/src/class_bindings/app.component.ts index 73ffcaae3b077..27aa5e20f9521 100644 --- a/modules/benchmarks/src/class_bindings/app.component.ts +++ b/modules/benchmarks/src/class_bindings/app.component.ts @@ -27,12 +27,16 @@ export class AppComponent { } } - create() { this.show = true; } + create() { + this.show = true; + } update() { this.msg = this.msg === 'hello' ? 'bye' : 'hello'; this.list[0].text = this.msg; } - destroy() { this.show = false; } + destroy() { + this.show = false; + } } diff --git a/modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts b/modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts index 41486c5ce64ac..e21d27dadf2a8 100644 --- a/modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts +++ b/modules/benchmarks/src/class_bindings/class_bindings.perf-spec.ts @@ -10,8 +10,7 @@ import {$, browser} from 'protractor'; import {runBenchmark} from '../../../e2e_util/perf_util'; describe('class bindings perf', () => { - - it('should work for update', async() => { + it('should work for update', async () => { browser.rootEl = '#root'; await runBenchmark({ id: 'create', @@ -23,7 +22,7 @@ describe('class bindings perf', () => { }); }); - it('should work for update', async() => { + it('should work for update', async () => { browser.rootEl = '#root'; await runBenchmark({ id: 'update', @@ -34,5 +33,4 @@ describe('class bindings perf', () => { work: () => $('#update').click() }); }); - }); diff --git a/modules/benchmarks/src/expanding_rows/benchmark.ts b/modules/benchmarks/src/expanding_rows/benchmark.ts index 2fc9492f0a8a7..df18ff4a28a70 100644 --- a/modules/benchmarks/src/expanding_rows/benchmark.ts +++ b/modules/benchmarks/src/expanding_rows/benchmark.ts @@ -31,23 +31,32 @@ import {BenchmarkableExpandingRowModule} from './benchmarkable_expanding_row_mod </benchmark-area>`, }) export class InitializationRoot implements AfterViewInit { - @ViewChild(BenchmarkableExpandingRow, {static: true}) - expandingRow !: BenchmarkableExpandingRow; + @ViewChild(BenchmarkableExpandingRow, {static: true}) expandingRow!: BenchmarkableExpandingRow; ngAfterViewInit() {} - reset() { this.expandingRow.reset(); } + reset() { + this.expandingRow.reset(); + } - init() { this.expandingRow.init(); } + init() { + this.expandingRow.init(); + } async runAll() { - await execTimed('initialization_benchmark', async() => { await this.doInit(); }); + await execTimed('initialization_benchmark', async () => { + await this.doInit(); + }); } - async handleInitClick() { await this.doInit(); } + async handleInitClick() { + await this.doInit(); + } private async doInit() { - await execTimed('initial_load', async() => { this.expandingRow.init(); }); + await execTimed('initial_load', async () => { + this.expandingRow.init(); + }); } } @@ -74,5 +83,9 @@ export async function execTimed(description: string, func: () => Promise<void>) } export async function nextTick(delay = 1) { - return new Promise((res, rej) => { setTimeout(() => { res(); }, delay); }); + return new Promise((res, rej) => { + setTimeout(() => { + res(); + }, delay); + }); } diff --git a/modules/benchmarks/src/expanding_rows/benchmark_module.ts b/modules/benchmarks/src/expanding_rows/benchmark_module.ts index 6f13981f6067d..6a51767018b12 100644 --- a/modules/benchmarks/src/expanding_rows/benchmark_module.ts +++ b/modules/benchmarks/src/expanding_rows/benchmark_module.ts @@ -26,7 +26,9 @@ import {Component, ErrorHandler, Injectable, NgModule} from '@angular/core'; export class BenchmarkArea { } -declare interface ExtendedWindow extends Window { benchmarkErrors?: string[]; } +declare interface ExtendedWindow extends Window { + benchmarkErrors?: string[]; +} const extendedWindow = window as ExtendedWindow; @Injectable({providedIn: 'root'}) diff --git a/modules/benchmarks/src/expanding_rows/benchmarkable_expanding_row.ts b/modules/benchmarks/src/expanding_rows/benchmarkable_expanding_row.ts index 8c70934388bbc..a677ef152e4f3 100644 --- a/modules/benchmarks/src/expanding_rows/benchmarkable_expanding_row.ts +++ b/modules/benchmarks/src/expanding_rows/benchmarkable_expanding_row.ts @@ -44,12 +44,12 @@ export interface MlbTeam { }) export class BenchmarkableExpandingRow { // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - showExpandingRow !: boolean; + showExpandingRow!: boolean; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - teams !: MlbTeam[]; + teams!: MlbTeam[]; // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - private fakeTeams !: MlbTeam[]; + private fakeTeams!: MlbTeam[]; init(): void { this.teams = this.fakeTeams; diff --git a/modules/benchmarks/src/expanding_rows/expanding_row.ts b/modules/benchmarks/src/expanding_rows/expanding_row.ts index da6da38bb8543..aadfded4e639a 100644 --- a/modules/benchmarks/src/expanding_rows/expanding_row.ts +++ b/modules/benchmarks/src/expanding_rows/expanding_row.ts @@ -112,15 +112,14 @@ export class ExpandingRow { * The identifier for this node provided by the user code. We need this * while we are emitting onToggle event. */ - @Input() rowId !: string; + @Input() rowId!: string; /** * An ElementRef to the main element in this component. We need a reference * to this element to compute the height. The height of cfc-expanding-row * is used in [cfcExpandingRowHost] directive for scroll adjustments. */ - @ViewChild('expandingRowMainElement', {static: true}) - expandingRowMainElement !: ElementRef; + @ViewChild('expandingRowMainElement', {static: true}) expandingRowMainElement!: ElementRef; /** * This @Output event emitter will be triggered when the user expands or @@ -145,7 +144,9 @@ export class ExpandingRow { } /** TS getter for isExpanded property. */ - get isExpanded(): boolean { return this.isExpandedInternal; } + get isExpanded(): boolean { + return this.isExpandedInternal; + } /** Triggered when isExpanded property changes. */ isExpandedChange = new EventEmitter<void>(); @@ -164,7 +165,9 @@ export class ExpandingRow { } /** TS getter for isFocused property. */ - get isFocused(): boolean { return this.isFocusedInternal; } + get isFocused(): boolean { + return this.isFocusedInternal; + } /** The index of the row in the context of the entire collection. */ set index(value: number) { @@ -178,7 +181,9 @@ export class ExpandingRow { } /** TS getter for index property. */ - get index(): number { return this.indexInternal; } + get index(): number { + return this.indexInternal; + } /** * We should probably rename this to summaryContentChild. Because technically @@ -188,7 +193,7 @@ export class ExpandingRow { * component is not in the same file as ExpandingRow. */ // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - summaryViewChild !: ExpandingRowSummary; + summaryViewChild!: ExpandingRowSummary; /** * We compute the collapsed height (which is just height of @@ -205,7 +210,7 @@ export class ExpandingRow { /** Internal storage for index public property. */ // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - private indexInternal !: number; + private indexInternal!: number; /** * This holds a reference to [cfcExpandingRowHost] directive. We need @@ -233,7 +238,9 @@ export class ExpandingRow { * When user tabs into child cfc-expanding-row-summary component. This method * will make sure we focuse on this row, and blur on previously focused row. */ - handleSummaryFocus(): void { this.focus(); } + handleSummaryFocus(): void { + this.focus(); + } /** * cfc-expanding-row-details-caption component will call this function to @@ -256,7 +263,9 @@ export class ExpandingRow { * Gets the height of this component. This height is used in parent * [cfcExpandingRowHost] directive to compute scroll adjustment. */ - getHeight(): number { return this.expandingRowMainElement.nativeElement.offsetHeight; } + getHeight(): number { + return this.expandingRowMainElement.nativeElement.offsetHeight; + } /** * Expands this row. This will notify the host so that it can collapse @@ -268,7 +277,9 @@ export class ExpandingRow { this.expandingRowHost.handleRowExpand(this); // setTimeout here makes sure we scroll this row into view after animation. - setTimeout(() => { this.expandingRowMainElement.nativeElement.focus(); }); + setTimeout(() => { + this.expandingRowMainElement.nativeElement.focus(); + }); this.onToggle.emit({rowId: this.rowId, isExpand: true}); } @@ -305,7 +316,9 @@ export class ExpandingRow { // Summary child is not present currently. We need to NG2 to update the // template. - setTimeout(() => { this.summaryViewChild.focus(); }); + setTimeout(() => { + this.summaryViewChild.focus(); + }); } /** diff --git a/modules/benchmarks/src/expanding_rows/expanding_row_details_caption.ts b/modules/benchmarks/src/expanding_rows/expanding_row_details_caption.ts index 15f77c95db13b..00cbe534fa5e9 100644 --- a/modules/benchmarks/src/expanding_rows/expanding_row_details_caption.ts +++ b/modules/benchmarks/src/expanding_rows/expanding_row_details_caption.ts @@ -49,5 +49,7 @@ export class ExpandingRowDetailsCaption implements OnDestroy { } /** When component is destroyed, unlisten to isExpanded. */ - ngOnDestroy(): void { this.onDestroy.next(); } + ngOnDestroy(): void { + this.onDestroy.next(); + } } diff --git a/modules/benchmarks/src/expanding_rows/expanding_row_details_content.ts b/modules/benchmarks/src/expanding_rows/expanding_row_details_content.ts index 2ab182a39ca3f..557f6f2731966 100644 --- a/modules/benchmarks/src/expanding_rows/expanding_row_details_content.ts +++ b/modules/benchmarks/src/expanding_rows/expanding_row_details_content.ts @@ -35,10 +35,13 @@ export class ExpandingRowDetailsContent implements OnDestroy { * hide this component if the row is collapsed. */ constructor(@Host() public expandingRow: ExpandingRow, changeDetectorRef: ChangeDetectorRef) { - this.isExpandedChangeSubscription = - this.expandingRow.isExpandedChange.subscribe(() => { changeDetectorRef.markForCheck(); }); + this.isExpandedChangeSubscription = this.expandingRow.isExpandedChange.subscribe(() => { + changeDetectorRef.markForCheck(); + }); } /** Unsubscribe from changes in parent isExpanded property. */ - ngOnDestroy(): void { this.isExpandedChangeSubscription.unsubscribe(); } + ngOnDestroy(): void { + this.isExpandedChangeSubscription.unsubscribe(); + } } diff --git a/modules/benchmarks/src/expanding_rows/expanding_row_host.ts b/modules/benchmarks/src/expanding_rows/expanding_row_host.ts index 52bf88ecb8f52..195013c43004a 100644 --- a/modules/benchmarks/src/expanding_rows/expanding_row_host.ts +++ b/modules/benchmarks/src/expanding_rows/expanding_row_host.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, ContentChildren, ElementRef, EventEmitter, HostListener, Input, OnDestroy, Output, QueryList, ViewChild, forwardRef} from '@angular/core'; +import {AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, HostListener, Input, OnDestroy, Output, QueryList, ViewChild} from '@angular/core'; import {Subscription} from 'rxjs'; import {EXPANDING_ROW_HOST_INJECTION_TOKEN, ExpandingRow, ExpandingRowHostBase} from './expanding_row'; @@ -26,7 +26,7 @@ export const EXPANDING_ROW_KEYPRESS_THORTTLE_MS = 50; * This type union is created to make arguments of handleUpOrDownPress* * methods in ExpandingRowHost class more readable. */ -type UpOrDown = 'up' | 'down'; +type UpOrDown = 'up'|'down'; /** * This is the wrapper directive for the cfc-expanding-row components. Note that @@ -48,8 +48,7 @@ type UpOrDown = 'up' | 'down'; changeDetection: ChangeDetectionStrategy.OnPush, providers: [{provide: EXPANDING_ROW_HOST_INJECTION_TOKEN, useExisting: ExpandingRowHost}], }) -export class ExpandingRowHost implements AfterViewInit, - OnDestroy, ExpandingRowHostBase { +export class ExpandingRowHost implements AfterViewInit, OnDestroy, ExpandingRowHostBase { /** * An HTML selector (e.g. "body") for the scroll element. We need this to * make some scroll adjustments. @@ -71,11 +70,10 @@ export class ExpandingRowHost implements AfterViewInit, @Output() onPrepend = new EventEmitter<void>(); /** A reference to the last focusable element in list of expanding rows. */ - @ViewChild('lastFocusable', {static: true}) lastFocusableElement !: ElementRef; + @ViewChild('lastFocusable', {static: true}) lastFocusableElement!: ElementRef; /** A reference to the first focusable element in list of expanding rows. */ - @ViewChild('firstFocusable', {static: true}) - firstFocusableElement !: ElementRef; + @ViewChild('firstFocusable', {static: true}) firstFocusableElement!: ElementRef; /** * A reference to all child cfc-expanding-row elements. We will need for @@ -83,7 +81,7 @@ export class ExpandingRowHost implements AfterViewInit, * which row is previous row when user presses "left arrow" on a focused row. */ @ContentChildren(forwardRef(() => ExpandingRow), {descendants: true}) - contentRows !: QueryList<ExpandingRow>; + contentRows!: QueryList<ExpandingRow>; /** * Keeps track of the last row that had focus before focus left the list @@ -122,7 +120,7 @@ export class ExpandingRowHost implements AfterViewInit, /** Subscription to changes in the expanding rows. */ // TODO(b/109816955): remove '!', see go/strict-prop-init-fix. - private rowChangeSubscription !: Subscription; + private rowChangeSubscription!: Subscription; /** * When component initializes we need to attach click listener to the root @@ -138,8 +136,9 @@ export class ExpandingRowHost implements AfterViewInit, clickRootElement.addEventListener('mouseup', this.handleRootMouseUpBound); - this.rowChangeSubscription = - this.contentRows.changes.subscribe(() => { this.recalcRowIndexes(); }); + this.rowChangeSubscription = this.contentRows.changes.subscribe(() => { + this.recalcRowIndexes(); + }); this.recalcRowIndexes(); } @@ -256,13 +255,17 @@ export class ExpandingRowHost implements AfterViewInit, * Function that is called by expanding row summary to focus on the last * focusable element before the list of expanding rows. */ - focusOnPreviousFocusableElement(): void { this.lastFocusedRow = this.focusedRow; } + focusOnPreviousFocusableElement(): void { + this.lastFocusedRow = this.focusedRow; + } /** * Function that is called by expanding row summary to focus on the next * focusable element after the list of expanding rows. */ - focusOnNextFocusableElement(): void { this.lastFocusedRow = this.focusedRow; } + focusOnNextFocusableElement(): void { + this.lastFocusedRow = this.focusedRow; + } /** * Handles keydown event on the host. We are just concerned with up, @@ -275,7 +278,8 @@ export class ExpandingRowHost implements AfterViewInit, * - Enter: Expands the focused row. */ @HostListener('keydown', ['$event']) - handleKeyDown(event: KeyboardEvent) {} + handleKeyDown(event: KeyboardEvent) { + } /** * Recursively returns true if target HTMLElement is within a @@ -491,7 +495,10 @@ export class ExpandingRowHost implements AfterViewInit, // Updates all of the rows with their new index. private recalcRowIndexes() { let index = 0; - setTimeout( - () => { this.contentRows.forEach((row: ExpandingRow) => { row.index = index++; }); }); + setTimeout(() => { + this.contentRows.forEach((row: ExpandingRow) => { + row.index = index++; + }); + }); } } diff --git a/modules/benchmarks/src/expanding_rows/expanding_row_summary.ts b/modules/benchmarks/src/expanding_rows/expanding_row_summary.ts index e8ffb31534aa1..673e796271fc5 100644 --- a/modules/benchmarks/src/expanding_rows/expanding_row_summary.ts +++ b/modules/benchmarks/src/expanding_rows/expanding_row_summary.ts @@ -48,8 +48,7 @@ export class ExpandingRowSummary implements OnDestroy { * reference to compute collapsed height of the row. We also use this * reference for focus and blur methods below. */ - @ViewChild('expandingRowSummaryMainElement') - mainElementRef !: ElementRef; + @ViewChild('expandingRowSummaryMainElement') mainElementRef!: ElementRef; /** Subscription for changes in parent isExpanded property. */ private isExpandedSubscription: Subscription; @@ -65,11 +64,13 @@ export class ExpandingRowSummary implements OnDestroy { */ constructor(@Host() public expandingRow: ExpandingRow, changeDetectorRef: ChangeDetectorRef) { this.expandingRow.summaryViewChild = this; - this.isExpandedSubscription = - this.expandingRow.isExpandedChange.subscribe(() => { changeDetectorRef.markForCheck(); }); + this.isExpandedSubscription = this.expandingRow.isExpandedChange.subscribe(() => { + changeDetectorRef.markForCheck(); + }); - this.indexSubscription = - this.expandingRow.indexChange.subscribe(() => { changeDetectorRef.markForCheck(); }); + this.indexSubscription = this.expandingRow.indexChange.subscribe(() => { + changeDetectorRef.markForCheck(); + }); } @@ -203,5 +204,7 @@ export class ExpandingRowSummary implements OnDestroy { } /** Returns array of focusable elements within this component. */ - private getFocusableChildren(): HTMLElement[] { return []; } + private getFocusableChildren(): HTMLElement[] { + return []; + } } diff --git a/modules/benchmarks/src/expanding_rows/expanding_rows.perf-spec.ts b/modules/benchmarks/src/expanding_rows/expanding_rows.perf-spec.ts index ee4bab2193c83..316de6c5abd49 100644 --- a/modules/benchmarks/src/expanding_rows/expanding_rows.perf-spec.ts +++ b/modules/benchmarks/src/expanding_rows/expanding_rows.perf-spec.ts @@ -10,8 +10,7 @@ import {$, browser} from 'protractor'; import {runBenchmark} from '../../../e2e_util/perf_util'; describe('benchmarks', () => { - - it('should work for create', async() => { + it('should work for create', async () => { browser.rootEl = '#root'; await runBenchmark({ id: 'create', @@ -22,5 +21,4 @@ describe('benchmarks', () => { work: () => $('#init').click() }); }); - }); diff --git a/modules/benchmarks/src/expanding_rows/index_aot.ts b/modules/benchmarks/src/expanding_rows/index_aot.ts index d2318d8818f59..367e8753327cc 100644 --- a/modules/benchmarks/src/expanding_rows/index_aot.ts +++ b/modules/benchmarks/src/expanding_rows/index_aot.ts @@ -18,5 +18,5 @@ enableProdMode(); platformBrowser().bootstrapModuleFactory(ExpandingRowBenchmarkModuleNgFactory); function setMode(name: string): void { - document.querySelector('#rendererMode') !.textContent = `Render Mode: ${name}`; + document.querySelector('#rendererMode')!.textContent = `Render Mode: ${name}`; } diff --git a/modules/benchmarks/src/js-web-frameworks/js-web-frameworks.perf-spec.ts b/modules/benchmarks/src/js-web-frameworks/js-web-frameworks.perf-spec.ts index 0ed6859aa6fb0..200590588e9bd 100644 --- a/modules/benchmarks/src/js-web-frameworks/js-web-frameworks.perf-spec.ts +++ b/modules/benchmarks/src/js-web-frameworks/js-web-frameworks.perf-spec.ts @@ -24,19 +24,25 @@ const Create1KWorker: Worker = { const Delete1KWorker: Worker = { id: 'delete1K', prepare: () => $('#create1KRows').click(), - work: () => { $('#deleteAll').click(); } + work: () => { + $('#deleteAll').click(); + } }; const UpdateWorker: Worker = { id: 'update', prepare: () => $('#create1KRows').click(), - work: () => { $('#update').click(); } + work: () => { + $('#update').click(); + } }; const SwapWorker: Worker = { id: 'swap', prepare: () => $('#create1KRows').click(), - work: () => { $('#swap').click(); } + work: () => { + $('#swap').click(); + } }; // In order to make sure that we don't change the ids of the benchmarks, we need to @@ -45,15 +51,14 @@ const SwapWorker: Worker = { // name. e.g. "largeTable.ng2_switch.createDestroy". We determine the name of the // Bazel package where this test runs from the current test target. The Bazel target // looks like: "//modules/benchmarks/src/largetable/{pkg_name}:{target_name}". -const testPackageName = process.env['BAZEL_TARGET'] !.split(':')[0].split('/').pop(); +const testPackageName = process.env['BAZEL_TARGET']!.split(':')[0].split('/').pop(); describe('js-web-frameworks benchmark perf', () => { - afterEach(verifyNoBrowserErrors); [Create1KWorker, Delete1KWorker, UpdateWorker, SwapWorker].forEach((worker) => { describe(worker.id, () => { - it(`should run benchmark for ${testPackageName}`, async() => { + it(`should run benchmark for ${testPackageName}`, async () => { await runTableBenchmark({ id: `js-web-frameworks.${testPackageName}.${worker.id}`, url: '/', diff --git a/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts b/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts index 655c2385cddc0..e691da507c131 100644 --- a/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts +++ b/modules/benchmarks/src/js-web-frameworks/ng2/rows.ts @@ -42,14 +42,16 @@ export class JsWebFrameworksComponent { constructor(private _appRef: ApplicationRef) {} - itemById(index: number, item: RowData) { return item.id; } + itemById(index: number, item: RowData) { + return item.id; + } select(itemId: number) { this.selected = itemId; this._appRef.tick(); } - delete (itemId: number) { + delete(itemId: number) { const data = this.data; for (let i = 0, l = data.length; i < l; i++) { if (data[i].id === itemId) { diff --git a/modules/benchmarks/src/largeform/largeform.e2e-spec.ts b/modules/benchmarks/src/largeform/largeform.e2e-spec.ts index 5cd7516a27689..de55e1600263a 100644 --- a/modules/benchmarks/src/largeform/largeform.e2e-spec.ts +++ b/modules/benchmarks/src/largeform/largeform.e2e-spec.ts @@ -11,10 +11,9 @@ import {$, By, element} from 'protractor'; import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('largeform benchmark', () => { - afterEach(verifyNoBrowserErrors); - it('should work for ng2', async() => { + it('should work for ng2', async () => { openBrowser({ url: '/', params: [{name: 'copies', value: 1}], diff --git a/modules/benchmarks/src/largeform/largeform.perf-spec.ts b/modules/benchmarks/src/largeform/largeform.perf-spec.ts index fe06cd8ef361a..ccab69f06521d 100644 --- a/modules/benchmarks/src/largeform/largeform.perf-spec.ts +++ b/modules/benchmarks/src/largeform/largeform.perf-spec.ts @@ -26,12 +26,11 @@ const CreateAndDestroyWorker = { }; describe('largeform benchmark spec', () => { - afterEach(verifyNoBrowserErrors); [CreateAndDestroyWorker].forEach((worker) => { describe(worker.id, () => { - it('should run for ng2', async() => { + it('should run for ng2', async () => { await runLargeFormBenchmark({url: '/', id: `largeform.ng2.${worker.id}`, worker: worker}); }); }); diff --git a/modules/benchmarks/src/largetable/incremental_dom/table.ts b/modules/benchmarks/src/largetable/incremental_dom/table.ts index 7d50f8ff2731a..6a9e60024d985 100644 --- a/modules/benchmarks/src/largetable/incremental_dom/table.ts +++ b/modules/benchmarks/src/largetable/incremental_dom/table.ts @@ -17,7 +17,9 @@ const {patch, elementOpen, elementClose, elementOpenStart, elementOpenEnd, attr, export class TableComponent { constructor(private _rootEl: any) {} - set data(data: TableCell[][]) { patch(this._rootEl, () => this._render(data)); } + set data(data: TableCell[][]) { + patch(this._rootEl, () => this._render(data)); + } private _render(data: TableCell[][]) { elementOpen('table'); diff --git a/modules/benchmarks/src/largetable/largetable.e2e-spec.ts b/modules/benchmarks/src/largetable/largetable.e2e-spec.ts index 0068b33b2a521..3b6da53085fa0 100644 --- a/modules/benchmarks/src/largetable/largetable.e2e-spec.ts +++ b/modules/benchmarks/src/largetable/largetable.e2e-spec.ts @@ -13,7 +13,7 @@ import {openBrowser, verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('largetable benchmark', () => { afterEach(verifyNoBrowserErrors); - it(`should render the table`, async() => { + it(`should render the table`, async () => { openBrowser({ url: '', ignoreBrowserSynchronization: true, diff --git a/modules/benchmarks/src/largetable/largetable.perf-spec.ts b/modules/benchmarks/src/largetable/largetable.perf-spec.ts index b78931a009f96..ffd96ece13c65 100644 --- a/modules/benchmarks/src/largetable/largetable.perf-spec.ts +++ b/modules/benchmarks/src/largetable/largetable.perf-spec.ts @@ -40,15 +40,14 @@ const UpdateWorker: Worker = { // name. e.g. "largeTable.ng2_switch.createDestroy". We determine the name of the // Bazel package where this test runs from the current test target. The Bazel target // looks like: "//modules/benchmarks/src/largetable/{pkg_name}:{target_name}". -const testPackageName = process.env['BAZEL_TARGET'] !.split(':')[0].split('/').pop(); +const testPackageName = process.env['BAZEL_TARGET']!.split(':')[0].split('/').pop(); describe('largetable benchmark perf', () => { - afterEach(verifyNoBrowserErrors); [CreateOnlyWorker, CreateAndDestroyWorker, UpdateWorker].forEach((worker) => { describe(worker.id, () => { - it(`should run benchmark for ${testPackageName}`, async() => { + it(`should run benchmark for ${testPackageName}`, async () => { await runTableBenchmark({ id: `largeTable.${testPackageName}.${worker.id}`, url: '/', diff --git a/modules/benchmarks/src/largetable/ng2/table.ts b/modules/benchmarks/src/largetable/ng2/table.ts index 55028bf29a3f4..d00f811563312 100644 --- a/modules/benchmarks/src/largetable/ng2/table.ts +++ b/modules/benchmarks/src/largetable/ng2/table.ts @@ -9,7 +9,7 @@ import {Component, Input, NgModule} from '@angular/core'; import {BrowserModule, DomSanitizer, SafeStyle} from '@angular/platform-browser'; -import {TableCell, emptyTable} from '../util'; +import {emptyTable, TableCell} from '../util'; let trustedEmptyColor: SafeStyle; let trustedGreyColor: SafeStyle; @@ -25,12 +25,15 @@ let trustedGreyColor: SafeStyle; </tbody></table>`, }) export class TableComponent { - @Input() - data: TableCell[][] = emptyTable; + @Input() data: TableCell[][] = emptyTable; - trackByIndex(index: number, item: any) { return index; } + trackByIndex(index: number, item: any) { + return index; + } - getColor(row: number) { return row % 2 ? trustedEmptyColor : trustedGreyColor; } + getColor(row: number) { + return row % 2 ? trustedEmptyColor : trustedGreyColor; + } } @NgModule({imports: [BrowserModule], bootstrap: [TableComponent], declarations: [TableComponent]}) diff --git a/modules/benchmarks/src/largetable/ng2_switch/table.ts b/modules/benchmarks/src/largetable/ng2_switch/table.ts index 10b73f6539be0..8e1c5a7fe2bfd 100644 --- a/modules/benchmarks/src/largetable/ng2_switch/table.ts +++ b/modules/benchmarks/src/largetable/ng2_switch/table.ts @@ -9,7 +9,7 @@ import {Component, Input, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; -import {TableCell, emptyTable} from '../util'; +import {emptyTable, TableCell} from '../util'; @Component({ selector: 'largetable', @@ -22,10 +22,11 @@ import {TableCell, emptyTable} from '../util'; </tbody></table>` }) export class TableComponent { - @Input() - data: TableCell[][] = emptyTable; + @Input() data: TableCell[][] = emptyTable; - trackByIndex(index: number, item: any) { return index; } + trackByIndex(index: number, item: any) { + return index; + } } @NgModule({imports: [BrowserModule], bootstrap: [TableComponent], declarations: [TableComponent]}) diff --git a/modules/benchmarks/src/largetable/render3/index_aot.ts b/modules/benchmarks/src/largetable/render3/index_aot.ts index 77c3c8610dc89..6abeee67421bb 100644 --- a/modules/benchmarks/src/largetable/render3/index_aot.ts +++ b/modules/benchmarks/src/largetable/render3/index_aot.ts @@ -9,7 +9,7 @@ import {ɵrenderComponent as renderComponent} from '@angular/core'; import {bindAction, profile} from '../../util'; -import {LargeTableComponent, createDom, destroyDom} from './table'; +import {createDom, destroyDom, LargeTableComponent} from './table'; function noop() {} diff --git a/modules/benchmarks/src/largetable/render3/table.ts b/modules/benchmarks/src/largetable/render3/table.ts index 5634f68f375f7..85339a976e935 100644 --- a/modules/benchmarks/src/largetable/render3/table.ts +++ b/modules/benchmarks/src/largetable/render3/table.ts @@ -9,7 +9,7 @@ import {CommonModule} from '@angular/common'; import {Component, Input, NgModule, ɵdetectChanges} from '@angular/core'; -import {TableCell, buildTable, emptyTable} from '../util'; +import {buildTable, emptyTable, TableCell} from '../util'; @Component({ selector: 'largetable', @@ -26,12 +26,15 @@ import {TableCell, buildTable, emptyTable} from '../util'; `, }) export class LargeTableComponent { - @Input() - data: TableCell[][] = emptyTable; + @Input() data: TableCell[][] = emptyTable; - trackByIndex(index: number, item: any) { return index; } + trackByIndex(index: number, item: any) { + return index; + } - getColor(row: number) { return row % 2 ? '' : 'grey'; } + getColor(row: number) { + return row % 2 ? '' : 'grey'; + } } @NgModule({declarations: [LargeTableComponent], imports: [CommonModule]}) diff --git a/modules/benchmarks/src/old/compiler/compiler_benchmark.ts b/modules/benchmarks/src/old/compiler/compiler_benchmark.ts index 51cf1d0ffab45..9dd4572bc84b2 100644 --- a/modules/benchmarks/src/old/compiler/compiler_benchmark.ts +++ b/modules/benchmarks/src/old/compiler/compiler_benchmark.ts @@ -6,28 +6,23 @@ * found in the LICENSE file at https://angular.io/license */ +import {CompilerConfig, DirectiveResolver} from '@angular/compiler'; +import {Component, ComponentResolver, Directive, ViewContainerRef,} from '@angular/core'; +import {ViewMetadata} from '@angular/core/src/metadata/view'; import {PromiseWrapper} from '@angular/facade/src/async'; -import {Type, print} from '@angular/facade/src/lang'; +import {print, Type} from '@angular/facade/src/lang'; import {bootstrap} from '@angular/platform-browser'; import {BrowserDomAdapter} from '@angular/platform-browser/src/browser/browser_adapter'; import {DOM} from '@angular/platform-browser/src/dom/dom_adapter'; - -import {ComponentResolver, Component, Directive, ViewContainerRef,} from '@angular/core'; - -import {ViewMetadata} from '@angular/core/src/metadata/view'; - -import {CompilerConfig, DirectiveResolver} from '@angular/compiler'; - -import {getIntParameter, bindAction} from '@angular/testing/src/benchmark_util'; +import {bindAction, getIntParameter} from '@angular/testing/src/benchmark_util'; function _createBindings(): any[] { const multiplyTemplatesBy = getIntParameter('elements'); return [ { provide: DirectiveResolver, - useFactory: - () => new MultiplyDirectiveResolver( - multiplyTemplatesBy, [BenchmarkComponentNoBindings, BenchmarkComponentWithBindings]), + useFactory: () => new MultiplyDirectiveResolver( + multiplyTemplatesBy, [BenchmarkComponentNoBindings, BenchmarkComponentWithBindings]), deps: [] }, // Use interpretative mode as Dart does not support JIT and @@ -57,7 +52,9 @@ function measureWrapper(func, desc) { const elapsedMs = new Date().getTime() - begin.getTime(); print(`[${desc}] ...done, took ${elapsedMs} ms`); }; - const onError = function(e) { DOM.logError(e); }; + const onError = function(e) { + DOM.logError(e); + }; PromiseWrapper.then(func(), onSuccess, onError); }; } diff --git a/modules/benchmarks/src/old/compiler/selector_benchmark.ts b/modules/benchmarks/src/old/compiler/selector_benchmark.ts index d1812a2d6d20d..028728eaa6eef 100644 --- a/modules/benchmarks/src/old/compiler/selector_benchmark.ts +++ b/modules/benchmarks/src/old/compiler/selector_benchmark.ts @@ -47,7 +47,9 @@ export function main() { function match() { let matchCount = 0; for (let i = 0; i < count; i++) { - fixedMatcher.match(fixedSelectors[i][0], (selector, selected) => { matchCount += selected; }); + fixedMatcher.match(fixedSelectors[i][0], (selector, selected) => { + matchCount += selected; + }); } return matchCount; } diff --git a/modules/benchmarks/src/old/costs/index.ts b/modules/benchmarks/src/old/costs/index.ts index 74023d5610766..2d3929b8fb492 100644 --- a/modules/benchmarks/src/old/costs/index.ts +++ b/modules/benchmarks/src/old/costs/index.ts @@ -10,7 +10,7 @@ import {NgFor, NgIf} from '@angular/common'; import {Component, Directive, DynamicComponentLoader, ViewContainerRef} from '@angular/core'; import {ApplicationRef} from '@angular/core/src/application_ref'; import {ListWrapper} from '@angular/facade/src/lang'; -import {BrowserModule, bootstrap} from '@angular/platform-browser'; +import {bootstrap, BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {bindAction, getIntParameter} from '@angular/testing/src/benchmark_util'; @@ -89,7 +89,9 @@ class AppComponent { testingWithDirectives: boolean; testingDynamicComponents: boolean; - constructor() { this.reset(); } + constructor() { + this.reset(); + } reset(): void { this.list = []; diff --git a/modules/benchmarks/src/old/di/di_benchmark.ts b/modules/benchmarks/src/old/di/di_benchmark.ts index 6d1e8fcc48752..ca00d579639af 100644 --- a/modules/benchmarks/src/old/di/di_benchmark.ts +++ b/modules/benchmarks/src/old/di/di_benchmark.ts @@ -98,30 +98,42 @@ export function main() { @Injectable() class A { - constructor() { count++; } + constructor() { + count++; + } } @Injectable() class B { - constructor(a: A) { count++; } + constructor(a: A) { + count++; + } } @Injectable() class C { - constructor(b: B) { count++; } + constructor(b: B) { + count++; + } } @Injectable() class D { - constructor(c: C, b: B) { count++; } + constructor(c: C, b: B) { + count++; + } } @Injectable() class E { - constructor(d: D, c: C) { count++; } + constructor(d: D, c: C) { + count++; + } } @Injectable() class F { - constructor(e: E, d: D) { count++; } + constructor(e: E, d: D) { + count++; + } } diff --git a/modules/benchmarks/src/old/naive_infinite_scroll/app.ts b/modules/benchmarks/src/old/naive_infinite_scroll/app.ts index 4456bf3fe1c99..8d4297d7b5113 100644 --- a/modules/benchmarks/src/old/naive_infinite_scroll/app.ts +++ b/modules/benchmarks/src/old/naive_infinite_scroll/app.ts @@ -45,7 +45,9 @@ export class App { for (let i = 0; i < appSize; i++) { this.scrollAreas.push(i); } - bindAction('#run-btn', () => { this.runBenchmark(); }); + bindAction('#run-btn', () => { + this.runBenchmark(); + }); bindAction('#reset-btn', () => { this._getScrollDiv().scrollTop = 0; const existingMarker = this._locateFinishedMarker(); @@ -88,7 +90,11 @@ export class App { }, 0); } - private _locateFinishedMarker() { return DOM.querySelector(document.body, '#done'); } + private _locateFinishedMarker() { + return DOM.querySelector(document.body, '#done'); + } - private _getScrollDiv() { return DOM.query('body /deep/ #scrollDiv'); } + private _getScrollDiv() { + return DOM.query('body /deep/ #scrollDiv'); + } } diff --git a/modules/benchmarks/src/old/naive_infinite_scroll/cells.ts b/modules/benchmarks/src/old/naive_infinite_scroll/cells.ts index 747ff2fd2a205..1f4de9cb6f102 100644 --- a/modules/benchmarks/src/old/naive_infinite_scroll/cells.ts +++ b/modules/benchmarks/src/old/naive_infinite_scroll/cells.ts @@ -16,7 +16,9 @@ export class HasStyle { constructor() {} - set width(w: number) { this.cellWidth = w; } + set width(w: number) { + this.cellWidth = w; + } } @Component({ @@ -74,7 +76,9 @@ export class StageButtonsComponent extends HasStyle { private _offering: Offering; stages: Stage[]; - get offering(): Offering { return this._offering; } + get offering(): Offering { + return this._offering; + } set offering(offering: Offering) { this._offering = offering; diff --git a/modules/benchmarks/src/old/naive_infinite_scroll/common.ts b/modules/benchmarks/src/old/naive_infinite_scroll/common.ts index 4d0a269a051ec..2279def26466d 100644 --- a/modules/benchmarks/src/old/naive_infinite_scroll/common.ts +++ b/modules/benchmarks/src/old/naive_infinite_scroll/common.ts @@ -56,13 +56,17 @@ export class CustomDate { return new CustomDate(newYear, newMonth, newDay); } - static now(): CustomDate { return new CustomDate(2014, 1, 28); } + static now(): CustomDate { + return new CustomDate(2014, 1, 28); + } } export class RawEntity { private _data: Map<any, any>; - constructor() { this._data = new Map(); } + constructor() { + this._data = new Map(); + } get(key: string) { if (key.indexOf('.') == -1) { @@ -114,51 +118,107 @@ export class RawEntity { } export class Company extends RawEntity { - get name(): string { return this.get('name'); } - set name(val: string) { this.set('name', val); } + get name(): string { + return this.get('name'); + } + set name(val: string) { + this.set('name', val); + } } export class Offering extends RawEntity { - get name(): string { return this.get('name'); } - set name(val: string) { this.set('name', val); } + get name(): string { + return this.get('name'); + } + set name(val: string) { + this.set('name', val); + } - get company(): Company { return this.get('company'); } - set company(val: Company) { this.set('company', val); } + get company(): Company { + return this.get('company'); + } + set company(val: Company) { + this.set('company', val); + } - get opportunity(): Opportunity { return this.get('opportunity'); } - set opportunity(val: Opportunity) { this.set('opportunity', val); } + get opportunity(): Opportunity { + return this.get('opportunity'); + } + set opportunity(val: Opportunity) { + this.set('opportunity', val); + } - get account(): Account { return this.get('account'); } - set account(val: Account) { this.set('account', val); } + get account(): Account { + return this.get('account'); + } + set account(val: Account) { + this.set('account', val); + } - get basePoints(): number { return this.get('basePoints'); } - set basePoints(val: number) { this.set('basePoints', val); } + get basePoints(): number { + return this.get('basePoints'); + } + set basePoints(val: number) { + this.set('basePoints', val); + } - get kickerPoints(): number { return this.get('kickerPoints'); } - set kickerPoints(val: number) { this.set('kickerPoints', val); } + get kickerPoints(): number { + return this.get('kickerPoints'); + } + set kickerPoints(val: number) { + this.set('kickerPoints', val); + } - get status(): string { return this.get('status'); } - set status(val: string) { this.set('status', val); } + get status(): string { + return this.get('status'); + } + set status(val: string) { + this.set('status', val); + } - get bundles(): string { return this.get('bundles'); } - set bundles(val: string) { this.set('bundles', val); } + get bundles(): string { + return this.get('bundles'); + } + set bundles(val: string) { + this.set('bundles', val); + } - get dueDate(): CustomDate { return this.get('dueDate'); } - set dueDate(val: CustomDate) { this.set('dueDate', val); } + get dueDate(): CustomDate { + return this.get('dueDate'); + } + set dueDate(val: CustomDate) { + this.set('dueDate', val); + } - get endDate(): CustomDate { return this.get('endDate'); } - set endDate(val: CustomDate) { this.set('endDate', val); } + get endDate(): CustomDate { + return this.get('endDate'); + } + set endDate(val: CustomDate) { + this.set('endDate', val); + } - get aatStatus(): string { return this.get('aatStatus'); } - set aatStatus(val: string) { this.set('aatStatus', val); } + get aatStatus(): string { + return this.get('aatStatus'); + } + set aatStatus(val: string) { + this.set('aatStatus', val); + } } export class Opportunity extends RawEntity { - get name(): string { return this.get('name'); } - set name(val: string) { this.set('name', val); } + get name(): string { + return this.get('name'); + } + set name(val: string) { + this.set('name', val); + } } export class Account extends RawEntity { - get accountId(): number { return this.get('accountId'); } - set accountId(val: number) { this.set('accountId', val); } + get accountId(): number { + return this.get('accountId'); + } + set accountId(val: number) { + this.set('accountId', val); + } } diff --git a/modules/benchmarks/src/old/naive_infinite_scroll/scroll_area.ts b/modules/benchmarks/src/old/naive_infinite_scroll/scroll_area.ts index f0b71725d3ced..807c29a166563 100644 --- a/modules/benchmarks/src/old/naive_infinite_scroll/scroll_area.ts +++ b/modules/benchmarks/src/old/naive_infinite_scroll/scroll_area.ts @@ -9,7 +9,7 @@ import {NgFor} from '@angular/common'; import {Component, Directive} from '@angular/core'; -import {HEIGHT, ITEMS, ITEM_HEIGHT, Offering, ROW_WIDTH, VIEW_PORT_HEIGHT, VISIBLE_ITEMS} from './common'; +import {HEIGHT, ITEM_HEIGHT, ITEMS, Offering, ROW_WIDTH, VIEW_PORT_HEIGHT, VISIBLE_ITEMS} from './common'; import {generateOfferings} from './random_data'; import {ScrollItemComponent} from './scroll_item'; diff --git a/modules/benchmarks/src/old/naive_infinite_scroll/scroll_item.ts b/modules/benchmarks/src/old/naive_infinite_scroll/scroll_item.ts index b88862454449c..4604384676a67 100644 --- a/modules/benchmarks/src/old/naive_infinite_scroll/scroll_item.ts +++ b/modules/benchmarks/src/old/naive_infinite_scroll/scroll_item.ts @@ -9,7 +9,7 @@ import {Component, Directive} from '@angular/core'; import {AccountCellComponent, CompanyNameComponent, FormattedCellComponent, OfferingNameComponent, OpportunityNameComponent, StageButtonsComponent} from './cells'; -import {AAT_STATUS_WIDTH, ACCOUNT_CELL_WIDTH, BASE_POINTS_WIDTH, BUNDLES_WIDTH, COMPANY_NAME_WIDTH, DUE_DATE_WIDTH, END_DATE_WIDTH, ITEM_HEIGHT, KICKER_POINTS_WIDTH, OFFERING_NAME_WIDTH, OPPORTUNITY_NAME_WIDTH, Offering, STAGE_BUTTONS_WIDTH} from './common'; +import {AAT_STATUS_WIDTH, ACCOUNT_CELL_WIDTH, BASE_POINTS_WIDTH, BUNDLES_WIDTH, COMPANY_NAME_WIDTH, DUE_DATE_WIDTH, END_DATE_WIDTH, ITEM_HEIGHT, KICKER_POINTS_WIDTH, Offering, OFFERING_NAME_WIDTH, OPPORTUNITY_NAME_WIDTH, STAGE_BUTTONS_WIDTH} from './common'; @Component({ selector: 'scroll-item', @@ -63,17 +63,41 @@ export class ScrollItemComponent { itemHeight: number; - constructor() { this.itemHeight = ITEM_HEIGHT; } + constructor() { + this.itemHeight = ITEM_HEIGHT; + } - get companyNameWidth() { return COMPANY_NAME_WIDTH; } - get opportunityNameWidth() { return OPPORTUNITY_NAME_WIDTH; } - get offeringNameWidth() { return OFFERING_NAME_WIDTH; } - get accountCellWidth() { return ACCOUNT_CELL_WIDTH; } - get basePointsWidth() { return BASE_POINTS_WIDTH; } - get kickerPointsWidth() { return KICKER_POINTS_WIDTH; } - get stageButtonsWidth() { return STAGE_BUTTONS_WIDTH; } - get bundlesWidth() { return BUNDLES_WIDTH; } - get dueDateWidth() { return DUE_DATE_WIDTH; } - get endDateWidth() { return END_DATE_WIDTH; } - get aatStatusWidth() { return AAT_STATUS_WIDTH; } + get companyNameWidth() { + return COMPANY_NAME_WIDTH; + } + get opportunityNameWidth() { + return OPPORTUNITY_NAME_WIDTH; + } + get offeringNameWidth() { + return OFFERING_NAME_WIDTH; + } + get accountCellWidth() { + return ACCOUNT_CELL_WIDTH; + } + get basePointsWidth() { + return BASE_POINTS_WIDTH; + } + get kickerPointsWidth() { + return KICKER_POINTS_WIDTH; + } + get stageButtonsWidth() { + return STAGE_BUTTONS_WIDTH; + } + get bundlesWidth() { + return BUNDLES_WIDTH; + } + get dueDateWidth() { + return DUE_DATE_WIDTH; + } + get endDateWidth() { + return END_DATE_WIDTH; + } + get aatStatusWidth() { + return AAT_STATUS_WIDTH; + } } diff --git a/modules/benchmarks/src/styling/ng2/init.ts b/modules/benchmarks/src/styling/ng2/init.ts index e7816d80f8cd4..b697223019c09 100644 --- a/modules/benchmarks/src/styling/ng2/init.ts +++ b/modules/benchmarks/src/styling/ng2/init.ts @@ -23,7 +23,7 @@ export function init(moduleRef: NgModuleRef<StylingModule>) { const componentRef = appRef.components[0]; const component = componentRef.instance; const componentHostEl = componentRef.location.nativeElement; - const select = document.querySelector('#scenario-select') !as HTMLSelectElement; + const select = document.querySelector('#scenario-select')! as HTMLSelectElement; function create(tplRefIdx: number) { component.tplRefIdx = tplRefIdx; @@ -41,7 +41,9 @@ export function init(moduleRef: NgModuleRef<StylingModule>) { appRef.tick(); } - function detectChanges() { appRef.tick(); } + function detectChanges() { + appRef.tick(); + } function modifyExternally() { const buttonEls = componentHostEl.querySelectorAll('button') as HTMLButtonElement[]; diff --git a/modules/benchmarks/src/styling/ng2/styling.ts b/modules/benchmarks/src/styling/ng2/styling.ts index b669654ae7f05..87c65829f99df 100644 --- a/modules/benchmarks/src/styling/ng2/styling.ts +++ b/modules/benchmarks/src/styling/ng2/styling.ts @@ -35,7 +35,9 @@ export class StylingComponent { tplRefIdx: number = 0; staticStyle = {width: '10px'}; - getTplRef(...tplRefs): TemplateRef<any> { return tplRefs[this.tplRefIdx]; } + getTplRef(...tplRefs): TemplateRef<any> { + return tplRefs[this.tplRefIdx]; + } } @NgModule({ diff --git a/modules/benchmarks/src/styling/styling_perf.spec.ts b/modules/benchmarks/src/styling/styling_perf.spec.ts index edf69fd43d4bd..779ef33bf8c70 100644 --- a/modules/benchmarks/src/styling/styling_perf.spec.ts +++ b/modules/benchmarks/src/styling/styling_perf.spec.ts @@ -28,7 +28,7 @@ const SCENARIOS = [ describe('styling benchmark spec', () => { afterEach(verifyNoBrowserErrors); - it('should render and interact to update and detect changes', async() => { + it('should render and interact to update and detect changes', async () => { openBrowser({url: '/', ignoreBrowserSynchronization: true}); create(); const items = element.all(by.css('styling-bindings button')); @@ -38,7 +38,7 @@ describe('styling benchmark spec', () => { expect(await items.first().getAttribute('title')).toBe('baz'); }); - it('should render and run noop change detection', async() => { + it('should render and run noop change detection', async () => { openBrowser({url: '/', ignoreBrowserSynchronization: true}); create(); const items = element.all(by.css('styling-bindings button')); @@ -51,7 +51,7 @@ describe('styling benchmark spec', () => { // Create benchmarks for each possible test scenario. SCENARIOS.forEach(({optionIndex, id}) => { describe(id, () => { - it('should run create benchmark', async() => { + it('should run create benchmark', async () => { await runStylingBenchmark(`styling.${id}.create`, { work: () => create(), prepare: () => { @@ -61,7 +61,7 @@ describe('styling benchmark spec', () => { }); }); - it('should run update benchmark', async() => { + it('should run update benchmark', async () => { await runStylingBenchmark(`styling.${id}.update`, { work: () => update(), prepare: () => { @@ -71,7 +71,7 @@ describe('styling benchmark spec', () => { }); }); - it('should run detect changes benchmark', async() => { + it('should run detect changes benchmark', async () => { await runStylingBenchmark(`styling.${id}.noop_cd`, { work: () => detectChanges(), prepare: () => { diff --git a/modules/benchmarks/src/tree/baseline/tree.ts b/modules/benchmarks/src/tree/baseline/tree.ts index 8350018a600c1..c1a97ba99cfbb 100644 --- a/modules/benchmarks/src/tree/baseline/tree.ts +++ b/modules/benchmarks/src/tree/baseline/tree.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {TreeNode, newArray} from '../util'; +import {newArray, TreeNode} from '../util'; export class TreeComponent { private _renderNodes: any[]; diff --git a/modules/benchmarks/src/tree/incremental_dom/tree.ts b/modules/benchmarks/src/tree/incremental_dom/tree.ts index 0a5a23ab6bafe..c241f4ab5b1b1 100644 --- a/modules/benchmarks/src/tree/incremental_dom/tree.ts +++ b/modules/benchmarks/src/tree/incremental_dom/tree.ts @@ -17,7 +17,9 @@ const {patch, elementOpen, elementClose, elementOpenStart, elementOpenEnd, text, export class TreeComponent { constructor(private _rootEl: any) {} - set data(data: TreeNode) { patch(this._rootEl, () => this._render(data)); } + set data(data: TreeNode) { + patch(this._rootEl, () => this._render(data)); + } private _render(data: TreeNode) { elementOpenStart('span', '', null); diff --git a/modules/benchmarks/src/tree/ng1/index.ts b/modules/benchmarks/src/tree/ng1/index.ts index d4dd3c80ae2ae..40348ed4aaebe 100644 --- a/modules/benchmarks/src/tree/ng1/index.ts +++ b/modules/benchmarks/src/tree/ng1/index.ts @@ -15,7 +15,7 @@ declare var angular: any; function init() { let detectChangesRuns = 0; - const numberOfChecksEl = document.getElementById('numberOfChecks') !; + const numberOfChecksEl = document.getElementById('numberOfChecks')!; addTreeToModule(angular.module('app', [])).run([ '$rootScope', @@ -31,11 +31,15 @@ function init() { function noop() {} function destroyDom() { - $rootScope.$apply(() => { $rootScope.initData = emptyTree; }); + $rootScope.$apply(() => { + $rootScope.initData = emptyTree; + }); } function createDom() { - $rootScope.$apply(() => { $rootScope.initData = buildTree(); }); + $rootScope.$apply(() => { + $rootScope.initData = buildTree(); + }); } bindAction('#destroyDom', destroyDom); diff --git a/modules/benchmarks/src/tree/ng1/tree.ts b/modules/benchmarks/src/tree/ng1/tree.ts index d914fa9b7b1bb..a212febb9819e 100644 --- a/modules/benchmarks/src/tree/ng1/tree.ts +++ b/modules/benchmarks/src/tree/ng1/tree.ts @@ -41,7 +41,6 @@ export function addTreeToModule(mod: any): any { } let childElement: any, childScope: any; $scope.$watch($attr.data, function ngIfWatchAction(value: any) { - if (value) { if (!childScope) { childScope = $scope.$new(); @@ -67,6 +66,8 @@ export function addTreeToModule(mod: any): any { ]) .config([ '$compileProvider', - function($compileProvider: any) { $compileProvider.debugInfoEnabled(false); } + function($compileProvider: any) { + $compileProvider.debugInfoEnabled(false); + } ]); } diff --git a/modules/benchmarks/src/tree/ng2/init.ts b/modules/benchmarks/src/tree/ng2/init.ts index 06d5b861283bf..1f45f7cb0f2f6 100644 --- a/modules/benchmarks/src/tree/ng2/init.ts +++ b/modules/benchmarks/src/tree/ng2/init.ts @@ -40,7 +40,7 @@ export function init(moduleRef: NgModuleRef<AppModule>) { const injector = moduleRef.injector; appRef = injector.get(ApplicationRef); - const numberOfChecksEl = document.getElementById('numberOfChecks') !; + const numberOfChecksEl = document.getElementById('numberOfChecks')!; tree = appRef.components[0].instance; diff --git a/modules/benchmarks/src/tree/ng2/tree.ts b/modules/benchmarks/src/tree/ng2/tree.ts index eea897e5cb6a0..199f33355cc4c 100644 --- a/modules/benchmarks/src/tree/ng2/tree.ts +++ b/modules/benchmarks/src/tree/ng2/tree.ts @@ -9,7 +9,7 @@ import {Component, NgModule} from '@angular/core'; import {BrowserModule, DomSanitizer, SafeStyle} from '@angular/platform-browser'; -import {TreeNode, emptyTree} from '../util'; +import {emptyTree, TreeNode} from '../util'; let trustedEmptyColor: SafeStyle; let trustedGreyColor: SafeStyle; @@ -22,7 +22,9 @@ let trustedGreyColor: SafeStyle; }) export class TreeComponent { data: TreeNode = emptyTree; - get bgColor() { return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; } + get bgColor() { + return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; + } } @NgModule({imports: [BrowserModule], bootstrap: [TreeComponent], declarations: [TreeComponent]}) diff --git a/modules/benchmarks/src/tree/ng2_next/tree.ts b/modules/benchmarks/src/tree/ng2_next/tree.ts index 6ded8e33d64ae..31a28a9e3f82d 100644 --- a/modules/benchmarks/src/tree/ng2_next/tree.ts +++ b/modules/benchmarks/src/tree/ng2_next/tree.ts @@ -7,17 +7,19 @@ */ import {NgIf} from '@angular/common'; -import {ComponentFactory, ComponentFactoryResolver, ComponentRef, ErrorHandler, Injector, NgModuleRef, RendererFactory2, Sanitizer, TemplateRef, ViewContainerRef, ɵArgumentType as ArgumentType, ɵBindingFlags as BindingFlags, ɵNodeFlags as NodeFlags, ɵViewDefinition as ViewDefinition, ɵViewFlags as ViewFlags, ɵand as anchorDef, ɵccf as createComponentFactory, ɵdid as directiveDef, ɵeld as elementDef, ɵinitServicesIfNeeded as initServicesIfNeeded, ɵted as textDef, ɵvid as viewDef} from '@angular/core'; +import {ComponentFactory, ComponentFactoryResolver, ComponentRef, ErrorHandler, Injector, NgModuleRef, RendererFactory2, Sanitizer, TemplateRef, ViewContainerRef, ɵand as anchorDef, ɵArgumentType as ArgumentType, ɵBindingFlags as BindingFlags, ɵccf as createComponentFactory, ɵdid as directiveDef, ɵeld as elementDef, ɵinitServicesIfNeeded as initServicesIfNeeded, ɵNodeFlags as NodeFlags, ɵted as textDef, ɵvid as viewDef, ɵViewDefinition as ViewDefinition, ɵViewFlags as ViewFlags} from '@angular/core'; import {SafeStyle, ɵDomRendererFactory2 as DomRendererFactory2, ɵDomSanitizerImpl as DomSanitizerImpl} from '@angular/platform-browser'; -import {TreeNode, emptyTree} from '../util'; +import {emptyTree, TreeNode} from '../util'; let trustedEmptyColor: SafeStyle; let trustedGreyColor: SafeStyle; export class TreeComponent { data: TreeNode = emptyTree; - get bgColor() { return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; } + get bgColor() { + return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; + } } let viewFlags = ViewFlags.None; @@ -120,11 +122,19 @@ export class AppModule implements Injector, NgModuleRef<any> { this.componentFactory.create(Injector.NULL, [], this.componentFactory.selector, this); } - tick() { this.componentRef.changeDetectorRef.detectChanges(); } + tick() { + this.componentRef.changeDetectorRef.detectChanges(); + } - get injector() { return this; } - get componentFactoryResolver(): ComponentFactoryResolver { return null; } - get instance() { return this; } + get injector() { + return this; + } + get componentFactoryResolver(): ComponentFactoryResolver { + return null; + } + get instance() { + return this; + } destroy() {} onDestroy(callback: () => void) {} } diff --git a/modules/benchmarks/src/tree/ng2_static/tree.ts b/modules/benchmarks/src/tree/ng2_static/tree.ts index 2ca2adaf1d184..cf0af17d51230 100644 --- a/modules/benchmarks/src/tree/ng2_static/tree.ts +++ b/modules/benchmarks/src/tree/ng2_static/tree.ts @@ -9,24 +9,25 @@ import {Component, Input, NgModule} from '@angular/core'; import {BrowserModule, DomSanitizer, SafeStyle} from '@angular/platform-browser'; -import {TreeNode, emptyTree, getMaxDepth} from '../util'; +import {emptyTree, getMaxDepth, TreeNode} from '../util'; let trustedEmptyColor: SafeStyle; let trustedGreyColor: SafeStyle; function createTreeComponent(level: number, isLeaf: boolean) { - const nextTreeEl = `tree${level+1}`; + const nextTreeEl = `tree${level + 1}`; let template = `<span [style.backgroundColor]="bgColor"> {{data.value}} </span>`; if (!isLeaf) { - template += - `<${nextTreeEl} [data]='data.right'></${nextTreeEl}><${nextTreeEl} [data]='data.left'></${nextTreeEl}>`; + template += `<${nextTreeEl} [data]='data.right'></${nextTreeEl}><${ + nextTreeEl} [data]='data.left'></${nextTreeEl}>`; } @Component({selector: `tree${level}`, template: template}) class TreeComponent { - @Input() - data: TreeNode; - get bgColor() { return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; } + @Input() data: TreeNode; + get bgColor() { + return this.data.depth % 2 ? trustedEmptyColor : trustedGreyColor; + } } return TreeComponent; @@ -34,8 +35,7 @@ function createTreeComponent(level: number, isLeaf: boolean) { @Component({selector: 'tree', template: `<tree0 *ngIf="data.left != null" [data]='data'></tree0>`}) export class RootTreeComponent { - @Input() - data: TreeNode = emptyTree; + @Input() data: TreeNode = emptyTree; } function createModule(): any { diff --git a/modules/benchmarks/src/tree/ng2_switch/tree.ts b/modules/benchmarks/src/tree/ng2_switch/tree.ts index 42164490744a9..24ec4c6df9abd 100644 --- a/modules/benchmarks/src/tree/ng2_switch/tree.ts +++ b/modules/benchmarks/src/tree/ng2_switch/tree.ts @@ -9,7 +9,7 @@ import {Component, Input, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; -import {TreeNode, emptyTree} from '../util'; +import {emptyTree, TreeNode} from '../util'; @Component({ selector: 'tree', @@ -19,8 +19,7 @@ import {TreeNode, emptyTree} from '../util'; <tree *ngIf='data.right != null' [data]='data.right'></tree><tree *ngIf='data.left != null' [data]='data.left'></tree>` }) export class TreeComponent { - @Input() - data: TreeNode = emptyTree; + @Input() data: TreeNode = emptyTree; } @NgModule({ diff --git a/modules/benchmarks/src/tree/render3/index_aot.ts b/modules/benchmarks/src/tree/render3/index_aot.ts index b9235143140d6..797ccc7ff3976 100644 --- a/modules/benchmarks/src/tree/render3/index_aot.ts +++ b/modules/benchmarks/src/tree/render3/index_aot.ts @@ -7,8 +7,10 @@ */ import {ɵrenderComponent as renderComponent} from '@angular/core'; + import {bindAction, profile} from '../../util'; -import {TreeComponent, createDom, destroyDom, detectChanges} from './tree'; + +import {createDom, destroyDom, detectChanges, TreeComponent} from './tree'; function noop() {} diff --git a/modules/benchmarks/src/tree/render3/tree.ts b/modules/benchmarks/src/tree/render3/tree.ts index a6c77591cefd5..8fa337963d8e8 100644 --- a/modules/benchmarks/src/tree/render3/tree.ts +++ b/modules/benchmarks/src/tree/render3/tree.ts @@ -21,7 +21,7 @@ export function createDom(component: TreeComponent) { ɵdetectChanges(component); } -const numberOfChecksEl = document.getElementById('numberOfChecks') !; +const numberOfChecksEl = document.getElementById('numberOfChecks')!; let detectChangesRuns = 0; export function detectChanges(component: TreeComponent) { for (let i = 0; i < 10; i++) { @@ -42,7 +42,9 @@ export function detectChanges(component: TreeComponent) { }) export class TreeComponent { data: any = emptyTree; - get bgColor() { return this.data.depth % 2 ? '' : 'grey'; } + get bgColor() { + return this.data.depth % 2 ? '' : 'grey'; + } } @NgModule({declarations: [TreeComponent], imports: [CommonModule]}) diff --git a/modules/benchmarks/src/tree/render3_function/index.ts b/modules/benchmarks/src/tree/render3_function/index.ts index 32be3be0b8608..8afd56308d3b4 100644 --- a/modules/benchmarks/src/tree/render3_function/index.ts +++ b/modules/benchmarks/src/tree/render3_function/index.ts @@ -6,11 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {ɵRenderFlags, ɵrenderComponent as renderComponent, ɵɵadvance, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵdefineComponent, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵstyleProp, ɵɵtext, ɵɵtextInterpolate1} from '@angular/core'; +import {ɵrenderComponent as renderComponent, ɵRenderFlags, ɵɵadvance, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵdefineComponent, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵstyleProp, ɵɵtext, ɵɵtextInterpolate1} from '@angular/core'; import {bindAction, profile} from '../../util'; import {createDom, destroyDom, detectChanges} from '../render3/tree'; -import {TreeNode, emptyTree} from '../util'; +import {emptyTree, TreeNode} from '../util'; function noop() {} @@ -26,15 +26,16 @@ export class TreeFunction { selectors: [['tree']], decls: 5, vars: 2, - template: function(rf: ɵRenderFlags, ctx: TreeFunction) { - // bit of a hack - TreeTpl(rf, ctx.data); - }, + template: + function(rf: ɵRenderFlags, ctx: TreeFunction) { + // bit of a hack + TreeTpl(rf, ctx.data); + }, inputs: {data: 'data'} }); } -const TreeFunctionCmpDef = TreeFunction.ɵcmp as{decls: number, vars: number}; +const TreeFunctionCmpDef = TreeFunction.ɵcmp as {decls: number, vars: number}; export function TreeTpl(rf: ɵRenderFlags, ctx: TreeNode) { if (rf & ɵRenderFlags.Create) { ɵɵelementStart(0, 'tree'); diff --git a/modules/benchmarks/src/tree/tree.e2e-spec.ts b/modules/benchmarks/src/tree/tree.e2e-spec.ts index f86a822568f05..8f9ecfb3d5fa9 100644 --- a/modules/benchmarks/src/tree/tree.e2e-spec.ts +++ b/modules/benchmarks/src/tree/tree.e2e-spec.ts @@ -11,7 +11,7 @@ import {$} from 'protractor'; import {openTreeBenchmark} from './test_utils'; describe('tree benchmark', () => { - it('should work for createDestroy', async() => { + it('should work for createDestroy', async () => { openTreeBenchmark(); await $('#createDom').click(); expect($('#root').getText()).toContain('1'); @@ -19,7 +19,7 @@ describe('tree benchmark', () => { expect(await $('#root').getText()).toEqual(''); }); - it('should work for update', async() => { + it('should work for update', async () => { openTreeBenchmark(); await $('#createDom').click(); await $('#createDom').click(); diff --git a/modules/benchmarks/src/tree/tree.perf-spec.ts b/modules/benchmarks/src/tree/tree.perf-spec.ts index 2e52a2fae88f3..dc703a061826b 100644 --- a/modules/benchmarks/src/tree/tree.perf-spec.ts +++ b/modules/benchmarks/src/tree/tree.perf-spec.ts @@ -10,7 +10,7 @@ import {$} from 'protractor'; import {runTreeBenchmark} from './test_utils'; describe('tree benchmark perf', () => { - it('should work for createOnly', async() => { + it('should work for createOnly', async () => { await runTreeBenchmark({ // This cannot be called "createOnly" because the actual destroy benchmark // has the "createOnly" id already. See: https://github.com/angular/angular/pull/21503 @@ -20,7 +20,7 @@ describe('tree benchmark perf', () => { }); }); - it('should work for destroy', async() => { + it('should work for destroy', async () => { await runTreeBenchmark({ // This is actually a benchmark for destroying the dom, but it has been accidentally // named "createOnly". See https://github.com/angular/angular/pull/21503. @@ -30,7 +30,7 @@ describe('tree benchmark perf', () => { }); }); - it('should work for createDestroy', async() => { + it('should work for createDestroy', async () => { await runTreeBenchmark({ id: 'createDestroy', work: () => { @@ -40,7 +40,7 @@ describe('tree benchmark perf', () => { }); }); - it('should work for update', async() => { + it('should work for update', async () => { await runTreeBenchmark({ id: 'update', work: () => $('#createDom').click(), diff --git a/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts b/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts index d75539af1340f..d6f61653e2385 100644 --- a/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts +++ b/modules/benchmarks/src/tree/tree_detect_changes.e2e-spec.ts @@ -11,7 +11,7 @@ import {$} from 'protractor'; import {openTreeBenchmark} from './test_utils'; describe('tree benchmark detect changes', () => { - it('should work for detectChanges', async() => { + it('should work for detectChanges', async () => { openTreeBenchmark(); await $('#detectChanges').click(); expect($('#numberOfChecks').getText()).toContain('10'); diff --git a/modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts b/modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts index 822491e6193fe..49a391f476205 100644 --- a/modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts +++ b/modules/benchmarks/src/tree/tree_detect_changes.perf-spec.ts @@ -10,7 +10,7 @@ import {$} from 'protractor'; import {runTreeBenchmark} from './test_utils'; describe('tree benchmark detect changes perf', () => { - it('should work for detectChanges', async() => { + it('should work for detectChanges', async () => { await runTreeBenchmark({ id: 'detectChanges', work: () => $('#detectChanges').click(), diff --git a/modules/benchmarks/src/tree/util.ts b/modules/benchmarks/src/tree/util.ts index 4c9dc197898fa..519945df508e3 100644 --- a/modules/benchmarks/src/tree/util.ts +++ b/modules/benchmarks/src/tree/util.ts @@ -16,12 +16,14 @@ export class TreeNode { public value: string, public depth: number, public maxDepth: number, public left: TreeNode|null, public right: TreeNode|null) { this.transitiveChildCount = Math.pow(2, (this.maxDepth - this.depth + 1)) - 1; - this.children = this.left ? [this.left, this.right !] : []; + this.children = this.left ? [this.left, this.right!] : []; } // Needed for Polymer as it does not support ternary nor modulo operator // in expressions - get style(): string { return this.depth % 2 === 0 ? 'background-color: grey' : ''; } + get style(): string { + return this.depth % 2 === 0 ? 'background-color: grey' : ''; + } } let treeCreateCount: number; @@ -78,7 +80,7 @@ export function newArray<T>(size: number, value: T): T[]; export function newArray<T>(size: number, value?: T): T[] { const list: T[] = []; for (let i = 0; i < size; i++) { - list.push(value !); + list.push(value!); } return list; } diff --git a/modules/benchmarks/src/util.ts b/modules/benchmarks/src/util.ts index 099be1664c68b..e5937a64a1fb1 100644 --- a/modules/benchmarks/src/util.ts +++ b/modules/benchmarks/src/util.ts @@ -35,7 +35,7 @@ export function getStringParameter(name: string) { } export function bindAction(selector: string, callback: () => void) { - document.querySelector(selector) !.addEventListener('click', callback); + document.querySelector(selector)!.addEventListener('click', callback); } @@ -66,7 +66,8 @@ function reportProfileResults(durations: number[], count: number) { Number.MAX_SAFE_INTEGER) .toFixed(2); window.console.log( - `Iterations: ${count}; cold time: ${durations[0].toFixed(2)} ms; average time: ${avgDuration} ms / iteration; best time: ${minDuration} ms`); + `Iterations: ${count}; cold time: ${durations[0].toFixed(2)} ms; average time: ${ + avgDuration} ms / iteration; best time: ${minDuration} ms`); } // helper script that will read out the url parameters diff --git a/modules/benchmarks/src/views/views-benchmark.ts b/modules/benchmarks/src/views/views-benchmark.ts index 5984d34480b6e..d6d807c1a629b 100644 --- a/modules/benchmarks/src/views/views-benchmark.ts +++ b/modules/benchmarks/src/views/views-benchmark.ts @@ -20,7 +20,9 @@ export class ViewManipulationDirective { } } - clear() { this._vcRef.clear(); } + clear() { + this._vcRef.clear(); + } } @Component({ @@ -44,9 +46,13 @@ export class ViewsBenchmark { constructor(private _cdRef: ChangeDetectorRef) {} - create(vm: ViewManipulationDirective) { vm.create(1000); } + create(vm: ViewManipulationDirective) { + vm.create(1000); + } - destroy(vm: ViewManipulationDirective) { vm.clear(); } + destroy(vm: ViewManipulationDirective) { + vm.clear(); + } check() { for (let i = 0; i < 10000; i++) { diff --git a/modules/playground/e2e_test/hello_world/hello_world_spec.ts b/modules/playground/e2e_test/hello_world/hello_world_spec.ts index 7e20b09b742f3..2d167fec7436b 100644 --- a/modules/playground/e2e_test/hello_world/hello_world_spec.ts +++ b/modules/playground/e2e_test/hello_world/hello_world_spec.ts @@ -11,7 +11,6 @@ import {browser} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('hello world', function() { - afterEach(verifyNoBrowserErrors); describe('hello world app', function() { @@ -30,7 +29,6 @@ describe('hello world', function() { expect(getComponentText('hello-app', '.greeting')).toEqual('howdy world!'); }); }); - }); function getComponentText(selector: string, innerSelector: string) { diff --git a/modules/playground/e2e_test/http/http_spec.ts b/modules/playground/e2e_test/http/http_spec.ts index 58d4ecb0db8e6..f5a5618b3f198 100644 --- a/modules/playground/e2e_test/http/http_spec.ts +++ b/modules/playground/e2e_test/http/http_spec.ts @@ -11,7 +11,6 @@ import {browser} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('http', function() { - afterEach(verifyNoBrowserErrors); describe('fetching', function() { @@ -25,6 +24,6 @@ describe('http', function() { }); function getComponentText(selector: string, innerSelector: string) { - return browser.executeScript( - `return document.querySelector("${selector}").querySelector("${innerSelector}").textContent.trim()`); + return browser.executeScript(`return document.querySelector("${selector}").querySelector("${ + innerSelector}").textContent.trim()`); } diff --git a/modules/playground/e2e_test/jsonp/jsonp_spec.ts b/modules/playground/e2e_test/jsonp/jsonp_spec.ts index 71c6734ea4ba9..72f1003a5fffd 100644 --- a/modules/playground/e2e_test/jsonp/jsonp_spec.ts +++ b/modules/playground/e2e_test/jsonp/jsonp_spec.ts @@ -11,7 +11,6 @@ import {browser} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('jsonp', function() { - afterEach(verifyNoBrowserErrors); describe('fetching', function() { @@ -25,6 +24,6 @@ describe('jsonp', function() { }); function getComponentText(selector: string, innerSelector: string) { - return browser.executeScript( - `return document.querySelector("${selector}").querySelector("${innerSelector}").textContent.trim()`); + return browser.executeScript(`return document.querySelector("${selector}").querySelector("${ + innerSelector}").textContent.trim()`); } diff --git a/modules/playground/e2e_test/key_events/key_events_spec.ts b/modules/playground/e2e_test/key_events/key_events_spec.ts index f98d087df49c1..898950d8c5036 100644 --- a/modules/playground/e2e_test/key_events/key_events_spec.ts +++ b/modules/playground/e2e_test/key_events/key_events_spec.ts @@ -13,11 +13,12 @@ import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; const Key = protractor.Key; describe('key_events', function() { - const URL = '/'; afterEach(verifyNoBrowserErrors); - beforeEach(() => { browser.get(URL); }); + beforeEach(() => { + browser.get(URL); + }); it('should display correct key names', function() { const firstArea = element.all(by.css('.sample-area')).get(0); @@ -78,5 +79,4 @@ describe('key_events', function() { secondArea.sendKeys(Key.CONTROL, Key.SHIFT, Key.ENTER); expect(secondArea.getText()).toEqual(''); }); - }); diff --git a/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts b/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts index 8fd35bea15aed..25c96ee92c0af 100644 --- a/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts +++ b/modules/playground/e2e_test/model_driven_forms/model_driven_forms_spec.ts @@ -11,7 +11,6 @@ import {browser, by, element} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('Model-Driven Forms', function() { - afterEach(verifyNoBrowserErrors); const URL = '/'; diff --git a/modules/playground/e2e_test/relative_assets/assets_spec.ts b/modules/playground/e2e_test/relative_assets/assets_spec.ts index 1b777c6d2d0a1..eb57cfe5c3323 100644 --- a/modules/playground/e2e_test/relative_assets/assets_spec.ts +++ b/modules/playground/e2e_test/relative_assets/assets_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; @@ -16,7 +16,6 @@ function waitForElement(selector: string) { } describe('relative assets relative-app', () => { - afterEach(verifyNoBrowserErrors); const URL = '/'; diff --git a/modules/playground/e2e_test/routing/routing_spec.ts b/modules/playground/e2e_test/routing/routing_spec.ts index 9e28ba0d41752..f71e7eed8cf5f 100644 --- a/modules/playground/e2e_test/routing/routing_spec.ts +++ b/modules/playground/e2e_test/routing/routing_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; @@ -16,7 +16,6 @@ function waitForElement(selector: string) { } describe('routing inbox-app', () => { - afterEach(verifyNoBrowserErrors); describe('index view', () => { diff --git a/modules/playground/e2e_test/svg/svg_spec.ts b/modules/playground/e2e_test/svg/svg_spec.ts index 0c58cab353616..7cbeb29b98b50 100644 --- a/modules/playground/e2e_test/svg/svg_spec.ts +++ b/modules/playground/e2e_test/svg/svg_spec.ts @@ -11,15 +11,15 @@ import {browser, by, element} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('SVG', function() { - const URL = '/'; afterEach(verifyNoBrowserErrors); - beforeEach(() => { browser.get(URL); }); + beforeEach(() => { + browser.get(URL); + }); it('should display SVG component contents', function() { const svgText = element.all(by.css('g text')).get(0); expect(svgText.getText()).toEqual('Hello'); }); - }); diff --git a/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts b/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts index b822ad49cd2aa..96f0efc869c05 100644 --- a/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts +++ b/modules/playground/e2e_test/template_driven_forms/template_driven_forms_spec.ts @@ -11,7 +11,6 @@ import {browser, by, element} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('Template-Driven Forms', function() { - afterEach(verifyNoBrowserErrors); const URL = '/'; diff --git a/modules/playground/e2e_test/web_workers/input/input_spec.ts b/modules/playground/e2e_test/web_workers/input/input_spec.ts index 0659ba5adf8d8..bd73b09ccf81f 100644 --- a/modules/playground/e2e_test/web_workers/input/input_spec.ts +++ b/modules/playground/e2e_test/web_workers/input/input_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ExpectedConditions, browser, by, element, protractor} from 'protractor'; +import {browser, by, element, ExpectedConditions, protractor} from 'protractor'; import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; diff --git a/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts b/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts index a271f82ce5277..ecb474a84f486 100644 --- a/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts +++ b/modules/playground/e2e_test/web_workers/kitchen_sink/kitchen_sink_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ExpectedConditions, browser, by, element, protractor} from 'protractor'; +import {browser, by, element, ExpectedConditions, protractor} from 'protractor'; import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; @@ -27,7 +27,6 @@ describe('WebWorkers Kitchen Sink', function() { const elem = element(by.css(selector)); browser.wait(ExpectedConditions.textToBePresentInElement(elem, 'hello world!'), 5000); expect(elem.getText()).toEqual('hello world!'); - }); it('should change greeting', () => { diff --git a/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts b/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts index d5c1ec34ca878..23d59484addad 100644 --- a/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts +++ b/modules/playground/e2e_test/web_workers/message_broker/message_broker_spec.ts @@ -6,14 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {ExpectedConditions, browser, by, element, protractor} from 'protractor'; +import {browser, by, element, ExpectedConditions, protractor} from 'protractor'; import {verifyNoBrowserErrors} from '../../../../e2e_util/e2e_util'; const URL = '/'; describe('MessageBroker', function() { - afterEach(() => { verifyNoBrowserErrors(); browser.ignoreSynchronization = false; diff --git a/modules/playground/e2e_test/web_workers/router/router_spec.ts b/modules/playground/e2e_test/web_workers/router/router_spec.ts index 736e01fc54283..752687c20c9dd 100644 --- a/modules/playground/e2e_test/web_workers/router/router_spec.ts +++ b/modules/playground/e2e_test/web_workers/router/router_spec.ts @@ -69,7 +69,9 @@ describe('WebWorker Router', () => { browser.wait(() => { const deferred = protractor.promise.defer(); const elem = element(by.css(contentSelector)); - elem.getText().then((text: string) => { return deferred.fulfill(text === expected); }); + elem.getText().then((text: string) => { + return deferred.fulfill(text === expected); + }); return deferred.promise; }, 5000); } @@ -77,8 +79,9 @@ describe('WebWorker Router', () => { function waitForUrl(regex: RegExp): void { browser.wait(() => { const deferred = protractor.promise.defer(); - browser.getCurrentUrl().then( - (url: string) => { return deferred.fulfill(url.match(regex) !== null); }); + browser.getCurrentUrl().then((url: string) => { + return deferred.fulfill(url.match(regex) !== null); + }); return deferred.promise; }, 5000); } diff --git a/modules/playground/e2e_test/web_workers/todo/todo_spec.ts b/modules/playground/e2e_test/web_workers/todo/todo_spec.ts index f1a54158663db..2af60cf400fe2 100644 --- a/modules/playground/e2e_test/web_workers/todo/todo_spec.ts +++ b/modules/playground/e2e_test/web_workers/todo/todo_spec.ts @@ -26,7 +26,6 @@ describe('WebWorkers Todo', function() { waitForBootstrap(); expect(element(by.css('#todoapp header')).getText()).toEqual('todos'); }); - }); function waitForBootstrap(): void { diff --git a/modules/playground/e2e_test/zippy_component/zippy_spec.ts b/modules/playground/e2e_test/zippy_component/zippy_spec.ts index e3d7f25043564..6e66e4049be7f 100644 --- a/modules/playground/e2e_test/zippy_component/zippy_spec.ts +++ b/modules/playground/e2e_test/zippy_component/zippy_spec.ts @@ -11,13 +11,14 @@ import {browser, by, element} from 'protractor'; import {verifyNoBrowserErrors} from '../../../e2e_util/e2e_util'; describe('Zippy Component', function() { - afterEach(verifyNoBrowserErrors); describe('zippy', function() { const URL = '/'; - beforeEach(function() { browser.get(URL); }); + beforeEach(function() { + browser.get(URL); + }); it('should change the zippy title depending on it\'s state', function() { const zippyTitle = element(by.css('.zippy__title')); diff --git a/modules/playground/src/animate/app/animate-app.ts b/modules/playground/src/animate/app/animate-app.ts index 273fa5441563a..14f55429b46a8 100644 --- a/modules/playground/src/animate/app/animate-app.ts +++ b/modules/playground/src/animate/app/animate-app.ts @@ -87,7 +87,9 @@ export class AnimateApp { alert(`backgroundAnimation has ${phase} from ${data['fromState']} to ${data['toState']}`); } - get state() { return this._state; } + get state() { + return this._state; + } set state(s) { this._state = s; if (s == 'void') { diff --git a/modules/playground/src/async/index.ts b/modules/playground/src/async/index.ts index d3405212e02c8..5036c61f5e0a0 100644 --- a/modules/playground/src/async/index.ts +++ b/modules/playground/src/async/index.ts @@ -43,7 +43,9 @@ class AsyncApplication { multiTimeoutId: any = null; intervalId: any = null; - increment(): void { this.val1++; } + increment(): void { + this.val1++; + } delayedIncrement(): void { this.cancelDelayedIncrement(); diff --git a/modules/playground/src/gestures/index.ts b/modules/playground/src/gestures/index.ts index 2dbc531eb68ce..56f3c1c21b6cd 100644 --- a/modules/playground/src/gestures/index.ts +++ b/modules/playground/src/gestures/index.ts @@ -16,11 +16,17 @@ class GesturesCmp { pinchScale: number = 1; rotateAngle: number = 0; - onSwipe(event: HammerInput): void { this.swipeDirection = event.deltaX > 0 ? 'right' : 'left'; } + onSwipe(event: HammerInput): void { + this.swipeDirection = event.deltaX > 0 ? 'right' : 'left'; + } - onPinch(event: HammerInput): void { this.pinchScale = event.scale; } + onPinch(event: HammerInput): void { + this.pinchScale = event.scale; + } - onRotate(event: HammerInput): void { this.rotateAngle = event.rotation; } + onRotate(event: HammerInput): void { + this.rotateAngle = event.rotation; + } } @NgModule({declarations: [GesturesCmp], bootstrap: [GesturesCmp], imports: [BrowserModule]}) diff --git a/modules/playground/src/hello_world/index.ts b/modules/playground/src/hello_world/index.ts index 5a449f7f3ec09..c0a37bded689c 100644 --- a/modules/playground/src/hello_world/index.ts +++ b/modules/playground/src/hello_world/index.ts @@ -48,9 +48,13 @@ export class RedDec { export class HelloCmp { greeting: string; - constructor(service: GreetingService) { this.greeting = service.greeting; } + constructor(service: GreetingService) { + this.greeting = service.greeting; + } - changeGreeting(): void { this.greeting = 'howdy'; } + changeGreeting(): void { + this.greeting = 'howdy'; + } } @NgModule({declarations: [HelloCmp, RedDec], bootstrap: [HelloCmp], imports: [BrowserModule]}) diff --git a/modules/playground/src/key_events/index.ts b/modules/playground/src/key_events/index.ts index e73aaf437b14e..ed4c34bf67683 100644 --- a/modules/playground/src/key_events/index.ts +++ b/modules/playground/src/key_events/index.ts @@ -36,7 +36,9 @@ export class KeyEventsApp { event.preventDefault(); } - resetShiftEnter(): void { this.shiftEnter = false; } + resetShiftEnter(): void { + this.shiftEnter = false; + } /** * Get a more readable version of current pressed keys. diff --git a/modules/playground/src/model_driven_forms/index.ts b/modules/playground/src/model_driven_forms/index.ts index b71d22cf76bda..94138296a5b59 100644 --- a/modules/playground/src/model_driven_forms/index.ts +++ b/modules/playground/src/model_driven_forms/index.ts @@ -52,7 +52,9 @@ export class ShowError { controlPath: string; errorTypes: string[]; - constructor(@Host() formDir: FormGroupDirective) { this.formDir = formDir; } + constructor(@Host() formDir: FormGroupDirective) { + this.formDir = formDir; + } get errorMessage(): string { const form: FormGroup = this.formDir.form; diff --git a/modules/playground/src/order_management/index.ts b/modules/playground/src/order_management/index.ts index b83b10b9f1fea..10d933702f668 100644 --- a/modules/playground/src/order_management/index.ts +++ b/modules/playground/src/order_management/index.ts @@ -23,7 +23,9 @@ class OrderItem { public orderItemId: number, public orderId: number, public productName: string, public qty: number, public unitPrice: number) {} - get total(): number { return this.qty * this.unitPrice; } + get total(): number { + return this.qty * this.unitPrice; + } } class Order { @@ -31,8 +33,12 @@ class Order { public orderId: number, public customerName: string, public limit: number, private _dataService: DataService) {} - get items(): OrderItem[] { return this._dataService.itemsFor(this); } - get total(): number { return this.items.map(i => i.total).reduce((a, b) => a + b, 0); } + get items(): OrderItem[] { + return this._dataService.itemsFor(this); + } + get total(): number { + return this.items.map(i => i.total).reduce((a, b) => a + b, 0); + } } @@ -69,7 +75,9 @@ export class DataService { this.orderItems.push(new OrderItem(_nextId++, order.orderId, '', 0, 0)); } - deleteItem(item: OrderItem): void { this.orderItems.splice(this.orderItems.indexOf(item), 1); } + deleteItem(item: OrderItem): void { + this.orderItems.splice(this.orderItems.indexOf(item), 1); + } } @@ -107,8 +115,12 @@ export class DataService { export class OrderListComponent { orders: Order[]; - constructor(private _service: DataService) { this.orders = _service.orders; } - select(order: Order): void { this._service.currentOrder = order; } + constructor(private _service: DataService) { + this.orders = _service.orders; + } + select(order: Order): void { + this._service.currentOrder = order; + } } @@ -141,7 +153,9 @@ export class OrderItemComponent { @Input() item: OrderItem; @Output() delete = new EventEmitter(); - onDelete(): void { this.delete.emit(this.item); } + onDelete(): void { + this.delete.emit(this.item); + } } @Component({ @@ -176,11 +190,17 @@ export class OrderItemComponent { export class OrderDetailsComponent { constructor(private _service: DataService) {} - get order(): Order { return this._service.currentOrder; } + get order(): Order { + return this._service.currentOrder; + } - deleteItem(item: OrderItem): void { this._service.deleteItem(item); } + deleteItem(item: OrderItem): void { + this._service.deleteItem(item); + } - addItem(): void { this._service.addItemForOrder(this.order); } + addItem(): void { + this._service.addItemForOrder(this.order); + } } @Component({ diff --git a/modules/playground/src/person_management/index.ts b/modules/playground/src/person_management/index.ts index d981acad14575..e660952e1b294 100644 --- a/modules/playground/src/person_management/index.ts +++ b/modules/playground/src/person_management/index.ts @@ -35,9 +35,15 @@ class Person { this.personId = _nextId++; } - get age(): number { return 2015 - this.yearOfBirth; } - get fullName(): string { return `${this.firstName} ${this.lastName}`; } - get friendNames(): string { return this.friends.map(f => f.fullName).join(', '); } + get age(): number { + return 2015 - this.yearOfBirth; + } + get fullName(): string { + return `${this.firstName} ${this.lastName}`; + } + get friendNames(): string { + return this.friends.map(f => f.fullName).join(', '); + } } @@ -106,7 +112,9 @@ export class DataService { }) export class FullNameComponent { constructor(private _service: DataService) {} - get person(): Person { return this._service.currentPerson; } + get person(): Person { + return this._service.currentPerson; + } } @Component({ @@ -158,7 +166,9 @@ export class FullNameComponent { }) export class PersonsDetailComponent { constructor(private _service: DataService) {} - get person(): Person { return this._service.currentPerson; } + get person(): Person { + return this._service.currentPerson; + } } @Component({ @@ -179,9 +189,13 @@ export class PersonsDetailComponent { export class PersonsComponent { persons: Person[]; - constructor(private _service: DataService) { this.persons = _service.persons; } + constructor(private _service: DataService) { + this.persons = _service.persons; + } - select(person: Person): void { this._service.currentPerson = person; } + select(person: Person): void { + this._service.currentPerson = person; + } } @@ -199,8 +213,12 @@ export class PersonsComponent { export class PersonManagementApplication { mode: string; - switchToEditName(): void { this.mode = 'editName'; } - switchToPersonList(): void { this.mode = 'personList'; } + switchToEditName(): void { + this.mode = 'editName'; + } + switchToPersonList(): void { + this.mode = 'personList'; + } } @NgModule({ diff --git a/modules/playground/src/routing/app/inbox-app.ts b/modules/playground/src/routing/app/inbox-app.ts index 2d87ef3719da6..4e06ab860192f 100644 --- a/modules/playground/src/routing/app/inbox-app.ts +++ b/modules/playground/src/routing/app/inbox-app.ts @@ -29,7 +29,8 @@ export class InboxRecord { email: string, firstName: string, lastName: string, - date: string, draft?: boolean + date: string, + draft?: boolean } = null) { if (data) { this.setData(data); @@ -43,7 +44,8 @@ export class InboxRecord { email: string, firstName: string, lastName: string, - date: string, draft?: boolean + date: string, + draft?: boolean }) { this.id = record.id; this.subject = record.subject; diff --git a/modules/playground/src/routing/app/inbox-detail.ts b/modules/playground/src/routing/app/inbox-detail.ts index d59ccd0e0c1ab..9b95cadcf0a9d 100644 --- a/modules/playground/src/routing/app/inbox-detail.ts +++ b/modules/playground/src/routing/app/inbox-detail.ts @@ -17,8 +17,11 @@ export class InboxDetailCmp { private ready: boolean = false; constructor(db: DbService, route: ActivatedRoute) { - route.paramMap.forEach( - p => { db.email(p.get('id')).then((data) => { this.record.setData(data); }); }); + route.paramMap.forEach(p => { + db.email(p.get('id')).then((data) => { + this.record.setData(data); + }); + }); } } diff --git a/modules/playground/src/sourcemap/index.ts b/modules/playground/src/sourcemap/index.ts index 2a0622683da9d..80e3b844588d4 100644 --- a/modules/playground/src/sourcemap/index.ts +++ b/modules/playground/src/sourcemap/index.ts @@ -16,7 +16,9 @@ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; <button class="errorButton" (click)="createError()">create error</button>` }) export class ErrorComponent { - createError(): void { throw new Error('Sourcemap test'); } + createError(): void { + throw new Error('Sourcemap test'); + } } @NgModule({declarations: [ErrorComponent], bootstrap: [ErrorComponent], imports: [BrowserModule]}) diff --git a/modules/playground/src/template_driven_forms/index.ts b/modules/playground/src/template_driven_forms/index.ts index e5c316370ba66..59f3f25080a91 100644 --- a/modules/playground/src/template_driven_forms/index.ts +++ b/modules/playground/src/template_driven_forms/index.ts @@ -78,7 +78,9 @@ export class ShowError { controlPath: string; errorTypes: string[]; - constructor(@Host() formDir: NgForm) { this.formDir = formDir; } + constructor(@Host() formDir: NgForm) { + this.formDir = formDir; + } get errorMessage(): string { const form: FormGroup = this.formDir.form; diff --git a/modules/playground/src/todo/app/TodoStore.ts b/modules/playground/src/todo/app/TodoStore.ts index e8bde62ae16ae..5938b9674ca2c 100644 --- a/modules/playground/src/todo/app/TodoStore.ts +++ b/modules/playground/src/todo/app/TodoStore.ts @@ -14,14 +14,18 @@ export abstract class KeyModel { } export class Todo extends KeyModel { - constructor(key: number, public title: string, public completed: boolean) { super(key); } + constructor(key: number, public title: string, public completed: boolean) { + super(key); + } } @Injectable() export class TodoFactory { private _uid: number = 0; - nextUid(): number { return ++this._uid; } + nextUid(): number { + return ++this._uid; + } create(title: string, isCompleted: boolean): Todo { return new Todo(this.nextUid(), title, isCompleted); @@ -33,9 +37,13 @@ export class TodoFactory { export class Store<T extends KeyModel> { list: T[] = []; - add(record: T): void { this.list.push(record); } + add(record: T): void { + this.list.push(record); + } - remove(record: T): void { this.removeBy((item) => item === record); } + remove(record: T): void { + this.removeBy((item) => item === record); + } removeBy(callback: (record: T) => boolean): void { this.list = this.list.filter((record) => !callback(record)); diff --git a/modules/playground/src/todo/index.ts b/modules/playground/src/todo/index.ts index 3e6526cf9488a..04a1d55fabf5e 100644 --- a/modules/playground/src/todo/index.ts +++ b/modules/playground/src/todo/index.ts @@ -23,7 +23,9 @@ export class TodoApp { inputElement.value = ''; } - editTodo(todo: Todo): void { this.todoEdit = todo; } + editTodo(todo: Todo): void { + this.todoEdit = todo; + } doneEditing($event: KeyboardEvent, todo: Todo): void { const which = $event.which; @@ -37,18 +39,28 @@ export class TodoApp { } } - addTodo(newTitle: string): void { this.todoStore.add(this.factory.create(newTitle, false)); } + addTodo(newTitle: string): void { + this.todoStore.add(this.factory.create(newTitle, false)); + } - completeMe(todo: Todo): void { todo.completed = !todo.completed; } + completeMe(todo: Todo): void { + todo.completed = !todo.completed; + } - deleteMe(todo: Todo): void { this.todoStore.remove(todo); } + deleteMe(todo: Todo): void { + this.todoStore.remove(todo); + } toggleAll($event: MouseEvent): void { const isComplete = ($event.target as HTMLInputElement).checked; - this.todoStore.list.forEach((todo: Todo) => { todo.completed = isComplete; }); + this.todoStore.list.forEach((todo: Todo) => { + todo.completed = isComplete; + }); } - clearCompleted(): void { this.todoStore.removeBy((todo: Todo) => todo.completed); } + clearCompleted(): void { + this.todoStore.removeBy((todo: Todo) => todo.completed); + } } @NgModule({declarations: [TodoApp], bootstrap: [TodoApp], imports: [BrowserModule]}) diff --git a/modules/playground/src/upgrade/index.ts b/modules/playground/src/upgrade/index.ts index 7b737ebeab7cb..6a336abc9cc18 100644 --- a/modules/playground/src/upgrade/index.ts +++ b/modules/playground/src/upgrade/index.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, EventEmitter, Input, NgModule, Output, forwardRef} from '@angular/core'; +import {Component, EventEmitter, forwardRef, Input, NgModule, Output} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {UpgradeAdapter} from '@angular/upgrade'; @@ -30,7 +30,9 @@ const styles = [` const adapter = new UpgradeAdapter(forwardRef(() => Ng2AppModule)); const ng1module = angular.module('myExample', []); -ng1module.controller('Index', function($scope: any) { $scope.name = 'World'; }); +ng1module.controller('Index', function($scope: any) { + $scope.name = 'World'; +}); ng1module.directive('ng1User', function() { return { diff --git a/modules/playground/src/web_workers/input/index_common.ts b/modules/playground/src/web_workers/input/index_common.ts index 6ac81ce050a92..f820e28e52fd0 100644 --- a/modules/playground/src/web_workers/input/index_common.ts +++ b/modules/playground/src/web_workers/input/index_common.ts @@ -26,7 +26,11 @@ export class InputCmp { inputVal = ''; textareaVal = ''; - inputChanged(e: Event) { this.inputVal = (e.target as HTMLInputElement).value; } + inputChanged(e: Event) { + this.inputVal = (e.target as HTMLInputElement).value; + } - textAreaChanged(e: Event) { this.textareaVal = (e.target as HTMLTextAreaElement).value; } + textAreaChanged(e: Event) { + this.textareaVal = (e.target as HTMLTextAreaElement).value; + } } diff --git a/modules/playground/src/web_workers/kitchen_sink/index_common.ts b/modules/playground/src/web_workers/kitchen_sink/index_common.ts index 387c95d5995cf..53d3d5a508298 100644 --- a/modules/playground/src/web_workers/kitchen_sink/index_common.ts +++ b/modules/playground/src/web_workers/kitchen_sink/index_common.ts @@ -49,9 +49,15 @@ export class HelloCmp { greeting: string; lastKey: string = '(none)'; - constructor(service: GreetingService) { this.greeting = service.greeting; } + constructor(service: GreetingService) { + this.greeting = service.greeting; + } - changeGreeting(): void { this.greeting = 'howdy'; } + changeGreeting(): void { + this.greeting = 'howdy'; + } - onKeyDown(event: KeyboardEvent): void { this.lastKey = String.fromCharCode(event.keyCode); } + onKeyDown(event: KeyboardEvent): void { + this.lastKey = String.fromCharCode(event.keyCode); + } } diff --git a/modules/playground/src/web_workers/message_broker/index.ts b/modules/playground/src/web_workers/message_broker/index.ts index 0f6979eecea1c..c00828e9e77a5 100644 --- a/modules/playground/src/web_workers/message_broker/index.ts +++ b/modules/playground/src/web_workers/message_broker/index.ts @@ -7,7 +7,7 @@ */ import {PlatformRef} from '@angular/core'; -import {ClientMessageBrokerFactory, FnArg, SerializerTypes, UiArguments, bootstrapWorkerUi} from '@angular/platform-webworker'; +import {bootstrapWorkerUi, ClientMessageBrokerFactory, FnArg, SerializerTypes, UiArguments} from '@angular/platform-webworker'; const ECHO_CHANNEL = 'ECHO'; diff --git a/modules/playground/src/web_workers/message_broker/index_common.ts b/modules/playground/src/web_workers/message_broker/index_common.ts index 181b5811669c6..b451fcc8df41c 100644 --- a/modules/playground/src/web_workers/message_broker/index_common.ts +++ b/modules/playground/src/web_workers/message_broker/index_common.ts @@ -19,5 +19,7 @@ export class App { 'echo', [SerializerTypes.PRIMITIVE], this._echo, SerializerTypes.PRIMITIVE); } - private _echo(val: string) { return new Promise((res) => res(val)); } + private _echo(val: string) { + return new Promise((res) => res(val)); + } } diff --git a/modules/playground/src/web_workers/router/index.ts b/modules/playground/src/web_workers/router/index.ts index 788553247276a..50e4244c3fe6a 100644 --- a/modules/playground/src/web_workers/router/index.ts +++ b/modules/playground/src/web_workers/router/index.ts @@ -6,6 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import {WORKER_UI_LOCATION_PROVIDERS, bootstrapWorkerUi} from '@angular/platform-webworker'; +import {bootstrapWorkerUi, WORKER_UI_LOCATION_PROVIDERS} from '@angular/platform-webworker'; bootstrapWorkerUi('loader.js', WORKER_UI_LOCATION_PROVIDERS); diff --git a/modules/playground/src/web_workers/todo/index_common.ts b/modules/playground/src/web_workers/todo/index_common.ts index 584ae61e86ee4..443557f9b8cc7 100644 --- a/modules/playground/src/web_workers/todo/index_common.ts +++ b/modules/playground/src/web_workers/todo/index_common.ts @@ -36,11 +36,17 @@ export class TodoApp { } } - editTodo(todo: Todo): void { this.todoEdit = todo; } + editTodo(todo: Todo): void { + this.todoEdit = todo; + } - addTodo(newTitle: string): void { this.todoStore.add(this.factory.create(newTitle, false)); } + addTodo(newTitle: string): void { + this.todoStore.add(this.factory.create(newTitle, false)); + } - completeMe(todo: Todo): void { todo.completed = !todo.completed; } + completeMe(todo: Todo): void { + todo.completed = !todo.completed; + } toggleCompleted(): void { this.hideActive = !this.hideActive; @@ -57,12 +63,18 @@ export class TodoApp { this.hideActive = false; } - deleteMe(todo: Todo): void { this.todoStore.remove(todo); } + deleteMe(todo: Todo): void { + this.todoStore.remove(todo); + } toggleAll($event: MouseEvent): void { this.isComplete = !this.isComplete; - this.todoStore.list.forEach((todo: Todo) => { todo.completed = this.isComplete; }); + this.todoStore.list.forEach((todo: Todo) => { + todo.completed = this.isComplete; + }); } - clearCompleted(): void { this.todoStore.removeBy((todo: Todo) => todo.completed); } + clearCompleted(): void { + this.todoStore.removeBy((todo: Todo) => todo.completed); + } } diff --git a/modules/playground/src/web_workers/todo/services/TodoStore.ts b/modules/playground/src/web_workers/todo/services/TodoStore.ts index c889788eb83b8..3486fe7fc131d 100644 --- a/modules/playground/src/web_workers/todo/services/TodoStore.ts +++ b/modules/playground/src/web_workers/todo/services/TodoStore.ts @@ -25,7 +25,9 @@ export class Todo extends KeyModel { export class TodoFactory { private _uid: number = 0; - nextUid(): number { return ++this._uid; } + nextUid(): number { + return ++this._uid; + } create(title: string, isCompleted: boolean): Todo { return new Todo(this.nextUid(), title, isCompleted); @@ -37,9 +39,13 @@ export class TodoFactory { export class Store<T extends KeyModel> { list: T[] = []; - add(record: T): void { this.list.push(record); } + add(record: T): void { + this.list.push(record); + } - remove(record: T): void { this.removeBy((item) => item === record); } + remove(record: T): void { + this.removeBy((item) => item === record); + } removeBy(callback: (record: T) => boolean): void { this.list = this.list.filter((record) => !callback(record)); diff --git a/modules/playground/src/zippy_component/index.ts b/modules/playground/src/zippy_component/index.ts index 00ede4cd6cae4..9d1b5706db338 100644 --- a/modules/playground/src/zippy_component/index.ts +++ b/modules/playground/src/zippy_component/index.ts @@ -26,7 +26,9 @@ import {Zippy} from './app/zippy'; export class ZippyApp { logs: string[] = []; - pushLog(log: string) { this.logs.push(log); } + pushLog(log: string) { + this.logs.push(log); + } } @NgModule({declarations: [ZippyApp, Zippy], bootstrap: [ZippyApp], imports: [BrowserModule]}) diff --git a/packages/animations/browser/src/dsl/animation.ts b/packages/animations/browser/src/dsl/animation.ts index e21494a980a86..a9ba429ca0048 100644 --- a/packages/animations/browser/src/dsl/animation.ts +++ b/packages/animations/browser/src/dsl/animation.ts @@ -22,7 +22,7 @@ export class Animation { const errors: any[] = []; const ast = buildAnimationAst(_driver, input, errors); if (errors.length) { - const errorMessage = `animation validation failed:\n${errors.join("\n")}`; + const errorMessage = `animation validation failed:\n${errors.join('\n')}`; throw new Error(errorMessage); } this._animationAst = ast; @@ -42,7 +42,7 @@ export class Animation { this._driver, element, this._animationAst, ENTER_CLASSNAME, LEAVE_CLASSNAME, start, dest, options, subInstructions, errors); if (errors.length) { - const errorMessage = `animation building failed:\n${errors.join("\n")}`; + const errorMessage = `animation building failed:\n${errors.join('\n')}`; throw new Error(errorMessage); } return result; diff --git a/packages/animations/browser/src/dsl/animation_ast.ts b/packages/animations/browser/src/dsl/animation_ast.ts index dd5a46363becc..8d57c09f0a5e3 100644 --- a/packages/animations/browser/src/dsl/animation_ast.ts +++ b/packages/animations/browser/src/dsl/animation_ast.ts @@ -74,7 +74,9 @@ export interface StyleAst extends Ast<AnimationMetadataType.Style> { isEmptyStep?: boolean; } -export interface KeyframesAst extends Ast<AnimationMetadataType.Keyframes> { styles: StyleAst[]; } +export interface KeyframesAst extends Ast<AnimationMetadataType.Keyframes> { + styles: StyleAst[]; +} export interface ReferenceAst extends Ast<AnimationMetadataType.Reference> { animation: Ast<AnimationMetadataType>; diff --git a/packages/animations/browser/src/dsl/animation_ast_builder.ts b/packages/animations/browser/src/dsl/animation_ast_builder.ts index e883eb742e065..5184e74589d5d 100644 --- a/packages/animations/browser/src/dsl/animation_ast_builder.ts +++ b/packages/animations/browser/src/dsl/animation_ast_builder.ts @@ -5,11 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, style, ɵStyleData} from '@angular/animations'; +import {AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, AUTO_STYLE, style, ɵStyleData} from '@angular/animations'; import {AnimationDriver} from '../render/animation_driver'; import {getOrSetAsInMap} from '../render/shared'; -import {ENTER_SELECTOR, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, SUBSTITUTION_EXPR_START, copyObj, extractStyleParams, iteratorToArray, normalizeAnimationEntry, resolveTiming, validateStyleParams, visitDslNode} from '../util'; +import {copyObj, ENTER_SELECTOR, extractStyleParams, iteratorToArray, LEAVE_SELECTOR, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, normalizeAnimationEntry, resolveTiming, SUBSTITUTION_EXPR_START, validateStyleParams, visitDslNode} from '../util'; import {AnimateAst, AnimateChildAst, AnimateRefAst, Ast, DynamicTimingAst, GroupAst, KeyframesAst, QueryAst, ReferenceAst, SequenceAst, StaggerAst, StateAst, StyleAst, TimingAst, TransitionAst, TriggerAst} from './animation_ast'; import {AnimationDslVisitor} from './animation_dsl_visitor'; @@ -55,7 +55,7 @@ const SELF_TOKEN_REGEX = new RegExp(`\s*${SELF_TOKEN}\s*,?`, 'g'); * Otherwise an error will be thrown. */ export function buildAnimationAst( - driver: AnimationDriver, metadata: AnimationMetadata | AnimationMetadata[], + driver: AnimationDriver, metadata: AnimationMetadata|AnimationMetadata[], errors: any[]): Ast<AnimationMetadataType> { return new AnimationAstBuilderVisitor(driver).build(metadata, errors); } @@ -114,7 +114,11 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { return { type: AnimationMetadataType.Trigger, - name: metadata.name, states, transitions, queryCount, depCount, + name: metadata.name, + states, + transitions, + queryCount, + depCount, options: null }; } @@ -139,8 +143,10 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { }); if (missingSubs.size) { const missingSubsArr = iteratorToArray(missingSubs.values()); - context.errors.push( - `state("${metadata.name}", ...) must define default values for all the following style substitutions: ${missingSubsArr.join(', ')}`); + context.errors.push(`state("${ + metadata + .name}", ...) must define default values for all the following style substitutions: ${ + missingSubsArr.join(', ')}`); } } @@ -210,7 +216,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { let isEmpty = false; if (!styleMetadata) { isEmpty = true; - const newStyleData: {[prop: string]: string | number} = {}; + const newStyleData: {[prop: string]: string|number} = {}; if (timingAst.easing) { newStyleData['easing'] = timingAst.easing; } @@ -239,9 +245,9 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { private _makeStyleAst(metadata: AnimationStyleMetadata, context: AnimationAstBuilderContext): StyleAst { - const styles: (ɵStyleData | string)[] = []; + const styles: (ɵStyleData|string)[] = []; if (Array.isArray(metadata.styles)) { - (metadata.styles as(ɵStyleData | string)[]).forEach(styleTuple => { + (metadata.styles as (ɵStyleData | string)[]).forEach(styleTuple => { if (typeof styleTuple == 'string') { if (styleTuple == AUTO_STYLE) { styles.push(styleTuple); @@ -282,7 +288,8 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { type: AnimationMetadataType.Style, styles, easing: collectedEasing, - offset: metadata.offset, containsDynamicStyles, + offset: metadata.offset, + containsDynamicStyles, options: null }; } @@ -300,19 +307,22 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { Object.keys(tuple).forEach(prop => { if (!this._driver.validateStyleProperty(prop)) { - context.errors.push( - `The provided animation property "${prop}" is not a supported CSS property for animations`); + context.errors.push(`The provided animation property "${ + prop}" is not a supported CSS property for animations`); return; } - const collectedStyles = context.collectedStyles[context.currentQuerySelector !]; + const collectedStyles = context.collectedStyles[context.currentQuerySelector!]; const collectedEntry = collectedStyles[prop]; let updateCollectedStyle = true; if (collectedEntry) { if (startTime != endTime && startTime >= collectedEntry.startTime && endTime <= collectedEntry.endTime) { - context.errors.push( - `The CSS property "${prop}" that exists between the times of "${collectedEntry.startTime}ms" and "${collectedEntry.endTime}ms" is also being animated in a parallel animation between the times of "${startTime}ms" and "${endTime}ms"`); + context.errors.push(`The CSS property "${prop}" that exists between the times of "${ + collectedEntry.startTime}ms" and "${ + collectedEntry + .endTime}ms" is also being animated in a parallel animation between the times of "${ + startTime}ms" and "${endTime}ms"`); updateCollectedStyle = false; } @@ -383,7 +393,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { const limit = length - 1; const currentTime = context.currentTime; - const currentAnimateTimings = context.currentAnimateTimings !; + const currentAnimateTimings = context.currentAnimateTimings!; const animateDuration = currentAnimateTimings.duration; keyframes.forEach((kf, i) => { const offset = generatedOffset > 0 ? (i == limit ? 1 : (generatedOffset * i)) : offsets[i]; @@ -427,7 +437,7 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { } visitQuery(metadata: AnimationQueryMetadata, context: AnimationAstBuilderContext): QueryAst { - const parentSelector = context.currentQuerySelector !; + const parentSelector = context.currentQuerySelector!; const options = (metadata.options || {}) as AnimationQueryOptions; context.queryCount++; @@ -445,7 +455,9 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { type: AnimationMetadataType.Query, selector, limit: options.limit || 0, - optional: !!options.optional, includeSelf, animation, + optional: !!options.optional, + includeSelf, + animation, originalSelector: metadata.selector, options: normalizeAnimationOptions(metadata.options) }; @@ -462,7 +474,8 @@ export class AnimationAstBuilderVisitor implements AnimationDslVisitor { return { type: AnimationMetadataType.Stagger, - animation: visitDslNode(this, normalizeAnimationEntry(metadata.animation), context), timings, + animation: visitDslNode(this, normalizeAnimationEntry(metadata.animation), context), + timings, options: null }; } @@ -483,7 +496,7 @@ function normalizeSelector(selector: string): [string, boolean] { } -function normalizeParams(obj: {[key: string]: any} | any): {[key: string]: any}|null { +function normalizeParams(obj: {[key: string]: any}|any): {[key: string]: any}|null { return obj ? copyObj(obj) : null; } @@ -504,7 +517,7 @@ export class AnimationAstBuilderContext { constructor(public errors: any[]) {} } -function consumeOffset(styles: ɵStyleData | string | (ɵStyleData | string)[]): number|null { +function consumeOffset(styles: ɵStyleData|string|(ɵStyleData | string)[]): number|null { if (typeof styles == 'string') return null; let offset: number|null = null; @@ -529,7 +542,7 @@ function isObject(value: any): boolean { return !Array.isArray(value) && typeof value == 'object'; } -function constructTimingAst(value: string | number | AnimateTimings, errors: any[]) { +function constructTimingAst(value: string|number|AnimateTimings, errors: any[]) { let timings: AnimateTimings|null = null; if (value.hasOwnProperty('duration')) { timings = value as AnimateTimings; @@ -551,11 +564,11 @@ function constructTimingAst(value: string | number | AnimateTimings, errors: any return makeTimingAst(timings.duration, timings.delay, timings.easing); } -function normalizeAnimationOptions(options: AnimationOptions | null): AnimationOptions { +function normalizeAnimationOptions(options: AnimationOptions|null): AnimationOptions { if (options) { options = copyObj(options); if (options['params']) { - options['params'] = normalizeParams(options['params']) !; + options['params'] = normalizeParams(options['params'])!; } } else { options = {}; @@ -563,6 +576,6 @@ function normalizeAnimationOptions(options: AnimationOptions | null): AnimationO return options; } -function makeTimingAst(duration: number, delay: number, easing: string | null): TimingAst { +function makeTimingAst(duration: number, delay: number, easing: string|null): TimingAst { return {duration, delay, easing}; } diff --git a/packages/animations/browser/src/dsl/animation_timeline_builder.ts b/packages/animations/browser/src/dsl/animation_timeline_builder.ts index b9bc5b09202df..7995610117a4a 100644 --- a/packages/animations/browser/src/dsl/animation_timeline_builder.ts +++ b/packages/animations/browser/src/dsl/animation_timeline_builder.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationMetadataType, AnimationOptions, AnimationQueryOptions, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations'; +import {AnimateChildOptions, AnimateTimings, AnimationMetadataType, AnimationOptions, AnimationQueryOptions, AUTO_STYLE, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations'; import {AnimationDriver} from '../render/animation_driver'; import {copyObj, copyStyles, interpolateParams, iteratorToArray, resolveTiming, resolveTimingValue, visitDslNode} from '../util'; @@ -301,7 +301,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { visitStyle(ast: StyleAst, context: AnimationTimelineContext) { const timeline = context.currentTimeline; - const timings = context.currentAnimateTimings !; + const timings = context.currentAnimateTimings!; // this is a special case for when a style() call // directly follows an animate() call (but not inside of an animate() call) @@ -320,8 +320,8 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { } visitKeyframes(ast: KeyframesAst, context: AnimationTimelineContext) { - const currentAnimateTimings = context.currentAnimateTimings !; - const startTime = (context.currentTimeline !).duration; + const currentAnimateTimings = context.currentAnimateTimings!; + const startTime = (context.currentTimeline!).duration; const duration = currentAnimateTimings.duration; const innerContext = context.createSubContext(); const innerTimeline = innerContext.currentTimeline; @@ -351,8 +351,9 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { const options = (ast.options || {}) as AnimationQueryOptions; const delay = options.delay ? resolveTimingValue(options.delay) : 0; - if (delay && (context.previousNode.type === AnimationMetadataType.Style || - (startTime == 0 && context.currentTimeline.getCurrentStyleProperties().length))) { + if (delay && + (context.previousNode.type === AnimationMetadataType.Style || + (startTime == 0 && context.currentTimeline.getCurrentStyleProperties().length))) { context.currentTimeline.snapshotCurrentStyles(); context.previousNode = DEFAULT_NOOP_PREVIOUS_NODE; } @@ -365,7 +366,6 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { context.currentQueryTotal = elms.length; let sameElementTimeline: TimelineBuilder|null = null; elms.forEach((element, i) => { - context.currentQueryIndex = i; const innerContext = context.createSubContext(ast.options, element); if (delay) { @@ -400,7 +400,7 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { } visitStagger(ast: StaggerAst, context: AnimationTimelineContext) { - const parentContext = context.parentContext !; + const parentContext = context.parentContext!; const tl = context.currentTimeline; const timings = ast.timings; const duration = Math.abs(timings.duration); @@ -460,7 +460,9 @@ export class AnimationTimelineContext { timelines.push(this.currentTimeline); } - get params() { return this.options.params; } + get params() { + return this.options.params; + } updateOptions(options: AnimationOptions|null, skipIfExists?: boolean) { if (!options) return; @@ -479,7 +481,7 @@ export class AnimationTimelineContext { const newParams = newOptions.params; if (newParams) { - let paramsToUpdate: {[name: string]: any} = optionsToUpdate.params !; + let paramsToUpdate: {[name: string]: any} = optionsToUpdate.params!; if (!paramsToUpdate) { paramsToUpdate = this.options.params = {}; } @@ -498,7 +500,9 @@ export class AnimationTimelineContext { const oldParams = this.options.params; if (oldParams) { const params: {[name: string]: any} = options['params'] = {}; - Object.keys(oldParams).forEach(name => { params[name] = oldParams[name]; }); + Object.keys(oldParams).forEach(name => { + params[name] = oldParams[name]; + }); } } return options; @@ -576,8 +580,8 @@ export class AnimationTimelineContext { } if (!optional && results.length == 0) { - errors.push( - `\`query("${originalSelector}")\` returned zero elements. (Use \`query("${originalSelector}", { optional: true })\` if you wish to allow this.)`); + errors.push(`\`query("${originalSelector}")\` returned zero elements. (Use \`query("${ + originalSelector}", { optional: true })\` if you wish to allow this.)`); } return results; } @@ -587,7 +591,7 @@ export class AnimationTimelineContext { export class TimelineBuilder { public duration: number = 0; // TODO(issue/24571): remove '!'. - public easing !: string | null; + public easing!: string|null; private _previousKeyframe: ɵStyleData = {}; private _currentKeyframe: ɵStyleData = {}; private _keyframes = new Map<number, ɵStyleData>(); @@ -606,7 +610,7 @@ export class TimelineBuilder { } this._localTimelineStyles = Object.create(this._backFill, {}); - this._globalTimelineStyles = this._elementTimelineStylesLookup.get(element) !; + this._globalTimelineStyles = this._elementTimelineStylesLookup.get(element)!; if (!this._globalTimelineStyles) { this._globalTimelineStyles = this._localTimelineStyles; this._elementTimelineStylesLookup.set(element, this._localTimelineStyles); @@ -625,9 +629,13 @@ export class TimelineBuilder { } } - getCurrentStyleProperties(): string[] { return Object.keys(this._currentKeyframe); } + getCurrentStyleProperties(): string[] { + return Object.keys(this._currentKeyframe); + } - get currentTime() { return this.startTime + this.duration; } + get currentTime() { + return this.startTime + this.duration; + } delayNextStep(delay: number) { // in the event that a style() step is placed right before a stagger() @@ -656,7 +664,7 @@ export class TimelineBuilder { if (this._currentKeyframe) { this._previousKeyframe = this._currentKeyframe; } - this._currentKeyframe = this._keyframes.get(this.duration) !; + this._currentKeyframe = this._keyframes.get(this.duration)!; if (!this._currentKeyframe) { this._currentKeyframe = Object.create(this._backFill, {}); this._keyframes.set(this.duration, this._currentKeyframe); @@ -680,7 +688,9 @@ export class TimelineBuilder { this._styleSummary[prop] = {time: this.currentTime, value}; } - allowOnlyTimelineStyles() { return this._currentEmptyStepKeyframe !== this._currentKeyframe; } + allowOnlyTimelineStyles() { + return this._currentEmptyStepKeyframe !== this._currentKeyframe; + } applyEmptyStep(easing: string|null) { if (easing) { @@ -748,7 +758,9 @@ export class TimelineBuilder { }); } - getFinalKeyframe() { return this._keyframes.get(this.duration); } + getFinalKeyframe() { + return this._keyframes.get(this.duration); + } get properties() { const properties: string[] = []; @@ -820,7 +832,9 @@ class SubTimelineBuilder extends TimelineBuilder { this.timings = {duration: timings.duration, delay: timings.delay, easing: timings.easing}; } - containsAnimation(): boolean { return this.keyframes.length > 1; } + containsAnimation(): boolean { + return this.keyframes.length > 1; + } buildKeyframes(): AnimationTimelineInstruction { let keyframes = this.keyframes; @@ -883,13 +897,15 @@ function roundOffset(offset: number, decimalPoints = 3): number { return Math.round(offset * mult) / mult; } -function flattenStyles(input: (ɵStyleData | string)[], allStyles: ɵStyleData) { +function flattenStyles(input: (ɵStyleData|string)[], allStyles: ɵStyleData) { const styles: ɵStyleData = {}; let allProperties: string[]; input.forEach(token => { if (token === '*') { allProperties = allProperties || Object.keys(allStyles); - allProperties.forEach(prop => { styles[prop] = AUTO_STYLE; }); + allProperties.forEach(prop => { + styles[prop] = AUTO_STYLE; + }); } else { copyStyles(token as ɵStyleData, false, styles); } diff --git a/packages/animations/browser/src/dsl/animation_timeline_instruction.ts b/packages/animations/browser/src/dsl/animation_timeline_instruction.ts index 4c10d69a3dfd9..13e4cc4d01c4f 100644 --- a/packages/animations/browser/src/dsl/animation_timeline_instruction.ts +++ b/packages/animations/browser/src/dsl/animation_timeline_instruction.ts @@ -23,7 +23,7 @@ export interface AnimationTimelineInstruction extends AnimationEngineInstruction export function createTimelineInstruction( element: any, keyframes: ɵStyleData[], preStyleProps: string[], postStyleProps: string[], - duration: number, delay: number, easing: string | null = null, + duration: number, delay: number, easing: string|null = null, subTimeline: boolean = false): AnimationTimelineInstruction { return { type: AnimationTransitionInstructionType.TimelineAnimation, @@ -33,6 +33,8 @@ export function createTimelineInstruction( postStyleProps, duration, delay, - totalTime: duration + delay, easing, subTimeline + totalTime: duration + delay, + easing, + subTimeline }; } diff --git a/packages/animations/browser/src/dsl/animation_transition_expr.ts b/packages/animations/browser/src/dsl/animation_transition_expr.ts index 120e97bd2b1cd..9fe58d271a3a6 100644 --- a/packages/animations/browser/src/dsl/animation_transition_expr.ts +++ b/packages/animations/browser/src/dsl/animation_transition_expr.ts @@ -10,7 +10,7 @@ export declare type TransitionMatcherFn = (fromState: any, toState: any, element: any, params: {[key: string]: any}) => boolean; export function parseTransitionExpr( - transitionValue: string | TransitionMatcherFn, errors: string[]): TransitionMatcherFn[] { + transitionValue: string|TransitionMatcherFn, errors: string[]): TransitionMatcherFn[] { const expressions: TransitionMatcherFn[] = []; if (typeof transitionValue == 'string') { transitionValue.split(/\s*,\s*/).forEach( diff --git a/packages/animations/browser/src/dsl/animation_transition_factory.ts b/packages/animations/browser/src/dsl/animation_transition_factory.ts index f1499e862b6a8..ab7729fe6b6d6 100644 --- a/packages/animations/browser/src/dsl/animation_transition_factory.ts +++ b/packages/animations/browser/src/dsl/animation_transition_factory.ts @@ -55,13 +55,16 @@ export class AnimationTransitionFactory { const animationOptions = {params: {...transitionAnimationParams, ...nextAnimationParams}}; - const timelines = skipAstBuild ? [] : buildAnimationTimelines( - driver, element, this.ast.animation, enterClassName, - leaveClassName, currentStateStyles, nextStateStyles, - animationOptions, subInstructions, errors); + const timelines = skipAstBuild ? + [] : + buildAnimationTimelines( + driver, element, this.ast.animation, enterClassName, leaveClassName, currentStateStyles, + nextStateStyles, animationOptions, subInstructions, errors); let totalTime = 0; - timelines.forEach(tl => { totalTime = Math.max(tl.duration + tl.delay, totalTime); }); + timelines.forEach(tl => { + totalTime = Math.max(tl.duration + tl.delay, totalTime); + }); if (errors.length) { return createTransitionInstruction( diff --git a/packages/animations/browser/src/dsl/animation_trigger.ts b/packages/animations/browser/src/dsl/animation_trigger.ts index 79d948af9c06b..5e307adc88776 100644 --- a/packages/animations/browser/src/dsl/animation_trigger.ts +++ b/packages/animations/browser/src/dsl/animation_trigger.ts @@ -22,8 +22,8 @@ export function buildTrigger(name: string, ast: TriggerAst): AnimationTrigger { } /** -* @publicApi -*/ + * @publicApi + */ export class AnimationTrigger { public transitionFactories: AnimationTransitionFactory[] = []; public fallbackTransition: AnimationTransitionFactory; @@ -45,7 +45,9 @@ export class AnimationTrigger { this.fallbackTransition = createFallbackTransition(name, this.states); } - get containsQueries() { return this.ast.queryCount > 0; } + get containsQueries() { + return this.ast.queryCount > 0; + } matchTransition(currentState: any, nextState: any, element: any, params: {[key: string]: any}): AnimationTransitionFactory|null { diff --git a/packages/animations/browser/src/dsl/element_instruction_map.ts b/packages/animations/browser/src/dsl/element_instruction_map.ts index ad61a5f35ee39..7d5ca8baac211 100644 --- a/packages/animations/browser/src/dsl/element_instruction_map.ts +++ b/packages/animations/browser/src/dsl/element_instruction_map.ts @@ -28,7 +28,11 @@ export class ElementInstructionMap { existingInstructions.push(...instructions); } - has(element: any): boolean { return this._map.has(element); } + has(element: any): boolean { + return this._map.has(element); + } - clear() { this._map.clear(); } + clear() { + this._map.clear(); + } } diff --git a/packages/animations/browser/src/dsl/style_normalization/animation_style_normalizer.ts b/packages/animations/browser/src/dsl/style_normalization/animation_style_normalizer.ts index ea0161b90810b..3ab5f062575e8 100644 --- a/packages/animations/browser/src/dsl/style_normalization/animation_style_normalizer.ts +++ b/packages/animations/browser/src/dsl/style_normalization/animation_style_normalizer.ts @@ -20,7 +20,9 @@ export abstract class AnimationStyleNormalizer { * @publicApi */ export class NoopAnimationStyleNormalizer { - normalizePropertyName(propertyName: string, errors: string[]): string { return propertyName; } + normalizePropertyName(propertyName: string, errors: string[]): string { + return propertyName; + } normalizeStyleValue( userProvidedProperty: string, normalizedProperty: string, value: string|number, diff --git a/packages/animations/browser/src/private_export.ts b/packages/animations/browser/src/private_export.ts index bcce822afca9d..3773ef5348807 100644 --- a/packages/animations/browser/src/private_export.ts +++ b/packages/animations/browser/src/private_export.ts @@ -13,6 +13,6 @@ export {AnimationEngine as ɵAnimationEngine} from './render/animation_engine_ne export {CssKeyframesDriver as ɵCssKeyframesDriver} from './render/css_keyframes/css_keyframes_driver'; export {CssKeyframesPlayer as ɵCssKeyframesPlayer} from './render/css_keyframes/css_keyframes_player'; export {containsElement as ɵcontainsElement, invokeQuery as ɵinvokeQuery, matchesElement as ɵmatchesElement, validateStyleProperty as ɵvalidateStyleProperty} from './render/shared'; -export {WebAnimationsDriver as ɵWebAnimationsDriver, supportsWebAnimations as ɵsupportsWebAnimations} from './render/web_animations/web_animations_driver'; +export {supportsWebAnimations as ɵsupportsWebAnimations, WebAnimationsDriver as ɵWebAnimationsDriver} from './render/web_animations/web_animations_driver'; export {WebAnimationsPlayer as ɵWebAnimationsPlayer} from './render/web_animations/web_animations_player'; export {allowPreviousPlayerStylesMerge as ɵallowPreviousPlayerStylesMerge} from './util'; diff --git a/packages/animations/browser/src/render/animation_driver.ts b/packages/animations/browser/src/render/animation_driver.ts index 2302b4f40349d..84085e18656b7 100644 --- a/packages/animations/browser/src/render/animation_driver.ts +++ b/packages/animations/browser/src/render/animation_driver.ts @@ -15,13 +15,17 @@ import {containsElement, invokeQuery, matchesElement, validateStyleProperty} fro */ @Injectable() export class NoopAnimationDriver implements AnimationDriver { - validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); } + validateStyleProperty(prop: string): boolean { + return validateStyleProperty(prop); + } matchesElement(element: any, selector: string): boolean { return matchesElement(element, selector); } - containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); } + containsElement(elm1: any, elm2: any): boolean { + return containsElement(elm1, elm2); + } query(element: any, selector: string, multi: boolean): any[] { return invokeQuery(element, selector, multi); @@ -32,7 +36,7 @@ export class NoopAnimationDriver implements AnimationDriver { } animate( - element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number, + element: any, keyframes: {[key: string]: string|number}[], duration: number, delay: number, easing: string, previousPlayers: any[] = [], scrubberAccessRequested?: boolean): AnimationPlayer { return new NoopAnimationPlayer(duration, delay); @@ -56,6 +60,6 @@ export abstract class AnimationDriver { abstract computeStyle(element: any, prop: string, defaultValue?: string): string; abstract animate( - element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number, + element: any, keyframes: {[key: string]: string|number}[], duration: number, delay: number, easing?: string|null, previousPlayers?: any[], scrubberAccessRequested?: boolean): any; } diff --git a/packages/animations/browser/src/render/animation_engine_instruction.ts b/packages/animations/browser/src/render/animation_engine_instruction.ts index 43c9fcd773ef2..d263df4ffde83 100644 --- a/packages/animations/browser/src/render/animation_engine_instruction.ts +++ b/packages/animations/browser/src/render/animation_engine_instruction.ts @@ -5,6 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -export const enum AnimationTransitionInstructionType {TransitionAnimation, TimelineAnimation} +export const enum AnimationTransitionInstructionType { + TransitionAnimation, + TimelineAnimation +} -export interface AnimationEngineInstruction { type: AnimationTransitionInstructionType; } +export interface AnimationEngineInstruction { + type: AnimationTransitionInstructionType; +} diff --git a/packages/animations/browser/src/render/animation_engine_next.ts b/packages/animations/browser/src/render/animation_engine_next.ts index fe458b7611772..fa5ec2b5b966a 100644 --- a/packages/animations/browser/src/render/animation_engine_next.ts +++ b/packages/animations/browser/src/render/animation_engine_next.ts @@ -45,8 +45,8 @@ export class AnimationEngine { const ast = buildAnimationAst(this._driver, metadata as AnimationMetadata, errors) as TriggerAst; if (errors.length) { - throw new Error( - `The animation trigger "${name}" has failed to build due to the following errors:\n - ${errors.join("\n - ")}`); + throw new Error(`The animation trigger "${ + name}" has failed to build due to the following errors:\n - ${errors.join('\n - ')}`); } trigger = buildTrigger(name, ast); this._triggerCache[cacheKey] = trigger; @@ -95,12 +95,16 @@ export class AnimationEngine { return this._transitionEngine.listen(namespaceId, element, eventName, eventPhase, callback); } - flush(microtaskId: number = -1): void { this._transitionEngine.flush(microtaskId); } + flush(microtaskId: number = -1): void { + this._transitionEngine.flush(microtaskId); + } get players(): AnimationPlayer[] { return (this._transitionEngine.players as AnimationPlayer[]) .concat(this._timelineEngine.players as AnimationPlayer[]); } - whenRenderingDone(): Promise<any> { return this._transitionEngine.whenRenderingDone(); } + whenRenderingDone(): Promise<any> { + return this._transitionEngine.whenRenderingDone(); + } } diff --git a/packages/animations/browser/src/render/css_keyframes/css_keyframes_driver.ts b/packages/animations/browser/src/render/css_keyframes/css_keyframes_driver.ts index c69ee499c922c..a849111dfb6e5 100644 --- a/packages/animations/browser/src/render/css_keyframes/css_keyframes_driver.ts +++ b/packages/animations/browser/src/render/css_keyframes/css_keyframes_driver.ts @@ -23,13 +23,17 @@ export class CssKeyframesDriver implements AnimationDriver { private readonly _head: any = document.querySelector('head'); private _warningIssued = false; - validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); } + validateStyleProperty(prop: string): boolean { + return validateStyleProperty(prop); + } matchesElement(element: any, selector: string): boolean { return matchesElement(element, selector); } - containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); } + containsElement(elm1: any, elm2: any): boolean { + return containsElement(elm1, elm2); + } query(element: any, selector: string, multi: boolean): any[] { return invokeQuery(element, selector, multi); @@ -104,7 +108,7 @@ export class CssKeyframesDriver implements AnimationDriver { const animationName = `${KEYFRAMES_NAME_PREFIX}${this._count++}`; const kfElm = this.buildKeyframeElement(element, animationName, keyframes); - document.querySelector('head') !.appendChild(kfElm); + document.querySelector('head')!.appendChild(kfElm); const specialStyles = packageNonAnimatableStyles(element, keyframes); const player = new CssKeyframesPlayer( @@ -124,8 +128,8 @@ export class CssKeyframesDriver implements AnimationDriver { } } -function flattenKeyframesIntoStyles( - keyframes: null | {[key: string]: any} | {[key: string]: any}[]): {[key: string]: any} { +function flattenKeyframesIntoStyles(keyframes: null|{[key: string]: any}| + {[key: string]: any}[]): {[key: string]: any} { let flatKeyframes: {[key: string]: any} = {}; if (keyframes) { const kfs = Array.isArray(keyframes) ? keyframes : [keyframes]; diff --git a/packages/animations/browser/src/render/css_keyframes/css_keyframes_player.ts b/packages/animations/browser/src/render/css_keyframes/css_keyframes_player.ts index 1a6f302b043f3..114929a8e3038 100644 --- a/packages/animations/browser/src/render/css_keyframes/css_keyframes_player.ts +++ b/packages/animations/browser/src/render/css_keyframes/css_keyframes_player.ts @@ -14,7 +14,12 @@ import {ElementAnimationStyleHandler} from './element_animation_style_handler'; const DEFAULT_FILL_MODE = 'forwards'; const DEFAULT_EASING = 'linear'; -export const enum AnimatorControlState {INITIALIZED = 1, STARTED = 2, FINISHED = 3, DESTROYED = 4} +export const enum AnimatorControlState { + INITIALIZED = 1, + STARTED = 2, + FINISHED = 3, + DESTROYED = 4 +} export class CssKeyframesPlayer implements AnimationPlayer { private _onDoneFns: Function[] = []; @@ -23,10 +28,10 @@ export class CssKeyframesPlayer implements AnimationPlayer { private _started = false; // TODO(issue/24571): remove '!'. - private _styler !: ElementAnimationStyleHandler; + private _styler!: ElementAnimationStyleHandler; // TODO(issue/24571): remove '!'. - public parentPlayer !: AnimationPlayer; + public parentPlayer!: AnimationPlayer; public readonly totalTime: number; public readonly easing: string; public currentSnapshot: {[key: string]: string} = {}; @@ -34,7 +39,7 @@ export class CssKeyframesPlayer implements AnimationPlayer { private _state: AnimatorControlState = 0; constructor( - public readonly element: any, public readonly keyframes: {[key: string]: string | number}[], + public readonly element: any, public readonly keyframes: {[key: string]: string|number}[], public readonly animationName: string, private readonly _duration: number, private readonly _delay: number, easing: string, private readonly _finalStyles: {[key: string]: any}, @@ -44,11 +49,17 @@ export class CssKeyframesPlayer implements AnimationPlayer { this._buildStyler(); } - onStart(fn: () => void): void { this._onStartFns.push(fn); } + onStart(fn: () => void): void { + this._onStartFns.push(fn); + } - onDone(fn: () => void): void { this._onDoneFns.push(fn); } + onDone(fn: () => void): void { + this._onDoneFns.push(fn); + } - onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); } + onDestroy(fn: () => void): void { + this._onDestroyFns.push(fn); + } destroy() { this.init(); @@ -86,11 +97,17 @@ export class CssKeyframesPlayer implements AnimationPlayer { this._flushDoneFns(); } - setPosition(value: number) { this._styler.setPosition(value); } + setPosition(value: number) { + this._styler.setPosition(value); + } - getPosition(): number { return this._styler.getPosition(); } + getPosition(): number { + return this._styler.getPosition(); + } - hasStarted(): boolean { return this._state >= AnimatorControlState.STARTED; } + hasStarted(): boolean { + return this._state >= AnimatorControlState.STARTED; + } init(): void { if (this._state >= AnimatorControlState.INITIALIZED) return; this._state = AnimatorControlState.INITIALIZED; diff --git a/packages/animations/browser/src/render/css_keyframes/direct_style_player.ts b/packages/animations/browser/src/render/css_keyframes/direct_style_player.ts index f4c092d27eb88..6a7ff3a453eec 100644 --- a/packages/animations/browser/src/render/css_keyframes/direct_style_player.ts +++ b/packages/animations/browser/src/render/css_keyframes/direct_style_player.ts @@ -22,7 +22,7 @@ export class DirectStylePlayer extends NoopAnimationPlayer { if (this.__initialized || !this._startingStyles) return; this.__initialized = true; Object.keys(this._styles).forEach(prop => { - this._startingStyles ![prop] = this.element.style[prop]; + this._startingStyles![prop] = this.element.style[prop]; }); super.init(); } @@ -38,7 +38,7 @@ export class DirectStylePlayer extends NoopAnimationPlayer { destroy() { if (!this._startingStyles) return; Object.keys(this._startingStyles).forEach(prop => { - const value = this._startingStyles ![prop]; + const value = this._startingStyles![prop]; if (value) { this.element.style.setProperty(prop, value); } else { diff --git a/packages/animations/browser/src/render/css_keyframes/element_animation_style_handler.ts b/packages/animations/browser/src/render/css_keyframes/element_animation_style_handler.ts index 03e06889d30b2..095c726a38f84 100644 --- a/packages/animations/browser/src/render/css_keyframes/element_animation_style_handler.ts +++ b/packages/animations/browser/src/render/css_keyframes/element_animation_style_handler.ts @@ -28,14 +28,19 @@ export class ElementAnimationStyleHandler { apply() { applyKeyframeAnimation( this._element, - `${this._duration}ms ${this._easing} ${this._delay}ms 1 normal ${this._fillMode} ${this._name}`); + `${this._duration}ms ${this._easing} ${this._delay}ms 1 normal ${this._fillMode} ${ + this._name}`); addRemoveAnimationEvent(this._element, this._eventFn, false); this._startTime = Date.now(); } - pause() { playPauseAnimation(this._element, this._name, 'paused'); } + pause() { + playPauseAnimation(this._element, this._name, 'paused'); + } - resume() { playPauseAnimation(this._element, this._name, 'running'); } + resume() { + playPauseAnimation(this._element, this._name, 'running'); + } setPosition(position: number) { const index = findIndexForAnimation(this._element, this._name); @@ -43,7 +48,9 @@ export class ElementAnimationStyleHandler { setAnimationStyle(this._element, 'Delay', `-${this._position}ms`, index); } - getPosition() { return this._position; } + getPosition() { + return this._position; + } private _handleCallback(event: any) { const timestamp = event._ngTestManualTimestamp || Date.now(); @@ -70,7 +77,7 @@ export class ElementAnimationStyleHandler { } } -function playPauseAnimation(element: any, name: string, status: 'running' | 'paused') { +function playPauseAnimation(element: any, name: string, status: 'running'|'paused') { const index = findIndexForAnimation(element, name); setAnimationStyle(element, 'PlayState', status, index); } diff --git a/packages/animations/browser/src/render/shared.ts b/packages/animations/browser/src/render/shared.ts index e3d6119fad1c0..c8cbe83ddab71 100644 --- a/packages/animations/browser/src/render/shared.ts +++ b/packages/animations/browser/src/render/shared.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationEvent, AnimationPlayer, NoopAnimationPlayer, ɵAnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations'; +import {AnimationEvent, AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵAnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations'; import {AnimationStyleNormalizer} from '../../src/dsl/style_normalization/animation_style_normalizer'; import {AnimationDriver} from '../../src/render/animation_driver'; @@ -89,7 +89,7 @@ export function normalizeKeyframes( } export function listenOnPlayer( - player: AnimationPlayer, eventName: string, event: AnimationEvent | undefined, + player: AnimationPlayer, eventName: string, event: AnimationEvent|undefined, callback: (event: any) => any) { switch (eventName) { case 'start': @@ -125,7 +125,7 @@ export function makeAnimationEvent( } export function getOrSetAsInMap( - map: Map<any, any>| {[key: string]: any}, key: any, defaultValue: any) { + map: Map<any, any>|{[key: string]: any}, key: any, defaultValue: any) { let value: any; if (map instanceof Map) { value = map.get(key); @@ -161,7 +161,9 @@ let _query: (element: any, selector: string, multi: boolean) => any[] = const _isNode = isNode(); if (_isNode || typeof Element !== 'undefined') { // this is well supported in all browsers - _contains = (elm1: any, elm2: any) => { return elm1.contains(elm2) as boolean; }; + _contains = (elm1: any, elm2: any) => { + return elm1.contains(elm2) as boolean; + }; _matches = (() => { if (_isNode || Element.prototype.matches) { @@ -203,15 +205,15 @@ let _IS_WEBKIT = false; export function validateStyleProperty(prop: string): boolean { if (!_CACHED_BODY) { _CACHED_BODY = getBodyNode() || {}; - _IS_WEBKIT = _CACHED_BODY !.style ? ('WebkitAppearance' in _CACHED_BODY !.style) : false; + _IS_WEBKIT = _CACHED_BODY!.style ? ('WebkitAppearance' in _CACHED_BODY!.style) : false; } let result = true; - if (_CACHED_BODY !.style && !containsVendorPrefix(prop)) { - result = prop in _CACHED_BODY !.style; + if (_CACHED_BODY!.style && !containsVendorPrefix(prop)) { + result = prop in _CACHED_BODY!.style; if (!result && _IS_WEBKIT) { const camelProp = 'Webkit' + prop.charAt(0).toUpperCase() + prop.substr(1); - result = camelProp in _CACHED_BODY !.style; + result = camelProp in _CACHED_BODY!.style; } } diff --git a/packages/animations/browser/src/render/special_cased_styles.ts b/packages/animations/browser/src/render/special_cased_styles.ts index 546c3df5e8943..e97aadbc855b4 100644 --- a/packages/animations/browser/src/render/special_cased_styles.ts +++ b/packages/animations/browser/src/render/special_cased_styles.ts @@ -19,7 +19,7 @@ import {eraseStyles, setStyles} from '../util'; * @returns an instance of `SpecialCasedStyles` if any special styles are detected otherwise `null` */ export function packageNonAnimatableStyles( - element: any, styles: {[key: string]: any} | {[key: string]: any}[]): SpecialCasedStyles|null { + element: any, styles: {[key: string]: any}|{[key: string]: any}[]): SpecialCasedStyles|null { let startStyles: {[key: string]: any}|null = null; let endStyles: {[key: string]: any}|null = null; if (Array.isArray(styles) && styles.length) { @@ -47,7 +47,7 @@ export class SpecialCasedStyles { static initialStylesByElement = new WeakMap<any, {[key: string]: any}>(); private _state = SpecialCasedStylesState.Pending; - private _initialStyles !: {[key: string]: any}; + private _initialStyles!: {[key: string]: any}; constructor( private _element: any, private _startStyles: {[key: string]: any}|null, diff --git a/packages/animations/browser/src/render/timeline_animation_engine.ts b/packages/animations/browser/src/render/timeline_animation_engine.ts index d83ad50223207..df26094c0a74c 100644 --- a/packages/animations/browser/src/render/timeline_animation_engine.ts +++ b/packages/animations/browser/src/render/timeline_animation_engine.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationPlayer, ɵStyleData} from '@angular/animations'; +import {AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationPlayer, AUTO_STYLE, ɵStyleData} from '@angular/animations'; import {Ast} from '../dsl/animation_ast'; import {buildAnimationAst} from '../dsl/animation_ast_builder'; @@ -34,7 +34,7 @@ export class TimelineAnimationEngine { const ast = buildAnimationAst(this._driver, metadata, errors); if (errors.length) { throw new Error( - `Unable to build the animation due to the following errors: ${errors.join("\n")}`); + `Unable to build the animation due to the following errors: ${errors.join('\n')}`); } else { this._animations[id] = ast; } @@ -71,12 +71,13 @@ export class TimelineAnimationEngine { if (errors.length) { throw new Error( - `Unable to create the animation due to the following errors: ${errors.join("\n")}`); + `Unable to create the animation due to the following errors: ${errors.join('\n')}`); } autoStylesMap.forEach((styles, element) => { - Object.keys(styles).forEach( - prop => { styles[prop] = this._driver.computeStyle(element, prop, AUTO_STYLE); }); + Object.keys(styles).forEach(prop => { + styles[prop] = this._driver.computeStyle(element, prop, AUTO_STYLE); + }); }); const players = instructions.map(i => { diff --git a/packages/animations/browser/src/render/transition_animation_engine.ts b/packages/animations/browser/src/render/transition_animation_engine.ts index f3ef0f80bc098..236f1e31808eb 100644 --- a/packages/animations/browser/src/render/transition_animation_engine.ts +++ b/packages/animations/browser/src/render/transition_animation_engine.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationOptions, AnimationPlayer, NoopAnimationPlayer, ɵAnimationGroupPlayer as AnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations'; +import {AnimationOptions, AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵAnimationGroupPlayer as AnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleData} from '@angular/animations'; import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction'; import {AnimationTransitionFactory} from '../dsl/animation_transition_factory'; @@ -13,7 +13,7 @@ import {AnimationTransitionInstruction} from '../dsl/animation_transition_instru import {AnimationTrigger} from '../dsl/animation_trigger'; import {ElementInstructionMap} from '../dsl/element_instruction_map'; import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer'; -import {ENTER_CLASSNAME, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, copyObj, eraseStyles, iteratorToArray, setStyles} from '../util'; +import {copyObj, ENTER_CLASSNAME, eraseStyles, iteratorToArray, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, setStyles} from '../util'; import {AnimationDriver} from './animation_driver'; import {getOrSetAsInMap, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer} from './shared'; @@ -71,7 +71,9 @@ export class StateValue { public value: string; public options: AnimationOptions; - get params(): {[key: string]: any} { return this.options.params as{[key: string]: any}; } + get params(): {[key: string]: any} { + return this.options.params as {[key: string]: any}; + } constructor(input: any, public namespaceId: string = '') { const isObj = input && input.hasOwnProperty('value'); @@ -92,7 +94,7 @@ export class StateValue { absorbOptions(options: AnimationOptions) { const newParams = options.params; if (newParams) { - const oldParams = this.options.params !; + const oldParams = this.options.params!; Object.keys(newParams).forEach(prop => { if (oldParams[prop] == null) { oldParams[prop] = newParams[prop]; @@ -263,7 +265,9 @@ export class AnimationTransitionNamespace { if (!isFallbackTransition) { addClass(element, QUEUED_CLASSNAME); - player.onStart(() => { removeClass(element, QUEUED_CLASSNAME); }); + player.onStart(() => { + removeClass(element, QUEUED_CLASSNAME); + }); } player.onDone(() => { @@ -290,11 +294,14 @@ export class AnimationTransitionNamespace { deregister(name: string) { delete this._triggers[name]; - this._engine.statesByElement.forEach((stateMap, element) => { delete stateMap[name]; }); + this._engine.statesByElement.forEach((stateMap, element) => { + delete stateMap[name]; + }); this._elementListeners.forEach((listeners, element) => { - this._elementListeners.set( - element, listeners.filter(entry => { return entry.name != name; })); + this._elementListeners.set(element, listeners.filter(entry => { + return entry.name != name; + })); }); } @@ -372,7 +379,7 @@ export class AnimationTransitionNamespace { const trigger = this._triggers[triggerName]; const transition = trigger.fallbackTransition; - const elementStates = this._engine.statesByElement.get(element) !; + const elementStates = this._engine.statesByElement.get(element)!; const fromState = elementStates[triggerName] || DEFAULT_STATE_VALUE; const toState = new StateValue(VOID_VALUE); const player = new TransitionAnimationPlayer(this.id, triggerName, element); @@ -448,7 +455,9 @@ export class AnimationTransitionNamespace { } } - insertNode(element: any, parent: any): void { addClass(element, this._hostClassName); } + insertNode(element: any, parent: any): void { + addClass(element, this._hostClassName); + } drainQueuedTransitions(microtaskId: number): QueueInstruction[] { const instructions: QueueInstruction[] = []; @@ -538,7 +547,9 @@ export class TransitionAnimationEngine { public onRemovalComplete = (element: any, context: any) => {}; /** @internal */ - _onRemovalComplete(element: any, context: any) { this.onRemovalComplete(element, context); } + _onRemovalComplete(element: any, context: any) { + this.onRemovalComplete(element, context); + } constructor( public bodyNode: any, public driver: AnimationDriver, @@ -631,7 +642,9 @@ export class TransitionAnimationEngine { this.afterFlushAnimationsDone(() => ns.destroy(context)); } - private _fetchNamespace(id: string) { return this._namespaceLookup[id]; } + private _fetchNamespace(id: string) { + return this._namespaceLookup[id]; + } fetchNamespacesByElement(element: any): Set<AnimationTransitionNamespace> { // normally there should only be one namespace per element, however @@ -704,7 +717,9 @@ export class TransitionAnimationEngine { } } - collectEnterElement(element: any) { this.collectedEnterElements.push(element); } + collectEnterElement(element: any) { + this.collectedEnterElements.push(element); + } markElementAsDisabled(element: any, value: boolean) { if (value) { @@ -740,11 +755,8 @@ export class TransitionAnimationEngine { markElementAsRemoved(namespaceId: string, element: any, hasAnimation?: boolean, context?: any) { this.collectedLeaveElements.push(element); - element[REMOVAL_FLAG] = { - namespaceId, - setForRemoval: context, hasAnimation, - removedBeforeQueried: false - }; + element[REMOVAL_FLAG] = + {namespaceId, setForRemoval: context, hasAnimation, removedBeforeQueried: false}; } listen( @@ -876,7 +888,9 @@ export class TransitionAnimationEngine { this._whenQuietFns = []; if (players.length) { - optimizeGroupPlayer(players).onDone(() => { quietFns.forEach(fn => fn()); }); + optimizeGroupPlayer(players).onDone(() => { + quietFns.forEach(fn => fn()); + }); } else { quietFns.forEach(fn => fn()); } @@ -950,16 +964,18 @@ export class TransitionAnimationEngine { cleanupFns.push(() => { enterNodeMap.forEach((nodes, root) => { - const className = enterNodeMapIds.get(root) !; + const className = enterNodeMapIds.get(root)!; nodes.forEach(node => removeClass(node, className)); }); leaveNodeMap.forEach((nodes, root) => { - const className = leaveNodeMapIds.get(root) !; + const className = leaveNodeMapIds.get(root)!; nodes.forEach(node => removeClass(node, className)); }); - allLeaveNodes.forEach(element => { this.processLeaveNode(element); }); + allLeaveNodes.forEach(element => { + this.processLeaveNode(element); + }); }); const allPlayers: TransitionAnimationPlayer[] = []; @@ -981,10 +997,10 @@ export class TransitionAnimationEngine { } const nodeIsOrphaned = !bodyNode || !this.driver.containsElement(bodyNode, element); - const leaveClassName = leaveNodeMapIds.get(element) !; - const enterClassName = enterNodeMapIds.get(element) !; + const leaveClassName = leaveNodeMapIds.get(element)!; + const enterClassName = enterNodeMapIds.get(element)!; const instruction = this._buildInstruction( - entry, subTimelines, enterClassName, leaveClassName, nodeIsOrphaned) !; + entry, subTimelines, enterClassName, leaveClassName, nodeIsOrphaned)!; if (instruction.errors && instruction.errors.length) { erroneousTransitions.push(instruction); return; @@ -1029,7 +1045,7 @@ export class TransitionAnimationEngine { instruction.preStyleProps.forEach((stringMap, element) => { const props = Object.keys(stringMap); if (props.length) { - let setVal: Set<string> = allPreStyleElements.get(element) !; + let setVal: Set<string> = allPreStyleElements.get(element)!; if (!setVal) { allPreStyleElements.set(element, setVal = new Set<string>()); } @@ -1039,7 +1055,7 @@ export class TransitionAnimationEngine { instruction.postStyleProps.forEach((stringMap, element) => { const props = Object.keys(stringMap); - let setVal: Set<string> = allPostStyleElements.get(element) !; + let setVal: Set<string> = allPostStyleElements.get(element)!; if (!setVal) { allPostStyleElements.set(element, setVal = new Set<string>()); } @@ -1052,7 +1068,7 @@ export class TransitionAnimationEngine { const errors: string[] = []; erroneousTransitions.forEach(instruction => { errors.push(`@${instruction.triggerName} has failed due to:\n`); - instruction.errors !.forEach(error => errors.push(`- ${error}\n`)); + instruction.errors!.forEach(error => errors.push(`- ${error}\n`)); }); allPlayers.forEach(player => player.destroy()); @@ -1116,7 +1132,7 @@ export class TransitionAnimationEngine { replaceNodes.forEach(node => { const post = postStylesMap.get(node); const pre = preStylesMap.get(node); - postStylesMap.set(node, { ...post, ...pre } as any); + postStylesMap.set(node, {...post, ...pre} as any); }); const rootPlayers: TransitionAnimationPlayer[] = []; @@ -1274,9 +1290,13 @@ export class TransitionAnimationEngine { return this._fetchNamespace(namespaceId).elementContainsData(element) || containsData; } - afterFlush(callback: () => any) { this._flushFns.push(callback); } + afterFlush(callback: () => any) { + this._flushFns.push(callback); + } - afterFlushAnimationsDone(callback: () => any) { this._whenQuietFns.push(callback); } + afterFlushAnimationsDone(callback: () => any) { + this._whenQuietFns.push(callback); + } private _getPreviousPlayers( element: string, isQueriedElement: boolean, namespaceId?: string, triggerName?: string, @@ -1413,8 +1433,9 @@ export class TransitionAnimationEngine { // this basically makes all of the callbacks for sub element animations // be dependent on the upper players for when they finish - allSubElements.forEach( - element => { getOrSetAsInMap(skippedPlayersMap, element, []).push(player); }); + allSubElements.forEach(element => { + getOrSetAsInMap(skippedPlayersMap, element, []).push(player); + }); return player; } @@ -1441,7 +1462,7 @@ export class TransitionAnimationPlayer implements AnimationPlayer { private _queuedCallbacks: {[name: string]: (() => any)[]} = {}; public readonly destroyed = false; // TODO(issue/24571): remove '!'. - public parentPlayer !: AnimationPlayer; + public parentPlayer!: AnimationPlayer; public markedForDestroy: boolean = false; public disabled = false; @@ -1462,17 +1483,21 @@ export class TransitionAnimationPlayer implements AnimationPlayer { this._queuedCallbacks = {}; this._containsRealPlayer = true; this.overrideTotalTime(player.totalTime); - (this as{queued: boolean}).queued = false; + (this as {queued: boolean}).queued = false; } - getRealPlayer() { return this._player; } + getRealPlayer() { + return this._player; + } - overrideTotalTime(totalTime: number) { (this as any).totalTime = totalTime; } + overrideTotalTime(totalTime: number) { + (this as any).totalTime = totalTime; + } syncPlayerEvents(player: AnimationPlayer) { const p = this._player as any; if (p.triggerCallback) { - player.onStart(() => p.triggerCallback !('start')); + player.onStart(() => p.triggerCallback!('start')); } player.onDone(() => this.finish()); player.onDestroy(() => this.destroy()); @@ -1503,24 +1528,38 @@ export class TransitionAnimationPlayer implements AnimationPlayer { this._player.onDestroy(fn); } - init(): void { this._player.init(); } + init(): void { + this._player.init(); + } - hasStarted(): boolean { return this.queued ? false : this._player.hasStarted(); } + hasStarted(): boolean { + return this.queued ? false : this._player.hasStarted(); + } - play(): void { !this.queued && this._player.play(); } + play(): void { + !this.queued && this._player.play(); + } - pause(): void { !this.queued && this._player.pause(); } + pause(): void { + !this.queued && this._player.pause(); + } - restart(): void { !this.queued && this._player.restart(); } + restart(): void { + !this.queued && this._player.restart(); + } - finish(): void { this._player.finish(); } + finish(): void { + this._player.finish(); + } destroy(): void { - (this as{destroyed: boolean}).destroyed = true; + (this as {destroyed: boolean}).destroyed = true; this._player.destroy(); } - reset(): void { !this.queued && this._player.reset(); } + reset(): void { + !this.queued && this._player.reset(); + } setPosition(p: any): void { if (!this.queued) { @@ -1528,7 +1567,9 @@ export class TransitionAnimationPlayer implements AnimationPlayer { } } - getPosition(): number { return this.queued ? 0 : this._player.getPosition(); } + getPosition(): number { + return this.queued ? 0 : this._player.getPosition(); + } /** @internal */ triggerCallback(phaseName: string): void { @@ -1539,7 +1580,7 @@ export class TransitionAnimationPlayer implements AnimationPlayer { } } -function deleteOrUnsetInMap(map: Map<any, any[]>| {[key: string]: any}, key: any, value: any) { +function deleteOrUnsetInMap(map: Map<any, any[]>|{[key: string]: any}, key: any, value: any) { let currentValues: any[]|null|undefined; if (map instanceof Map) { currentValues = map.get(key); @@ -1661,7 +1702,7 @@ function buildRootMap(roots: any[], nodes: any[]): Map<any, any[]> { nodes.forEach(node => { const root = getRoot(node); if (root !== NULL_NODE) { - rootMap.get(root) !.push(node); + rootMap.get(root)!.push(node); } }); @@ -1742,7 +1783,7 @@ function replacePostStylesAsPre( let preEntry = allPreStyleElements.get(element); if (preEntry) { - postEntry.forEach(data => preEntry !.add(data)); + postEntry.forEach(data => preEntry!.add(data)); } else { allPreStyleElements.set(element, postEntry); } diff --git a/packages/animations/browser/src/render/web_animations/web_animations_driver.ts b/packages/animations/browser/src/render/web_animations/web_animations_driver.ts index 29cd26e376ea2..00657d309abda 100644 --- a/packages/animations/browser/src/render/web_animations/web_animations_driver.ts +++ b/packages/animations/browser/src/render/web_animations/web_animations_driver.ts @@ -19,13 +19,17 @@ export class WebAnimationsDriver implements AnimationDriver { private _isNativeImpl = /\{\s*\[native\s+code\]\s*\}/.test(getElementAnimateFn().toString()); private _cssKeyframesDriver = new CssKeyframesDriver(); - validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); } + validateStyleProperty(prop: string): boolean { + return validateStyleProperty(prop); + } matchesElement(element: any, selector: string): boolean { return matchesElement(element, selector); } - containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); } + containsElement(elm1: any, elm2: any): boolean { + return containsElement(elm1, elm2); + } query(element: any, selector: string, multi: boolean): any[] { return invokeQuery(element, selector, multi); @@ -35,7 +39,9 @@ export class WebAnimationsDriver implements AnimationDriver { return (window.getComputedStyle(element) as any)[prop] as string; } - overrideWebAnimationsSupport(supported: boolean) { this._isNativeImpl = supported; } + overrideWebAnimationsSupport(supported: boolean) { + this._isNativeImpl = supported; + } animate( element: any, keyframes: ɵStyleData[], duration: number, delay: number, easing: string, @@ -47,7 +53,7 @@ export class WebAnimationsDriver implements AnimationDriver { } const fill = delay == 0 ? 'both' : 'forwards'; - const playerOptions: {[key: string]: string | number} = {duration, delay, fill}; + const playerOptions: {[key: string]: string|number} = {duration, delay, fill}; // we check for this to avoid having a null|undefined value be present // for the easing (which results in an error for certain browsers #9752) if (easing) { diff --git a/packages/animations/browser/src/render/web_animations/web_animations_player.ts b/packages/animations/browser/src/render/web_animations/web_animations_player.ts index 76c2cd44bed34..025fff00c490e 100644 --- a/packages/animations/browser/src/render/web_animations/web_animations_player.ts +++ b/packages/animations/browser/src/render/web_animations/web_animations_player.ts @@ -23,18 +23,18 @@ export class WebAnimationsPlayer implements AnimationPlayer { private _started = false; private _destroyed = false; // TODO(issue/24571): remove '!'. - private _finalKeyframe !: {[key: string]: string | number}; + private _finalKeyframe!: {[key: string]: string|number}; // TODO(issue/24571): remove '!'. - public readonly domPlayer !: DOMAnimation; + public readonly domPlayer!: DOMAnimation; public time = 0; public parentPlayer: AnimationPlayer|null = null; - public currentSnapshot: {[styleName: string]: string | number} = {}; + public currentSnapshot: {[styleName: string]: string|number} = {}; constructor( - public element: any, public keyframes: {[key: string]: string | number}[], - public options: {[key: string]: string | number}, + public element: any, public keyframes: {[key: string]: string|number}[], + public options: {[key: string]: string|number}, private _specialStyles?: SpecialCasedStyles|null) { this._duration = <number>options['duration']; this._delay = <number>options['delay'] || 0; @@ -59,7 +59,7 @@ export class WebAnimationsPlayer implements AnimationPlayer { this._initialized = true; const keyframes = this.keyframes; - (this as{domPlayer: DOMAnimation}).domPlayer = + (this as {domPlayer: DOMAnimation}).domPlayer = this._triggerWebAnimation(this.element, keyframes, this.options); this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : {}; this.domPlayer.addEventListener('finish', () => this._onFinish()); @@ -81,11 +81,17 @@ export class WebAnimationsPlayer implements AnimationPlayer { return element['animate'](keyframes, options) as DOMAnimation; } - onStart(fn: () => void): void { this._onStartFns.push(fn); } + onStart(fn: () => void): void { + this._onStartFns.push(fn); + } - onDone(fn: () => void): void { this._onDoneFns.push(fn); } + onDone(fn: () => void): void { + this._onDoneFns.push(fn); + } - onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); } + onDestroy(fn: () => void): void { + this._onDestroyFns.push(fn); + } play(): void { this._buildPlayer(); @@ -132,7 +138,9 @@ export class WebAnimationsPlayer implements AnimationPlayer { this.play(); } - hasStarted(): boolean { return this._started; } + hasStarted(): boolean { + return this._started; + } destroy(): void { if (!this._destroyed) { @@ -147,14 +155,20 @@ export class WebAnimationsPlayer implements AnimationPlayer { } } - setPosition(p: number): void { this.domPlayer.currentTime = p * this.time; } + setPosition(p: number): void { + this.domPlayer.currentTime = p * this.time; + } - getPosition(): number { return this.domPlayer.currentTime / this.time; } + getPosition(): number { + return this.domPlayer.currentTime / this.time; + } - get totalTime(): number { return this._delay + this._duration; } + get totalTime(): number { + return this._delay + this._duration; + } beforeDestroy() { - const styles: {[key: string]: string | number} = {}; + const styles: {[key: string]: string|number} = {}; if (this.hasStarted()) { Object.keys(this._finalKeyframe).forEach(prop => { if (prop != 'offset') { diff --git a/packages/animations/browser/src/util.ts b/packages/animations/browser/src/util.ts index ffcc2a7567d1d..aad7d53ae104b 100644 --- a/packages/animations/browser/src/util.ts +++ b/packages/animations/browser/src/util.ts @@ -23,7 +23,7 @@ export const NG_TRIGGER_SELECTOR = '.ng-trigger'; export const NG_ANIMATING_CLASSNAME = 'ng-animating'; export const NG_ANIMATING_SELECTOR = '.ng-animating'; -export function resolveTimingValue(value: string | number) { +export function resolveTimingValue(value: string|number) { if (typeof value == 'number') return value; const matches = value.match(/^(-?[\.\d]+)(m?s)/); @@ -42,14 +42,14 @@ function _convertTimeValueToMS(value: number, unit: string): number { } export function resolveTiming( - timings: string | number | AnimateTimings, errors: any[], allowNegativeValues?: boolean) { + timings: string|number|AnimateTimings, errors: any[], allowNegativeValues?: boolean) { return timings.hasOwnProperty('duration') ? <AnimateTimings>timings : parseTimeExpression(<string|number>timings, errors, allowNegativeValues); } function parseTimeExpression( - exp: string | number, errors: string[], allowNegativeValues?: boolean): AnimateTimings { + exp: string|number, errors: string[], allowNegativeValues?: boolean): AnimateTimings { const regex = /^(-?[\.\d]+)(m?s)(?:\s+(-?[\.\d]+)(m?s))?(?:\s+([-a-z]+(?:\(.+?\))?))?$/i; let duration: number; let delay: number = 0; @@ -97,11 +97,13 @@ function parseTimeExpression( export function copyObj( obj: {[key: string]: any}, destination: {[key: string]: any} = {}): {[key: string]: any} { - Object.keys(obj).forEach(prop => { destination[prop] = obj[prop]; }); + Object.keys(obj).forEach(prop => { + destination[prop] = obj[prop]; + }); return destination; } -export function normalizeStyles(styles: ɵStyleData | ɵStyleData[]): ɵStyleData { +export function normalizeStyles(styles: ɵStyleData|ɵStyleData[]): ɵStyleData { const normalizedStyles: ɵStyleData = {}; if (Array.isArray(styles)) { styles.forEach(data => copyStyles(data, false, normalizedStyles)); @@ -186,8 +188,8 @@ export function eraseStyles(element: any, styles: ɵStyleData) { } } -export function normalizeAnimationEntry(steps: AnimationMetadata | AnimationMetadata[]): - AnimationMetadata { +export function normalizeAnimationEntry(steps: AnimationMetadata| + AnimationMetadata[]): AnimationMetadata { if (Array.isArray(steps)) { if (steps.length == 1) return steps[0]; return sequence(steps); @@ -196,7 +198,7 @@ export function normalizeAnimationEntry(steps: AnimationMetadata | AnimationMeta } export function validateStyleParams( - value: string | number, options: AnimationOptions, errors: any[]) { + value: string|number, options: AnimationOptions, errors: any[]) { const params = options.params || {}; const matches = extractStyleParams(value); if (matches.length) { @@ -211,7 +213,7 @@ export function validateStyleParams( const PARAM_REGEX = new RegExp(`${SUBSTITUTION_EXPR_START}\\s*(.+?)\\s*${SUBSTITUTION_EXPR_END}`, 'g'); -export function extractStyleParams(value: string | number): string[] { +export function extractStyleParams(value: string|number): string[] { let params: string[] = []; if (typeof value === 'string') { let match: any; @@ -224,7 +226,7 @@ export function extractStyleParams(value: string | number): string[] { } export function interpolateParams( - value: string | number, params: {[name: string]: any}, errors: any[]): string|number { + value: string|number, params: {[name: string]: any}, errors: any[]): string|number { const original = value.toString(); const str = original.replace(PARAM_REGEX, (_, varName) => { let localVal = params[varName]; @@ -297,7 +299,9 @@ export function balancePreviousStylesIntoKeyframes( // tslint:disable-next-line for (var i = 1; i < keyframes.length; i++) { let kf = keyframes[i]; - missingStyleProps.forEach(function(prop) { kf[prop] = computeStyle(element, prop); }); + missingStyleProps.forEach(function(prop) { + kf[prop] = computeStyle(element, prop); + }); } } } diff --git a/packages/animations/browser/test/dsl/animation_spec.ts b/packages/animations/browser/test/dsl/animation_spec.ts index 4fe716c808717..5aacf1c78b734 100644 --- a/packages/animations/browser/test/dsl/animation_spec.ts +++ b/packages/animations/browser/test/dsl/animation_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationMetadata, AnimationMetadataType, AnimationOptions, animate, animation, group, keyframes, query, sequence, state, style, transition, trigger, useAnimation, ɵStyleData} from '@angular/animations'; +import {animate, animation, AnimationMetadata, AnimationMetadataType, AnimationOptions, AUTO_STYLE, group, keyframes, query, sequence, state, style, transition, trigger, useAnimation, ɵStyleData} from '@angular/animations'; import {Animation} from '../../src/dsl/animation'; import {buildAnimationAst} from '../../src/dsl/animation_ast_builder'; @@ -35,7 +35,9 @@ function createDiv() { rootElement.appendChild(subElement2); }); - afterEach(() => { document.body.removeChild(rootElement); }); + afterEach(() => { + document.body.removeChild(rootElement); + }); describe('validation', () => { it('should throw an error if one or more but not all keyframes() styles contain offsets', @@ -45,7 +47,9 @@ function createDiv() { style({opacity: 1, offset: 1}), ])); - expect(() => { validateAndThrowAnimationSequence(steps); }) + expect(() => { + validateAndThrowAnimationSequence(steps); + }) .toThrowError( /Not all style\(\) steps within the declared keyframes\(\) contain offsets/); }); @@ -96,7 +100,9 @@ function createDiv() { ])) ]); - expect(() => { validateAndThrowAnimationSequence(steps); }) + expect(() => { + validateAndThrowAnimationSequence(steps); + }) .toThrowError( /The CSS property "opacity" that exists between the times of "0ms" and "2000ms" is also being animated in a parallel animation between the times of "0ms" and "1500ms"/); }); @@ -191,7 +197,9 @@ function createDiv() { })), ]; - expect(() => { validateAndThrowAnimationSequence(steps); }) + expect(() => { + validateAndThrowAnimationSequence(steps); + }) .toThrowError( /state\("final", ...\) must define default values for all the following style substitutions: one, two, three/); @@ -203,7 +211,9 @@ function createDiv() { }), {params: {redColor: 'maroon'}})]; - expect(() => { validateAndThrowAnimationSequence(steps2); }) + expect(() => { + validateAndThrowAnimationSequence(steps2); + }) .toThrowError( /state\("panfinal", ...\) must define default values for all the following style substitutions: greyColor/); }); @@ -211,7 +221,9 @@ function createDiv() { it('should throw an error if an invalid CSS property is used in the animation', () => { const steps = [animate(1000, style({abc: '500px'}))]; - expect(() => { validateAndThrowAnimationSequence(steps); }) + expect(() => { + validateAndThrowAnimationSequence(steps); + }) .toThrowError( /The provided animation property "abc" is not a supported CSS property for animations/); }); @@ -388,7 +400,7 @@ function createDiv() { let players = invokeAnimationSequence(rootElement, steps); expect(players.length).toEqual(1); - let p1 = players.pop() !; + let p1 = players.pop()!; expect(p1.duration).toEqual(1500); expect(p1.keyframes).toEqual([ {width: '*', offset: 0}, @@ -405,7 +417,7 @@ function createDiv() { players = invokeAnimationSequence(rootElement, steps); expect(players.length).toEqual(1); - p1 = players.pop() !; + p1 = players.pop()!; expect(p1.duration).toEqual(1000); expect(p1.keyframes).toEqual([ {width: '100px', offset: 0}, @@ -876,7 +888,9 @@ function createDiv() { const steps = [query('somethingFake', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]; - expect(() => { invokeAnimationSequence(rootElement, steps); }) + expect(() => { + invokeAnimationSequence(rootElement, steps); + }) .toThrowError( /`query\("somethingFake"\)` returned zero elements\. \(Use `query\("somethingFake", \{ optional: true \}\)` if you wish to allow this\.\)/); }); @@ -887,13 +901,17 @@ function createDiv() { 'somethingFake', [style({opacity: 0}), animate(1000, style({opacity: 1}))], {optional: true})]; - expect(() => { invokeAnimationSequence(rootElement, steps); }).not.toThrow(); + expect(() => { + invokeAnimationSequence(rootElement, steps); + }).not.toThrow(); const steps2 = [query( 'fakeSomethings', [style({opacity: 0}), animate(1000, style({opacity: 1}))], {optional: true})]; - expect(() => { invokeAnimationSequence(rootElement, steps2); }).not.toThrow(); + expect(() => { + invokeAnimationSequence(rootElement, steps2); + }).not.toThrow(); }); it('should delay the query operation if a delay option is provided', () => { @@ -1025,8 +1043,7 @@ function createDiv() { const players = invokeAnimationSequence(rootElement, steps, {}, fromStyles, toStyles); expect(players[0].keyframes).toEqual([ - {background: 'blue', offset: 0, easing: 'ease-out'}, - {background: 'red', offset: 1} + {background: 'blue', offset: 0, easing: 'ease-out'}, {background: 'red', offset: 1} ]); }); }); @@ -1042,7 +1059,7 @@ function humanizeOffsets(keyframes: ɵStyleData[], digits: number = 3): ɵStyleD } function invokeAnimationSequence( - element: any, steps: AnimationMetadata | AnimationMetadata[], locals: {[key: string]: any} = {}, + element: any, steps: AnimationMetadata|AnimationMetadata[], locals: {[key: string]: any} = {}, startingStyles: ɵStyleData[] = [], destinationStyles: ɵStyleData[] = [], subInstructions?: ElementInstructionMap): AnimationTimelineInstruction[] { const driver = new MockAnimationDriver(); @@ -1050,7 +1067,7 @@ function invokeAnimationSequence( .buildTimelines(element, startingStyles, destinationStyles, locals, subInstructions); } -function validateAndThrowAnimationSequence(steps: AnimationMetadata | AnimationMetadata[]) { +function validateAndThrowAnimationSequence(steps: AnimationMetadata|AnimationMetadata[]) { const driver = new MockAnimationDriver(); const errors: any[] = []; const ast = buildAnimationAst(driver, steps, errors); diff --git a/packages/animations/browser/test/dsl/animation_trigger_spec.ts b/packages/animations/browser/test/dsl/animation_trigger_spec.ts index 5482075fc6458..f2c2e134b4e6c 100644 --- a/packages/animations/browser/test/dsl/animation_trigger_spec.ts +++ b/packages/animations/browser/test/dsl/animation_trigger_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {AnimationOptions, animate, state, style, transition} from '@angular/animations'; +import {animate, AnimationOptions, state, style, transition} from '@angular/animations'; import {AnimationTransitionInstruction} from '@angular/animations/browser/src/dsl/animation_transition_instruction'; import {AnimationTrigger} from '@angular/animations/browser/src/dsl/animation_trigger'; @@ -25,7 +25,9 @@ import {makeTrigger} from '../shared'; document.body.appendChild(element); }); - afterEach(() => { document.body.removeChild(element); }); + afterEach(() => { + document.body.removeChild(element); + }); describe('trigger validation', () => { it('should group errors together for an animation trigger', () => { @@ -36,8 +38,9 @@ import {makeTrigger} from '../shared'; it('should throw an error when a transition within a trigger contains an invalid expression', () => { - expect( - () => { makeTrigger('name', [transition('somethingThatIsWrong', animate(3333))]); }) + expect(() => { + makeTrigger('name', [transition('somethingThatIsWrong', animate(3333))]); + }) .toThrowError( /- The provided transition expression "somethingThatIsWrong" is not supported/); }); @@ -78,7 +81,7 @@ import {makeTrigger} from '../shared'; const result = makeTrigger( 'name', [transition('a => b', animate(1234)), transition('b => c', animate(5678))]); - const trans = buildTransition(result, element, 'b', 'c') !; + const trans = buildTransition(result, element, 'b', 'c')!; expect(trans.timelines.length).toEqual(1); const timeline = trans.timelines[0]; expect(timeline.duration).toEqual(5678); @@ -90,13 +93,13 @@ import {makeTrigger} from '../shared'; transition('* => *', animate(9999)) ]); - let trans = buildTransition(result, element, 'b', 'c') !; + let trans = buildTransition(result, element, 'b', 'c')!; expect(trans.timelines[0].duration).toEqual(5678); - trans = buildTransition(result, element, 'a', 'b') !; + trans = buildTransition(result, element, 'a', 'b')!; expect(trans.timelines[0].duration).toEqual(1234); - trans = buildTransition(result, element, 'c', 'c') !; + trans = buildTransition(result, element, 'c', 'c')!; expect(trans.timelines[0].duration).toEqual(9999); }); @@ -110,23 +113,23 @@ import {makeTrigger} from '../shared'; it('should support bi-directional transition expressions', () => { const result = makeTrigger('name', [transition('a <=> b', animate(2222))]); - const t1 = buildTransition(result, element, 'a', 'b') !; + const t1 = buildTransition(result, element, 'a', 'b')!; expect(t1.timelines[0].duration).toEqual(2222); - const t2 = buildTransition(result, element, 'b', 'a') !; + const t2 = buildTransition(result, element, 'b', 'a')!; expect(t2.timelines[0].duration).toEqual(2222); }); it('should support multiple transition statements in one string', () => { const result = makeTrigger('name', [transition('a => b, b => a, c => *', animate(1234))]); - const t1 = buildTransition(result, element, 'a', 'b') !; + const t1 = buildTransition(result, element, 'a', 'b')!; expect(t1.timelines[0].duration).toEqual(1234); - const t2 = buildTransition(result, element, 'b', 'a') !; + const t2 = buildTransition(result, element, 'b', 'a')!; expect(t2.timelines[0].duration).toEqual(1234); - const t3 = buildTransition(result, element, 'c', 'a') !; + const t3 = buildTransition(result, element, 'c', 'a')!; expect(t3.timelines[0].duration).toEqual(1234); }); @@ -138,7 +141,7 @@ import {makeTrigger} from '../shared'; 'a => b', [style({height: '{{ a }}'}), animate(1000, style({height: '{{ b }}'}))], buildParams({a: '100px', b: '200px'}))]); - const trans = buildTransition(result, element, 'a', 'b') !; + const trans = buildTransition(result, element, 'a', 'b')!; const keyframes = trans.timelines[0].keyframes; expect(keyframes).toEqual([{height: '100px', offset: 0}, {height: '200px', offset: 1}]); }); @@ -153,7 +156,7 @@ import {makeTrigger} from '../shared'; buildParams({a: '100px', b: '200px'}))]); const trans = - buildTransition(result, element, 'a', 'b', {}, buildParams({a: '300px'})) !; + buildTransition(result, element, 'a', 'b', {}, buildParams({a: '300px'}))!; const keyframes = trans.timelines[0].keyframes; expect(keyframes).toEqual( @@ -167,7 +170,7 @@ import {makeTrigger} from '../shared'; transition('true <=> false', animate(1234)) ]); - const trans = buildTransition(result, element, false, true) !; + const trans = buildTransition(result, element, false, true)!; expect(trans.timelines[0].duration).toEqual(1234); }); @@ -177,7 +180,7 @@ import {makeTrigger} from '../shared'; transition('1 <=> 0', animate(4567)) ]); - const trans = buildTransition(result, element, false, true) !; + const trans = buildTransition(result, element, false, true)!; expect(trans.timelines[0].duration).toEqual(4567); }); @@ -188,7 +191,7 @@ import {makeTrigger} from '../shared'; transition('1 <=> 0', animate(4567)) ]); - const trans = buildTransition(result, element, false, true) !; + const trans = buildTransition(result, element, false, true)!; expect(trans.timelines[0].keyframes).toEqual([ {offset: 0, color: 'red'}, {offset: 1, color: 'green'} ]); @@ -201,7 +204,7 @@ import {makeTrigger} from '../shared'; transition('true <=> false', animate(4567)) ]); - const trans = buildTransition(result, element, false, true) !; + const trans = buildTransition(result, element, false, true)!; expect(trans.timelines[0].keyframes).toEqual([ {offset: 0, color: 'orange'}, {offset: 1, color: 'blue'} ]); @@ -214,7 +217,7 @@ import {makeTrigger} from '../shared'; ]); expect(() => { - const trans = buildTransition(result, element, false, true) !; + const trans = buildTransition(result, element, false, true)!; }).not.toThrow(); }); @@ -222,14 +225,14 @@ import {makeTrigger} from '../shared'; it('should alias the :enter transition as void => *', () => { const result = makeTrigger('name', [transition(':enter', animate(3333))]); - const trans = buildTransition(result, element, 'void', 'something') !; + const trans = buildTransition(result, element, 'void', 'something')!; expect(trans.timelines[0].duration).toEqual(3333); }); it('should alias the :leave transition as * => void', () => { const result = makeTrigger('name', [transition(':leave', animate(3333))]); - const trans = buildTransition(result, element, 'something', 'void') !; + const trans = buildTransition(result, element, 'something', 'void')!; expect(trans.timelines[0].duration).toEqual(3333); }); }); @@ -242,12 +245,12 @@ function buildTransition( fromOptions?: AnimationOptions, toOptions?: AnimationOptions): AnimationTransitionInstruction| null { const params = toOptions && toOptions.params || {}; - const trans = trigger.matchTransition(fromState, toState, element, params) !; + const trans = trigger.matchTransition(fromState, toState, element, params)!; if (trans) { const driver = new MockAnimationDriver(); return trans.build( driver, element, fromState, toState, ENTER_CLASSNAME, LEAVE_CLASSNAME, fromOptions, - toOptions) !; + toOptions)!; } return null; } diff --git a/packages/animations/browser/test/dsl/style_normalizer/web_animations_style_normalizer_spec.ts b/packages/animations/browser/test/dsl/style_normalizer/web_animations_style_normalizer_spec.ts index 003df7678cc9a..17d5878ffe775 100644 --- a/packages/animations/browser/test/dsl/style_normalizer/web_animations_style_normalizer_spec.ts +++ b/packages/animations/browser/test/dsl/style_normalizer/web_animations_style_normalizer_spec.ts @@ -16,13 +16,13 @@ import {WebAnimationsStyleNormalizer} from '../../../src/dsl/style_normalization expect(normalizer.normalizePropertyName('width', [])).toEqual('width'); expect(normalizer.normalizePropertyName('border-width', [])).toEqual('borderWidth'); expect(normalizer.normalizePropertyName('borderHeight', [])).toEqual('borderHeight'); - expect(normalizer.normalizePropertyName('-webkit-animation', [ - ])).toEqual('WebkitAnimation'); + expect(normalizer.normalizePropertyName('-webkit-animation', [])) + .toEqual('WebkitAnimation'); }); }); describe('normalizeStyleValue', () => { - function normalize(prop: string, val: string | number): string { + function normalize(prop: string, val: string|number): string { const errors: string[] = []; const result = normalizer.normalizeStyleValue(prop, prop, val, errors); if (errors.length) { diff --git a/packages/animations/browser/test/render/css_keyframes/css_keyframes_driver_spec.ts b/packages/animations/browser/test/render/css_keyframes/css_keyframes_driver_spec.ts index 747a3895751ee..54a4a73d06d1d 100644 --- a/packages/animations/browser/test/render/css_keyframes/css_keyframes_driver_spec.ts +++ b/packages/animations/browser/test/render/css_keyframes/css_keyframes_driver_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing'; import {CssKeyframesDriver} from '../../../src/render/css_keyframes/css_keyframes_driver'; import {CssKeyframesPlayer} from '../../../src/render/css_keyframes/css_keyframes_player'; @@ -16,7 +16,7 @@ import {assertElementExistsInDom, createElement, findKeyframeDefinition, forceRe const CSS_KEYFRAME_RULE_TYPE = 7; describe('CssKeyframesDriver tests', () => { - if (isNode || typeof(window as any)['AnimationEvent'] == 'undefined') return; + if (isNode || typeof (window as any)['AnimationEvent'] == 'undefined') return; describe('building keyframes', () => { it('should build CSS keyframe style object containing the keyframe styles', () => { @@ -28,7 +28,7 @@ describe('CssKeyframesDriver tests', () => { {opacity: 1, width: '200px', offset: 1}, ]); - const head = document.querySelector('head') !; + const head = document.querySelector('head')!; head.appendChild(kfElm); forceReflow(); @@ -67,7 +67,7 @@ describe('CssKeyframesDriver tests', () => { {width: '200px', offset: 1}, ]); - const head = document.querySelector('head') !; + const head = document.querySelector('head')!; head.appendChild(kfElm); forceReflow(); @@ -261,7 +261,7 @@ describe('CssKeyframesDriver tests', () => { player.play(); player.finish(); - player.beforeDestroy !(); + player.beforeDestroy!(); expect(player.currentSnapshot).toEqual({ width: '999px', height: '999px', diff --git a/packages/animations/browser/test/render/css_keyframes/direct_style_player_spec.ts b/packages/animations/browser/test/render/css_keyframes/direct_style_player_spec.ts index c04ae07783dfe..86234018ad614 100644 --- a/packages/animations/browser/test/render/css_keyframes/direct_style_player_spec.ts +++ b/packages/animations/browser/test/render/css_keyframes/direct_style_player_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing'; import {DirectStylePlayer} from '../../../src/render/css_keyframes/direct_style_player'; diff --git a/packages/animations/browser/test/render/css_keyframes/element_animation_style_handler_spec.ts b/packages/animations/browser/test/render/css_keyframes/element_animation_style_handler_spec.ts index d5b64b5758d1b..ad5984c599add 100644 --- a/packages/animations/browser/test/render/css_keyframes/element_animation_style_handler_spec.ts +++ b/packages/animations/browser/test/render/css_keyframes/element_animation_style_handler_spec.ts @@ -13,7 +13,7 @@ import {assertStyle, createElement, makeAnimationEvent, supportsAnimationEventCr const EMPTY_FN = () => {}; { describe('ElementAnimationStyleHandler', () => { - if (isNode || typeof(window as any)['AnimationEvent'] == 'undefined') return; + if (isNode || typeof (window as any)['AnimationEvent'] == 'undefined') return; it('should add and remove an animation on to an element\'s styling', () => { const element = createElement(); diff --git a/packages/animations/browser/test/render/css_keyframes/shared.ts b/packages/animations/browser/test/render/css_keyframes/shared.ts index e60a4f50ad665..d9592ee5a0f0a 100644 --- a/packages/animations/browser/test/render/css_keyframes/shared.ts +++ b/packages/animations/browser/test/render/css_keyframes/shared.ts @@ -10,7 +10,7 @@ export function forceReflow() { } export function makeAnimationEvent( - startOrEnd: 'start' | 'end', animationName: string, elapsedTime: number, timestamp?: number) { + startOrEnd: 'start'|'end', animationName: string, elapsedTime: number, timestamp?: number) { const e = new AnimationEvent('animation' + startOrEnd, {animationName, elapsedTime}); if (timestamp) { (e as any)._ngTestManualTimestamp = timestamp; diff --git a/packages/animations/browser/test/render/timeline_animation_engine_spec.ts b/packages/animations/browser/test/render/timeline_animation_engine_spec.ts index b9471416335b9..a6fb9e873103a 100644 --- a/packages/animations/browser/test/render/timeline_animation_engine_spec.ts +++ b/packages/animations/browser/test/render/timeline_animation_engine_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AnimationMetadata, animate, style} from '@angular/animations'; +import {animate, AnimationMetadata, style} from '@angular/animations'; import {AnimationStyleNormalizer, NoopAnimationStyleNormalizer} from '../../src/dsl/style_normalization/animation_style_normalizer'; import {AnimationDriver} from '../../src/render/animation_driver'; @@ -14,98 +14,101 @@ import {TimelineAnimationEngine} from '../../src/render/timeline_animation_engin import {MockAnimationDriver, MockAnimationPlayer} from '../../testing/src/mock_animation_driver'; (function() { - const defaultDriver = new MockAnimationDriver(); +const defaultDriver = new MockAnimationDriver(); - function makeEngine(body: any, driver?: AnimationDriver, normalizer?: AnimationStyleNormalizer) { - return new TimelineAnimationEngine( - body, driver || defaultDriver, normalizer || new NoopAnimationStyleNormalizer()); - } +function makeEngine(body: any, driver?: AnimationDriver, normalizer?: AnimationStyleNormalizer) { + return new TimelineAnimationEngine( + body, driver || defaultDriver, normalizer || new NoopAnimationStyleNormalizer()); +} + +// these tests are only mean't to be run within the DOM +if (isNode) return; + +describe('TimelineAnimationEngine', () => { + let element: any; + + beforeEach(() => { + MockAnimationDriver.log = []; + element = document.createElement('div'); + document.body.appendChild(element); + }); + + afterEach(() => document.body.removeChild(element)); + + it('should animate a timeline', () => { + const engine = makeEngine(getBodyNode()); + const steps = [style({height: 100}), animate(1000, style({height: 0}))]; + expect(MockAnimationDriver.log.length).toEqual(0); + invokeAnimation(engine, element, steps); + expect(MockAnimationDriver.log.length).toEqual(1); + }); - // these tests are only mean't to be run within the DOM - if (isNode) return; - - describe('TimelineAnimationEngine', () => { - let element: any; - - beforeEach(() => { - MockAnimationDriver.log = []; - element = document.createElement('div'); - document.body.appendChild(element); - }); - - afterEach(() => document.body.removeChild(element)); - - it('should animate a timeline', () => { - const engine = makeEngine(getBodyNode()); - const steps = [style({height: 100}), animate(1000, style({height: 0}))]; - expect(MockAnimationDriver.log.length).toEqual(0); - invokeAnimation(engine, element, steps); - expect(MockAnimationDriver.log.length).toEqual(1); - }); - - it('should not destroy timeline-based animations after they have finished', () => { - const engine = makeEngine(getBodyNode()); - - const log: string[] = []; - function capture(value: string) { - return () => { log.push(value); }; - } - - const steps = [style({height: 0}), animate(1000, style({height: 500}))]; - - const player = invokeAnimation(engine, element, steps); - player.onDone(capture('done')); - player.onDestroy(capture('destroy')); - expect(log).toEqual([]); - - player.finish(); - expect(log).toEqual(['done']); - - player.destroy(); - expect(log).toEqual(['done', 'destroy']); - }); - - it('should normalize the style values that are animateTransitioned within an a timeline animation', - () => { - const engine = - makeEngine(getBodyNode(), defaultDriver, new SuffixNormalizer('-normalized')); - - const steps = [ - style({width: '333px'}), - animate(1000, style({width: '999px'})), - ]; - - const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer; - expect(player.keyframes).toEqual([ - {'width-normalized': '333px-normalized', offset: 0}, - {'width-normalized': '999px-normalized', offset: 1} - ]); - }); - - it('should normalize `*` values', () => { - const driver = new SuperMockDriver(); - const engine = makeEngine(getBodyNode(), driver); - - const steps = [ - style({width: '*'}), - animate(1000, style({width: '999px'})), - ]; - - const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer; - expect(player.keyframes).toEqual([{width: '*star*', offset: 0}, {width: '999px', offset: 1}]); - }); + it('should not destroy timeline-based animations after they have finished', () => { + const engine = makeEngine(getBodyNode()); + + const log: string[] = []; + function capture(value: string) { + return () => { + log.push(value); + }; + } + + const steps = [style({height: 0}), animate(1000, style({height: 500}))]; + + const player = invokeAnimation(engine, element, steps); + player.onDone(capture('done')); + player.onDestroy(capture('destroy')); + expect(log).toEqual([]); + + player.finish(); + expect(log).toEqual(['done']); + + player.destroy(); + expect(log).toEqual(['done', 'destroy']); }); + + it('should normalize the style values that are animateTransitioned within an a timeline animation', + () => { + const engine = makeEngine(getBodyNode(), defaultDriver, new SuffixNormalizer('-normalized')); + + const steps = [ + style({width: '333px'}), + animate(1000, style({width: '999px'})), + ]; + + const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer; + expect(player.keyframes).toEqual([ + {'width-normalized': '333px-normalized', offset: 0}, + {'width-normalized': '999px-normalized', offset: 1} + ]); + }); + + it('should normalize `*` values', () => { + const driver = new SuperMockDriver(); + const engine = makeEngine(getBodyNode(), driver); + + const steps = [ + style({width: '*'}), + animate(1000, style({width: '999px'})), + ]; + + const player = invokeAnimation(engine, element, steps) as MockAnimationPlayer; + expect(player.keyframes).toEqual([{width: '*star*', offset: 0}, {width: '999px', offset: 1}]); + }); +}); })(); function invokeAnimation( - engine: TimelineAnimationEngine, element: any, steps: AnimationMetadata | AnimationMetadata[], + engine: TimelineAnimationEngine, element: any, steps: AnimationMetadata|AnimationMetadata[], id: string = 'id') { engine.register(id, steps); return engine.create(id, element); } class SuffixNormalizer extends AnimationStyleNormalizer { - constructor(private _suffix: string) { super(); } + constructor(private _suffix: string) { + super(); + } normalizePropertyName(propertyName: string, errors: string[]): string { return propertyName + this._suffix; @@ -119,5 +122,7 @@ class SuffixNormalizer extends AnimationStyleNormalizer { } class SuperMockDriver extends MockAnimationDriver { - computeStyle(element: any, prop: string, defaultValue?: string): string { return '*star*'; } + computeStyle(element: any, prop: string, defaultValue?: string): string { + return '*star*'; + } } diff --git a/packages/animations/browser/test/render/transition_animation_engine_spec.ts b/packages/animations/browser/test/render/transition_animation_engine_spec.ts index 98d80c294d6c4..21502489e9587 100644 --- a/packages/animations/browser/test/render/transition_animation_engine_spec.ts +++ b/packages/animations/browser/test/render/transition_animation_engine_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AnimationEvent, AnimationMetadata, AnimationTriggerMetadata, NoopAnimationPlayer, animate, state, style, transition, trigger} from '@angular/animations'; +import {animate, AnimationEvent, AnimationMetadata, AnimationTriggerMetadata, NoopAnimationPlayer, state, style, transition, trigger} from '@angular/animations'; import {TriggerAst} from '../../src/dsl/animation_ast'; import {buildAnimationAst} from '../../src/dsl/animation_ast_builder'; @@ -18,673 +18,680 @@ import {MockAnimationDriver, MockAnimationPlayer} from '../../testing/src/mock_a const DEFAULT_NAMESPACE_ID = 'id'; (function() { - const driver = new MockAnimationDriver(); +const driver = new MockAnimationDriver(); - // these tests are only mean't to be run within the DOM - if (isNode) return; +// these tests are only mean't to be run within the DOM +if (isNode) return; - describe('TransitionAnimationEngine', () => { - let element: any; +describe('TransitionAnimationEngine', () => { + let element: any; - beforeEach(() => { - MockAnimationDriver.log = []; - element = document.createElement('div'); - document.body.appendChild(element); - }); + beforeEach(() => { + MockAnimationDriver.log = []; + element = document.createElement('div'); + document.body.appendChild(element); + }); - afterEach(() => { document.body.removeChild(element); }); + afterEach(() => { + document.body.removeChild(element); + }); - function makeEngine(normalizer?: AnimationStyleNormalizer) { - const engine = new TransitionAnimationEngine( - getBodyNode(), driver, normalizer || new NoopAnimationStyleNormalizer()); - engine.createNamespace(DEFAULT_NAMESPACE_ID, element); - return engine; - } + function makeEngine(normalizer?: AnimationStyleNormalizer) { + const engine = new TransitionAnimationEngine( + getBodyNode(), driver, normalizer || new NoopAnimationStyleNormalizer()); + engine.createNamespace(DEFAULT_NAMESPACE_ID, element); + return engine; + } - describe('trigger registration', () => { - it('should ignore and not throw an error if the same trigger is registered twice', () => { - // TODO (matsko): ask why this is avoided - const engine = makeEngine(); + describe('trigger registration', () => { + it('should ignore and not throw an error if the same trigger is registered twice', () => { + // TODO (matsko): ask why this is avoided + const engine = makeEngine(); + registerTrigger(element, engine, trigger('trig', [])); + expect(() => { registerTrigger(element, engine, trigger('trig', [])); - expect(() => { registerTrigger(element, engine, trigger('trig', [])); }).not.toThrow(); - }); + }).not.toThrow(); }); + }); - describe('property setting', () => { - it('should invoke a transition based on a property change', () => { - const engine = makeEngine(); - const trig = trigger('myTrigger', [ - transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) - ]); + describe('property setting', () => { + it('should invoke a transition based on a property change', () => { + const engine = makeEngine(); + const trig = trigger('myTrigger', [ + transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); - registerTrigger(element, engine, trig); - setProperty(element, engine, 'myTrigger', 'value'); - engine.flush(); - expect(engine.players.length).toEqual(1); + registerTrigger(element, engine, trig); + setProperty(element, engine, 'myTrigger', 'value'); + engine.flush(); + expect(engine.players.length).toEqual(1); - const player = MockAnimationDriver.log.pop() as MockAnimationPlayer; - expect(player.keyframes).toEqual([ - {height: '0px', offset: 0}, {height: '100px', offset: 1} - ]); - }); - - it('should not queue an animation if the property value has not changed at all', () => { - const engine = makeEngine(); + const player = MockAnimationDriver.log.pop() as MockAnimationPlayer; + expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]); + }); - const trig = trigger('myTrigger', [ - transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) - ]); + it('should not queue an animation if the property value has not changed at all', () => { + const engine = makeEngine(); - registerTrigger(element, engine, trig); - engine.flush(); - expect(engine.players.length).toEqual(0); + const trig = trigger('myTrigger', [ + transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); - setProperty(element, engine, 'myTrigger', 'abc'); - engine.flush(); - expect(engine.players.length).toEqual(1); + registerTrigger(element, engine, trig); + engine.flush(); + expect(engine.players.length).toEqual(0); - setProperty(element, engine, 'myTrigger', 'abc'); - engine.flush(); - expect(engine.players.length).toEqual(1); - }); + setProperty(element, engine, 'myTrigger', 'abc'); + engine.flush(); + expect(engine.players.length).toEqual(1); - it('should throw an error if an animation property without a matching trigger is changed', - () => { - const engine = makeEngine(); - expect(() => { - setProperty(element, engine, 'myTrigger', 'no'); - }).toThrowError(/The provided animation trigger "myTrigger" has not been registered!/); - }); + setProperty(element, engine, 'myTrigger', 'abc'); + engine.flush(); + expect(engine.players.length).toEqual(1); }); - describe('removal operations', () => { - it('should cleanup all inner state that\'s tied to an element once removed', () => { - const engine = makeEngine(); + it('should throw an error if an animation property without a matching trigger is changed', + () => { + const engine = makeEngine(); + expect(() => { + setProperty(element, engine, 'myTrigger', 'no'); + }).toThrowError(/The provided animation trigger "myTrigger" has not been registered!/); + }); + }); + + describe('removal operations', () => { + it('should cleanup all inner state that\'s tied to an element once removed', () => { + const engine = makeEngine(); - const trig = trigger('myTrigger', [ - transition(':leave', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) - ]); + const trig = trigger('myTrigger', [ + transition(':leave', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); - registerTrigger(element, engine, trig); - setProperty(element, engine, 'myTrigger', 'value'); - engine.flush(); + registerTrigger(element, engine, trig); + setProperty(element, engine, 'myTrigger', 'value'); + engine.flush(); - expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy(); + expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy(); - engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true); - engine.flush(); + engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true); + engine.flush(); - expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy(); - }); + expect(engine.elementContainsData(DEFAULT_NAMESPACE_ID, element)).toBeTruthy(); + }); - it('should create and recreate a namespace for a host element with the same component source', - () => { - const engine = makeEngine(); - - const trig = - trigger('myTrigger', [transition('* => *', animate(1234, style({color: 'red'})))]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, 'myTrigger', 'value'); - engine.flush(); - expect(((engine.players[0] as TransitionAnimationPlayer) - .getRealPlayer() as MockAnimationPlayer) - .duration) - .toEqual(1234); - - engine.destroy(DEFAULT_NAMESPACE_ID, null); - - registerTrigger(element, engine, trig); - setProperty(element, engine, 'myTrigger', 'value2'); - engine.flush(); - expect(((engine.players[0] as TransitionAnimationPlayer) - .getRealPlayer() as MockAnimationPlayer) - .duration) - .toEqual(1234); - }); - - it('should clear child node data when a parent node with leave transition is removed', () => { - const engine = makeEngine(); - const child = document.createElement('div'); - const parentTrigger = trigger('parent', [ - transition(':leave', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) - ]); - const childTrigger = trigger( - 'child', - [transition(':enter', [style({opacity: '0'}), animate(1000, style({opacity: '1'}))])]); - - registerTrigger(element, engine, parentTrigger); - registerTrigger(child, engine, childTrigger); - - element.appendChild(child); - engine.insertNode(DEFAULT_NAMESPACE_ID, child, element, true); - - setProperty(element, engine, 'parent', 'value'); - setProperty(child, engine, 'child', 'visible'); - engine.flush(); + it('should create and recreate a namespace for a host element with the same component source', + () => { + const engine = makeEngine(); + + const trig = + trigger('myTrigger', [transition('* => *', animate(1234, style({color: 'red'})))]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, 'myTrigger', 'value'); + engine.flush(); + expect(((engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as + MockAnimationPlayer) + .duration) + .toEqual(1234); + + engine.destroy(DEFAULT_NAMESPACE_ID, null); + + registerTrigger(element, engine, trig); + setProperty(element, engine, 'myTrigger', 'value2'); + engine.flush(); + expect(((engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as + MockAnimationPlayer) + .duration) + .toEqual(1234); + }); + + it('should clear child node data when a parent node with leave transition is removed', () => { + const engine = makeEngine(); + const child = document.createElement('div'); + const parentTrigger = trigger('parent', [ + transition(':leave', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); + const childTrigger = trigger( + 'child', + [transition(':enter', [style({opacity: '0'}), animate(1000, style({opacity: '1'}))])]); + + registerTrigger(element, engine, parentTrigger); + registerTrigger(child, engine, childTrigger); + + element.appendChild(child); + engine.insertNode(DEFAULT_NAMESPACE_ID, child, element, true); + + setProperty(element, engine, 'parent', 'value'); + setProperty(child, engine, 'child', 'visible'); + engine.flush(); + + expect(engine.statesByElement.has(element)).toBe(true, 'Expected parent data to be defined.'); + expect(engine.statesByElement.has(child)).toBe(true, 'Expected child data to be defined.'); + + engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true); + engine.flush(); + engine.players[0].finish(); + + expect(engine.statesByElement.has(element)) + .toBe(false, 'Expected parent data to be cleared.'); + expect(engine.statesByElement.has(child)).toBe(false, 'Expected child data to be cleared.'); + }); + }); - expect(engine.statesByElement.has(element)) - .toBe(true, 'Expected parent data to be defined.'); - expect(engine.statesByElement.has(child)).toBe(true, 'Expected child data to be defined.'); + describe('event listeners', () => { + it('should listen to the onStart operation for the animation', () => { + const engine = makeEngine(); - engine.removeNode(DEFAULT_NAMESPACE_ID, element, true, true); - engine.flush(); - engine.players[0].finish(); + const trig = trigger('myTrigger', [ + transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); - expect(engine.statesByElement.has(element)) - .toBe(false, 'Expected parent data to be cleared.'); - expect(engine.statesByElement.has(child)).toBe(false, 'Expected child data to be cleared.'); - }); + let count = 0; + registerTrigger(element, engine, trig); + listen(element, engine, 'myTrigger', 'start', () => count++); + setProperty(element, engine, 'myTrigger', 'value'); + expect(count).toEqual(0); + engine.flush(); + expect(count).toEqual(1); }); - describe('event listeners', () => { - it('should listen to the onStart operation for the animation', () => { - const engine = makeEngine(); + it('should listen to the onDone operation for the animation', () => { + const engine = makeEngine(); - const trig = trigger('myTrigger', [ - transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) - ]); + const trig = trigger('myTrigger', [ + transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); - let count = 0; - registerTrigger(element, engine, trig); - listen(element, engine, 'myTrigger', 'start', () => count++); - setProperty(element, engine, 'myTrigger', 'value'); - expect(count).toEqual(0); + let count = 0; + registerTrigger(element, engine, trig); + listen(element, engine, 'myTrigger', 'done', () => count++); + setProperty(element, engine, 'myTrigger', 'value'); + expect(count).toEqual(0); - engine.flush(); - expect(count).toEqual(1); - }); + engine.flush(); + expect(count).toEqual(0); - it('should listen to the onDone operation for the animation', () => { - const engine = makeEngine(); + engine.players[0].finish(); + expect(count).toEqual(1); + }); - const trig = trigger('myTrigger', [ - transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) - ]); + it('should throw an error when an event is listened to that isn\'t supported', () => { + const engine = makeEngine(); + const trig = trigger('myTrigger', []); + registerTrigger(element, engine, trig); - let count = 0; - registerTrigger(element, engine, trig); - listen(element, engine, 'myTrigger', 'done', () => count++); - setProperty(element, engine, 'myTrigger', 'value'); - expect(count).toEqual(0); + expect(() => { + listen(element, engine, 'myTrigger', 'explode', () => {}); + }) + .toThrowError( + /The provided animation trigger event "explode" for the animation trigger "myTrigger" is not supported!/); + }); - engine.flush(); - expect(count).toEqual(0); + it('should throw an error when an event is listened for a trigger that doesn\'t exist', () => { + const engine = makeEngine(); + expect(() => { + listen(element, engine, 'myTrigger', 'explode', () => {}); + }) + .toThrowError( + /Unable to listen on the animation trigger event "explode" because the animation trigger "myTrigger" doesn\'t exist!/); + }); - engine.players[0].finish(); - expect(count).toEqual(1); - }); + it('should throw an error when an undefined event is listened for', () => { + const engine = makeEngine(); + const trig = trigger('myTrigger', []); + registerTrigger(element, engine, trig); + expect(() => { + listen(element, engine, 'myTrigger', '', () => {}); + }) + .toThrowError( + /Unable to listen on the animation trigger "myTrigger" because the provided event is undefined!/); + }); - it('should throw an error when an event is listened to that isn\'t supported', () => { - const engine = makeEngine(); - const trig = trigger('myTrigger', []); - registerTrigger(element, engine, trig); + it('should retain event listeners and call them for successive animation state changes', () => { + const engine = makeEngine(); + const trig = trigger('myTrigger', [ + transition('* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); - expect(() => { listen(element, engine, 'myTrigger', 'explode', () => {}); }) - .toThrowError( - /The provided animation trigger event "explode" for the animation trigger "myTrigger" is not supported!/); - }); + registerTrigger(element, engine, trig); - it('should throw an error when an event is listened for a trigger that doesn\'t exist', () => { - const engine = makeEngine(); - expect(() => { listen(element, engine, 'myTrigger', 'explode', () => {}); }) - .toThrowError( - /Unable to listen on the animation trigger event "explode" because the animation trigger "myTrigger" doesn\'t exist!/); - }); + let count = 0; + listen(element, engine, 'myTrigger', 'start', () => count++); - it('should throw an error when an undefined event is listened for', () => { - const engine = makeEngine(); - const trig = trigger('myTrigger', []); - registerTrigger(element, engine, trig); - expect(() => { listen(element, engine, 'myTrigger', '', () => {}); }) - .toThrowError( - /Unable to listen on the animation trigger "myTrigger" because the provided event is undefined!/); - }); + setProperty(element, engine, 'myTrigger', '123'); + engine.flush(); + expect(count).toEqual(1); - it('should retain event listeners and call them for successive animation state changes', - () => { - const engine = makeEngine(); - const trig = trigger( - 'myTrigger', - [transition( - '* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))])]); - - registerTrigger(element, engine, trig); - - let count = 0; - listen(element, engine, 'myTrigger', 'start', () => count++); - - setProperty(element, engine, 'myTrigger', '123'); - engine.flush(); - expect(count).toEqual(1); - - setProperty(element, engine, 'myTrigger', '456'); - engine.flush(); - expect(count).toEqual(2); - }); - - it('should only fire event listener changes for when the corresponding trigger changes state', - () => { - const engine = makeEngine(); - const trig1 = trigger( - 'myTrigger1', - [transition( - '* => 123', [style({height: '0px'}), animate(1000, style({height: '100px'}))])]); - registerTrigger(element, engine, trig1); - - const trig2 = trigger( - 'myTrigger2', - [transition( - '* => 123', [style({width: '0px'}), animate(1000, style({width: '100px'}))])]); - registerTrigger(element, engine, trig2); - - let count = 0; - listen(element, engine, 'myTrigger1', 'start', () => count++); - - setProperty(element, engine, 'myTrigger1', '123'); - engine.flush(); - expect(count).toEqual(1); - - setProperty(element, engine, 'myTrigger2', '123'); - engine.flush(); - expect(count).toEqual(1); - }); - - it('should allow a listener to be deregistered, but only after a flush occurs', () => { - const engine = makeEngine(); - const trig = trigger( - 'myTrigger', - [transition( - '* => 123', [style({height: '0px'}), animate(1000, style({height: '100px'}))])]); - registerTrigger(element, engine, trig); - - let count = 0; - const deregisterFn = listen(element, engine, 'myTrigger', 'start', () => count++); - setProperty(element, engine, 'myTrigger', '123'); - engine.flush(); - expect(count).toEqual(1); + setProperty(element, engine, 'myTrigger', '456'); + engine.flush(); + expect(count).toEqual(2); + }); - deregisterFn(); - engine.flush(); + it('should only fire event listener changes for when the corresponding trigger changes state', + () => { + const engine = makeEngine(); + const trig1 = trigger('myTrigger1', [ + transition('* => 123', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); + registerTrigger(element, engine, trig1); + + const trig2 = trigger('myTrigger2', [ + transition('* => 123', [style({width: '0px'}), animate(1000, style({width: '100px'}))]) + ]); + registerTrigger(element, engine, trig2); + + let count = 0; + listen(element, engine, 'myTrigger1', 'start', () => count++); + + setProperty(element, engine, 'myTrigger1', '123'); + engine.flush(); + expect(count).toEqual(1); + + setProperty(element, engine, 'myTrigger2', '123'); + engine.flush(); + expect(count).toEqual(1); + }); + + it('should allow a listener to be deregistered, but only after a flush occurs', () => { + const engine = makeEngine(); + const trig = trigger('myTrigger', [ + transition('* => 123', [style({height: '0px'}), animate(1000, style({height: '100px'}))]) + ]); + registerTrigger(element, engine, trig); + + let count = 0; + const deregisterFn = listen(element, engine, 'myTrigger', 'start', () => count++); + setProperty(element, engine, 'myTrigger', '123'); + engine.flush(); + expect(count).toEqual(1); + + deregisterFn(); + engine.flush(); + + setProperty(element, engine, 'myTrigger', '456'); + engine.flush(); + expect(count).toEqual(1); + }); - setProperty(element, engine, 'myTrigger', '456'); - engine.flush(); - expect(count).toEqual(1); + it('should trigger a listener callback with an AnimationEvent argument', () => { + const engine = makeEngine(); + registerTrigger( + element, engine, trigger('myTrigger', [ + transition('* => *', [style({height: '0px'}), animate(1234, style({height: '100px'}))]) + ])); + + // we do this so that the next transition has a starting value that isn't null + setProperty(element, engine, 'myTrigger', '123'); + engine.flush(); + + let capture: AnimationEvent = null!; + listen(element, engine, 'myTrigger', 'start', e => capture = e); + listen(element, engine, 'myTrigger', 'done', e => capture = e); + setProperty(element, engine, 'myTrigger', '456'); + engine.flush(); + + delete (capture as any)['_data']; + expect(capture).toEqual({ + element, + triggerName: 'myTrigger', + phaseName: 'start', + fromState: '123', + toState: '456', + totalTime: 1234, + disabled: false }); - it('should trigger a listener callback with an AnimationEvent argument', () => { - const engine = makeEngine(); - registerTrigger( - element, engine, trigger('myTrigger', [ - transition( - '* => *', [style({height: '0px'}), animate(1234, style({height: '100px'}))]) - ])); - - // we do this so that the next transition has a starting value that isn't null - setProperty(element, engine, 'myTrigger', '123'); - engine.flush(); - - let capture: AnimationEvent = null !; - listen(element, engine, 'myTrigger', 'start', e => capture = e); - listen(element, engine, 'myTrigger', 'done', e => capture = e); - setProperty(element, engine, 'myTrigger', '456'); - engine.flush(); - - delete (capture as any)['_data']; - expect(capture).toEqual({ - element, - triggerName: 'myTrigger', - phaseName: 'start', - fromState: '123', - toState: '456', - totalTime: 1234, - disabled: false - }); - - capture = null !; - const player = engine.players.pop() !; - player.finish(); - - delete (capture as any)['_data']; - expect(capture).toEqual({ - element, - triggerName: 'myTrigger', - phaseName: 'done', - fromState: '123', - toState: '456', - totalTime: 1234, - disabled: false - }); + capture = null!; + const player = engine.players.pop()!; + player.finish(); + + delete (capture as any)['_data']; + expect(capture).toEqual({ + element, + triggerName: 'myTrigger', + phaseName: 'done', + fromState: '123', + toState: '456', + totalTime: 1234, + disabled: false }); }); + }); - describe('transition operations', () => { - it('should persist the styles on the element as actual styles once the animation is complete', - () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('on', style({height: '100px'})), state('off', style({height: '0px'})), - transition('on => off', animate(9876)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'on'); - setProperty(element, engine, trig.name, 'off'); - engine.flush(); - - expect(element.style.height).not.toEqual('0px'); - engine.players[0].finish(); - expect(element.style.height).toEqual('0px'); - }); - - it('should remove all existing state styling from an element when a follow-up transition occurs on the same trigger', - () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('a', style({height: '100px'})), state('b', style({height: '500px'})), - state('c', style({width: '200px'})), transition('* => *', animate(9876)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'a'); - setProperty(element, engine, trig.name, 'b'); - engine.flush(); - - const player1 = engine.players[0]; - player1.finish(); - expect(element.style.height).toEqual('500px'); - - setProperty(element, engine, trig.name, 'c'); - engine.flush(); - - const player2 = engine.players[0]; - expect(element.style.height).not.toEqual('500px'); - player2.finish(); - expect(element.style.width).toEqual('200px'); - expect(element.style.height).not.toEqual('500px'); - }); - - it('should allow two animation transitions with different triggers to animate in parallel', - () => { - const engine = makeEngine(); - const trig1 = trigger('something1', [ - state('a', style({width: '100px'})), state('b', style({width: '200px'})), - transition('* => *', animate(1000)) - ]); - - const trig2 = trigger('something2', [ - state('x', style({height: '500px'})), state('y', style({height: '1000px'})), - transition('* => *', animate(2000)) - ]); - - registerTrigger(element, engine, trig1); - registerTrigger(element, engine, trig2); - - let doneCount = 0; - function doneCallback() { doneCount++; } - - setProperty(element, engine, trig1.name, 'a'); - setProperty(element, engine, trig1.name, 'b'); - setProperty(element, engine, trig2.name, 'x'); - setProperty(element, engine, trig2.name, 'y'); - engine.flush(); - - const player1 = engine.players[0] !; - player1.onDone(doneCallback); - expect(doneCount).toEqual(0); - - const player2 = engine.players[1] !; - player2.onDone(doneCallback); - expect(doneCount).toEqual(0); - - player1.finish(); - expect(doneCount).toEqual(1); - - player2.finish(); - expect(doneCount).toEqual(2); - - expect(element.style.width).toEqual('200px'); - expect(element.style.height).toEqual('1000px'); - }); - - it('should cancel a previously running animation when a follow-up transition kicks off on the same trigger', - () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('x', style({opacity: 0})), - state('y', style({opacity: .5})), - state('z', style({opacity: 1})), - transition('* => *', animate(1000)), - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'x'); - setProperty(element, engine, trig.name, 'y'); - engine.flush(); - - expect(parseFloat(element.style.opacity)).not.toEqual(.5); - - const player1 = engine.players[0]; - setProperty(element, engine, trig.name, 'z'); - engine.flush(); - - const player2 = engine.players[0]; - - expect(parseFloat(element.style.opacity)).not.toEqual(.5); - - player2.finish(); - expect(parseFloat(element.style.opacity)).toEqual(1); - - player1.finish(); - expect(parseFloat(element.style.opacity)).toEqual(1); - }); - - it('should pass in the previously running players into the follow-up transition player when cancelled', - () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('x', style({opacity: 0})), state('y', style({opacity: .5})), - state('z', style({opacity: 1})), transition('* => *', animate(1000)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'x'); - setProperty(element, engine, trig.name, 'y'); - engine.flush(); - - const player1 = MockAnimationDriver.log.pop() !as MockAnimationPlayer; - player1.setPosition(0.5); - - setProperty(element, engine, trig.name, 'z'); - engine.flush(); - - const player2 = MockAnimationDriver.log.pop() !as MockAnimationPlayer; - expect(player2.previousPlayers).toEqual([player1]); - player2.finish(); - - setProperty(element, engine, trig.name, 'x'); - engine.flush(); - - const player3 = MockAnimationDriver.log.pop() !as MockAnimationPlayer; - expect(player3.previousPlayers).toEqual([]); - }); - - it('should cancel all existing players if a removal animation is set to occur', () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('m', style({opacity: 0})), state('n', style({opacity: 1})), - transition('* => *', animate(1000)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'm'); - setProperty(element, engine, trig.name, 'n'); - engine.flush(); + describe('transition operations', () => { + it('should persist the styles on the element as actual styles once the animation is complete', + () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('on', style({height: '100px'})), state('off', style({height: '0px'})), + transition('on => off', animate(9876)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'on'); + setProperty(element, engine, trig.name, 'off'); + engine.flush(); + + expect(element.style.height).not.toEqual('0px'); + engine.players[0].finish(); + expect(element.style.height).toEqual('0px'); + }); + + it('should remove all existing state styling from an element when a follow-up transition occurs on the same trigger', + () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('a', style({height: '100px'})), state('b', style({height: '500px'})), + state('c', style({width: '200px'})), transition('* => *', animate(9876)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'a'); + setProperty(element, engine, trig.name, 'b'); + engine.flush(); + + const player1 = engine.players[0]; + player1.finish(); + expect(element.style.height).toEqual('500px'); + + setProperty(element, engine, trig.name, 'c'); + engine.flush(); + + const player2 = engine.players[0]; + expect(element.style.height).not.toEqual('500px'); + player2.finish(); + expect(element.style.width).toEqual('200px'); + expect(element.style.height).not.toEqual('500px'); + }); + + it('should allow two animation transitions with different triggers to animate in parallel', + () => { + const engine = makeEngine(); + const trig1 = trigger('something1', [ + state('a', style({width: '100px'})), state('b', style({width: '200px'})), + transition('* => *', animate(1000)) + ]); + + const trig2 = trigger('something2', [ + state('x', style({height: '500px'})), state('y', style({height: '1000px'})), + transition('* => *', animate(2000)) + ]); + + registerTrigger(element, engine, trig1); + registerTrigger(element, engine, trig2); + + let doneCount = 0; + function doneCallback() { + doneCount++; + } + + setProperty(element, engine, trig1.name, 'a'); + setProperty(element, engine, trig1.name, 'b'); + setProperty(element, engine, trig2.name, 'x'); + setProperty(element, engine, trig2.name, 'y'); + engine.flush(); + + const player1 = engine.players[0]!; + player1.onDone(doneCallback); + expect(doneCount).toEqual(0); + + const player2 = engine.players[1]!; + player2.onDone(doneCallback); + expect(doneCount).toEqual(0); + + player1.finish(); + expect(doneCount).toEqual(1); + + player2.finish(); + expect(doneCount).toEqual(2); + + expect(element.style.width).toEqual('200px'); + expect(element.style.height).toEqual('1000px'); + }); + + it('should cancel a previously running animation when a follow-up transition kicks off on the same trigger', + () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('x', style({opacity: 0})), + state('y', style({opacity: .5})), + state('z', style({opacity: 1})), + transition('* => *', animate(1000)), + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'x'); + setProperty(element, engine, trig.name, 'y'); + engine.flush(); + + expect(parseFloat(element.style.opacity)).not.toEqual(.5); + + const player1 = engine.players[0]; + setProperty(element, engine, trig.name, 'z'); + engine.flush(); + + const player2 = engine.players[0]; + + expect(parseFloat(element.style.opacity)).not.toEqual(.5); + + player2.finish(); + expect(parseFloat(element.style.opacity)).toEqual(1); + + player1.finish(); + expect(parseFloat(element.style.opacity)).toEqual(1); + }); + + it('should pass in the previously running players into the follow-up transition player when cancelled', + () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('x', style({opacity: 0})), state('y', style({opacity: .5})), + state('z', style({opacity: 1})), transition('* => *', animate(1000)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'x'); + setProperty(element, engine, trig.name, 'y'); + engine.flush(); + + const player1 = MockAnimationDriver.log.pop()! as MockAnimationPlayer; + player1.setPosition(0.5); + + setProperty(element, engine, trig.name, 'z'); + engine.flush(); + + const player2 = MockAnimationDriver.log.pop()! as MockAnimationPlayer; + expect(player2.previousPlayers).toEqual([player1]); + player2.finish(); + + setProperty(element, engine, trig.name, 'x'); + engine.flush(); + + const player3 = MockAnimationDriver.log.pop()! as MockAnimationPlayer; + expect(player3.previousPlayers).toEqual([]); + }); - let doneCount = 0; - function doneCallback() { doneCount++; } + it('should cancel all existing players if a removal animation is set to occur', () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('m', style({opacity: 0})), state('n', style({opacity: 1})), + transition('* => *', animate(1000)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'm'); + setProperty(element, engine, trig.name, 'n'); + engine.flush(); - const player1 = engine.players[0]; - player1.onDone(doneCallback); + let doneCount = 0; + function doneCallback() { + doneCount++; + } - expect(doneCount).toEqual(0); + const player1 = engine.players[0]; + player1.onDone(doneCallback); - setProperty(element, engine, trig.name, 'void'); - engine.flush(); + expect(doneCount).toEqual(0); - expect(doneCount).toEqual(1); - }); - - it('should only persist styles that exist in the final state styles and not the last keyframe', - () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('0', style({width: '0px'})), state('1', style({width: '100px'})), - transition('* => *', [animate(1000, style({height: '200px'}))]) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, '0'); - setProperty(element, engine, trig.name, '1'); - engine.flush(); - - const player = engine.players[0] !; - expect(element.style.width).not.toEqual('100px'); - - player.finish(); - expect(element.style.height).not.toEqual('200px'); - expect(element.style.width).toEqual('100px'); - }); - - it('should default to using styling from the `*` state if a matching state is not found', - () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('a', style({opacity: 0})), state('*', style({opacity: .5})), - transition('* => *', animate(1000)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'a'); - setProperty(element, engine, trig.name, 'z'); - engine.flush(); - - engine.players[0].finish(); - expect(parseFloat(element.style.opacity)).toEqual(.5); - }); - - it('should treat `void` as `void`', () => { - const engine = makeEngine(); - const trig = trigger('something', [ - state('a', style({opacity: 0})), state('void', style({opacity: .8})), - transition('* => *', animate(1000)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'a'); - setProperty(element, engine, trig.name, 'void'); - engine.flush(); + setProperty(element, engine, trig.name, 'void'); + engine.flush(); - engine.players[0].finish(); - expect(parseFloat(element.style.opacity)).toEqual(.8); - }); + expect(doneCount).toEqual(1); }); - describe('style normalizer', () => { - it('should normalize the style values that are animateTransitioned within an a transition animation', - () => { - const engine = makeEngine(new SuffixNormalizer('-normalized')); - - const trig = trigger('something', [ - state('on', style({height: 100})), state('off', style({height: 0})), - transition('on => off', animate(9876)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'on'); - setProperty(element, engine, trig.name, 'off'); - engine.flush(); - - const player = MockAnimationDriver.log.pop() as MockAnimationPlayer; - expect(player.keyframes).toEqual([ - {'height-normalized': '100-normalized', offset: 0}, - {'height-normalized': '0-normalized', offset: 1} - ]); - }); - - it('should throw an error when normalization fails within a transition animation', () => { - const engine = makeEngine(new ExactCssValueNormalizer({left: '100px'})); - - const trig = trigger('something', [ - state('a', style({left: '0px', width: '200px'})), - state('b', style({left: '100px', width: '100px'})), transition('a => b', animate(9876)) - ]); - - registerTrigger(element, engine, trig); - setProperty(element, engine, trig.name, 'a'); - setProperty(element, engine, trig.name, 'b'); - - let errorMessage = ''; - try { - engine.flush(); - } catch (e) { - errorMessage = e.toString(); - } - - expect(errorMessage).toMatch(/Unable to animate due to the following errors:/); - expect(errorMessage).toMatch(/- The CSS property `left` is not allowed to be `0px`/); - expect(errorMessage).toMatch(/- The CSS property `width` is not allowed/); - }); + it('should only persist styles that exist in the final state styles and not the last keyframe', + () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('0', style({width: '0px'})), state('1', style({width: '100px'})), + transition('* => *', [animate(1000, style({height: '200px'}))]) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, '0'); + setProperty(element, engine, trig.name, '1'); + engine.flush(); + + const player = engine.players[0]!; + expect(element.style.width).not.toEqual('100px'); + + player.finish(); + expect(element.style.height).not.toEqual('200px'); + expect(element.style.width).toEqual('100px'); + }); + + it('should default to using styling from the `*` state if a matching state is not found', + () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('a', style({opacity: 0})), state('*', style({opacity: .5})), + transition('* => *', animate(1000)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'a'); + setProperty(element, engine, trig.name, 'z'); + engine.flush(); + + engine.players[0].finish(); + expect(parseFloat(element.style.opacity)).toEqual(.5); + }); + + it('should treat `void` as `void`', () => { + const engine = makeEngine(); + const trig = trigger('something', [ + state('a', style({opacity: 0})), state('void', style({opacity: .8})), + transition('* => *', animate(1000)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'a'); + setProperty(element, engine, trig.name, 'void'); + engine.flush(); + + engine.players[0].finish(); + expect(parseFloat(element.style.opacity)).toEqual(.8); }); + }); + + describe('style normalizer', () => { + it('should normalize the style values that are animateTransitioned within an a transition animation', + () => { + const engine = makeEngine(new SuffixNormalizer('-normalized')); + + const trig = trigger('something', [ + state('on', style({height: 100})), state('off', style({height: 0})), + transition('on => off', animate(9876)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'on'); + setProperty(element, engine, trig.name, 'off'); + engine.flush(); + + const player = MockAnimationDriver.log.pop() as MockAnimationPlayer; + expect(player.keyframes).toEqual([ + {'height-normalized': '100-normalized', offset: 0}, + {'height-normalized': '0-normalized', offset: 1} + ]); + }); + + it('should throw an error when normalization fails within a transition animation', () => { + const engine = makeEngine(new ExactCssValueNormalizer({left: '100px'})); + + const trig = trigger('something', [ + state('a', style({left: '0px', width: '200px'})), + state('b', style({left: '100px', width: '100px'})), transition('a => b', animate(9876)) + ]); + + registerTrigger(element, engine, trig); + setProperty(element, engine, trig.name, 'a'); + setProperty(element, engine, trig.name, 'b'); + + let errorMessage = ''; + try { + engine.flush(); + } catch (e) { + errorMessage = e.toString(); + } - describe('view operations', () => { - it('should perform insert operations immediately ', () => { - const engine = makeEngine(); + expect(errorMessage).toMatch(/Unable to animate due to the following errors:/); + expect(errorMessage).toMatch(/- The CSS property `left` is not allowed to be `0px`/); + expect(errorMessage).toMatch(/- The CSS property `width` is not allowed/); + }); + }); - const child1 = document.createElement('div'); - const child2 = document.createElement('div'); - element.appendChild(child1); - element.appendChild(child2); + describe('view operations', () => { + it('should perform insert operations immediately ', () => { + const engine = makeEngine(); - element.appendChild(child1); - engine.insertNode(DEFAULT_NAMESPACE_ID, child1, element, true); - element.appendChild(child2); - engine.insertNode(DEFAULT_NAMESPACE_ID, child2, element, true); + const child1 = document.createElement('div'); + const child2 = document.createElement('div'); + element.appendChild(child1); + element.appendChild(child2); - expect(element.contains(child1)).toBe(true); - expect(element.contains(child2)).toBe(true); - }); + element.appendChild(child1); + engine.insertNode(DEFAULT_NAMESPACE_ID, child1, element, true); + element.appendChild(child2); + engine.insertNode(DEFAULT_NAMESPACE_ID, child2, element, true); - it('should not throw an error if a missing namespace is used', () => { - const engine = makeEngine(); - const ID = 'foo'; - const TRIGGER = 'fooTrigger'; - expect(() => { engine.trigger(ID, element, TRIGGER, 'something'); }).not.toThrow(); - }); + expect(element.contains(child1)).toBe(true); + expect(element.contains(child2)).toBe(true); + }); - it('should still apply state-styling to an element even if it is not yet inserted into the DOM', - () => { - const engine = makeEngine(); - const orphanElement = document.createElement('div'); - orphanElement.classList.add('orphan'); - - registerTrigger( - orphanElement, engine, trigger('trig', [ - state('go', style({opacity: 0.5})), transition('* => go', animate(1000)) - ])); - - setProperty(orphanElement, engine, 'trig', 'go'); - engine.flush(); - expect(engine.players.length).toEqual(0); - expect(orphanElement.style.opacity).toEqual('0.5'); - }); + it('should not throw an error if a missing namespace is used', () => { + const engine = makeEngine(); + const ID = 'foo'; + const TRIGGER = 'fooTrigger'; + expect(() => { + engine.trigger(ID, element, TRIGGER, 'something'); + }).not.toThrow(); }); + + it('should still apply state-styling to an element even if it is not yet inserted into the DOM', + () => { + const engine = makeEngine(); + const orphanElement = document.createElement('div'); + orphanElement.classList.add('orphan'); + + registerTrigger(orphanElement, engine, trigger('trig', [ + state('go', style({opacity: 0.5})), transition('* => go', animate(1000)) + ])); + + setProperty(orphanElement, engine, 'trig', 'go'); + engine.flush(); + expect(engine.players.length).toEqual(0); + expect(orphanElement.style.opacity).toEqual('0.5'); + }); }); +}); })(); class SuffixNormalizer extends AnimationStyleNormalizer { - constructor(private _suffix: string) { super(); } + constructor(private _suffix: string) { + super(); + } normalizePropertyName(propertyName: string, errors: string[]): string { return propertyName + this._suffix; @@ -698,7 +705,9 @@ class SuffixNormalizer extends AnimationStyleNormalizer { } class ExactCssValueNormalizer extends AnimationStyleNormalizer { - constructor(private _allowedValues: {[propName: string]: any}) { super(); } + constructor(private _allowedValues: {[propName: string]: any}) { + super(); + } normalizePropertyName(propertyName: string, errors: string[]): string { if (!this._allowedValues[propertyName]) { diff --git a/packages/animations/browser/test/render/web_animations/web_animations_player_spec.ts b/packages/animations/browser/test/render/web_animations/web_animations_player_spec.ts index c8e44bc11ca83..cbcdceda78f63 100644 --- a/packages/animations/browser/test/render/web_animations/web_animations_player_spec.ts +++ b/packages/animations/browser/test/render/web_animations/web_animations_player_spec.ts @@ -13,7 +13,9 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat let innerPlayer: MockDomAnimation|null = null; beforeEach(() => { element = {}; - element['animate'] = () => { return innerPlayer = new MockDomAnimation(); }; + element['animate'] = () => { + return innerPlayer = new MockDomAnimation(); + }; }); describe('WebAnimationsPlayer tests', () => { @@ -26,7 +28,7 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat const player = new WebAnimationsPlayer(element, keyframes, {duration: 1000}); player.init(); - const p = innerPlayer !; + const p = innerPlayer!; expect(p.log).toEqual(['pause']); player.play(); @@ -42,7 +44,7 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat const player = new WebAnimationsPlayer(element, keyframes, {duration: 1000}); player.play(); - const p = innerPlayer !; + const p = innerPlayer!; expect(p.log).toEqual(['play']); }); @@ -70,10 +72,18 @@ import {WebAnimationsPlayer} from '../../../src/render/web_animations/web_animat class MockDomAnimation implements DOMAnimation { log: string[] = []; - cancel(): void { this.log.push('cancel'); } - play(): void { this.log.push('play'); } - pause(): void { this.log.push('pause'); } - finish(): void { this.log.push('finish'); } + cancel(): void { + this.log.push('cancel'); + } + play(): void { + this.log.push('play'); + } + pause(): void { + this.log.push('pause'); + } + finish(): void { + this.log.push('finish'); + } onfinish: Function = () => {}; position: number = 0; currentTime: number = 0; diff --git a/packages/animations/browser/test/shared.ts b/packages/animations/browser/test/shared.ts index 12904ef157232..f89b4ddf79341 100644 --- a/packages/animations/browser/test/shared.ts +++ b/packages/animations/browser/test/shared.ts @@ -21,8 +21,8 @@ export function makeTrigger( const triggerAst = buildAnimationAst(driver, triggerData, errors) as TriggerAst; if (!skipErrors && errors.length) { const LINE_START = '\n - '; - throw new Error( - `Animation parsing for the ${name} trigger have failed:${LINE_START}${errors.join(LINE_START)}`); + throw new Error(`Animation parsing for the ${name} trigger have failed:${LINE_START}${ + errors.join(LINE_START)}`); } return buildTrigger(name, triggerAst); } diff --git a/packages/animations/browser/testing/src/mock_animation_driver.ts b/packages/animations/browser/testing/src/mock_animation_driver.ts index 367d9e4a0128f..d21fc192d3e40 100644 --- a/packages/animations/browser/testing/src/mock_animation_driver.ts +++ b/packages/animations/browser/testing/src/mock_animation_driver.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationPlayer, NoopAnimationPlayer, ɵStyleData} from '@angular/animations'; +import {AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵStyleData} from '@angular/animations'; import {AnimationDriver, ɵallowPreviousPlayerStylesMerge as allowPreviousPlayerStylesMerge, ɵcontainsElement as containsElement, ɵinvokeQuery as invokeQuery, ɵmatchesElement as matchesElement, ɵvalidateStyleProperty as validateStyleProperty} from '@angular/animations/browser'; @@ -15,13 +15,17 @@ import {AnimationDriver, ɵallowPreviousPlayerStylesMerge as allowPreviousPlayer export class MockAnimationDriver implements AnimationDriver { static log: AnimationPlayer[] = []; - validateStyleProperty(prop: string): boolean { return validateStyleProperty(prop); } + validateStyleProperty(prop: string): boolean { + return validateStyleProperty(prop); + } matchesElement(element: any, selector: string): boolean { return matchesElement(element, selector); } - containsElement(elm1: any, elm2: any): boolean { return containsElement(elm1, elm2); } + containsElement(elm1: any, elm2: any): boolean { + return containsElement(elm1, elm2); + } query(element: any, selector: string, multi: boolean): any[] { return invokeQuery(element, selector, multi); @@ -32,7 +36,7 @@ export class MockAnimationDriver implements AnimationDriver { } animate( - element: any, keyframes: {[key: string]: string | number}[], duration: number, delay: number, + element: any, keyframes: {[key: string]: string|number}[], duration: number, delay: number, easing: string, previousPlayers: any[] = []): MockAnimationPlayer { const player = new MockAnimationPlayer(element, keyframes, duration, delay, easing, previousPlayers); @@ -47,12 +51,12 @@ export class MockAnimationDriver implements AnimationDriver { export class MockAnimationPlayer extends NoopAnimationPlayer { private __finished = false; private __started = false; - public previousStyles: {[key: string]: string | number} = {}; + public previousStyles: {[key: string]: string|number} = {}; private _onInitFns: (() => any)[] = []; public currentSnapshot: ɵStyleData = {}; constructor( - public element: any, public keyframes: {[key: string]: string | number}[], + public element: any, public keyframes: {[key: string]: string|number}[], public duration: number, public delay: number, public easing: string, public previousPlayers: any[]) { super(duration, delay); @@ -68,7 +72,9 @@ export class MockAnimationPlayer extends NoopAnimationPlayer { } /* @internal */ - onInit(fn: () => any) { this._onInitFns.push(fn); } + onInit(fn: () => any) { + this._onInitFns.push(fn); + } /* @internal */ init() { @@ -95,7 +101,9 @@ export class MockAnimationPlayer extends NoopAnimationPlayer { this.__started = true; } - hasStarted() { return this.__started; } + hasStarted() { + return this.__started; + } beforeDestroy() { const captures: ɵStyleData = {}; diff --git a/packages/animations/src/animation_metadata.ts b/packages/animations/src/animation_metadata.ts index 89492cf68845e..079744bf7391f 100755 --- a/packages/animations/src/animation_metadata.ts +++ b/packages/animations/src/animation_metadata.ts @@ -9,7 +9,9 @@ /** * Represents a set of CSS styles for use in an animation style. */ -export interface ɵStyleData { [key: string]: string|number; } +export interface ɵStyleData { + [key: string]: string|number; +} /** * Represents animation-step timing parameters for an animation step. @@ -67,10 +69,10 @@ export declare interface AnimationOptions { */ delay?: number|string; /** - * A set of developer-defined parameters that modify styling and timing - * when an animation action starts. An array of key-value pairs, where the provided value - * is used as a default. - */ + * A set of developer-defined parameters that modify styling and timing + * when an animation action starts. An array of key-value pairs, where the provided value + * is used as a default. + */ params?: {[name: string]: any}; } @@ -81,7 +83,9 @@ export declare interface AnimationOptions { * * @publicApi */ -export declare interface AnimateChildOptions extends AnimationOptions { duration?: number|string; } +export declare interface AnimateChildOptions extends AnimationOptions { + duration?: number|string; +} /** * @description Constants for the categories of parameters that can be defined for animations. @@ -171,7 +175,9 @@ export const AUTO_STYLE = '*'; * * @publicApi */ -export interface AnimationMetadata { type: AnimationMetadataType; } +export interface AnimationMetadata { + type: AnimationMetadataType; +} /** * Contains an animation trigger. Instantiated and returned by the @@ -181,8 +187,8 @@ export interface AnimationMetadata { type: AnimationMetadataType; } */ export interface AnimationTriggerMetadata extends AnimationMetadata { /** - * The trigger name, used to associate it with an element. Unique within the component. - */ + * The trigger name, used to associate it with an element. Unique within the component. + */ name: string; /** * An animation definition object, containing an array of state and transition declarations. @@ -654,8 +660,9 @@ export function trigger(name: string, definitions: AnimationMetadata[]): Animati * @publicApi */ export function animate( - timings: string | number, styles: AnimationStyleMetadata | AnimationKeyframesSequenceMetadata | - null = null): AnimationAnimateMetadata { + timings: string|number, + styles: AnimationStyleMetadata|AnimationKeyframesSequenceMetadata|null = + null): AnimationAnimateMetadata { return {type: AnimationMetadataType.Animate, styles, timings}; } @@ -693,7 +700,7 @@ export function animate( * @publicApi */ export function group( - steps: AnimationMetadata[], options: AnimationOptions | null = null): AnimationGroupMetadata { + steps: AnimationMetadata[], options: AnimationOptions|null = null): AnimationGroupMetadata { return {type: AnimationMetadataType.Group, steps, options}; } @@ -721,7 +728,8 @@ export function group( * @usageNotes * When you pass an array of steps to a * `transition()` call, the steps run sequentially by default. - * Compare this to the `{@link animations/group group()}` call, which runs animation steps in parallel. + * Compare this to the `{@link animations/group group()}` call, which runs animation steps in + *parallel. * * When a sequence is used within a `{@link animations/group group()}` or a `transition()` call, * execution continues to the next instruction only after each of the inner animation @@ -729,8 +737,8 @@ export function group( * * @publicApi **/ -export function sequence(steps: AnimationMetadata[], options: AnimationOptions | null = null): - AnimationSequenceMetadata { +export function sequence( + steps: AnimationMetadata[], options: AnimationOptions|null = null): AnimationSequenceMetadata { return {type: AnimationMetadataType.Sequence, steps, options}; } @@ -773,9 +781,8 @@ export function sequence(steps: AnimationMetadata[], options: AnimationOptions | * * @publicApi **/ -export function style( - tokens: '*' | {[key: string]: string | number} | - Array<'*'|{[key: string]: string | number}>): AnimationStyleMetadata { +export function style(tokens: '*'|{[key: string]: string | number}| + Array<'*'|{[key: string]: string | number}>): AnimationStyleMetadata { return {type: AnimationMetadataType.Style, styles: tokens, offset: null}; } @@ -1032,10 +1039,10 @@ export function keyframes(steps: AnimationStyleMetadata[]): AnimationKeyframesSe * @publicApi **/ export function transition( - stateChangeExpr: string | ((fromState: string, toState: string, element?: any, - params?: {[key: string]: any}) => boolean), - steps: AnimationMetadata | AnimationMetadata[], - options: AnimationOptions | null = null): AnimationTransitionMetadata { + stateChangeExpr: string| + ((fromState: string, toState: string, element?: any, params?: {[key: string]: any}) => boolean), + steps: AnimationMetadata|AnimationMetadata[], + options: AnimationOptions|null = null): AnimationTransitionMetadata { return {type: AnimationMetadataType.Transition, expr: stateChangeExpr, animation: steps, options}; } @@ -1085,8 +1092,8 @@ export function transition( * @publicApi */ export function animation( - steps: AnimationMetadata | AnimationMetadata[], - options: AnimationOptions | null = null): AnimationReferenceMetadata { + steps: AnimationMetadata|AnimationMetadata[], + options: AnimationOptions|null = null): AnimationReferenceMetadata { return {type: AnimationMetadataType.Reference, animation: steps, options}; } @@ -1109,7 +1116,7 @@ export function animation( * * @publicApi */ -export function animateChild(options: AnimateChildOptions | null = null): +export function animateChild(options: AnimateChildOptions|null = null): AnimationAnimateChildMetadata { return {type: AnimationMetadataType.AnimateChild, options}; } @@ -1126,7 +1133,7 @@ export function animateChild(options: AnimateChildOptions | null = null): */ export function useAnimation( animation: AnimationReferenceMetadata, - options: AnimationOptions | null = null): AnimationAnimateRefMetadata { + options: AnimationOptions|null = null): AnimationAnimateRefMetadata { return {type: AnimationMetadataType.AnimateRef, animation, options}; } @@ -1179,7 +1186,7 @@ export function useAnimation( * ### Usage Example * * The following example queries for inner elements and animates them - * individually using `animate()`. + * individually using `animate()`. * * ```typescript * @Component({ @@ -1218,8 +1225,8 @@ export function useAnimation( * @publicApi */ export function query( - selector: string, animation: AnimationMetadata | AnimationMetadata[], - options: AnimationQueryOptions | null = null): AnimationQueryMetadata { + selector: string, animation: AnimationMetadata|AnimationMetadata[], + options: AnimationQueryOptions|null = null): AnimationQueryMetadata { return {type: AnimationMetadataType.Query, selector, animation, options}; } @@ -1303,8 +1310,7 @@ export function query( * * @publicApi */ -export function stagger( - timings: string | number, - animation: AnimationMetadata | AnimationMetadata[]): AnimationStaggerMetadata { +export function stagger(timings: string|number, animation: AnimationMetadata|AnimationMetadata[]): + AnimationStaggerMetadata { return {type: AnimationMetadataType.Stagger, timings, animation}; } diff --git a/packages/animations/src/animations.ts b/packages/animations/src/animations.ts index 7f8acfadc9c2d..66482a0d79fc1 100644 --- a/packages/animations/src/animations.ts +++ b/packages/animations/src/animations.ts @@ -13,7 +13,7 @@ */ export {AnimationBuilder, AnimationFactory} from './animation_builder'; export {AnimationEvent} from './animation_event'; -export {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, animate, animateChild, animation, group, keyframes, query, sequence, stagger, state, style, transition, trigger, useAnimation, ɵStyleData} from './animation_metadata'; +export {animate, animateChild, AnimateChildOptions, AnimateTimings, animation, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, AUTO_STYLE, group, keyframes, query, sequence, stagger, state, style, transition, trigger, useAnimation, ɵStyleData} from './animation_metadata'; export {AnimationPlayer, NoopAnimationPlayer} from './players/animation_player'; export * from './private_export'; diff --git a/packages/animations/src/players/animation_group_player.ts b/packages/animations/src/players/animation_group_player.ts index c1f6a40c23aba..79f6611735411 100644 --- a/packages/animations/src/players/animation_group_player.ts +++ b/packages/animations/src/players/animation_group_player.ts @@ -69,9 +69,13 @@ export class AnimationGroupPlayer implements AnimationPlayer { } } - init(): void { this.players.forEach(player => player.init()); } + init(): void { + this.players.forEach(player => player.init()); + } - onStart(fn: () => void): void { this._onStartFns.push(fn); } + onStart(fn: () => void): void { + this._onStartFns.push(fn); + } private _onStart() { if (!this.hasStarted()) { @@ -81,11 +85,17 @@ export class AnimationGroupPlayer implements AnimationPlayer { } } - onDone(fn: () => void): void { this._onDoneFns.push(fn); } + onDone(fn: () => void): void { + this._onDoneFns.push(fn); + } - onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); } + onDestroy(fn: () => void): void { + this._onDestroyFns.push(fn); + } - hasStarted() { return this._started; } + hasStarted() { + return this._started; + } play() { if (!this.parentPlayer) { @@ -95,16 +105,22 @@ export class AnimationGroupPlayer implements AnimationPlayer { this.players.forEach(player => player.play()); } - pause(): void { this.players.forEach(player => player.pause()); } + pause(): void { + this.players.forEach(player => player.pause()); + } - restart(): void { this.players.forEach(player => player.restart()); } + restart(): void { + this.players.forEach(player => player.restart()); + } finish(): void { this._onFinish(); this.players.forEach(player => player.finish()); } - destroy(): void { this._onDestroy(); } + destroy(): void { + this._onDestroy(); + } private _onDestroy() { if (!this._destroyed) { diff --git a/packages/animations/src/players/animation_player.ts b/packages/animations/src/players/animation_player.ts index 3a183db7c2012..6ec35d6b81c39 100644 --- a/packages/animations/src/players/animation_player.ts +++ b/packages/animations/src/players/animation_player.ts @@ -94,11 +94,13 @@ export interface AnimationPlayer { * Provides a callback to invoke before the animation is destroyed. */ beforeDestroy?: () => any; - /** @internal + /** + * @internal * Internal */ triggerCallback?: (phaseName: string) => void; - /** @internal + /** + * @internal * Internal */ disabled?: boolean; @@ -124,7 +126,9 @@ export class NoopAnimationPlayer implements AnimationPlayer { private _finished = false; public parentPlayer: AnimationPlayer|null = null; public readonly totalTime: number; - constructor(duration: number = 0, delay: number = 0) { this.totalTime = duration + delay; } + constructor(duration: number = 0, delay: number = 0) { + this.totalTime = duration + delay; + } private _onFinish() { if (!this._finished) { this._finished = true; @@ -132,10 +136,18 @@ export class NoopAnimationPlayer implements AnimationPlayer { this._onDoneFns = []; } } - onStart(fn: () => void): void { this._onStartFns.push(fn); } - onDone(fn: () => void): void { this._onDoneFns.push(fn); } - onDestroy(fn: () => void): void { this._onDestroyFns.push(fn); } - hasStarted(): boolean { return this._started; } + onStart(fn: () => void): void { + this._onStartFns.push(fn); + } + onDone(fn: () => void): void { + this._onDoneFns.push(fn); + } + onDestroy(fn: () => void): void { + this._onDestroyFns.push(fn); + } + hasStarted(): boolean { + return this._started; + } init(): void {} play(): void { if (!this.hasStarted()) { @@ -146,7 +158,9 @@ export class NoopAnimationPlayer implements AnimationPlayer { } /** @internal */ - triggerMicrotask() { scheduleMicroTask(() => this._onFinish()); } + triggerMicrotask() { + scheduleMicroTask(() => this._onFinish()); + } private _onStart() { this._onStartFns.forEach(fn => fn()); @@ -155,7 +169,9 @@ export class NoopAnimationPlayer implements AnimationPlayer { pause(): void {} restart(): void {} - finish(): void { this._onFinish(); } + finish(): void { + this._onFinish(); + } destroy(): void { if (!this._destroyed) { this._destroyed = true; @@ -169,7 +185,9 @@ export class NoopAnimationPlayer implements AnimationPlayer { } reset(): void {} setPosition(position: number): void {} - getPosition(): number { return 0; } + getPosition(): number { + return 0; + } /** @internal */ triggerCallback(phaseName: string): void { diff --git a/packages/animations/test/animation_player_spec.ts b/packages/animations/test/animation_player_spec.ts index 7ad7152d6018f..2bf205fcbb9cc 100644 --- a/packages/animations/test/animation_player_spec.ts +++ b/packages/animations/test/animation_player_spec.ts @@ -69,7 +69,9 @@ import {scheduleMicroTask} from '../src/util'; const log: string[] = []; const player = new NoopAnimationPlayer(); - player.onStart(() => { scheduleMicroTask(() => log.push('started')); }); + player.onStart(() => { + scheduleMicroTask(() => log.push('started')); + }); player.onDone(() => log.push('done')); expect(log).toEqual([]); diff --git a/packages/bazel/src/api-extractor/index.ts b/packages/bazel/src/api-extractor/index.ts index 71e46ca72c148..b89304cfe8998 100644 --- a/packages/bazel/src/api-extractor/index.ts +++ b/packages/bazel/src/api-extractor/index.ts @@ -38,7 +38,7 @@ export function runMain( // API extractor doesn't always support the version of TypeScript used in the repo // example: at the moment it is not compatable with 3.2 // to use the internal TypeScript we shall not create a program but rather pass a parsed tsConfig. - const parsedTsConfig = parsedConfig !.config as any; + const parsedTsConfig = parsedConfig!.config as any; const compilerOptions = parsedTsConfig.compilerOptions; for (const [key, values] of Object.entries<string[]>(compilerOptions.paths)) { if (key === '*') { @@ -113,8 +113,8 @@ api-extractor: running with const dtsBundleOuts = dtsBundleOut.split(','); if (entryPoints.length !== entryPoints.length) { - throw new Error( - `Entry points count (${entryPoints.length}) does not match Bundle out count (${dtsBundleOuts.length})`); + throw new Error(`Entry points count (${entryPoints.length}) does not match Bundle out count (${ + dtsBundleOuts.length})`); } for (let i = 0; i < entryPoints.length; i++) { diff --git a/packages/bazel/src/builders/bazel.ts b/packages/bazel/src/builders/bazel.ts index e2dd5cb82f624..b737c9c969ed6 100644 --- a/packages/bazel/src/builders/bazel.ts +++ b/packages/bazel/src/builders/bazel.ts @@ -9,12 +9,12 @@ /// <reference types='node'/> import {spawn} from 'child_process'; -import {copyFileSync, existsSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync} from 'fs'; +import {copyFileSync, existsSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync} from 'fs'; import {platform} from 'os'; import {dirname, join, normalize} from 'path'; -export type Executable = 'bazel' | 'ibazel'; -export type Command = 'build' | 'test' | 'run' | 'coverage' | 'query'; +export type Executable = 'bazel'|'ibazel'; +export type Command = 'build'|'test'|'run'|'coverage'|'query'; /** * Spawn the Bazel process. Trap SINGINT to make sure Bazel process is killed. diff --git a/packages/bazel/src/builders/index.ts b/packages/bazel/src/builders/index.ts index 99d6549f5f989..54ac7e90a485b 100644 --- a/packages/bazel/src/builders/index.ts +++ b/packages/bazel/src/builders/index.ts @@ -13,27 +13,29 @@ import {JsonObject} from '@angular-devkit/core'; import {checkInstallation, copyBazelFiles, deleteBazelFiles, getTemplateDir, runBazel} from './bazel'; import {Schema} from './schema'; -async function _bazelBuilder(options: JsonObject & Schema, context: BuilderContext, ): - Promise<BuilderOutput> { - const {logger, workspaceRoot} = context; - const {bazelCommand, leaveBazelFilesOnDisk, targetLabel, watch} = options; - const executable = watch ? 'ibazel' : 'bazel'; - const binary = checkInstallation(executable, workspaceRoot); - const templateDir = getTemplateDir(workspaceRoot); - const bazelFiles = copyBazelFiles(workspaceRoot, templateDir); +async function _bazelBuilder( + options: JsonObject&Schema, + context: BuilderContext, + ): Promise<BuilderOutput> { + const {logger, workspaceRoot} = context; + const {bazelCommand, leaveBazelFilesOnDisk, targetLabel, watch} = options; + const executable = watch ? 'ibazel' : 'bazel'; + const binary = checkInstallation(executable, workspaceRoot); + const templateDir = getTemplateDir(workspaceRoot); + const bazelFiles = copyBazelFiles(workspaceRoot, templateDir); - try { - const flags: string[] = []; - await runBazel(workspaceRoot, binary, bazelCommand, targetLabel, flags); - return {success: true}; - } catch (err) { - logger.error(err.message); - return {success: false}; - } finally { - if (!leaveBazelFilesOnDisk) { - deleteBazelFiles(bazelFiles); // this will never throw - } - } + try { + const flags: string[] = []; + await runBazel(workspaceRoot, binary, bazelCommand, targetLabel, flags); + return {success: true}; + } catch (err) { + logger.error(err.message); + return {success: false}; + } finally { + if (!leaveBazelFilesOnDisk) { + deleteBazelFiles(bazelFiles); // this will never throw } + } +} export default createBuilder(_bazelBuilder); diff --git a/packages/bazel/src/ng_package/packager.ts b/packages/bazel/src/ng_package/packager.ts index c4f17fb77f22c..10d269e0c5360 100644 --- a/packages/bazel/src/ng_package/packager.ts +++ b/packages/bazel/src/ng_package/packager.ts @@ -22,7 +22,9 @@ function main(args: string[]): number { const paramFilePath = args[0]; // Bazel params may be surrounded with quotes - function unquoteParameter(s: string) { return s.replace(/^'(.*)'$/, '$1'); } + function unquoteParameter(s: string) { + return s.replace(/^'(.*)'$/, '$1'); + } // Parameters are specified in the file one per line. const params = fs.readFileSync(paramFilePath, 'utf-8').split('\n').map(unquoteParameter); @@ -109,7 +111,7 @@ function main(args: string[]): number { * @param inputPath Path to the file in the input tree. * @param fileContent Content of the file. */ - function writeFileFromInputPath(inputPath: string, fileContent: string | Buffer) { + function writeFileFromInputPath(inputPath: string, fileContent: string|Buffer) { // We want the relative path from the given file to its ancestor "root" directory. // This root depends on whether the file lives in the source tree (srcDir) as a basic file // input to ng_package, the bin output tree (binDir) as the output of another rule, or @@ -164,9 +166,15 @@ function main(args: string[]): number { esm2015.forEach(file => writeEsmFile(file, '', 'esm2015')); esm5.forEach(file => writeEsmFile(file, '.esm5', 'esm5')); - bundles.forEach(bundle => { copyFile(bundle, out, 'bundles'); }); - fesm2015.forEach(file => { copyFile(file, out, 'fesm2015'); }); - fesm5.forEach(file => { copyFile(file, out, 'fesm5'); }); + bundles.forEach(bundle => { + copyFile(bundle, out, 'bundles'); + }); + fesm2015.forEach(file => { + copyFile(file, out, 'fesm2015'); + }); + fesm5.forEach(file => { + copyFile(file, out, 'fesm5'); + }); // Copy all type definitions into the package. This is necessary so that developers can use // the package with type definitions. @@ -419,14 +427,16 @@ export * from '${srcDirRelative(inputPath, typingsFile.replace(/\.d\.tsx?$/, '') * Normalizes the specified path by replacing backslash separators with Posix * forward slash separators. */ - function normalizeSeparators(path: string): string { return path.replace(/\\/g, '/'); } + function normalizeSeparators(path: string): string { + return path.replace(/\\/g, '/'); + } /** - * Rewires metadata to point to the flattened dts file. - * - * @param metadataPath the metadata file path - * @param typingsPath the typings bundle entrypoint - */ + * Rewires metadata to point to the flattened dts file. + * + * @param metadataPath the metadata file path + * @param typingsPath the typings bundle entrypoint + */ function rewireMetadata(metadataPath: string, typingsPath: string): string { const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8')); @@ -470,7 +480,7 @@ export function newArray<T>(size: number, value: T): T[]; export function newArray<T>(size: number, value?: T): T[] { const list: T[] = []; for (let i = 0; i < size; i++) { - list.push(value !); + list.push(value!); } return list; } diff --git a/packages/bazel/src/ngc-wrapped/index.ts b/packages/bazel/src/ngc-wrapped/index.ts index e78b1064548f4..a80c00cd846db 100644 --- a/packages/bazel/src/ngc-wrapped/index.ts +++ b/packages/bazel/src/ngc-wrapped/index.ts @@ -7,7 +7,7 @@ */ import * as ng from '@angular/compiler-cli'; -import {BazelOptions, CachedFileLoader, CompilerHost, FileCache, FileLoader, UncachedFileLoader, constructManifest, debug, parseTsconfig, resolveNormalizedPath, runAsWorker, runWorkerLoop} from '@bazel/typescript'; +import {BazelOptions, CachedFileLoader, CompilerHost, constructManifest, debug, FileCache, FileLoader, parseTsconfig, resolveNormalizedPath, runAsWorker, runWorkerLoop, UncachedFileLoader} from '@bazel/typescript'; import * as fs from 'fs'; import * as path from 'path'; import * as tsickle from 'tsickle'; @@ -123,7 +123,12 @@ export function runOneBuild(args: string[], inputs?: {[path: string]: string}): const {diagnostics} = compile({ allDepsCompiledWithBazel: ALL_DEPS_COMPILED_WITH_BAZEL, useManifestPathsAsModuleName: _useManifestPathsAsModuleName, - expectedOuts: expectedOut, compilerOpts, tsHost, bazelOpts, files, inputs, + expectedOuts: expectedOut, + compilerOpts, + tsHost, + bazelOpts, + files, + inputs, }); if (diagnostics.length) { console.error(ng.formatDiagnostics(diagnostics)); @@ -142,16 +147,24 @@ export function relativeToRootDirs(filePath: string, rootDirs: string[]): string return filePath; } -export function compile({allDepsCompiledWithBazel = true, useManifestPathsAsModuleName, - compilerOpts, tsHost, bazelOpts, files, inputs, expectedOuts, - gatherDiagnostics, bazelHost}: { +export function compile({ + allDepsCompiledWithBazel = true, + useManifestPathsAsModuleName, + compilerOpts, + tsHost, + bazelOpts, + files, + inputs, + expectedOuts, + gatherDiagnostics, + bazelHost +}: { allDepsCompiledWithBazel?: boolean, - useManifestPathsAsModuleName?: boolean, - compilerOpts: ng.CompilerOptions, - tsHost: ts.CompilerHost, inputs?: {[path: string]: string}, - bazelOpts: BazelOptions, - files: string[], - expectedOuts: string[], + useManifestPathsAsModuleName?: boolean, compilerOpts: ng.CompilerOptions, tsHost: ts.CompilerHost, + inputs?: {[path: string]: string}, + bazelOpts: BazelOptions, + files: string[], + expectedOuts: string[], gatherDiagnostics?: (program: ng.Program) => ng.Diagnostics, bazelHost?: CompilerHost, }): {diagnostics: ng.Diagnostics, program: ng.Program} { @@ -362,7 +375,7 @@ export function compile({allDepsCompiledWithBazel = true, useManifestPathsAsModu if ((compilerOpts.module === ts.ModuleKind.UMD || compilerOpts.module === ts.ModuleKind.AMD) && ngHost.amdModuleName) { - return ngHost.amdModuleName({ fileName: importedFilePath } as ts.SourceFile); + return ngHost.amdModuleName({fileName: importedFilePath} as ts.SourceFile); } // If no AMD module name has been set for the source file by the `@bazel/typescript` compiler @@ -434,8 +447,10 @@ export function compile({allDepsCompiledWithBazel = true, useManifestPathsAsModu const {diagnostics, emitResult, program} = ng.performCompilation({ rootNames: files, options: compilerOpts, - host: ngHost, emitCallback, - mergeEmitResultsCallback: tsickle.mergeEmitResults, gatherDiagnostics + host: ngHost, + emitCallback, + mergeEmitResultsCallback: tsickle.mergeEmitResults, + gatherDiagnostics }); const tsickleEmitResult = emitResult as tsickle.EmitResult; let externs = '/** @externs */\n'; @@ -512,9 +527,9 @@ function convertToForwardSlashPath(filePath: string): string { function gatherDiagnosticsForInputsOnly( options: ng.CompilerOptions, bazelOpts: BazelOptions, - ngProgram: ng.Program): (ng.Diagnostic | ts.Diagnostic)[] { + ngProgram: ng.Program): (ng.Diagnostic|ts.Diagnostic)[] { const tsProgram = ngProgram.getTsProgram(); - const diagnostics: (ng.Diagnostic | ts.Diagnostic)[] = []; + const diagnostics: (ng.Diagnostic|ts.Diagnostic)[] = []; // These checks mirror ts.getPreEmitDiagnostics, with the important // exception of avoiding b/30708240, which is that if you call // program.getDeclarationDiagnostics() it somehow corrupts the emit. diff --git a/packages/bazel/src/schematics/ng-add/index_spec.ts b/packages/bazel/src/schematics/ng-add/index_spec.ts index 133584ac9e109..7dc0f7ca58fdf 100644 --- a/packages/bazel/src/schematics/ng-add/index_spec.ts +++ b/packages/bazel/src/schematics/ng-add/index_spec.ts @@ -10,7 +10,6 @@ import {HostTree} from '@angular-devkit/schematics'; import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; describe('ng-add schematic', () => { - const defaultOptions = {name: 'demo'}; let host: UnitTestTree; let schematicRunner: SchematicTestRunner; @@ -61,7 +60,7 @@ describe('ng-add schematic', () => { new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json')); }); - it('throws if package.json is not found', async() => { + it('throws if package.json is not found', async () => { expect(host.files).toContain('/package.json'); host.delete('/package.json'); @@ -76,7 +75,7 @@ describe('ng-add schematic', () => { expect(message).toBe('Could not read package.json.'); }); - it('throws if angular.json is not found', async() => { + it('throws if angular.json is not found', async () => { expect(host.files).toContain('/angular.json'); host.delete('/angular.json'); @@ -91,7 +90,7 @@ describe('ng-add schematic', () => { expect(message).toBe('Could not find angular.json'); }); - it('should add @angular/bazel to package.json dependencies', async() => { + it('should add @angular/bazel to package.json dependencies', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; expect(files).toContain('/package.json'); @@ -106,7 +105,7 @@ describe('ng-add schematic', () => { expect(Object.keys(json.devDependencies)).toContain(bazel); }); - it('should add @bazel/* dev dependencies', async() => { + it('should add @bazel/* dev dependencies', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const content = host.readContent('/package.json'); const json = JSON.parse(content); @@ -118,7 +117,7 @@ describe('ng-add schematic', () => { expect(devDeps).toContain('@bazel/typescript'); }); - it('should replace an existing dev dependency', async() => { + it('should replace an existing dev dependency', async () => { expect(host.files).toContain('/package.json'); const packageJson = JSON.parse(host.readContent('/package.json')); packageJson.devDependencies['@angular/bazel'] = '4.2.42'; @@ -126,12 +125,12 @@ describe('ng-add schematic', () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const content = host.readContent('/package.json'); // It is possible that a dep gets added twice if the package already exists. - expect(content.match(/@angular\/bazel/g) !.length).toEqual(1); + expect(content.match(/@angular\/bazel/g)!.length).toEqual(1); const json = JSON.parse(content); expect(json.devDependencies['@angular/bazel']).toBe('1.2.3'); }); - it('should remove an existing dependency', async() => { + it('should remove an existing dependency', async () => { expect(host.files).toContain('/package.json'); const packageJson = JSON.parse(host.readContent('/package.json')); packageJson.dependencies['@angular/bazel'] = '4.2.42'; @@ -144,7 +143,7 @@ describe('ng-add schematic', () => { expect(json.devDependencies['@angular/bazel']).toBe('1.2.3'); }); - it('should remove unneeded dependencies', async() => { + it('should remove unneeded dependencies', async () => { const packageJson = JSON.parse(host.readContent('/package.json')); packageJson.devDependencies['@angular-devkit/build-angular'] = '1.2.3'; host.overwrite('/package.json', JSON.stringify(packageJson)); @@ -154,7 +153,7 @@ describe('ng-add schematic', () => { expect(json.devDependencies['angular-devkit/build-angular']).toBeUndefined(); }); - it('should append to scripts.postinstall if it already exists', async() => { + it('should append to scripts.postinstall if it already exists', async () => { const packageJson = JSON.parse(host.readContent('/package.json')); packageJson['scripts'] = { postinstall: 'angular rocks', @@ -167,7 +166,7 @@ describe('ng-add schematic', () => { .toBe('angular rocks; ngcc --properties es2015 browser module main'); }); - it('should update ngcc in scripts.postinstall if it already exists', async() => { + it('should update ngcc in scripts.postinstall if it already exists', async () => { const packageJson = JSON.parse(host.readContent('/package.json')); packageJson['scripts'] = { postinstall: @@ -180,14 +179,14 @@ describe('ng-add schematic', () => { expect(json.scripts['postinstall']).toBe('ngcc --properties es2015 browser module main'); }); - it('should not create Bazel workspace file', async() => { + it('should not create Bazel workspace file', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; expect(files).not.toContain('/WORKSPACE'); expect(files).not.toContain('/BUILD.bazel'); }); - it('should produce main.dev.ts and main.prod.ts for AOT', async() => { + it('should produce main.dev.ts and main.prod.ts for AOT', async () => { host.create('/src/main.ts', 'generated by CLI'); host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; @@ -199,7 +198,7 @@ describe('ng-add schematic', () => { expect(files).toContain('/src/main.ts'); }); - it('should not overwrite index.html with script tags', async() => { + it('should not overwrite index.html with script tags', async () => { host.create('/src/index.html', '<html>Hello World</html>'); host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; @@ -209,14 +208,14 @@ describe('ng-add schematic', () => { expect(content).not.toMatch('<script src="/bundle.min.js"></script>'); }); - it('should generate main.dev.ts and main.prod.ts', async() => { + it('should generate main.dev.ts and main.prod.ts', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; expect(files).toContain('/src/main.dev.ts'); expect(files).toContain('/src/main.prod.ts'); }); - it('should overwrite .gitignore for bazel-out directory', async() => { + it('should overwrite .gitignore for bazel-out directory', async () => { host.create('.gitignore', '\n# compiled output\n'); host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; @@ -225,7 +224,7 @@ describe('ng-add schematic', () => { expect(content).toMatch('\n# compiled output\n/bazel-out\n'); }); - it('should create a backup for original angular.json', async() => { + it('should create a backup for original angular.json', async () => { expect(host.files).toContain('/angular.json'); const original = host.readContent('/angular.json'); host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); @@ -235,7 +234,7 @@ describe('ng-add schematic', () => { expect(content).toMatch(original); }); - it('should update angular.json to use Bazel builder', async() => { + it('should update angular.json to use Bazel builder', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const {files} = host; expect(files).toContain('/angular.json'); @@ -256,7 +255,7 @@ describe('ng-add schematic', () => { expect(lint.builder).toBe('@angular-devkit/build-angular:tslint'); }); - it('should get defaultProject if name is not provided', async() => { + it('should get defaultProject if name is not provided', async () => { const options = {}; host = await schematicRunner.runSchematicAsync('ng-add', options, host).toPromise(); const content = host.readContent('/angular.json'); @@ -281,7 +280,7 @@ describe('ng-add schematic', () => { ['~7.0.1', false], ]; for (const [version, upgrade] of cases) { - it(`should ${upgrade ? '' : 'not '}upgrade v${version}')`, async() => { + it(`should ${upgrade ? '' : 'not '}upgrade v${version}')`, async () => { host.overwrite('package.json', JSON.stringify({ name: 'demo', dependencies: { @@ -305,7 +304,7 @@ describe('ng-add schematic', () => { } }); - it('should add a postinstall step to package.json', async() => { + it('should add a postinstall step to package.json', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); expect(host.files).toContain('/package.json'); const content = host.readContent('/package.json'); @@ -313,7 +312,7 @@ describe('ng-add schematic', () => { expect(json.scripts.postinstall).toBe('ngcc --properties es2015 browser module main'); }); - it('should work when run on a minimal project (without test and e2e targets)', async() => { + it('should work when run on a minimal project (without test and e2e targets)', async () => { host.overwrite('angular.json', JSON.stringify({ projects: { 'demo': { @@ -338,5 +337,4 @@ describe('ng-add schematic', () => { expect(error).toBeNull(); }); - }); diff --git a/packages/bazel/src/schematics/ng-new/index.ts b/packages/bazel/src/schematics/ng-new/index.ts index 94a3826399ca1..51e52e5051f82 100644 --- a/packages/bazel/src/schematics/ng-new/index.ts +++ b/packages/bazel/src/schematics/ng-new/index.ts @@ -8,8 +8,9 @@ * @fileoverview Schematics for ng-new project that builds with Bazel. */ -import {Rule, Tree, chain, externalSchematic, schematic} from '@angular-devkit/schematics'; +import {chain, externalSchematic, Rule, schematic, Tree} from '@angular-devkit/schematics'; import {validateProjectName} from '@schematics/angular/utility/validation'; + import {Schema} from './schema'; export default function(options: Schema): Rule { diff --git a/packages/bazel/src/schematics/ng-new/index_spec.ts b/packages/bazel/src/schematics/ng-new/index_spec.ts index 3d1fef16bf787..1da740b925f36 100644 --- a/packages/bazel/src/schematics/ng-new/index_spec.ts +++ b/packages/bazel/src/schematics/ng-new/index_spec.ts @@ -9,14 +9,16 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; describe('ng-new schematic', () => { - const schematicRunner = - new SchematicTestRunner('@angular/bazel', require.resolve('../collection.json'), ); + const schematicRunner = new SchematicTestRunner( + '@angular/bazel', + require.resolve('../collection.json'), + ); const defaultOptions = { name: 'demo', version: '7.0.0', }; - it('should call external @schematics/angular', async() => { + it('should call external @schematics/angular', async () => { const options = {...defaultOptions}; const host = await schematicRunner.runSchematicAsync('ng-new', options).toPromise(); const {files} = host; @@ -25,7 +27,7 @@ describe('ng-new schematic', () => { expect(files).toContain('/demo/package.json'); }); - it('should call ng-add to generate additional files needed by Bazel', async() => { + it('should call ng-add to generate additional files needed by Bazel', async () => { const options = {...defaultOptions}; const host = await schematicRunner.runSchematicAsync('ng-new', options).toPromise(); const {files} = host; diff --git a/packages/bazel/src/schematics/ng-new/schema.d.ts b/packages/bazel/src/schematics/ng-new/schema.d.ts index 9cf013db9e82f..913cf2bc26622 100644 --- a/packages/bazel/src/schematics/ng-new/schema.d.ts +++ b/packages/bazel/src/schematics/ng-new/schema.d.ts @@ -86,8 +86,8 @@ export interface Schema { viewEncapsulation?: ViewEncapsulation; } /** -* Initial git repository commit information. -*/ + * Initial git repository commit information. + */ export declare type CommitUnion = boolean | CommitObject; export interface CommitObject { email: string; @@ -95,16 +95,16 @@ export interface CommitObject { name: string; } /** -* The file extension or preprocessor to use for style files. -*/ + * The file extension or preprocessor to use for style files. + */ export declare enum Style { Css = 'css', Sass = 'sass', Scss = 'scss', } /** -* The view encapsulation strategy to use in the initial project. -*/ + * The view encapsulation strategy to use in the initial project. + */ export declare enum ViewEncapsulation { Emulated = 'Emulated', Native = 'Native', diff --git a/packages/bazel/src/schematics/utility/json-utils.ts b/packages/bazel/src/schematics/utility/json-utils.ts index 0c42716dbdba1..449ea6d62a573 100644 --- a/packages/bazel/src/schematics/utility/json-utils.ts +++ b/packages/bazel/src/schematics/utility/json-utils.ts @@ -42,7 +42,7 @@ export function removeKeyValueInAstObject( let length = end - start; const match = content.slice(end).match(/^[,\s]+/); if (match) { - length += match.pop() !.length; + length += match.pop()!.length; } recorder.remove(start, length); if (i === node.properties.length - 1) { // last property @@ -60,6 +60,6 @@ export function removeKeyValueInAstObject( /** * Returns true if the specified 'node' is a JsonAstObject, false otherwise. */ -export function isJsonAstObject(node: JsonAstNode | null): node is JsonAstObject { +export function isJsonAstObject(node: JsonAstNode|null): node is JsonAstObject { return !!node && node.kind === 'object'; } diff --git a/packages/bazel/src/schematics/utility/json-utils_spec.ts b/packages/bazel/src/schematics/utility/json-utils_spec.ts index 0f7e2d24aa902..4341d083459ed 100644 --- a/packages/bazel/src/schematics/utility/json-utils_spec.ts +++ b/packages/bazel/src/schematics/utility/json-utils_spec.ts @@ -12,9 +12,10 @@ import {UnitTestTree} from '@angular-devkit/schematics/testing'; import {isJsonAstObject, removeKeyValueInAstObject, replacePropertyInAstObject} from './json-utils'; describe('JsonUtils', () => { - let tree: UnitTestTree; - beforeEach(() => { tree = new UnitTestTree(new HostTree()); }); + beforeEach(() => { + tree = new UnitTestTree(new HostTree()); + }); describe('replacePropertyInAstObject', () => { it('should replace property', () => { diff --git a/packages/bazel/test/ng_package/common_package.spec.ts b/packages/bazel/test/ng_package/common_package.spec.ts index 5966ae1f248a0..cfe1144e234e4 100644 --- a/packages/bazel/test/ng_package/common_package.spec.ts +++ b/packages/bazel/test/ng_package/common_package.spec.ts @@ -30,8 +30,9 @@ describe('@angular/common ng_package', () => { }); // regression test for https://github.com/angular/angular/issues/23217 // Note, we don't have an e2e test that covers this - it('doesn\'t pass require in a way that breaks webpack static analysis', - () => { expect(shx.cat('locales/fr.js')).not.toContain('factory(require, exports)'); }); + it('doesn\'t pass require in a way that breaks webpack static analysis', () => { + expect(shx.cat('locales/fr.js')).not.toContain('factory(require, exports)'); + }); }); it('should have right bundle files', () => { @@ -59,8 +60,9 @@ describe('@angular/common ng_package', () => { ]); }); - it('should reference core using global symbol in umd', - () => { expect(shx.cat('bundles/common.umd.js')).toContain('global.ng.core'); }); + it('should reference core using global symbol in umd', () => { + expect(shx.cat('bundles/common.umd.js')).toContain('global.ng.core'); + }); it('should have right fesm files', () => { const expected = [ diff --git a/packages/bazel/test/ng_package/core_package.spec.ts b/packages/bazel/test/ng_package/core_package.spec.ts index bbfe3594acf9b..0f6bda62c5235 100644 --- a/packages/bazel/test/ng_package/core_package.spec.ts +++ b/packages/bazel/test/ng_package/core_package.spec.ts @@ -41,8 +41,9 @@ describe('@angular/core ng_package', () => { describe('package.json', () => { const packageJson = 'package.json'; - it('should have a package.json file', - () => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`); }); + it('should have a package.json file', () => { + expect(shx.grep('"name":', packageJson)).toContain(`@angular/core`); + }); it('should contain correct version number with the PLACEHOLDER string replaced', () => { expect(shx.grep('"version":', packageJson)).toMatch(/\d+\.\d+\.\d+(?!-PLACEHOLDER)/); @@ -66,16 +67,20 @@ describe('@angular/core ng_package', () => { describe('typescript support', () => { if (ivyEnabled) { - it('should have an index d.ts file', - () => { expect(shx.cat('core.d.ts')).toContain(`export *`); }); + it('should have an index d.ts file', () => { + expect(shx.cat('core.d.ts')).toContain(`export *`); + }); - it('should not have amd module names', - () => { expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name'); }); + it('should not have amd module names', () => { + expect(shx.cat('public_api.d.ts')).not.toContain('<amd-module name'); + }); } else { - it('should have an index d.ts file', - () => { expect(shx.cat('core.d.ts')).toContain('export declare'); }); - it('should have an r3_symbols d.ts file', - () => { expect(shx.cat('src/r3_symbols.d.ts')).toContain('export declare'); }); + it('should have an index d.ts file', () => { + expect(shx.cat('core.d.ts')).toContain('export declare'); + }); + it('should have an r3_symbols d.ts file', () => { + expect(shx.cat('src/r3_symbols.d.ts')).toContain('export declare'); + }); } }); @@ -87,15 +92,18 @@ describe('@angular/core ng_package', () => { obsoleteInIvy('metadata files are no longer needed or produced in Ivy') .describe('angular metadata', () => { - it('should have metadata.json files', - () => { expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`); }); - it('should not have self-references in metadata.json', - () => { expect(shx.cat('core.metadata.json')).not.toContain(`"from":"./core"`); }); + it('should have metadata.json files', () => { + expect(shx.cat('core.metadata.json')).toContain(`"__symbolic":"module"`); + }); + it('should not have self-references in metadata.json', () => { + expect(shx.cat('core.metadata.json')).not.toContain(`"from":"./core"`); + }); }); describe('fesm2015', () => { - it('should have a fesm15 file in the /fesm2015 directory', - () => { expect(shx.cat('fesm2015/core.js')).toContain(`export {`); }); + it('should have a fesm15 file in the /fesm2015 directory', () => { + expect(shx.cat('fesm2015/core.js')).toContain(`export {`); + }); it('should have a source map', () => { expect(shx.cat('fesm2015/core.js.map')) @@ -114,8 +122,9 @@ describe('@angular/core ng_package', () => { }); describe('fesm5', () => { - it('should have a fesm5 file in the /fesm5 directory', - () => { expect(shx.cat('fesm5/core.js')).toContain(`export {`); }); + it('should have a fesm5 file in the /fesm5 directory', () => { + expect(shx.cat('fesm5/core.js')).toContain(`export {`); + }); it('should have a source map', () => { expect(shx.cat('fesm5/core.js.map')).toContain(`{"version":3,"file":"core.js","sources":`); @@ -131,12 +140,14 @@ describe('@angular/core ng_package', () => { expect(shx.cat('fesm5/core.js')).toContain('.ɵprov = '); }); } else { - it('should have decorators', - () => { expect(shx.cat('fesm5/core.js')).toContain('__decorate'); }); + it('should have decorators', () => { + expect(shx.cat('fesm5/core.js')).toContain('__decorate'); + }); // See: https://github.com/angular/angular/pull/32069 - it('should retain access to const', - () => { expect(shx.cat('fesm5/core.js')).toContain('!ivyEnabled'); }); + it('should retain access to const', () => { + expect(shx.cat('fesm5/core.js')).toContain('!ivyEnabled'); + }); } it('should load tslib from external bundle', () => { @@ -145,8 +156,9 @@ describe('@angular/core ng_package', () => { }); obsoleteInIvy('we no longer need to export private symbols') - .it('should have been built from the generated bundle index', - () => { expect(shx.cat('fesm5/core.js')).toMatch('export {.*makeParamDecorator'); }); + .it('should have been built from the generated bundle index', () => { + expect(shx.cat('fesm5/core.js')).toMatch('export {.*makeParamDecorator'); + }); }); describe('esm2015', () => { @@ -160,25 +172,31 @@ describe('@angular/core ng_package', () => { }); describe('esm5', () => { - it('should not contain any *.ngfactory.js files', - () => { expect(shx.find('esm5').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]); }); + it('should not contain any *.ngfactory.js files', () => { + expect(shx.find('esm5').filter(f => f.endsWith('.ngfactory.js'))).toEqual([]); + }); - it('should not contain any *.ngsummary.js files', - () => { expect(shx.find('esm5').filter(f => f.endsWith('.ngsummary.js'))).toEqual([]); }); + it('should not contain any *.ngsummary.js files', () => { + expect(shx.find('esm5').filter(f => f.endsWith('.ngsummary.js'))).toEqual([]); + }); }); describe('umd', () => { - it('should have a umd file in the /bundles directory', - () => { expect(shx.ls('bundles/core.umd.js').length).toBe(1, 'File not found'); }); + it('should have a umd file in the /bundles directory', () => { + expect(shx.ls('bundles/core.umd.js').length).toBe(1, 'File not found'); + }); - it('should have a source map next to the umd file', - () => { expect(shx.ls('bundles/core.umd.js.map').length).toBe(1, 'File not found'); }); + it('should have a source map next to the umd file', () => { + expect(shx.ls('bundles/core.umd.js.map').length).toBe(1, 'File not found'); + }); - it('should have a minified umd file in the /bundles directory', - () => { expect(shx.ls('bundles/core.umd.min.js').length).toBe(1, 'File not found'); }); + it('should have a minified umd file in the /bundles directory', () => { + expect(shx.ls('bundles/core.umd.min.js').length).toBe(1, 'File not found'); + }); - it('should have a source map next to the minified umd file', - () => { expect(shx.ls('bundles/core.umd.min.js.map').length).toBe(1, 'File not found'); }); + it('should have a source map next to the minified umd file', () => { + expect(shx.ls('bundles/core.umd.min.js.map').length).toBe(1, 'File not found'); + }); it('should have the version info in the header', () => { expect(shx.cat('bundles/core.umd.js')) @@ -189,22 +207,25 @@ describe('@angular/core ng_package', () => { expect(shx.cat('bundles/core.umd.js')).toContain('function __extends'); expect(shx.cat('bundles/core.umd.js')).not.toContain('undefined.__extends'); }); - it('should have an AMD name', - () => { expect(shx.cat('bundles/core.umd.js')).toContain('define(\'@angular/core\''); }); - it('should define ng global symbols', - () => { expect(shx.cat('bundles/core.umd.js')).toContain('global.ng.core = {}'); }); + it('should have an AMD name', () => { + expect(shx.cat('bundles/core.umd.js')).toContain('define(\'@angular/core\''); + }); + it('should define ng global symbols', () => { + expect(shx.cat('bundles/core.umd.js')).toContain('global.ng.core = {}'); + }); }); }); describe('secondary entry-point', () => { describe('package.json', () => { - const packageJson = p `testing/package.json`; + const packageJson = p`testing/package.json`; - it('should have a package.json file', - () => { expect(shx.grep('"name":', packageJson)).toContain(`@angular/core/testing`); }); + it('should have a package.json file', () => { + expect(shx.grep('"name":', packageJson)).toContain(`@angular/core/testing`); + }); it('should have its module resolution mappings defined in the nested package.json', () => { - const packageJson = p `testing/package.json`; + const packageJson = p`testing/package.json`; expect(shx.grep('"main":', packageJson)).toContain(`../bundles/core-testing.umd.js`); expect(shx.grep('"module":', packageJson)).toContain(`../fesm5/testing.js`); expect(shx.grep('"es2015":', packageJson)).toContain(`../fesm2015/testing.js`); @@ -216,13 +237,15 @@ describe('@angular/core ng_package', () => { describe('typings', () => { if (ivyEnabled) { - const typingsFile = p `testing/index.d.ts`; - it('should have a typings file', - () => { expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); }); + const typingsFile = p`testing/index.d.ts`; + it('should have a typings file', () => { + expect(shx.cat(typingsFile)).toContain(`export * from './public_api';`); + }); } else { - const typingsFile = p `testing/testing.d.ts`; - it('should have a typings file', - () => { expect(shx.cat(typingsFile)).toContain('export declare'); }); + const typingsFile = p`testing/testing.d.ts`; + it('should have a typings file', () => { + expect(shx.cat(typingsFile)).toContain('export declare'); + }); } obsoleteInIvy( @@ -242,8 +265,9 @@ describe('@angular/core ng_package', () => { }); describe('fesm2015', () => { - it('should have a fesm15 file in the /fesm2015 directory', - () => { expect(shx.cat('fesm2015/testing.js')).toContain(`export {`); }); + it('should have a fesm15 file in the /fesm2015 directory', () => { + expect(shx.cat('fesm2015/testing.js')).toContain(`export {`); + }); it('should have a source map', () => { expect(shx.cat('fesm2015/testing.js.map')) @@ -257,8 +281,9 @@ describe('@angular/core ng_package', () => { }); describe('fesm5', () => { - it('should have a fesm5 file in the /fesm5 directory', - () => { expect(shx.cat('fesm5/testing.js')).toContain(`export {`); }); + it('should have a fesm5 file in the /fesm5 directory', () => { + expect(shx.cat('fesm5/testing.js')).toContain(`export {`); + }); it('should have a source map', () => { expect(shx.cat('fesm5/testing.js.map')) @@ -267,8 +292,9 @@ describe('@angular/core ng_package', () => { }); describe('umd', () => { - it('should have a umd file in the /bundles directory', - () => { expect(shx.ls('bundles/core-testing.umd.js').length).toBe(1, 'File not found'); }); + it('should have a umd file in the /bundles directory', () => { + expect(shx.ls('bundles/core-testing.umd.js').length).toBe(1, 'File not found'); + }); it('should have a source map next to the umd file', () => { expect(shx.ls('bundles/core-testing.umd.js.map').length).toBe(1, 'File not found'); diff --git a/packages/bazel/test/ngc-wrapped/flat_module_test.ts b/packages/bazel/test/ngc-wrapped/flat_module_test.ts index b7fdec9b79d63..664a4e736f55e 100644 --- a/packages/bazel/test/ngc-wrapped/flat_module_test.ts +++ b/packages/bazel/test/ngc-wrapped/flat_module_test.ts @@ -11,7 +11,6 @@ import {existsSync, readFileSync} from 'fs'; import {dirname, join} from 'path'; describe('flat_module ng_module', () => { - let packageOutput: string; let flatModuleOutFile: string; @@ -21,11 +20,11 @@ describe('flat_module ng_module', () => { flatModuleOutFile = join(packageOutput, 'flat_module.js'); }); - it('should have a flat module out file', - () => { expect(existsSync(flatModuleOutFile)).toBe(true); }); + it('should have a flat module out file', () => { + expect(existsSync(flatModuleOutFile)).toBe(true); + }); describe('flat module out file', () => { - obsoleteInIvy('Ngtsc computes the AMD module name differently than NGC') .it('should have a proper AMD module name', () => { expect(readFileSync(flatModuleOutFile, 'utf8')) diff --git a/packages/bazel/test/ngc-wrapped/index_test.ts b/packages/bazel/test/ngc-wrapped/index_test.ts index 5c22cc2d7bb05..3932730149b8c 100644 --- a/packages/bazel/test/ngc-wrapped/index_test.ts +++ b/packages/bazel/test/ngc-wrapped/index_test.ts @@ -11,7 +11,6 @@ import * as path from 'path'; import {setup} from './test_support'; describe('ngc_wrapped', () => { - it('should work', () => { const {read, write, runOneBuild, writeConfig, shouldExist, basePath, typesRoots} = setup(); diff --git a/packages/bazel/test/ngc-wrapped/test_support.ts b/packages/bazel/test/ngc-wrapped/test_support.ts index 9f0dc054a8d24..69098ba0538bc 100644 --- a/packages/bazel/test/ngc-wrapped/test_support.ts +++ b/packages/bazel/test/ngc-wrapped/test_support.ts @@ -19,7 +19,9 @@ export interface TestSupport { angularCorePath: string; typesRoots: string; writeConfig({ - srcTargetPath, depPaths, pathMapping, + srcTargetPath, + depPaths, + pathMapping, }: { srcTargetPath: string, depPaths?: string[], @@ -33,13 +35,13 @@ export interface TestSupport { runOneBuild(): boolean; } -export function setup( - { - bazelBin = 'bazel-bin', tsconfig = 'tsconfig.json', - }: { - bazelBin?: string, - tsconfig?: string, - } = {}): TestSupport { +export function setup({ + bazelBin = 'bazel-bin', + tsconfig = 'tsconfig.json', +}: { + bazelBin?: string, + tsconfig?: string, +} = {}): TestSupport { const runfilesPath = process.env['TEST_SRCDIR']; const basePath = makeTempDir(runfilesPath); @@ -93,12 +95,17 @@ export function setup( } function writeFiles(...mockDirs: {[fileName: string]: string}[]) { - mockDirs.forEach( - (dir) => { Object.keys(dir).forEach((fileName) => { write(fileName, dir[fileName]); }); }); + mockDirs.forEach((dir) => { + Object.keys(dir).forEach((fileName) => { + write(fileName, dir[fileName]); + }); + }); } function writeConfig({ - srcTargetPath, depPaths = [], pathMapping = [], + srcTargetPath, + depPaths = [], + pathMapping = [], }: { srcTargetPath: string, depPaths?: string[], @@ -133,7 +140,8 @@ export function setup( defaultTsConfig: emptyTsConfig.config, rootDir: basePath, target: target, - outDir: bazelBinPath, compilationTargetSrc, + outDir: bazelBinPath, + compilationTargetSrc, files: files, pathMapping: pathMappingObj, }); @@ -153,7 +161,9 @@ export function setup( } } - function runOneBuildImpl(): boolean { return runOneBuild(['@' + tsConfigJsonPath]); } + function runOneBuildImpl(): boolean { + return runOneBuild(['@' + tsConfigJsonPath]); + } } function makeTempDir(baseDir: string): string { diff --git a/packages/benchpress/index.ts b/packages/benchpress/index.ts index 716714669c7e6..0808d5f55f77a 100644 --- a/packages/benchpress/index.ts +++ b/packages/benchpress/index.ts @@ -24,7 +24,7 @@ export {JsonFileReporter} from './src/reporter/json_file_reporter'; export {MultiReporter} from './src/reporter/multi_reporter'; export {Runner} from './src/runner'; export {SampleDescription} from './src/sample_description'; -export {SampleState, Sampler} from './src/sampler'; +export {Sampler, SampleState} from './src/sampler'; export {Validator} from './src/validator'; export {RegressionSlopeValidator} from './src/validator/regression_slope_validator'; export {SizeValidator} from './src/validator/size_validator'; diff --git a/packages/benchpress/src/metric.ts b/packages/benchpress/src/metric.ts index 60fb0a8f0bcb5..228282ff1a2fc 100644 --- a/packages/benchpress/src/metric.ts +++ b/packages/benchpress/src/metric.ts @@ -14,18 +14,24 @@ export abstract class Metric { /** * Starts measuring */ - beginMeasure(): Promise<any> { throw new Error('NYI'); } + beginMeasure(): Promise<any> { + throw new Error('NYI'); + } /** * Ends measuring and reports the data * since the begin call. * @param restart: Whether to restart right after this. */ - endMeasure(restart: boolean): Promise<{[key: string]: any}> { throw new Error('NYI'); } + endMeasure(restart: boolean): Promise<{[key: string]: any}> { + throw new Error('NYI'); + } /** * Describes the metrics provided by this metric implementation. * (e.g. units, ...) */ - describe(): {[key: string]: string} { throw new Error('NYI'); } + describe(): {[key: string]: string} { + throw new Error('NYI'); + } } diff --git a/packages/benchpress/src/metric/multi_metric.ts b/packages/benchpress/src/metric/multi_metric.ts index 47310e74835cf..05994585d4813 100644 --- a/packages/benchpress/src/metric/multi_metric.ts +++ b/packages/benchpress/src/metric/multi_metric.ts @@ -26,7 +26,9 @@ export class MultiMetric extends Metric { ]; } - constructor(private _metrics: Metric[]) { super(); } + constructor(private _metrics: Metric[]) { + super(); + } /** * Starts measuring @@ -56,7 +58,11 @@ export class MultiMetric extends Metric { function mergeStringMaps(maps: {[key: string]: string}[]): {[key: string]: string} { const result: {[key: string]: string} = {}; - maps.forEach(map => { Object.keys(map).forEach(prop => { result[prop] = map[prop]; }); }); + maps.forEach(map => { + Object.keys(map).forEach(prop => { + result[prop] = map[prop]; + }); + }); return result; } diff --git a/packages/benchpress/src/metric/perflog_metric.ts b/packages/benchpress/src/metric/perflog_metric.ts index ac285e7a959e7..7a1dbd99a7203 100644 --- a/packages/benchpress/src/metric/perflog_metric.ts +++ b/packages/benchpress/src/metric/perflog_metric.ts @@ -23,11 +23,12 @@ export class PerflogMetric extends Metric { static PROVIDERS = [ { provide: PerflogMetric, - deps: [ - WebDriverExtension, PerflogMetric.SET_TIMEOUT, Options.MICRO_METRICS, Options.FORCE_GC, - Options.CAPTURE_FRAMES, Options.RECEIVED_DATA, Options.REQUEST_COUNT, - PerflogMetric.IGNORE_NAVIGATION - ] + deps: + [ + WebDriverExtension, PerflogMetric.SET_TIMEOUT, Options.MICRO_METRICS, Options.FORCE_GC, + Options.CAPTURE_FRAMES, Options.RECEIVED_DATA, Options.REQUEST_COUNT, + PerflogMetric.IGNORE_NAVIGATION + ] }, { provide: PerflogMetric.SET_TIMEOUT, @@ -169,7 +170,9 @@ export class PerflogMetric extends Metric { return result; } let resolve: (result: any) => void; - const promise = new Promise<{[key: string]: number}>(res => { resolve = res; }); + const promise = new Promise<{[key: string]: number}>(res => { + resolve = res; + }); this._setTimeout(() => resolve(this._readUntilEndMark(markName, loopCount + 1)), 100); return promise; }); @@ -188,7 +191,7 @@ export class PerflogMetric extends Metric { } startEvent['ph'] = 'B'; endEvent['ph'] = 'E'; - endEvent['ts'] = startEvent['ts'] ! + startEvent['dur'] !; + endEvent['ts'] = startEvent['ts']! + startEvent['dur']!; this._remainingEvents.push(startEvent); this._remainingEvents.push(endEvent); } else { @@ -198,7 +201,7 @@ export class PerflogMetric extends Metric { if (needSort) { // Need to sort because of the ph==='X' events this._remainingEvents.sort((a, b) => { - const diff = a['ts'] ! - b['ts'] !; + const diff = a['ts']! - b['ts']!; return diff > 0 ? 1 : diff < 0 ? -1 : 0; }); } @@ -230,8 +233,8 @@ export class PerflogMetric extends Metric { result['requestCount'] = 0; } - let markStartEvent: PerfLogEvent = null !; - let markEndEvent: PerfLogEvent = null !; + let markStartEvent: PerfLogEvent = null!; + let markEndEvent: PerfLogEvent = null!; events.forEach((event) => { const ph = event['ph']; const name = event['name']; @@ -267,7 +270,7 @@ export class PerflogMetric extends Metric { let inMeasureRange = false; events.forEach((event) => { const ph = event['ph']; - let name = event['name'] !; + let name = event['name']!; let microIterations = 1; const microIterationsMatch = name.match(_MICRO_ITERATIONS_REGEX); if (microIterationsMatch) { @@ -286,7 +289,7 @@ export class PerflogMetric extends Metric { if (this._requestCount && name === 'sendRequest') { result['requestCount'] += 1; } else if (this._receivedData && name === 'receivedData' && ph === 'I') { - result['receivedData'] += event['args'] !['encodedDataLength'] !; + result['receivedData'] += event['args']!['encodedDataLength']!; } if (ph === 'B' && name === _MARK_NAME_FRAME_CAPTURE) { if (frameCaptureStartEvent) { @@ -305,7 +308,7 @@ export class PerflogMetric extends Metric { } if (ph === 'I' && frameCaptureStartEvent && !frameCaptureEndEvent && name === 'frame') { - frameTimestamps.push(event['ts'] !); + frameTimestamps.push(event['ts']!); if (frameTimestamps.length >= 2) { frameTimes.push( frameTimestamps[frameTimestamps.length - 1] - @@ -324,14 +327,14 @@ export class PerflogMetric extends Metric { intervalStartCount[name]--; if (intervalStartCount[name] === 0) { const startEvent = intervalStarts[name]; - const duration = (event['ts'] ! - startEvent['ts'] !); - intervalStarts[name] = null !; + const duration = (event['ts']! - startEvent['ts']!); + intervalStarts[name] = null!; if (name === 'gc') { result['gcTime'] += duration; const amount = - (startEvent['args'] !['usedHeapSize'] ! - event['args'] !['usedHeapSize'] !) / 1000; + (startEvent['args']!['usedHeapSize']! - event['args']!['usedHeapSize']!) / 1000; result['gcAmount'] += amount; - const majorGc = event['args'] !['majorGc']; + const majorGc = event['args']!['majorGc']; if (majorGc && majorGc) { result['majorGcTime'] += duration; } @@ -374,7 +377,9 @@ export class PerflogMetric extends Metric { frameTimes.filter(t => t < _FRAME_TIME_SMOOTH_THRESHOLD).length / frameTimes.length; } - private _markName(index: number) { return `${_MARK_NAME_PREFIX}${index}`; } + private _markName(index: number) { + return `${_MARK_NAME_PREFIX}${index}`; + } } const _MICRO_ITERATIONS_REGEX = /(.+)\*(\d+)$/; diff --git a/packages/benchpress/src/metric/user_metric.ts b/packages/benchpress/src/metric/user_metric.ts index 0adf2f08ef6ae..d08964a75f6b4 100644 --- a/packages/benchpress/src/metric/user_metric.ts +++ b/packages/benchpress/src/metric/user_metric.ts @@ -26,7 +26,9 @@ export class UserMetric extends Metric { /** * Starts measuring */ - beginMeasure(): Promise<any> { return Promise.resolve(true); } + beginMeasure(): Promise<any> { + return Promise.resolve(true); + } /** * Ends measuring. @@ -34,8 +36,7 @@ export class UserMetric extends Metric { endMeasure(restart: boolean): Promise<{[key: string]: any}> { let resolve: (result: any) => void; let reject: (error: any) => void; - const promise = new Promise < { [key: string]: any; } - > ((res, rej) => { + const promise = new Promise<{[key: string]: any;}>((res, rej) => { resolve = res; reject = rej; }); @@ -67,5 +68,7 @@ export class UserMetric extends Metric { * Describes the metrics provided by this metric implementation. * (e.g. units, ...) */ - describe(): {[key: string]: any} { return this._userMetrics; } + describe(): {[key: string]: any} { + return this._userMetrics; + } } diff --git a/packages/benchpress/src/reporter.ts b/packages/benchpress/src/reporter.ts index 0a75e79614a57..842fd31d89d92 100644 --- a/packages/benchpress/src/reporter.ts +++ b/packages/benchpress/src/reporter.ts @@ -12,7 +12,9 @@ import {MeasureValues} from './measure_values'; * A reporter reports measure values and the valid sample. */ export abstract class Reporter { - reportMeasureValues(values: MeasureValues): Promise<any> { throw new Error('NYI'); } + reportMeasureValues(values: MeasureValues): Promise<any> { + throw new Error('NYI'); + } reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> { throw new Error('NYI'); diff --git a/packages/benchpress/src/reporter/console_reporter.ts b/packages/benchpress/src/reporter/console_reporter.ts index 1659640010591..e2dc0e519c386 100644 --- a/packages/benchpress/src/reporter/console_reporter.ts +++ b/packages/benchpress/src/reporter/console_reporter.ts @@ -28,10 +28,11 @@ export class ConsoleReporter extends Reporter { }, {provide: ConsoleReporter.COLUMN_WIDTH, useValue: 18}, { provide: ConsoleReporter.PRINT, - useValue: function(v: any) { - // tslint:disable-next-line:no-console - console.log(v); - } + useValue: + function(v: any) { + // tslint:disable-next-line:no-console + console.log(v); + } } ]; @@ -58,7 +59,9 @@ export class ConsoleReporter extends Reporter { this._print(`BENCHMARK ${sampleDescription.id}`); this._print('Description:'); const props = sortedProps(sampleDescription.description); - props.forEach((prop) => { this._print(`- ${prop}: ${sampleDescription.description[prop]}`); }); + props.forEach((prop) => { + this._print(`- ${prop}: ${sampleDescription.description[prop]}`); + }); this._print('Metrics:'); this._metricNames.forEach((metricName) => { this._print(`- ${metricName}: ${sampleDescription.metrics[metricName]}`); diff --git a/packages/benchpress/src/reporter/json_file_reporter.ts b/packages/benchpress/src/reporter/json_file_reporter.ts index aaca71e9164ad..702b94ca5d695 100644 --- a/packages/benchpress/src/reporter/json_file_reporter.ts +++ b/packages/benchpress/src/reporter/json_file_reporter.ts @@ -37,7 +37,9 @@ export class JsonFileReporter extends Reporter { super(); } - reportMeasureValues(measureValues: MeasureValues): Promise<any> { return Promise.resolve(null); } + reportMeasureValues(measureValues: MeasureValues): Promise<any> { + return Promise.resolve(null); + } reportSample(completeSample: MeasureValues[], validSample: MeasureValues[]): Promise<any> { const stats: {[key: string]: string} = {}; diff --git a/packages/benchpress/src/reporter/multi_reporter.ts b/packages/benchpress/src/reporter/multi_reporter.ts index 07b507148ac24..355ef4482f12f 100644 --- a/packages/benchpress/src/reporter/multi_reporter.ts +++ b/packages/benchpress/src/reporter/multi_reporter.ts @@ -27,7 +27,9 @@ export class MultiReporter extends Reporter { ]; } - constructor(private _reporters: Reporter[]) { super(); } + constructor(private _reporters: Reporter[]) { + super(); + } reportMeasureValues(values: MeasureValues): Promise<any[]> { return Promise.all(this._reporters.map(reporter => reporter.reportMeasureValues(values))); diff --git a/packages/benchpress/src/runner.ts b/packages/benchpress/src/runner.ts index 7ba28dbf8a330..2b6e2f65fc270 100644 --- a/packages/benchpress/src/runner.ts +++ b/packages/benchpress/src/runner.ts @@ -17,7 +17,7 @@ import {Reporter} from './reporter'; import {ConsoleReporter} from './reporter/console_reporter'; import {MultiReporter} from './reporter/multi_reporter'; import {SampleDescription} from './sample_description'; -import {SampleState, Sampler} from './sampler'; +import {Sampler, SampleState} from './sampler'; import {Validator} from './validator'; import {RegressionSlopeValidator} from './validator/regression_slope_validator'; import {SizeValidator} from './validator/size_validator'; diff --git a/packages/benchpress/src/sample_description.ts b/packages/benchpress/src/sample_description.ts index ccecf159b5754..c99d65f902dbb 100644 --- a/packages/benchpress/src/sample_description.ts +++ b/packages/benchpress/src/sample_description.ts @@ -29,10 +29,11 @@ export class SampleDescription { userDesc ], metric.describe()), - deps: [ - Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator, - Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION - ] + deps: + [ + Metric, Options.SAMPLE_ID, Options.FORCE_GC, Options.USER_AGENT, Validator, + Options.DEFAULT_DESCRIPTION, Options.SAMPLE_DESCRIPTION + ] }]; description: {[key: string]: any}; @@ -41,9 +42,13 @@ export class SampleDescription { public metrics: {[key: string]: any}) { this.description = {}; descriptions.forEach(description => { - Object.keys(description).forEach(prop => { this.description[prop] = description[prop]; }); + Object.keys(description).forEach(prop => { + this.description[prop] = description[prop]; + }); }); } - toJson() { return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; } + toJson() { + return {'id': this.id, 'description': this.description, 'metrics': this.metrics}; + } } diff --git a/packages/benchpress/src/sampler.ts b/packages/benchpress/src/sampler.ts index 720fe621a5355..1d3999682b2fc 100644 --- a/packages/benchpress/src/sampler.ts +++ b/packages/benchpress/src/sampler.ts @@ -28,9 +28,11 @@ import {WebDriverAdapter} from './web_driver_adapter'; export class Sampler { static PROVIDERS = <StaticProvider[]>[{ provide: Sampler, - deps: [ - WebDriverAdapter, Metric, Reporter, Validator, Options.PREPARE, Options.EXECUTE, Options.NOW - ] + deps: + [ + WebDriverAdapter, Metric, Reporter, Validator, Options.PREPARE, Options.EXECUTE, + Options.NOW + ] }]; constructor( private _driver: WebDriverAdapter, private _metric: Metric, private _reporter: Reporter, diff --git a/packages/benchpress/src/validator.ts b/packages/benchpress/src/validator.ts index 536c22949d6e0..8838af7a2f772 100644 --- a/packages/benchpress/src/validator.ts +++ b/packages/benchpress/src/validator.ts @@ -17,11 +17,15 @@ export abstract class Validator { /** * Calculates a valid sample out of the complete sample */ - validate(completeSample: MeasureValues[]): MeasureValues[]|null { throw new Error('NYI'); } + validate(completeSample: MeasureValues[]): MeasureValues[]|null { + throw new Error('NYI'); + } /** * Returns a Map that describes the properties of the validator * (e.g. sample size, ...) */ - describe(): {[key: string]: any} { throw new Error('NYI'); } + describe(): {[key: string]: any} { + throw new Error('NYI'); + } } diff --git a/packages/benchpress/src/validator/size_validator.ts b/packages/benchpress/src/validator/size_validator.ts index 7d546c186a436..61e6c8cf71914 100644 --- a/packages/benchpress/src/validator/size_validator.ts +++ b/packages/benchpress/src/validator/size_validator.ts @@ -22,9 +22,13 @@ export class SizeValidator extends Validator { {provide: SizeValidator.SAMPLE_SIZE, useValue: 10} ]; - constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { super(); } + constructor(@Inject(SizeValidator.SAMPLE_SIZE) private _sampleSize: number) { + super(); + } - describe(): {[key: string]: any} { return {'sampleSize': this._sampleSize}; } + describe(): {[key: string]: any} { + return {'sampleSize': this._sampleSize}; + } validate(completeSample: MeasureValues[]): MeasureValues[]|null { if (completeSample.length >= this._sampleSize) { diff --git a/packages/benchpress/src/web_driver_adapter.ts b/packages/benchpress/src/web_driver_adapter.ts index d43e022f0e477..7e671a59ad89c 100644 --- a/packages/benchpress/src/web_driver_adapter.ts +++ b/packages/benchpress/src/web_driver_adapter.ts @@ -14,9 +14,19 @@ * Needs one implementation for every supported WebDriver client. */ export abstract class WebDriverAdapter { - waitFor(callback: Function): Promise<any> { throw new Error('NYI'); } - executeScript(script: string): Promise<any> { throw new Error('NYI'); } - executeAsyncScript(script: string): Promise<any> { throw new Error('NYI'); } - capabilities(): Promise<{[key: string]: any}> { throw new Error('NYI'); } - logs(type: string): Promise<any[]> { throw new Error('NYI'); } + waitFor(callback: Function): Promise<any> { + throw new Error('NYI'); + } + executeScript(script: string): Promise<any> { + throw new Error('NYI'); + } + executeAsyncScript(script: string): Promise<any> { + throw new Error('NYI'); + } + capabilities(): Promise<{[key: string]: any}> { + throw new Error('NYI'); + } + logs(type: string): Promise<any[]> { + throw new Error('NYI'); + } } diff --git a/packages/benchpress/src/web_driver_extension.ts b/packages/benchpress/src/web_driver_extension.ts index f5d1739763811..87e83c29bdb1c 100644 --- a/packages/benchpress/src/web_driver_extension.ts +++ b/packages/benchpress/src/web_driver_extension.ts @@ -12,7 +12,7 @@ import {Options} from './common_options'; export type PerfLogEvent = { [key: string]: any -} & { +}&{ ph?: 'X' | 'B' | 'E' | 'I', ts?: number, dur?: number, @@ -43,7 +43,7 @@ export abstract class WebDriverExtension { { provide: WebDriverExtension, useFactory: (children: WebDriverExtension[], capabilities: {[key: string]: any}) => { - let delegate: WebDriverExtension = undefined !; + let delegate: WebDriverExtension = undefined!; children.forEach(extension => { if (extension.supports(capabilities)) { delegate = extension; @@ -60,11 +60,17 @@ export abstract class WebDriverExtension { return res; } - gc(): Promise<any> { throw new Error('NYI'); } + gc(): Promise<any> { + throw new Error('NYI'); + } - timeBegin(name: string): Promise<any> { throw new Error('NYI'); } + timeBegin(name: string): Promise<any> { + throw new Error('NYI'); + } - timeEnd(name: string, restartName: string|null): Promise<any> { throw new Error('NYI'); } + timeEnd(name: string, restartName: string|null): Promise<any> { + throw new Error('NYI'); + } /** * Format: @@ -78,11 +84,17 @@ export abstract class WebDriverExtension { * Based on [Chrome Trace Event *Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit) **/ - readPerfLog(): Promise<PerfLogEvent[]> { throw new Error('NYI'); } + readPerfLog(): Promise<PerfLogEvent[]> { + throw new Error('NYI'); + } - perfLogFeatures(): PerfLogFeatures { throw new Error('NYI'); } + perfLogFeatures(): PerfLogFeatures { + throw new Error('NYI'); + } - supports(capabilities: {[key: string]: any}): boolean { return true; } + supports(capabilities: {[key: string]: any}): boolean { + return true; + } } export class PerfLogFeatures { diff --git a/packages/benchpress/src/webdriver/chrome_driver_extension.ts b/packages/benchpress/src/webdriver/chrome_driver_extension.ts index 9dba35fb28cbe..649c8f925082e 100644 --- a/packages/benchpress/src/webdriver/chrome_driver_extension.ts +++ b/packages/benchpress/src/webdriver/chrome_driver_extension.ts @@ -54,7 +54,9 @@ export class ChromeDriverExtension extends WebDriverExtension { return parseInt(v, 10); } - gc() { return this.driver.executeScript('window.gc()'); } + gc() { + return this.driver.executeScript('window.gc()'); + } async timeBegin(name: string): Promise<any> { if (this._firstRun) { @@ -108,7 +110,7 @@ export class ChromeDriverExtension extends WebDriverExtension { chromeEvents.forEach((event) => { const categories = this._parseCategories(event['cat']); const normalizedEvent = this._convertEvent(event, categories); - if (normalizedEvent != null) normalizedEvents !.push(normalizedEvent); + if (normalizedEvent != null) normalizedEvents!.push(normalizedEvent); }); return normalizedEvents; } @@ -184,7 +186,9 @@ export class ChromeDriverExtension extends WebDriverExtension { return null; // nothing useful in this event } - private _parseCategories(categories: string): string[] { return categories.split(','); } + private _parseCategories(categories: string): string[] { + return categories.split(','); + } private _isEvent( eventCategories: string[], eventName: string, expectedCategories: string[], diff --git a/packages/benchpress/src/webdriver/firefox_driver_extension.ts b/packages/benchpress/src/webdriver/firefox_driver_extension.ts index 2d34742505618..796eaef34d0d8 100644 --- a/packages/benchpress/src/webdriver/firefox_driver_extension.ts +++ b/packages/benchpress/src/webdriver/firefox_driver_extension.ts @@ -22,7 +22,9 @@ export class FirefoxDriverExtension extends WebDriverExtension { this._profilerStarted = false; } - gc() { return this._driver.executeScript('window.forceGC()'); } + gc() { + return this._driver.executeScript('window.forceGC()'); + } timeBegin(name: string): Promise<any> { if (!this._profilerStarted) { @@ -44,7 +46,9 @@ export class FirefoxDriverExtension extends WebDriverExtension { return this._driver.executeAsyncScript('var cb = arguments[0]; window.getProfile(cb);'); } - perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true, gc: true}); } + perfLogFeatures(): PerfLogFeatures { + return new PerfLogFeatures({render: true, gc: true}); + } supports(capabilities: {[key: string]: any}): boolean { return capabilities['browserName'].toLowerCase() === 'firefox'; diff --git a/packages/benchpress/src/webdriver/ios_driver_extension.ts b/packages/benchpress/src/webdriver/ios_driver_extension.ts index fefef6314c006..5200ee57e614f 100644 --- a/packages/benchpress/src/webdriver/ios_driver_extension.ts +++ b/packages/benchpress/src/webdriver/ios_driver_extension.ts @@ -15,9 +15,13 @@ import {PerfLogEvent, PerfLogFeatures, WebDriverExtension} from '../web_driver_e export class IOsDriverExtension extends WebDriverExtension { static PROVIDERS = [{provide: IOsDriverExtension, deps: [WebDriverAdapter]}]; - constructor(private _driver: WebDriverAdapter) { super(); } + constructor(private _driver: WebDriverAdapter) { + super(); + } - gc(): Promise<any> { throw new Error('Force GC is not supported on iOS'); } + gc(): Promise<any> { + throw new Error('Force GC is not supported on iOS'); + } timeBegin(name: string): Promise<any> { return this._driver.executeScript(`console.time('${name}');`); @@ -62,16 +66,16 @@ export class IOsDriverExtension extends WebDriverExtension { const endTime = record['endTime']; if (type === 'FunctionCall' && (data == null || data['scriptName'] !== 'InjectedScript')) { - events !.push(createStartEvent('script', startTime)); + events!.push(createStartEvent('script', startTime)); endEvent = createEndEvent('script', endTime); } else if (type === 'Time') { - events !.push(createMarkStartEvent(data['message'], startTime)); + events!.push(createMarkStartEvent(data['message'], startTime)); } else if (type === 'TimeEnd') { - events !.push(createMarkEndEvent(data['message'], startTime)); + events!.push(createMarkEndEvent(data['message'], startTime)); } else if ( type === 'RecalculateStyles' || type === 'Layout' || type === 'UpdateLayerTree' || type === 'Paint' || type === 'Rasterize' || type === 'CompositeLayers') { - events !.push(createStartEvent('render', startTime)); + events!.push(createStartEvent('render', startTime)); endEvent = createEndEvent('render', endTime); } // Note: ios used to support GCEvent up until iOS 6 :-( @@ -79,21 +83,22 @@ export class IOsDriverExtension extends WebDriverExtension { this._convertPerfRecordsToEvents(record['children'], events); } if (endEvent != null) { - events !.push(endEvent); + events!.push(endEvent); } }); return events; } - perfLogFeatures(): PerfLogFeatures { return new PerfLogFeatures({render: true}); } + perfLogFeatures(): PerfLogFeatures { + return new PerfLogFeatures({render: true}); + } supports(capabilities: {[key: string]: any}): boolean { return capabilities['browserName'].toLowerCase() === 'safari'; } } -function createEvent( - ph: 'X' | 'B' | 'E' | 'B' | 'E', name: string, time: number, args: any = null) { +function createEvent(ph: 'X'|'B'|'E'|'B'|'E', name: string, time: number, args: any = null) { const result: PerfLogEvent = { 'cat': 'timeline', 'name': name, diff --git a/packages/benchpress/src/webdriver/selenium_webdriver_adapter.ts b/packages/benchpress/src/webdriver/selenium_webdriver_adapter.ts index 3f7f7c4aa1fd7..74cc405dd3ff0 100644 --- a/packages/benchpress/src/webdriver/selenium_webdriver_adapter.ts +++ b/packages/benchpress/src/webdriver/selenium_webdriver_adapter.ts @@ -21,11 +21,17 @@ export class SeleniumWebDriverAdapter extends WebDriverAdapter { deps: [] }]; - constructor(private _driver: any) { super(); } + constructor(private _driver: any) { + super(); + } - waitFor(callback: () => any): Promise<any> { return this._driver.call(callback); } + waitFor(callback: () => any): Promise<any> { + return this._driver.call(callback); + } - executeScript(script: string): Promise<any> { return this._driver.executeScript(script); } + executeScript(script: string): Promise<any> { + return this._driver.executeScript(script); + } executeAsyncScript(script: string): Promise<any> { return this._driver.executeAsyncScript(script); @@ -58,7 +64,9 @@ class Command { private parameters_: {[key: string]: any} = {}; constructor(private name_: string) {} - getName() { return this.name_; } + getName() { + return this.name_; + } setParameter(name: string, value: any) { this.parameters_[name] = value; @@ -70,7 +78,11 @@ class Command { return this; } - getParameter(key: string) { return this.parameters_[key]; } + getParameter(key: string) { + return this.parameters_[key]; + } - getParameters() { return this.parameters_; } + getParameters() { + return this.parameters_; + } } diff --git a/packages/benchpress/test/metric/multi_metric_spec.ts b/packages/benchpress/test/metric/multi_metric_spec.ts index 1eb8bda5bc8b2..16335f7fcd676 100644 --- a/packages/benchpress/test/metric/multi_metric_spec.ts +++ b/packages/benchpress/test/metric/multi_metric_spec.ts @@ -11,50 +11,52 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te import {Injector, Metric, MultiMetric} from '../../index'; (function() { - function createMetric(ids: any[]) { - const m = Injector - .create([ - ids.map(id => ({provide: id, useValue: new MockMetric(id)})), - MultiMetric.provideWith(ids) - ]) - .get<MultiMetric>(MultiMetric); - return Promise.resolve(m); - } +function createMetric(ids: any[]) { + const m = Injector + .create([ + ids.map(id => ({provide: id, useValue: new MockMetric(id)})), + MultiMetric.provideWith(ids) + ]) + .get<MultiMetric>(MultiMetric); + return Promise.resolve(m); +} - describe('multi metric', () => { - it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createMetric(['m1', 'm2']).then((m) => { - expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'}); - async.done(); - }); - })); +describe('multi metric', () => { + it('should merge descriptions', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + createMetric(['m1', 'm2']).then((m) => { + expect(m.describe()).toEqual({'m1': 'describe', 'm2': 'describe'}); + async.done(); + }); + })); - it('should merge all beginMeasure calls', + it('should merge all beginMeasure calls', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => { + expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']); + async.done(); + }); + })); + + [false, true].forEach((restartFlag) => { + it(`should merge all endMeasure calls for restart=${restartFlag}`, inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createMetric(['m1', 'm2']).then((m) => m.beginMeasure()).then((values) => { - expect(values).toEqual(['m1_beginMeasure', 'm2_beginMeasure']); + createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => { + expect(values).toEqual({'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}}); async.done(); }); })); - - [false, true].forEach((restartFlag) => { - it(`should merge all endMeasure calls for restart=${restartFlag}`, - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createMetric(['m1', 'm2']).then((m) => m.endMeasure(restartFlag)).then((values) => { - expect(values).toEqual( - {'m1': {'restart': restartFlag}, 'm2': {'restart': restartFlag}}); - async.done(); - }); - })); - }); - }); +}); })(); class MockMetric extends Metric { - constructor(private _id: string) { super(); } + constructor(private _id: string) { + super(); + } - beginMeasure(): Promise<string> { return Promise.resolve(`${this._id}_beginMeasure`); } + beginMeasure(): Promise<string> { + return Promise.resolve(`${this._id}_beginMeasure`); + } endMeasure(restart: boolean): Promise<{[key: string]: any}> { const result: {[key: string]: any} = {}; diff --git a/packages/benchpress/test/metric/perflog_metric_spec.ts b/packages/benchpress/test/metric/perflog_metric_spec.ts index 7c068403a7de6..0133ff65db3f8 100644 --- a/packages/benchpress/test/metric/perflog_metric_spec.ts +++ b/packages/benchpress/test/metric/perflog_metric_spec.ts @@ -13,691 +13,677 @@ import {Injector, Metric, Options, PerfLogEvent, PerfLogFeatures, PerflogMetric, import {TraceEventFactory} from '../trace_event_factory'; (function() { - let commandLog: any[]; - const eventFactory = new TraceEventFactory('timeline', 'pid0'); - - function createMetric( - perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures, - {microMetrics, forceGc, captureFrames, receivedData, requestCount, ignoreNavigation}: { - microMetrics?: {[key: string]: string}, - forceGc?: boolean, - captureFrames?: boolean, - receivedData?: boolean, - requestCount?: boolean, - ignoreNavigation?: boolean - } = {}): Metric { - commandLog = []; - if (!perfLogFeatures) { - perfLogFeatures = - new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true}); - } - if (!microMetrics) { - microMetrics = {}; - } - const providers: StaticProvider[] = [ - Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS, - {provide: Options.MICRO_METRICS, useValue: microMetrics}, { - provide: PerflogMetric.SET_TIMEOUT, - useValue: (fn: Function, millis: number) => { - commandLog.push(['setTimeout', millis]); - fn(); - }, +let commandLog: any[]; +const eventFactory = new TraceEventFactory('timeline', 'pid0'); + +function createMetric( + perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures, + {microMetrics, forceGc, captureFrames, receivedData, requestCount, ignoreNavigation}: { + microMetrics?: {[key: string]: string}, + forceGc?: boolean, + captureFrames?: boolean, + receivedData?: boolean, + requestCount?: boolean, + ignoreNavigation?: boolean + } = {}): Metric { + commandLog = []; + if (!perfLogFeatures) { + perfLogFeatures = + new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true}); + } + if (!microMetrics) { + microMetrics = {}; + } + const providers: StaticProvider[] = [ + Options.DEFAULT_PROVIDERS, PerflogMetric.PROVIDERS, + {provide: Options.MICRO_METRICS, useValue: microMetrics}, { + provide: PerflogMetric.SET_TIMEOUT, + useValue: (fn: Function, millis: number) => { + commandLog.push(['setTimeout', millis]); + fn(); }, - { - provide: WebDriverExtension, - useValue: new MockDriverExtension(perfLogs, commandLog, perfLogFeatures) - } - ]; - if (forceGc != null) { - providers.push({provide: Options.FORCE_GC, useValue: forceGc}); - } - if (captureFrames != null) { - providers.push({provide: Options.CAPTURE_FRAMES, useValue: captureFrames}); - } - if (receivedData != null) { - providers.push({provide: Options.RECEIVED_DATA, useValue: receivedData}); + }, + { + provide: WebDriverExtension, + useValue: new MockDriverExtension(perfLogs, commandLog, perfLogFeatures) } - if (requestCount != null) { - providers.push({provide: Options.REQUEST_COUNT, useValue: requestCount}); - } - if (ignoreNavigation != null) { - providers.push({provide: PerflogMetric.IGNORE_NAVIGATION, useValue: ignoreNavigation}); - } - return Injector.create(providers).get(PerflogMetric); + ]; + if (forceGc != null) { + providers.push({provide: Options.FORCE_GC, useValue: forceGc}); } + if (captureFrames != null) { + providers.push({provide: Options.CAPTURE_FRAMES, useValue: captureFrames}); + } + if (receivedData != null) { + providers.push({provide: Options.RECEIVED_DATA, useValue: receivedData}); + } + if (requestCount != null) { + providers.push({provide: Options.REQUEST_COUNT, useValue: requestCount}); + } + if (ignoreNavigation != null) { + providers.push({provide: PerflogMetric.IGNORE_NAVIGATION, useValue: ignoreNavigation}); + } + return Injector.create(providers).get(PerflogMetric); +} - describe('perflog metric', () => { - - function sortedKeys(stringMap: {[key: string]: any}) { - const res: string[] = []; - res.push(...Object.keys(stringMap)); - res.sort(); - return res; - } - - it('should describe itself based on the perfLogFeatrues', () => { - expect(sortedKeys(createMetric([[]], new PerfLogFeatures()).describe())).toEqual([ - 'pureScriptTime', 'scriptTime' - ]); - - expect( - sortedKeys(createMetric([[]], new PerfLogFeatures({render: true, gc: false})).describe())) - .toEqual(['pureScriptTime', 'renderTime', 'scriptTime']); - - expect(sortedKeys(createMetric([[]], null !).describe())).toEqual([ - 'gcAmount', 'gcTime', 'majorGcTime', 'pureScriptTime', 'renderTime', 'scriptTime' - ]); - - expect(sortedKeys(createMetric([[]], new PerfLogFeatures({render: true, gc: true}), { - forceGc: true - }).describe())) - .toEqual([ - 'forcedGcAmount', 'forcedGcTime', 'gcAmount', 'gcTime', 'majorGcTime', 'pureScriptTime', - 'renderTime', 'scriptTime' - ]); - - - expect(sortedKeys(createMetric([[]], new PerfLogFeatures({userTiming: true}), { - receivedData: true, - requestCount: true - }).describe())) - .toEqual(['pureScriptTime', 'receivedData', 'requestCount', 'scriptTime']); - }); - - it('should describe itself based on micro metrics', () => { - const description = - createMetric([[]], null !, {microMetrics: {'myMicroMetric': 'someDesc'}}).describe(); - expect(description['myMicroMetric']).toEqual('someDesc'); - }); - - it('should describe itself if frame capture is requested and available', () => { - const description = createMetric([[]], new PerfLogFeatures({frameCapture: true}), { - captureFrames: true - }).describe(); - expect(description['frameTime.mean']).not.toContain('WARNING'); - expect(description['frameTime.best']).not.toContain('WARNING'); - expect(description['frameTime.worst']).not.toContain('WARNING'); - expect(description['frameTime.smooth']).not.toContain('WARNING'); - }); +describe('perflog metric', () => { + function sortedKeys(stringMap: {[key: string]: any}) { + const res: string[] = []; + res.push(...Object.keys(stringMap)); + res.sort(); + return res; + } - it('should describe itself if frame capture is requested and not available', () => { - const description = createMetric([[]], new PerfLogFeatures({frameCapture: false}), { - captureFrames: true - }).describe(); - expect(description['frameTime.mean']).toContain('WARNING'); - expect(description['frameTime.best']).toContain('WARNING'); - expect(description['frameTime.worst']).toContain('WARNING'); - expect(description['frameTime.smooth']).toContain('WARNING'); - }); + it('should describe itself based on the perfLogFeatrues', () => { + expect(sortedKeys(createMetric([[]], new PerfLogFeatures()).describe())).toEqual([ + 'pureScriptTime', 'scriptTime' + ]); + + expect( + sortedKeys(createMetric([[]], new PerfLogFeatures({render: true, gc: false})).describe())) + .toEqual(['pureScriptTime', 'renderTime', 'scriptTime']); + + expect(sortedKeys(createMetric([[]], null!).describe())).toEqual([ + 'gcAmount', 'gcTime', 'majorGcTime', 'pureScriptTime', 'renderTime', 'scriptTime' + ]); + + expect(sortedKeys(createMetric([[]], new PerfLogFeatures({render: true, gc: true}), { + forceGc: true + }).describe())) + .toEqual([ + 'forcedGcAmount', 'forcedGcTime', 'gcAmount', 'gcTime', 'majorGcTime', 'pureScriptTime', + 'renderTime', 'scriptTime' + ]); + + + expect(sortedKeys(createMetric([[]], new PerfLogFeatures({userTiming: true}), { + receivedData: true, + requestCount: true + }).describe())) + .toEqual(['pureScriptTime', 'receivedData', 'requestCount', 'scriptTime']); + }); - describe('beginMeasure', () => { + it('should describe itself based on micro metrics', () => { + const description = + createMetric([[]], null!, {microMetrics: {'myMicroMetric': 'someDesc'}}).describe(); + expect(description['myMicroMetric']).toEqual('someDesc'); + }); - it('should not force gc and mark the timeline', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const metric = createMetric([[]], null !); - metric.beginMeasure().then((_) => { - expect(commandLog).toEqual([['timeBegin', 'benchpress0']]); + it('should describe itself if frame capture is requested and available', () => { + const description = createMetric([[]], new PerfLogFeatures({frameCapture: true}), { + captureFrames: true + }).describe(); + expect(description['frameTime.mean']).not.toContain('WARNING'); + expect(description['frameTime.best']).not.toContain('WARNING'); + expect(description['frameTime.worst']).not.toContain('WARNING'); + expect(description['frameTime.smooth']).not.toContain('WARNING'); + }); - async.done(); - }); - })); + it('should describe itself if frame capture is requested and not available', () => { + const description = createMetric([[]], new PerfLogFeatures({frameCapture: false}), { + captureFrames: true + }).describe(); + expect(description['frameTime.mean']).toContain('WARNING'); + expect(description['frameTime.best']).toContain('WARNING'); + expect(description['frameTime.worst']).toContain('WARNING'); + expect(description['frameTime.smooth']).toContain('WARNING'); + }); - it('should force gc and mark the timeline', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const metric = createMetric([[]], null !, {forceGc: true}); - metric.beginMeasure().then((_) => { - expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]); + describe('beginMeasure', () => { + it('should not force gc and mark the timeline', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const metric = createMetric([[]], null!); + metric.beginMeasure().then((_) => { + expect(commandLog).toEqual([['timeBegin', 'benchpress0']]); + + async.done(); + }); + })); + + it('should force gc and mark the timeline', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const metric = createMetric([[]], null!, {forceGc: true}); + metric.beginMeasure().then((_) => { + expect(commandLog).toEqual([['gc'], ['timeBegin', 'benchpress0']]); + + async.done(); + }); + })); + }); - async.done(); - }); - })); + describe('endMeasure', () => { + it('should mark and aggregate events in between the marks', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const events = [[ + eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), + eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10) + ]]; + const metric = createMetric(events, null!); + metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { + expect(commandLog).toEqual([ + ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', null], 'readPerfLog' + ]); + expect(data['scriptTime']).toBe(2); + + async.done(); + }); + })); + + it('should mark and aggregate events since navigationStart', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const events = [[ + eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), + eventFactory.end('script', 6), eventFactory.instant('navigationStart', 7), + eventFactory.start('script', 8), eventFactory.end('script', 9), + eventFactory.markEnd('benchpress0', 10) + ]]; + const metric = createMetric(events, null!); + metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { + expect(data['scriptTime']).toBe(1); + + async.done(); + }); + })); + + it('should ignore navigationStart if ignoreNavigation is set', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const events = [[ + eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), + eventFactory.end('script', 6), eventFactory.instant('navigationStart', 7), + eventFactory.start('script', 8), eventFactory.end('script', 9), + eventFactory.markEnd('benchpress0', 10) + ]]; + const metric = createMetric(events, null!, {ignoreNavigation: true}); + metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { + expect(data['scriptTime']).toBe(3); + + async.done(); + }); + })); + + it('should restart timing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const events = [ + [ + eventFactory.markStart('benchpress0', 0), + eventFactory.markEnd('benchpress0', 1), + eventFactory.markStart('benchpress1', 2), + ], + [eventFactory.markEnd('benchpress1', 3)] + ]; + const metric = createMetric(events, null!); + metric.beginMeasure() + .then((_) => metric.endMeasure(true)) + .then((_) => metric.endMeasure(true)) + .then((_) => { + expect(commandLog).toEqual([ + ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'], + 'readPerfLog', ['timeEnd', 'benchpress1', 'benchpress2'], 'readPerfLog' + ]); - }); + async.done(); + }); + })); + + it('should loop and aggregate until the end mark is present', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const events = [ + [eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)], + [eventFactory.end('script', 2)], + [ + eventFactory.start('script', 3), eventFactory.end('script', 5), + eventFactory.markEnd('benchpress0', 10) + ] + ]; + const metric = createMetric(events, null!); + metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { + expect(commandLog).toEqual([ + ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', null], 'readPerfLog', + ['setTimeout', 100], 'readPerfLog', ['setTimeout', 100], 'readPerfLog' + ]); + expect(data['scriptTime']).toBe(3); + + async.done(); + }); + })); + + it('should store events after the end mark for the next call', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const events = [ + [ + eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1), + eventFactory.markStart('benchpress1', 1), eventFactory.start('script', 1), + eventFactory.end('script', 2) + ], + [ + eventFactory.start('script', 3), eventFactory.end('script', 5), + eventFactory.markEnd('benchpress1', 6) + ] + ]; + const metric = createMetric(events, null!); + metric.beginMeasure() + .then((_) => metric.endMeasure(true)) + .then((data) => { + expect(data['scriptTime']).toBe(0); + return metric.endMeasure(true); + }) + .then((data) => { + expect(commandLog).toEqual([ + ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'], + 'readPerfLog', ['timeEnd', 'benchpress1', 'benchpress2'], 'readPerfLog' + ]); + expect(data['scriptTime']).toBe(3); - describe('endMeasure', () => { + async.done(); + }); + })); + + describe('with forced gc', () => { + let events: PerfLogEvent[][]; + beforeEach(() => { + events = [[ + eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), + eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10), + eventFactory.markStart('benchpress1', 11), + eventFactory.start('gc', 12, {'usedHeapSize': 2500}), + eventFactory.end('gc', 15, {'usedHeapSize': 1000}), + eventFactory.markEnd('benchpress1', 20) + ]]; + }); - it('should mark and aggregate events in between the marks', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const events = [[ - eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), - eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10) - ]]; - const metric = createMetric(events, null !); + it('should measure forced gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const metric = createMetric(events, null!, {forceGc: true}); metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { expect(commandLog).toEqual([ - ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', null], 'readPerfLog' + ['gc'], ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'], + 'readPerfLog', ['gc'], ['timeEnd', 'benchpress1', null], 'readPerfLog' ]); - expect(data['scriptTime']).toBe(2); + expect(data['forcedGcTime']).toBe(3); + expect(data['forcedGcAmount']).toBe(1.5); async.done(); }); })); - it('should mark and aggregate events since navigationStart', + it('should restart after the forced gc if needed', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const events = [[ - eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), - eventFactory.end('script', 6), eventFactory.instant('navigationStart', 7), - eventFactory.start('script', 8), eventFactory.end('script', 9), - eventFactory.markEnd('benchpress0', 10) - ]]; - const metric = createMetric(events, null !); - metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { - expect(data['scriptTime']).toBe(1); - - async.done(); - }); - })); - - it('should ignore navigationStart if ignoreNavigation is set', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const events = [[ - eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), - eventFactory.end('script', 6), eventFactory.instant('navigationStart', 7), - eventFactory.start('script', 8), eventFactory.end('script', 9), - eventFactory.markEnd('benchpress0', 10) - ]]; - const metric = createMetric(events, null !, {ignoreNavigation: true}); - metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { - expect(data['scriptTime']).toBe(3); + const metric = createMetric(events, null!, {forceGc: true}); + metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => { + expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']); async.done(); }); })); + }); + }); - it('should restart timing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const events = [ - [ - eventFactory.markStart('benchpress0', 0), - eventFactory.markEnd('benchpress0', 1), - eventFactory.markStart('benchpress1', 2), - ], - [eventFactory.markEnd('benchpress1', 3)] - ]; - const metric = createMetric(events, null !); - metric.beginMeasure() - .then((_) => metric.endMeasure(true)) - .then((_) => metric.endMeasure(true)) - .then((_) => { - expect(commandLog).toEqual([ - ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'], - 'readPerfLog', ['timeEnd', 'benchpress1', 'benchpress2'], 'readPerfLog' - ]); + describe('aggregation', () => { + function aggregate(events: any[], {microMetrics, captureFrames, receivedData, requestCount}: { + microMetrics?: {[key: string]: string}, + captureFrames?: boolean, + receivedData?: boolean, + requestCount?: boolean + } = {}) { + events.unshift(eventFactory.markStart('benchpress0', 0)); + events.push(eventFactory.markEnd('benchpress0', 10)); + const metric = createMetric([events], null!, { + microMetrics: microMetrics, + captureFrames: captureFrames, + receivedData: receivedData, + requestCount: requestCount + }); + return metric.beginMeasure().then((_) => metric.endMeasure(false)); + } + describe('frame metrics', () => { + it('should calculate mean frame time', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate( + [ + eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), + eventFactory.instant('frame', 3), eventFactory.instant('frame', 4), + eventFactory.markEnd('frameCapture', 5) + ], + {captureFrames: true}) + .then((data) => { + expect(data['frameTime.mean']).toBe(((3 - 1) + (4 - 3)) / 2); async.done(); }); })); - it('should loop and aggregate until the end mark is present', + it('should throw if no start event', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const events = [ - [eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 1)], - [eventFactory.end('script', 2)], - [ - eventFactory.start('script', 3), eventFactory.end('script', 5), - eventFactory.markEnd('benchpress0', 10) - ] - ]; - const metric = createMetric(events, null !); - metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { - expect(commandLog).toEqual([ - ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', null], 'readPerfLog', - ['setTimeout', 100], 'readPerfLog', ['setTimeout', 100], 'readPerfLog' - ]); - expect(data['scriptTime']).toBe(3); - + aggregate([eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)], { + captureFrames: true + }).catch((err): any => { + expect(() => { + throw err; + }).toThrowError('missing start event for frame capture'); async.done(); }); })); - it('should store events after the end mark for the next call', + it('should throw if no end event', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const events = [ - [ - eventFactory.markStart('benchpress0', 0), eventFactory.markEnd('benchpress0', 1), - eventFactory.markStart('benchpress1', 1), eventFactory.start('script', 1), - eventFactory.end('script', 2) - ], - [ - eventFactory.start('script', 3), eventFactory.end('script', 5), - eventFactory.markEnd('benchpress1', 6) - ] - ]; - const metric = createMetric(events, null !); - metric.beginMeasure() - .then((_) => metric.endMeasure(true)) - .then((data) => { - expect(data['scriptTime']).toBe(0); - return metric.endMeasure(true); - }) - .then((data) => { - expect(commandLog).toEqual([ - ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'], - 'readPerfLog', ['timeEnd', 'benchpress1', 'benchpress2'], 'readPerfLog' - ]); - expect(data['scriptTime']).toBe(3); - + aggregate( + [eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)], + {captureFrames: true}) + .catch((err): any => { + expect(() => { + throw err; + }).toThrowError('missing end event for frame capture'); async.done(); }); })); - describe('with forced gc', () => { - let events: PerfLogEvent[][]; - beforeEach(() => { - events = [[ - eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 4), - eventFactory.end('script', 6), eventFactory.markEnd('benchpress0', 10), - eventFactory.markStart('benchpress1', 11), - eventFactory.start('gc', 12, {'usedHeapSize': 2500}), - eventFactory.end('gc', 15, {'usedHeapSize': 1000}), - eventFactory.markEnd('benchpress1', 20) - ]]; - }); - - it('should measure forced gc', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const metric = createMetric(events, null !, {forceGc: true}); - metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { - expect(commandLog).toEqual([ - ['gc'], ['timeBegin', 'benchpress0'], ['timeEnd', 'benchpress0', 'benchpress1'], - 'readPerfLog', ['gc'], ['timeEnd', 'benchpress1', null], 'readPerfLog' - ]); - expect(data['forcedGcTime']).toBe(3); - expect(data['forcedGcAmount']).toBe(1.5); - - async.done(); - }); - })); - - it('should restart after the forced gc if needed', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const metric = createMetric(events, null !, {forceGc: true}); - metric.beginMeasure().then((_) => metric.endMeasure(true)).then((data) => { - expect(commandLog[5]).toEqual(['timeEnd', 'benchpress1', 'benchpress2']); - - async.done(); - }); - })); - - }); - - }); - - describe('aggregation', () => { - - function aggregate(events: any[], {microMetrics, captureFrames, receivedData, requestCount}: { - microMetrics?: {[key: string]: string}, - captureFrames?: boolean, - receivedData?: boolean, - requestCount?: boolean - } = {}) { - events.unshift(eventFactory.markStart('benchpress0', 0)); - events.push(eventFactory.markEnd('benchpress0', 10)); - const metric = createMetric([events], null !, { - microMetrics: microMetrics, - captureFrames: captureFrames, - receivedData: receivedData, - requestCount: requestCount - }); - return metric.beginMeasure().then((_) => metric.endMeasure(false)); - } - - describe('frame metrics', () => { - it('should calculate mean frame time', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), - eventFactory.instant('frame', 3), eventFactory.instant('frame', 4), - eventFactory.markEnd('frameCapture', 5) - ], - {captureFrames: true}) - .then((data) => { - expect(data['frameTime.mean']).toBe(((3 - 1) + (4 - 3)) / 2); - async.done(); - }); - })); - - it('should throw if no start event', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - - aggregate( - [eventFactory.instant('frame', 4), eventFactory.markEnd('frameCapture', 5)], - {captureFrames: true}) - .catch((err): any => { - expect(() => { - throw err; - }).toThrowError('missing start event for frame capture'); - async.done(); - }); - })); - - it('should throw if no end event', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - - aggregate( - [eventFactory.markStart('frameCapture', 3), eventFactory.instant('frame', 4)], - {captureFrames: true}) - .catch((err): any => { - expect(() => { throw err; }).toThrowError('missing end event for frame capture'); - async.done(); - }); - })); - - it('should throw if trying to capture twice', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - - aggregate( - [ - eventFactory.markStart('frameCapture', 3), - eventFactory.markStart('frameCapture', 4) - ], - {captureFrames: true}) - .catch((err): any => { - expect(() => { - throw err; - }).toThrowError('can capture frames only once per benchmark run'); - async.done(); - }); - })); - - it('should throw if trying to capture when frame capture is disabled', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([eventFactory.markStart('frameCapture', 3)]).catch((err) => { - expect(() => { throw err; }) - .toThrowError( - 'found start event for frame capture, but frame capture was not requested in benchpress'); - async.done(); - return null; - }); - })); - - it('should throw if frame capture is enabled, but nothing is captured', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([], {captureFrames: true}).catch((err): any => { - expect(() => { throw err; }) - .toThrowError( - 'frame capture requested in benchpress, but no start event was found'); - async.done(); - }); - })); - - it('should calculate best and worst frame time', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), - eventFactory.instant('frame', 9), eventFactory.instant('frame', 15), - eventFactory.instant('frame', 18), eventFactory.instant('frame', 28), - eventFactory.instant('frame', 32), eventFactory.markEnd('frameCapture', 10) - ], - {captureFrames: true}) - .then((data) => { - expect(data['frameTime.worst']).toBe(10); - expect(data['frameTime.best']).toBe(3); - async.done(); - }); - })); - - it('should calculate percentage of smoothness to be good', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), - eventFactory.instant('frame', 2), eventFactory.instant('frame', 3), - eventFactory.markEnd('frameCapture', 4) - ], - {captureFrames: true}) - .then((data) => { - expect(data['frameTime.smooth']).toBe(1.0); - async.done(); - }); - })); - - it('should calculate percentage of smoothness to be bad', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), - eventFactory.instant('frame', 2), eventFactory.instant('frame', 22), - eventFactory.instant('frame', 23), eventFactory.instant('frame', 24), - eventFactory.markEnd('frameCapture', 4) - ], - {captureFrames: true}) - .then((data) => { - expect(data['frameTime.smooth']).toBe(0.75); - async.done(); - }); - })); - - }); - - it('should report a single interval', + it('should throw if trying to capture twice', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('script', 0), eventFactory.end('script', 5) - ]).then((data) => { - expect(data['scriptTime']).toBe(5); - async.done(); - }); - })); - - it('should sum up multiple intervals', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('script', 0), eventFactory.end('script', 5), - eventFactory.start('script', 10), eventFactory.end('script', 17) - ]).then((data) => { - expect(data['scriptTime']).toBe(12); - async.done(); - }); + aggregate( + [ + eventFactory.markStart('frameCapture', 3), + eventFactory.markStart('frameCapture', 4) + ], + {captureFrames: true}) + .catch((err): any => { + expect(() => { + throw err; + }).toThrowError('can capture frames only once per benchmark run'); + async.done(); + }); })); - it('should ignore not started intervals', + it('should throw if trying to capture when frame capture is disabled', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([eventFactory.end('script', 10)]).then((data) => { - expect(data['scriptTime']).toBe(0); + aggregate([eventFactory.markStart('frameCapture', 3)]).catch((err) => { + expect(() => { + throw err; + }) + .toThrowError( + 'found start event for frame capture, but frame capture was not requested in benchpress'); async.done(); + return null; }); })); - it('should ignore not ended intervals', + it('should throw if frame capture is enabled, but nothing is captured', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([eventFactory.start('script', 10)]).then((data) => { - expect(data['scriptTime']).toBe(0); + aggregate([], {captureFrames: true}).catch((err): any => { + expect(() => { + throw err; + }).toThrowError('frame capture requested in benchpress, but no start event was found'); async.done(); }); })); - it('should ignore nested intervals', + it('should calculate best and worst frame time', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('script', 0), eventFactory.start('script', 5), - eventFactory.end('script', 10), eventFactory.end('script', 17) - ]).then((data) => { - expect(data['scriptTime']).toBe(17); - async.done(); - }); + aggregate( + [ + eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), + eventFactory.instant('frame', 9), eventFactory.instant('frame', 15), + eventFactory.instant('frame', 18), eventFactory.instant('frame', 28), + eventFactory.instant('frame', 32), eventFactory.markEnd('frameCapture', 10) + ], + {captureFrames: true}) + .then((data) => { + expect(data['frameTime.worst']).toBe(10); + expect(data['frameTime.best']).toBe(3); + async.done(); + }); })); - it('should ignore events from different processed as the start mark', + it('should calculate percentage of smoothness to be good', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1'); - const metric = createMetric( - [[ - eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null), - eventFactory.end('script', 5, null), - otherProcessEventFactory.start('script', 10, null), - otherProcessEventFactory.end('script', 17, null), - eventFactory.markEnd('benchpress0', 20) - ]], - null !); - metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { - expect(data['scriptTime']).toBe(5); - async.done(); - }); + aggregate( + [ + eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), + eventFactory.instant('frame', 2), eventFactory.instant('frame', 3), + eventFactory.markEnd('frameCapture', 4) + ], + {captureFrames: true}) + .then((data) => { + expect(data['frameTime.smooth']).toBe(1.0); + async.done(); + }); })); - it('should mark a run as invalid if the start and end marks are different', + it('should calculate percentage of smoothness to be bad', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1'); - const metric = createMetric( - [[ - eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null), - eventFactory.end('script', 5, null), - otherProcessEventFactory.start('script', 10, null), - otherProcessEventFactory.end('script', 17, null), - otherProcessEventFactory.markEnd('benchpress0', 20) - ]], - null !); - metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { - expect(data['invalid']).toBe(1); - async.done(); - }); + aggregate( + [ + eventFactory.markStart('frameCapture', 0), eventFactory.instant('frame', 1), + eventFactory.instant('frame', 2), eventFactory.instant('frame', 22), + eventFactory.instant('frame', 23), eventFactory.instant('frame', 24), + eventFactory.markEnd('frameCapture', 4) + ], + {captureFrames: true}) + .then((data) => { + expect(data['frameTime.smooth']).toBe(0.75); + async.done(); + }); })); + }); - it('should support scriptTime metric', + it('should report a single interval', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('script', 0), eventFactory.end('script', 5) + ]).then((data) => { + expect(data['scriptTime']).toBe(5); + async.done(); + }); + })); + + it('should sum up multiple intervals', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('script', 0), eventFactory.end('script', 5), + eventFactory.start('script', 10), eventFactory.end('script', 17) + ]).then((data) => { + expect(data['scriptTime']).toBe(12); + async.done(); + }); + })); + + it('should ignore not started intervals', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([eventFactory.end('script', 10)]).then((data) => { + expect(data['scriptTime']).toBe(0); + async.done(); + }); + })); + + it('should ignore not ended intervals', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([eventFactory.start('script', 10)]).then((data) => { + expect(data['scriptTime']).toBe(0); + async.done(); + }); + })); + + it('should ignore nested intervals', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('script', 0), eventFactory.start('script', 5), + eventFactory.end('script', 10), eventFactory.end('script', 17) + ]).then((data) => { + expect(data['scriptTime']).toBe(17); + async.done(); + }); + })); + + it('should ignore events from different processed as the start mark', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1'); + const metric = createMetric( + [[ + eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null), + eventFactory.end('script', 5, null), + otherProcessEventFactory.start('script', 10, null), + otherProcessEventFactory.end('script', 17, null), + eventFactory.markEnd('benchpress0', 20) + ]], + null!); + metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { + expect(data['scriptTime']).toBe(5); + async.done(); + }); + })); + + it('should mark a run as invalid if the start and end marks are different', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const otherProcessEventFactory = new TraceEventFactory('timeline', 'pid1'); + const metric = createMetric( + [[ + eventFactory.markStart('benchpress0', 0), eventFactory.start('script', 0, null), + eventFactory.end('script', 5, null), + otherProcessEventFactory.start('script', 10, null), + otherProcessEventFactory.end('script', 17, null), + otherProcessEventFactory.markEnd('benchpress0', 20) + ]], + null!); + metric.beginMeasure().then((_) => metric.endMeasure(false)).then((data) => { + expect(data['invalid']).toBe(1); + async.done(); + }); + })); + + it('should support scriptTime metric', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('script', 0), eventFactory.end('script', 5) + ]).then((data) => { + expect(data['scriptTime']).toBe(5); + async.done(); + }); + })); + + it('should support renderTime metric', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('render', 0), eventFactory.end('render', 5) + ]).then((data) => { + expect(data['renderTime']).toBe(5); + async.done(); + }); + })); + + it('should support gcTime/gcAmount metric', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('gc', 0, {'usedHeapSize': 2500}), + eventFactory.end('gc', 5, {'usedHeapSize': 1000}) + ]).then((data) => { + expect(data['gcTime']).toBe(5); + expect(data['gcAmount']).toBe(1.5); + expect(data['majorGcTime']).toBe(0); + async.done(); + }); + })); + + it('should support majorGcTime metric', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('gc', 0, {'usedHeapSize': 2500}), + eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true}) + ]).then((data) => { + expect(data['gcTime']).toBe(5); + expect(data['majorGcTime']).toBe(5); + async.done(); + }); + })); + + it('should support pureScriptTime = scriptTime-gcTime-renderTime', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + aggregate([ + eventFactory.start('script', 0), eventFactory.start('gc', 1, {'usedHeapSize': 1000}), + eventFactory.end('gc', 4, {'usedHeapSize': 0}), eventFactory.start('render', 4), + eventFactory.end('render', 5), eventFactory.end('script', 6) + ]).then((data) => { + expect(data['scriptTime']).toBe(6); + expect(data['pureScriptTime']).toBe(2); + async.done(); + }); + })); + + describe('receivedData', () => { + it('should report received data since last navigationStart', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('script', 0), eventFactory.end('script', 5) - ]).then((data) => { - expect(data['scriptTime']).toBe(5); - async.done(); - }); + aggregate( + [ + eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}), + eventFactory.instant('navigationStart', 1), + eventFactory.instant('receivedData', 2, {'encodedDataLength': 2}), + eventFactory.instant('navigationStart', 3), + eventFactory.instant('receivedData', 4, {'encodedDataLength': 4}), + eventFactory.instant('receivedData', 5, {'encodedDataLength': 8}) + ], + {receivedData: true}) + .then((data) => { + expect(data['receivedData']).toBe(12); + async.done(); + }); })); + }); - it('should support renderTime metric', + describe('requestCount', () => { + it('should report count of requests sent since last navigationStart', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('render', 0), eventFactory.end('render', 5) - ]).then((data) => { - expect(data['renderTime']).toBe(5); - async.done(); - }); + aggregate( + [ + eventFactory.instant('sendRequest', 0), eventFactory.instant('navigationStart', 1), + eventFactory.instant('sendRequest', 2), eventFactory.instant('navigationStart', 3), + eventFactory.instant('sendRequest', 4), eventFactory.instant('sendRequest', 5) + ], + {requestCount: true}) + .then((data) => { + expect(data['requestCount']).toBe(2); + async.done(); + }); })); + }); - it('should support gcTime/gcAmount metric', + describe('microMetrics', () => { + it('should report micro metrics', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('gc', 0, {'usedHeapSize': 2500}), - eventFactory.end('gc', 5, {'usedHeapSize': 1000}) - ]).then((data) => { - expect(data['gcTime']).toBe(5); - expect(data['gcAmount']).toBe(1.5); - expect(data['majorGcTime']).toBe(0); - async.done(); - }); + aggregate( + [ + eventFactory.markStart('mm1', 0), + eventFactory.markEnd('mm1', 5), + ], + {microMetrics: {'mm1': 'micro metric 1'}}) + .then((data) => { + expect(data['mm1']).toBe(5.0); + async.done(); + }); })); - it('should support majorGcTime metric', + it('should ignore micro metrics that were not specified', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { aggregate([ - eventFactory.start('gc', 0, {'usedHeapSize': 2500}), - eventFactory.end('gc', 5, {'usedHeapSize': 1000, 'majorGc': true}) + eventFactory.markStart('mm1', 0), + eventFactory.markEnd('mm1', 5), ]).then((data) => { - expect(data['gcTime']).toBe(5); - expect(data['majorGcTime']).toBe(5); + expect(data['mm1']).toBeFalsy(); async.done(); }); })); - it('should support pureScriptTime = scriptTime-gcTime-renderTime', + it('should report micro metric averages', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.start('script', 0), eventFactory.start('gc', 1, {'usedHeapSize': 1000}), - eventFactory.end('gc', 4, {'usedHeapSize': 0}), eventFactory.start('render', 4), - eventFactory.end('render', 5), eventFactory.end('script', 6) - ]).then((data) => { - expect(data['scriptTime']).toBe(6); - expect(data['pureScriptTime']).toBe(2); - async.done(); - }); + aggregate( + [ + eventFactory.markStart('mm1*20', 0), + eventFactory.markEnd('mm1*20', 5), + ], + {microMetrics: {'mm1': 'micro metric 1'}}) + .then((data) => { + expect(data['mm1']).toBe(5 / 20); + async.done(); + }); })); - - describe('receivedData', () => { - it('should report received data since last navigationStart', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.instant('receivedData', 0, {'encodedDataLength': 1}), - eventFactory.instant('navigationStart', 1), - eventFactory.instant('receivedData', 2, {'encodedDataLength': 2}), - eventFactory.instant('navigationStart', 3), - eventFactory.instant('receivedData', 4, {'encodedDataLength': 4}), - eventFactory.instant('receivedData', 5, {'encodedDataLength': 8}) - ], - {receivedData: true}) - .then((data) => { - expect(data['receivedData']).toBe(12); - async.done(); - }); - })); - }); - - describe('requestCount', () => { - it('should report count of requests sent since last navigationStart', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.instant('sendRequest', 0), - eventFactory.instant('navigationStart', 1), - eventFactory.instant('sendRequest', 2), - eventFactory.instant('navigationStart', 3), - eventFactory.instant('sendRequest', 4), eventFactory.instant('sendRequest', 5) - ], - {requestCount: true}) - .then((data) => { - expect(data['requestCount']).toBe(2); - async.done(); - }); - })); - }); - - describe('microMetrics', () => { - - it('should report micro metrics', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.markStart('mm1', 0), - eventFactory.markEnd('mm1', 5), - ], - {microMetrics: {'mm1': 'micro metric 1'}}) - .then((data) => { - expect(data['mm1']).toBe(5.0); - async.done(); - }); - })); - - it('should ignore micro metrics that were not specified', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate([ - eventFactory.markStart('mm1', 0), - eventFactory.markEnd('mm1', 5), - ]).then((data) => { - expect(data['mm1']).toBeFalsy(); - async.done(); - }); - })); - - it('should report micro metric averages', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - aggregate( - [ - eventFactory.markStart('mm1*20', 0), - eventFactory.markEnd('mm1*20', 5), - ], - {microMetrics: {'mm1': 'micro metric 1'}}) - .then((data) => { - expect(data['mm1']).toBe(5 / 20); - async.done(); - }); - })); - - }); - }); - }); +}); })(); class MockDriverExtension extends WebDriverExtension { @@ -717,7 +703,9 @@ class MockDriverExtension extends WebDriverExtension { return Promise.resolve(null); } - perfLogFeatures(): PerfLogFeatures { return this._perfLogFeatures; } + perfLogFeatures(): PerfLogFeatures { + return this._perfLogFeatures; + } readPerfLog(): Promise<any> { this._commandLog.push('readPerfLog'); diff --git a/packages/benchpress/test/metric/user_metric_spec.ts b/packages/benchpress/test/metric/user_metric_spec.ts index 0225154a585f5..0f551c3184c2e 100644 --- a/packages/benchpress/test/metric/user_metric_spec.ts +++ b/packages/benchpress/test/metric/user_metric_spec.ts @@ -12,55 +12,55 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te import {Options, PerfLogEvent, PerfLogFeatures, UserMetric, WebDriverAdapter} from '../../index'; (function() { - let wdAdapter: MockDriverAdapter; +let wdAdapter: MockDriverAdapter; - function createMetric( - perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures, - {userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric { - if (!perfLogFeatures) { - perfLogFeatures = - new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true}); - } - if (!userMetrics) { - userMetrics = {}; - } - wdAdapter = new MockDriverAdapter(); - const providers: StaticProvider[] = [ - Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS, - {provide: Options.USER_METRICS, useValue: userMetrics}, - {provide: WebDriverAdapter, useValue: wdAdapter} - ]; - return Injector.create(providers).get(UserMetric); +function createMetric( + perfLogs: PerfLogEvent[], perfLogFeatures: PerfLogFeatures, + {userMetrics}: {userMetrics?: {[key: string]: string}} = {}): UserMetric { + if (!perfLogFeatures) { + perfLogFeatures = + new PerfLogFeatures({render: true, gc: true, frameCapture: true, userTiming: true}); } + if (!userMetrics) { + userMetrics = {}; + } + wdAdapter = new MockDriverAdapter(); + const providers: StaticProvider[] = [ + Options.DEFAULT_PROVIDERS, UserMetric.PROVIDERS, + {provide: Options.USER_METRICS, useValue: userMetrics}, + {provide: WebDriverAdapter, useValue: wdAdapter} + ]; + return Injector.create(providers).get(UserMetric); +} - describe('user metric', () => { - - it('should describe itself based on userMetrics', () => { - expect(createMetric([[]], new PerfLogFeatures(), { - userMetrics: {'loadTime': 'time to load'} - }).describe()) - .toEqual({'loadTime': 'time to load'}); - }); - - describe('endMeasure', () => { - it('should stop measuring when all properties have numeric values', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const metric = createMetric( - [[]], new PerfLogFeatures(), - {userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}}); - metric.beginMeasure().then(() => metric.endMeasure(true)).then(values => { - expect(values['loadTime']).toBe(25); - expect(values['content']).toBe(250); - async.done(); - }); +describe('user metric', () => { + it('should describe itself based on userMetrics', () => { + expect(createMetric([[]], new PerfLogFeatures(), { + userMetrics: {'loadTime': 'time to load'} + }).describe()) + .toEqual({'loadTime': 'time to load'}); + }); - wdAdapter.data['loadTime'] = 25; - // Wait before setting 2nd property. - setTimeout(() => { wdAdapter.data['content'] = 250; }, 50); + describe('endMeasure', () => { + it('should stop measuring when all properties have numeric values', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const metric = createMetric( + [[]], new PerfLogFeatures(), + {userMetrics: {'loadTime': 'time to load', 'content': 'time to see content'}}); + metric.beginMeasure().then(() => metric.endMeasure(true)).then(values => { + expect(values['loadTime']).toBe(25); + expect(values['content']).toBe(250); + async.done(); + }); - }), 600); - }); + wdAdapter.data['loadTime'] = 25; + // Wait before setting 2nd property. + setTimeout(() => { + wdAdapter.data['content'] = 250; + }, 50); + }), 600); }); +}); })(); class MockDriverAdapter extends WebDriverAdapter { diff --git a/packages/benchpress/test/reporter/console_reporter_spec.ts b/packages/benchpress/test/reporter/console_reporter_spec.ts index 0181382b11f2d..ac1397a82caa1 100644 --- a/packages/benchpress/test/reporter/console_reporter_spec.ts +++ b/packages/benchpress/test/reporter/console_reporter_spec.ts @@ -18,10 +18,10 @@ import {ConsoleReporter, Injector, MeasureValues, SampleDescription} from '../.. function createReporter( {columnWidth = null, sampleId = null, descriptions = null, metrics = null}: { - columnWidth?: number | null, - sampleId?: string | null, - descriptions?: {[key: string]: any}[] | null, - metrics?: {[key: string]: any} | null + columnWidth?: number|null, + sampleId?: string|null, + descriptions?: {[key: string]: any}[]|null, + metrics?: {[key: string]: any}|null }) { log = []; if (!descriptions) { @@ -33,7 +33,7 @@ import {ConsoleReporter, Injector, MeasureValues, SampleDescription} from '../.. const providers: StaticProvider[] = [ ConsoleReporter.PROVIDERS, { provide: SampleDescription, - useValue: new SampleDescription(sampleId, descriptions, metrics !) + useValue: new SampleDescription(sampleId, descriptions, metrics!) }, {provide: ConsoleReporter.PRINT, useValue: (line: string) => log.push(line)} ]; @@ -84,7 +84,6 @@ import {ConsoleReporter, Injector, MeasureValues, SampleDescription} from '../.. reporter.reportSample([], [mv(0, 0, {'a': 3, 'b': 0}), mv(1, 1, {'a': 5, 'b': 0})]); expect(log).toEqual(['======== | ========', '4.00+-25% | 0.00']); }); - }); } diff --git a/packages/benchpress/test/reporter/json_file_reporter_spec.ts b/packages/benchpress/test/reporter/json_file_reporter_spec.ts index 2ca147f2379d4..3ade0b9a27f1d 100644 --- a/packages/benchpress/test/reporter/json_file_reporter_spec.ts +++ b/packages/benchpress/test/reporter/json_file_reporter_spec.ts @@ -62,16 +62,12 @@ import {Injector, JsonFileReporter, MeasureValues, Options, SampleDescription} f {'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}} ], 'validSample': [ - {'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}}, { - 'timeStamp': '1970-01-01T00:00:00.001Z', - 'runIndex': 1, - 'values': {'a': 5, 'b': 9} - } + {'timeStamp': '1970-01-01T00:00:00.000Z', 'runIndex': 0, 'values': {'a': 3, 'b': 6}}, + {'timeStamp': '1970-01-01T00:00:00.001Z', 'runIndex': 1, 'values': {'a': 5, 'b': 9}} ] }); async.done(); })); - }); } diff --git a/packages/benchpress/test/reporter/multi_reporter_spec.ts b/packages/benchpress/test/reporter/multi_reporter_spec.ts index 4bfeb5ff82282..96045b5a1f79c 100644 --- a/packages/benchpress/test/reporter/multi_reporter_spec.ts +++ b/packages/benchpress/test/reporter/multi_reporter_spec.ts @@ -11,50 +11,48 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te import {Injector, MeasureValues, MultiReporter, Reporter} from '../../index'; (function() { - function createReporters(ids: any[]) { - const r = Injector - .create([ - ids.map(id => ({provide: id, useValue: new MockReporter(id)})), - MultiReporter.provideWith(ids) - ]) - .get<MultiReporter>(MultiReporter); - return Promise.resolve(r); - } - - describe('multi reporter', () => { - - it('should reportMeasureValues to all', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const mv = new MeasureValues(0, new Date(), {}); - createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => { - - expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]); - async.done(); - }); - })); - - it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - const completeSample = - [new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})]; - const validSample = [completeSample[1]]; +function createReporters(ids: any[]) { + const r = Injector + .create([ + ids.map(id => ({provide: id, useValue: new MockReporter(id)})), + MultiReporter.provideWith(ids) + ]) + .get<MultiReporter>(MultiReporter); + return Promise.resolve(r); +} - createReporters(['m1', 'm2']) - .then((r) => r.reportSample(completeSample, validSample)) - .then((values) => { +describe('multi reporter', () => { + it('should reportMeasureValues to all', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const mv = new MeasureValues(0, new Date(), {}); + createReporters(['m1', 'm2']).then((r) => r.reportMeasureValues(mv)).then((values) => { + expect(values).toEqual([{'id': 'm1', 'values': mv}, {'id': 'm2', 'values': mv}]); + async.done(); + }); + })); - expect(values).toEqual([ - {'id': 'm1', 'completeSample': completeSample, 'validSample': validSample}, - {'id': 'm2', 'completeSample': completeSample, 'validSample': validSample} - ]); - async.done(); - }); - })); + it('should reportSample to call', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const completeSample = + [new MeasureValues(0, new Date(), {}), new MeasureValues(1, new Date(), {})]; + const validSample = [completeSample[1]]; - }); + createReporters(['m1', 'm2']) + .then((r) => r.reportSample(completeSample, validSample)) + .then((values) => { + expect(values).toEqual([ + {'id': 'm1', 'completeSample': completeSample, 'validSample': validSample}, + {'id': 'm2', 'completeSample': completeSample, 'validSample': validSample} + ]); + async.done(); + }); + })); +}); })(); class MockReporter extends Reporter { - constructor(private _id: string) { super(); } + constructor(private _id: string) { + super(); + } reportMeasureValues(values: MeasureValues): Promise<{[key: string]: any}> { return Promise.resolve({'id': this._id, 'values': values}); diff --git a/packages/benchpress/test/runner_spec.ts b/packages/benchpress/test/runner_spec.ts index 3487b5988eb52..87cd2710c952f 100644 --- a/packages/benchpress/test/runner_spec.ts +++ b/packages/benchpress/test/runner_spec.ts @@ -8,7 +8,7 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal'; -import {Injector, Metric, Options, Runner, SampleDescription, SampleState, Sampler, Validator, WebDriverAdapter} from '../index'; +import {Injector, Metric, Options, Runner, SampleDescription, Sampler, SampleState, Validator, WebDriverAdapter} from '../index'; { describe('runner', () => { @@ -68,7 +68,6 @@ import {Injector, Metric, Options, Runner, SampleDescription, SampleState, Sampl .sample({id: 'someId'}) .then((_) => injector.get(SampleDescription)) .then((desc) => { - expect(desc.metrics).toEqual({'m1': 'some metric'}); async.done(); }); @@ -109,32 +108,45 @@ import {Injector, Metric, Options, Runner, SampleDescription, SampleState, Sampl }) .then((_) => injector.get(SampleDescription)) .then((desc) => { - expect(desc.description['a']).toBe(2); async.done(); }); - })); - }); } class MockWebDriverAdapter extends WebDriverAdapter { - executeScript(script: string): Promise<string> { return Promise.resolve('someUserAgent'); } - capabilities(): Promise<Map<string, any>> { return null !; } + executeScript(script: string): Promise<string> { + return Promise.resolve('someUserAgent'); + } + capabilities(): Promise<Map<string, any>> { + return null!; + } } class MockValidator extends Validator { - constructor() { super(); } - describe() { return {'v': 11}; } + constructor() { + super(); + } + describe() { + return {'v': 11}; + } } class MockMetric extends Metric { - constructor() { super(); } - describe() { return {'m1': 'some metric'}; } + constructor() { + super(); + } + describe() { + return {'m1': 'some metric'}; + } } class MockSampler extends Sampler { - constructor() { super(null !, null !, null !, null !, null !, null !, null !); } - sample(): Promise<SampleState> { return Promise.resolve(new SampleState([], [])); } + constructor() { + super(null!, null!, null!, null!, null!, null!, null!); + } + sample(): Promise<SampleState> { + return Promise.resolve(new SampleState([], [])); + } } diff --git a/packages/benchpress/test/sampler_spec.ts b/packages/benchpress/test/sampler_spec.ts index 9b1b7864e38d6..ec416c8d0f468 100644 --- a/packages/benchpress/test/sampler_spec.ts +++ b/packages/benchpress/test/sampler_spec.ts @@ -67,7 +67,6 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, expect(log).toEqual([0, 1, 2, 3]); async.done(); }); - })); it('should call prepare, beginMeasure, execute, endMeasure for every iteration', @@ -77,8 +76,12 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, createSampler({ metric: createCountingMetric(log), validator: createCountingValidator(2), - prepare: () => { log.push(`p${workCount++}`); }, - execute: () => { log.push(`w${workCount++}`); } + prepare: () => { + log.push(`p${workCount++}`); + }, + execute: () => { + log.push(`w${workCount++}`); + } }); sampler.sample().then((_) => { expect(log).toEqual([ @@ -102,7 +105,9 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, createSampler({ metric: createCountingMetric(log), validator: createCountingValidator(2), - execute: () => { log.push(`w${workCount++}`); }, + execute: () => { + log.push(`w${workCount++}`); + }, prepare: null }); sampler.sample().then((_) => { @@ -130,7 +135,9 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, scriptTime = 0; return result; }), - prepare: () => { scriptTime = 1 * iterationCount; }, + prepare: () => { + scriptTime = 1 * iterationCount; + }, execute: () => { scriptTime = 10 * iterationCount; iterationCount++; @@ -147,7 +154,7 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, it('should call the validator for every execution and store the valid sample', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const log: any[] = []; - const validSample = [mv(null !, null !, {})]; + const validSample = [mv(null!, null!, {})]; createSampler({ metric: createCountingMetric(), @@ -174,7 +181,7 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, it('should report the metric values', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const log: any[] = []; - const validSample = [mv(null !, null !, {})]; + const validSample = [mv(null!, null!, {})]; createSampler({ validator: createCountingValidator(2, validSample), metric: createCountingMetric(), @@ -198,7 +205,6 @@ import {Injector, MeasureValues, Metric, Options, Reporter, Sampler, Validator, async.done(); }); })); - }); } @@ -223,7 +229,9 @@ function createCountingMetric(log: any[] = []) { } class MockDriverAdapter extends WebDriverAdapter { - constructor(private _log: any[] = [], private _waitFor: Function|null = null) { super(); } + constructor(private _log: any[] = [], private _waitFor: Function|null = null) { + super(); + } waitFor(callback: Function): Promise<any> { if (this._waitFor != null) { return this._waitFor(callback); @@ -235,7 +243,9 @@ class MockDriverAdapter extends WebDriverAdapter { class MockValidator extends Validator { - constructor(private _log: any[] = [], private _validate: Function|null = null) { super(); } + constructor(private _log: any[] = [], private _validate: Function|null = null) { + super(); + } validate(completeSample: MeasureValues[]): MeasureValues[] { const stableSample = this._validate != null ? this._validate(completeSample) : completeSample; this._log.push(['validate', completeSample, stableSample]); @@ -244,7 +254,9 @@ class MockValidator extends Validator { } class MockMetric extends Metric { - constructor(private _log: any[] = [], private _endMeasure: Function|null = null) { super(); } + constructor(private _log: any[] = [], private _endMeasure: Function|null = null) { + super(); + } beginMeasure() { this._log.push(['beginMeasure']); return Promise.resolve(null); @@ -257,7 +269,9 @@ class MockMetric extends Metric { } class MockReporter extends Reporter { - constructor(private _log: any[] = []) { super(); } + constructor(private _log: any[] = []) { + super(); + } reportMeasureValues(values: MeasureValues): Promise<any> { this._log.push(['reportMeasureValues', values]); return Promise.resolve(null); diff --git a/packages/benchpress/test/statistic_spec.ts b/packages/benchpress/test/statistic_spec.ts index efbeaa8766723..9f8a90b5cadc0 100644 --- a/packages/benchpress/test/statistic_spec.ts +++ b/packages/benchpress/test/statistic_spec.ts @@ -11,7 +11,6 @@ import {Statistic} from '../src/statistic'; { describe('statistic', () => { - it('should calculate the mean', () => { expect(Statistic.calculateMean([])).toBeNaN(); expect(Statistic.calculateMean([1, 2, 3])).toBe(2.0); @@ -34,6 +33,5 @@ import {Statistic} from '../src/statistic'; expect(Statistic.calculateRegressionSlope([1], 1, [2], 2)).toBeNaN(); expect(Statistic.calculateRegressionSlope([1, 2], 1.5, [2, 4], 3)).toBe(2.0); }); - }); } diff --git a/packages/benchpress/test/trace_event_factory.ts b/packages/benchpress/test/trace_event_factory.ts index 11ce4c0b53151..e687f2b0a2092 100644 --- a/packages/benchpress/test/trace_event_factory.ts +++ b/packages/benchpress/test/trace_event_factory.ts @@ -20,13 +20,21 @@ export class TraceEventFactory { return res; } - markStart(name: string, time: number) { return this.create('B', name, time); } + markStart(name: string, time: number) { + return this.create('B', name, time); + } - markEnd(name: string, time: number) { return this.create('E', name, time); } + markEnd(name: string, time: number) { + return this.create('E', name, time); + } - start(name: string, time: number, args: any = null) { return this.create('B', name, time, args); } + start(name: string, time: number, args: any = null) { + return this.create('B', name, time, args); + } - end(name: string, time: number, args: any = null) { return this.create('E', name, time, args); } + end(name: string, time: number, args: any = null) { + return this.create('E', name, time, args); + } instant(name: string, time: number, args: any = null) { return this.create('I', name, time, args); diff --git a/packages/benchpress/test/validator/regression_slope_validator_spec.ts b/packages/benchpress/test/validator/regression_slope_validator_spec.ts index 07cc120cc906d..ceafcca4e3b22 100644 --- a/packages/benchpress/test/validator/regression_slope_validator_spec.ts +++ b/packages/benchpress/test/validator/regression_slope_validator_spec.ts @@ -53,7 +53,6 @@ import {Injector, MeasureValues, RegressionSlopeValidator} from '../../index'; expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2)); expect(validator.validate(sample)).toEqual(sample.slice(1, 3)); }); - }); } diff --git a/packages/benchpress/test/validator/size_validator_spec.ts b/packages/benchpress/test/validator/size_validator_spec.ts index 782b36ab1f250..aa809412bfe91 100644 --- a/packages/benchpress/test/validator/size_validator_spec.ts +++ b/packages/benchpress/test/validator/size_validator_spec.ts @@ -39,7 +39,6 @@ import {Injector, MeasureValues, SizeValidator} from '../../index'; expect(validator.validate(sample.slice(0, 2))).toEqual(sample.slice(0, 2)); expect(validator.validate(sample)).toEqual(sample.slice(1, 3)); }); - }); } diff --git a/packages/benchpress/test/web_driver_extension_spec.ts b/packages/benchpress/test/web_driver_extension_spec.ts index 907c464eaad5c..8ec00b4355276 100644 --- a/packages/benchpress/test/web_driver_extension_spec.ts +++ b/packages/benchpress/test/web_driver_extension_spec.ts @@ -11,44 +11,45 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/te import {Injector, Options, WebDriverExtension} from '../index'; (function() { - function createExtension(ids: any[], caps: any) { - return new Promise<any>((res, rej) => { - try { - res(Injector - .create([ - ids.map((id) => ({provide: id, useValue: new MockExtension(id)})), - {provide: Options.CAPABILITIES, useValue: caps}, - WebDriverExtension.provideFirstSupported(ids) - ]) - .get(WebDriverExtension)); - } catch (e) { - rej(e); - } - }); - } - - describe('WebDriverExtension.provideFirstSupported', () => { - - it('should provide the extension that matches the capabilities', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => { - expect(m.id).toEqual('m2'); - async.done(); - }); - })); - - it('should throw if there is no match', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createExtension(['m1'], {'browser': 'm2'}).catch((err) => { - expect(err != null).toBe(true); - async.done(); - }); - })); +function createExtension(ids: any[], caps: any) { + return new Promise<any>((res, rej) => { + try { + res(Injector + .create([ + ids.map((id) => ({provide: id, useValue: new MockExtension(id)})), + {provide: Options.CAPABILITIES, useValue: caps}, + WebDriverExtension.provideFirstSupported(ids) + ]) + .get(WebDriverExtension)); + } catch (e) { + rej(e); + } }); +} + +describe('WebDriverExtension.provideFirstSupported', () => { + it('should provide the extension that matches the capabilities', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + createExtension(['m1', 'm2', 'm3'], {'browser': 'm2'}).then((m) => { + expect(m.id).toEqual('m2'); + async.done(); + }); + })); + + it('should throw if there is no match', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + createExtension(['m1'], {'browser': 'm2'}).catch((err) => { + expect(err != null).toBe(true); + async.done(); + }); + })); +}); })(); class MockExtension extends WebDriverExtension { - constructor(public id: string) { super(); } + constructor(public id: string) { + super(); + } supports(capabilities: {[key: string]: any}): boolean { return capabilities['browser'] === this.id; diff --git a/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts b/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts index 988352345cdd2..1e353a05b257e 100644 --- a/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts +++ b/packages/benchpress/test/webdriver/chrome_driver_extension_spec.ts @@ -32,7 +32,7 @@ import {TraceEventFactory} from '../trace_event_factory'; const normEvents = new TraceEventFactory('timeline', 'pid0'); function createExtension( - perfRecords: any[] | null = null, userAgent: string | null = null, + perfRecords: any[]|null = null, userAgent: string|null = null, messageMethod = 'Tracing.dataCollected'): WebDriverExtension { if (!perfRecords) { perfRecords = []; @@ -97,9 +97,9 @@ import {TraceEventFactory} from '../trace_event_factory'; it('should mark the timeline via performance.mark() with start and end of a test', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { createExtension().timeEnd('name1', 'name2').then((_) => { - expect(log).toEqual([[ - 'executeScript', `performance.mark('name1-bpend');performance.mark('name2-bpstart');` - ]]); + expect(log).toEqual([ + ['executeScript', `performance.mark('name1-bpend');performance.mark('name2-bpstart');`] + ]); async.done(); }); })); @@ -173,7 +173,8 @@ import {TraceEventFactory} from '../trace_event_factory'; [ chromeTimelineV8Events.start('MajorGC', 1000, {'usedHeapSizeBefore': 1000}), chromeTimelineV8Events.end('MajorGC', 2000, {'usedHeapSizeAfter': 0}), - ], ) + ], + ) .readPerfLog() .then((events) => { expect(events.length).toEqual(2); @@ -192,7 +193,8 @@ import {TraceEventFactory} from '../trace_event_factory'; [ chrome45TimelineEvents.start(recordType, 1234), chrome45TimelineEvents.end(recordType, 2345) - ], ) + ], + ) .readPerfLog() .then((events) => { expect(events).toEqual([ @@ -210,7 +212,8 @@ import {TraceEventFactory} from '../trace_event_factory'; [ chromeBlinkTimelineEvents.start('UpdateLayoutTree', 1234), chromeBlinkTimelineEvents.end('UpdateLayoutTree', 2345) - ], ) + ], + ) .readPerfLog() .then((events) => { expect(events).toEqual([ @@ -254,8 +257,10 @@ import {TraceEventFactory} from '../trace_event_factory'; })); it('should report receivedData', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createExtension([chrome45TimelineEvents.instant( - 'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})], ) + createExtension( + [chrome45TimelineEvents.instant( + 'ResourceReceivedData', 1234, {'data': {'encodedDataLength': 987}})], + ) .readPerfLog() .then((events) => { expect(events).toEqual( @@ -265,9 +270,11 @@ import {TraceEventFactory} from '../trace_event_factory'; })); it('should report sendRequest', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createExtension([chrome45TimelineEvents.instant( - 'ResourceSendRequest', 1234, - {'data': {'url': 'http://here', 'requestMethod': 'GET'}})], ) + createExtension( + [chrome45TimelineEvents.instant( + 'ResourceSendRequest', 1234, + {'data': {'url': 'http://here', 'requestMethod': 'GET'}})], + ) .readPerfLog() .then((events) => { expect(events).toEqual([normEvents.instant( @@ -277,7 +284,6 @@ import {TraceEventFactory} from '../trace_event_factory'; })); describe('readPerfLog (common)', () => { - it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { // TODO(tbosch): This seems to be a bug in ChromeDriver: @@ -296,7 +302,8 @@ import {TraceEventFactory} from '../trace_event_factory'; [ chromeTimelineEvents.start(recordType, 1234), chromeTimelineEvents.end(recordType, 2345) - ], ) + ], + ) .readPerfLog() .then((events) => { expect(events).toEqual([ @@ -337,7 +344,6 @@ import {TraceEventFactory} from '../trace_event_factory'; it('should throw when ImplThreadRenderingStats contains more than one frame', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createExtension([benchmarkEvents.instant( 'BenchmarkInstrumentation::ImplThreadRenderingStats', 1100, {'data': {'frame_count': 2}})]) @@ -349,7 +355,6 @@ import {TraceEventFactory} from '../trace_event_factory'; async.done(); }); })); - }); it('should report begin timestamps', @@ -374,7 +379,6 @@ import {TraceEventFactory} from '../trace_event_factory'; it('should throw an error on buffer overflow', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - createExtension( [ chromeTimelineEvents.start('FunctionCall', 1234), @@ -394,9 +398,7 @@ import {TraceEventFactory} from '../trace_event_factory'; expect(createExtension().supports({'browserName': 'Chrome'})).toBe(true); }); - }); - }); } @@ -419,7 +421,7 @@ class MockDriverAdapter extends WebDriverAdapter { {'message': {'method': this._messageMethod, 'params': event}}, null, 2) }))); } else { - return null !; + return null!; } } } diff --git a/packages/benchpress/test/webdriver/ios_driver_extension_spec.ts b/packages/benchpress/test/webdriver/ios_driver_extension_spec.ts index f2edbc774015f..6e7e6de0289f1 100644 --- a/packages/benchpress/test/webdriver/ios_driver_extension_spec.ts +++ b/packages/benchpress/test/webdriver/ios_driver_extension_spec.ts @@ -8,7 +8,7 @@ import {AsyncTestCompleter, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal'; -import {IOsDriverExtension, Injector, WebDriverAdapter, WebDriverExtension} from '../../index'; +import {Injector, IOsDriverExtension, WebDriverAdapter, WebDriverExtension} from '../../index'; import {TraceEventFactory} from '../trace_event_factory'; { @@ -18,7 +18,7 @@ import {TraceEventFactory} from '../trace_event_factory'; const normEvents = new TraceEventFactory('timeline', 'pid0'); - function createExtension(perfRecords: any[] | null = null): WebDriverExtension { + function createExtension(perfRecords: any[]|null = null): WebDriverExtension { if (!perfRecords) { perfRecords = []; } @@ -63,7 +63,6 @@ import {TraceEventFactory} from '../trace_event_factory'; })); describe('readPerfLog', () => { - it('should execute a dummy script before reading them', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { // TODO(tbosch): This seems to be a bug in ChromeDriver: @@ -140,9 +139,7 @@ import {TraceEventFactory} from '../trace_event_factory'; expect(createExtension().supports({'browserName': 'Safari'})).toBe(true); }); - }); - }); } @@ -155,7 +152,7 @@ function timeEndRecord(name: string, time: number) { } function durationRecord( - type: string, startTime: number, endTime: number, children: any[] | null = null) { + type: string, startTime: number, endTime: number, children: any[]|null = null) { if (!children) { children = []; } @@ -172,7 +169,9 @@ function internalScriptRecord(startTime: number, endTime: number) { } class MockDriverAdapter extends WebDriverAdapter { - constructor(private _log: any[], private _perfRecords: any[]) { super(); } + constructor(private _log: any[], private _perfRecords: any[]) { + super(); + } executeScript(script: string) { this._log.push(['executeScript', script]); @@ -190,7 +189,7 @@ class MockDriverAdapter extends WebDriverAdapter { }; })); } else { - return null !; + return null!; } } } diff --git a/packages/common/http/src/client.ts b/packages/common/http/src/client.ts index 275fc69a77508..6814034f8b46e 100644 --- a/packages/common/http/src/client.ts +++ b/packages/common/http/src/client.ts @@ -7,7 +7,7 @@ */ import {Injectable} from '@angular/core'; -import {Observable, of } from 'rxjs'; +import {Observable, of} from 'rxjs'; import {concatMap, filter, map} from 'rxjs/operators'; import {HttpHandler} from './backend'; @@ -29,14 +29,14 @@ import {HttpEvent, HttpResponse} from './response'; */ function addBody<T>( options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, - params?: HttpParams | {[param: string]: string | string[]}, + params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, - responseType?: 'arraybuffer' | 'blob' | 'json' | 'text', + responseType?: 'arraybuffer'|'blob'|'json'|'text', withCredentials?: boolean, }, - body: T | null): any { + body: T|null): any { return { body, headers: options.headers, @@ -48,7 +48,7 @@ function addBody<T>( }; } -export type HttpObserve = 'body' | 'events' | 'response'; +export type HttpObserve = 'body'|'events'|'response'; /** * Performs HTTP requests. @@ -108,8 +108,8 @@ export class HttpClient { request<R>(req: HttpRequest<any>): Observable<HttpEvent<R>>; /** - * Constructs a request that interprets the body as an `ArrayBuffer` and returns the response in an - * `ArrayBuffer`. + * Constructs a request that interprets the body as an `ArrayBuffer` and returns the response in + * an `ArrayBuffer`. * * @param method The HTTP method. * @param url The endpoint URL. @@ -123,8 +123,8 @@ export class HttpClient { headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -142,8 +142,8 @@ export class HttpClient { headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -161,8 +161,8 @@ export class HttpClient { headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -173,15 +173,16 @@ export class HttpClient { * @param url The endpoint URL. * @param options The HTTP options to send with the request. * - * @return An `Observable` of the response, with the response body as an array of `HTTPEvents` for the + * @return An `Observable` of the response, with the response body as an array of `HTTPEvents` for + * the * request. */ request(method: string, url: string, options: { body?: any, headers?: HttpHeaders|{[header: string]: string | string[]}, - params?: HttpParams|{[param: string]: string | string[]}, - observe: 'events', reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + params?: HttpParams|{[param: string]: string | string[]}, observe: 'events', + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -197,15 +198,15 @@ export class HttpClient { */ request(method: string, url: string, options: { body?: any, - headers?: HttpHeaders|{[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** - * Constructs a request which interprets the body as a text string and returns the full event stream. + * Constructs a request which interprets the body as a text string and returns the full event + * stream. * * @param method The HTTP method. * @param url The endpoint URL. @@ -216,15 +217,15 @@ export class HttpClient { */ request(method: string, url: string, options: { body?: any, - headers?: HttpHeaders|{[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** - * Constructs a request which interprets the body as a JSON object and returns the full event stream. + * Constructs a request which interprets the body as a JSON object and returns the full event + * stream. * * @param method The HTTP method. * @param url The endpoint URL. @@ -236,15 +237,15 @@ export class HttpClient { request(method: string, url: string, options: { body?: any, headers?: HttpHeaders|{[header: string]: string | string[]}, - reportProgress?: boolean, - observe: 'events', + reportProgress?: boolean, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, responseType?: 'json', withCredentials?: boolean, }): Observable<HttpEvent<any>>; /** - * Constructs a request which interprets the body as a JSON object and returns the full event stream. + * Constructs a request which interprets the body as a JSON object and returns the full event + * stream. * * @param method The HTTP method. * @param url The endpoint URL. @@ -256,8 +257,7 @@ export class HttpClient { request<R>(method: string, url: string, options: { body?: any, headers?: HttpHeaders|{[header: string]: string | string[]}, - reportProgress?: boolean, - observe: 'events', + reportProgress?: boolean, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, responseType?: 'json', withCredentials?: boolean, @@ -275,11 +275,10 @@ export class HttpClient { */ request(method: string, url: string, options: { body?: any, - headers?: HttpHeaders|{[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -293,15 +292,15 @@ export class HttpClient { */ request(method: string, url: string, options: { body?: any, - headers?: HttpHeaders|{[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** - * Constructs a request which interprets the body as a text stream and returns the full `HTTPResponse`. + * Constructs a request which interprets the body as a text stream and returns the full + * `HTTPResponse`. * * @param method The HTTP method. * @param url The endpoint URL. @@ -311,15 +310,15 @@ export class HttpClient { */ request(method: string, url: string, options: { body?: any, - headers?: HttpHeaders|{[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** - * Constructs a request which interprets the body as a JSON object and returns the full `HTTPResponse`. + * Constructs a request which interprets the body as a JSON object and returns the full + * `HTTPResponse`. * * @param method The HTTP method. * @param url The endpoint URL. @@ -331,8 +330,7 @@ export class HttpClient { request(method: string, url: string, options: { body?: any, headers?: HttpHeaders|{[header: string]: string | string[]}, - reportProgress?: boolean, - observe: 'response', + reportProgress?: boolean, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, responseType?: 'json', withCredentials?: boolean, @@ -351,8 +349,7 @@ export class HttpClient { request<R>(method: string, url: string, options: { body?: any, headers?: HttpHeaders|{[header: string]: string | string[]}, - reportProgress?: boolean, - observe: 'response', + reportProgress?: boolean, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, responseType?: 'json', withCredentials?: boolean, @@ -477,12 +474,12 @@ export class HttpClient { if (options.params instanceof HttpParams) { params = options.params; } else { - params = new HttpParams({ fromObject: options.params } as HttpParamsOptions); + params = new HttpParams({fromObject: options.params} as HttpParamsOptions); } } // Construct the request. - req = new HttpRequest(first, url !, (options.body !== undefined ? options.body : null), { + req = new HttpRequest(first, url!, (options.body !== undefined ? options.body : null), { headers, params, reportProgress: options.reportProgress, @@ -497,7 +494,7 @@ export class HttpClient { // inside an Observable chain, which causes interceptors to be re-run on every // subscription (this also makes retries re-run the handler, including interceptors). const events$: Observable<HttpEvent<any>> = - of (req).pipe(concatMap((req: HttpRequest<any>) => this.handler.handle(req))); + of(req).pipe(concatMap((req: HttpRequest<any>) => this.handler.handle(req))); // If coming via the API signature which accepts a previously constructed HttpRequest, // the only option is to get the event stream. Otherwise, return the event stream if @@ -568,12 +565,12 @@ export class HttpClient { * * @return An `Observable` of the response body as an `ArrayBuffer`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; @@ -586,12 +583,12 @@ export class HttpClient { * * @return An `Observable` of the response body as a `Blob`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -603,12 +600,12 @@ export class HttpClient { * * @return An `Observable` of the response, with the response body of type string. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -621,12 +618,11 @@ export class HttpClient { * @return An `Observable` of all `HTTPEvents` for the request, * with response body as an `ArrayBuffer`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -639,12 +635,11 @@ export class HttpClient { * @return An `Observable` of all the `HTTPEvents` for the request, with the response body as a * `Blob`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** @@ -657,12 +652,11 @@ export class HttpClient { * @return An `Observable` of all `HTTPEvents` for the request, with the response * body of type string. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** @@ -675,9 +669,8 @@ export class HttpClient { * @return An `Observable` of all `HTTPEvents` for the request, with response body of * type `Object`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -695,8 +688,7 @@ export class HttpClient { * body in the requested type. */ delete<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -712,12 +704,11 @@ export class HttpClient { * * @return An `Observable` of the full `HTTPResponse`, with the response body as an `ArrayBuffer`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -729,12 +720,11 @@ export class HttpClient { * * @return An `Observable` of the `HTTPResponse`, with the response body of type `Blob`. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -746,12 +736,11 @@ export class HttpClient { * * @return An `Observable` of the full `HTTPResponse`, with the response body of type string. */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** @@ -764,9 +753,8 @@ export class HttpClient { * @return An `Observable` of the `HTTPResponse`, with the response body of type `Object`. * */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -783,8 +771,7 @@ export class HttpClient { * @return An `Observable` of the `HTTPResponse`, with the response body of the requested type. */ delete<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -800,8 +787,8 @@ export class HttpClient { * * @return An `Observable` of the response, with the response body of type `Object`. */ - delete (url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + delete(url: string, options?: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -819,7 +806,7 @@ export class HttpClient { * @return An `Observable` of the `HTTPResponse`, with response body in the requested type. */ delete<T>(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -836,8 +823,8 @@ export class HttpClient { * @param options The HTTP options to send with the request. * */ - delete (url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + delete(url: string, options: { + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -849,8 +836,8 @@ export class HttpClient { /** - * Constructs a `GET` request that interprets the body as an `ArrayBuffer` and returns the response in - * an `ArrayBuffer`. + * Constructs a `GET` request that interprets the body as an `ArrayBuffer` and returns the + * response in an `ArrayBuffer`. * * @param url The endpoint URL. * @param options The HTTP options to send with the request. @@ -858,11 +845,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as an `ArrayBuffer`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -875,11 +862,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a `Blob`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -892,11 +879,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body of type string. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -910,11 +897,10 @@ export class HttpClient { * body as an `ArrayBuffer`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -927,11 +913,10 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a `Blob`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** @@ -944,11 +929,10 @@ export class HttpClient { * @return An `Observable` of the response, with the response body of type string. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** @@ -961,8 +945,7 @@ export class HttpClient { * @return An `Observable` of the response, with the response body of type `Object`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -970,7 +953,8 @@ export class HttpClient { }): Observable<HttpEvent<Object>>; /** - * Constructs a `GET` request that interprets the body as a JSON object and returns the full event stream. + * Constructs a `GET` request that interprets the body as a JSON object and returns the full event + * stream. * * @param url The endpoint URL. * @param options The HTTP options to send with the request. @@ -978,8 +962,7 @@ export class HttpClient { * @return An `Observable` of the response, with a response body in the requested type. */ get<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -997,11 +980,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -1015,11 +997,10 @@ export class HttpClient { * with the response body as a `Blob`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -1033,11 +1014,10 @@ export class HttpClient { * with the response body of type string. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** @@ -1051,8 +1031,7 @@ export class HttpClient { * with the response body of type `Object`. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1070,8 +1049,7 @@ export class HttpClient { * with a response body in the requested type. */ get<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1089,7 +1067,7 @@ export class HttpClient { * @return An `Observable` of the response body as a JSON object. */ get(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1107,7 +1085,7 @@ export class HttpClient { * @return An `Observable` of the `HTTPResponse`, with a response body in the requested type. */ get<T>(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1121,7 +1099,7 @@ export class HttpClient { * details on the return type. */ get(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1142,11 +1120,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as an `ArrayBuffer`. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -1160,11 +1138,11 @@ export class HttpClient { */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -1177,11 +1155,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body of type string. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -1195,11 +1173,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -1213,11 +1190,10 @@ export class HttpClient { * with the response body as a `Blob`. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** @@ -1227,14 +1203,14 @@ export class HttpClient { * @param url The endpoint URL. * @param options The HTTP options to send with the request. * - * @return An `Observable` of all HttpEvents for the request, with the response body of type string. + * @return An `Observable` of all HttpEvents for the request, with the response body of type + * string. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** @@ -1248,8 +1224,7 @@ export class HttpClient { * type `Object`. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1267,8 +1242,7 @@ export class HttpClient { * @param options The HTTP options to send with the request. */ head<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1286,11 +1260,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -1304,11 +1277,10 @@ export class HttpClient { * with the response body as a blob. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -1322,11 +1294,10 @@ export class HttpClient { * with the response body of type string. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** @@ -1340,8 +1311,7 @@ export class HttpClient { * with the response body of type `Object`. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1359,8 +1329,7 @@ export class HttpClient { * with a responmse body of the requested type. */ head<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1377,7 +1346,7 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a JSON object. */ head(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1396,7 +1365,7 @@ export class HttpClient { * with a response body of the given type. */ head<T>(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1412,7 +1381,7 @@ export class HttpClient { * details on the return type. */ head(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1482,11 +1451,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as an `ArrayBuffer`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -1499,11 +1468,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a `Blob`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -1516,11 +1485,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body of type string. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -1534,11 +1503,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -1552,11 +1520,10 @@ export class HttpClient { * with the response body as a `Blob`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** @@ -1570,11 +1537,10 @@ export class HttpClient { * with the response body of type string. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** @@ -1588,8 +1554,7 @@ export class HttpClient { * body of type `Object`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1607,8 +1572,7 @@ export class HttpClient { * with a response body in the requested type. */ options<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1626,11 +1590,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -1644,11 +1607,10 @@ export class HttpClient { * with the response body as a `Blob`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -1662,11 +1624,10 @@ export class HttpClient { * with the response body of type string. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** @@ -1680,8 +1641,7 @@ export class HttpClient { * with the response body of type `Object`. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1699,8 +1659,7 @@ export class HttpClient { * with a response body in the requested type. */ options<T>(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1708,8 +1667,8 @@ export class HttpClient { }): Observable<HttpResponse<T>>; /** - * Constructs an `OPTIONS` request that interprets the body as a JSON object and returns the response - * body as a JSON object. + * Constructs an `OPTIONS` request that interprets the body as a JSON object and returns the + * response body as a JSON object. * * @param url The endpoint URL. * @param options HTTP options. @@ -1717,7 +1676,7 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a JSON object. */ options(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1726,8 +1685,8 @@ export class HttpClient { }): Observable<Object>; /** - * Constructs an `OPTIONS` request that interprets the body as a JSON object and returns the response - * in a given type. + * Constructs an `OPTIONS` request that interprets the body as a JSON object and returns the + * response in a given type. * * @param url The endpoint URL. * @param options HTTP options. @@ -1735,7 +1694,7 @@ export class HttpClient { * @return An `Observable` of the `HTTPResponse`, with a response body of the given type. */ options<T>(url: string, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1751,7 +1710,7 @@ export class HttpClient { * details on the return type. */ options(url: string, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -1772,11 +1731,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as an `ArrayBuffer`. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -1790,11 +1749,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a `Blob`. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -1808,11 +1767,11 @@ export class HttpClient { * @return An `Observable` of the response, with a response body of type string. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -1828,11 +1787,10 @@ export class HttpClient { */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -1847,11 +1805,10 @@ export class HttpClient { * response body as `Blob`. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** @@ -1866,11 +1823,10 @@ export class HttpClient { * response body of type string. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** @@ -1885,8 +1841,7 @@ export class HttpClient { * with a response body of type `Object`. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1905,8 +1860,7 @@ export class HttpClient { * with a response body in the requested type. */ patch<T>(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -1925,11 +1879,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -1944,11 +1897,10 @@ export class HttpClient { * with the response body as a `Blob`. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -1963,11 +1915,10 @@ export class HttpClient { * with a response body of type string. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** @@ -1982,8 +1933,7 @@ export class HttpClient { * with a response body in the requested type. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2002,8 +1952,7 @@ export class HttpClient { * with a response body in the given type. */ patch<T>(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2021,7 +1970,7 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a JSON object. */ patch(url: string, body: any|null, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2041,7 +1990,7 @@ export class HttpClient { * with a response body in the given type. */ patch<T>(url: string, body: any|null, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2055,7 +2004,7 @@ export class HttpClient { * details on the return type. */ patch(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2076,11 +2025,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as an `ArrayBuffer`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -2094,11 +2043,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a `Blob`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -2112,11 +2061,11 @@ export class HttpClient { * @return An `Observable` of the response, with a response body of type string. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -2131,11 +2080,10 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** @@ -2149,15 +2097,15 @@ export class HttpClient { * @return An `Observable` of all `HttpEvents` for the request, with the response body as `Blob`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** - * Constructs a `POST` request that interprets the body as a text string and returns the full event stream. + * Constructs a `POST` request that interprets the body as a text string and returns the full + * event stream. * * @param url The endpoint URL. * @param body The content to replace with. @@ -2167,15 +2115,15 @@ export class HttpClient { * with a response body of type string. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** - * Constructs a POST request that interprets the body as a JSON object and returns the full event stream. + * Constructs a POST request that interprets the body as a JSON object and returns the full event + * stream. * * @param url The endpoint URL. * @param body The content to replace with. @@ -2185,8 +2133,7 @@ export class HttpClient { * with a response body of type `Object`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2194,7 +2141,8 @@ export class HttpClient { }): Observable<HttpEvent<Object>>; /** - * Constructs a POST request that interprets the body as a JSON object and returns the full event stream. + * Constructs a POST request that interprets the body as a JSON object and returns the full event + * stream. * * @param url The endpoint URL. * @param body The content to replace with. @@ -2204,8 +2152,7 @@ export class HttpClient { * with a response body in the requested type. */ post<T>(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2220,14 +2167,14 @@ export class HttpClient { * @param body The content to replace with. * @param options HTTP options * - * @return An `Observable` of the `HTTPResponse` for the request, with the response body as an `ArrayBuffer`. + * @return An `Observable` of the `HTTPResponse` for the request, with the response body as an + * `ArrayBuffer`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -2242,11 +2189,10 @@ export class HttpClient { * with the response body as a `Blob`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -2261,11 +2207,10 @@ export class HttpClient { * with a response body of type string. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** @@ -2280,8 +2225,7 @@ export class HttpClient { * `Object`. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2297,11 +2241,11 @@ export class HttpClient { * @param body The content to replace with. * @param options HTTP options * - * @return An `Observable` of the `HTTPResponse` for the request, with a response body in the requested type. + * @return An `Observable` of the `HTTPResponse` for the request, with a response body in the + * requested type. */ post<T>(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2319,7 +2263,7 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a JSON object. */ post(url: string, body: any|null, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2335,10 +2279,11 @@ export class HttpClient { * @param body The content to replace with. * @param options HTTP options * - * @return An `Observable` of the `HTTPResponse` for the request, with a response body in the requested type. + * @return An `Observable` of the `HTTPResponse` for the request, with a response body in the + * requested type. */ post<T>(url: string, body: any|null, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2353,7 +2298,7 @@ export class HttpClient { * details on the return type. */ post(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2374,11 +2319,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as an `ArrayBuffer`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<ArrayBuffer>; /** @@ -2392,11 +2337,11 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a `Blob`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<Blob>; /** @@ -2410,11 +2355,11 @@ export class HttpClient { * @return An `Observable` of the response, with a response body of type string. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<string>; /** @@ -2429,15 +2374,15 @@ export class HttpClient { * with the response body as an `ArrayBuffer`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpEvent<ArrayBuffer>>; /** - * Constructs a `PUT` request that interprets the body as a `Blob` and returns the full event stream. + * Constructs a `PUT` request that interprets the body as a `Blob` and returns the full event + * stream. * * @param url The endpoint URL. * @param body The resources to add/update. @@ -2447,15 +2392,15 @@ export class HttpClient { * with the response body as a `Blob`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpEvent<Blob>>; /** - * Constructs a `PUT` request that interprets the body as a text string and returns the full event stream. + * Constructs a `PUT` request that interprets the body as a text string and returns the full event + * stream. * * @param url The endpoint URL. * @param body The resources to add/update. @@ -2465,15 +2410,15 @@ export class HttpClient { * of type string. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpEvent<string>>; /** - * Constructs a `PUT` request that interprets the body as a JSON object and returns the full event stream. + * Constructs a `PUT` request that interprets the body as a JSON object and returns the full event + * stream. * * @param url The endpoint URL. * @param body The resources to add/update. @@ -2483,8 +2428,7 @@ export class HttpClient { * type `Object`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2503,8 +2447,9 @@ export class HttpClient { * with a response body in the requested type. */ put<T>(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'events', responseType?: 'json', withCredentials?: boolean, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'events', + responseType?: 'json', + withCredentials?: boolean, }): Observable<HttpEvent<T>>; /** @@ -2515,14 +2460,14 @@ export class HttpClient { * @param body The resources to add/update. * @param options HTTP options * - * @return An `Observable` of the `HTTPResponse` for the request, with the response body as an `ArrayBuffer`. + * @return An `Observable` of the `HTTPResponse` for the request, with the response body as an + * `ArrayBuffer`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'arraybuffer', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'arraybuffer', + withCredentials?: boolean, }): Observable<HttpResponse<ArrayBuffer>>; /** @@ -2537,11 +2482,10 @@ export class HttpClient { * with the response body as a `Blob`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'blob', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'blob', + withCredentials?: boolean, }): Observable<HttpResponse<Blob>>; /** @@ -2552,18 +2496,19 @@ export class HttpClient { * @param body The resources to add/update. * @param options HTTP options * - * @return An `Observable` of the `HTTPResponse` for the request, with a response body of type string. + * @return An `Observable` of the `HTTPResponse` for the request, with a response body of type + * string. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, - reportProgress?: boolean, - responseType: 'text', withCredentials?: boolean, + reportProgress?: boolean, responseType: 'text', + withCredentials?: boolean, }): Observable<HttpResponse<string>>; /** - * Constructs a `PUT` request that interprets the body as a JSON object and returns the full HTTP response. + * Constructs a `PUT` request that interprets the body as a JSON object and returns the full HTTP + * response. * * @param url The endpoint URL. * @param body The resources to add/update. @@ -2573,8 +2518,7 @@ export class HttpClient { * of type 'Object`. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2582,7 +2526,8 @@ export class HttpClient { }): Observable<HttpResponse<Object>>; /** - * Constructs a `PUT` request that interprets the body as a JSON object and returns the full HTTP response. + * Constructs a `PUT` request that interprets the body as a JSON object and returns the full HTTP + * response. * * @param url The endpoint URL. * @param body The resources to add/update. @@ -2592,8 +2537,7 @@ export class HttpClient { * with a response body in the requested type. */ put<T>(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, - observe: 'response', + headers?: HttpHeaders|{[header: string]: string | string[]}, observe: 'response', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, responseType?: 'json', @@ -2611,7 +2555,7 @@ export class HttpClient { * @return An `Observable` of the response, with the response body as a JSON object. */ put(url: string, body: any|null, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2627,10 +2571,11 @@ export class HttpClient { * @param body The resources to add/update. * @param options HTTP options * - * @return An `Observable` of the `HTTPResponse` for the request, with a response body in the requested type. + * @return An `Observable` of the `HTTPResponse` for the request, with a response body in the + * requested type. */ put<T>(url: string, body: any|null, options?: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: 'body', params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, @@ -2645,7 +2590,7 @@ export class HttpClient { * See the individual overloads for details on the return type. */ put(url: string, body: any|null, options: { - headers?: HttpHeaders | {[header: string]: string | string[]}, + headers?: HttpHeaders|{[header: string]: string | string[]}, observe?: HttpObserve, params?: HttpParams|{[param: string]: string | string[]}, reportProgress?: boolean, diff --git a/packages/common/http/src/headers.ts b/packages/common/http/src/headers.ts index a8a006d467e7b..6e187c3adabf7 100755 --- a/packages/common/http/src/headers.ts +++ b/packages/common/http/src/headers.ts @@ -24,7 +24,7 @@ export class HttpHeaders { * Internal map of lowercase header names to values. */ // TODO(issue/24571): remove '!'. - private headers !: Map<string, string[]>; + private headers!: Map<string, string[]>; /** @@ -36,7 +36,7 @@ export class HttpHeaders { /** * Complete the lazy initialization of this object (needed before reading). */ - private lazyInit !: HttpHeaders | Function | null; + private lazyInit!: HttpHeaders|Function|null; /** * Queued updates to be materialized the next initialization. @@ -59,7 +59,7 @@ export class HttpHeaders { const value = line.slice(index + 1).trim(); this.maybeSetNormalizedName(name, key); if (this.headers.has(key)) { - this.headers.get(key) !.push(value); + this.headers.get(key)!.push(value); } else { this.headers.set(key, [value]); } @@ -169,7 +169,7 @@ export class HttpHeaders { * * @returns A clone of the HTTP headers object with the given value deleted. */ - delete (name: string, value?: string|string[]): HttpHeaders { + delete(name: string, value?: string|string[]): HttpHeaders { return this.clone({name, value, op: 'd'}); } @@ -197,8 +197,8 @@ export class HttpHeaders { private copyFrom(other: HttpHeaders) { other.init(); Array.from(other.headers.keys()).forEach(key => { - this.headers.set(key, other.headers.get(key) !); - this.normalizedNames.set(key, other.normalizedNames.get(key) !); + this.headers.set(key, other.headers.get(key)!); + this.normalizedNames.set(key, other.normalizedNames.get(key)!); }); } @@ -215,7 +215,7 @@ export class HttpHeaders { switch (update.op) { case 'a': case 's': - let value = update.value !; + let value = update.value!; if (typeof value === 'string') { value = [value]; } @@ -255,6 +255,6 @@ export class HttpHeaders { forEach(fn: (name: string, values: string[]) => void) { this.init(); Array.from(this.normalizedNames.keys()) - .forEach(key => fn(this.normalizedNames.get(key) !, this.headers.get(key) !)); + .forEach(key => fn(this.normalizedNames.get(key)!, this.headers.get(key)!)); } } diff --git a/packages/common/http/src/interceptor.ts b/packages/common/http/src/interceptor.ts index 0f71d46eb44b2..5f83c1421230e 100644 --- a/packages/common/http/src/interceptor.ts +++ b/packages/common/http/src/interceptor.ts @@ -38,8 +38,8 @@ import {HttpEvent} from './response'; * To use the same instance of `HttpInterceptors` for the entire app, import the `HttpClientModule` * only in your `AppModule`, and add the interceptors to the root application injector . * If you import `HttpClientModule` multiple times across different modules (for example, in lazy - * loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the interceptors - * provided in the root module. + * loading modules), each import creates a new copy of the `HttpClientModule`, which overwrites the + * interceptors provided in the root module. * */ export interface HttpInterceptor { diff --git a/packages/common/http/src/jsonp.ts b/packages/common/http/src/jsonp.ts index b613434039a8e..7a6c9311e4775 100644 --- a/packages/common/http/src/jsonp.ts +++ b/packages/common/http/src/jsonp.ts @@ -36,7 +36,9 @@ export const JSONP_ERR_WRONG_RESPONSE_TYPE = 'JSONP requests must use Json respo * * */ -export abstract class JsonpCallbackContext { [key: string]: (data: any) => void; } +export abstract class JsonpCallbackContext { + [key: string]: (data: any) => void; +} /** * Processes an `HttpRequest` with the JSONP method, @@ -53,7 +55,9 @@ export class JsonpClientBackend implements HttpBackend { /** * Get the name of the next callback method, by incrementing the global `nextRequestId`. */ - private nextCallback(): string { return `ng_jsonp_callback_${nextRequestId++}`; } + private nextCallback(): string { + return `ng_jsonp_callback_${nextRequestId++}`; + } /** * Processes a JSONP request and returns an event stream of the results. @@ -157,7 +161,8 @@ export class JsonpClientBackend implements HttpBackend { observer.next(new HttpResponse({ body, status: 200, - statusText: 'OK', url, + statusText: 'OK', + url, })); // Complete the stream, the response is over. @@ -178,7 +183,8 @@ export class JsonpClientBackend implements HttpBackend { observer.error(new HttpErrorResponse({ error, status: 0, - statusText: 'JSONP Error', url, + statusText: 'JSONP Error', + url, })); }; diff --git a/packages/common/http/src/module.ts b/packages/common/http/src/module.ts index 9225814ac66ae..33460638ef5e8 100644 --- a/packages/common/http/src/module.ts +++ b/packages/common/http/src/module.ts @@ -52,7 +52,7 @@ export class HttpInterceptingHandler implements HttpHandler { * */ export function interceptingHandler( - backend: HttpBackend, interceptors: HttpInterceptor[] | null = []): HttpHandler { + backend: HttpBackend, interceptors: HttpInterceptor[]|null = []): HttpHandler { if (!interceptors) { return backend; } diff --git a/packages/common/http/src/params.ts b/packages/common/http/src/params.ts index 30caa33cdec79..1e0ab81e9f4bb 100755 --- a/packages/common/http/src/params.ts +++ b/packages/common/http/src/params.ts @@ -37,28 +37,36 @@ export class HttpUrlEncodingCodec implements HttpParameterCodec { * @param key The key name. * @returns The encoded key name. */ - encodeKey(key: string): string { return standardEncoding(key); } + encodeKey(key: string): string { + return standardEncoding(key); + } /** * Encodes the value of a URL parameter or query-string. * @param value The value. * @returns The encoded value. */ - encodeValue(value: string): string { return standardEncoding(value); } + encodeValue(value: string): string { + return standardEncoding(value); + } /** * Decodes an encoded URL parameter or query-string key. * @param key The encoded key name. * @returns The decoded key name. */ - decodeKey(key: string): string { return decodeURIComponent(key); } + decodeKey(key: string): string { + return decodeURIComponent(key); + } /** * Decodes an encoded URL parameter or query-string value. * @param value The encoded value. * @returns The decoded value. */ - decodeValue(value: string) { return decodeURIComponent(value); } + decodeValue(value: string) { + return decodeURIComponent(value); + } } @@ -97,7 +105,8 @@ interface Update { op: 'a'|'d'|'s'; } -/** Options used to construct an `HttpParams` instance. +/** + * Options used to construct an `HttpParams` instance. * * @publicApi */ @@ -109,7 +118,7 @@ export interface HttpParamsOptions { fromString?: string; /** Object map of the HTTP parameters. Mutually exclusive with `fromString`. */ - fromObject?: {[param: string]: string | ReadonlyArray<string>}; + fromObject?: {[param: string]: string|ReadonlyArray<string>}; /** Encoding codec used to parse and serialize the parameters. */ encoder?: HttpParameterCodec; @@ -140,7 +149,7 @@ export class HttpParams { this.map = new Map<string, string[]>(); Object.keys(options.fromObject).forEach(key => { const value = (options.fromObject as any)[key]; - this.map !.set(key, Array.isArray(value) ? value : [value]); + this.map!.set(key, Array.isArray(value) ? value : [value]); }); } else { this.map = null; @@ -155,7 +164,7 @@ export class HttpParams { */ has(param: string): boolean { this.init(); - return this.map !.has(param); + return this.map!.has(param); } /** @@ -166,7 +175,7 @@ export class HttpParams { */ get(param: string): string|null { this.init(); - const res = this.map !.get(param); + const res = this.map!.get(param); return !!res ? res[0] : null; } @@ -178,7 +187,7 @@ export class HttpParams { */ getAll(param: string): string[]|null { this.init(); - return this.map !.get(param) || null; + return this.map!.get(param) || null; } /** @@ -187,7 +196,7 @@ export class HttpParams { */ keys(): string[] { this.init(); - return Array.from(this.map !.keys()); + return Array.from(this.map!.keys()); } /** @@ -196,7 +205,9 @@ export class HttpParams { * @param value The new value to add. * @return A new body with the appended value. */ - append(param: string, value: string): HttpParams { return this.clone({param, value, op: 'a'}); } + append(param: string, value: string): HttpParams { + return this.clone({param, value, op: 'a'}); + } /** * Replaces the value for a parameter. @@ -204,7 +215,9 @@ export class HttpParams { * @param value The new value. * @return A new body with the new value. */ - set(param: string, value: string): HttpParams { return this.clone({param, value, op: 's'}); } + set(param: string, value: string): HttpParams { + return this.clone({param, value, op: 's'}); + } /** * Removes a given value or all values from a parameter. @@ -213,7 +226,9 @@ export class HttpParams { * @return A new body with the given value removed, or with all values * removed if no value is specified. */ - delete (param: string, value?: string): HttpParams { return this.clone({param, value, op: 'd'}); } + delete(param: string, value?: string): HttpParams { + return this.clone({param, value, op: 'd'}); + } /** * Serializes the body to an encoded string, where key-value pairs (separated by `=`) are @@ -227,7 +242,7 @@ export class HttpParams { // `a: ['1']` produces `'a=1'` // `b: []` produces `''` // `c: ['1', '2']` produces `'c=1&c=2'` - return this.map !.get(key) !.map(value => eKey + '=' + this.encoder.encodeValue(value)) + return this.map!.get(key)!.map(value => eKey + '=' + this.encoder.encodeValue(value)) .join('&'); }) // filter out empty values because `b: []` produces `''` @@ -237,7 +252,7 @@ export class HttpParams { } private clone(update: Update): HttpParams { - const clone = new HttpParams({ encoder: this.encoder } as HttpParamsOptions); + const clone = new HttpParams({encoder: this.encoder} as HttpParamsOptions); clone.cloneFrom = this.cloneFrom || this; clone.updates = (this.updates || []).concat([update]); return clone; @@ -249,29 +264,29 @@ export class HttpParams { } if (this.cloneFrom !== null) { this.cloneFrom.init(); - this.cloneFrom.keys().forEach(key => this.map !.set(key, this.cloneFrom !.map !.get(key) !)); - this.updates !.forEach(update => { + this.cloneFrom.keys().forEach(key => this.map!.set(key, this.cloneFrom!.map!.get(key)!)); + this.updates!.forEach(update => { switch (update.op) { case 'a': case 's': - const base = (update.op === 'a' ? this.map !.get(update.param) : undefined) || []; - base.push(update.value !); - this.map !.set(update.param, base); + const base = (update.op === 'a' ? this.map!.get(update.param) : undefined) || []; + base.push(update.value!); + this.map!.set(update.param, base); break; case 'd': if (update.value !== undefined) { - let base = this.map !.get(update.param) || []; + let base = this.map!.get(update.param) || []; const idx = base.indexOf(update.value); if (idx !== -1) { base.splice(idx, 1); } if (base.length > 0) { - this.map !.set(update.param, base); + this.map!.set(update.param, base); } else { - this.map !.delete(update.param); + this.map!.delete(update.param); } } else { - this.map !.delete(update.param); + this.map!.delete(update.param); break; } } diff --git a/packages/common/http/src/request.ts b/packages/common/http/src/request.ts index b641daad9b4a0..12409680ce357 100644 --- a/packages/common/http/src/request.ts +++ b/packages/common/http/src/request.ts @@ -89,7 +89,7 @@ export class HttpRequest<T> { * Outgoing headers for this request. */ // TODO(issue/24571): remove '!'. - readonly headers !: HttpHeaders; + readonly headers!: HttpHeaders; /** * Whether this request should be made in a way that exposes progress events. @@ -121,7 +121,7 @@ export class HttpRequest<T> { * Outgoing URL parameters. */ // TODO(issue/24571): remove '!'. - readonly params !: HttpParams; + readonly params!: HttpParams; /** * The outgoing URL with all URL parameters set. @@ -312,7 +312,7 @@ export class HttpRequest<T> { body?: T|null, method?: string, url?: string, - setHeaders?: {[name: string]: string | string[]}, + setHeaders?: {[name: string]: string|string[]}, setParams?: {[param: string]: string}, }): HttpRequest<T>; clone<V>(update: { @@ -324,7 +324,7 @@ export class HttpRequest<T> { body?: V|null, method?: string, url?: string, - setHeaders?: {[name: string]: string | string[]}, + setHeaders?: {[name: string]: string|string[]}, setParams?: {[param: string]: string}, }): HttpRequest<V>; clone(update: { @@ -336,7 +336,7 @@ export class HttpRequest<T> { body?: any|null, method?: string, url?: string, - setHeaders?: {[name: string]: string | string[]}, + setHeaders?: {[name: string]: string|string[]}, setParams?: {[param: string]: string}; } = {}): HttpRequest<any> { // For method, url, and responseType, take the current value unless @@ -368,20 +368,23 @@ export class HttpRequest<T> { // Set every requested header. headers = Object.keys(update.setHeaders) - .reduce((headers, name) => headers.set(name, update.setHeaders ![name]), headers); + .reduce((headers, name) => headers.set(name, update.setHeaders![name]), headers); } // Check whether the caller has asked to set params. if (update.setParams) { // Set every requested param. params = Object.keys(update.setParams) - .reduce((params, param) => params.set(param, update.setParams ![param]), params); + .reduce((params, param) => params.set(param, update.setParams![param]), params); } // Finally, construct the new HttpRequest using the pieces from above. - return new HttpRequest( - method, url, body, { - params, headers, reportProgress, responseType, withCredentials, - }); + return new HttpRequest(method, url, body, { + params, + headers, + reportProgress, + responseType, + withCredentials, + }); } } diff --git a/packages/common/http/src/response.ts b/packages/common/http/src/response.ts index 35af00813d524..d41d7aeef7a89 100644 --- a/packages/common/http/src/response.ts +++ b/packages/common/http/src/response.ts @@ -100,7 +100,9 @@ export interface HttpUploadProgressEvent extends HttpProgressEvent { * * @publicApi */ -export interface HttpSentEvent { type: HttpEventType.Sent; } +export interface HttpSentEvent { + type: HttpEventType.Sent; +} /** * A user-defined event. @@ -110,7 +112,9 @@ export interface HttpSentEvent { type: HttpEventType.Sent; } * * @publicApi */ -export interface HttpUserEvent<T> { type: HttpEventType.User; } +export interface HttpUserEvent<T> { + type: HttpEventType.User; +} /** * An error that represents a failed attempt to JSON.parse text coming back @@ -133,7 +137,7 @@ export interface HttpJsonParseError { * @publicApi */ export type HttpEvent<T> = - HttpSentEvent | HttpHeaderResponse | HttpResponse<T>| HttpProgressEvent | HttpUserEvent<T>; + HttpSentEvent|HttpHeaderResponse|HttpResponse<T>|HttpProgressEvent|HttpUserEvent<T>; /** * Base class for both `HttpResponse` and `HttpHeaderResponse`. @@ -172,7 +176,7 @@ export abstract class HttpResponseBase { * Type of the response, narrowed to either the full response or the header. */ // TODO(issue/24571): remove '!'. - readonly type !: HttpEventType.Response | HttpEventType.ResponseHeader; + readonly type!: HttpEventType.Response|HttpEventType.ResponseHeader; /** * Super-constructor for all responses. @@ -260,7 +264,11 @@ export class HttpResponse<T> extends HttpResponseBase { * Construct a new `HttpResponse`. */ constructor(init: { - body?: T | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string; + body?: T|null, + headers?: HttpHeaders; + status?: number; + statusText?: string; + url?: string; } = {}) { super(init); this.body = init.body !== undefined ? init.body : null; @@ -272,10 +280,18 @@ export class HttpResponse<T> extends HttpResponseBase { clone(update: {headers?: HttpHeaders; status?: number; statusText?: string; url?: string;}): HttpResponse<T>; clone<V>(update: { - body?: V | null, headers?: HttpHeaders; status?: number; statusText?: string; url?: string; + body?: V|null, + headers?: HttpHeaders; + status?: number; + statusText?: string; + url?: string; }): HttpResponse<V>; clone(update: { - body?: any | null; headers?: HttpHeaders; status?: number; statusText?: string; url?: string; + body?: any|null; + headers?: HttpHeaders; + status?: number; + statusText?: string; + url?: string; } = {}): HttpResponse<any> { return new HttpResponse<any>({ body: (update.body !== undefined) ? update.body : this.body, @@ -311,7 +327,11 @@ export class HttpErrorResponse extends HttpResponseBase implements Error { readonly ok = false; constructor(init: { - error?: any; headers?: HttpHeaders; status?: number; statusText?: string; url?: string; + error?: any; + headers?: HttpHeaders; + status?: number; + statusText?: string; + url?: string; }) { // Initialize with a default status of 0 / Unknown Error. super(init, 0, 'Unknown Error'); @@ -322,8 +342,8 @@ export class HttpErrorResponse extends HttpResponseBase implements Error { if (this.status >= 200 && this.status < 300) { this.message = `Http failure during parsing for ${init.url || '(unknown url)'}`; } else { - this.message = - `Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${init.statusText}`; + this.message = `Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${ + init.statusText}`; } this.error = init.error || null; } diff --git a/packages/common/http/src/xhr.ts b/packages/common/http/src/xhr.ts index b1c00e3249903..f0e4eb9a81860 100644 --- a/packages/common/http/src/xhr.ts +++ b/packages/common/http/src/xhr.ts @@ -35,7 +35,9 @@ function getResponseUrl(xhr: any): string|null { * * @publicApi */ -export abstract class XhrFactory { abstract build(): XMLHttpRequest; } +export abstract class XhrFactory { + abstract build(): XMLHttpRequest; +} /** * A factory for `HttpXhrBackend` that uses the `XMLHttpRequest` browser API. @@ -44,7 +46,9 @@ export abstract class XhrFactory { abstract build(): XMLHttpRequest; } @Injectable() export class BrowserXhr implements XhrFactory { constructor() {} - build(): any { return <any>(new XMLHttpRequest()); } + build(): any { + return <any>(new XMLHttpRequest()); + } } /** @@ -200,7 +204,7 @@ export class HttpXhrBackend implements HttpBackend { // Even though the response status was 2xx, this is still an error. ok = false; // The parse error contains the text of the body that failed to parse. - body = { error, text: body } as HttpJsonParseError; + body = {error, text: body} as HttpJsonParseError; } } } @@ -318,7 +322,7 @@ export class HttpXhrBackend implements HttpBackend { } // Fire the request, and notify the event stream that it was fired. - xhr.send(reqBody !); + xhr.send(reqBody!); observer.next({type: HttpEventType.Sent}); // This is the return from the Observable function, which is the diff --git a/packages/common/http/test/client_spec.ts b/packages/common/http/test/client_spec.ts index bed29df8eb351..d84925c2d0d55 100644 --- a/packages/common/http/test/client_spec.ts +++ b/packages/common/http/test/client_spec.ts @@ -14,13 +14,15 @@ import {toArray} from 'rxjs/operators'; { describe('HttpClient', () => { - let client: HttpClient = null !; - let backend: HttpClientTestingBackend = null !; + let client: HttpClient = null!; + let backend: HttpClientTestingBackend = null!; beforeEach(() => { backend = new HttpClientTestingBackend(); client = new HttpClient(backend); }); - afterEach(() => { backend.verify(); }); + afterEach(() => { + backend.verify(); + }); describe('makes a basic request', () => { it('for JSON data', done => { client.get('/test').subscribe(res => { diff --git a/packages/common/http/test/headers_spec.ts b/packages/common/http/test/headers_spec.ts index c7e23e2b2c4bc..49554a52015a4 100644 --- a/packages/common/http/test/headers_spec.ts +++ b/packages/common/http/test/headers_spec.ts @@ -10,7 +10,6 @@ import {HttpHeaders} from '@angular/common/http/src/headers'; { describe('HttpHeaders', () => { - describe('initialization', () => { it('should conform to spec', () => { const httpHeaders = { diff --git a/packages/common/http/test/jsonp_mock.ts b/packages/common/http/test/jsonp_mock.ts index 7b2345d7c3494..b05f25672dae7 100644 --- a/packages/common/http/test/jsonp_mock.ts +++ b/packages/common/http/test/jsonp_mock.ts @@ -18,19 +18,23 @@ export class MockScriptElement { this.listeners[event] = handler as any; } - removeEventListener(event: 'load'|'error'): void { delete this.listeners[event]; } + removeEventListener(event: 'load'|'error'): void { + delete this.listeners[event]; + } } export class MockDocument { // TODO(issue/24571): remove '!'. - mock !: MockScriptElement | null; + mock!: MockScriptElement|null; readonly body: any = this; createElement(tag: 'script'): HTMLScriptElement { return new MockScriptElement() as any as HTMLScriptElement; } - appendChild(node: any): void { this.mock = node; } + appendChild(node: any): void { + this.mock = node; + } removeNode(node: any): void { if (this.mock === node) { @@ -38,7 +42,11 @@ export class MockDocument { } } - mockLoad(): void { this.mock !.listeners.load !(null as any); } + mockLoad(): void { + this.mock!.listeners.load!(null as any); + } - mockError(err: Error) { this.mock !.listeners.error !(err); } + mockError(err: Error) { + this.mock!.listeners.error!(err); + } } diff --git a/packages/common/http/test/module_spec.ts b/packages/common/http/test/module_spec.ts index a6a66440f3cb2..4841de7b496f9 100644 --- a/packages/common/http/test/module_spec.ts +++ b/packages/common/http/test/module_spec.ts @@ -38,11 +38,15 @@ class TestInterceptor implements HttpInterceptor { } class InterceptorA extends TestInterceptor { - constructor() { super('A'); } + constructor() { + super('A'); + } } class InterceptorB extends TestInterceptor { - constructor() { super('B'); } + constructor() { + super('B'); + } } @Injectable() @@ -98,7 +102,9 @@ class ReentrantInterceptor implements HttpInterceptor { {provide: HTTP_INTERCEPTORS, useClass: ReentrantInterceptor, multi: true}, ], }); - injector.get(HttpClient).get('/test').subscribe(() => { done(); }); + injector.get(HttpClient).get('/test').subscribe(() => { + done(); + }); injector.get(HttpTestingController).expectOne('/test').flush('ok!'); }); }); diff --git a/packages/common/http/test/request_spec.ts b/packages/common/http/test/request_spec.ts index af17f0f7887e6..4c4f74d4a36df 100644 --- a/packages/common/http/test/request_spec.ts +++ b/packages/common/http/test/request_spec.ts @@ -80,16 +80,21 @@ const TEST_STRING = `I'm a body!`; expect(clone.headers).toBe(headers); expect(clone.headers.get('Test')).toBe('Test header'); }); - it('and updates the url', - () => { expect(req.clone({url: '/changed'}).url).toBe('/changed'); }); - it('and updates the method', - () => { expect(req.clone({method: 'PUT'}).method).toBe('PUT'); }); - it('and updates the body', - () => { expect(req.clone({body: 'changed body'}).body).toBe('changed body'); }); + it('and updates the url', () => { + expect(req.clone({url: '/changed'}).url).toBe('/changed'); + }); + it('and updates the method', () => { + expect(req.clone({method: 'PUT'}).method).toBe('PUT'); + }); + it('and updates the body', () => { + expect(req.clone({body: 'changed body'}).body).toBe('changed body'); + }); }); describe('content type detection', () => { const baseReq = new HttpRequest('POST', '/test', null); - it('handles a null body', () => { expect(baseReq.detectContentTypeHeader()).toBeNull(); }); + it('handles a null body', () => { + expect(baseReq.detectContentTypeHeader()).toBeNull(); + }); it('doesn\'t associate a content type with ArrayBuffers', () => { const req = baseReq.clone({body: new ArrayBuffer(4)}); expect(req.detectContentTypeHeader()).toBeNull(); @@ -113,7 +118,9 @@ const TEST_STRING = `I'm a body!`; }); describe('body serialization', () => { const baseReq = new HttpRequest('POST', '/test', null); - it('handles a null body', () => { expect(baseReq.serializeBody()).toBeNull(); }); + it('handles a null body', () => { + expect(baseReq.serializeBody()).toBeNull(); + }); it('passes ArrayBuffers through', () => { const body = new ArrayBuffer(4); expect(baseReq.clone({body}).serializeBody()).toBe(body); @@ -125,8 +132,9 @@ const TEST_STRING = `I'm a body!`; it('serializes arrays as json', () => { expect(baseReq.clone({body: ['a', 'b']}).serializeBody()).toBe('["a","b"]'); }); - it('handles numbers as json', - () => { expect(baseReq.clone({body: 314159}).serializeBody()).toBe('314159'); }); + it('handles numbers as json', () => { + expect(baseReq.clone({body: 314159}).serializeBody()).toBe('314159'); + }); it('handles objects as json', () => { const req = baseReq.clone({body: {data: 'test data'}}); expect(req.serializeBody()).toBe('{"data":"test data"}'); diff --git a/packages/common/http/test/xhr_mock.ts b/packages/common/http/test/xhr_mock.ts index bfac036991ba8..3634293726e6d 100644 --- a/packages/common/http/test/xhr_mock.ts +++ b/packages/common/http/test/xhr_mock.ts @@ -11,9 +11,11 @@ import {XhrFactory} from '@angular/common/http/src/xhr'; export class MockXhrFactory implements XhrFactory { // TODO(issue/24571): remove '!'. - mock !: MockXMLHttpRequest; + mock!: MockXMLHttpRequest; - build(): XMLHttpRequest { return (this.mock = new MockXMLHttpRequest()) as any; } + build(): XMLHttpRequest { + return (this.mock = new MockXMLHttpRequest()) as any; + } } export class MockXMLHttpRequestUpload { @@ -32,9 +34,9 @@ export class MockXMLHttpRequest { // Set by method calls. body: any; // TODO(issue/24571): remove '!'. - method !: string; + method!: string; // TODO(issue/24571): remove '!'. - url !: string; + url!: string; mockHeaders: {[key: string]: string} = {}; mockAborted: boolean = false; @@ -64,7 +66,9 @@ export class MockXMLHttpRequest { this.url = url; } - send(body: any): void { this.body = body; } + send(body: any): void { + this.body = body; + } addEventListener(event: 'error'|'load'|'progress'|'uploadProgress', handler: Function): void { this.listeners[event] = handler as any; @@ -74,9 +78,13 @@ export class MockXMLHttpRequest { delete this.listeners[event]; } - setRequestHeader(name: string, value: string): void { this.mockHeaders[name] = value; } + setRequestHeader(name: string, value: string): void { + this.mockHeaders[name] = value; + } - getAllResponseHeaders(): string { return this.mockResponseHeaders; } + getAllResponseHeaders(): string { + return this.mockResponseHeaders; + } getResponseHeader(header: string): string|null { return new HttpHeaders(this.mockResponseHeaders).get(header); @@ -95,14 +103,17 @@ export class MockXMLHttpRequest { mockDownloadProgressEvent(loaded: number, total?: number): void { if (this.listeners.progress) { - this.listeners.progress({ lengthComputable: total !== undefined, loaded, total } as any); + this.listeners.progress({lengthComputable: total !== undefined, loaded, total} as any); } } mockUploadProgressEvent(loaded: number, total?: number) { if (this.listeners.uploadProgress) { - this.listeners.uploadProgress( - { lengthComputable: total !== undefined, loaded, total, } as any); + this.listeners.uploadProgress({ + lengthComputable: total !== undefined, + loaded, + total, + } as any); } } @@ -118,5 +129,7 @@ export class MockXMLHttpRequest { } } - abort() { this.mockAborted = true; } + abort() { + this.mockAborted = true; + } } diff --git a/packages/common/http/test/xsrf_spec.ts b/packages/common/http/test/xsrf_spec.ts index 252b0032b6fcc..bf588b2fab9cc 100644 --- a/packages/common/http/test/xsrf_spec.ts +++ b/packages/common/http/test/xsrf_spec.ts @@ -13,16 +13,22 @@ import {HttpXsrfCookieExtractor, HttpXsrfInterceptor, HttpXsrfTokenExtractor} fr import {HttpClientTestingBackend} from '@angular/common/http/testing/src/backend'; class SampleTokenExtractor extends HttpXsrfTokenExtractor { - constructor(private token: string|null) { super(); } + constructor(private token: string|null) { + super(); + } - getToken(): string|null { return this.token; } + getToken(): string|null { + return this.token; + } } { describe('HttpXsrfInterceptor', () => { let backend: HttpClientTestingBackend; const interceptor = new HttpXsrfInterceptor(new SampleTokenExtractor('test'), 'X-XSRF-TOKEN'); - beforeEach(() => { backend = new HttpClientTestingBackend(); }); + beforeEach(() => { + backend = new HttpClientTestingBackend(); + }); it('applies XSRF protection to outgoing requests', () => { interceptor.intercept(new HttpRequest('POST', '/test', {}), backend).subscribe(); const req = backend.expectOne('/test'); @@ -59,7 +65,9 @@ class SampleTokenExtractor extends HttpXsrfTokenExtractor { expect(req.request.headers.has('X-XSRF-TOKEN')).toEqual(false); req.flush({}); }); - afterEach(() => { backend.verify(); }); + afterEach(() => { + backend.verify(); + }); }); describe('HttpXsrfCookieExtractor', () => { let document: {[key: string]: string}; @@ -70,8 +78,9 @@ class SampleTokenExtractor extends HttpXsrfTokenExtractor { }; extractor = new HttpXsrfCookieExtractor(document, 'browser', 'XSRF-TOKEN'); }); - it('parses the cookie from document.cookie', - () => { expect(extractor.getToken()).toEqual('test'); }); + it('parses the cookie from document.cookie', () => { + expect(extractor.getToken()).toEqual('test'); + }); it('does not re-parse if document.cookie has not changed', () => { expect(extractor.getToken()).toEqual('test'); expect(extractor.getToken()).toEqual('test'); diff --git a/packages/common/http/testing/src/backend.ts b/packages/common/http/testing/src/backend.ts index 75a32389b8dff..b01dc0dc353c0 100644 --- a/packages/common/http/testing/src/backend.ts +++ b/packages/common/http/testing/src/backend.ts @@ -39,8 +39,10 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl return new Observable((observer: Observer<any>) => { const testReq = new TestRequest(req, observer); this.open.push(testReq); - observer.next({ type: HttpEventType.Sent } as HttpEvent<any>); - return () => { testReq._cancelled = true; }; + observer.next({type: HttpEventType.Sent} as HttpEvent<any>); + return () => { + testReq._cancelled = true; + }; }); } @@ -86,8 +88,8 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl description = description || this.descriptionFromMatcher(match); const matches = this.match(match); if (matches.length > 1) { - throw new Error( - `Expected one matching request for criteria "${description}", found ${matches.length} requests.`); + throw new Error(`Expected one matching request for criteria "${description}", found ${ + matches.length} requests.`); } if (matches.length === 0) { let message = `Expected one matching request for criteria "${description}", found none.`; @@ -116,8 +118,8 @@ export class HttpClientTestingBackend implements HttpBackend, HttpTestingControl description = description || this.descriptionFromMatcher(match); const matches = this.match(match); if (matches.length > 0) { - throw new Error( - `Expected zero matching requests for criteria "${description}", found ${matches.length}.`); + throw new Error(`Expected zero matching requests for criteria "${description}", found ${ + matches.length}.`); } } diff --git a/packages/common/http/testing/src/request.ts b/packages/common/http/testing/src/request.ts index 022cf77e19be1..9f240be590785 100644 --- a/packages/common/http/testing/src/request.ts +++ b/packages/common/http/testing/src/request.ts @@ -21,7 +21,9 @@ export class TestRequest { /** * Whether the request was cancelled after it was sent. */ - get cancelled(): boolean { return this._cancelled; } + get cancelled(): boolean { + return this._cancelled; + } /** * @internal set by `HttpClientTestingBackend` @@ -39,7 +41,7 @@ export class TestRequest { * Both successful and unsuccessful responses can be delivered via `flush()`. */ flush(body: ArrayBuffer|Blob|string|number|Object|(string|number|Object|null)[]|null, opts: { - headers?: HttpHeaders | {[name: string]: string | string[]}, + headers?: HttpHeaders|{[name: string]: string | string[]}, status?: number, statusText?: string, } = {}): void { @@ -75,7 +77,7 @@ export class TestRequest { * Resolve the request by returning an `ErrorEvent` (e.g. simulating a network failure). */ error(error: ErrorEvent, opts: { - headers?: HttpHeaders | {[name: string]: string | string[]}, + headers?: HttpHeaders|{[name: string]: string | string[]}, status?: number, statusText?: string, } = {}): void { @@ -112,9 +114,8 @@ export class TestRequest { /** * Helper function to convert a response body to an ArrayBuffer. */ -function _toArrayBufferBody( - body: ArrayBuffer | Blob | string | number | Object | - (string | number | Object | null)[]): ArrayBuffer { +function _toArrayBufferBody(body: ArrayBuffer|Blob|string|number|Object| + (string | number | Object | null)[]): ArrayBuffer { if (typeof ArrayBuffer === 'undefined') { throw new Error('ArrayBuffer responses are not supported on this platform.'); } @@ -127,9 +128,8 @@ function _toArrayBufferBody( /** * Helper function to convert a response body to a Blob. */ -function _toBlob( - body: ArrayBuffer | Blob | string | number | Object | - (string | number | Object | null)[]): Blob { +function _toBlob(body: ArrayBuffer|Blob|string|number|Object| + (string | number | Object | null)[]): Blob { if (typeof Blob === 'undefined') { throw new Error('Blob responses are not supported on this platform.'); } @@ -146,7 +146,7 @@ function _toBlob( * Helper function to convert a response body to JSON data. */ function _toJsonBody( - body: ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[], + body: ArrayBuffer|Blob|string|number|Object|(string | number | Object | null)[], format: string = 'JSON'): Object|string|number|(Object | string | number)[] { if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) { throw new Error(`Automatic conversion to ${format} is not supported for ArrayBuffers.`); @@ -164,9 +164,8 @@ function _toJsonBody( /** * Helper function to convert a response body to a string. */ -function _toTextBody( - body: ArrayBuffer | Blob | string | number | Object | - (string | number | Object | null)[]): string { +function _toTextBody(body: ArrayBuffer|Blob|string|number|Object| + (string | number | Object | null)[]): string { if (typeof body === 'string') { return body; } @@ -183,9 +182,9 @@ function _toTextBody( * Convert a response body to the requested type. */ function _maybeConvertBody( - responseType: string, body: ArrayBuffer | Blob | string | number | Object | - (string | number | Object | null)[] | null): ArrayBuffer|Blob|string|number|Object| - (string | number | Object | null)[]|null { + responseType: string, + body: ArrayBuffer|Blob|string|number|Object|(string | number | Object | null)[]| + null): ArrayBuffer|Blob|string|number|Object|(string | number | Object | null)[]|null { if (body === null) { return null; } diff --git a/packages/common/http/testing/test/request_spec.ts b/packages/common/http/testing/test/request_spec.ts index 92d78399d29d7..5c4092a52d2c3 100644 --- a/packages/common/http/testing/test/request_spec.ts +++ b/packages/common/http/testing/test/request_spec.ts @@ -15,7 +15,9 @@ describe('HttpClient TestRequest', () => { const client = new HttpClient(mock); let resp: any; - client.post('/some-url', {test: 'test'}).subscribe(body => { resp = body; }); + client.post('/some-url', {test: 'test'}).subscribe(body => { + resp = body; + }); const req = mock.expectOne('/some-url'); req.flush(null); @@ -28,7 +30,9 @@ describe('HttpClient TestRequest', () => { const client = new HttpClient(mock); let resp: any; - client.get('/some-other-url').subscribe(body => { resp = body; }); + client.get('/some-other-url').subscribe(body => { + resp = body; + }); try { // expect different URL @@ -48,7 +52,9 @@ describe('HttpClient TestRequest', () => { let resp: any; const params = {query: 'hello'}; - client.get('/some-url', {params}).subscribe(body => { resp = body; }); + client.get('/some-url', {params}).subscribe(body => { + resp = body; + }); try { // expect different query parameters @@ -67,8 +73,12 @@ describe('HttpClient TestRequest', () => { const client = new HttpClient(mock); let resp: any; - client.get('/some-other-url?query=world').subscribe(body => { resp = body; }); - client.post('/and-another-url', {}).subscribe(body => { resp = body; }); + client.get('/some-other-url?query=world').subscribe(body => { + resp = body; + }); + client.post('/and-another-url', {}).subscribe(body => { + resp = body; + }); try { // expect different URL diff --git a/packages/common/src/directives/ng_class.ts b/packages/common/src/directives/ng_class.ts index 63ddbe198e422..d24e4dfae7796 100644 --- a/packages/common/src/directives/ng_class.ts +++ b/packages/common/src/directives/ng_class.ts @@ -7,7 +7,7 @@ */ import {Directive, DoCheck, ElementRef, Input, IterableChanges, IterableDiffer, IterableDiffers, KeyValueChanges, KeyValueDiffer, KeyValueDiffers, Renderer2, ɵisListLikeIterable as isListLikeIterable, ɵstringify as stringify} from '@angular/core'; -type NgClassSupportedTypes = string[] | Set<string>| {[klass: string]: any} | null | undefined; +type NgClassSupportedTypes = string[]|Set<string>|{[klass: string]: any}|null|undefined; /** * @ngModule CommonModule @@ -83,7 +83,7 @@ export class NgClass implements DoCheck { this._applyIterableChanges(iterableChanges); } } else if (this._keyValueDiffer) { - const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as{[k: string]: any}); + const keyValueChanges = this._keyValueDiffer.diff(this._rawClass as {[k: string]: any}); if (keyValueChanges) { this._applyKeyValueChanges(keyValueChanges); } @@ -105,8 +105,8 @@ export class NgClass implements DoCheck { if (typeof record.item === 'string') { this._toggleClass(record.item, true); } else { - throw new Error( - `NgClass can only toggle CSS classes expressed as strings, got ${stringify(record.item)}`); + throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${ + stringify(record.item)}`); } }); diff --git a/packages/common/src/directives/ng_component_outlet.ts b/packages/common/src/directives/ng_component_outlet.ts index 23f2b856a482d..6c601b6442043 100644 --- a/packages/common/src/directives/ng_component_outlet.ts +++ b/packages/common/src/directives/ng_component_outlet.ts @@ -67,13 +67,13 @@ import {ComponentFactoryResolver, ComponentRef, Directive, Injector, Input, NgMo @Directive({selector: '[ngComponentOutlet]'}) export class NgComponentOutlet implements OnChanges, OnDestroy { // TODO(issue/24571): remove '!'. - @Input() ngComponentOutlet !: Type<any>; + @Input() ngComponentOutlet!: Type<any>; // TODO(issue/24571): remove '!'. - @Input() ngComponentOutletInjector !: Injector; + @Input() ngComponentOutletInjector!: Injector; // TODO(issue/24571): remove '!'. - @Input() ngComponentOutletContent !: any[][]; + @Input() ngComponentOutletContent!: any[][]; // TODO(issue/24571): remove '!'. - @Input() ngComponentOutletNgModuleFactory !: NgModuleFactory<any>; + @Input() ngComponentOutletNgModuleFactory!: NgModuleFactory<any>; private _componentRef: ComponentRef<any>|null = null; private _moduleRef: NgModuleRef<any>|null = null; diff --git a/packages/common/src/directives/ng_for_of.ts b/packages/common/src/directives/ng_for_of.ts index 02d8243690c99..dc176145abe3e 100644 --- a/packages/common/src/directives/ng_for_of.ts +++ b/packages/common/src/directives/ng_for_of.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef, isDevMode} from '@angular/core'; +import {Directive, DoCheck, EmbeddedViewRef, Input, isDevMode, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDiffers, NgIterable, TemplateRef, TrackByFunction, ViewContainerRef} from '@angular/core'; /** * @publicApi @@ -14,13 +14,21 @@ import {Directive, DoCheck, EmbeddedViewRef, Input, IterableChangeRecord, Iterab export class NgForOfContext<T, U extends NgIterable<T> = NgIterable<T>> { constructor(public $implicit: T, public ngForOf: U, public index: number, public count: number) {} - get first(): boolean { return this.index === 0; } + get first(): boolean { + return this.index === 0; + } - get last(): boolean { return this.index === this.count - 1; } + get last(): boolean { + return this.index === this.count - 1; + } - get even(): boolean { return this.index % 2 === 0; } + get even(): boolean { + return this.index % 2 === 0; + } - get odd(): boolean { return !this.even; } + get odd(): boolean { + return !this.even; + } } /** @@ -162,13 +170,15 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh this._trackByFn = fn; } - get ngForTrackBy(): TrackByFunction<T> { return this._trackByFn; } + get ngForTrackBy(): TrackByFunction<T> { + return this._trackByFn; + } private _ngForOf: U|undefined|null = null; private _ngForOfDirty: boolean = true; private _differ: IterableDiffer<T>|null = null; // TODO(issue/24571): remove '!'. - private _trackByFn !: TrackByFunction<T>; + private _trackByFn!: TrackByFunction<T>; constructor( private _viewContainer: ViewContainerRef, @@ -200,8 +210,8 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh try { this._differ = this._differs.find(value).create(this.ngForTrackBy); } catch { - throw new Error( - `Cannot find a differ supporting object '${value}' of type '${getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`); + throw new Error(`Cannot find a differ supporting object '${value}' of type '${ + getTypeName(value)}'. NgFor only supports binding to Iterables such as Arrays.`); } } } @@ -214,14 +224,14 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh private _applyChanges(changes: IterableChanges<T>) { const insertTuples: RecordViewTuple<T, U>[] = []; changes.forEachOperation( - (item: IterableChangeRecord<any>, adjustedPreviousIndex: number | null, - currentIndex: number | null) => { + (item: IterableChangeRecord<any>, adjustedPreviousIndex: number|null, + currentIndex: number|null) => { if (item.previousIndex == null) { // NgForOf is never "null" or "undefined" here because the differ detected // that a new item needs to be inserted from the iterable. This implies that // there is an iterable value for "_ngForOf". const view = this._viewContainer.createEmbeddedView( - this._template, new NgForOfContext<T, U>(null !, this._ngForOf !, -1, -1), + this._template, new NgForOfContext<T, U>(null!, this._ngForOf!, -1, -1), currentIndex === null ? undefined : currentIndex); const tuple = new RecordViewTuple<T, U>(item, view); insertTuples.push(tuple); @@ -229,7 +239,7 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh this._viewContainer.remove( adjustedPreviousIndex === null ? undefined : adjustedPreviousIndex); } else if (adjustedPreviousIndex !== null) { - const view = this._viewContainer.get(adjustedPreviousIndex) !; + const view = this._viewContainer.get(adjustedPreviousIndex)!; this._viewContainer.move(view, currentIndex); const tuple = new RecordViewTuple(item, <EmbeddedViewRef<NgForOfContext<T, U>>>view); insertTuples.push(tuple); @@ -244,7 +254,7 @@ export class NgForOf<T, U extends NgIterable<T> = NgIterable<T>> implements DoCh const viewRef = <EmbeddedViewRef<NgForOfContext<T, U>>>this._viewContainer.get(i); viewRef.context.index = i; viewRef.context.count = ilen; - viewRef.context.ngForOf = this._ngForOf !; + viewRef.context.ngForOf = this._ngForOf!; } changes.forEachIdentityChange((record: any) => { diff --git a/packages/common/src/directives/ng_if.ts b/packages/common/src/directives/ng_if.ts index e9cb89227e4c0..2868055a973e0 100644 --- a/packages/common/src/directives/ng_if.ts +++ b/packages/common/src/directives/ng_if.ts @@ -241,11 +241,11 @@ export class NgIf<T = unknown> { * @publicApi */ export class NgIfContext<T = unknown> { - public $implicit: T = null !; - public ngIf: T = null !; + public $implicit: T = null!; + public ngIf: T = null!; } -function assertTemplate(property: string, templateRef: TemplateRef<any>| null): void { +function assertTemplate(property: string, templateRef: TemplateRef<any>|null): void { const isTemplateRefOrNull = !!(!templateRef || templateRef.createEmbeddedView); if (!isTemplateRefOrNull) { throw new Error(`${property} must be a TemplateRef, but received '${stringify(templateRef)}'.`); diff --git a/packages/common/src/directives/ng_plural.ts b/packages/common/src/directives/ng_plural.ts index 1cc7de97c4633..52158f9347c4a 100644 --- a/packages/common/src/directives/ng_plural.ts +++ b/packages/common/src/directives/ng_plural.ts @@ -8,7 +8,7 @@ import {Attribute, Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core'; -import {NgLocalization, getPluralCategory} from '../i18n/localization'; +import {getPluralCategory, NgLocalization} from '../i18n/localization'; import {SwitchView} from './ng_switch'; @@ -47,9 +47,9 @@ import {SwitchView} from './ng_switch'; @Directive({selector: '[ngPlural]'}) export class NgPlural { // TODO(issue/24571): remove '!'. - private _switchValue !: number; + private _switchValue!: number; // TODO(issue/24571): remove '!'. - private _activeView !: SwitchView; + private _activeView!: SwitchView; private _caseViews: {[k: string]: SwitchView} = {}; constructor(private _localization: NgLocalization) {} @@ -60,7 +60,9 @@ export class NgPlural { this._updateView(); } - addCase(value: string, switchView: SwitchView): void { this._caseViews[value] = switchView; } + addCase(value: string, switchView: SwitchView): void { + this._caseViews[value] = switchView; + } private _updateView(): void { this._clearViews(); diff --git a/packages/common/src/directives/ng_style.ts b/packages/common/src/directives/ng_style.ts index 73dab1a154bb4..f13a93e6dc988 100644 --- a/packages/common/src/directives/ng_style.ts +++ b/packages/common/src/directives/ng_style.ts @@ -62,7 +62,7 @@ export class NgStyle implements DoCheck { ngDoCheck() { if (this._differ) { - const changes = this._differ.diff(this._ngStyle !); + const changes = this._differ.diff(this._ngStyle!); if (changes) { this._applyChanges(changes); } diff --git a/packages/common/src/directives/ng_switch.ts b/packages/common/src/directives/ng_switch.ts index 11c0fc8aef19c..e964491e93078 100644 --- a/packages/common/src/directives/ng_switch.ts +++ b/packages/common/src/directives/ng_switch.ts @@ -104,7 +104,7 @@ export class SwitchView { @Directive({selector: '[ngSwitch]'}) export class NgSwitch { // TODO(issue/24571): remove '!'. - private _defaultViews !: SwitchView[]; + private _defaultViews!: SwitchView[]; private _defaultUsed = false; private _caseCount = 0; private _lastCaseCheckIndex = 0; @@ -120,7 +120,9 @@ export class NgSwitch { } /** @internal */ - _addCase(): number { return this._caseCount++; } + _addCase(): number { + return this._caseCount++; + } /** @internal */ _addDefault(view: SwitchView) { @@ -193,8 +195,7 @@ export class NgSwitchCase implements DoCheck { /** * Stores the HTML template to be selected on match. */ - @Input() - ngSwitchCase: any; + @Input() ngSwitchCase: any; constructor( viewContainer: ViewContainerRef, templateRef: TemplateRef<Object>, @@ -206,7 +207,9 @@ export class NgSwitchCase implements DoCheck { /** * Performs case matching. For internal use only. */ - ngDoCheck() { this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); } + ngDoCheck() { + this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); + } } /** diff --git a/packages/common/src/directives/ng_template_outlet.ts b/packages/common/src/directives/ng_template_outlet.ts index 69662161e7b9c..4256313edc548 100644 --- a/packages/common/src/directives/ng_template_outlet.ts +++ b/packages/common/src/directives/ng_template_outlet.ts @@ -101,7 +101,7 @@ export class NgTemplateOutlet implements OnChanges { private _updateExistingContext(ctx: Object): void { for (let propName of Object.keys(ctx)) { - (<any>this._viewRef !.context)[propName] = (<any>this.ngTemplateOutletContext)[propName]; + (<any>this._viewRef!.context)[propName] = (<any>this.ngTemplateOutletContext)[propName]; } } } diff --git a/packages/common/src/dom_adapter.ts b/packages/common/src/dom_adapter.ts index ea8ba85defbf7..5b715ff982b78 100644 --- a/packages/common/src/dom_adapter.ts +++ b/packages/common/src/dom_adapter.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -let _DOM: DomAdapter = null !; +let _DOM: DomAdapter = null!; export function getDOM(): DomAdapter { return _DOM; diff --git a/packages/common/src/i18n/format_date.ts b/packages/common/src/i18n/format_date.ts index b5df8175b377f..06ad7ab760f8c 100644 --- a/packages/common/src/i18n/format_date.ts +++ b/packages/common/src/i18n/format_date.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {FormStyle, FormatWidth, NumberSymbol, Time, TranslationWidth, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleId, getLocaleMonthNames, getLocaleNumberSymbol, getLocaleTimeFormat} from './locale_data_api'; +import {FormatWidth, FormStyle, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleId, getLocaleMonthNames, getLocaleNumberSymbol, getLocaleTimeFormat, NumberSymbol, Time, TranslationWidth} from './locale_data_api'; export const ISO8601_DATE_REGEX = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; @@ -62,7 +62,7 @@ enum TranslationType { * @publicApi */ export function formatDate( - value: string | number | Date, format: string, locale: string, timezone?: string): string { + value: string|number|Date, format: string, locale: string, timezone?: string): string { let date = toDate(value); const namedFormat = getNamedFormat(locale, format); format = namedFormat || format; @@ -278,7 +278,7 @@ function getDateTranslation( const rules = getLocaleExtraDayPeriodRules(locale); const dayPeriods = getLocaleExtraDayPeriods(locale, form, width); let result; - rules.forEach((rule: Time | [Time, Time], index: number) => { + rules.forEach((rule: Time|[Time, Time], index: number) => { if (Array.isArray(rule)) { // morning, afternoon, evening, night const {hours: hoursFrom, minutes: minutesFrom} = rule[0]; @@ -652,7 +652,7 @@ function convertTimezoneToLocal(date: Date, timezone: string, reverse: boolean): * * Throws if unable to convert to a date. */ -export function toDate(value: string | number | Date): Date { +export function toDate(value: string|number|Date): Date { if (isDate(value)) { return value; } diff --git a/packages/common/src/i18n/format_number.ts b/packages/common/src/i18n/format_number.ts index 770b55032d09e..ba4e358e8dbdf 100644 --- a/packages/common/src/i18n/format_number.ts +++ b/packages/common/src/i18n/format_number.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {NumberFormatStyle, NumberSymbol, getLocaleNumberFormat, getLocaleNumberSymbol, getNumberOfCurrencyDigits} from './locale_data_api'; +import {getLocaleNumberFormat, getLocaleNumberSymbol, getNumberOfCurrencyDigits, NumberFormatStyle, NumberSymbol} from './locale_data_api'; export const NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/; const MAX_DIGITS = 22; @@ -153,7 +153,7 @@ export function formatCurrency( const format = getLocaleNumberFormat(locale, NumberFormatStyle.Currency); const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign)); - pattern.minFrac = getNumberOfCurrencyDigits(currencyCode !); + pattern.minFrac = getNumberOfCurrencyDigits(currencyCode!); pattern.maxFrac = pattern.minFrac; const res = formatNumberToLocaleString( @@ -392,8 +392,8 @@ function parseNumber(num: number): ParsedNumber { */ function roundNumber(parsedNumber: ParsedNumber, minFrac: number, maxFrac: number) { if (minFrac > maxFrac) { - throw new Error( - `The minimum number of digits after fraction (${minFrac}) is higher than the maximum (${maxFrac}).`); + throw new Error(`The minimum number of digits after fraction (${ + minFrac}) is higher than the maximum (${maxFrac}).`); } let digits = parsedNumber.digits; diff --git a/packages/common/src/i18n/locale_data.ts b/packages/common/src/i18n/locale_data.ts index cfbdee94d916b..c2355c8a5d333 100644 --- a/packages/common/src/i18n/locale_data.ts +++ b/packages/common/src/i18n/locale_data.ts @@ -16,6 +16,6 @@ import {ɵregisterLocaleData} from '@angular/core'; * * @publicApi */ -export function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void { +export function registerLocaleData(data: any, localeId?: string|any, extraData?: any): void { return ɵregisterLocaleData(data, localeId, extraData); } diff --git a/packages/common/src/i18n/locale_data_api.ts b/packages/common/src/i18n/locale_data_api.ts index 2354580d434ab..94bbb3fabc9be 100644 --- a/packages/common/src/i18n/locale_data_api.ts +++ b/packages/common/src/i18n/locale_data_api.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ɵCurrencyIndex, ɵExtraLocaleDataIndex, ɵLocaleDataIndex, ɵfindLocaleData, ɵgetLocaleCurrencyCode, ɵgetLocalePluralCase} from '@angular/core'; +import {ɵCurrencyIndex, ɵExtraLocaleDataIndex, ɵfindLocaleData, ɵgetLocaleCurrencyCode, ɵgetLocalePluralCase, ɵLocaleDataIndex} from '@angular/core'; import {CURRENCIES_EN, CurrenciesSymbols} from './currencies'; @@ -235,9 +235,9 @@ export function getLocaleId(locale: string): string { export function getLocaleDayPeriods( locale: string, formStyle: FormStyle, width: TranslationWidth): [string, string] { const data = ɵfindLocaleData(locale); - const amPmData = <[ - string, string - ][][]>[data[ɵLocaleDataIndex.DayPeriodsFormat], data[ɵLocaleDataIndex.DayPeriodsStandalone]]; + const amPmData = <[string, string][][]>[ + data[ɵLocaleDataIndex.DayPeriodsFormat], data[ɵLocaleDataIndex.DayPeriodsStandalone] + ]; const amPm = getLastDefinedValue(amPmData, formStyle); return getLastDefinedValue(amPm, width); } @@ -509,8 +509,9 @@ export const getLocalePluralCase: (locale: string) => ((value: number) => Plural function checkFullData(data: any) { if (!data[ɵLocaleDataIndex.ExtraData]) { - throw new Error( - `Missing extra locale data for the locale "${data[ɵLocaleDataIndex.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`); + throw new Error(`Missing extra locale data for the locale "${ + data[ɵLocaleDataIndex + .LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`); } } @@ -536,11 +537,11 @@ function checkFullData(data: any) { * * @publicApi */ -export function getLocaleExtraDayPeriodRules(locale: string): (Time | [Time, Time])[] { +export function getLocaleExtraDayPeriodRules(locale: string): (Time|[Time, Time])[] { const data = ɵfindLocaleData(locale); checkFullData(data); const rules = data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodsRules] || []; - return rules.map((rule: string | [string, string]) => { + return rules.map((rule: string|[string, string]) => { if (typeof rule === 'string') { return extractTime(rule); } @@ -570,8 +571,8 @@ export function getLocaleExtraDayPeriods( const data = ɵfindLocaleData(locale); checkFullData(data); const dayPeriodsData = <string[][][]>[ - data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodFormats], - data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone] + data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodFormats], + data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone] ]; const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || []; return getLastDefinedValue(dayPeriods, width) || []; @@ -646,7 +647,7 @@ function extractTime(time: string): Time { * * @publicApi */ -export function getCurrencySymbol(code: string, format: 'wide' | 'narrow', locale = 'en'): string { +export function getCurrencySymbol(code: string, format: 'wide'|'narrow', locale = 'en'): string { const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || []; const symbolNarrow = currency[ɵCurrencyIndex.SymbolNarrow]; diff --git a/packages/common/src/i18n/localization.ts b/packages/common/src/i18n/localization.ts index 64227fbcbdadf..b213aae529d83 100644 --- a/packages/common/src/i18n/localization.ts +++ b/packages/common/src/i18n/localization.ts @@ -7,7 +7,8 @@ */ import {Inject, Injectable, LOCALE_ID} from '@angular/core'; -import {Plural, getLocalePluralCase} from './locale_data_api'; + +import {getLocalePluralCase, Plural} from './locale_data_api'; /** @@ -51,7 +52,9 @@ export function getPluralCategory( */ @Injectable() export class NgLocaleLocalization extends NgLocalization { - constructor(@Inject(LOCALE_ID) protected locale: string) { super(); } + constructor(@Inject(LOCALE_ID) protected locale: string) { + super(); + } getPluralCategory(value: any, locale?: string): string { const plural = getLocalePluralCase(locale || this.locale)(value); diff --git a/packages/common/src/location/hash_location_strategy.ts b/packages/common/src/location/hash_location_strategy.ts index b25601127e320..4c17e30cbe9da 100644 --- a/packages/common/src/location/hash_location_strategy.ts +++ b/packages/common/src/location/hash_location_strategy.ts @@ -48,7 +48,9 @@ export class HashLocationStrategy extends LocationStrategy { this._platformLocation.onHashChange(fn); } - getBaseHref(): string { return this._baseHref; } + getBaseHref(): string { + return this._baseHref; + } path(includeHash: boolean = false): string { // the hash value is always prefixed with a `#` @@ -80,7 +82,11 @@ export class HashLocationStrategy extends LocationStrategy { this._platformLocation.replaceState(state, title, url); } - forward(): void { this._platformLocation.forward(); } + forward(): void { + this._platformLocation.forward(); + } - back(): void { this._platformLocation.back(); } + back(): void { + this._platformLocation.back(); + } } diff --git a/packages/common/src/location/location.ts b/packages/common/src/location/location.ts index a161654e6d6ea..415852cc2c147 100644 --- a/packages/common/src/location/location.ts +++ b/packages/common/src/location/location.ts @@ -97,7 +97,9 @@ export class Location { * Reports the current state of the location history. * @returns The current value of the `history.state` object. */ - getState(): unknown { return this._platformLocation.getState(); } + getState(): unknown { + return this._platformLocation.getState(); + } /** * Normalizes the given path and compares to the current normalized path. @@ -173,12 +175,16 @@ export class Location { /** * Navigates forward in the platform's history. */ - forward(): void { this._platformStrategy.forward(); } + forward(): void { + this._platformStrategy.forward(); + } /** * Navigates back in the platform's history. */ - back(): void { this._platformStrategy.back(); } + back(): void { + this._platformStrategy.back(); + } /** * Registers a URL change listener. Use to catch updates performed by the Angular @@ -188,7 +194,9 @@ export class Location { */ onUrlChange(fn: (url: string, state: unknown) => void) { this._urlChangeListeners.push(fn); - this.subscribe(v => { this._notifyUrlChangeListeners(v.url, v.state); }); + this.subscribe(v => { + this._notifyUrlChangeListeners(v.url, v.state); + }); } /** @internal */ diff --git a/packages/common/src/location/location_strategy.ts b/packages/common/src/location/location_strategy.ts index a4e732c20ad8d..6e3fc8bbb1772 100644 --- a/packages/common/src/location/location_strategy.ts +++ b/packages/common/src/location/location_strategy.ts @@ -126,9 +126,13 @@ export class PathLocationStrategy extends LocationStrategy { this._platformLocation.onHashChange(fn); } - getBaseHref(): string { return this._baseHref; } + getBaseHref(): string { + return this._baseHref; + } - prepareExternalUrl(internal: string): string { return joinWithSlash(this._baseHref, internal); } + prepareExternalUrl(internal: string): string { + return joinWithSlash(this._baseHref, internal); + } path(includeHash: boolean = false): string { const pathname = @@ -147,7 +151,11 @@ export class PathLocationStrategy extends LocationStrategy { this._platformLocation.replaceState(state, title, externalUrl); } - forward(): void { this._platformLocation.forward(); } + forward(): void { + this._platformLocation.forward(); + } - back(): void { this._platformLocation.back(); } + back(): void { + this._platformLocation.back(); + } } diff --git a/packages/common/src/location/platform_location.ts b/packages/common/src/location/platform_location.ts index 4139d768153c1..8470161f7174d 100644 --- a/packages/common/src/location/platform_location.ts +++ b/packages/common/src/location/platform_location.ts @@ -86,7 +86,9 @@ export interface LocationChangeEvent { /** * @publicApi */ -export interface LocationChangeListener { (event: LocationChangeEvent): any; } +export interface LocationChangeListener { + (event: LocationChangeEvent): any; +} @@ -101,8 +103,8 @@ export interface LocationChangeListener { (event: LocationChangeEvent): any; } useFactory: createBrowserPlatformLocation, }) export class BrowserPlatformLocation extends PlatformLocation { - public readonly location !: Location; - private _history !: History; + public readonly location!: Location; + private _history!: History; constructor(@Inject(DOCUMENT) private _doc: any) { super(); @@ -112,11 +114,13 @@ export class BrowserPlatformLocation extends PlatformLocation { // This is moved to its own method so that `MockPlatformLocationStrategy` can overwrite it /** @internal */ _init() { - (this as{location: Location}).location = getDOM().getLocation(); + (this as {location: Location}).location = getDOM().getLocation(); this._history = getDOM().getHistory(); } - getBaseHrefFromDOM(): string { return getDOM().getBaseHref(this._doc) !; } + getBaseHrefFromDOM(): string { + return getDOM().getBaseHref(this._doc)!; + } onPopState(fn: LocationChangeListener): void { getDOM().getGlobalEventTarget(this._doc, 'window').addEventListener('popstate', fn, false); @@ -126,14 +130,30 @@ export class BrowserPlatformLocation extends PlatformLocation { getDOM().getGlobalEventTarget(this._doc, 'window').addEventListener('hashchange', fn, false); } - get href(): string { return this.location.href; } - get protocol(): string { return this.location.protocol; } - get hostname(): string { return this.location.hostname; } - get port(): string { return this.location.port; } - get pathname(): string { return this.location.pathname; } - get search(): string { return this.location.search; } - get hash(): string { return this.location.hash; } - set pathname(newPath: string) { this.location.pathname = newPath; } + get href(): string { + return this.location.href; + } + get protocol(): string { + return this.location.protocol; + } + get hostname(): string { + return this.location.hostname; + } + get port(): string { + return this.location.port; + } + get pathname(): string { + return this.location.pathname; + } + get search(): string { + return this.location.search; + } + get hash(): string { + return this.location.hash; + } + set pathname(newPath: string) { + this.location.pathname = newPath; + } pushState(state: any, title: string, url: string): void { if (supportsState()) { @@ -151,11 +171,17 @@ export class BrowserPlatformLocation extends PlatformLocation { } } - forward(): void { this._history.forward(); } + forward(): void { + this._history.forward(); + } - back(): void { this._history.back(); } + back(): void { + this._history.back(); + } - getState(): unknown { return this._history.state; } + getState(): unknown { + return this._history.state; + } } export function supportsState(): boolean { diff --git a/packages/common/src/pipes/async_pipe.ts b/packages/common/src/pipes/async_pipe.ts index 40d565d2f18d3..54a62d69031ef 100644 --- a/packages/common/src/pipes/async_pipe.ts +++ b/packages/common/src/pipes/async_pipe.ts @@ -19,17 +19,28 @@ interface SubscriptionStrategy { class ObservableStrategy implements SubscriptionStrategy { createSubscription(async: Observable<any>, updateLatestValue: any): SubscriptionLike { - return async.subscribe({next: updateLatestValue, error: (e: any) => { throw e; }}); + return async.subscribe({ + next: updateLatestValue, + error: (e: any) => { + throw e; + } + }); } - dispose(subscription: SubscriptionLike): void { subscription.unsubscribe(); } + dispose(subscription: SubscriptionLike): void { + subscription.unsubscribe(); + } - onDestroy(subscription: SubscriptionLike): void { subscription.unsubscribe(); } + onDestroy(subscription: SubscriptionLike): void { + subscription.unsubscribe(); + } } class PromiseStrategy implements SubscriptionStrategy { createSubscription(async: Promise<any>, updateLatestValue: (v: any) => any): Promise<any> { - return async.then(updateLatestValue, e => { throw e; }); + return async.then(updateLatestValue, e => { + throw e; + }); } dispose(subscription: Promise<any>): void {} @@ -74,7 +85,7 @@ export class AsyncPipe implements OnDestroy, PipeTransform { private _subscription: SubscriptionLike|Promise<any>|null = null; private _obj: Observable<any>|Promise<any>|EventEmitter<any>|null = null; - private _strategy: SubscriptionStrategy = null !; + private _strategy: SubscriptionStrategy = null!; constructor(private _ref: ChangeDetectorRef) {} @@ -130,7 +141,7 @@ export class AsyncPipe implements OnDestroy, PipeTransform { } private _dispose(): void { - this._strategy.dispose(this._subscription !); + this._strategy.dispose(this._subscription!); this._latestValue = null; this._latestReturnedValue = null; this._subscription = null; diff --git a/packages/common/src/pipes/i18n_plural_pipe.ts b/packages/common/src/pipes/i18n_plural_pipe.ts index 0a4fa6a030ebd..e8500d86bd867 100644 --- a/packages/common/src/pipes/i18n_plural_pipe.ts +++ b/packages/common/src/pipes/i18n_plural_pipe.ts @@ -7,7 +7,9 @@ */ import {Pipe, PipeTransform} from '@angular/core'; -import {NgLocalization, getPluralCategory} from '../i18n/localization'; + +import {getPluralCategory, NgLocalization} from '../i18n/localization'; + import {invalidPipeArgumentError} from './invalid_pipe_argument_error'; const _INTERPOLATION_REGEXP: RegExp = /#/g; diff --git a/packages/common/src/pipes/index.ts b/packages/common/src/pipes/index.ts index 9dc1e8d10a296..708b67f49ad05 100644 --- a/packages/common/src/pipes/index.ts +++ b/packages/common/src/pipes/index.ts @@ -26,11 +26,11 @@ export { CurrencyPipe, DatePipe, DecimalPipe, - KeyValue, - KeyValuePipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, + KeyValue, + KeyValuePipe, LowerCasePipe, PercentPipe, SlicePipe, diff --git a/packages/common/src/pipes/json_pipe.ts b/packages/common/src/pipes/json_pipe.ts index 7ecbdddbe370b..4bae1ec2a055e 100644 --- a/packages/common/src/pipes/json_pipe.ts +++ b/packages/common/src/pipes/json_pipe.ts @@ -28,5 +28,7 @@ export class JsonPipe implements PipeTransform { /** * @param value A value of any type to convert into a JSON-format string. */ - transform(value: any): string { return JSON.stringify(value, null, 2); } + transform(value: any): string { + return JSON.stringify(value, null, 2); + } } diff --git a/packages/common/src/pipes/keyvalue_pipe.ts b/packages/common/src/pipes/keyvalue_pipe.ts index 592e57f95849a..a0e56be48a75d 100644 --- a/packages/common/src/pipes/keyvalue_pipe.ts +++ b/packages/common/src/pipes/keyvalue_pipe.ts @@ -47,7 +47,7 @@ export interface KeyValue<K, V> { export class KeyValuePipe implements PipeTransform { constructor(private readonly differs: KeyValueDiffers) {} - private differ !: KeyValueDiffer<any, any>; + private differ!: KeyValueDiffer<any, any>; private keyValues: Array<KeyValue<any, any>> = []; transform<K, V>(input: null, compareFn?: (a: KeyValue<K, V>, b: KeyValue<K, V>) => number): null; @@ -90,7 +90,7 @@ export class KeyValuePipe implements PipeTransform { if (differChanges) { this.keyValues = []; differChanges.forEachItem((r: KeyValueChangeRecord<K, V>) => { - this.keyValues.push(makeKeyValuePair(r.key, r.currentValue !)); + this.keyValues.push(makeKeyValuePair(r.key, r.currentValue!)); }); this.keyValues.sort(compareFn); } diff --git a/packages/common/src/pipes/number_pipe.ts b/packages/common/src/pipes/number_pipe.ts index db8c6546faf67..e681f27803c59 100644 --- a/packages/common/src/pipes/number_pipe.ts +++ b/packages/common/src/pipes/number_pipe.ts @@ -253,7 +253,7 @@ function isEmpty(value: any): boolean { /** * Transforms a string into a number (if needed). */ -function strToNumber(value: number | string): number { +function strToNumber(value: number|string): number { // Convert strings to numbers if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) { return Number(value); diff --git a/packages/common/src/pipes/slice_pipe.ts b/packages/common/src/pipes/slice_pipe.ts index 13f57fc2ae7cb..59fd55da63fe2 100644 --- a/packages/common/src/pipes/slice_pipe.ts +++ b/packages/common/src/pipes/slice_pipe.ts @@ -75,5 +75,7 @@ export class SlicePipe implements PipeTransform { return value.slice(start, end); } - private supports(obj: any): boolean { return typeof obj === 'string' || Array.isArray(obj); } + private supports(obj: any): boolean { + return typeof obj === 'string' || Array.isArray(obj); + } } diff --git a/packages/common/src/viewport_scroller.ts b/packages/common/src/viewport_scroller.ts index 39044f51d93ca..9462a709a327b 100644 --- a/packages/common/src/viewport_scroller.ts +++ b/packages/common/src/viewport_scroller.ts @@ -186,7 +186,9 @@ export class NullViewportScroller implements ViewportScroller { /** * Empty implementation */ - getScrollPosition(): [number, number] { return [0, 0]; } + getScrollPosition(): [number, number] { + return [0, 0]; + } /** * Empty implementation diff --git a/packages/common/test/cookie_spec.ts b/packages/common/test/cookie_spec.ts index 36b10c0e35328..0fa17ba5ab1d6 100644 --- a/packages/common/test/cookie_spec.ts +++ b/packages/common/test/cookie_spec.ts @@ -9,12 +9,12 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {parseCookieValue} from '@angular/common/src/cookie'; import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; diff --git a/packages/common/test/directives/ng_class_spec.ts b/packages/common/test/directives/ng_class_spec.ts index d31771932de40..419b443f8370d 100644 --- a/packages/common/test/directives/ng_class_spec.ts +++ b/packages/common/test/directives/ng_class_spec.ts @@ -7,7 +7,7 @@ */ import {Component} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; { describe('binding to CSS class list', () => { @@ -18,14 +18,18 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; } function detectChangesAndExpectClassName(classes: string): void { - fixture !.detectChanges(); - let nonNormalizedClassName = fixture !.debugElement.children[0].nativeElement.className; + fixture!.detectChanges(); + let nonNormalizedClassName = fixture!.debugElement.children[0].nativeElement.className; expect(normalizeClassNames(nonNormalizedClassName)).toEqual(normalizeClassNames(classes)); } - function getComponent(): TestComponent { return fixture !.debugElement.componentInstance; } + function getComponent(): TestComponent { + return fixture!.debugElement.componentInstance; + } - afterEach(() => { fixture = null; }); + afterEach(() => { + fixture = null; + }); beforeEach(() => { TestBed.configureTestingModule({ @@ -43,7 +47,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; })); describe('expressions evaluating to objects', () => { - it('should add classes specified in an object literal', async(() => { fixture = createTestComponent('<div [ngClass]="{foo: true, bar: false}"></div>'); @@ -74,13 +77,13 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; detectChangesAndExpectClassName('foo'); - objExpr !['bar'] = true; + objExpr!['bar'] = true; detectChangesAndExpectClassName('foo bar'); - objExpr !['baz'] = true; + objExpr!['baz'] = true; detectChangesAndExpectClassName('foo bar baz'); - delete (objExpr !['bar']); + delete (objExpr!['bar']); detectChangesAndExpectClassName('foo baz'); })); @@ -129,7 +132,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; }); describe('expressions evaluating to lists', () => { - it('should add classes specified in a list literal', async(() => { fixture = createTestComponent(`<div [ngClass]="['foo', 'bar', 'foo-bar', 'fooBar']"></div>`); @@ -194,14 +196,13 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; it('should throw with descriptive error message when CSS class is not a string', () => { fixture = createTestComponent(`<div [ngClass]="['foo', {}]"></div>`); - expect(() => fixture !.detectChanges()) + expect(() => fixture!.detectChanges()) .toThrowError( /NgClass can only toggle CSS classes expressed as strings, got \[object Object\]/); }); }); describe('expressions evaluating to sets', () => { - it('should add and remove classes if the set instance changed', async(() => { fixture = createTestComponent('<div [ngClass]="setExpr"></div>'); let setExpr = new Set<string>(); @@ -217,7 +218,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; }); describe('expressions evaluating to string', () => { - it('should add classes specified in a string literal', async(() => { fixture = createTestComponent(`<div [ngClass]="'foo bar foo-bar fooBar'"></div>`); detectChangesAndExpectClassName('foo bar foo-bar fooBar'); @@ -257,19 +257,17 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; getComponent().strExpr = ''; detectChangesAndExpectClassName('foo'); })); - }); describe('cooperation with other class-changing constructs', () => { - it('should co-operate with the class attribute', async(() => { fixture = createTestComponent('<div [ngClass]="objExpr" class="init foo"></div>'); const objExpr = getComponent().objExpr; - objExpr !['bar'] = true; + objExpr!['bar'] = true; detectChangesAndExpectClassName('init foo bar'); - objExpr !['foo'] = false; + objExpr!['foo'] = false; detectChangesAndExpectClassName('init bar'); getComponent().objExpr = null; @@ -280,10 +278,10 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; fixture = createTestComponent(`<div [ngClass]="objExpr" class="{{'init foo'}}"></div>`); const objExpr = getComponent().objExpr; - objExpr !['bar'] = true; + objExpr!['bar'] = true; detectChangesAndExpectClassName(`init foo bar`); - objExpr !['foo'] = false; + objExpr!['foo'] = false; detectChangesAndExpectClassName(`init bar`); getComponent().objExpr = null; @@ -306,10 +304,10 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; createTestComponent(`<div [ngClass]="objExpr" class="init" [class]="'foo'"></div>`); const objExpr = getComponent().objExpr; - objExpr !['bar'] = true; + objExpr!['bar'] = true; detectChangesAndExpectClassName(`init foo bar`); - objExpr !['foo'] = false; + objExpr!['foo'] = false; detectChangesAndExpectClassName(`init bar`); getComponent().objExpr = null; @@ -324,10 +322,10 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; detectChangesAndExpectClassName('init foo baz'); - objExpr !['bar'] = true; + objExpr!['bar'] = true; detectChangesAndExpectClassName('init foo baz bar'); - objExpr !['foo'] = false; + objExpr!['foo'] = false; detectChangesAndExpectClassName('init baz bar'); getComponent().condition = false; @@ -342,7 +340,7 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; detectChangesAndExpectClassName('init foo'); - cmp.objExpr !['bar'] = true; + cmp.objExpr!['bar'] = true; detectChangesAndExpectClassName('init foo bar'); cmp.strExpr = 'baz'; @@ -354,7 +352,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; }); describe('prevent regressions', () => { - // https://github.com/angular/angular/issues/34336 it('should not write to the native node unless the bound expression has changed', () => { fixture = createTestComponent(`<div [ngClass]="{'color-red': condition}"></div>`); @@ -392,7 +389,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; expect(leading.className).toBe('foo'); expect(trailing.className).toBe('foo'); }); - }); }); } @@ -406,7 +402,9 @@ class TestComponent { objExpr: {[klass: string]: any}|null = {'foo': true, 'bar': false}; strExpr: string|null = 'foo'; - constructor() { this.setExpr.add('foo'); } + constructor() { + this.setExpr.add('foo'); + } } function createTestComponent(template: string): ComponentFixture<TestComponent> { diff --git a/packages/common/test/directives/ng_component_outlet_spec.ts b/packages/common/test/directives/ng_component_outlet_spec.ts index b00c2e8efe46d..e5ddc9d63b796 100644 --- a/packages/common/test/directives/ng_component_outlet_spec.ts +++ b/packages/common/test/directives/ng_component_outlet_spec.ts @@ -8,13 +8,14 @@ import {CommonModule} from '@angular/common'; import {NgComponentOutlet} from '@angular/common/src/directives/ng_component_outlet'; -import {Compiler, Component, ComponentRef, Inject, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, NgModuleFactory, Optional, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core'; -import {TestBed, async} from '@angular/core/testing'; +import {Compiler, Component, ComponentRef, Inject, InjectionToken, Injector, NgModule, NgModuleFactory, NO_ERRORS_SCHEMA, Optional, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core'; +import {async, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('insert/remove', () => { - - beforeEach(() => { TestBed.configureTestingModule({imports: [TestModule]}); }); + beforeEach(() => { + TestBed.configureTestingModule({imports: [TestModule]}); + }); it('should do nothing if component is null', async(() => { const template = `<ng-template *ngComponentOutlet="currentComponent"></ng-template>`; @@ -51,7 +52,7 @@ describe('insert/remove', () => { fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('foo'); expect(fixture.componentInstance.cmpRef).toBeAnInstanceOf(ComponentRef); - expect(fixture.componentInstance.cmpRef !.instance).toBeAnInstanceOf(InjectedComponent); + expect(fixture.componentInstance.cmpRef!.instance).toBeAnInstanceOf(InjectedComponent); })); @@ -99,11 +100,10 @@ describe('insert/remove', () => { [{provide: TEST_TOKEN, useValue: uniqueValue}], fixture.componentRef.injector); fixture.detectChanges(); - let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef !; + let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef!; expect(cmpRef).toBeAnInstanceOf(ComponentRef); expect(cmpRef.instance).toBeAnInstanceOf(InjectedComponent); expect(cmpRef.instance.testToken).toBe(uniqueValue); - })); @@ -114,7 +114,7 @@ describe('insert/remove', () => { fixture.componentInstance.cmpRef = null; fixture.componentInstance.currentComponent = InjectedComponent; fixture.detectChanges(); - let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef !; + let cmpRef: ComponentRef<InjectedComponent> = fixture.componentInstance.cmpRef!; expect(cmpRef).toBeAnInstanceOf(ComponentRef); expect(cmpRef.instance).toBeAnInstanceOf(InjectedComponent); expect(cmpRef.instance.testToken).toBeNull(); @@ -166,7 +166,7 @@ describe('insert/remove', () => { fixture.componentInstance.currentComponent = Module2InjectedComponent; fixture.detectChanges(); - const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef'] !; + const moduleRef = fixture.componentInstance.ngComponentOutlet['_moduleRef']!; spyOn(moduleRef, 'destroy').and.callThrough(); expect(moduleRef.destroy).not.toHaveBeenCalled(); @@ -224,21 +224,25 @@ const TEST_CMP_TEMPLATE = @Component({selector: 'test-cmp', template: TEST_CMP_TEMPLATE}) class TestComponent { // TODO(issue/24571): remove '!'. - currentComponent !: Type<any>| null; + currentComponent!: Type<any>|null; // TODO(issue/24571): remove '!'. - injector !: Injector; + injector!: Injector; // TODO(issue/24571): remove '!'. - projectables !: any[][]; + projectables!: any[][]; // TODO(issue/24571): remove '!'. - module !: NgModuleFactory<any>; + module!: NgModuleFactory<any>; - get cmpRef(): ComponentRef<any>|null { return this.ngComponentOutlet['_componentRef']; } - set cmpRef(value: ComponentRef<any>|null) { this.ngComponentOutlet['_componentRef'] = value; } + get cmpRef(): ComponentRef<any>|null { + return this.ngComponentOutlet['_componentRef']; + } + set cmpRef(value: ComponentRef<any>|null) { + this.ngComponentOutlet['_componentRef'] = value; + } // TODO(issue/24571): remove '!'. - @ViewChildren(TemplateRef) tplRefs !: QueryList<TemplateRef<any>>; + @ViewChildren(TemplateRef) tplRefs!: QueryList<TemplateRef<any>>; // TODO(issue/24571): remove '!'. - @ViewChild(NgComponentOutlet, {static: true}) ngComponentOutlet !: NgComponentOutlet; + @ViewChild(NgComponentOutlet, {static: true}) ngComponentOutlet!: NgComponentOutlet; constructor(public vcRef: ViewContainerRef) {} } diff --git a/packages/common/test/directives/ng_for_spec.ts b/packages/common/test/directives/ng_for_spec.ts index fef7e67976573..6ce561de1221a 100644 --- a/packages/common/test/directives/ng_for_spec.ts +++ b/packages/common/test/directives/ng_for_spec.ts @@ -8,7 +8,7 @@ import {CommonModule} from '@angular/common'; import {Component} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -18,14 +18,18 @@ let thisArg: any; describe('ngFor', () => { let fixture: ComponentFixture<any>; - function getComponent(): TestComponent { return fixture.componentInstance; } + function getComponent(): TestComponent { + return fixture.componentInstance; + } function detectChangesAndExpectText(text: string): void { fixture.detectChanges(); expect(fixture.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null as any; }); + afterEach(() => { + fixture = null as any; + }); beforeEach(() => { TestBed.configureTestingModule({ @@ -103,7 +107,7 @@ let thisArg: any; detectChangesAndExpectText('1;2;'); - getComponent().items = null !; + getComponent().items = null!; detectChangesAndExpectText(''); getComponent().items = [1, 2, 3]; @@ -377,16 +381,24 @@ let thisArg: any; } class Foo { - toString() { return 'foo'; } + toString() { + return 'foo'; + } } @Component({selector: 'test-cmp', template: ''}) class TestComponent { value: any; items: any[] = [1, 2]; - trackById(index: number, item: any): string { return item['id']; } - trackByIndex(index: number, item: any): number { return index; } - trackByContext(): void { thisArg = this; } + trackById(index: number, item: any): string { + return item['id']; + } + trackByIndex(index: number, item: any): number { + return index; + } + trackByContext(): void { + thisArg = this; + } } const TEMPLATE = '<div><span *ngFor="let item of items">{{item.toString()}};</span></div>'; diff --git a/packages/common/test/directives/ng_if_spec.ts b/packages/common/test/directives/ng_if_spec.ts index 84b73b4ce1436..2e9cd74069a71 100644 --- a/packages/common/test/directives/ng_if_spec.ts +++ b/packages/common/test/directives/ng_if_spec.ts @@ -8,7 +8,7 @@ import {CommonModule, ɵgetDOM as getDOM} from '@angular/common'; import {Component} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -16,9 +16,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('ngIf directive', () => { let fixture: ComponentFixture<any>; - function getComponent(): TestComponent { return fixture.componentInstance; } + function getComponent(): TestComponent { + return fixture.componentInstance; + } - afterEach(() => { fixture = null !; }); + afterEach(() => { + fixture = null!; + }); beforeEach(() => { TestBed.configureTestingModule({ diff --git a/packages/common/test/directives/ng_plural_spec.ts b/packages/common/test/directives/ng_plural_spec.ts index 07e6e66740b7f..9a5a30bb983d2 100644 --- a/packages/common/test/directives/ng_plural_spec.ts +++ b/packages/common/test/directives/ng_plural_spec.ts @@ -8,21 +8,25 @@ import {CommonModule, NgLocalization} from '@angular/common'; import {Component, Injectable} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; { describe('ngPlural', () => { let fixture: ComponentFixture<any>; - function getComponent(): TestComponent { return fixture.componentInstance; } + function getComponent(): TestComponent { + return fixture.componentInstance; + } function detectChangesAndExpectText<T>(text: string): void { fixture.detectChanges(); expect(fixture.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null !; }); + afterEach(() => { + fixture = null!; + }); beforeEach(() => { TestBed.configureTestingModule({ diff --git a/packages/common/test/directives/ng_style_spec.ts b/packages/common/test/directives/ng_style_spec.ts index aaba40cd80e88..3ec43fa203aa4 100644 --- a/packages/common/test/directives/ng_style_spec.ts +++ b/packages/common/test/directives/ng_style_spec.ts @@ -8,19 +8,23 @@ import {CommonModule} from '@angular/common'; import {Component} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; { describe('NgStyle', () => { let fixture: ComponentFixture<TestComponent>; - function getComponent(): TestComponent { return fixture.componentInstance; } + function getComponent(): TestComponent { + return fixture.componentInstance; + } function expectNativeEl(fixture: ComponentFixture<any>): any { return expect(fixture.debugElement.children[0].nativeElement); } - afterEach(() => { fixture = null !; }); + afterEach(() => { + fixture = null!; + }); beforeEach(() => { TestBed.configureTestingModule({declarations: [TestComponent], imports: [CommonModule]}); @@ -159,7 +163,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; })); it('should not write to the native node unless the bound expression has changed', () => { - const template = `<div [ngStyle]="{'color': expr}"></div>`; fixture = createTestComponent(template); @@ -189,7 +192,6 @@ import {ComponentFixture, TestBed, async} from '@angular/core/testing'; fixture.detectChanges(); expectNativeEl(fixture).toHaveCssStyle({'width': '400px'}); }); - }); } diff --git a/packages/common/test/directives/ng_switch_spec.ts b/packages/common/test/directives/ng_switch_spec.ts index 436d8ad36bb18..0dbeab3acef4d 100644 --- a/packages/common/test/directives/ng_switch_spec.ts +++ b/packages/common/test/directives/ng_switch_spec.ts @@ -15,14 +15,18 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('NgSwitch', () => { let fixture: ComponentFixture<any>; - function getComponent(): TestComponent { return fixture.componentInstance; } + function getComponent(): TestComponent { + return fixture.componentInstance; + } function detectChangesAndExpectText(text: string): void { fixture.detectChanges(); expect(fixture.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null !; }); + afterEach(() => { + fixture = null!; + }); beforeEach(() => { TestBed.configureTestingModule({ @@ -118,13 +122,14 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); describe('corner cases', () => { - it('should not create the default case if another case matches', () => { const log: string[] = []; @Directive({selector: '[test]'}) class TestDirective { - constructor(@Attribute('test') test: string) { log.push(test); } + constructor(@Attribute('test') test: string) { + log.push(test); + } } const template = '<div [ngSwitch]="switchValue">' + @@ -149,7 +154,6 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; fixture = createTestComponent(template); detectChangesAndExpectText('when default1;when default2;'); - }); it('should allow defaults before cases', () => { @@ -223,8 +227,8 @@ class TestComponent { ` }) class ComplexComponent { - @ViewChild('foo', {static: true}) foo !: TemplateRef<any>; - @ViewChild('bar', {static: true}) bar !: TemplateRef<any>; + @ViewChild('foo', {static: true}) foo!: TemplateRef<any>; + @ViewChild('bar', {static: true}) bar!: TemplateRef<any>; state: string = 'case1'; } diff --git a/packages/common/test/directives/ng_template_outlet_spec.ts b/packages/common/test/directives/ng_template_outlet_spec.ts index 57ee45b50976b..b6f6776806e1f 100644 --- a/packages/common/test/directives/ng_template_outlet_spec.ts +++ b/packages/common/test/directives/ng_template_outlet_spec.ts @@ -8,20 +8,24 @@ import {CommonModule} from '@angular/common'; import {Component, ContentChildren, Directive, Injectable, NO_ERRORS_SCHEMA, OnDestroy, QueryList, TemplateRef} from '@angular/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('NgTemplateOutlet', () => { let fixture: ComponentFixture<any>; - function setTplRef(value: any): void { fixture.componentInstance.currentTplRef = value; } + function setTplRef(value: any): void { + fixture.componentInstance.currentTplRef = value; + } function detectChangesAndExpectText(text: string): void { fixture.detectChanges(); expect(fixture.debugElement.nativeElement).toHaveText(text); } - afterEach(() => { fixture = null as any; }); + afterEach(() => { + fixture = null as any; + }); beforeEach(() => { TestBed.configureTestingModule({ @@ -58,7 +62,7 @@ describe('NgTemplateOutlet', () => { `<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`; fixture = createTestComponent(template); fixture.detectChanges(); - const refs = fixture.debugElement.children[0].references !['refs']; + const refs = fixture.debugElement.children[0].references!['refs']; setTplRef(refs.tplRefs.first); detectChangesAndExpectText('foo'); @@ -74,7 +78,7 @@ describe('NgTemplateOutlet', () => { fixture = createTestComponent(template); fixture.detectChanges(); - const refs = fixture.debugElement.children[0].references !['refs']; + const refs = fixture.debugElement.children[0].references!['refs']; setTplRef(refs.tplRefs.first); detectChangesAndExpectText('foo'); @@ -223,7 +227,7 @@ describe('NgTemplateOutlet', () => { `<ng-container [ngTemplateOutlet]="currentTplRef"></ng-container>`; fixture = createTestComponent(template); fixture.detectChanges(); - const refs = fixture.debugElement.children[0].references !['refs']; + const refs = fixture.debugElement.children[0].references!['refs']; setTplRef(refs.tplRefs.first); detectChangesAndExpectText('foo'); @@ -236,7 +240,6 @@ describe('NgTemplateOutlet', () => { detectChangesAndExpectText('foo'); }).not.toThrow(); })); - }); @Injectable() @@ -248,19 +251,21 @@ class DestroyedSpyService { class DestroyableCmpt implements OnDestroy { constructor(private _spyService: DestroyedSpyService) {} - ngOnDestroy(): void { this._spyService.destroyed = true; } + ngOnDestroy(): void { + this._spyService.destroyed = true; + } } @Directive({selector: 'tpl-refs', exportAs: 'tplRefs'}) class CaptureTplRefs { // TODO(issue/24571): remove '!'. - @ContentChildren(TemplateRef) tplRefs !: QueryList<TemplateRef<any>>; + @ContentChildren(TemplateRef) tplRefs!: QueryList<TemplateRef<any>>; } @Component({selector: 'test-cmp', template: ''}) class TestComponent { // TODO(issue/24571): remove '!'. - currentTplRef !: TemplateRef<any>; + currentTplRef!: TemplateRef<any>; context: any = {foo: 'bar'}; value = 'bar'; } diff --git a/packages/common/test/directives/non_bindable_spec.ts b/packages/common/test/directives/non_bindable_spec.ts index d77194450cb54..ceda2fb42fd95 100644 --- a/packages/common/test/directives/non_bindable_spec.ts +++ b/packages/common/test/directives/non_bindable_spec.ts @@ -9,13 +9,12 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {Component, Directive} from '@angular/core'; import {ElementRef} from '@angular/core/src/linker/element_ref'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {hasClass} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; { describe('non-bindable', () => { - beforeEach(() => { TestBed.configureTestingModule({ declarations: [TestComponent, TestDirective], @@ -53,13 +52,17 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; @Directive({selector: '[test-dec]'}) class TestDirective { - constructor(el: ElementRef) { el.nativeElement.classList.add('compiled'); } + constructor(el: ElementRef) { + el.nativeElement.classList.add('compiled'); + } } @Component({selector: 'test-cmp', template: ''}) class TestComponent { text: string; - constructor() { this.text = 'foo'; } + constructor() { + this.text = 'foo'; + } } function createTestComponent(template: string): ComponentFixture<TestComponent> { diff --git a/packages/common/test/i18n/format_date_spec.ts b/packages/common/test/i18n/format_date_spec.ts index 7bbe33938888a..cd1b6dfcae4fe 100644 --- a/packages/common/test/i18n/format_date_spec.ts +++ b/packages/common/test/i18n/format_date_spec.ts @@ -12,35 +12,50 @@ import localeEnExtra from '@angular/common/locales/extra/en'; import localeHu from '@angular/common/locales/hu'; import localeSr from '@angular/common/locales/sr'; import localeTh from '@angular/common/locales/th'; -import {isDate, toDate, formatDate} from '@angular/common/src/i18n/format_date'; -import {ɵDEFAULT_LOCALE_ID, ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core'; +import {formatDate, isDate, toDate} from '@angular/common/src/i18n/format_date'; +import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; describe('Format date', () => { describe('toDate', () => { - it('should support date', () => { expect(isDate(toDate(new Date()))).toBeTruthy(); }); + it('should support date', () => { + expect(isDate(toDate(new Date()))).toBeTruthy(); + }); - it('should support int', () => { expect(isDate(toDate(123456789))).toBeTruthy(); }); + it('should support int', () => { + expect(isDate(toDate(123456789))).toBeTruthy(); + }); - it('should support numeric strings', - () => { expect(isDate(toDate('123456789'))).toBeTruthy(); }); + it('should support numeric strings', () => { + expect(isDate(toDate('123456789'))).toBeTruthy(); + }); - it('should support decimal strings', - () => { expect(isDate(toDate('123456789.11'))).toBeTruthy(); }); + it('should support decimal strings', () => { + expect(isDate(toDate('123456789.11'))).toBeTruthy(); + }); - it('should support ISO string', - () => { expect(isDate(toDate('2015-06-15T21:43:11Z'))).toBeTruthy(); }); + it('should support ISO string', () => { + expect(isDate(toDate('2015-06-15T21:43:11Z'))).toBeTruthy(); + }); - it('should throw for empty string', () => { expect(() => toDate('')).toThrow(); }); + it('should throw for empty string', () => { + expect(() => toDate('')).toThrow(); + }); - it('should throw for alpha numeric strings', - () => { expect(() => toDate('123456789 hello')).toThrow(); }); + it('should throw for alpha numeric strings', () => { + expect(() => toDate('123456789 hello')).toThrow(); + }); - it('should throw for NaN', () => { expect(() => toDate(Number.NaN)).toThrow(); }); + it('should throw for NaN', () => { + expect(() => toDate(Number.NaN)).toThrow(); + }); - it('should support ISO string without time', - () => { expect(isDate(toDate('2015-01-01'))).toBeTruthy(); }); + it('should support ISO string without time', () => { + expect(isDate(toDate('2015-01-01'))).toBeTruthy(); + }); - it('should throw for objects', () => { expect(() => toDate({} as any)).toThrow(); }); + it('should throw for objects', () => { + expect(() => toDate({} as any)).toThrow(); + }); }); describe('formatDate', () => { @@ -49,7 +64,7 @@ describe('Format date', () => { let date: Date; // Check the transformation of a date into a pattern - function expectDateFormatAs(date: Date | string, pattern: any, output: string): void { + function expectDateFormatAs(date: Date|string, pattern: any, output: string): void { expect(formatDate(date, pattern, ɵDEFAULT_LOCALE_ID)) .toEqual(output, `pattern: "${pattern}"`); } @@ -65,7 +80,9 @@ describe('Format date', () => { afterAll(() => ɵunregisterLocaleData()); - beforeEach(() => { date = new Date(2015, 5, 15, 9, 3, 1, 550); }); + beforeEach(() => { + date = new Date(2015, 5, 15, 9, 3, 1, 550); + }); it('should format each component correctly', () => { const dateFixtures: any = { @@ -293,7 +310,7 @@ describe('Format date', () => { }); it('should remove bidi control characters', - () => expect(formatDate(date, 'MM/dd/yyyy', ɵDEFAULT_LOCALE_ID) !.length).toEqual(10)); + () => expect(formatDate(date, 'MM/dd/yyyy', ɵDEFAULT_LOCALE_ID)!.length).toEqual(10)); it(`should format the date correctly in various locales`, () => { expect(formatDate(date, 'short', 'de')).toEqual('15.06.15, 09:03'); diff --git a/packages/common/test/i18n/format_number_spec.ts b/packages/common/test/i18n/format_number_spec.ts index c6f384095398b..f16cb9ec1731a 100644 --- a/packages/common/test/i18n/format_number_spec.ts +++ b/packages/common/test/i18n/format_number_spec.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import {formatCurrency, formatNumber, formatPercent} from '@angular/common'; +import localeAr from '@angular/common/locales/ar'; import localeEn from '@angular/common/locales/en'; import localeEsUS from '@angular/common/locales/es-US'; import localeFr from '@angular/common/locales/fr'; -import localeAr from '@angular/common/locales/ar'; -import {formatCurrency, formatNumber, formatPercent} from '@angular/common'; +import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; -import {ɵDEFAULT_LOCALE_ID, ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core'; describe('Format number', () => { beforeAll(() => { @@ -44,8 +44,9 @@ describe('Format number', () => { }); describe('transform with custom locales', () => { - it('should return the correct format for es-US', - () => { expect(formatNumber(9999999.99, 'es-US', '1.2-2')).toEqual('9,999,999.99'); }); + it('should return the correct format for es-US', () => { + expect(formatNumber(9999999.99, 'es-US', '1.2-2')).toEqual('9,999,999.99'); + }); }); }); diff --git a/packages/common/test/i18n/locale_data_api_spec.ts b/packages/common/test/i18n/locale_data_api_spec.ts index c4cb78d6f002b..74eb1914e765a 100644 --- a/packages/common/test/i18n/locale_data_api_spec.ts +++ b/packages/common/test/i18n/locale_data_api_spec.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; - import localeEn from '@angular/common/locales/en'; -import localeFr from '@angular/common/locales/fr'; -import localeZh from '@angular/common/locales/zh'; import localeEnAU from '@angular/common/locales/en-AU'; +import localeFr from '@angular/common/locales/fr'; import localeHe from '@angular/common/locales/he'; -import {getCurrencySymbol, getLocaleDateFormat, FormatWidth, getNumberOfCurrencyDigits, getLocaleDirection} from '../../src/i18n/locale_data_api'; +import localeZh from '@angular/common/locales/zh'; +import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; + +import {FormatWidth, getCurrencySymbol, getLocaleDateFormat, getLocaleDirection, getNumberOfCurrencyDigits} from '../../src/i18n/locale_data_api'; { describe('locale data api', () => { @@ -25,7 +25,9 @@ import {getCurrencySymbol, getLocaleDateFormat, FormatWidth, getNumberOfCurrency ɵregisterLocaleData(localeHe); }); - afterAll(() => { ɵunregisterLocaleData(); }); + afterAll(() => { + ɵunregisterLocaleData(); + }); describe('getting currency symbol', () => { it('should return the correct symbol', () => { @@ -55,16 +57,19 @@ import {getCurrencySymbol, getLocaleDateFormat, FormatWidth, getNumberOfCurrency }); describe('getLastDefinedValue', () => { - it('should find the last defined date format when format not defined', - () => { expect(getLocaleDateFormat('zh', FormatWidth.Long)).toEqual('y年M月d日'); }); + it('should find the last defined date format when format not defined', () => { + expect(getLocaleDateFormat('zh', FormatWidth.Long)).toEqual('y年M月d日'); + }); }); describe('getDirectionality', () => { - it('should have correct direction for rtl languages', - () => { expect(getLocaleDirection('he')).toEqual('rtl'); }); + it('should have correct direction for rtl languages', () => { + expect(getLocaleDirection('he')).toEqual('rtl'); + }); - it('should have correct direction for ltr languages', - () => { expect(getLocaleDirection('en')).toEqual('ltr'); }); + it('should have correct direction for ltr languages', () => { + expect(getLocaleDirection('en')).toEqual('ltr'); + }); }); }); } diff --git a/packages/common/test/i18n/localization_spec.ts b/packages/common/test/i18n/localization_spec.ts index dd078c6d89c4d..01c22b4e6c7d1 100644 --- a/packages/common/test/i18n/localization_spec.ts +++ b/packages/common/test/i18n/localization_spec.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ +import localeFr from '@angular/common/locales/fr'; import localeRo from '@angular/common/locales/ro'; import localeSr from '@angular/common/locales/sr'; import localeZgh from '@angular/common/locales/zgh'; -import localeFr from '@angular/common/locales/fr'; -import {LOCALE_ID, ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core'; -import {TestBed, inject} from '@angular/core/testing'; -import {NgLocaleLocalization, NgLocalization, getPluralCategory} from '@angular/common/src/i18n/localization'; +import {getPluralCategory, NgLocaleLocalization, NgLocalization} from '@angular/common/src/i18n/localization'; +import {LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; +import {inject, TestBed} from '@angular/core/testing'; { describe('l10n', () => { diff --git a/packages/common/test/location/location_spec.ts b/packages/common/test/location/location_spec.ts index 92b876f5f656f..9bee33fcba47f 100644 --- a/packages/common/test/location/location_spec.ts +++ b/packages/common/test/location/location_spec.ts @@ -8,7 +8,7 @@ import {CommonModule, Location, LocationStrategy, PathLocationStrategy, PlatformLocation} from '@angular/common'; import {MockPlatformLocation} from '@angular/common/testing'; -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from '@angular/core/testing'; const baseUrl = '/base'; @@ -46,14 +46,18 @@ describe('Location Class', () => { imports: [CommonModule], providers: [ {provide: LocationStrategy, useClass: PathLocationStrategy}, - {provide: PlatformLocation, useFactory: () => { return new MockPlatformLocation(); }}, + { + provide: PlatformLocation, + useFactory: () => { + return new MockPlatformLocation(); + } + }, {provide: Location, useClass: Location, deps: [LocationStrategy, PlatformLocation]}, ] }); }); it('should get the state object', inject([Location], (location: Location) => { - expect(location.getState()).toBe(null); location.go('/test', '', {foo: 'bar'}); @@ -62,7 +66,6 @@ describe('Location Class', () => { })); it('should work after using back button', inject([Location], (location: Location) => { - expect(location.getState()).toBe(null); location.go('/test1', '', {url: 'test1'}); @@ -74,7 +77,6 @@ describe('Location Class', () => { expect(location.getState()).toEqual({url: 'test1'}); })); - }); describe('location.onUrlChange()', () => { @@ -83,7 +85,12 @@ describe('Location Class', () => { imports: [CommonModule], providers: [ {provide: LocationStrategy, useClass: PathLocationStrategy}, - {provide: PlatformLocation, useFactory: () => { return new MockPlatformLocation(); }}, + { + provide: PlatformLocation, + useFactory: () => { + return new MockPlatformLocation(); + } + }, {provide: Location, useClass: Location, deps: [LocationStrategy, PlatformLocation]}, ] }); @@ -95,8 +102,9 @@ describe('Location Class', () => { it('should add registered functions to urlChangeListeners', inject([Location], (location: Location) => { - - function changeListener(url: string, state: unknown) { return undefined; } + function changeListener(url: string, state: unknown) { + return undefined; + } expect((location as any)._urlChangeListeners.length).toBe(0); @@ -104,8 +112,6 @@ describe('Location Class', () => { expect((location as any)._urlChangeListeners.length).toBe(1); expect((location as any)._urlChangeListeners[0]).toEqual(changeListener); - })); - }); }); \ No newline at end of file diff --git a/packages/common/test/pipes/async_pipe_spec.ts b/packages/common/test/pipes/async_pipe_spec.ts index 29f945ef9b86a..0d1635938c78c 100644 --- a/packages/common/test/pipes/async_pipe_spec.ts +++ b/packages/common/test/pipes/async_pipe_spec.ts @@ -15,7 +15,6 @@ import {SpyChangeDetectorRef} from '../spies'; { describe('AsyncPipe', () => { - describe('Observable', () => { let emitter: EventEmitter<any>; let pipe: AsyncPipe; @@ -29,8 +28,9 @@ import {SpyChangeDetectorRef} from '../spies'; }); describe('transform', () => { - it('should return null when subscribing to an observable', - () => { expect(pipe.transform(emitter)).toBe(null); }); + it('should return null when subscribing to an observable', () => { + expect(pipe.transform(emitter)).toBe(null); + }); it('should return the latest available value wrapped', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { @@ -96,8 +96,9 @@ import {SpyChangeDetectorRef} from '../spies'; }); describe('ngOnDestroy', () => { - it('should do nothing when no subscription', - () => { expect(() => pipe.ngOnDestroy()).not.toThrow(); }); + it('should do nothing when no subscription', () => { + expect(() => pipe.ngOnDestroy()).not.toThrow(); + }); it('should dispose of the existing subscription', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { @@ -133,8 +134,9 @@ import {SpyChangeDetectorRef} from '../spies'; }); describe('transform', () => { - it('should return null when subscribing to a promise', - () => { expect(pipe.transform(promise)).toBe(null); }); + it('should return null when subscribing to a promise', () => { + expect(pipe.transform(promise)).toBe(null); + }); it('should return the latest available value', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { @@ -189,8 +191,9 @@ import {SpyChangeDetectorRef} from '../spies'; })); describe('ngOnDestroy', () => { - it('should do nothing when no source', - () => { expect(() => pipe.ngOnDestroy()).not.toThrow(); }); + it('should do nothing when no source', () => { + expect(() => pipe.ngOnDestroy()).not.toThrow(); + }); it('should dispose of the existing source', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { diff --git a/packages/common/test/pipes/case_conversion_pipes_spec.ts b/packages/common/test/pipes/case_conversion_pipes_spec.ts index 22458d785508e..5584f5e468d2b 100644 --- a/packages/common/test/pipes/case_conversion_pipes_spec.ts +++ b/packages/common/test/pipes/case_conversion_pipes_spec.ts @@ -12,41 +12,55 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common'; describe('LowerCasePipe', () => { let pipe: LowerCasePipe; - beforeEach(() => { pipe = new LowerCasePipe(); }); + beforeEach(() => { + pipe = new LowerCasePipe(); + }); - it('should return lowercase', () => { expect(pipe.transform('FOO')).toEqual('foo'); }); + it('should return lowercase', () => { + expect(pipe.transform('FOO')).toEqual('foo'); + }); it('should lowercase when there is a new value', () => { expect(pipe.transform('FOO')).toEqual('foo'); expect(pipe.transform('BAr')).toEqual('bar'); }); - it('should not support other objects', - () => { expect(() => pipe.transform(<any>{})).toThrowError(); }); + it('should not support other objects', () => { + expect(() => pipe.transform(<any>{})).toThrowError(); + }); }); describe('TitleCasePipe', () => { let pipe: TitleCasePipe; - beforeEach(() => { pipe = new TitleCasePipe(); }); + beforeEach(() => { + pipe = new TitleCasePipe(); + }); - it('should return titlecase', () => { expect(pipe.transform('foo')).toEqual('Foo'); }); + it('should return titlecase', () => { + expect(pipe.transform('foo')).toEqual('Foo'); + }); - it('should return titlecase for subsequent words', - () => { expect(pipe.transform('one TWO Three fouR')).toEqual('One Two Three Four'); }); + it('should return titlecase for subsequent words', () => { + expect(pipe.transform('one TWO Three fouR')).toEqual('One Two Three Four'); + }); - it('should support empty strings', () => { expect(pipe.transform('')).toEqual(''); }); + it('should support empty strings', () => { + expect(pipe.transform('')).toEqual(''); + }); - it('should persist whitespace', - () => { expect(pipe.transform('one two')).toEqual('One Two'); }); + it('should persist whitespace', () => { + expect(pipe.transform('one two')).toEqual('One Two'); + }); it('should titlecase when there is a new value', () => { expect(pipe.transform('bar')).toEqual('Bar'); expect(pipe.transform('foo')).toEqual('Foo'); }); - it('should not capitalize letter after the quotes', - () => { expect(pipe.transform('it\'s complicated')).toEqual('It\'s Complicated'); }); + it('should not capitalize letter after the quotes', () => { + expect(pipe.transform('it\'s complicated')).toEqual('It\'s Complicated'); + }); it('should not treat non-space character as a separator', () => { expect(pipe.transform('one,two,three')).toEqual('One,two,three'); @@ -66,23 +80,29 @@ import {LowerCasePipe, TitleCasePipe, UpperCasePipe} from '@angular/common'; expect(pipe.transform('éric')).toEqual('Éric'); }); - it('should not support other objects', - () => { expect(() => pipe.transform(<any>{})).toThrowError(); }); + it('should not support other objects', () => { + expect(() => pipe.transform(<any>{})).toThrowError(); + }); }); describe('UpperCasePipe', () => { let pipe: UpperCasePipe; - beforeEach(() => { pipe = new UpperCasePipe(); }); + beforeEach(() => { + pipe = new UpperCasePipe(); + }); - it('should return uppercase', () => { expect(pipe.transform('foo')).toEqual('FOO'); }); + it('should return uppercase', () => { + expect(pipe.transform('foo')).toEqual('FOO'); + }); it('should uppercase when there is a new value', () => { expect(pipe.transform('foo')).toEqual('FOO'); expect(pipe.transform('bar')).toEqual('BAR'); }); - it('should not support other objects', - () => { expect(() => pipe.transform(<any>{})).toThrowError(); }); + it('should not support other objects', () => { + expect(() => pipe.transform(<any>{})).toThrowError(); + }); }); } diff --git a/packages/common/test/pipes/date_pipe_spec.ts b/packages/common/test/pipes/date_pipe_spec.ts index d651ceb7d431f..c1542d60e4dbb 100644 --- a/packages/common/test/pipes/date_pipe_spec.ts +++ b/packages/common/test/pipes/date_pipe_spec.ts @@ -10,8 +10,8 @@ import {DatePipe} from '@angular/common'; import localeEn from '@angular/common/locales/en'; import localeEnExtra from '@angular/common/locales/extra/en'; import {PipeResolver} from '@angular/compiler/src/pipe_resolver'; +import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_reflector'; -import {ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core'; { let date: Date; @@ -28,33 +28,44 @@ import {ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core'; }); it('should be marked as pure', () => { - expect(new PipeResolver(new JitReflector()).resolve(DatePipe) !.pure).toEqual(true); + expect(new PipeResolver(new JitReflector()).resolve(DatePipe)!.pure).toEqual(true); }); describe('supports', () => { - it('should support date', () => { expect(() => pipe.transform(date)).not.toThrow(); }); + it('should support date', () => { + expect(() => pipe.transform(date)).not.toThrow(); + }); - it('should support int', () => { expect(() => pipe.transform(123456789)).not.toThrow(); }); + it('should support int', () => { + expect(() => pipe.transform(123456789)).not.toThrow(); + }); - it('should support numeric strings', - () => { expect(() => pipe.transform('123456789')).not.toThrow(); }); + it('should support numeric strings', () => { + expect(() => pipe.transform('123456789')).not.toThrow(); + }); - it('should support decimal strings', - () => { expect(() => pipe.transform('123456789.11')).not.toThrow(); }); + it('should support decimal strings', () => { + expect(() => pipe.transform('123456789.11')).not.toThrow(); + }); it('should support ISO string', () => expect(() => pipe.transform('2015-06-15T21:43:11Z')).not.toThrow()); - it('should return null for empty string', - () => { expect(pipe.transform('')).toEqual(null); }); + it('should return null for empty string', () => { + expect(pipe.transform('')).toEqual(null); + }); - it('should return null for NaN', () => { expect(pipe.transform(Number.NaN)).toEqual(null); }); + it('should return null for NaN', () => { + expect(pipe.transform(Number.NaN)).toEqual(null); + }); - it('should support ISO string without time', - () => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); }); + it('should support ISO string without time', () => { + expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); + }); - it('should not support other objects', - () => { expect(() => pipe.transform({})).toThrowError(/InvalidPipeArgument/); }); + it('should not support other objects', () => { + expect(() => pipe.transform({})).toThrowError(/InvalidPipeArgument/); + }); }); describe('transform', () => { diff --git a/packages/common/test/pipes/i18n_plural_pipe_spec.ts b/packages/common/test/pipes/i18n_plural_pipe_spec.ts index 2941584b3cf8b..104716b195d21 100644 --- a/packages/common/test/pipes/i18n_plural_pipe_spec.ts +++ b/packages/common/test/pipes/i18n_plural_pipe_spec.ts @@ -29,7 +29,7 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle }); it('should be marked as pure', () => { - expect(new PipeResolver(new JitReflector()).resolve(I18nPluralPipe) !.pure).toEqual(true); + expect(new PipeResolver(new JitReflector()).resolve(I18nPluralPipe)!.pure).toEqual(true); }); describe('transform', () => { @@ -54,17 +54,19 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle }); it('should use "" if value is undefined', () => { - const val = pipe.transform(void(0) as any, mapping); + const val = pipe.transform(void (0) as any, mapping); expect(val).toEqual(''); }); - it('should not support bad arguments', - () => { expect(() => pipe.transform(0, <any>'hey')).toThrowError(); }); + it('should not support bad arguments', () => { + expect(() => pipe.transform(0, <any>'hey')).toThrowError(); + }); }); - }); } class TestLocalization extends NgLocalization { - getPluralCategory(value: number): string { return value > 1 && value < 6 ? 'many' : 'other'; } + getPluralCategory(value: number): string { + return value > 1 && value < 6 ? 'many' : 'other'; + } } diff --git a/packages/common/test/pipes/i18n_select_pipe_spec.ts b/packages/common/test/pipes/i18n_select_pipe_spec.ts index 2d68a237d325c..998ab7fd40a19 100644 --- a/packages/common/test/pipes/i18n_select_pipe_spec.ts +++ b/packages/common/test/pipes/i18n_select_pipe_spec.ts @@ -16,7 +16,7 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle const mapping = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'}; it('should be marked as pure', () => { - expect(new PipeResolver(new JitReflector()).resolve(I18nSelectPipe) !.pure).toEqual(true); + expect(new PipeResolver(new JitReflector()).resolve(I18nSelectPipe)!.pure).toEqual(true); }); describe('transform', () => { @@ -30,17 +30,18 @@ import {JitReflector} from '@angular/platform-browser-dynamic/src/compiler_refle expect(val).toEqual('Invite her.'); }); - it('should return the "other" text if value is neither "male" nor "female"', - () => { expect(pipe.transform('Anything else', mapping)).toEqual('Invite them.'); }); + it('should return the "other" text if value is neither "male" nor "female"', () => { + expect(pipe.transform('Anything else', mapping)).toEqual('Invite them.'); + }); it('should return an empty text if value is null or undefined', () => { expect(pipe.transform(null, mapping)).toEqual(''); expect(pipe.transform(void 0, mapping)).toEqual(''); }); - it('should throw on bad arguments', - () => { expect(() => pipe.transform('male', <any>'hey')).toThrowError(); }); + it('should throw on bad arguments', () => { + expect(() => pipe.transform('male', <any>'hey')).toThrowError(); + }); }); - }); } diff --git a/packages/common/test/pipes/json_pipe_spec.ts b/packages/common/test/pipes/json_pipe_spec.ts index a9f5e4637d7bc..b1a9fb5bb58ec 100644 --- a/packages/common/test/pipes/json_pipe_spec.ts +++ b/packages/common/test/pipes/json_pipe_spec.ts @@ -8,7 +8,7 @@ import {CommonModule, JsonPipe} from '@angular/common'; import {Component} from '@angular/core'; -import {TestBed, async} from '@angular/core/testing'; +import {async, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; { @@ -18,7 +18,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; let inceptionObjString: string; let pipe: JsonPipe; - function normalize(obj: string): string { return obj.replace(regNewLine, ''); } + function normalize(obj: string): string { + return obj.replace(regNewLine, ''); + } beforeEach(() => { inceptionObj = {dream: {dream: {dream: 'Limbo'}}}; @@ -35,8 +37,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); describe('transform', () => { - it('should return JSON-formatted string', - () => { expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); }); + it('should return JSON-formatted string', () => { + expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); + }); it('should return JSON-formatted string even when normalized', () => { const dream1 = normalize(pipe.transform(inceptionObj)); @@ -52,7 +55,6 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); describe('integration', () => { - @Component({selector: 'test-comp', template: '{{data | json}}'}) class TestComp { data: any; diff --git a/packages/common/test/pipes/keyvalue_pipe_spec.ts b/packages/common/test/pipes/keyvalue_pipe_spec.ts index 4433f9c98d052..e4af0fc130760 100644 --- a/packages/common/test/pipes/keyvalue_pipe_spec.ts +++ b/packages/common/test/pipes/keyvalue_pipe_spec.ts @@ -64,12 +64,12 @@ describe('KeyValuePipe', () => { expect(transform1 !== transform2).toEqual(true); }); it('should accept a type union of an object with string keys and null', () => { - let value !: {[key: string]: string} | null; + let value!: {[key: string]: string}|null; const pipe = new KeyValuePipe(defaultKeyValueDiffers); expect(pipe.transform(value)).toEqual(null); }); it('should accept a type union of an object with number keys and null', () => { - let value !: {[key: number]: string} | null; + let value!: {[key: number]: string}|null; const pipe = new KeyValuePipe(defaultKeyValueDiffers); expect(pipe.transform(value)).toEqual(null); }); @@ -126,7 +126,7 @@ describe('KeyValuePipe', () => { expect(transform1 !== transform2).toEqual(true); }); it('should accept a type union of a Map and null', () => { - let value !: Map<number, number>| null; + let value!: Map<number, number>|null; const pipe = new KeyValuePipe(defaultKeyValueDiffers); expect(pipe.transform(value)).toEqual(null); }); diff --git a/packages/common/test/pipes/number_pipe_spec.ts b/packages/common/test/pipes/number_pipe_spec.ts index c0a456451d6b9..a57690451018e 100644 --- a/packages/common/test/pipes/number_pipe_spec.ts +++ b/packages/common/test/pipes/number_pipe_spec.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ +import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common'; +import localeAr from '@angular/common/locales/ar'; +import localeDa from '@angular/common/locales/da'; +import localeDeAt from '@angular/common/locales/de-AT'; import localeEn from '@angular/common/locales/en'; import localeEsUS from '@angular/common/locales/es-US'; import localeFr from '@angular/common/locales/fr'; -import localeAr from '@angular/common/locales/ar'; -import localeDeAt from '@angular/common/locales/de-AT'; -import localeDa from '@angular/common/locales/da'; -import {ɵunregisterLocaleData, ɵregisterLocaleData} from '@angular/core'; -import {CurrencyPipe, DecimalPipe, PercentPipe} from '@angular/common'; +import {ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core'; import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; { @@ -32,7 +32,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin describe('DecimalPipe', () => { describe('transform', () => { let pipe: DecimalPipe; - beforeEach(() => { pipe = new DecimalPipe('en-US'); }); + beforeEach(() => { + pipe = new DecimalPipe('en-US'); + }); it('should return correct value for numbers', () => { expect(pipe.transform(12345)).toEqual('12,345'); @@ -68,7 +70,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin describe('PercentPipe', () => { let pipe: PercentPipe; - beforeEach(() => { pipe = new PercentPipe('en-US'); }); + beforeEach(() => { + pipe = new PercentPipe('en-US'); + }); describe('transform', () => { it('should return correct value for numbers', () => { @@ -89,7 +93,9 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin describe('CurrencyPipe', () => { let pipe: CurrencyPipe; - beforeEach(() => { pipe = new CurrencyPipe('en-US', 'USD'); }); + beforeEach(() => { + pipe = new CurrencyPipe('en-US', 'USD'); + }); describe('transform', () => { it('should return correct value for numbers', () => { diff --git a/packages/common/test/pipes/slice_pipe_spec.ts b/packages/common/test/pipes/slice_pipe_spec.ts index 63c79f188067a..e86edf75651a8 100644 --- a/packages/common/test/pipes/slice_pipe_spec.ts +++ b/packages/common/test/pipes/slice_pipe_spec.ts @@ -8,7 +8,7 @@ import {CommonModule, SlicePipe} from '@angular/common'; import {Component} from '@angular/core'; -import {TestBed, async} from '@angular/core/testing'; +import {async, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; { @@ -24,24 +24,32 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); describe('supports', () => { - it('should support strings', () => { expect(() => pipe.transform(str, 0)).not.toThrow(); }); - it('should support lists', () => { expect(() => pipe.transform(list, 0)).not.toThrow(); }); - it('should support readonly lists', - () => { expect(() => pipe.transform(list as ReadonlyArray<number>, 0)).not.toThrow(); }); + it('should support strings', () => { + expect(() => pipe.transform(str, 0)).not.toThrow(); + }); + it('should support lists', () => { + expect(() => pipe.transform(list, 0)).not.toThrow(); + }); + it('should support readonly lists', () => { + expect(() => pipe.transform(list as ReadonlyArray<number>, 0)).not.toThrow(); + }); it('should not support other objects', // this would not compile // so we cast as `any` to check that it throws for unsupported objects - () => { expect(() => pipe.transform({} as any, 0)).toThrow(); }); + () => { + expect(() => pipe.transform({} as any, 0)).toThrow(); + }); }); describe('transform', () => { + it('should return null if the value is null', () => { + expect(pipe.transform(null, 1)).toBe(null); + }); - it('should return null if the value is null', - () => { expect(pipe.transform(null, 1)).toBe(null); }); - - it('should return undefined if the value is undefined', - () => { expect(pipe.transform(undefined, 1)).toBe(undefined); }); + it('should return undefined if the value is undefined', () => { + expect(pipe.transform(undefined, 1)).toBe(undefined); + }); it('should return all items after START index when START is positive and END is omitted', () => { @@ -85,11 +93,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; expect(pipe.transform(list, 2)).toEqual([3, 4, 5]); expect(list).toEqual([1, 2, 3, 4, 5]); }); - }); describe('integration', () => { - @Component({selector: 'test-comp', template: '{{(data | slice:1).join(",") }}'}) class TestComp { data: any; diff --git a/packages/common/test/spies.ts b/packages/common/test/spies.ts index e956a4821c474..e889b9431e49c 100644 --- a/packages/common/test/spies.ts +++ b/packages/common/test/spies.ts @@ -18,4 +18,6 @@ export class SpyChangeDetectorRef extends SpyObject { export class SpyNgControl extends SpyObject {} -export class SpyValueAccessor extends SpyObject { writeValue: any; } +export class SpyValueAccessor extends SpyObject { + writeValue: any; +} diff --git a/packages/common/test/viewport_scroller_spec.ts b/packages/common/test/viewport_scroller_spec.ts index 281ef96d37d47..fd0485546a0ea 100644 --- a/packages/common/test/viewport_scroller_spec.ts +++ b/packages/common/test/viewport_scroller_spec.ts @@ -9,12 +9,12 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; import {BrowserViewportScroller, ViewportScroller} from '../src/viewport_scroller'; @@ -25,7 +25,7 @@ import {BrowserViewportScroller, ViewportScroller} from '../src/viewport_scrolle let documentSpy: any; beforeEach(() => { documentSpy = jasmine.createSpyObj('document', ['querySelector']); - scroller = new BrowserViewportScroller(documentSpy, {scrollTo: 1}, null !); + scroller = new BrowserViewportScroller(documentSpy, {scrollTo: 1}, null!); }); it('escapes invalid characters selectors', () => { const invalidSelectorChars = `"' :.[],=`; diff --git a/packages/common/testing/src/location_mock.ts b/packages/common/testing/src/location_mock.ts index a5efc1ffb318b..b02d5e2b2fd05 100644 --- a/packages/common/testing/src/location_mock.ts +++ b/packages/common/testing/src/location_mock.ts @@ -25,19 +25,27 @@ export class SpyLocation implements Location { /** @internal */ _baseHref: string = ''; /** @internal */ - _platformStrategy: LocationStrategy = null !; + _platformStrategy: LocationStrategy = null!; /** @internal */ - _platformLocation: PlatformLocation = null !; + _platformLocation: PlatformLocation = null!; /** @internal */ _urlChangeListeners: ((url: string, state: unknown) => void)[] = []; - setInitialPath(url: string) { this._history[this._historyIndex].path = url; } + setInitialPath(url: string) { + this._history[this._historyIndex].path = url; + } - setBaseHref(url: string) { this._baseHref = url; } + setBaseHref(url: string) { + this._baseHref = url; + } - path(): string { return this._history[this._historyIndex].path; } + path(): string { + return this._history[this._historyIndex].path; + } - getState(): unknown { return this._history[this._historyIndex].state; } + getState(): unknown { + return this._history[this._historyIndex].state; + } isCurrentPathEqualTo(path: string, query: string = ''): boolean { const givenPath = path.endsWith('/') ? path.substring(0, path.length - 1) : path; @@ -115,7 +123,9 @@ export class SpyLocation implements Location { } onUrlChange(fn: (url: string, state: unknown) => void) { this._urlChangeListeners.push(fn); - this.subscribe(v => { this._notifyUrlChangeListeners(v.url, v.state); }); + this.subscribe(v => { + this._notifyUrlChangeListeners(v.url, v.state); + }); } /** @internal */ @@ -129,7 +139,9 @@ export class SpyLocation implements Location { return this._subject.subscribe({next: onNext, error: onThrow, complete: onReturn}); } - normalize(url: string): string { return null !; } + normalize(url: string): string { + return null!; + } } class LocationState { diff --git a/packages/common/testing/src/mock_location_strategy.ts b/packages/common/testing/src/mock_location_strategy.ts index 2c38f8d39f591..8cd329aa64f25 100644 --- a/packages/common/testing/src/mock_location_strategy.ts +++ b/packages/common/testing/src/mock_location_strategy.ts @@ -26,14 +26,18 @@ export class MockLocationStrategy extends LocationStrategy { /** @internal */ _subject: EventEmitter<any> = new EventEmitter(); private stateChanges: any[] = []; - constructor() { super(); } + constructor() { + super(); + } simulatePopState(url: string): void { this.internalPath = url; this._subject.emit(new _MockPopStateEvent(this.path())); } - path(includeHash: boolean = false): string { return this.internalPath; } + path(includeHash: boolean = false): string { + return this.internalPath; + } prepareExternalUrl(internal: string): string { if (internal.startsWith('/') && this.internalBaseHref.endsWith('/')) { @@ -68,9 +72,13 @@ export class MockLocationStrategy extends LocationStrategy { this.urlChanges.push('replace: ' + externalUrl); } - onPopState(fn: (value: any) => void): void { this._subject.subscribe({next: fn}); } + onPopState(fn: (value: any) => void): void { + this._subject.subscribe({next: fn}); + } - getBaseHref(): string { return this.internalBaseHref; } + getBaseHref(): string { + return this.internalBaseHref; + } back(): void { if (this.urlChanges.length > 0) { @@ -81,9 +89,13 @@ export class MockLocationStrategy extends LocationStrategy { } } - forward(): void { throw 'not implemented'; } + forward(): void { + throw 'not implemented'; + } - getState(): unknown { return this.stateChanges[(this.stateChanges.length || 1) - 1]; } + getState(): unknown { + return this.stateChanges[(this.stateChanges.length || 1) - 1]; + } } class _MockPopStateEvent { diff --git a/packages/common/testing/src/mock_platform_location.ts b/packages/common/testing/src/mock_platform_location.ts index 4f7c15602252f..4cbb5a677ceb9 100644 --- a/packages/common/testing/src/mock_platform_location.ts +++ b/packages/common/testing/src/mock_platform_location.ts @@ -126,23 +126,41 @@ export class MockPlatformLocation implements PlatformLocation { } } - get hostname() { return this.urlChanges[0].hostname; } - get protocol() { return this.urlChanges[0].protocol; } - get port() { return this.urlChanges[0].port; } - get pathname() { return this.urlChanges[0].pathname; } - get search() { return this.urlChanges[0].search; } - get hash() { return this.urlChanges[0].hash; } - get state() { return this.urlChanges[0].state; } + get hostname() { + return this.urlChanges[0].hostname; + } + get protocol() { + return this.urlChanges[0].protocol; + } + get port() { + return this.urlChanges[0].port; + } + get pathname() { + return this.urlChanges[0].pathname; + } + get search() { + return this.urlChanges[0].search; + } + get hash() { + return this.urlChanges[0].hash; + } + get state() { + return this.urlChanges[0].state; + } - getBaseHrefFromDOM(): string { return this.baseHref; } + getBaseHrefFromDOM(): string { + return this.baseHref; + } onPopState(fn: LocationChangeListener): void { // No-op: a state stack is not implemented, so // no events will ever come. } - onHashChange(fn: LocationChangeListener): void { this.hashUpdate.subscribe(fn); } + onHashChange(fn: LocationChangeListener): void { + this.hashUpdate.subscribe(fn); + } get href(): string { let url = `${this.protocol}//${this.hostname}${this.port ? ':' + this.port : ''}`; @@ -150,7 +168,9 @@ export class MockPlatformLocation implements PlatformLocation { return url; } - get url(): string { return `${this.pathname}${this.search}${this.hash}`; } + get url(): string { + return `${this.pathname}${this.search}${this.hash}`; + } private parseChanges(state: unknown, url: string, baseHref: string = '') { // When the `history.state` value is stored, it is always copied. @@ -169,7 +189,9 @@ export class MockPlatformLocation implements PlatformLocation { this.urlChanges.unshift({...this.urlChanges[0], pathname, search, hash, state: parsedState}); } - forward(): void { throw new Error('Not implemented'); } + forward(): void { + throw new Error('Not implemented'); + } back(): void { const oldUrl = this.url; @@ -178,13 +200,15 @@ export class MockPlatformLocation implements PlatformLocation { const newHash = this.hash; if (oldHash !== newHash) { - scheduleMicroTask(() => this.hashUpdate.next({ - type: 'hashchange', state: null, oldUrl, newUrl: this.url - } as LocationChangeEvent)); + scheduleMicroTask( + () => this.hashUpdate.next( + {type: 'hashchange', state: null, oldUrl, newUrl: this.url} as LocationChangeEvent)); } } - getState(): unknown { return this.state; } + getState(): unknown { + return this.state; + } } export function scheduleMicroTask(cb: () => any) { diff --git a/packages/common/upgrade/src/location_upgrade_module.ts b/packages/common/upgrade/src/location_upgrade_module.ts index 720dd986a0125..d11f9dfd23eb2 100644 --- a/packages/common/upgrade/src/location_upgrade_module.ts +++ b/packages/common/upgrade/src/location_upgrade_module.ts @@ -55,7 +55,7 @@ const APP_BASE_HREF_RESOLVED = new InjectionToken<string>('APP_BASE_HREF_RESOLVE /** * `NgModule` used for providing and configuring Angular's Unified Location Service for upgrading. - * + * * @see [Using the Unified Angular Location Service](guide/upgrade#using-the-unified-angular-location-service) * * @publicApi diff --git a/packages/common/upgrade/src/params.ts b/packages/common/upgrade/src/params.ts index ac9fe5f7d64b6..587816ecb0e92 100644 --- a/packages/common/upgrade/src/params.ts +++ b/packages/common/upgrade/src/params.ts @@ -152,7 +152,9 @@ export class AngularJSUrlCodec implements UrlCodec { } // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L72 - decodeSearch(search: string) { return parseKeyValue(search); } + decodeSearch(search: string) { + return parseKeyValue(search); + } // https://github.com/angular/angular.js/blob/864c7f0/src/ng/location.js#L73 decodeHash(hash: string) { @@ -193,7 +195,9 @@ export class AngularJSUrlCodec implements UrlCodec { } } - areEqual(valA: string, valB: string) { return this.normalize(valA) === this.normalize(valB); } + areEqual(valA: string, valB: string) { + return this.normalize(valA) === this.normalize(valB); + } // https://github.com/angular/angular.js/blob/864c7f0/src/ng/urlUtils.js#L60 parse(url: string, base?: string) { diff --git a/packages/common/upgrade/src/utils.ts b/packages/common/upgrade/src/utils.ts index 48cba8e2fee97..0ce909ecda499 100644 --- a/packages/common/upgrade/src/utils.ts +++ b/packages/common/upgrade/src/utils.ts @@ -27,7 +27,7 @@ export function deepEqual(a: any, b: any): boolean { } } -export function isAnchor(el: (Node & ParentNode) | Element | null): el is HTMLAnchorElement { +export function isAnchor(el: (Node&ParentNode)|Element|null): el is HTMLAnchorElement { return (<HTMLAnchorElement>el).href !== undefined; } diff --git a/packages/common/upgrade/test/upgrade.spec.ts b/packages/common/upgrade/test/upgrade.spec.ts index cab39addc56b3..47d3af76d32aa 100644 --- a/packages/common/upgrade/test/upgrade.spec.ts +++ b/packages/common/upgrade/test/upgrade.spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule, PathLocationStrategy} from '@angular/common'; -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from '@angular/core/testing'; import {UpgradeModule} from '@angular/upgrade/static'; import {$locationShim} from '../src/location_shim'; @@ -43,15 +43,26 @@ export function injectorFactory() { export class $rootScopeMock { private watchers: any[] = []; private events: {[k: string]: any[]} = {}; - runWatchers() { this.watchers.forEach(fn => fn()); } + runWatchers() { + this.watchers.forEach(fn => fn()); + } - $watch(fn: any) { this.watchers.push(fn); } + $watch(fn: any) { + this.watchers.push(fn); + } $broadcast(evt: string, ...args: any[]) { if (this.events[evt]) { - this.events[evt].forEach(fn => { fn.apply(fn, args); }); + this.events[evt].forEach(fn => { + fn.apply(fn, args); + }); } - return {defaultPrevented: false, preventDefault() { this.defaultPrevented = true; }}; + return { + defaultPrevented: false, + preventDefault() { + this.defaultPrevented = true; + } + }; } $on(evt: string, fn: any) { @@ -61,7 +72,9 @@ export class $rootScopeMock { this.events[evt].push(fn); } - $evalAsync(fn: any) { fn(); } + $evalAsync(fn: any) { + fn(); + } } describe('LocationProvider', () => { @@ -83,7 +96,6 @@ describe('LocationProvider', () => { expect($location).toBeDefined(); expect($location instanceof $locationShim).toBe(true); })); - }); @@ -105,7 +117,9 @@ describe('LocationHtml5Url', function() { upgradeModule.$injector = {get: injectorFactory()}; }); - beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; })); + beforeEach(inject([$locationShim], (loc: $locationShim) => { + $location = loc; + })); it('should set the URL', () => { @@ -158,8 +172,9 @@ describe('LocationHtml5Url', function() { }).toThrow(); }); - it('should support state', - function() { expect($location.state({a: 2}).state()).toEqual({a: 2}); }); + it('should support state', function() { + expect($location.state({a: 2}).state()).toEqual({a: 2}); + }); }); @@ -180,10 +195,14 @@ describe('NewUrl', function() { upgradeModule.$injector = {get: injectorFactory()}; }); - beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; })); + beforeEach(inject([$locationShim], (loc: $locationShim) => { + $location = loc; + })); // Sets the default most of these tests rely on - function setupUrl(url = '/path/b?search=a&b=c&d#hash') { $location.url(url); } + function setupUrl(url = '/path/b?search=a&b=c&d#hash') { + $location.url(url); + } it('should provide common getters', function() { setupUrl(); @@ -409,7 +428,6 @@ describe('NewUrl', function() { }); describe('encoding', function() { - it('should encode special characters', function() { $location.path('/a <>#'); $location.search({'i j': '<>#'}); @@ -455,7 +473,6 @@ describe('NewUrl', function() { $location.search({'a+b': 'c+d'}); expect($location.search()).toEqual({'a+b': 'c+d'}); }); - }); it('should not preserve old properties when parsing new url', function() { @@ -486,7 +503,9 @@ describe('New URL Parsing', () => { upgradeModule.$injector = {get: injectorFactory()}; }); - beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; })); + beforeEach(inject([$locationShim], (loc: $locationShim) => { + $location = loc; + })); it('should prepend path with basePath', function() { $location.$$parse('http://server/base/abc?a'); @@ -496,7 +515,6 @@ describe('New URL Parsing', () => { $location.path('/new/path'); expect($location.absUrl()).toBe('http://server/base/new/path?a'); }); - }); describe('New URL Parsing', () => { @@ -516,7 +534,9 @@ describe('New URL Parsing', () => { upgradeModule.$injector = {get: injectorFactory()}; }); - beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; })); + beforeEach(inject([$locationShim], (loc: $locationShim) => { + $location = loc; + })); it('should parse new url', function() { $location.$$parse('http://host.com/base'); @@ -549,8 +569,9 @@ describe('New URL Parsing', () => { }); it('should throw error when invalid server url given', function() { - - expect(function() { $location.$$parse('http://other.server.org/path#/path'); }) + expect(function() { + $location.$$parse('http://other.server.org/path#/path'); + }) .toThrowError( 'Invalid url "http://other.server.org/path#/path", missing path prefix "http://host.com/".'); }); @@ -620,12 +641,10 @@ describe('New URL Parsing', () => { // After watchers have been run, location should be updated and `state` should change expect($location.state()).toBe(null); }); - }); }); describe('$location.onChange()', () => { - let $location: $locationShim; let upgradeModule: UpgradeModule; let mock$rootScope: $rootScopeMock; @@ -644,13 +663,18 @@ describe('$location.onChange()', () => { mock$rootScope = upgradeModule.$injector.get('$rootScope'); }); - beforeEach(inject([$locationShim], (loc: $locationShim) => { $location = loc; })); + beforeEach(inject([$locationShim], (loc: $locationShim) => { + $location = loc; + })); - it('should have onChange method', () => { expect(typeof $location.onChange).toBe('function'); }); + it('should have onChange method', () => { + expect(typeof $location.onChange).toBe('function'); + }); it('should add registered functions to changeListeners', () => { - - function changeListener(url: string, state: unknown) { return undefined; } + function changeListener(url: string, state: unknown) { + return undefined; + } function errorHandler(e: Error) {} expect(($location as any).$$changeListeners.length).toBe(0); @@ -663,7 +687,6 @@ describe('$location.onChange()', () => { }); it('should call changeListeners when URL is updated', () => { - const onChangeVals = {url: 'url', state: 'state' as unknown, oldUrl: 'oldUrl', oldState: 'oldState' as unknown}; @@ -688,7 +711,6 @@ describe('$location.onChange()', () => { }); it('should call changeListeners after $locationChangeSuccess', () => { - let changeListenerCalled = false; let locationChangeSuccessEmitted = false; @@ -715,13 +737,14 @@ describe('$location.onChange()', () => { }); it('should call forward errors to error handler', () => { - - let error !: Error; + let error!: Error; function changeListener(url: string, state: unknown, oldUrl: string, oldState: unknown) { throw new Error('Handle error'); } - function errorHandler(e: Error) { error = e; } + function errorHandler(e: Error) { + error = e; + } $location.onChange(changeListener, errorHandler); @@ -729,7 +752,6 @@ describe('$location.onChange()', () => { mock$rootScope.runWatchers(); expect(error.message).toBe('Handle error'); }); - }); function parseLinkAndReturn(location: $locationShim, toUrl: string, relHref?: string) { diff --git a/packages/common/upgrade/test/upgrade_location_test_module.ts b/packages/common/upgrade/test/upgrade_location_test_module.ts index efcb0ab607bd5..52f093c64d5fc 100644 --- a/packages/common/upgrade/test/upgrade_location_test_module.ts +++ b/packages/common/upgrade/test/upgrade_location_test_module.ts @@ -72,7 +72,7 @@ export class LocationUpgradeTestModule { appBaseHref: config && config.appBaseHref, useHash: config && config.useHash || false }) - .providers ! + .providers! ], }; } diff --git a/packages/compiler-cli/integrationtest/test.js b/packages/compiler-cli/integrationtest/test.js index c30bb482c6179..39e23aa4b6a1d 100644 --- a/packages/compiler-cli/integrationtest/test.js +++ b/packages/compiler-cli/integrationtest/test.js @@ -34,8 +34,8 @@ function nodejs_repository() { const nodejsBinaryExt = os.platform() === 'win32' ? '.bat' : '.sh'; const ngcBin = require.resolve(`./ngc_bin${nodejsBinaryExt}`); const xi18nBin = require.resolve(`./ng_xi18n${nodejsBinaryExt}`); -const nodeBin = require.resolve( - `${nodejs_repository()}/${(os.platform() === 'win32' ? 'bin/nodejs/node.exe' : 'bin/nodejs/bin/node')}`); +const nodeBin = require.resolve(`${nodejs_repository()}/${ + (os.platform() === 'win32' ? 'bin/nodejs/node.exe' : 'bin/nodejs/bin/node')}`); const jasmineBin = require.resolve('npm/node_modules/jasmine/bin/jasmine.js'); // Prepare the test directory before building the integration test output. This ensures that diff --git a/packages/core/schematics/migrations/google3/explicitQueryTimingRule.ts b/packages/core/schematics/migrations/google3/explicitQueryTimingRule.ts index 4a218c8aca536..895cb276dbbeb 100644 --- a/packages/core/schematics/migrations/google3/explicitQueryTimingRule.ts +++ b/packages/core/schematics/migrations/google3/explicitQueryTimingRule.ts @@ -28,7 +28,7 @@ export class Rule extends Rules.TypedRule { const typeChecker = program.getTypeChecker(); const queryVisitor = new NgQueryResolveVisitor(program.getTypeChecker()); const templateVisitor = new NgComponentTemplateVisitor(typeChecker); - const rootSourceFiles = program.getRootFileNames().map(f => program.getSourceFile(f) !); + const rootSourceFiles = program.getRootFileNames().map(f => program.getSourceFile(f)!); const printer = ts.createPrinter(); const failures: RuleFailure[] = []; @@ -44,7 +44,7 @@ export class Rule extends Rules.TypedRule { // check component templates for static query usage. templateVisitor.resolvedTemplates.forEach(template => { if (classMetadata.has(template.container)) { - classMetadata.get(template.container) !.template = template; + classMetadata.get(template.container)!.template = template; } }); diff --git a/packages/core/schematics/migrations/google3/noMissingInjectableRule.ts b/packages/core/schematics/migrations/google3/noMissingInjectableRule.ts index 5fa6511c9c483..ffb810cdac25c 100644 --- a/packages/core/schematics/migrations/google3/noMissingInjectableRule.ts +++ b/packages/core/schematics/migrations/google3/noMissingInjectableRule.ts @@ -50,7 +50,7 @@ export class Rule extends Rules.TypedRule { transformer.recordChanges(); if (updateRecorders.has(sourceFile)) { - failures.push(...updateRecorders.get(sourceFile) !.failures); + failures.push(...updateRecorders.get(sourceFile)!.failures); } return failures; @@ -58,7 +58,7 @@ export class Rule extends Rules.TypedRule { /** Gets the update recorder for the specified source file. */ function getUpdateRecorder(sourceFile: ts.SourceFile): TslintUpdateRecorder { if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !; + return updateRecorders.get(sourceFile)!; } const recorder = new TslintUpdateRecorder(ruleName, sourceFile); updateRecorders.set(sourceFile, recorder); diff --git a/packages/core/schematics/migrations/google3/rendererToRenderer2Rule.ts b/packages/core/schematics/migrations/google3/rendererToRenderer2Rule.ts index 767621218f6c4..c0e1108f752ae 100644 --- a/packages/core/schematics/migrations/google3/rendererToRenderer2Rule.ts +++ b/packages/core/schematics/migrations/google3/rendererToRenderer2Rule.ts @@ -9,7 +9,7 @@ import {Replacement, RuleFailure, Rules} from 'tslint'; import * as ts from 'typescript'; -import {HelperFunction, getHelper} from '../renderer-to-renderer2/helpers'; +import {getHelper, HelperFunction} from '../renderer-to-renderer2/helpers'; import {migrateExpression, replaceImport} from '../renderer-to-renderer2/migration'; import {findCoreImport, findRendererReferences} from '../renderer-to-renderer2/util'; @@ -75,7 +75,7 @@ export class Rule extends Rules.TypedRule { private _getTypedNodeFailure( node: ts.ParameterDeclaration|ts.PropertyDeclaration|ts.AsExpression, sourceFile: ts.SourceFile): RuleFailure { - const type = node.type !; + const type = node.type!; return new RuleFailure( sourceFile, type.getStart(), type.getEnd(), diff --git a/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts b/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts index 9a1150a9aad44..2b2a32836498a 100644 --- a/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts +++ b/packages/core/schematics/migrations/google3/undecoratedClassesWithDecoratedFieldsRule.ts @@ -32,14 +32,14 @@ export class Rule extends Rules.TypedRule { transform.recordChanges(); if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !.failures; + return updateRecorders.get(sourceFile)!.failures; } return []; /** Gets the update recorder for the specified source file. */ function getUpdateRecorder(sourceFile: ts.SourceFile): TslintUpdateRecorder { if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !; + return updateRecorders.get(sourceFile)!; } const recorder = new TslintUpdateRecorder(ruleName, sourceFile); updateRecorders.set(sourceFile, recorder); diff --git a/packages/core/schematics/migrations/missing-injectable/definition_collector.ts b/packages/core/schematics/migrations/missing-injectable/definition_collector.ts index b2d5cee32edde..abf5f5842b039 100644 --- a/packages/core/schematics/migrations/missing-injectable/definition_collector.ts +++ b/packages/core/schematics/migrations/missing-injectable/definition_collector.ts @@ -8,7 +8,7 @@ import * as ts from 'typescript'; -import {NgDecorator, getAngularDecorators} from '../../utils/ng_decorators'; +import {getAngularDecorators, NgDecorator} from '../../utils/ng_decorators'; import {getPropertyNameText} from '../../utils/typescript/property_name'; export interface ResolvedNgModule { diff --git a/packages/core/schematics/migrations/missing-injectable/google3/tslint_update_recorder.ts b/packages/core/schematics/migrations/missing-injectable/google3/tslint_update_recorder.ts index 0f3da184da8b9..195469b2688fa 100644 --- a/packages/core/schematics/migrations/missing-injectable/google3/tslint_update_recorder.ts +++ b/packages/core/schematics/migrations/missing-injectable/google3/tslint_update_recorder.ts @@ -21,7 +21,8 @@ export class TslintUpdateRecorder implements UpdateRecorder { // are handled in reverse and in case a decorator and import are inserted at // the start of the file, the class decorator should come after the import. this.failures.unshift(new RuleFailure( - this.sourceFile, node.getStart(), 0, `Class needs to be decorated with ` + + this.sourceFile, node.getStart(), 0, + `Class needs to be decorated with ` + `"${decoratorText}" because it has been provided by "${className}".`, this.ruleName, Replacement.appendText(node.getStart(), `${decoratorText}\n`))); } diff --git a/packages/core/schematics/migrations/missing-injectable/transform.ts b/packages/core/schematics/migrations/missing-injectable/transform.ts index c70e75b12dc5d..aad21c9d12ad3 100644 --- a/packages/core/schematics/migrations/missing-injectable/transform.ts +++ b/packages/core/schematics/migrations/missing-injectable/transform.ts @@ -46,7 +46,9 @@ export class MissingInjectableTransform { new TypeScriptReflectionHost(typeChecker), typeChecker, /* dependencyTracker */ null); } - recordChanges() { this.importManager.recordChanges(); } + recordChanges() { + this.importManager.recordChanges(); + } /** * Migrates all specified NgModule's by walking through referenced providers @@ -76,10 +78,9 @@ export class MissingInjectableTransform { this._migrateLiteralProviders(literals); if (!Array.isArray(resolvedValue)) { - return [{ - node: module.providersExpr, - message: 'Providers of module are not statically analyzable.' - }]; + return [ + {node: module.providersExpr, message: 'Providers of module are not statically analyzable.'} + ]; } return this._visitProviderResolvedValue(resolvedValue, module); @@ -194,8 +195,9 @@ export class MissingInjectableTransform { const sourceFile = node.getSourceFile(); const newObjectLiteral = ts.updateObjectLiteral( - node, node.properties.concat( - ts.createPropertyAssignment('useValue', ts.createIdentifier('undefined')))); + node, + node.properties.concat( + ts.createPropertyAssignment('useValue', ts.createIdentifier('undefined')))); this.getUpdateRecorder(sourceFile) .updateObjectLiteral( @@ -217,11 +219,12 @@ export class MissingInjectableTransform { // decorate the class. This is because the class is instantiated through the // specified "deps" and the class does not need a factory definition. if (value.has('provide') && value.has('useClass') && value.get('deps') == null) { - return this._visitProviderResolvedValue(value.get('useClass') !, module); + return this._visitProviderResolvedValue(value.get('useClass')!, module); } } else if (Array.isArray(value)) { - return value.reduce((res, v) => res.concat(this._visitProviderResolvedValue(v, module)), [ - ] as AnalysisFailure[]); + return value.reduce( + (res, v) => res.concat(this._visitProviderResolvedValue(v, module)), + [] as AnalysisFailure[]); } else if (value instanceof DynamicValue) { return [{node: value.node, message: `Provider is not statically analyzable.`}]; } diff --git a/packages/core/schematics/migrations/module-with-providers/collector.ts b/packages/core/schematics/migrations/module-with-providers/collector.ts index ee30d5e192ced..ebad0c3587a6c 100644 --- a/packages/core/schematics/migrations/module-with-providers/collector.ts +++ b/packages/core/schematics/migrations/module-with-providers/collector.ts @@ -8,7 +8,8 @@ import * as ts from 'typescript'; -import {NgDecorator, getAngularDecorators} from '../../utils/ng_decorators'; +import {getAngularDecorators, NgDecorator} from '../../utils/ng_decorators'; + import {isModuleWithProvidersNotGeneric} from './util'; export interface ResolvedNgModule { diff --git a/packages/core/schematics/migrations/module-with-providers/transform.ts b/packages/core/schematics/migrations/module-with-providers/transform.ts index e11d17e82088a..c4ac37e8be43a 100644 --- a/packages/core/schematics/migrations/module-with-providers/transform.ts +++ b/packages/core/schematics/migrations/module-with-providers/transform.ts @@ -35,7 +35,7 @@ export class ModuleWithProvidersTransform { /** Migrates a given NgModule by walking through the referenced providers and static methods. */ migrateModule(module: ResolvedNgModule): AnalysisFailure[] { return module.staticMethodsWithoutType.map(this._migrateStaticNgModuleMethod.bind(this)) - .filter(v => v) as AnalysisFailure[]; + .filter(v => v) as AnalysisFailure[]; } /** Migrates a ModuleWithProviders type definition that has no explicit generic type */ @@ -98,8 +98,10 @@ export class ModuleWithProvidersTransform { return ngModule && (value.size === 1 || (providers && value.size === 2)); } - /** Determine the generic type of a suspected ModuleWithProviders return type and add it - * explicitly */ + /** + * Determine the generic type of a suspected ModuleWithProviders return type and add it + * explicitly + */ private _migrateStaticNgModuleMethod(node: ts.MethodDeclaration): AnalysisFailure|null { const returnStatement = node.body && node.body.statements.find(n => ts.isReturnStatement(n)) as ts.ReturnStatement | undefined; @@ -131,7 +133,7 @@ export class ModuleWithProvidersTransform { */ private _getTypeOfResolvedValue(value: ResolvedValue): string|undefined { if (value instanceof Map && this.isModuleWithProvidersType(value)) { - const mapValue = value.get('ngModule') !; + const mapValue = value.get('ngModule')!; if (mapValue instanceof Reference && ts.isClassDeclaration(mapValue.node) && mapValue.node.name) { return mapValue.node.name.text; diff --git a/packages/core/schematics/migrations/renderer-to-renderer2/helpers.ts b/packages/core/schematics/migrations/renderer-to-renderer2/helpers.ts index b41a5c2cee95b..d7cff149c3cae 100644 --- a/packages/core/schematics/migrations/renderer-to-renderer2/helpers.ts +++ b/packages/core/schematics/migrations/renderer-to-renderer2/helpers.ts @@ -69,7 +69,7 @@ function createAnyTypeHelper(): ts.TypeAliasDeclaration { /** Creates a function parameter that is typed as `any`. */ function getAnyTypedParameter( - parameterName: string | ts.Identifier, isRequired = true): ts.ParameterDeclaration { + parameterName: string|ts.Identifier, isRequired = true): ts.ParameterDeclaration { // Declare the parameter as `any` so we don't have to add extra logic to ensure that the // generated code will pass type checking. Use our custom `any` type so people have an incentive // to clean it up afterwards and to avoid potentially introducing lint warnings in G3. @@ -153,10 +153,11 @@ function getCreationHelper( // `if (parent) { renderer.appendChild(parent, node) }`. const guardedAppendChildCall = ts.createIf( - parent, ts.createBlock( - [ts.createExpressionStatement(ts.createCall( - ts.createPropertyAccess(renderer, 'appendChild'), [], [parent, node]))], - true)); + parent, + ts.createBlock( + [ts.createExpressionStatement( + ts.createCall(ts.createPropertyAccess(renderer, 'appendChild'), [], [parent, node]))], + true)); return ts.createFunctionDeclaration( [], [], undefined, functionName, [], @@ -258,10 +259,11 @@ function getDetachViewHelper(): ts.FunctionDeclaration { // const node = rootNodes[i]; const nodeVariableStatement = ts.createVariableStatement( - undefined, ts.createVariableDeclarationList( - [ts.createVariableDeclaration( - node, undefined, ts.createElementAccess(rootNodes, incrementor))], - ts.NodeFlags.Const)); + undefined, + ts.createVariableDeclarationList( + [ts.createVariableDeclaration( + node, undefined, ts.createElementAccess(rootNodes, incrementor))], + ts.NodeFlags.Const)); // renderer.removeChild(renderer.parentNode(node), node); const removeCall = ts.createCall( ts.createPropertyAccess(renderer, 'removeChild'), [], diff --git a/packages/core/schematics/migrations/renderer-to-renderer2/migration.ts b/packages/core/schematics/migrations/renderer-to-renderer2/migration.ts index 88f29fd3e38f4..f82ab0809f49b 100644 --- a/packages/core/schematics/migrations/renderer-to-renderer2/migration.ts +++ b/packages/core/schematics/migrations/renderer-to-renderer2/migration.ts @@ -12,7 +12,7 @@ import {HelperFunction} from './helpers'; import {findImportSpecifier} from './util'; /** A call expression that is based on a property access. */ -type PropertyAccessCallExpression = ts.CallExpression & {expression: ts.PropertyAccessExpression}; +type PropertyAccessCallExpression = ts.CallExpression&{expression: ts.PropertyAccessExpression}; /** Replaces an import inside an import statement with a different one. */ export function replaceImport(node: ts.NamedImports, oldImport: string, newImport: string) { @@ -42,7 +42,7 @@ export function replaceImport(node: ts.NamedImports, oldImport: string, newImpor * Returns null if the expression should be dropped. */ export function migrateExpression(node: ts.CallExpression, typeChecker: ts.TypeChecker): - {node: ts.Node | null, requiredHelpers?: HelperFunction[]} { + {node: ts.Node|null, requiredHelpers?: HelperFunction[]} { if (isPropertyAccessCallExpression(node)) { switch (node.expression.name.getText()) { case 'setElementProperty': @@ -152,7 +152,7 @@ function migrateSetElementClass(node: PropertyAccessCallExpression): ts.Node { // Clone so we don't mutate by accident. Note that we assume that // the user's code is providing all three required arguments. const outputMethodArgs = node.arguments.slice(); - const isAddArgument = outputMethodArgs.pop() !; + const isAddArgument = outputMethodArgs.pop()!; const createRendererCall = (isAdd: boolean) => { const innerExpression = node.expression.expression; const topExpression = @@ -263,6 +263,6 @@ function migrateAnimateCall() { */ function switchToHelperCall( node: PropertyAccessCallExpression, helper: HelperFunction, - args: ts.Expression[] | ts.NodeArray<ts.Expression>): ts.Node { + args: ts.Expression[]|ts.NodeArray<ts.Expression>): ts.Node { return ts.createCall(ts.createIdentifier(helper), [], [node.expression.expression, ...args]); } diff --git a/packages/core/schematics/migrations/renderer-to-renderer2/util.ts b/packages/core/schematics/migrations/renderer-to-renderer2/util.ts index e2dc21df8aa35..993dd82aa3b08 100644 --- a/packages/core/schematics/migrations/renderer-to-renderer2/util.ts +++ b/packages/core/schematics/migrations/renderer-to-renderer2/util.ts @@ -88,8 +88,7 @@ export function findImportSpecifier( /** Checks whether a node is referring to an import spcifier. */ function isReferenceToImport( - typeChecker: ts.TypeChecker, node: ts.Node, - importSpecifier: ts.ImportSpecifier | null): boolean { + typeChecker: ts.TypeChecker, node: ts.Node, importSpecifier: ts.ImportSpecifier|null): boolean { if (importSpecifier) { const nodeSymbol = typeChecker.getTypeAtLocation(node).getSymbol(); const importSymbol = typeChecker.getTypeAtLocation(importSpecifier).getSymbol(); @@ -102,7 +101,7 @@ function isReferenceToImport( /** Finds the identifier referring to the `Renderer` inside a `forwardRef` call expression. */ function findRendererIdentifierInForwardRef( typeChecker: ts.TypeChecker, node: ts.CallExpression, - rendererImport: ts.ImportSpecifier | null): ts.Identifier|null { + rendererImport: ts.ImportSpecifier|null): ts.Identifier|null { const firstArg = node.arguments[0]; if (ts.isArrowFunction(firstArg)) { diff --git a/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts b/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts index fa511a964ae20..457ee8818f433 100644 --- a/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts +++ b/packages/core/schematics/migrations/static-queries/angular/directive_inputs.ts @@ -24,7 +24,7 @@ export function getInputNamesOfClass( } const inputDecorator = - getAngularDecorators(typeChecker, m.decorators !).find(d => d.name === 'Input'); + getAngularDecorators(typeChecker, m.decorators!).find(d => d.name === 'Input'); if (inputDecorator && hasPropertyNameText(m.name)) { resolvedInputSetters.push(m.name.text); diff --git a/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts b/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts index c614961b67332..1414809880b06 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/template_strategy/template_strategy.ts @@ -7,7 +7,7 @@ */ import {AotCompiler, CompileDirectiveMetadata, CompileMetadataResolver, CompileNgModuleMetadata, CompileStylesheetMetadata, ElementAst, EmbeddedTemplateAst, NgAnalyzedModules, QueryMatch, StaticSymbol, TemplateAst} from '@angular/compiler'; -import {Diagnostic, createProgram, readConfiguration} from '@angular/compiler-cli'; +import {createProgram, Diagnostic, readConfiguration} from '@angular/compiler-cli'; import {resolve} from 'path'; import * as ts from 'typescript'; @@ -46,17 +46,17 @@ export class QueryTemplateStrategy implements TimingStrategy { // expose the logic that is necessary to analyze the determined modules. We work around // this by just accessing the necessary private properties using the bracket notation. this.compiler = (aotProgram as any)['compiler']; - this.metadataResolver = this.compiler !['_metadataResolver']; + this.metadataResolver = this.compiler!['_metadataResolver']; // Modify the "DirectiveNormalizer" to not normalize any referenced external stylesheets. // This is necessary because in CLI projects preprocessor files are commonly referenced // and we don't want to parse them in order to extract relative style references. This // breaks the analysis of the project because we instantiate a standalone AOT compiler // program which does not contain the custom logic by the Angular CLI Webpack compiler plugin. - const directiveNormalizer = this.metadataResolver !['_directiveNormalizer']; + const directiveNormalizer = this.metadataResolver!['_directiveNormalizer']; directiveNormalizer['_normalizeStylesheet'] = function(metadata: CompileStylesheetMetadata) { return new CompileStylesheetMetadata( - {styles: metadata.styles, styleUrls: [], moduleUrl: metadata.moduleUrl !}); + {styles: metadata.styles, styleUrls: [], moduleUrl: metadata.moduleUrl!}); }; // Retrieves the analyzed modules of the current program. This data can be @@ -75,7 +75,7 @@ export class QueryTemplateStrategy implements TimingStrategy { /** Analyzes a given directive by determining the timing of all matched view queries. */ private _analyzeDirective(symbol: StaticSymbol, analyzedModules: NgAnalyzedModules) { - const metadata = this.metadataResolver !.getDirectiveMetadata(symbol); + const metadata = this.metadataResolver!.getDirectiveMetadata(symbol); const ngModule = analyzedModules.ngModuleByPipeOrDirective.get(symbol); if (!metadata.isComponent || !ngModule) { @@ -168,7 +168,7 @@ export class QueryTemplateStrategy implements TimingStrategy { const queryKey = this._getViewQueryUniqueKey(filePath, classDecl.name.text, queryName); if (this.analyzedQueries.has(queryKey)) { - return this.analyzedQueries.get(queryKey) !; + return this.analyzedQueries.get(queryKey)!; } return null; } @@ -176,7 +176,7 @@ export class QueryTemplateStrategy implements TimingStrategy { private _parseTemplate(component: CompileDirectiveMetadata, ngModule: CompileNgModuleMetadata): TemplateAst[] { return this - .compiler !['_parseTemplate'](component, ngModule, ngModule.transitiveModule.directives) + .compiler!['_parseTemplate'](component, ngModule, ngModule.transitiveModule.directives) .template; } @@ -201,11 +201,11 @@ function findStaticQueryIds( nodes.forEach((node) => { const staticQueryIds = new Set<number>(); const dynamicQueryIds = new Set<number>(); - let queryMatches: QueryMatch[] = undefined !; + let queryMatches: QueryMatch[] = undefined!; if (node instanceof ElementAst) { findStaticQueryIds(node.children, result); node.children.forEach((child) => { - const childData = result.get(child) !; + const childData = result.get(child)!; childData.staticQueryIds.forEach(queryId => staticQueryIds.add(queryId)); childData.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId)); }); @@ -213,7 +213,7 @@ function findStaticQueryIds( } else if (node instanceof EmbeddedTemplateAst) { findStaticQueryIds(node.children, result); node.children.forEach((child) => { - const childData = result.get(child) !; + const childData = result.get(child)!; childData.staticQueryIds.forEach(queryId => dynamicQueryIds.add(queryId)); childData.dynamicQueryIds.forEach(queryId => dynamicQueryIds.add(queryId)); }); diff --git a/packages/core/schematics/migrations/static-queries/strategies/timing-strategy.ts b/packages/core/schematics/migrations/static-queries/strategies/timing-strategy.ts index b530f60055d1b..0c35f6c6e45ee 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/timing-strategy.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/timing-strategy.ts @@ -16,5 +16,6 @@ export interface TimingStrategy { } export type TimingResult = { - timing: QueryTiming | null; message?: string; + timing: QueryTiming|null; + message?: string; }; diff --git a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts index f42d647005abe..269f901f2c5bb 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/declaration_usage_visitor.ts @@ -167,7 +167,7 @@ export class DeclarationUsageVisitor { d.body && !this.visitedJumpExprNodes.has(d)) .forEach(d => { this.visitedJumpExprNodes.add(d); - this.nodeQueue.push(d.body !); + this.nodeQueue.push(d.body!); }); } @@ -212,7 +212,7 @@ export class DeclarationUsageVisitor { this.ambiguousNodeQueue = []; while (this.nodeQueue.length) { - const node = this.nodeQueue.shift() !; + const node = this.nodeQueue.shift()!; if (ts.isIdentifier(node) && this.isReferringToSymbol(node)) { return ResolvedUsage.SYNCHRONOUS; @@ -306,7 +306,7 @@ export class DeclarationUsageVisitor { } } - jumpExp.arguments !.forEach((node: ts.Node) => { + jumpExp.arguments!.forEach((node: ts.Node) => { node = this._resolveDeclarationOfNode(node); if (ts.isVariableDeclaration(node) && node.initializer) { @@ -325,7 +325,7 @@ export class DeclarationUsageVisitor { */ private _resolveNodeFromContext(node: ts.Node): ts.Node { if (this.context.has(node)) { - return this.context.get(node) !; + return this.context.get(node)!; } return node; } diff --git a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/super_class_context.ts b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/super_class_context.ts index b48589e8a112d..d8bfafeedc428 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/super_class_context.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/super_class_context.ts @@ -35,7 +35,7 @@ export function updateSuperClassAbstractMembersContext( const baseClassImpl = baseClass.members.find( baseClassMethod => !!baseClassMethod.name && getPropertyNameText(baseClassMethod.name) === - getPropertyNameText(superClassMember.name !)); + getPropertyNameText(superClassMember.name!)); if (!baseClassImpl || !isFunctionLikeDeclaration(baseClassImpl) || !baseClassImpl.body) { return; diff --git a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/template_usage_visitor.ts b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/template_usage_visitor.ts index 3cfc79c2d2974..ec7c9b27d30e3 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/template_usage_visitor.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/template_usage_visitor.ts @@ -17,7 +17,9 @@ export class TemplateUsageVisitor extends NullVisitor { private hasQueryTemplateReference = false; private expressionAstVisitor = new ExpressionAstVisitor(this.queryPropertyName); - constructor(public queryPropertyName: string) { super(); } + constructor(public queryPropertyName: string) { + super(); + } /** Checks whether the given query is statically accessed within the specified HTML nodes. */ isQueryUsedStatically(htmlNodes: Node[]): boolean { @@ -59,7 +61,9 @@ export class TemplateUsageVisitor extends NullVisitor { attribute.value.visit(this.expressionAstVisitor, attribute.sourceSpan); } - visitBoundText(text: BoundText) { text.value.visit(this.expressionAstVisitor, text.sourceSpan); } + visitBoundText(text: BoundText) { + text.value.visit(this.expressionAstVisitor, text.sourceSpan); + } visitBoundEvent(node: BoundEvent) { node.handler.visit(this.expressionAstVisitor, node.handlerSpan); @@ -73,7 +77,9 @@ export class TemplateUsageVisitor extends NullVisitor { class ExpressionAstVisitor extends RecursiveAstVisitor { hasQueryPropertyRead = false; - constructor(private queryPropertyName: string) { super(); } + constructor(private queryPropertyName: string) { + super(); + } visitPropertyRead(node: PropertyRead, span: ParseSourceSpan): any { // The receiver of the property read needs to be "implicit" as queries are accessed diff --git a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/usage_strategy.ts b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/usage_strategy.ts index 81de639b5501d..6085105e9f61f 100644 --- a/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/usage_strategy.ts +++ b/packages/core/schematics/migrations/static-queries/strategies/usage_strategy/usage_strategy.ts @@ -70,7 +70,7 @@ export class QueryUsageStrategy implements TimingStrategy { classDecl: ts.ClassDeclaration, query: NgQueryDefinition, knownInputNames: string[], functionCtx: FunctionContext = new Map(), visitInheritedClasses = true): ResolvedUsage { const usageVisitor = - new DeclarationUsageVisitor(query.property !, this.typeChecker, functionCtx); + new DeclarationUsageVisitor(query.property!, this.typeChecker, functionCtx); const classMetadata = this.classMetadata.get(classDecl); let usage: ResolvedUsage = ResolvedUsage.ASYNCHRONOUS; @@ -99,10 +99,10 @@ export class QueryUsageStrategy implements TimingStrategy { // In case there is a component template for the current class, we check if the // template statically accesses the current query. In case that's true, the query // can be marked as static. - if (classMetadata.template && hasPropertyNameText(query.property !.name)) { + if (classMetadata.template && hasPropertyNameText(query.property!.name)) { const template = classMetadata.template; const parsedHtml = parseHtmlGracefully(template.content, template.filePath); - const htmlVisitor = new TemplateUsageVisitor(query.property !.name.text); + const htmlVisitor = new TemplateUsageVisitor(query.property!.name.text); if (parsedHtml && htmlVisitor.isQueryUsedStatically(parsedHtml)) { return ResolvedUsage.SYNCHRONOUS; @@ -179,5 +179,5 @@ function filterQueryClassMemberNodes( } return false; }) - .map(member => member.body !); + .map(member => member.body!); } diff --git a/packages/core/schematics/migrations/static-queries/transform.ts b/packages/core/schematics/migrations/static-queries/transform.ts index f60875799aade..379e64bba89f4 100644 --- a/packages/core/schematics/migrations/static-queries/transform.ts +++ b/packages/core/schematics/migrations/static-queries/transform.ts @@ -10,7 +10,7 @@ import * as ts from 'typescript'; import {getPropertyNameText} from '../../utils/typescript/property_name'; import {NgQueryDefinition, QueryTiming} from './angular/query-definition'; -export type TransformedQueryResult = null | { +export type TransformedQueryResult = null|{ /** Transformed call expression. */ node: ts.CallExpression; /** Failure message which is set when the query could not be transformed successfully. */ @@ -25,7 +25,7 @@ const TODO_CHECK_COMMENT = 'TODO: check static flag'; * determined timing. The updated decorator call expression node will be returned. */ export function getTransformedQueryCallExpr( - query: NgQueryDefinition, timing: QueryTiming | null, + query: NgQueryDefinition, timing: QueryTiming|null, createTodo: boolean): TransformedQueryResult { const queryExpr = query.decorator.node.expression; const queryArguments = queryExpr.arguments; @@ -81,7 +81,7 @@ export function getTransformedQueryCallExpr( failureMessage, node: ts.updateCall( queryExpr, queryExpr.expression, queryExpr.typeArguments, - [queryArguments[0], newOptionsNode !]) + [queryArguments[0], newOptionsNode!]) }; } @@ -94,8 +94,7 @@ export function getTransformedQueryCallExpr( return { failureMessage: null, node: ts.updateCall( - queryExpr, queryExpr.expression, queryExpr.typeArguments, - [queryArguments[0], optionsNode]) + queryExpr, queryExpr.expression, queryExpr.typeArguments, [queryArguments[0], optionsNode]) }; } diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts index 5dc825721b668..311bdb15e869f 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/google3/tslint_update_recorder.ts @@ -22,7 +22,8 @@ export class TslintUpdateRecorder implements UpdateRecorder { // are handled in reverse and in case a decorator and import are inserted at // the start of the file, the class decorator should come after the import. this.failures.unshift(new RuleFailure( - this.sourceFile, node.getStart(), 0, `Class needs to be decorated with ` + + this.sourceFile, node.getStart(), 0, + `Class needs to be decorated with ` + `"${decoratorText}" because it uses Angular features.`, this.ruleName, Replacement.appendText(node.getStart(), `${decoratorText}\n`))); } diff --git a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts index 159f65d6c81ed..012ff0c43a0d9 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-decorated-fields/transform.ts @@ -7,11 +7,11 @@ */ import {PartialEvaluator} from '@angular/compiler-cli/src/ngtsc/partial_evaluator'; -import {TypeScriptReflectionHost, reflectObjectLiteral} from '@angular/compiler-cli/src/ngtsc/reflection'; +import {reflectObjectLiteral, TypeScriptReflectionHost} from '@angular/compiler-cli/src/ngtsc/reflection'; import * as ts from 'typescript'; import {ImportManager} from '../../utils/import_manager'; -import {NgDecorator, getAngularDecorators} from '../../utils/ng_decorators'; +import {getAngularDecorators, NgDecorator} from '../../utils/ng_decorators'; import {findBaseClassDeclarations} from '../../utils/typescript/find_base_classes'; import {unwrapExpression} from '../../utils/typescript/functions'; @@ -56,7 +56,9 @@ export class UndecoratedClassesWithDecoratedFieldsTransform { } /** Records all changes that were made in the import manager. */ - recordChanges() { this.importManager.recordChanges(); } + recordChanges() { + this.importManager.recordChanges(); + } /** Finds undecorated abstract directives in the specified source files. */ private _findUndecoratedAbstractDirectives(sourceFiles: ts.SourceFile[]) { @@ -130,9 +132,9 @@ export class UndecoratedClassesWithDecoratedFieldsTransform { } /** - * Checks whether the given decorator resolves to an abstract directive. An directive is - * considered "abstract" if there is no selector specified. - */ + * Checks whether the given decorator resolves to an abstract directive. An directive is + * considered "abstract" if there is no selector specified. + */ private _isAbstractDirective({node}: NgDecorator): boolean { const metadataArgs = node.expression.arguments; if (metadataArgs.length === 0) { @@ -146,7 +148,7 @@ export class UndecoratedClassesWithDecoratedFieldsTransform { if (!metadata.has('selector')) { return false; } - const selector = this.partialEvaluator.evaluate(metadata.get('selector') !); + const selector = this.partialEvaluator.evaluate(metadata.get('selector')!); return selector == null; } diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/convert_directive_metadata.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/convert_directive_metadata.ts index aef0570b178af..faa6ca4bf7053 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/convert_directive_metadata.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/convert_directive_metadata.ts @@ -78,7 +78,7 @@ export function convertDirectiveMetadataToExpression( /** * Gets a valid property name from the given text. If the text cannot be used * as unquoted identifier, the name will be wrapped in a string literal. -*/ + */ function getPropertyName(name: string): string|ts.StringLiteral { // Matches the most common identifiers that do not need quotes. Constructing a // regular expression that matches the ECMAScript specification in order to determine diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts index fa34c27d63463..1767ccd3451b4 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/decorator_rewriter.ts @@ -122,7 +122,7 @@ export class DecoratorRewriter { |null { try { return ts - .transform(prop, [ctx => this.importRewriterFactory.create(ctx, this.newSourceFile !)]) + .transform(prop, [ctx => this.importRewriterFactory.create(ctx, this.newSourceFile!)]) .transformed[0]; } catch (e) { // If the error is for an unresolved identifier, we want to return "null" because diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts index 3003e9cc276a7..1cbc50aed6f1e 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/decorator_rewrite/import_rewrite_visitor.ts @@ -11,11 +11,11 @@ import {dirname, resolve} from 'path'; import * as ts from 'typescript'; import {ImportManager} from '../../../utils/import_manager'; -import {Import, getImportOfIdentifier} from '../../../utils/typescript/imports'; +import {getImportOfIdentifier, Import} from '../../../utils/typescript/imports'; import {getValueSymbolOfDeclaration} from '../../../utils/typescript/symbol'; import {getPosixPath} from './path_format'; -import {ResolvedExport, getExportSymbolsOfFile} from './source_file_exports'; +import {getExportSymbolsOfFile, ResolvedExport} from './source_file_exports'; /** @@ -116,7 +116,7 @@ export class ImportRewriteTransformerFactory { */ private _getSourceFileExports(sourceFile: ts.SourceFile): ResolvedExport[] { if (this.sourceFileExports.has(sourceFile)) { - return this.sourceFileExports.get(sourceFile) !; + return this.sourceFileExports.get(sourceFile)!; } const sourceFileExports = getExportSymbolsOfFile(sourceFile, this.typeChecker); diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/index.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/index.ts index ceef1fbc4d119..6ad2f725d9399 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/index.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/index.ts @@ -123,7 +123,7 @@ function runUndecoratedClassesMigration( /** Gets the update recorder for the specified source file. */ function getUpdateRecorder(sourceFile: ts.SourceFile): UpdateRecorder { if (updateRecorders.has(sourceFile)) { - return updateRecorders.get(sourceFile) !; + return updateRecorders.get(sourceFile)!; } const treeRecorder = tree.beginUpdate(relative(basePath, sourceFile.fileName)); const recorder: UpdateRecorder = { @@ -146,7 +146,9 @@ function runUndecoratedClassesMigration( treeRecorder.remove(namedBindings.getStart(), namedBindings.getWidth()); treeRecorder.insertRight(namedBindings.getStart(), newNamedBindings); }, - commitUpdate() { tree.commitUpdate(treeRecorder); } + commitUpdate() { + tree.commitUpdate(treeRecorder); + } }; updateRecorders.set(sourceFile, recorder); return recorder; diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/ng_declaration_collector.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/ng_declaration_collector.ts index f0c770cbda18b..e6d569c28bed9 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/ng_declaration_collector.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/ng_declaration_collector.ts @@ -10,7 +10,7 @@ import {Reference} from '@angular/compiler-cli/src/ngtsc/imports'; import {PartialEvaluator, ResolvedValue} from '@angular/compiler-cli/src/ngtsc/partial_evaluator'; import * as ts from 'typescript'; -import {NgDecorator, getAngularDecorators} from '../../utils/ng_decorators'; +import {getAngularDecorators, NgDecorator} from '../../utils/ng_decorators'; import {getPropertyNameText} from '../../utils/typescript/property_name'; diff --git a/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts b/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts index 5ec39b6e3eb7a..f6857adde714f 100644 --- a/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts +++ b/packages/core/schematics/migrations/undecorated-classes-with-di/transform.ts @@ -17,7 +17,7 @@ import {hasExplicitConstructor} from '../../utils/typescript/class_declaration'; import {findBaseClassDeclarations} from '../../utils/typescript/find_base_classes'; import {getImportOfIdentifier} from '../../utils/typescript/imports'; -import {UnexpectedMetadataValueError, convertDirectiveMetadataToExpression} from './decorator_rewrite/convert_directive_metadata'; +import {convertDirectiveMetadataToExpression, UnexpectedMetadataValueError} from './decorator_rewrite/convert_directive_metadata'; import {DecoratorRewriter} from './decorator_rewrite/decorator_rewriter'; import {hasDirectiveDecorator, hasInjectableDecorator} from './ng_declaration_collector'; import {UpdateRecorder} from './update_recorder'; @@ -316,7 +316,9 @@ export class UndecoratedClassesTransform { } /** Records all changes that were made in the import manager. */ - recordChanges() { this.importManager.recordChanges(); } + recordChanges() { + this.importManager.recordChanges(); + } /** * Constructs a TypeScript decorator node from the specified declaration metadata. Returns diff --git a/packages/core/schematics/test/dynamic_queries_migration_spec.ts b/packages/core/schematics/test/dynamic_queries_migration_spec.ts index 19b23c951ed51..69b31fb5309ef 100644 --- a/packages/core/schematics/test/dynamic_queries_migration_spec.ts +++ b/packages/core/schematics/test/dynamic_queries_migration_spec.ts @@ -47,7 +47,7 @@ describe('dynamic queries migration', () => { }); it('should remove the options object from a dynamic ViewChild query that only has one property', - async() => { + async () => { writeFile('/index.ts', ` import { Directive, ViewChild } from '@angular/core'; @@ -62,7 +62,7 @@ describe('dynamic queries migration', () => { }); it('should remove the options object from a dynamic ContentChild query that only has one property', - async() => { + async () => { writeFile('/index.ts', ` import { Directive, ContentChild } from '@angular/core'; @@ -77,7 +77,7 @@ describe('dynamic queries migration', () => { }); it('should only remove the `static` flag from a ViewChild query if it has more than one property', - async() => { + async () => { writeFile('/index.ts', ` import { Directive, ViewChild, ElementRef } from '@angular/core'; @@ -93,7 +93,7 @@ describe('dynamic queries migration', () => { }); it('should only remove the `static` flag from a ContentChild query if it has more than one property', - async() => { + async () => { writeFile('/index.ts', ` import { Directive, ContentChild, ElementRef } from '@angular/core'; @@ -108,7 +108,7 @@ describe('dynamic queries migration', () => { .toContain(`@ContentChild('child', { read: ElementRef }) child: ElementRef;`); }); - it('should not change static ViewChild queries', async() => { + it('should not change static ViewChild queries', async () => { writeFile('/index.ts', ` import { Directive, ViewChild, ElementRef } from '@angular/core'; @@ -123,7 +123,7 @@ describe('dynamic queries migration', () => { .toContain(`@ViewChild('child', { read: ElementRef, static: true }) child: ElementRef;`); }); - it('should not change static ContentChild queries', async() => { + it('should not change static ContentChild queries', async () => { writeFile('/index.ts', ` import { Directive, ContentChild, ElementRef } from '@angular/core'; @@ -138,7 +138,7 @@ describe('dynamic queries migration', () => { .toContain(`@ContentChild('child', { static: true, read: ElementRef }) child: ElementRef;`); }); - it('should migrate dynamic queries on a setter', async() => { + it('should migrate dynamic queries on a setter', async () => { writeFile('/index.ts', ` import { Directive, ContentChild, ViewChild } from '@angular/core'; diff --git a/packages/core/schematics/test/google3/dynamic_queries_spec.ts b/packages/core/schematics/test/google3/dynamic_queries_spec.ts index 51f5a2ec8000b..16ec13d368cb3 100644 --- a/packages/core/schematics/test/google3/dynamic_queries_spec.ts +++ b/packages/core/schematics/test/google3/dynamic_queries_spec.ts @@ -17,7 +17,7 @@ describe('Google3 dynamic queries TSLint rule', () => { let tmpDir: string; beforeEach(() => { - tmpDir = join(process.env['TEST_TMPDIR'] !, 'google3-test'); + tmpDir = join(process.env['TEST_TMPDIR']!, 'google3-test'); shx.mkdir('-p', tmpDir); writeFile('tsconfig.json', JSON.stringify({compilerOptions: {module: 'es2015'}})); @@ -31,7 +31,7 @@ describe('Google3 dynamic queries TSLint rule', () => { const config = Configuration.parseConfigFile({rules: {'dynamic-queries': true}}); program.getRootFileNames().forEach(fileName => { - linter.lint(fileName, program.getSourceFile(fileName) !.getFullText(), config); + linter.lint(fileName, program.getSourceFile(fileName)!.getFullText(), config); }); return linter; @@ -41,7 +41,9 @@ describe('Google3 dynamic queries TSLint rule', () => { writeFileSync(join(tmpDir, fileName), content); } - function getFile(fileName: string) { return readFileSync(join(tmpDir, fileName), 'utf8'); } + function getFile(fileName: string) { + return readFileSync(join(tmpDir, fileName), 'utf8'); + } it('should flag dynamic queries', () => { writeFile('/index.ts', ` @@ -172,5 +174,4 @@ describe('Google3 dynamic queries TSLint rule', () => { expect(content).toContain(`@ContentChild('child') set child(c: any) {}`); expect(content).toContain(`@ViewChild('otherChild') set otherChild(c: any) {}`); }); - }); diff --git a/packages/core/schematics/test/google3/explicit_query_timing_rule_spec.ts b/packages/core/schematics/test/google3/explicit_query_timing_rule_spec.ts index 3705176b85f89..895973c728836 100644 --- a/packages/core/schematics/test/google3/explicit_query_timing_rule_spec.ts +++ b/packages/core/schematics/test/google3/explicit_query_timing_rule_spec.ts @@ -12,7 +12,6 @@ import * as shx from 'shelljs'; import {Configuration, Linter} from 'tslint'; describe('Google3 explicitQueryTiming TSLint rule', () => { - /** * Path to the static-query schematic rules directory. The path needs to be resolved through * the Bazel runfiles, because on Windows runfiles are not symlinked into the working directory. @@ -23,7 +22,7 @@ describe('Google3 explicitQueryTiming TSLint rule', () => { let tmpDir: string; beforeEach(() => { - tmpDir = join(process.env['TEST_TMPDIR'] !, 'google3-test'); + tmpDir = join(process.env['TEST_TMPDIR']!, 'google3-test'); shx.mkdir('-p', tmpDir); writeFile('tsconfig.json', JSON.stringify({compilerOptions: {module: 'es2015'}})); @@ -41,7 +40,7 @@ describe('Google3 explicitQueryTiming TSLint rule', () => { const config = Configuration.parseConfigFile({rules: {'explicit-query-timing': true}}); program.getRootFileNames().forEach(fileName => { - linter.lint(fileName, program.getSourceFile(fileName) !.getFullText(), config); + linter.lint(fileName, program.getSourceFile(fileName)!.getFullText(), config); }); return linter; diff --git a/packages/core/schematics/test/google3/missing_injectable_rule_spec.ts b/packages/core/schematics/test/google3/missing_injectable_rule_spec.ts index 87cf98a077f75..5a11ec8ad6431 100644 --- a/packages/core/schematics/test/google3/missing_injectable_rule_spec.ts +++ b/packages/core/schematics/test/google3/missing_injectable_rule_spec.ts @@ -18,7 +18,7 @@ describe('Google3 missing injectable tslint rule', () => { let tmpDir: string; beforeEach(() => { - tmpDir = join(process.env['TEST_TMPDIR'] !, 'google3-test'); + tmpDir = join(process.env['TEST_TMPDIR']!, 'google3-test'); shx.mkdir('-p', tmpDir); writeFile('tsconfig.json', JSON.stringify({compilerOptions: {module: 'es2015'}})); @@ -32,7 +32,7 @@ describe('Google3 missing injectable tslint rule', () => { const config = Configuration.parseConfigFile({rules: {'no-missing-injectable': true}}); program.getRootFileNames().forEach(fileName => { - linter.lint(fileName, program.getSourceFile(fileName) !.getFullText(), config); + linter.lint(fileName, program.getSourceFile(fileName)!.getFullText(), config); }); return linter; @@ -42,7 +42,9 @@ describe('Google3 missing injectable tslint rule', () => { writeFileSync(join(tmpDir, fileName), content); } - function getFile(fileName: string) { return readFileSync(join(tmpDir, fileName), 'utf8'); } + function getFile(fileName: string) { + return readFileSync(join(tmpDir, fileName), 'utf8'); + } describe('NgModule', () => createTests('NgModule', 'providers')); describe('Directive', () => createTests('Directive', 'providers')); @@ -77,7 +79,7 @@ describe('Google3 missing injectable tslint rule', () => { }); function createTests( - type: 'NgModule' | 'Directive' | 'Component', propName: 'providers' | 'viewProviders') { + type: 'NgModule'|'Directive'|'Component', propName: 'providers'|'viewProviders') { it('should create proper failures for missing injectable providers', () => { writeFile('index.ts', ` import { ${type} } from '@angular/core'; @@ -266,6 +268,4 @@ describe('Google3 missing injectable tslint rule', () => { .toMatch(/import { Inject, Injectable } from '@angular\/core';/); }); } - - }); diff --git a/packages/core/schematics/test/google3/no_template_variable_assignment_rule_spec.ts b/packages/core/schematics/test/google3/no_template_variable_assignment_rule_spec.ts index 66ce27f7ccbab..08ffd83ebf015 100644 --- a/packages/core/schematics/test/google3/no_template_variable_assignment_rule_spec.ts +++ b/packages/core/schematics/test/google3/no_template_variable_assignment_rule_spec.ts @@ -18,7 +18,7 @@ describe('Google3 noTemplateVariableAssignment TSLint rule', () => { let tmpDir: string; beforeEach(() => { - tmpDir = join(process.env['TEST_TMPDIR'] !, 'google3-test'); + tmpDir = join(process.env['TEST_TMPDIR']!, 'google3-test'); shx.mkdir('-p', tmpDir); writeFile('tsconfig.json', JSON.stringify({compilerOptions: {module: 'es2015'}})); @@ -34,7 +34,7 @@ describe('Google3 noTemplateVariableAssignment TSLint rule', () => { Configuration.parseConfigFile({rules: {'no-template-variable-assignment': true}}); program.getRootFileNames().forEach(fileName => { - linter.lint(fileName, program.getSourceFile(fileName) !.getFullText(), config); + linter.lint(fileName, program.getSourceFile(fileName)!.getFullText(), config); }); return linter; diff --git a/packages/core/schematics/test/google3/renderer_to_renderer2_spec.ts b/packages/core/schematics/test/google3/renderer_to_renderer2_spec.ts index f403e7a026782..ee5a452899b9f 100644 --- a/packages/core/schematics/test/google3/renderer_to_renderer2_spec.ts +++ b/packages/core/schematics/test/google3/renderer_to_renderer2_spec.ts @@ -18,7 +18,7 @@ describe('Google3 Renderer to Renderer2 TSLint rule', () => { let tmpDir: string; beforeEach(() => { - tmpDir = join(process.env['TEST_TMPDIR'] !, 'google3-test'); + tmpDir = join(process.env['TEST_TMPDIR']!, 'google3-test'); shx.mkdir('-p', tmpDir); // We need to declare the Angular symbols we're testing for, otherwise type checking won't work. @@ -46,7 +46,7 @@ describe('Google3 Renderer to Renderer2 TSLint rule', () => { const config = Configuration.parseConfigFile({rules: {'renderer-to-renderer2': true}}); program.getRootFileNames().forEach(fileName => { - linter.lint(fileName, program.getSourceFile(fileName) !.getFullText(), config); + linter.lint(fileName, program.getSourceFile(fileName)!.getFullText(), config); }); return linter; @@ -56,7 +56,9 @@ describe('Google3 Renderer to Renderer2 TSLint rule', () => { writeFileSync(join(tmpDir, fileName), content); } - function getFile(fileName: string) { return readFileSync(join(tmpDir, fileName), 'utf8'); } + function getFile(fileName: string) { + return readFileSync(join(tmpDir, fileName), 'utf8'); + } it('should flag Renderer imports and typed nodes', () => { writeFile('/index.ts', ` @@ -223,8 +225,8 @@ describe('Google3 Renderer to Renderer2 TSLint rule', () => { runTSLint(true); const content = getFile('index.ts'); - expect(content.match(/function __ngRendererCreateElementHelper\(/g) !.length).toBe(1); - expect(content.match(/function __ngRendererSetElementAttributeHelper\(/g) !.length).toBe(1); + expect(content.match(/function __ngRendererCreateElementHelper\(/g)!.length).toBe(1); + expect(content.match(/function __ngRendererSetElementAttributeHelper\(/g)!.length).toBe(1); }); it('should insert helpers after the user\'s code', () => { @@ -410,5 +412,4 @@ describe('Google3 Renderer to Renderer2 TSLint rule', () => { // Expect the `setInfo` method to only contain whitespace. expect(content).toMatch(/setInfo\(\) \{\s+\}/); }); - }); diff --git a/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts b/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts index c78cdfcad0307..a8e5764a5ef5d 100644 --- a/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts +++ b/packages/core/schematics/test/google3/undecorated_classes_with_decorated_fields_spec.ts @@ -18,7 +18,7 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => let tmpDir: string; beforeEach(() => { - tmpDir = join(process.env['TEST_TMPDIR'] !, 'google3-test'); + tmpDir = join(process.env['TEST_TMPDIR']!, 'google3-test'); shx.mkdir('-p', tmpDir); writeFile('tsconfig.json', JSON.stringify({compilerOptions: {module: 'es2015'}})); }); @@ -33,7 +33,7 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => }); program.getRootFileNames().forEach(fileName => { - linter.lint(fileName, program.getSourceFile(fileName) !.getFullText(), config); + linter.lint(fileName, program.getSourceFile(fileName)!.getFullText(), config); }); return linter; @@ -43,7 +43,9 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => writeFileSync(join(tmpDir, fileName), content); } - function getFile(fileName: string) { return readFileSync(join(tmpDir, fileName), 'utf8'); } + function getFile(fileName: string) { + return readFileSync(join(tmpDir, fileName), 'utf8'); + } it('should flag undecorated classes with decorated fields', () => { writeFile('/index.ts', ` @@ -97,8 +99,9 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => expect(getFile('/index.ts')).toContain(`import { Directive, Input } from '@angular/core';`); }); - it('should not generate conflicting imports there is a different `Directive` symbol', async() => { - writeFile('/index.ts', ` + it('should not generate conflicting imports there is a different `Directive` symbol', + async () => { + writeFile('/index.ts', ` import { HostBinding } from '@angular/core'; export class Directive { @@ -111,12 +114,12 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => } `); - runTSLint(true); - const fileContent = getFile('/index.ts'); - expect(fileContent) - .toContain(`import { HostBinding, Directive as Directive_1 } from '@angular/core';`); - expect(fileContent).toMatch(/@Directive_1\(\)\s+export class MyLibrarySharedBaseClass/); - }); + runTSLint(true); + const fileContent = getFile('/index.ts'); + expect(fileContent) + .toContain(`import { HostBinding, Directive as Directive_1 } from '@angular/core';`); + expect(fileContent).toMatch(/@Directive_1\(\)\s+export class MyLibrarySharedBaseClass/); + }); it('should add @Directive to undecorated classes that have @Input', () => { writeFile('/index.ts', ` @@ -250,7 +253,7 @@ describe('Google3 undecorated classes with decorated fields TSLint rule', () => expect(getFile('/index.ts')).toContain(`@Directive()\nexport class Base {`); }); - it('should add @Directive to undecorated derived classes of a migrated class', async() => { + it('should add @Directive to undecorated derived classes of a migrated class', async () => { writeFile('/index.ts', ` import { Input, Directive, NgModule } from '@angular/core'; diff --git a/packages/core/schematics/test/line_mappings_spec.ts b/packages/core/schematics/test/line_mappings_spec.ts index a9aa66fb5bb53..17565e11d88d2 100644 --- a/packages/core/schematics/test/line_mappings_spec.ts +++ b/packages/core/schematics/test/line_mappings_spec.ts @@ -9,7 +9,6 @@ import {computeLineStartsMap, getLineAndCharacterFromPosition} from '../utils/line_mappings'; describe('line mappings', () => { - it('should properly compute line starts', () => { expect(computeLineStartsMap(` diff --git a/packages/core/schematics/test/missing_injectable_migration_spec.ts b/packages/core/schematics/test/missing_injectable_migration_spec.ts index 762989f4a8204..f07027a538a7b 100644 --- a/packages/core/schematics/test/missing_injectable_migration_spec.ts +++ b/packages/core/schematics/test/missing_injectable_migration_spec.ts @@ -76,7 +76,7 @@ describe('Missing injectable migration', () => { it('should migrate all providers defined in "viewProviders" and "providers" in the ' + 'same component', - async() => { + async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -102,8 +102,8 @@ describe('Missing injectable migration', () => { }); function createTests( - type: 'NgModule' | 'Directive' | 'Component', propName: 'providers' | 'viewProviders') { - it(`should migrate type provider in ${type}`, async() => { + type: 'NgModule'|'Directive'|'Component', propName: 'providers'|'viewProviders') { + it(`should migrate type provider in ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -121,7 +121,7 @@ describe('Missing injectable migration', () => { .toContain(`{ ${type}, Injectable } from '@angular/core`); }); - it(`should migrate object literal provider in ${type} to explicit value provider`, async() => { + it(`should migrate object literal provider in ${type} to explicit value provider`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -140,7 +140,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).toContain(`{${type}} from '@angular/core`); }); - it(`should migrate object literal provider with forwardRef in ${type}`, async() => { + it(`should migrate object literal provider with forwardRef in ${type}`, async () => { writeFile('/index.ts', ` import {${type}, forwardRef} from '@angular/core'; @@ -158,7 +158,7 @@ describe('Missing injectable migration', () => { .toContain(`{ ${type}, forwardRef, Injectable } from '@angular/core`); }); - it(`should not migrate object literal provider with "useValue" in ${type}`, async() => { + it(`should not migrate object literal provider with "useValue" in ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -174,7 +174,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it(`should not migrate provider with "useClass" and "deps" in ${type}`, async() => { + it(`should not migrate provider with "useClass" and "deps" in ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -190,7 +190,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it(`should not migrate object literal provider with "useFactory" in ${type}`, async() => { + it(`should not migrate object literal provider with "useFactory" in ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -206,7 +206,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it(`should not migrate object literal provider with "useExisting" in ${type}`, async() => { + it(`should not migrate object literal provider with "useExisting" in ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -226,7 +226,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it(`should migrate object literal provider with "useClass" in ${type}`, async() => { + it(`should migrate object literal provider with "useClass" in ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -248,7 +248,7 @@ describe('Missing injectable migration', () => { it(`should not migrate references for providers with "useExisting" in ${type}, but migrate ` + `existing token if declared in other ${type}`, - async() => { + async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -281,7 +281,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).toMatch(/MyService {}\s+export class MyToken/); }); - it('should not migrate provider which is already decorated with @Injectable', async() => { + it('should not migrate provider which is already decorated with @Injectable', async () => { writeFile('/index.ts', ` import {Injectable, ${type}} from '@angular/core'; @@ -299,7 +299,7 @@ describe('Missing injectable migration', () => { .toMatch(/@angular\/core';\s+@Injectable\(\)\s+export class MyService/); }); - it('should not migrate provider which is already decorated with @Directive', async() => { + it('should not migrate provider which is already decorated with @Directive', async () => { writeFile('/index.ts', ` import {Directive, ${type}} from '@angular/core'; @@ -316,7 +316,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it('should not migrate provider which is already decorated with @Component', async() => { + it('should not migrate provider which is already decorated with @Component', async () => { writeFile('/index.ts', ` import {Component, ${type}} from '@angular/core'; @@ -333,7 +333,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it('should not migrate provider which is already decorated with @Pipe', async() => { + it('should not migrate provider which is already decorated with @Pipe', async () => { writeFile('/index.ts', ` import {Pipe, ${type}} from '@angular/core'; @@ -350,7 +350,7 @@ describe('Missing injectable migration', () => { expect(tree.readContent('/index.ts')).not.toContain('@Injectable'); }); - it(`should migrate multiple providers in same ${type}`, async() => { + it(`should migrate multiple providers in same ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -370,7 +370,7 @@ describe('Missing injectable migration', () => { .toContain(`{ ${type}, Injectable } from '@angular/core`); }); - it(`should migrate multiple mixed providers in same ${type}`, async() => { + it(`should migrate multiple mixed providers in same ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -399,7 +399,7 @@ describe('Missing injectable migration', () => { .toContain(`{ provide: ServiceB, useValue: undefined },`); }); - it(`should migrate multiple nested providers in same ${type}`, async() => { + it(`should migrate multiple nested providers in same ${type}`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -433,7 +433,7 @@ describe('Missing injectable migration', () => { .toContain(`{ provide: ServiceD, useValue: undefined },`); }); - it('should migrate providers referenced through identifier', async() => { + it('should migrate providers referenced through identifier', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -467,7 +467,7 @@ describe('Missing injectable migration', () => { .toContain(`{ provide: ServiceC, useValue: undefined },`); }); - it('should migrate providers created through static analyzable function call', async() => { + it('should migrate providers created through static analyzable function call', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -497,7 +497,7 @@ describe('Missing injectable migration', () => { .toContain(`ServiceB, { provide: ServiceC, useValue: undefined }),`); }); - it('should migrate providers which are computed through spread operator', async() => { + it('should migrate providers which are computed through spread operator', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -525,7 +525,7 @@ describe('Missing injectable migration', () => { .toContain(`ServiceB, { provide: ServiceC, useValue: undefined }];`); }); - it(`should migrate provider once if referenced in multiple ${type} definitions`, async() => { + it(`should migrate provider once if referenced in multiple ${type} definitions`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -559,7 +559,7 @@ describe('Missing injectable migration', () => { it(`should only migrate empty object provider literal once if referenced multiple times ` + `in ${type} definitions`, - async() => { + async () => { writeFile('/provider.ts', ` export class MyService {} @@ -592,7 +592,7 @@ describe('Missing injectable migration', () => { .toContain(`const PROVIDER = { provide: MyService, useValue: undefined };`); }); - it('should create new import for @Injectable when migrating provider', async() => { + it('should create new import for @Injectable when migrating provider', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; import {MyService, MySecondService} from './service'; @@ -617,7 +617,7 @@ describe('Missing injectable migration', () => { }); it('should re-use existing namespace import for importing @Injectable when migrating provider', - async() => { + async () => { writeFile('/index.ts', ` import * as core from '@angular/core'; @@ -643,7 +643,7 @@ describe('Missing injectable migration', () => { .toMatch(/@core.Injectable\(\)\s+export class MyService/); }); - it('should warn if a referenced individual provider could not be resolved', async() => { + it('should warn if a referenced individual provider could not be resolved', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -659,7 +659,7 @@ describe('Missing injectable migration', () => { expect(warnOutput[0]).toContain(`4:${providerSourceTextColumn}:`); }); - it(`should warn if ${propName} value could not be resolved`, async() => { + it(`should warn if ${propName} value could not be resolved`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -675,7 +675,7 @@ describe('Missing injectable migration', () => { expect(warnOutput[0]).toContain(`4:${propValueSourceTextColumn}:`); }); - it(`should not throw if an empty @${type} is analyzed`, async() => { + it(`should not throw if an empty @${type} is analyzed`, async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; @@ -693,7 +693,7 @@ describe('Missing injectable migration', () => { }); it('should create new import for injectable after full end of last import statement', - async() => { + async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; import {MyService} from './service'; @@ -718,7 +718,7 @@ describe('Missing injectable migration', () => { .toMatch(/'b'; \/\/ some comment\s+import { Injectable } from "@angular\/core";/); }); - it('should create new import at source file start with trailing new-line', async() => { + it('should create new import at source file start with trailing new-line', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; import {MyService} from './service'; @@ -739,7 +739,7 @@ describe('Missing injectable migration', () => { /^import { Injectable } from "@angular\/core";\s+\/\* @license \*\/\s+@Injectable\(\)\s+export class MyService/); }); - it('should remove @Inject decorator for providers which are migrated', async() => { + it('should remove @Inject decorator for providers which are migrated', async () => { writeFile('/index.ts', ` import {${type}} from '@angular/core'; import {MyService} from './service'; @@ -766,7 +766,7 @@ describe('Missing injectable migration', () => { .toMatch(/import { Inject, Injectable } from '@angular\/core';/); }); - it('should not migrate provider classes in library type definitions', async() => { + it('should not migrate provider classes in library type definitions', async () => { writeFile('/node_modules/my-lib/index.d.ts', ` export declare class MyService {} `); diff --git a/packages/core/schematics/test/module_with_providers_migration_spec.ts b/packages/core/schematics/test/module_with_providers_migration_spec.ts index 089753a633d15..13a999e76d90e 100644 --- a/packages/core/schematics/test/module_with_providers_migration_spec.ts +++ b/packages/core/schematics/test/module_with_providers_migration_spec.ts @@ -46,7 +46,7 @@ describe('ModuleWithProviders migration', () => { shx.rm('-r', tmpDirPath); }); - it('should add generic type for function return', async() => { + it('should add generic type for function return', async () => { writeFile('/index.ts', ` import {NgModule, ModuleWithProviders} from '@angular/core'; @@ -69,7 +69,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).toContain(`ModuleWithProviders<BaseModule>`); }); - it('should add generic type for function return; external file', async() => { + it('should add generic type for function return; external file', async () => { writeFile('/module.ts', ` import {NgModule} from '@angular/core'; @@ -96,7 +96,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).toContain(`ModuleWithProviders<BaseModule>`); }); - it('should add generic type for function return without explicit type', async() => { + it('should add generic type for function return without explicit type', async () => { writeFile('/index.ts', ` import {NgModule} from '@angular/core'; @@ -119,7 +119,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).toContain(`ModuleWithProviders<BaseModule>`); }); - it('should add generic type for const variable', async() => { + it('should add generic type for const variable', async () => { writeFile('/index.ts', ` import {ModuleWithProviders, NgModule} from '@angular/core'; @@ -140,7 +140,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).toContain(`ModuleWithProviders<BaseModule>`); }); - it('should add generic type for const variable without explicit type', async() => { + it('should add generic type for const variable without explicit type', async () => { writeFile('/index.ts', ` import {NgModule} from '@angular/core'; @@ -161,7 +161,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).toContain(`ModuleWithProviders<BaseModule>`); }); - it('should not add generic type for const variable with invalid base object', async() => { + it('should not add generic type for const variable with invalid base object', async () => { writeFile('/index.ts', ` import {NgModule} from '@angular/core'; @@ -182,7 +182,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).not.toContain(`ModuleWithProviders<BaseModule>`); }); - it('should add generic type for const variables and functions with incomplete type', async() => { + it('should add generic type for const variables and functions with incomplete type', async () => { writeFile('/index.ts', ` import {ModuleWithProviders, NgModule} from '@angular/core'; @@ -214,7 +214,7 @@ describe('ModuleWithProviders migration', () => { expect(tree.readContent('/index.ts')).not.toContain(`ModuleWithProviders `); }); - it('should not add generic type for const variables without initialization', async() => { + it('should not add generic type for const variables without initialization', async () => { writeFile('/index.ts', ` import {ModuleWithProviders} from '@angular/core'; diff --git a/packages/core/schematics/test/move_document_migration_spec.ts b/packages/core/schematics/test/move_document_migration_spec.ts index 46aefc9e016d2..d0f252c4fc5af 100644 --- a/packages/core/schematics/test/move_document_migration_spec.ts +++ b/packages/core/schematics/test/move_document_migration_spec.ts @@ -47,7 +47,7 @@ describe('move-document migration', () => { }); describe('move-document', () => { - it('should properly apply import replacement', async() => { + it('should properly apply import replacement', async () => { writeFile('/index.ts', ` import {DOCUMENT} from '@angular/platform-browser'; `); @@ -73,7 +73,7 @@ describe('move-document migration', () => { expect(content).not.toContain(`import {DOCUMENT} from '@angular/platform-browser';`); }); - it('should properly apply import replacement with existing import', async() => { + it('should properly apply import replacement with existing import', async () => { writeFile('/index.ts', ` import {DOCUMENT} from '@angular/platform-browser'; import {someImport} from '@angular/common'; @@ -96,7 +96,7 @@ describe('move-document migration', () => { expect(contentReverse).not.toContain(`import {DOCUMENT} from '@angular/platform-browser';`); }); - it('should properly apply import replacement with existing import w/ comments', async() => { + it('should properly apply import replacement with existing import w/ comments', async () => { writeFile('/index.ts', ` /** * this is a comment @@ -115,7 +115,7 @@ describe('move-document migration', () => { expect(content).toMatch(/.*this is a comment.*/); }); - it('should properly apply import replacement with existing and redundant imports', async() => { + it('should properly apply import replacement with existing and redundant imports', async () => { writeFile('/index.ts', ` import {DOCUMENT} from '@angular/platform-browser'; import {anotherImport} from '@angular/platform-browser-dynamic'; @@ -131,7 +131,7 @@ describe('move-document migration', () => { }); it('should properly apply import replacement with existing import and leave original import', - async() => { + async () => { writeFile('/index.ts', ` import {DOCUMENT, anotherImport} from '@angular/platform-browser'; import {someImport} from '@angular/common'; @@ -145,7 +145,7 @@ describe('move-document migration', () => { expect(content).toContain(`import { anotherImport } from '@angular/platform-browser';`); }); - it('should properly apply import replacement with existing import and alias', async() => { + it('should properly apply import replacement with existing import and alias', async () => { writeFile('/index.ts', ` import {DOCUMENT as doc, anotherImport} from '@angular/platform-browser'; import {someImport} from '@angular/common'; diff --git a/packages/core/schematics/test/project_tsconfig_paths_spec.ts b/packages/core/schematics/test/project_tsconfig_paths_spec.ts index 0ebf15276debc..b9cb58b5047c8 100644 --- a/packages/core/schematics/test/project_tsconfig_paths_spec.ts +++ b/packages/core/schematics/test/project_tsconfig_paths_spec.ts @@ -13,13 +13,14 @@ import {getProjectTsConfigPaths} from '../utils/project_tsconfig_paths'; describe('project tsconfig paths', () => { let testTree: UnitTestTree; - beforeEach(() => { testTree = new UnitTestTree(new HostTree()); }); + beforeEach(() => { + testTree = new UnitTestTree(new HostTree()); + }); it('should detect build tsconfig path inside of angular.json file', () => { testTree.create('/my-custom-config.json', ''); testTree.create('/angular.json', JSON.stringify({ - projects: - {my_name: {architect: {build: {options: {tsConfig: './my-custom-config.json'}}}}} + projects: {my_name: {architect: {build: {options: {tsConfig: './my-custom-config.json'}}}}} })); expect(getProjectTsConfigPaths(testTree).buildPaths).toEqual(['my-custom-config.json']); @@ -57,8 +58,7 @@ describe('project tsconfig paths', () => { it('should detect test tsconfig path inside of .angular.json file', () => { testTree.create('/my-test-config.json', ''); testTree.create('/.angular.json', JSON.stringify({ - projects: - {with_tests: {architect: {test: {options: {tsConfig: './my-test-config.json'}}}}} + projects: {with_tests: {architect: {test: {options: {tsConfig: './my-test-config.json'}}}}} })); expect(getProjectTsConfigPaths(testTree).testPaths).toEqual(['my-test-config.json']); diff --git a/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts b/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts index c30919ea5d9c8..c818804e89cf0 100644 --- a/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts +++ b/packages/core/schematics/test/renderer_to_renderer2_migration_spec.ts @@ -52,7 +52,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('import renaming', () => { - it('should change Renderer imports to Renderer2', async() => { + it('should change Renderer imports to Renderer2', async () => { writeFile('/index.ts', ` import { Renderer, Component } from '@angular/core'; @@ -67,7 +67,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain(`import { Component, Renderer2 } from '@angular/core';`); }); - it('should change aliased Renderer imports to Renderer2', async() => { + it('should change aliased Renderer imports to Renderer2', async () => { writeFile('/index.ts', ` import { Renderer as RenamedRenderer, Component } from '@angular/core'; @@ -82,7 +82,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain(`import { Component, Renderer2 as RenamedRenderer } from '@angular/core';`); }); - it('should not change Renderer imports if they are not from @angular/core', async() => { + it('should not change Renderer imports if they are not from @angular/core', async () => { writeFile('/index.ts', ` import { Component } from '@angular/core'; import { Renderer } from './my-renderer'; @@ -102,7 +102,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('type renaming', () => { - it('should change type of constructor parameter from Renderer to Renderer2', async() => { + it('should change type of constructor parameter from Renderer to Renderer2', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -117,7 +117,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain('constructor(element: ElementRef, renderer: Renderer2)'); }); - it('should change type of method parameter from Renderer to Renderer2', async() => { + it('should change type of method parameter from Renderer to Renderer2', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -134,7 +134,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain('disable(renderer: Renderer2, element: HTMLElement, isDisabled: boolean)'); }); - it('should change type of property declarations', async() => { + it('should change type of property declarations', async () => { writeFile('/index.ts', ` import { Renderer, Component } from '@angular/core'; @@ -148,7 +148,7 @@ describe('Renderer to Renderer2 migration', () => { expect(tree.readContent('/index.ts')).toContain('public renderer: Renderer2;'); }); - it('should change type of properties initialized via the constructor', async() => { + it('should change type of properties initialized via the constructor', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -163,7 +163,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain('constructor(element: ElementRef, private _renderer: Renderer2)'); }); - it('should change the type of something that was cast to Renderer', async() => { + it('should change the type of something that was cast to Renderer', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -184,7 +184,7 @@ describe('Renderer to Renderer2 migration', () => { expect(content).toContain(`renderer.setStyle(element.nativeElement, 'color', 'red');`); }); - it('should not rename types called Renderer that do not come from Angular', async() => { + it('should not rename types called Renderer that do not come from Angular', async () => { // Write a dummy renderer file so type checking picks it up. writeFile('/my-renderer.ts', `export abstract class Renderer {}`); @@ -203,7 +203,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain('constructor(element: ElementRef, renderer: Renderer)'); }); - it('should rename inside single-line forwardRef', async() => { + it('should rename inside single-line forwardRef', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef, forwardRef, Inject } from '@angular/core'; @@ -221,7 +221,7 @@ describe('Renderer to Renderer2 migration', () => { `constructor(@Inject(forwardRef(() => Renderer2)) private _renderer: Renderer2)`); }); - it('should rename inside multi-line forwardRef', async() => { + it('should rename inside multi-line forwardRef', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef, forwardRef, Inject } from '@angular/core'; @@ -238,11 +238,10 @@ describe('Renderer to Renderer2 migration', () => { expect(content).toContain( `constructor(@Inject(forwardRef(() => { return Renderer2; })) private _renderer: Renderer2) {}`); }); - }); describe('helper insertion', () => { - it('should only declare each helper once per file', async() => { + it('should only declare each helper once per file', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -260,11 +259,11 @@ describe('Renderer to Renderer2 migration', () => { const content = tree.readContent('/index.ts'); - expect(content.match(/function __ngRendererCreateElementHelper\(/g) !.length) + expect(content.match(/function __ngRendererCreateElementHelper\(/g)!.length) .toBe(1, 'Expected exactly one helper for createElement.'); }); - it('should insert helpers after the user\'s code', async() => { + it('should insert helpers after the user\'s code', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -287,7 +286,7 @@ describe('Renderer to Renderer2 migration', () => { expect(contentAfterSeparator).toContain('function __ngRendererCreateElementHelper('); }); - it('should be able to handle multiple helpers per file', async() => { + it('should be able to handle multiple helpers per file', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -314,15 +313,15 @@ describe('Renderer to Renderer2 migration', () => { const content = tree.readContent('/index.ts'); - expect(content.match(/function __ngRendererCreateTextHelper\(/g) !.length) + expect(content.match(/function __ngRendererCreateTextHelper\(/g)!.length) .toBe(1, 'Expected exactly one helper for createElement.'); - expect(content.match(/function __ngRendererCreateElementHelper\(/g) !.length) + expect(content.match(/function __ngRendererCreateElementHelper\(/g)!.length) .toBe(1, 'Expected exactly one helper for createText.'); - expect(content.match(/function __ngRendererCreateTemplateAnchorHelper\(/g) !.length) + expect(content.match(/function __ngRendererCreateTemplateAnchorHelper\(/g)!.length) .toBe(1, 'Expected exactly one helper for createTemplateAnchor.'); }); - it('should create the __ngRendererSplitNamespaceHelper', async() => { + it('should create the __ngRendererSplitNamespaceHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -347,7 +346,7 @@ describe('Renderer to Renderer2 migration', () => { `)); }); - it('should declare our custom any type', async() => { + it('should declare our custom any type', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -365,11 +364,10 @@ describe('Renderer to Renderer2 migration', () => { type AnyDuringRendererMigration = any; `)); }); - }); describe('setElementProperty migration', () => { - it('should migrate setElementProperty calls', async() => { + it('should migrate setElementProperty calls', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -390,7 +388,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('setText migration', () => { - it('should migrate setText calls', async() => { + it('should migrate setText calls', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -412,7 +410,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('listenGlobal migration', () => { - it('should migrate listenGlobal calls', async() => { + it('should migrate listenGlobal calls', async () => { writeFile('/index.ts', ` import { Renderer, Component } from '@angular/core'; @@ -433,7 +431,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('selectRootElement migration', () => { - it('should migrate selectRootElement calls', async() => { + it('should migrate selectRootElement calls', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -454,7 +452,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('setElementClass migration', () => { - it('should migrate calls with inline isAdd value', async() => { + it('should migrate calls with inline isAdd value', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -479,7 +477,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain(`this._renderer.removeClass(this._element.nativeElement, className);`); }); - it('should migrate calls with variable isAdd value', async() => { + it('should migrate calls with variable isAdd value', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -503,7 +501,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('setElementStyle migration', () => { - it('should migrate calls with two arguments to a removeStyle call', async() => { + it('should migrate calls with two arguments to a removeStyle call', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -522,7 +520,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain(`this._renderer.removeStyle(this._element.nativeElement, 'color');`); }); - it('should migrate calls with static third arguments to a setStyle call', async() => { + it('should migrate calls with static third arguments to a setStyle call', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -552,7 +550,7 @@ describe('Renderer to Renderer2 migration', () => { }); it('should migrate calls with null or undefined value for last argument to a removeStyle call', - async() => { + async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -575,7 +573,7 @@ describe('Renderer to Renderer2 migration', () => { `this._renderer.removeStyle(this._element.nativeElement, 'background-color');`); }); - it('should migrate calls with a variable third argument', async() => { + it('should migrate calls with a variable third argument', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -597,7 +595,7 @@ describe('Renderer to Renderer2 migration', () => { }); it('should migrate calls with a variable third argument whose value can be inferred', - async() => { + async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -625,7 +623,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('setElementAttribute migration', () => { - it('should migrate to calls to the __ngRendererSetElementAttributeHelper', async() => { + it('should migrate to calls to the __ngRendererSetElementAttributeHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -651,7 +649,7 @@ describe('Renderer to Renderer2 migration', () => { '__ngRendererSetElementAttributeHelper(this._renderer, this._element.nativeElement, name);'); }); - it('should declare the __ngRendererSetElementAttributeHelper', async() => { + it('should declare the __ngRendererSetElementAttributeHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -680,12 +678,11 @@ describe('Renderer to Renderer2 migration', () => { expect(content).toContain(stripWhitespace('function __ngRendererSplitNamespaceHelper(')); }); - }); describe('invokeElementMethod migration', () => { it('should migrate calls to a direct method call if the method name and arguments are static', - async() => { + async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -710,7 +707,7 @@ describe('Renderer to Renderer2 migration', () => { }); it('should migrate calls to a property access if the method name or arguments are dynamic', - async() => { + async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -738,7 +735,7 @@ describe('Renderer to Renderer2 migration', () => { `(this._element.nativeElement as any)['otherMethod'].apply(this._element.nativeElement, args);`); }); - it('should handle calls without an `args` array', async() => { + it('should handle calls without an `args` array', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -761,7 +758,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('setBindingDebugInfo migration', () => { - it('should drop calls to setBindingDebugInfo', async() => { + it('should drop calls to setBindingDebugInfo', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -783,7 +780,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('createViewRoot migration', () => { - it('should replace createViewRoot calls with a reference to the first argument', async() => { + it('should replace createViewRoot calls with a reference to the first argument', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -806,7 +803,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('createElement migration', () => { - it('should migrate to calls to the __ngRendererCreateElementHelper', async() => { + it('should migrate to calls to the __ngRendererCreateElementHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -833,7 +830,7 @@ describe('Renderer to Renderer2 migration', () => { 'return __ngRendererCreateElementHelper(this._renderer, this._element.nativeElement, nodeName);'); }); - it('should declare the __ngRendererCreateElementHelper', async() => { + it('should declare the __ngRendererCreateElementHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -862,11 +859,10 @@ describe('Renderer to Renderer2 migration', () => { expect(content).toContain(stripWhitespace('function __ngRendererSplitNamespaceHelper(')); }); - }); describe('createText migration', () => { - it('should migrate to calls to the __ngRendererCreateTextHelper', async() => { + it('should migrate to calls to the __ngRendererCreateTextHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -893,7 +889,7 @@ describe('Renderer to Renderer2 migration', () => { 'return __ngRendererCreateTextHelper(this._renderer, this._element.nativeElement, value);'); }); - it('should declare the __ngRendererCreateTextHelper', async() => { + it('should declare the __ngRendererCreateTextHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -917,11 +913,10 @@ describe('Renderer to Renderer2 migration', () => { } `)); }); - }); describe('createTemplateAnchor migration', () => { - it('should migrate to calls to the __ngRendererCreateTemplateAnchorHelper', async() => { + it('should migrate to calls to the __ngRendererCreateTemplateAnchorHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -947,7 +942,7 @@ describe('Renderer to Renderer2 migration', () => { 'return __ngRendererCreateTemplateAnchorHelper(this._renderer, this._element.nativeElement);'); }); - it('should declare the __ngRendererCreateTemplateAnchorHelper', async() => { + it('should declare the __ngRendererCreateTemplateAnchorHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -971,11 +966,10 @@ describe('Renderer to Renderer2 migration', () => { } `)); }); - }); describe('projectNodes migration', () => { - it('should migrate to calls to the __ngRendererProjectNodesHelper', async() => { + it('should migrate to calls to the __ngRendererProjectNodesHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -997,7 +991,7 @@ describe('Renderer to Renderer2 migration', () => { '__ngRendererProjectNodesHelper(this._renderer, this._element.nativeElement, nodesToProject);'); }); - it('should declare the __ngRendererProjectNodesHelper', async() => { + it('should declare the __ngRendererProjectNodesHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -1019,11 +1013,10 @@ describe('Renderer to Renderer2 migration', () => { } `)); }); - }); describe('animate migration', () => { - it('should migrate to calls to the __ngRendererAnimateHelper', async() => { + it('should migrate to calls to the __ngRendererAnimateHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -1043,7 +1036,7 @@ describe('Renderer to Renderer2 migration', () => { expect(tree.readContent('/index.ts')).toContain('__ngRendererAnimateHelper();'); }); - it('should declare the __ngRendererAnimateHelper', async() => { + it('should declare the __ngRendererAnimateHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -1063,11 +1056,10 @@ describe('Renderer to Renderer2 migration', () => { } `)); }); - }); describe('destroyView migration', () => { - it('should migrate to calls to the __ngRendererDestroyViewHelper', async() => { + it('should migrate to calls to the __ngRendererDestroyViewHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -1088,7 +1080,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain('__ngRendererDestroyViewHelper(this._renderer, allNodes);'); }); - it('should declare the __ngRendererDestroyViewHelper', async() => { + it('should declare the __ngRendererDestroyViewHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -1116,7 +1108,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('detachView migration', () => { - it('should migrate to calls to the __ngRendererDetachViewHelper', async() => { + it('should migrate to calls to the __ngRendererDetachViewHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component } from '@angular/core'; @@ -1137,7 +1129,7 @@ describe('Renderer to Renderer2 migration', () => { .toContain('__ngRendererDetachViewHelper(this._renderer, rootNodes);'); }); - it('should declare the __ngRendererDetachViewHelper', async() => { + it('should declare the __ngRendererDetachViewHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component } from '@angular/core'; @@ -1166,7 +1158,7 @@ describe('Renderer to Renderer2 migration', () => { }); describe('attachViewAfter migration', () => { - it('should migrate to calls to the __ngRendererAttachViewAfterHelper', async() => { + it('should migrate to calls to the __ngRendererAttachViewAfterHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component, ElementRef } from '@angular/core'; @@ -1188,7 +1180,7 @@ describe('Renderer to Renderer2 migration', () => { '__ngRendererAttachViewAfterHelper(this._renderer, this._element.nativeElement, rootNodes);'); }); - it('should declare the __ngRendererAttachViewAfterHelper', async() => { + it('should declare the __ngRendererAttachViewAfterHelper', async () => { writeFile('/index.ts', ` import { Renderer, Component } from '@angular/core'; @@ -1225,5 +1217,7 @@ describe('Renderer to Renderer2 migration', () => { return runner.runSchematicAsync('migration-v9-renderer-to-renderer2', {}, tree).toPromise(); } - function stripWhitespace(contents: string) { return contents.replace(/\s/g, ''); } + function stripWhitespace(contents: string) { + return contents.replace(/\s/g, ''); + } }); diff --git a/packages/core/schematics/test/static_queries_migration_template_spec.ts b/packages/core/schematics/test/static_queries_migration_template_spec.ts index 341bb27866d54..31882e577016e 100644 --- a/packages/core/schematics/test/static_queries_migration_template_spec.ts +++ b/packages/core/schematics/test/static_queries_migration_template_spec.ts @@ -61,7 +61,9 @@ describe('static-queries migration with template strategy', () => { shx.rm('-r', tmpDirPath); }); - function writeFakeAngular() { writeFile('/node_modules/@angular/core/index.d.ts', ``); } + function writeFakeAngular() { + writeFile('/node_modules/@angular/core/index.d.ts', ``); + } function writeFakeLibrary(selectorName = 'my-lib-selector') { writeFile('/node_modules/my-lib/index.d.ts', `export * from './public-api';`); @@ -105,8 +107,7 @@ describe('static-queries migration with template strategy', () => { } describe('ViewChild', () => { - - it('should detect queries selecting elements through template reference', async() => { + it('should detect queries selecting elements through template reference', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -135,7 +136,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myStaticButton', { static: true }) query2: any;`); }); - it('should detect queries selecting ng-template as static', async() => { + it('should detect queries selecting ng-template as static', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -158,7 +159,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myTmpl', { static: true }) query: any;`); }); - it('should detect queries selecting ng-template as static (BOM)', async() => { + it('should detect queries selecting ng-template as static (BOM)', async () => { writeFile('/index.ts', `\uFEFF import {Component, NgModule, ViewChild} from '@angular/core'; @@ -181,8 +182,9 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myTmpl', { static: true }) query: any;`); }); - it('should detect queries selecting component view providers through string token', async() => { - writeFile('/index.ts', ` + it('should detect queries selecting component view providers through string token', + async () => { + writeFile('/index.ts', ` import {Component, Directive, NgModule, ViewChild} from '@angular/core'; @Directive({ @@ -211,22 +213,22 @@ describe('static-queries migration with template strategy', () => { export class MyModule {} `); - writeFile(`/my-tmpl.html`, ` + writeFile(`/my-tmpl.html`, ` <span myDirective></span> <ng-template> <span myDirective2></span> </ng-template> `); - await runMigration(); + await runMigration(); - expect(tree.readContent('/index.ts')) - .toContain(`@ViewChild('my-token', { static: true }) query: any;`); - expect(tree.readContent('/index.ts')) - .toContain(`@ViewChild('my-token-2', { static: false }) query2: any;`); - }); + expect(tree.readContent('/index.ts')) + .toContain(`@ViewChild('my-token', { static: true }) query: any;`); + expect(tree.readContent('/index.ts')) + .toContain(`@ViewChild('my-token-2', { static: false }) query2: any;`); + }); - it('should detect queries selecting component view providers using class token', async() => { + it('should detect queries selecting component view providers using class token', async () => { writeFile('/index.ts', ` import {Component, Directive, NgModule, ViewChild} from '@angular/core'; @@ -270,7 +272,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild(MyService2, { static: false }) query2: any;`); }); - it('should detect queries selecting component', async() => { + it('should detect queries selecting component', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; import {HomeComponent, HomeComponent2} from './home-comp'; @@ -316,7 +318,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild(HomeComponent2, { static: false }) query2: any;`); }); - it('should detect queries selecting third-party component', async() => { + it('should detect queries selecting third-party component', async () => { writeFakeLibrary(); writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -341,9 +343,10 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild(MyLibComponent, { static: true }) query: any;`); }); - it('should detect queries selecting third-party component with multiple selectors', async() => { - writeFakeLibrary('a-selector, test-selector'); - writeFile('/index.ts', ` + it('should detect queries selecting third-party component with multiple selectors', + async () => { + writeFakeLibrary('a-selector, test-selector'); + writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; import {MyLibComponent} from 'my-lib'; @@ -356,20 +359,20 @@ describe('static-queries migration with template strategy', () => { export class MyModule {} `); - writeFile('/my-tmpl.html', ` + writeFile('/my-tmpl.html', ` <a-selector>Match 1</a-selector> <ng-template> <test-selector>Match 2</test-selector> </ng-template> `); - await runMigration(); + await runMigration(); - expect(tree.readContent('/index.ts')) - .toContain(`@ViewChild(MyLibComponent, { static: false }) query: any;`); - }); + expect(tree.readContent('/index.ts')) + .toContain(`@ViewChild(MyLibComponent, { static: false }) query: any;`); + }); - it('should detect queries within structural directive', async() => { + it('should detect queries within structural directive', async () => { writeFile('/index.ts', ` import {Component, Directive, NgModule, ViewChild} from '@angular/core'; @@ -399,7 +402,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myRef2', { static: false }) query2: any;`); }); - it('should detect inherited queries', async() => { + it('should detect inherited queries', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -424,7 +427,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myRef', { static: true }) query: any;`); }); - it('should detect queries declared on setter', async() => { + it('should detect queries declared on setter', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -448,7 +451,7 @@ describe('static-queries migration with template strategy', () => { .toMatch(/@ViewChild\('myRef', { static: true }\)\s+set query/); }); - it('should detect queries declared on getter', async() => { + it('should detect queries declared on getter', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -473,7 +476,7 @@ describe('static-queries migration with template strategy', () => { .toMatch(/@ViewChild\('myRef', { static: true }\)\s+get query/); }); - it('should add a todo if a query is not declared in any component', async() => { + it('should add a todo if a query is not declared in any component', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild, SomeToken} from '@angular/core'; @@ -493,7 +496,7 @@ describe('static-queries migration with template strategy', () => { /^⮑ {3}index.ts@5:11:.+could not be determined.+not declared in any component/); }); - it('should add a todo if a query is used multiple times with different timing', async() => { + it('should add a todo if a query is used multiple times with different timing', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -523,7 +526,7 @@ describe('static-queries migration with template strategy', () => { it('should be able to migrate an application with type checking failure which ' + 'does not affect analysis', - async() => { + async () => { // Fakes the `@angular/package` by creating a `ViewChild` decorator // function that requires developers to specify the "static" flag. writeFile('/node_modules/@angular/core/index.d.ts', ` @@ -565,7 +568,7 @@ describe('static-queries migration with template strategy', () => { it('should be able to migrate applications with template type checking failure ' + 'which does not affect analysis', - async() => { + async () => { writeFile('/index.ts', ` import {NgModule, Component, ViewChild} from '@angular/core'; @@ -596,7 +599,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myRef', { static: true }) query: any;`); }); - it('should notify user if project has syntax errors which can affect analysis', async() => { + it('should notify user if project has syntax errors which can affect analysis', async () => { writeFile('/index.ts', ` import {Component, ViewChild} from '@angular/core'; @@ -630,7 +633,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('myRef', { static: true }) query: any;`); }); - it('should gracefully exit migration if queries could not be analyzed', async() => { + it('should gracefully exit migration if queries could not be analyzed', async () => { writeFile('/index.ts', ` import {Component, ViewChild} from '@angular/core'; @@ -650,7 +653,7 @@ describe('static-queries migration with template strategy', () => { expect(errorOutput[0]).toMatch(/Cannot determine the module for class MyComp/); }); - it('should gracefully exit migration if AOT compiler throws exception', async() => { + it('should gracefully exit migration if AOT compiler throws exception', async () => { writeFile('/my-component.ts', ` import {Component, ViewChild} from '@angular/core'; @@ -691,7 +694,7 @@ describe('static-queries migration with template strategy', () => { expect(errorOutput[0]).toMatch(/^TypeError: Cannot read property 'module' of undefined/); }); - it('should add a todo for content queries which are not detectable', async() => { + it('should add a todo for content queries which are not detectable', async () => { writeFile('/index.ts', ` import {Component, NgModule, ContentChild} from '@angular/core'; @@ -713,7 +716,7 @@ describe('static-queries migration with template strategy', () => { .toMatch(/^⮑ {3}index.ts@6:11: Content queries cannot be migrated automatically\./); }); - it('should add a todo if query options cannot be migrated inline', async() => { + it('should add a todo if query options cannot be migrated inline', async () => { writeFile('/index.ts', ` import {Component, NgModule, ViewChild} from '@angular/core'; @@ -738,7 +741,7 @@ describe('static-queries migration with template strategy', () => { expect(warnOutput[0]).toMatch(/Please manually set the query timing to.*static: true/); }); - it('should not normalize stylesheets which are referenced in component', async() => { + it('should not normalize stylesheets which are referenced in component', async () => { writeFile('sub_dir/index.ts', ` import {Component, NgModule, ContentChild} from '@angular/core'; @@ -765,7 +768,7 @@ describe('static-queries migration with template strategy', () => { expect(console.error).toHaveBeenCalledTimes(0); }); - it('should always use the test migration strategy for test tsconfig files', async() => { + it('should always use the test migration strategy for test tsconfig files', async () => { writeFile('/src/tsconfig.spec.json', JSON.stringify({ compilerOptions: { experimentalDecorators: true, @@ -812,7 +815,7 @@ describe('static-queries migration with template strategy', () => { .toContain(`@ViewChild('test', { static: true }) query: any;`); }); - it('should not fall back to test strategy if selected strategy fails', async() => { + it('should not fall back to test strategy if selected strategy fails', async () => { writeFile('/src/tsconfig.spec.json', JSON.stringify({ compilerOptions: { experimentalDecorators: true, diff --git a/packages/core/schematics/test/static_queries_migration_usage_spec.ts b/packages/core/schematics/test/static_queries_migration_usage_spec.ts index 1ec96166486e7..e5738dea4c91d 100644 --- a/packages/core/schematics/test/static_queries_migration_usage_spec.ts +++ b/packages/core/schematics/test/static_queries_migration_usage_spec.ts @@ -63,7 +63,7 @@ describe('static-queries migration with usage strategy', () => { describe('ViewChild', () => { createQueryTests('ViewChild'); - it('should mark view queries used in "ngAfterContentInit" as static', async() => { + it('should mark view queries used in "ngAfterContentInit" as static', async () => { writeFile('/index.ts', ` import {Component, ViewChild} from '@angular/core'; @@ -83,7 +83,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@ViewChild('test', { static: true }) query: any;`); }); - it('should mark view queries used in "ngAfterContentChecked" as static', async() => { + it('should mark view queries used in "ngAfterContentChecked" as static', async () => { writeFile('/index.ts', ` import {Component, ViewChild} from '@angular/core'; @@ -107,7 +107,7 @@ describe('static-queries migration with usage strategy', () => { describe('ContentChild', () => { createQueryTests('ContentChild'); - it('should not mark content queries used in "ngAfterContentInit" as static', async() => { + it('should not mark content queries used in "ngAfterContentInit" as static', async () => { writeFile('/index.ts', ` import {Component, ContentChild} from '@angular/core'; @@ -127,7 +127,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@ContentChild('test', { static: false }) query: any;`); }); - it('should not mark content queries used in "ngAfterContentInit" as static (BOM)', async() => { + it('should not mark content queries used in "ngAfterContentInit" as static (BOM)', async () => { writeFile('/index.ts', `\uFEFF import {Component, ContentChild} from '@angular/core'; @@ -147,7 +147,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@ContentChild('test', { static: false }) query: any;`); }); - it('should not mark content queries used in "ngAfterContentChecked" as static', async() => { + it('should not mark content queries used in "ngAfterContentChecked" as static', async () => { writeFile('/index.ts', ` import {Component, ContentChild} from '@angular/core'; @@ -176,8 +176,8 @@ describe('static-queries migration with usage strategy', () => { return runner.runSchematicAsync('migration-v8-static-queries', {}, tree).toPromise(); } - function createQueryTests(queryType: 'ViewChild' | 'ContentChild') { - it('should mark queries as dynamic', async() => { + function createQueryTests(queryType: 'ViewChild'|'ContentChild') { + it('should mark queries as dynamic', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -200,7 +200,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('dynamic', { static: false }) dynamic: any`); }); - it('should mark queries used in "ngOnChanges" as static', async() => { + it('should mark queries used in "ngOnChanges" as static', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -220,7 +220,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should mark queries used in "ngOnInit" as static', async() => { + it('should mark queries used in "ngOnInit" as static', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -240,7 +240,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should mark queries used in "ngDoCheck" as static', async() => { + it('should mark queries used in "ngDoCheck" as static', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -260,7 +260,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should keep existing query options when updating timing', async() => { + it('should keep existing query options when updating timing', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -280,7 +280,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { /* test */ read: null, static: true }) query: any;`); }); - it('should add a todo for queries declared on setter', async() => { + it('should add a todo for queries declared on setter', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -300,7 +300,7 @@ describe('static-queries migration with usage strategy', () => { .toMatch(/index.ts@6:11: Queries defined on accessors cannot be analyzed.$/); }); - it('should add a todo for queries declared on getter', async() => { + it('should add a todo for queries declared on getter', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -321,7 +321,7 @@ describe('static-queries migration with usage strategy', () => { .toMatch(/index.ts@6:11: Queries defined on accessors cannot be analyzed.$/); }); - it('should not overwrite existing explicit query timing', async() => { + it('should not overwrite existing explicit query timing', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -337,7 +337,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', {static: /* untouched */ someVal}) query: any;`); }); - it('should detect queries used in deep method chain', async() => { + it('should detect queries used in deep method chain', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -372,7 +372,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should properly exit if recursive function is analyzed', async() => { + it('should properly exit if recursive function is analyzed', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -396,7 +396,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query: any;`); }); - it('should detect queries used in newly instantiated classes', async() => { + it('should detect queries used in newly instantiated classes', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -435,7 +435,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query2: any;`); }); - it('should detect queries used in parenthesized new expressions', async() => { + it('should detect queries used in parenthesized new expressions', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -461,7 +461,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect queries in lifecycle hook with string literal name', async() => { + it('should detect queries in lifecycle hook with string literal name', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -481,7 +481,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect static queries within nested inheritance', async() => { + it('should detect static queries within nested inheritance', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -506,7 +506,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect static queries used within input setters', async() => { + it('should detect static queries used within input setters', async () => { writeFile('/index.ts', ` import {Component, Input, ${queryType}} from '@angular/core'; @@ -528,7 +528,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect inputs defined in metadata', async() => { + it('should detect inputs defined in metadata', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -554,7 +554,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect aliased inputs declared in metadata', async() => { + it('should detect aliased inputs declared in metadata', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -577,7 +577,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should not mark query as static if query is used in non-input setter', async() => { + it('should not mark query as static if query is used in non-input setter', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -597,7 +597,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query: any;`); }); - it('should detect input decorator on setter', async() => { + it('should detect input decorator on setter', async () => { writeFile('/index.ts', ` import {Input, Component, ${queryType}} from '@angular/core'; @@ -622,7 +622,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect setter inputs in derived classes', async() => { + it('should detect setter inputs in derived classes', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -647,7 +647,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should properly detect static query in external derived class', async() => { + it('should properly detect static query in external derived class', async () => { writeFile('/src/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -680,7 +680,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should not mark queries used in promises as static', async() => { + it('should not mark queries used in promises as static', async () => { writeFile('/es2015.dom.d.ts', ` interface PromiseConstructor { resolve(): Promise; @@ -735,7 +735,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query2: any;`); }); - it('should handle function callbacks which statically access queries', async() => { + it('should handle function callbacks which statically access queries', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -764,7 +764,7 @@ describe('static-queries migration with usage strategy', () => { }); it('should handle class instantiations with specified callbacks that access queries', - async() => { + async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; import {External} from './external'; @@ -794,7 +794,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should handle nested functions with arguments from parent closure', async() => { + it('should handle nested functions with arguments from parent closure', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -823,7 +823,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should not mark queries used in setTimeout as static', async() => { + it('should not mark queries used in setTimeout as static', async () => { writeFile('/lib.dom.d.ts', `declare function setTimeout(cb: Function);`); writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -859,7 +859,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query3: any;`); }); - it('should not mark queries used in "addEventListener" as static', async() => { + it('should not mark queries used in "addEventListener" as static', async () => { writeFile('/lib.dom.d.ts', ` interface HTMLElement { addEventListener(cb: Function); @@ -888,7 +888,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query: any;`); }); - it('should not mark queries used in "requestAnimationFrame" as static', async() => { + it('should not mark queries used in "requestAnimationFrame" as static', async () => { writeFile('/lib.dom.d.ts', `declare function requestAnimationFrame(cb: Function);`); writeFile('/index.ts', ` import {Component, ElementRef, ${queryType}} from '@angular/core'; @@ -913,8 +913,9 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query: any;`); }); - it('should mark queries used in immediately-invoked function expression as static', async() => { - writeFile('/index.ts', ` + it('should mark queries used in immediately-invoked function expression as static', + async () => { + writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @Component({template: '<span #test></span>'}) @@ -934,15 +935,15 @@ describe('static-queries migration with usage strategy', () => { } `); - await runMigration(); + await runMigration(); - expect(tree.readContent('/index.ts')) - .toContain(`@${queryType}('test', { static: true }) query: any;`); - expect(tree.readContent('/index.ts')) - .toContain(`@${queryType}('test', { static: true }) query2: any;`); - }); + expect(tree.readContent('/index.ts')) + .toContain(`@${queryType}('test', { static: true }) query: any;`); + expect(tree.readContent('/index.ts')) + .toContain(`@${queryType}('test', { static: true }) query2: any;`); + }); - it('should detect static queries used in external function-like declaration', async() => { + it('should detect static queries used in external function-like declaration', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; import {externalFn} from './external'; @@ -971,7 +972,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect static queries used through getter property access', async() => { + it('should detect static queries used through getter property access', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -995,7 +996,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect static queries used through external getter access', async() => { + it('should detect static queries used through external getter access', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; import {External} from './external'; @@ -1033,8 +1034,9 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should not mark queries as static if a value is assigned to accessor property', async() => { - writeFile('/index.ts', ` + it('should not mark queries as static if a value is assigned to accessor property', + async () => { + writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @Component({template: '<span #test></span>'}) @@ -1052,13 +1054,13 @@ describe('static-queries migration with usage strategy', () => { } `); - await runMigration(); + await runMigration(); - expect(tree.readContent('/index.ts')) - .toContain(`@${queryType}('test', { static: false }) query: any;`); - }); + expect(tree.readContent('/index.ts')) + .toContain(`@${queryType}('test', { static: false }) query: any;`); + }); - it('should mark queries as static if non-input setter uses query', async() => { + it('should mark queries as static if non-input setter uses query', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1083,7 +1085,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should check setter and getter when using compound assignment', async() => { + it('should check setter and getter when using compound assignment', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1111,7 +1113,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query2: any;`); }); - it('should check getters when using comparison operator in binary expression', async() => { + it('should check getters when using comparison operator in binary expression', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1136,7 +1138,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should check derived abstract class methods', async() => { + it('should check derived abstract class methods', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1172,7 +1174,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect queries accessed through deep abstract class method', async() => { + it('should detect queries accessed through deep abstract class method', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1204,7 +1206,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect queries accessed through abstract property getter', async() => { + it('should detect queries accessed through abstract property getter', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1230,7 +1232,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect queries accessed through abstract property setter', async() => { + it('should detect queries accessed through abstract property setter', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1257,8 +1259,9 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect query usage in abstract class methods accessing inherited query', async() => { - writeFile('/index.ts', ` + it('should detect query usage in abstract class methods accessing inherited query', + async () => { + writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; export abstract class RootBaseClass { @@ -1287,13 +1290,13 @@ describe('static-queries migration with usage strategy', () => { } `); - await runMigration(); + await runMigration(); - expect(tree.readContent('/index.ts')) - .toContain(`@${queryType}('test', { static: true }) query: any;`); - }); + expect(tree.readContent('/index.ts')) + .toContain(`@${queryType}('test', { static: true }) query: any;`); + }); - it('should detect query usage within component template', async() => { + it('should detect query usage within component template', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1314,8 +1317,9 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: true }) query: any;`); }); - it('should detect query usage with nested property read within component template', async() => { - writeFile('/index.ts', ` + it('should detect query usage with nested property read within component template', + async () => { + writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @Component({templateUrl: 'my-template.html'}) @@ -1324,19 +1328,19 @@ describe('static-queries migration with usage strategy', () => { } `); - writeFile(`/my-template.html`, ` + writeFile(`/my-template.html`, ` <foo #test></foo> <comp [dir]="query.someProperty"></comp> `); - await runMigration(); + await runMigration(); - expect(tree.readContent('/index.ts')) - .toContain(`@${queryType}('test', { static: true }) query: any;`); - }); + expect(tree.readContent('/index.ts')) + .toContain(`@${queryType}('test', { static: true }) query: any;`); + }); it('should not mark query as static if template has template reference with same name', - async() => { + async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1360,7 +1364,7 @@ describe('static-queries migration with usage strategy', () => { }); it('should not mark query as static if template has property read with query name but different receiver', - async() => { + async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1385,7 +1389,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) someProp: any;`); }); - it('should ignore queries accessed within <ng-template> element', async() => { + it('should ignore queries accessed within <ng-template> element', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1409,7 +1413,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query: any;`); }); - it('should detect inherited queries used in templates', async() => { + it('should detect inherited queries used in templates', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1433,7 +1437,7 @@ describe('static-queries migration with usage strategy', () => { }); it('should mark queries which could be accessed statically within third-party calls as ambiguous', - async() => { + async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; import {thirdPartySync} from 'my-lib'; @@ -1458,18 +1462,18 @@ describe('static-queries migration with usage strategy', () => { await runMigration(); expect(tree.readContent('/index.ts')) - .toContain( - `@${queryType}('test', /* TODO: check static flag */ { static: true }) query: any;`); + .toContain(`@${ + queryType}('test', /* TODO: check static flag */ { static: true }) query: any;`); expect(tree.readContent('/index.ts')) - .toContain( - `@${queryType}('test', /* TODO: check static flag */ { static: true }) query2: any;`); + .toContain(`@${ + queryType}('test', /* TODO: check static flag */ { static: true }) query2: any;`); expect(warnOutput.length).toBe(2); expect(warnOutput[0]).toContain('Query timing is ambiguous.'); expect(warnOutput[1]).toContain('Query timing is ambiguous.'); }); it('should mark queries which could be accessed statically within third-party new expressions as ambiguous', - async() => { + async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; import {ThirdParty} from 'my-lib'; @@ -1493,15 +1497,15 @@ describe('static-queries migration with usage strategy', () => { await runMigration(); expect(tree.readContent('/index.ts')) - .toContain( - `@${queryType}('test', /* TODO: check static flag */ { static: true }) query: any;`); + .toContain(`@${ + queryType}('test', /* TODO: check static flag */ { static: true }) query: any;`); expect(warnOutput.length).toBe(1); expect(warnOutput[0]) .toContain( 'Query timing is ambiguous. Please check if the query can be marked as dynamic'); }); - it('should properly handle multiple tsconfig files', async() => { + it('should properly handle multiple tsconfig files', async () => { writeFile('/src/index.ts', ` import {Component, ${queryType}} from '@angular/core'; @@ -1526,7 +1530,7 @@ describe('static-queries migration with usage strategy', () => { .toContain(`@${queryType}('test', { static: false }) query: any;`); }); - it('should support function call with default parameter value', async() => { + it('should support function call with default parameter value', async () => { writeFile('/index.ts', ` import {Component, ${queryType}} from '@angular/core'; diff --git a/packages/core/schematics/test/template_var_assignment_migration_spec.ts b/packages/core/schematics/test/template_var_assignment_migration_spec.ts index a7d0f30e86c38..54a97867e384b 100644 --- a/packages/core/schematics/test/template_var_assignment_migration_spec.ts +++ b/packages/core/schematics/test/template_var_assignment_migration_spec.ts @@ -62,7 +62,7 @@ describe('template variable assignment migration', () => { return runner.runSchematicAsync('migration-v8-template-local-variables', {}, tree).toPromise(); } - it('should warn for two-way data binding variable assignment', async() => { + it('should warn for two-way data binding variable assignment', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -78,7 +78,7 @@ describe('template variable assignment migration', () => { expect(warnOutput[0]).toMatch(/^⮑ {3}index.ts@5:69: Found assignment/); }); - it('should warn for two-way data binding assigning to "as" variable', async() => { + it('should warn for two-way data binding assigning to "as" variable', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -100,7 +100,7 @@ describe('template variable assignment migration', () => { expect(warnOutput).toMatch(/^⮑ {3}tmpl.html@3:31: Found assignment/); }); - it('should warn for bound event assignments to "as" variable', async() => { + it('should warn for bound event assignments to "as" variable', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -124,7 +124,7 @@ describe('template variable assignment migration', () => { expect(warnOutput[1]).toMatch(/^⮑ {3}sub_dir\/tmpl.html@4:25: Found assignment/); }); - it('should warn for bound event assignments to template "let" variables', async() => { + it('should warn for bound event assignments to template "let" variables', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -148,7 +148,7 @@ describe('template variable assignment migration', () => { expect(warnOutput[1]).toMatch(/^⮑ {3}sub_dir\/tmpl.html@4:25: Found assignment/); }); - it('should not warn for bound event assignments to component property', async() => { + it('should not warn for bound event assignments to component property', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -166,7 +166,7 @@ describe('template variable assignment migration', () => { }); it('should not warn for bound event assignments to template variable object property', - async() => { + async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -186,7 +186,7 @@ describe('template variable assignment migration', () => { }); it('should not warn for property writes with template variable name but different receiver', - async() => { + async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -211,7 +211,7 @@ describe('template variable assignment migration', () => { expect(warnOutput.length).toBe(0); }); - it('should warn for template variable assignments in expression conditional', async() => { + it('should warn for template variable assignments in expression conditional', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -236,7 +236,7 @@ describe('template variable assignment migration', () => { }); it('should not warn for property writes with template variable name but different scope', - async() => { + async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -259,7 +259,7 @@ describe('template variable assignment migration', () => { }); - it('should not throw an error if a detected template fails parsing', async() => { + it('should not throw an error if a detected template fails parsing', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; @@ -276,7 +276,7 @@ describe('template variable assignment migration', () => { expect(warnOutput.length).toBe(0); }); - it('should be able to report multiple templates within the same source file', async() => { + it('should be able to report multiple templates within the same source file', async () => { writeFile('/index.ts', ` import {Component} from '@angular/core'; diff --git a/packages/core/schematics/test/undecorated_classes_with_di_migration_spec.ts b/packages/core/schematics/test/undecorated_classes_with_di_migration_spec.ts index 997dca5b52112..c67771226167e 100644 --- a/packages/core/schematics/test/undecorated_classes_with_di_migration_spec.ts +++ b/packages/core/schematics/test/undecorated_classes_with_di_migration_spec.ts @@ -83,7 +83,7 @@ describe('Undecorated classes with DI migration', () => { `); } - it('should print a failure message base class is declared through type definition', async() => { + it('should print a failure message base class is declared through type definition', async () => { writeFile('/node_modules/my-lib/package.json', JSON.stringify({ version: '0.0.0', main: './index.js', @@ -121,7 +121,7 @@ describe('Undecorated classes with DI migration', () => { 'dependency injection. Please manually fix the following failures'); }); - it('should add @Directive() decorator to extended base class', async() => { + it('should add @Directive() decorator to extended base class', async () => { writeFile('/index.ts', ` import {Component, NgModule, NgZone} from '@angular/core'; @@ -149,8 +149,8 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')).toMatch(/@Directive\(\)\nexport class BaseClass2 {/); }); - it('not decorated base class multiple times if extended multiple times', async() => { - writeFile('/index.ts', dedent ` + it('not decorated base class multiple times if extended multiple times', async () => { + writeFile('/index.ts', dedent` import {Component, NgModule, NgZone} from '@angular/core'; export class BaseClass { @@ -169,7 +169,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Directive() export class BaseClass { @@ -177,7 +177,7 @@ describe('Undecorated classes with DI migration', () => { }`); }); - it('should add @Injectable() decorator to extended base class', async() => { + it('should add @Injectable() decorator to extended base class', async () => { writeFile('/index.ts', ` import {Injectable, NgModule, NgZone} from '@angular/core'; @@ -197,8 +197,8 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')).toMatch(/@Injectable\(\)\nexport class BaseClass {/); }); - it('should not decorate base class for decorated pipe', async() => { - writeFile('/index.ts', dedent ` + it('should not decorate base class for decorated pipe', async () => { + writeFile('/index.ts', dedent` import {Component, NgModule, Pipe, PipeTransform} from '@angular/core'; @Pipe({name: 'test'}) @@ -213,13 +213,13 @@ describe('Undecorated classes with DI migration', () => { expect(errorOutput.length).toBe(0); expect(warnOutput.length).toBe(0); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Pipe({name: 'test'}) export class MyPipe extends PipeTransform {}`); }); - it('should not decorate base class if no constructor is inherited', async() => { - writeFile('/index.ts', dedent ` + it('should not decorate base class if no constructor is inherited', async () => { + writeFile('/index.ts', dedent` import {Component, NgModule, Directive} from '@angular/core'; export class BaseClassWithoutCtor { @@ -238,7 +238,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` export class BaseClassWithoutCtor { someUnrelatedProp = true; @@ -252,8 +252,8 @@ describe('Undecorated classes with DI migration', () => { }); it('should not decorate base class if directive/component/provider defines a constructor', - async() => { - writeFile('/index.ts', dedent ` + async () => { + writeFile('/index.ts', dedent` import {Component, Injectable, NgModule, NgZone} from '@angular/core'; export class BaseClass { @@ -284,15 +284,15 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` export class BaseClass { constructor(zone: NgZone) {} }`); }); - it('should not decorate base class if it already has decorator', async() => { - writeFile('/index.ts', dedent ` + it('should not decorate base class if it already has decorator', async () => { + writeFile('/index.ts', dedent` import {Component, Directive, NgModule, NgZone} from '@angular/core'; @Directive({selector: 'base-class'}) @@ -312,13 +312,13 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Directive({selector: 'base-class'}) export class BaseClass {`); }); - it('should add a comment if the base class is declared through type definition', async() => { + it('should add a comment if the base class is declared through type definition', async () => { writeFile('/node_modules/my-lib/package.json', JSON.stringify({ version: '0.0.0', main: './index.js', @@ -332,7 +332,7 @@ describe('Undecorated classes with DI migration', () => { } `); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {Component, Injectable, NgModule} from '@angular/core'; import {SuperBaseClass} from 'my-lib'; @@ -365,42 +365,42 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Directive() export class BaseClass extends SuperBaseClass { // TODO: add explicit constructor }`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Injectable() export class BaseClass2 extends SuperBaseClass { // TODO: add explicit constructor }`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Directive() export class PassThroughClass extends BaseClass {}`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({template: ''}) export class MyComponent extends PassThroughClass {}`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({template: ''}) export class MyComponent3 extends SuperBaseClass { // TODO: add explicit constructor }`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Injectable() export class MyService extends BaseClass2 {}`); }); it('should not add a comment if the base class is declared through type definition but is' + 'decorated', - async() => { + async () => { writeFakeLibrary(); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {Component, NgModule} from '@angular/core'; import {BaseComponent} from 'my-lib'; @@ -413,14 +413,14 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({template: ''}) export class MyComponent extends BaseComponent {}`); }); - it('should not decorate base class in typings if it misses an explicit constructor', async() => { + it('should not decorate base class in typings if it misses an explicit constructor', async () => { writeFakeLibrary(); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {Component, NgModule} from '@angular/core'; import {BaseDirective} from 'my-lib'; @@ -433,16 +433,16 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({template: ''}) export class MyComponent extends BaseDirective {}`); expect(tree.readContent('/node_modules/my-lib/public-api.d.ts')).not.toContain('@Directive'); }); - it('should detect decorated classes by respecting summary files', async() => { + it('should detect decorated classes by respecting summary files', async () => { writeSummaryOnlyThirdPartyLibrary(); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {Component, NgModule} from '@angular/core'; import {BaseComponent} from 'my-lib'; @@ -457,12 +457,12 @@ describe('Undecorated classes with DI migration', () => { expect(warnOutput.length).toBe(0); expect(errorOutput.length).toBe(0); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({template: ''}) export class MyComponent extends BaseComponent {}`); }); - it('should decorate all undecorated directives of inheritance chain', async() => { + it('should decorate all undecorated directives of inheritance chain', async () => { writeFile('/index.ts', ` import {Component, NgModule, NgZone} from '@angular/core'; @@ -486,7 +486,7 @@ describe('Undecorated classes with DI migration', () => { .toMatch(/}\s+@Directive\(\)\nexport class BaseClass extends SuperBaseClass {/); }); - it('should decorate all undecorated providers of inheritance chain', async() => { + it('should decorate all undecorated providers of inheritance chain', async () => { writeFile('/index.ts', ` import {Injectable, NgModule, NgZone} from '@angular/core'; @@ -511,7 +511,7 @@ describe('Undecorated classes with DI migration', () => { }); it('should properly update import if @Directive can be accessed through existing namespace import', - async() => { + async () => { writeFile('/index.ts', ` import {Component, NgModule, NgZone} from '@angular/core'; import {BaseClass} from './base'; @@ -537,7 +537,7 @@ describe('Undecorated classes with DI migration', () => { }); it('should properly update existing import with aliased specifier if identifier is already used', - async() => { + async () => { writeFile('/index.ts', ` import {Component, NgModule, NgZone} from '@angular/core'; import {Directive} from './third_party_directive'; @@ -561,7 +561,7 @@ describe('Undecorated classes with DI migration', () => { }); it('should properly create new import with aliased specifier if identifier is already used', - async() => { + async () => { writeFile('/index.ts', ` import {Component, NgModule, NgZone} from '@angular/core'; import {BaseClass} from './base'; @@ -590,8 +590,9 @@ describe('Undecorated classes with DI migration', () => { .toContain(`{ Directive as Directive_1 } from "@angular/core";`); }); - it('should use existing aliased import of @Directive instead of creating new import', async() => { - writeFile('/index.ts', ` + it('should use existing aliased import of @Directive instead of creating new import', + async () => { + writeFile('/index.ts', ` import {Component, NgModule} from '@angular/core'; import {BaseClass} from './base'; @@ -602,7 +603,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/base.ts', ` + writeFile('/base.ts', ` import {Directive as AliasedDir, NgZone} from '@angular/core'; export class BaseClass { @@ -610,15 +611,14 @@ describe('Undecorated classes with DI migration', () => { } `); - await runMigration(); - - expect(tree.readContent('/base.ts')).toMatch(/@AliasedDir\(\)\nexport class BaseClass {/); - }); + await runMigration(); - describe('decorator copying', async() => { + expect(tree.readContent('/base.ts')).toMatch(/@AliasedDir\(\)\nexport class BaseClass {/); + }); - it('should be able to copy the "templateUrl" field', async() => { - writeFile('/index.ts', dedent ` + describe('decorator copying', async () => { + it('should be able to copy the "templateUrl" field', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -628,7 +628,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Directive, NgModule} from '@angular/core'; @Directive({ @@ -645,7 +645,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain(`import { NgModule, Directive } from '@angular/core';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Directive({ selector: 'my-dir', templateUrl: './my-dir.html' @@ -653,8 +653,8 @@ describe('Undecorated classes with DI migration', () => { export class MyDir extends BaseClass {}`); }); - it('should be able to copy the "styleUrls" field', async() => { - writeFile('/index.ts', dedent ` + it('should be able to copy the "styleUrls" field', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -664,7 +664,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Directive, NgModule} from '@angular/core'; /** my comment */ @@ -680,7 +680,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` import {BaseClass} from './lib/base'; @Directive({ @@ -690,8 +690,8 @@ describe('Undecorated classes with DI migration', () => { export class MyDir extends BaseClass {}`); }); - it('should be able to copy @Pipe decorator', async() => { - writeFile('/index.ts', dedent ` + it('should be able to copy @Pipe decorator', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BasePipe} from './lib/base'; @@ -701,7 +701,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Pipe, NgModule} from '@angular/core'; @Pipe({name: 'my-pipe-name'}) @@ -715,16 +715,16 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain(`import { NgModule, Pipe } from '@angular/core';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Pipe({ name: 'my-pipe-name' }) export class MyPipe extends BasePipe {}`); }); - it('should be able to copy decorator in same source file', async() => { + it('should be able to copy decorator in same source file', async () => { writeFile( '/node_modules/@angular/cdk/table/index.d.ts', `export declare const CDK_TABLE_TEMPLATE = '';`); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {NgModule, Component} from '@angular/core'; import {CDK_TABLE_TEMPLATE} from '@angular/cdk/table'; @@ -748,7 +748,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ selector: 'my-dir', template: CDK_TABLE_TEMPLATE, @@ -757,8 +757,8 @@ describe('Undecorated classes with DI migration', () => { export class MyDir extends BaseClass {}`); }); - it('should be able to create new imports for copied identifier references', async() => { - writeFile('/index.ts', dedent ` + it('should be able to create new imports for copied identifier references', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -772,7 +772,7 @@ describe('Undecorated classes with DI migration', () => { '/node_modules/@angular/cdk/table/index.d.ts', `export declare const CDK_TABLE_TEMPLATE = '';`); writeFile('/styles.ts', `export const STYLE_THROUGH_VAR = 'external';`); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Component, NgModule} from '@angular/core'; import {CDK_TABLE_TEMPLATE as tableTmpl} from '@angular/cdk/table'; import {STYLE_THROUGH_VAR} from '../styles'; @@ -798,7 +798,7 @@ describe('Undecorated classes with DI migration', () => { .toContain(`import { STYLE_THROUGH_VAR } from "./styles";`); expect(tree.readContent('/index.ts')) .toContain(`import { BaseClass, LOCAL_STYLE } from './lib/base';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ selector: 'my-dir', template: CDK_TABLE_TEMPLATE, @@ -807,8 +807,8 @@ describe('Undecorated classes with DI migration', () => { export class MyDir extends BaseClass {}`); }); - it('should copy decorator once if directive is referenced multiple times', async() => { - writeFile('/index.ts', dedent ` + it('should copy decorator once if directive is referenced multiple times', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -818,7 +818,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/second-module.ts', dedent ` + writeFile('/second-module.ts', dedent` import {NgModule, Directive} from '@angular/core'; import {MyComp} from './index'; @@ -829,7 +829,7 @@ describe('Undecorated classes with DI migration', () => { export class MySecondModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Component, NgModule} from '@angular/core'; @Component({ @@ -844,7 +844,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` import {BaseClass} from './lib/base'; @Component({ @@ -854,8 +854,8 @@ describe('Undecorated classes with DI migration', () => { export class MyComp extends BaseClass {}`); }); - it('should create aliased imports to avoid collisions for referenced identifiers', async() => { - writeFile('/index.ts', dedent ` + it('should create aliased imports to avoid collisions for referenced identifiers', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -869,7 +869,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Component, NgModule} from '@angular/core'; export const MY_TEMPLATE = ''; @@ -888,7 +888,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain(`import { BaseClass, MY_TEMPLATE as MY_TEMPLATE_1 } from './lib/base';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ selector: 'my-dir', template: MY_TEMPLATE_1 @@ -896,8 +896,8 @@ describe('Undecorated classes with DI migration', () => { export class MyComp extends BaseClass {}`); }); - it('should add comment for metadata fields which cannot be copied', async() => { - writeFile('/index.ts', dedent ` + it('should add comment for metadata fields which cannot be copied', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -907,7 +907,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Component, NgModule, Document} from '@angular/core'; // this variable cannot be imported automatically. @@ -926,7 +926,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ selector: 'my-dir', template: '', @@ -940,8 +940,8 @@ describe('Undecorated classes with DI migration', () => { }); it('should add comment for metadata fields which are added through spread operator', - async() => { - writeFile('/index.ts', dedent ` + async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -951,7 +951,7 @@ describe('Undecorated classes with DI migration', () => { export class MyModule {} `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Component, NgModule} from '@angular/core'; export const metadataThroughVar = { @@ -971,7 +971,7 @@ describe('Undecorated classes with DI migration', () => { await runMigration(); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ selector: 'my-dir', template: '', @@ -984,10 +984,10 @@ describe('Undecorated classes with DI migration', () => { export class MyComp extends BaseClass {}`); }); - it('should be able to copy fields specified through shorthand assignment', async() => { + it('should be able to copy fields specified through shorthand assignment', async () => { writeFile('/hello.css', ''); writeFile('/my-tmpl.html', ''); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -999,7 +999,7 @@ describe('Undecorated classes with DI migration', () => { writeFile('/lib/hello.css', ''); writeFile('/lib/my-tmpl.html', ''); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Component, NgModule} from '@angular/core'; export const host = {}; @@ -1022,7 +1022,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain(`import { BaseClass, templateUrl, host } from './lib/base';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ selector: 'my-dir', templateUrl, @@ -1036,10 +1036,10 @@ describe('Undecorated classes with DI migration', () => { export class MyComp extends BaseClass {}`); }); - it('should serialize metadata from base class without source code', async() => { + it('should serialize metadata from base class without source code', async () => { writeFakeLibrary(); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseComponent, BasePipe} from 'my-lib'; @@ -1061,7 +1061,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain( `import { NgModule, ChangeDetectionStrategy, ViewEncapsulation, NG_VALIDATORS, Component, Pipe } from '@angular/core';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ changeDetection: ChangeDetectionStrategy.Default, selector: "comp-selector", @@ -1077,7 +1077,7 @@ describe('Undecorated classes with DI migration', () => { } }) export class PassThrough extends BaseComponent {}`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ changeDetection: ChangeDetectionStrategy.Default, selector: "comp-selector", @@ -1093,7 +1093,7 @@ describe('Undecorated classes with DI migration', () => { } }) export class MyComp extends PassThrough {}`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Pipe({ pure: true, name: "external-pipe-name" @@ -1101,12 +1101,12 @@ describe('Undecorated classes with DI migration', () => { export class MyPipe extends BasePipe {}`); }); - it('should serialize metadata with external references from class without source code', async() => { + it('should serialize metadata with external references from class without source code', async () => { writeFakeLibrary({useImportedTemplate: true}); writeFile( '/node_modules/@angular/cdk/table/index.d.ts', `export declare const CDK_TABLE_TEMPLATE = 'Template of CDK Table.';`); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseComponent} from 'my-lib'; @@ -1121,7 +1121,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain( `import { NgModule, ChangeDetectionStrategy, ViewEncapsulation, NG_VALIDATORS, Component } from '@angular/core';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Component({ changeDetection: ChangeDetectionStrategy.Default, selector: "comp-selector", @@ -1140,10 +1140,10 @@ describe('Undecorated classes with DI migration', () => { }); it('should not throw if metadata from base class without source code is not serializable', - async() => { + async () => { writeFakeLibrary({insertInvalidReference: true}); - writeFile('/index.ts', dedent ` + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseComponent} from 'my-lib'; @@ -1159,8 +1159,8 @@ describe('Undecorated classes with DI migration', () => { expect(errorOutput[0]).toMatch(/Could not resolve non-existent/); }); - it('should not create imports for identifiers resolving to target source file', async() => { - writeFile('/index.ts', dedent ` + it('should not create imports for identifiers resolving to target source file', async () => { + writeFile('/index.ts', dedent` import {NgModule} from '@angular/core'; import {BaseClass} from './lib/base'; @@ -1175,7 +1175,7 @@ describe('Undecorated classes with DI migration', () => { export {LOCAL_NAME as PUBLIC_NAME}; `); - writeFile('/lib/base.ts', dedent ` + writeFile('/lib/base.ts', dedent` import {Directive, NgModule} from '@angular/core'; import {SHARED_TEMPLATE_URL, PUBLIC_NAME} from '..'; @@ -1194,7 +1194,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/index.ts')) .toContain(`import { NgModule, Directive } from '@angular/core';`); - expect(tree.readContent('/index.ts')).toContain(dedent ` + expect(tree.readContent('/index.ts')).toContain(dedent` @Directive({ selector: 'my-dir', template: SHARED_TEMPLATE_URL, @@ -1388,7 +1388,7 @@ describe('Undecorated classes with DI migration', () => { })); } - it('should not run for test tsconfig files', async() => { + it('should not run for test tsconfig files', async () => { writeFile('/src/tsconfig.spec.json', JSON.stringify({ compilerOptions: { lib: ['es2015'], @@ -1429,8 +1429,8 @@ describe('Undecorated classes with DI migration', () => { expect(errorOutput.length).toBe(0); }); - describe('diagnostics', async() => { - it('should gracefully exit migration if project fails with structural diagnostic', async() => { + describe('diagnostics', async () => { + it('should gracefully exit migration if project fails with structural diagnostic', async () => { writeFile('/index.ts', ` import {Component, NgModule} from '@angular/core'; @@ -1455,28 +1455,29 @@ describe('Undecorated classes with DI migration', () => { 'TypeScript program failures'); }); - it('should gracefully exit migration if project fails with syntactical diagnostic', async() => { - writeFile('/index.ts', ` + it('should gracefully exit migration if project fails with syntactical diagnostic', + async () => { + writeFile('/index.ts', ` import {Component, NgModule} /* missing "from" */ '@angular/core'; `); - await runMigration(); + await runMigration(); - expect(warnOutput.length).toBe(1); - expect(warnOutput[0]) - .toMatch(/project "tsconfig.json" has syntactical errors which could cause/); - expect(errorOutput.length).toBe(1); - expect(errorOutput[0]).toMatch(/error TS1005: 'from' expected/); - expect(infoOutput.join(' ')) - .toContain( - 'Some project targets could not be analyzed due to ' + - 'TypeScript program failures'); - }); + expect(warnOutput.length).toBe(1); + expect(warnOutput[0]) + .toMatch(/project "tsconfig.json" has syntactical errors which could cause/); + expect(errorOutput.length).toBe(1); + expect(errorOutput[0]).toMatch(/error TS1005: 'from' expected/); + expect(infoOutput.join(' ')) + .toContain( + 'Some project targets could not be analyzed due to ' + + 'TypeScript program failures'); + }); // Regression test for: https://github.com/angular/angular/issues/34985. it('should be able to migrate libraries with multiple source files and flat-module ' + 'options set', - async() => { + async () => { writeFile('/tsconfig.json', JSON.stringify({ compilerOptions: { lib: ['es2015'], @@ -1507,7 +1508,7 @@ describe('Undecorated classes with DI migration', () => { expect(tree.readContent('/test.ts')).toMatch(/@Injectable\(\)\nexport class BaseClass {/); }); - it('should not throw if resources could not be read', async() => { + it('should not throw if resources could not be read', async () => { writeFile('/index.ts', ` import {Component, NgModule} from '@angular/core'; @@ -1529,7 +1530,7 @@ describe('Undecorated classes with DI migration', () => { expect(errorOutput.length).toBe(0); }); - it('should not throw if tsconfig references non-existent source file', async() => { + it('should not throw if tsconfig references non-existent source file', async () => { writeFile('/tsconfig.json', JSON.stringify({ compilerOptions: { lib: ['es2015'], diff --git a/packages/core/schematics/utils/import_manager.ts b/packages/core/schematics/utils/import_manager.ts index 12a9b6cbcc33b..07b7f945f9ae1 100644 --- a/packages/core/schematics/utils/import_manager.ts +++ b/packages/core/schematics/utils/import_manager.ts @@ -114,8 +114,8 @@ export class ImportManager { } if (existingImport) { - const propertyIdentifier = ts.createIdentifier(symbolName !); - const generatedUniqueIdentifier = this._getUniqueIdentifier(sourceFile, symbolName !); + const propertyIdentifier = ts.createIdentifier(symbolName!); + const generatedUniqueIdentifier = this._getUniqueIdentifier(sourceFile, symbolName!); const needsGeneratedUniqueName = generatedUniqueIdentifier.text !== symbolName; const importName = needsGeneratedUniqueName ? generatedUniqueIdentifier : propertyIdentifier; @@ -186,7 +186,7 @@ export class ImportManager { this.updatedImports.forEach((expressions, importDecl) => { const sourceFile = importDecl.getSourceFile(); const recorder = this.getUpdateRecorder(sourceFile); - const namedBindings = importDecl.importClause !.namedBindings as ts.NamedImports; + const namedBindings = importDecl.importClause!.namedBindings as ts.NamedImports; const newNamedBindings = ts.updateNamedImports( namedBindings, namedBindings.elements.concat(expressions.map( @@ -211,8 +211,8 @@ export class ImportManager { name = `${baseName}_${counter++}`; } while (!this.isUniqueIdentifierName(sourceFile, name)); - this._recordUsedIdentifier(sourceFile, name !); - return ts.createIdentifier(name !); + this._recordUsedIdentifier(sourceFile, name!); + return ts.createIdentifier(name!); } /** @@ -221,7 +221,7 @@ export class ImportManager { */ private isUniqueIdentifierName(sourceFile: ts.SourceFile, name: string) { if (this.usedIdentifierNames.has(sourceFile) && - this.usedIdentifierNames.get(sourceFile) !.indexOf(name) !== -1) { + this.usedIdentifierNames.get(sourceFile)!.indexOf(name) !== -1) { return false; } @@ -230,7 +230,7 @@ export class ImportManager { // is unique in the given declaration scope and we just return false. const nodeQueue: ts.Node[] = [sourceFile]; while (nodeQueue.length) { - const node = nodeQueue.shift() !; + const node = nodeQueue.shift()!; if (ts.isIdentifier(node) && node.text === name) { return false; } @@ -254,6 +254,6 @@ export class ImportManager { if (!commentRanges || !commentRanges.length) { return nodeEndPos; } - return commentRanges[commentRanges.length - 1] !.end; + return commentRanges[commentRanges.length - 1]!.end; } } diff --git a/packages/core/schematics/utils/ng_component_template.ts b/packages/core/schematics/utils/ng_component_template.ts index 5b20b964cbcf0..01b1dfcb5e69b 100644 --- a/packages/core/schematics/utils/ng_component_template.ts +++ b/packages/core/schematics/utils/ng_component_template.ts @@ -31,7 +31,9 @@ export interface ResolvedTemplate { * If the template is declared inline within a TypeScript source file, the line and * character are based on the full source file content. */ - getCharacterAndLineOfPosition: (pos: number) => { character: number, line: number }; + getCharacterAndLineOfPosition: (pos: number) => { + character: number, line: number + }; } /** @@ -103,8 +105,8 @@ export class NgComponentTemplateVisitor { content: property.initializer.text, inline: true, start: templateStartIdx, - getCharacterAndLineOfPosition: - pos => ts.getLineAndCharacterOfPosition(sourceFile, pos + templateStartIdx) + getCharacterAndLineOfPosition: pos => + ts.getLineAndCharacterOfPosition(sourceFile, pos + templateStartIdx) }); } if (propertyName === 'templateUrl' && ts.isStringLiteralLike(property.initializer)) { diff --git a/packages/core/schematics/utils/ng_decorators.ts b/packages/core/schematics/utils/ng_decorators.ts index 4e2fadea1c6ff..54f53c0b5cc74 100644 --- a/packages/core/schematics/utils/ng_decorators.ts +++ b/packages/core/schematics/utils/ng_decorators.ts @@ -9,7 +9,7 @@ import * as ts from 'typescript'; import {getCallDecoratorImport} from './typescript/decorators'; -export type CallExpressionDecorator = ts.Decorator & { +export type CallExpressionDecorator = ts.Decorator&{ expression: ts.CallExpression; }; @@ -30,8 +30,8 @@ export function getAngularDecorators( .filter(({importData}) => importData && importData.importModule.startsWith('@angular/')) .map(({node, importData}) => ({ node: node as CallExpressionDecorator, - name: importData !.name, - moduleName: importData !.importModule, - importNode: importData !.node + name: importData!.name, + moduleName: importData!.importModule, + importNode: importData!.node })); } diff --git a/packages/core/schematics/utils/project_tsconfig_paths.ts b/packages/core/schematics/utils/project_tsconfig_paths.ts index 6690974fb0dd4..64153a36a5ef0 100644 --- a/packages/core/schematics/utils/project_tsconfig_paths.ts +++ b/packages/core/schematics/utils/project_tsconfig_paths.ts @@ -71,7 +71,7 @@ function getTargetTsconfigPath(project: WorkspaceProject, targetName: string): s */ function getWorkspaceConfigGracefully(tree: Tree): any { const path = defaultWorkspaceConfigPaths.find(filePath => tree.exists(filePath)); - const configBuffer = tree.read(path !); + const configBuffer = tree.read(path!); if (!path || !configBuffer) { return null; diff --git a/packages/core/schematics/utils/schematics_prompt.ts b/packages/core/schematics/utils/schematics_prompt.ts index 9fcfc92f489ef..f32d64d7af821 100644 --- a/packages/core/schematics/utils/schematics_prompt.ts +++ b/packages/core/schematics/utils/schematics_prompt.ts @@ -30,5 +30,5 @@ export function supportsPrompt(): boolean { * create prompts. */ export function getInquirer(): Inquirer { - return resolvedInquirerModule !; + return resolvedInquirerModule!; } diff --git a/packages/core/schematics/utils/typescript/decorators.ts b/packages/core/schematics/utils/typescript/decorators.ts index de1df266e892e..7722961300282 100644 --- a/packages/core/schematics/utils/typescript/decorators.ts +++ b/packages/core/schematics/utils/typescript/decorators.ts @@ -7,7 +7,8 @@ */ import * as ts from 'typescript'; -import {Import, getImportOfIdentifier} from './imports'; + +import {getImportOfIdentifier, Import} from './imports'; export function getCallDecoratorImport( typeChecker: ts.TypeChecker, decorator: ts.Decorator): Import|null { diff --git a/packages/core/schematics/utils/typescript/functions.ts b/packages/core/schematics/utils/typescript/functions.ts index b8cd376588795..07c105604ef82 100644 --- a/packages/core/schematics/utils/typescript/functions.ts +++ b/packages/core/schematics/utils/typescript/functions.ts @@ -20,7 +20,7 @@ export function isFunctionLikeDeclaration(node: ts.Node): node is ts.FunctionLik * parentheses or as expression. e.g. "(((({exp}))))()". The function should return the * TypeScript node referring to the inner expression. e.g "exp". */ -export function unwrapExpression(node: ts.Expression | ts.ParenthesizedExpression): ts.Expression { +export function unwrapExpression(node: ts.Expression|ts.ParenthesizedExpression): ts.Expression { if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node)) { return unwrapExpression(node.expression); } else { diff --git a/packages/core/src/application_init.ts b/packages/core/src/application_init.ts index b9852148c1889..69a77c8bc5681 100644 --- a/packages/core/src/application_init.ts +++ b/packages/core/src/application_init.ts @@ -34,9 +34,9 @@ export const APP_INITIALIZER = new InjectionToken<Array<() => void>>('Applicatio @Injectable() export class ApplicationInitStatus { // TODO(issue/24571): remove '!'. - private resolve !: Function; + private resolve!: Function; // TODO(issue/24571): remove '!'. - private reject !: Function; + private reject!: Function; private initialized = false; public readonly donePromise: Promise<any>; public readonly done = false; @@ -57,7 +57,7 @@ export class ApplicationInitStatus { const asyncInitPromises: Promise<any>[] = []; const complete = () => { - (this as{done: boolean}).done = true; + (this as {done: boolean}).done = true; this.resolve(); }; @@ -70,7 +70,13 @@ export class ApplicationInitStatus { } } - Promise.all(asyncInitPromises).then(() => { complete(); }).catch(e => { this.reject(e); }); + Promise.all(asyncInitPromises) + .then(() => { + complete(); + }) + .catch(e => { + this.reject(e); + }); if (asyncInitPromises.length === 0) { complete(); diff --git a/packages/core/src/application_module.ts b/packages/core/src/application_module.ts index f59eb86cd3fdd..de727bc81b798 100644 --- a/packages/core/src/application_module.ts +++ b/packages/core/src/application_module.ts @@ -9,7 +9,7 @@ import {APP_INITIALIZER, ApplicationInitStatus} from './application_init'; import {ApplicationRef} from './application_ref'; import {APP_ID_RANDOM_PROVIDER} from './application_tokens'; -import {IterableDiffers, KeyValueDiffers, defaultIterableDiffers, defaultKeyValueDiffers} from './change_detection/change_detection'; +import {defaultIterableDiffers, defaultKeyValueDiffers, IterableDiffers, KeyValueDiffers} from './change_detection/change_detection'; import {Console} from './console'; import {Injector, StaticProvider} from './di'; import {Inject, Optional, SkipSelf} from './di/metadata'; @@ -78,8 +78,7 @@ export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [ { provide: ApplicationRef, useClass: ApplicationRef, - deps: - [NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus] + deps: [NgZone, Console, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus] }, {provide: SCHEDULER, deps: [NgZone], useFactory: zoneSchedulerFactory}, { @@ -112,10 +111,12 @@ export function zoneSchedulerFactory(ngZone: NgZone): (fn: () => void) => void { let queue: (() => void)[] = []; ngZone.onStable.subscribe(() => { while (queue.length) { - queue.pop() !(); + queue.pop()!(); } }); - return function(fn: () => void) { queue.push(fn); }; + return function(fn: () => void) { + queue.push(fn); + }; } /** diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index 694f5763b3c50..1149dc0ffca45 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -8,7 +8,7 @@ import './util/ng_jit_mode'; -import {Observable, Observer, Subscription, merge} from 'rxjs'; +import {merge, Observable, Observer, Subscription} from 'rxjs'; import {share} from 'rxjs/operators'; import {ApplicationInitStatus} from './application_init'; @@ -80,7 +80,7 @@ export function compileNgModuleFactory__POST_R3__<M>( return Promise.resolve(moduleFactory); } - const compilerProviders = _mergeArrays(compilerOptions.map(o => o.providers !)); + const compilerProviders = _mergeArrays(compilerOptions.map(o => o.providers!)); // In case there are no compiler providers, we just return the module factory as // there won't be any resource loader. This can happen with Ivy, because AOT compiled @@ -157,9 +157,8 @@ export function createPlatform(injector: Injector): PlatformRef { * @publicApi */ export function createPlatformFactory( - parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null, - name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) => - PlatformRef { + parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef)|null, name: string, + providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) => PlatformRef { const desc = `Platform: ${name}`; const marker = new InjectionToken(desc); return (extraProviders: StaticProvider[] = []) => { @@ -320,10 +319,12 @@ export class PlatformRef { throw new Error('No ErrorHandler. Is platform module (BrowserModule) included?'); } moduleRef.onDestroy(() => remove(this._modules, moduleRef)); - ngZone !.runOutsideAngular( - () => ngZone !.onError.subscribe( - {next: (error: any) => { exceptionHandler.handleError(error); }})); - return _callAndReportToErrorHandler(exceptionHandler, ngZone !, () => { + ngZone!.runOutsideAngular(() => ngZone!.onError.subscribe({ + next: (error: any) => { + exceptionHandler.handleError(error); + } + })); + return _callAndReportToErrorHandler(exceptionHandler, ngZone!, () => { const initStatus: ApplicationInitStatus = moduleRef.injector.get(ApplicationInitStatus); initStatus.runInitializers(); return initStatus.donePromise.then(() => { @@ -356,7 +357,8 @@ export class PlatformRef { * */ bootstrapModule<M>( - moduleType: Type<M>, compilerOptions: (CompilerOptions&BootstrapOptions)| + moduleType: Type<M>, + compilerOptions: (CompilerOptions&BootstrapOptions)| Array<CompilerOptions&BootstrapOptions> = []): Promise<NgModuleRef<M>> { const options = optionsReducer({}, compilerOptions); return compileNgModuleFactory(this.injector, options, moduleType) @@ -371,7 +373,10 @@ export class PlatformRef { moduleRef.instance.ngDoBootstrap(appRef); } else { throw new Error( - `The module ${stringify(moduleRef.instance.constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` + + `The module ${ + stringify( + moduleRef.instance + .constructor)} was bootstrapped, but it does not declare "@NgModule.bootstrap" components nor a "ngDoBootstrap" method. ` + `Please define one of these.`); } this._modules.push(moduleRef); @@ -380,13 +385,17 @@ export class PlatformRef { /** * Register a listener to be called when the platform is disposed. */ - onDestroy(callback: () => void): void { this._destroyListeners.push(callback); } + onDestroy(callback: () => void): void { + this._destroyListeners.push(callback); + } /** * Retrieve the platform {@link Injector}, which is the parent injector for * every Angular application on the page and provides singleton providers. */ - get injector(): Injector { return this._injector; } + get injector(): Injector { + return this._injector; + } /** * Destroy the Angular platform and all Angular applications on the page. @@ -400,11 +409,13 @@ export class PlatformRef { this._destroyed = true; } - get destroyed() { return this._destroyed; } + get destroyed() { + return this._destroyed; + } } function getNgZone( - ngZoneOption: NgZone | 'zone.js' | 'noop' | undefined, ngZoneEventCoalescing: boolean): NgZone { + ngZoneOption: NgZone|'zone.js'|'noop'|undefined, ngZoneEventCoalescing: boolean): NgZone { let ngZone: NgZone; if (ngZoneOption === 'noop') { @@ -438,7 +449,7 @@ function _callAndReportToErrorHandler( } } -function optionsReducer<T extends Object>(dst: any, objs: T | T[]): T { +function optionsReducer<T extends Object>(dst: any, objs: T|T[]): T { if (Array.isArray(objs)) { dst = objs.reduce(optionsReducer, dst); } else { @@ -566,7 +577,7 @@ export class ApplicationRef { * @see [Usage notes](#is-stable-examples) for examples and caveats when using this API. */ // TODO(issue/24571): remove '!'. - public readonly isStable !: Observable<boolean>; + public readonly isStable!: Observable<boolean>; /** @internal */ constructor( @@ -576,8 +587,13 @@ export class ApplicationRef { private _initStatus: ApplicationInitStatus) { this._enforceNoNewChanges = isDevMode(); - this._zone.onMicrotaskEmpty.subscribe( - {next: () => { this._zone.run(() => { this.tick(); }); }}); + this._zone.onMicrotaskEmpty.subscribe({ + next: () => { + this._zone.run(() => { + this.tick(); + }); + } + }); const isCurrentlyStable = new Observable<boolean>((observer: Observer<boolean>) => { this._stable = this._zone.isStable && !this._zone.hasPendingMacrotasks && @@ -612,7 +628,9 @@ export class ApplicationRef { NgZone.assertInAngularZone(); if (this._stable) { this._stable = false; - this._zone.runOutsideAngular(() => { observer.next(false); }); + this._zone.runOutsideAngular(() => { + observer.next(false); + }); } }); @@ -622,7 +640,7 @@ export class ApplicationRef { }; }); - (this as{isStable: Observable<boolean>}).isStable = + (this as {isStable: Observable<boolean>}).isStable = merge(isCurrentlyStable, isStable.pipe(share())); } @@ -653,7 +671,7 @@ export class ApplicationRef { componentFactory = componentOrFactory; } else { componentFactory = - this._componentFactoryResolver.resolveComponentFactory(componentOrFactory) !; + this._componentFactoryResolver.resolveComponentFactory(componentOrFactory)!; } this.componentTypes.push(componentFactory.componentType); @@ -663,7 +681,9 @@ export class ApplicationRef { const selectorOrNode = rootSelectorOrNode || componentFactory.selector; const compRef = componentFactory.create(Injector.NULL, [], selectorOrNode, ngModule); - compRef.onDestroy(() => { this._unloadComponent(compRef); }); + compRef.onDestroy(() => { + this._unloadComponent(compRef); + }); const testability = compRef.injector.get(Testability, null); if (testability) { compRef.injector.get(TestabilityRegistry) @@ -755,7 +775,9 @@ export class ApplicationRef { /** * Returns the number of attached views. */ - get viewCount() { return this._views.length; } + get viewCount() { + return this._views.length; + } } function remove<T>(list: T[], el: T): void { diff --git a/packages/core/src/change_detection/change_detection.ts b/packages/core/src/change_detection/change_detection.ts index 158bc238f9052..327beb1f6e875 100644 --- a/packages/core/src/change_detection/change_detection.ts +++ b/packages/core/src/change_detection/change_detection.ts @@ -11,26 +11,16 @@ import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ'; import {IterableDifferFactory, IterableDiffers} from './differs/iterable_differs'; import {KeyValueDifferFactory, KeyValueDiffers} from './differs/keyvalue_differs'; -export {WrappedValue, devModeEqual} from './change_detection_util'; +export {SimpleChange, SimpleChanges} from '../interface/simple_change'; +export {devModeEqual, WrappedValue} from './change_detection_util'; export {ChangeDetectorRef} from './change_detector_ref'; export {ChangeDetectionStrategy, ChangeDetectorStatus, isDefaultChangeDetectionStrategy} from './constants'; export {DefaultIterableDifferFactory} from './differs/default_iterable_differ'; export {DefaultIterableDiffer} from './differs/default_iterable_differ'; export {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ'; -export { - CollectionChangeRecord, - IterableChangeRecord, - IterableChanges, - IterableDiffer, - IterableDifferFactory, - IterableDiffers, - NgIterable, - TrackByFunction -} from -'./differs/iterable_differs'; +export {CollectionChangeRecord, IterableChangeRecord, IterableChanges, IterableDiffer, IterableDifferFactory, IterableDiffers, NgIterable, TrackByFunction} from './differs/iterable_differs'; export {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFactory, KeyValueDiffers} from './differs/keyvalue_differs'; export {PipeTransform} from './pipe_transform'; -export {SimpleChange, SimpleChanges} from '../interface/simple_change'; diff --git a/packages/core/src/change_detection/change_detection_util.ts b/packages/core/src/change_detection/change_detection_util.ts index b98a3756e751a..3d0ad85a4ab54 100644 --- a/packages/core/src/change_detection/change_detection_util.ts +++ b/packages/core/src/change_detection/change_detection_util.ts @@ -49,19 +49,27 @@ export class WrappedValue { /** @deprecated from 5.3, use `unwrap()` instead - will switch to protected */ wrapped: any; - constructor(value: any) { this.wrapped = value; } + constructor(value: any) { + this.wrapped = value; + } /** Creates a wrapped value. */ - static wrap(value: any): WrappedValue { return new WrappedValue(value); } + static wrap(value: any): WrappedValue { + return new WrappedValue(value); + } /** * Returns the underlying value of a wrapped value. * Returns the given `value` when it is not wrapped. **/ - static unwrap(value: any): any { return WrappedValue.isWrapped(value) ? value.wrapped : value; } + static unwrap(value: any): any { + return WrappedValue.isWrapped(value) ? value.wrapped : value; + } /** Returns true if `value` is a wrapped value. */ - static isWrapped(value: any): value is WrappedValue { return value instanceof WrappedValue; } + static isWrapped(value: any): value is WrappedValue { + return value instanceof WrappedValue; + } } export function isListLikeIterable(obj: any): boolean { diff --git a/packages/core/src/change_detection/differs/default_iterable_differ.ts b/packages/core/src/change_detection/differs/default_iterable_differ.ts index dd6d22a06d5ae..ea402369ab55b 100644 --- a/packages/core/src/change_detection/differs/default_iterable_differ.ts +++ b/packages/core/src/change_detection/differs/default_iterable_differ.ts @@ -15,7 +15,9 @@ import {IterableChangeRecord, IterableChanges, IterableDiffer, IterableDifferFac export class DefaultIterableDifferFactory implements IterableDifferFactory { constructor() {} - supports(obj: Object|null|undefined): boolean { return isListLikeIterable(obj); } + supports(obj: Object|null|undefined): boolean { + return isListLikeIterable(obj); + } create<V>(trackByFn?: TrackByFunction<V>): DefaultIterableDiffer<V> { return new DefaultIterableDiffer<V>(trackByFn); @@ -31,7 +33,7 @@ const trackByIdentity = (index: number, item: any) => item; export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChanges<V> { public readonly length: number = 0; // TODO(issue/24571): remove '!'. - public readonly collection !: V[] | Iterable<V>| null; + public readonly collection!: V[]|Iterable<V>|null; // Keeps track of the used records at any point in time (during & across `_check()` calls) private _linkedRecords: _DuplicateMap<V>|null = null; // Keeps track of the removed records at any point in time during `_check()` calls. @@ -50,7 +52,9 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan private _identityChangesTail: IterableChangeRecord_<V>|null = null; private _trackByFn: TrackByFunction<V>; - constructor(trackByFn?: TrackByFunction<V>) { this._trackByFn = trackByFn || trackByIdentity; } + constructor(trackByFn?: TrackByFunction<V>) { + this._trackByFn = trackByFn || trackByIdentity; + } forEachItem(fn: (record: IterableChangeRecord_<V>) => void) { let record: IterableChangeRecord_<V>|null; @@ -71,9 +75,9 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan // Order: remove, add, move const record: IterableChangeRecord<V> = !nextRemove || nextIt && - nextIt.currentIndex ! < + nextIt.currentIndex! < getPreviousIndex(nextRemove, addRemoveOffset, moveOffsets) ? - nextIt ! : + nextIt! : nextRemove; const adjPreviousIndex = getPreviousIndex(record, addRemoveOffset, moveOffsets); const currentIndex = record.currentIndex; @@ -83,14 +87,14 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan addRemoveOffset--; nextRemove = nextRemove._nextRemoved; } else { - nextIt = nextIt !._next; + nextIt = nextIt!._next; if (record.previousIndex == null) { addRemoveOffset++; } else { // INVARIANT: currentIndex < previousIndex if (!moveOffsets) moveOffsets = []; const localMovePreviousIndex = adjPreviousIndex - addRemoveOffset; - const localCurrentIndex = currentIndex ! - addRemoveOffset; + const localCurrentIndex = currentIndex! - addRemoveOffset; if (localMovePreviousIndex != localCurrentIndex) { for (let i = 0; i < localMovePreviousIndex; i++) { const offset = i < moveOffsets.length ? moveOffsets[i] : (moveOffsets[i] = 0); @@ -171,7 +175,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan let item: V; let itemTrackBy: any; if (Array.isArray(collection)) { - (this as{length: number}).length = collection.length; + (this as {length: number}).length = collection.length; for (let index = 0; index < this.length; index++) { item = collection[index]; @@ -206,11 +210,11 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan record = record._next; index++; }); - (this as{length: number}).length = index; + (this as {length: number}).length = index; } this._truncate(record); - (this as{collection: V[] | Iterable<V>}).collection = collection; + (this as {collection: V[] | Iterable<V>}).collection = collection; return this.isDirty; } @@ -338,7 +342,7 @@ export class DefaultIterableDiffer<V> implements IterableDiffer<V>, IterableChan let reinsertRecord: IterableChangeRecord_<V>|null = this._unlinkedRecords === null ? null : this._unlinkedRecords.get(itemTrackBy, null); if (reinsertRecord !== null) { - record = this._reinsertAfter(reinsertRecord, record._prev !, index); + record = this._reinsertAfter(reinsertRecord, record._prev!, index); } else if (record.currentIndex != index) { record.currentIndex = index; this._addToMoves(record, index); @@ -611,7 +615,7 @@ class _DuplicateItemRecordList<V> { // TODO(vicb): // assert(record.item == _head.item || // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN); - this._tail !._nextDup = record; + this._tail!._nextDup = record; record._prevDup = this._tail; record._nextDup = null; this._tail = record; @@ -623,7 +627,7 @@ class _DuplicateItemRecordList<V> { get(trackById: any, atOrAfterIndex: number|null): IterableChangeRecord_<V>|null { let record: IterableChangeRecord_<V>|null; for (record = this._head; record !== null; record = record._nextDup) { - if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex !) && + if ((atOrAfterIndex === null || atOrAfterIndex <= record.currentIndex!) && looseIdentical(record.trackById, trackById)) { return record; } @@ -696,7 +700,7 @@ class _DuplicateMap<V> { */ remove(record: IterableChangeRecord_<V>): IterableChangeRecord_<V> { const key = record.trackById; - const recordList: _DuplicateItemRecordList<V> = this.map.get(key) !; + const recordList: _DuplicateItemRecordList<V> = this.map.get(key)!; // Remove the list of duplicates when it gets empty if (recordList.remove(record)) { this.map.delete(key); @@ -704,13 +708,16 @@ class _DuplicateMap<V> { return record; } - get isEmpty(): boolean { return this.map.size === 0; } + get isEmpty(): boolean { + return this.map.size === 0; + } - clear() { this.map.clear(); } + clear() { + this.map.clear(); + } } -function getPreviousIndex( - item: any, addRemoveOffset: number, moveOffsets: number[] | null): number { +function getPreviousIndex(item: any, addRemoveOffset: number, moveOffsets: number[]|null): number { const previousIndex = item.previousIndex; if (previousIndex === null) return previousIndex; let moveOffset = 0; diff --git a/packages/core/src/change_detection/differs/default_keyvalue_differ.ts b/packages/core/src/change_detection/differs/default_keyvalue_differ.ts index b0d8f404b71e1..fce214ca4b30a 100644 --- a/packages/core/src/change_detection/differs/default_keyvalue_differ.ts +++ b/packages/core/src/change_detection/differs/default_keyvalue_differ.ts @@ -14,9 +14,13 @@ import {KeyValueChangeRecord, KeyValueChanges, KeyValueDiffer, KeyValueDifferFac export class DefaultKeyValueDifferFactory<K, V> implements KeyValueDifferFactory { constructor() {} - supports(obj: any): boolean { return obj instanceof Map || isJsObject(obj); } + supports(obj: any): boolean { + return obj instanceof Map || isJsObject(obj); + } - create<K, V>(): KeyValueDiffer<K, V> { return new DefaultKeyValueDiffer<K, V>(); } + create<K, V>(): KeyValueDiffer<K, V> { + return new DefaultKeyValueDiffer<K, V>(); + } } export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyValueChanges<K, V> { @@ -175,7 +179,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal private _getOrCreateRecordForKey(key: K, value: V): KeyValueChangeRecord_<K, V> { if (this._records.has(key)) { - const record = this._records.get(key) !; + const record = this._records.get(key)!; this._maybeAddToChanges(record, value); const prev = record._prev; const next = record._next; @@ -236,7 +240,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal if (this._additionsHead === null) { this._additionsHead = this._additionsTail = record; } else { - this._additionsTail !._nextAdded = record; + this._additionsTail!._nextAdded = record; this._additionsTail = record; } } @@ -245,7 +249,7 @@ export class DefaultKeyValueDiffer<K, V> implements KeyValueDiffer<K, V>, KeyVal if (this._changesHead === null) { this._changesHead = this._changesTail = record; } else { - this._changesTail !._nextChanged = record; + this._changesTail!._nextChanged = record; this._changesTail = record; } } diff --git a/packages/core/src/change_detection/differs/iterable_differs.ts b/packages/core/src/change_detection/differs/iterable_differs.ts index e9f6f660d9f6d..0029e61bd1e5e 100644 --- a/packages/core/src/change_detection/differs/iterable_differs.ts +++ b/packages/core/src/change_detection/differs/iterable_differs.ts @@ -18,7 +18,7 @@ import {DefaultIterableDifferFactory} from '../differs/default_iterable_differ'; * * @publicApi */ -export type NgIterable<T> = Array<T>| Iterable<T>; +export type NgIterable<T> = Array<T>|Iterable<T>; /** * A strategy for tracking changes over time to an iterable. Used by {@link NgForOf} to @@ -86,8 +86,10 @@ export interface IterableChanges<V> { /** Iterate over all removed items. */ forEachRemovedItem(fn: (record: IterableChangeRecord<V>) => void): void; - /** Iterate over all items which had their identity (as computed by the `TrackByFunction`) - * changed. */ + /** + * Iterate over all items which had their identity (as computed by the `TrackByFunction`) + * changed. + */ forEachIdentityChange(fn: (record: IterableChangeRecord<V>) => void): void; } @@ -124,7 +126,9 @@ export interface CollectionChangeRecord<V> extends IterableChangeRecord<V> {} * * @publicApi */ -export interface TrackByFunction<T> { (index: number, item: T): any; } +export interface TrackByFunction<T> { + (index: number, item: T): any; +} /** * Provides a factory for {@link IterableDiffer}. @@ -153,7 +157,9 @@ export class IterableDiffers { * @deprecated v4.0.0 - Should be private */ factories: IterableDifferFactory[]; - constructor(factories: IterableDifferFactory[]) { this.factories = factories; } + constructor(factories: IterableDifferFactory[]) { + this.factories = factories; + } static create(factories: IterableDifferFactory[], parent?: IterableDiffers): IterableDiffers { if (parent != null) { @@ -206,8 +212,8 @@ export class IterableDiffers { if (factory != null) { return factory; } else { - throw new Error( - `Cannot find a differ supporting object '${iterable}' of type '${getTypeNameForDebugging(iterable)}'`); + throw new Error(`Cannot find a differ supporting object '${iterable}' of type '${ + getTypeNameForDebugging(iterable)}'`); } } } diff --git a/packages/core/src/change_detection/differs/keyvalue_differs.ts b/packages/core/src/change_detection/differs/keyvalue_differs.ts index 953d787d36654..246bd4d357c6d 100644 --- a/packages/core/src/change_detection/differs/keyvalue_differs.ts +++ b/packages/core/src/change_detection/differs/keyvalue_differs.ts @@ -129,7 +129,9 @@ export class KeyValueDiffers { */ factories: KeyValueDifferFactory[]; - constructor(factories: KeyValueDifferFactory[]) { this.factories = factories; } + constructor(factories: KeyValueDifferFactory[]) { + this.factories = factories; + } static create<S>(factories: KeyValueDifferFactory[], parent?: KeyValueDiffers): KeyValueDiffers { if (parent) { diff --git a/packages/core/src/change_detection/pipe_transform.ts b/packages/core/src/change_detection/pipe_transform.ts index 3a6889e3a85a9..db5b0f4dc8f4e 100644 --- a/packages/core/src/change_detection/pipe_transform.ts +++ b/packages/core/src/change_detection/pipe_transform.ts @@ -30,4 +30,6 @@ * * @publicApi */ -export interface PipeTransform { transform(value: any, ...args: any[]): any; } +export interface PipeTransform { + transform(value: any, ...args: any[]): any; +} diff --git a/packages/core/src/codegen_private_exports.ts b/packages/core/src/codegen_private_exports.ts index 177d4560abb80..76bcb8614853c 100644 --- a/packages/core/src/codegen_private_exports.ts +++ b/packages/core/src/codegen_private_exports.ts @@ -8,4 +8,4 @@ export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver'; export {registerModuleFactory as ɵregisterModuleFactory} from './linker/ng_module_factory_registration'; -export {ArgumentType as ɵArgumentType, BindingFlags as ɵBindingFlags, DepFlags as ɵDepFlags, EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, NodeFlags as ɵNodeFlags, QueryBindingType as ɵQueryBindingType, QueryValueType as ɵQueryValueType, ViewDefinition as ɵViewDefinition, ViewFlags as ɵViewFlags, anchorDef as ɵand, createComponentFactory as ɵccf, createNgModuleFactory as ɵcmf, createRendererType2 as ɵcrt, directiveDef as ɵdid, elementDef as ɵeld, getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, moduleDef as ɵmod, moduleProvideDef as ɵmpd, ngContentDef as ɵncd, nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd, queryDef as ɵqud, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid} from './view/index'; +export {anchorDef as ɵand, ArgumentType as ɵArgumentType, BindingFlags as ɵBindingFlags, createComponentFactory as ɵccf, createNgModuleFactory as ɵcmf, createRendererType2 as ɵcrt, DepFlags as ɵDepFlags, directiveDef as ɵdid, elementDef as ɵeld, EMPTY_ARRAY as ɵEMPTY_ARRAY, EMPTY_MAP as ɵEMPTY_MAP, getComponentViewDefinitionFactory as ɵgetComponentViewDefinitionFactory, inlineInterpolate as ɵinlineInterpolate, interpolate as ɵinterpolate, moduleDef as ɵmod, moduleProvideDef as ɵmpd, ngContentDef as ɵncd, NodeFlags as ɵNodeFlags, nodeValue as ɵnov, pipeDef as ɵpid, providerDef as ɵprd, pureArrayDef as ɵpad, pureObjectDef as ɵpod, purePipeDef as ɵppd, QueryBindingType as ɵQueryBindingType, queryDef as ɵqud, QueryValueType as ɵQueryValueType, textDef as ɵted, unwrapValue as ɵunv, viewDef as ɵvid, ViewDefinition as ɵViewDefinition, ViewFlags as ɵViewFlags} from './view/index'; diff --git a/packages/core/src/compiler/compiler_facade_interface.ts b/packages/core/src/compiler/compiler_facade_interface.ts index 79d06d41c1147..e563344f23f6a 100644 --- a/packages/core/src/compiler/compiler_facade_interface.ts +++ b/packages/core/src/compiler/compiler_facade_interface.ts @@ -22,7 +22,9 @@ * ``` */ -export interface ExportedCompilerFacade { ɵcompilerFacade: CompilerFacade; } +export interface ExportedCompilerFacade { + ɵcompilerFacade: CompilerFacade; +} export interface CompilerFacade { compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade): @@ -44,13 +46,15 @@ export interface CompilerFacade { R3ResolvedDependencyType: typeof R3ResolvedDependencyType; R3FactoryTarget: typeof R3FactoryTarget; - ResourceLoader: {new (): ResourceLoader}; + ResourceLoader: {new(): ResourceLoader}; } -export interface CoreEnvironment { [name: string]: Function; } +export interface CoreEnvironment { + [name: string]: Function; +} export type ResourceLoader = { - get(url: string): Promise<string>| string; + get(url: string): Promise<string>|string; }; export type StringMap = { @@ -58,7 +62,7 @@ export type StringMap = { }; export type StringMapWithRename = { - [key: string]: string | [string, string]; + [key: string]: string|[string, string]; }; export type Provider = any; diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 640d7369fb95b..e8d075ea93506 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -16,7 +16,7 @@ export {getDebugNodeR2 as ɵgetDebugNodeR2} from './debug/debug_node'; export {inject, setCurrentInjector as ɵsetCurrentInjector, ɵɵinject} from './di/injector_compatibility'; export {getInjectableDef as ɵgetInjectableDef, ɵɵInjectableDef, ɵɵInjectorDef} from './di/interface/defs'; export {INJECTOR_SCOPE as ɵINJECTOR_SCOPE} from './di/scope'; -export {CurrencyIndex as ɵCurrencyIndex, ExtraLocaleDataIndex as ɵExtraLocaleDataIndex, LocaleDataIndex as ɵLocaleDataIndex, findLocaleData as ɵfindLocaleData, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, registerLocaleData as ɵregisterLocaleData, unregisterAllLocaleData as ɵunregisterLocaleData} from './i18n/locale_data_api'; +export {CurrencyIndex as ɵCurrencyIndex, ExtraLocaleDataIndex as ɵExtraLocaleDataIndex, findLocaleData as ɵfindLocaleData, getLocaleCurrencyCode as ɵgetLocaleCurrencyCode, getLocalePluralCase as ɵgetLocalePluralCase, LocaleDataIndex as ɵLocaleDataIndex, registerLocaleData as ɵregisterLocaleData, unregisterAllLocaleData as ɵunregisterLocaleData} from './i18n/locale_data_api'; export {DEFAULT_LOCALE_ID as ɵDEFAULT_LOCALE_ID} from './i18n/localization'; export {ivyEnabled as ɵivyEnabled} from './ivy_switch'; export {ComponentFactory as ɵComponentFactory} from './linker/component_factory'; @@ -24,7 +24,7 @@ export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} fr export {clearResolutionOfComponentResourcesQueue as ɵclearResolutionOfComponentResourcesQueue, resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading'; export {ReflectionCapabilities as ɵReflectionCapabilities} from './reflection/reflection_capabilities'; export {GetterFn as ɵGetterFn, MethodFn as ɵMethodFn, SetterFn as ɵSetterFn} from './reflection/types'; -export {BypassType as ɵBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, getSanitizationBypassType as ɵgetSanitizationBypassType, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass'; +export {allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, BypassType as ɵBypassType, getSanitizationBypassType as ɵgetSanitizationBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass'; export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer'; export {_sanitizeStyle as ɵ_sanitizeStyle} from './sanitization/style_sanitizer'; export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer'; diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index 24fdccfd2a182..0f1c8e77d58f5 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -7,7 +7,101 @@ */ // clang-format off +// we reexport these symbols just so that they are retained during the dead code elimination +// performed by rollup while it's creating fesm files. +// +// no code actually imports these symbols from the @angular/core entry point +export { + compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__, + isBoundToModule__POST_R3__ as ɵisBoundToModule__POST_R3__ +} from './application_ref'; +export { + SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as ɵSWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__, +} from './change_detection/change_detector_ref'; +export { + getDebugNode__POST_R3__ as ɵgetDebugNode__POST_R3__, +} from './debug/debug_node'; export { + SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__, +} from './di/injectable'; +export {INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__} from './di/injector'; +export { + NG_INJ_DEF as ɵNG_INJ_DEF, + NG_PROV_DEF as ɵNG_PROV_DEF, +} from './di/interface/defs'; +export {createInjector as ɵcreateInjector} from './di/r3_injector'; +export { + SWITCH_IVY_ENABLED__POST_R3__ as ɵSWITCH_IVY_ENABLED__POST_R3__, +} from './ivy_switch'; +export { + Compiler_compileModuleAndAllComponentsAsync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsAsync__POST_R3__, + Compiler_compileModuleAndAllComponentsSync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsSync__POST_R3__, + Compiler_compileModuleAsync__POST_R3__ as ɵCompiler_compileModuleAsync__POST_R3__, + Compiler_compileModuleSync__POST_R3__ as ɵCompiler_compileModuleSync__POST_R3__, +} from './linker/compiler'; +export { + SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as ɵSWITCH_ELEMENT_REF_FACTORY__POST_R3__, +} from './linker/element_ref'; +export { getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__ } from './linker/ng_module_factory_loader'; +export { registerNgModuleType as ɵregisterNgModuleType } from './linker/ng_module_factory_registration'; +export { + SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as ɵSWITCH_TEMPLATE_REF_FACTORY__POST_R3__, +} from './linker/template_ref'; +export { + SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as ɵSWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__, +} from './linker/view_container_ref'; +export { + SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__, + SWITCH_COMPILE_DIRECTIVE__POST_R3__ as ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__, + SWITCH_COMPILE_PIPE__POST_R3__ as ɵSWITCH_COMPILE_PIPE__POST_R3__, +} from './metadata/directives'; +export { + NgModuleDef as ɵNgModuleDef, + NgModuleTransitiveScopes as ɵNgModuleTransitiveScopes, + ɵɵNgModuleDefWithMeta, +} from './metadata/ng_module'; +export { + SWITCH_COMPILE_NGMODULE__POST_R3__ as ɵSWITCH_COMPILE_NGMODULE__POST_R3__, +} from './metadata/ng_module'; +export { + SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__, +} from './render/api'; +export { + getLContext as ɵgetLContext +} from './render3/context_discovery'; +export { + NG_COMP_DEF as ɵNG_COMP_DEF, + NG_DIR_DEF as ɵNG_DIR_DEF, + NG_ELEMENT_ID as ɵNG_ELEMENT_ID, + NG_MOD_DEF as ɵNG_MOD_DEF, + NG_PIPE_DEF as ɵNG_PIPE_DEF, +} from './render3/fields'; +export { + AttributeMarker as ɵAttributeMarker, + ComponentDef as ɵComponentDef, + ComponentFactory as ɵRender3ComponentFactory, + ComponentRef as ɵRender3ComponentRef, + ComponentType as ɵComponentType, + CssSelectorList as ɵCssSelectorList, + detectChanges as ɵdetectChanges, + DirectiveDef as ɵDirectiveDef, + DirectiveType as ɵDirectiveType, + getDirectives as ɵgetDirectives, + getHostElement as ɵgetHostElement, + LifecycleHooksFeature as ɵLifecycleHooksFeature, + markDirty as ɵmarkDirty, + NgModuleFactory as ɵNgModuleFactory, + NgModuleRef as ɵRender3NgModuleRef, + NgModuleType as ɵNgModuleType, + NO_CHANGE as ɵNO_CHANGE, + PipeDef as ɵPipeDef, + renderComponent as ɵrenderComponent, + RenderFlags as ɵRenderFlags, + setClassMetadata as ɵsetClassMetadata, + setLocaleId as ɵsetLocaleId, + store as ɵstore, + whenRendered as ɵwhenRendered, + ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, ɵɵattributeInterpolate2, @@ -18,88 +112,72 @@ export { ɵɵattributeInterpolate7, ɵɵattributeInterpolate8, ɵɵattributeInterpolateV, + ɵɵclassMap, + ɵɵclassMapInterpolate1, + ɵɵclassMapInterpolate2, + ɵɵclassMapInterpolate3, + ɵɵclassMapInterpolate4, + ɵɵclassMapInterpolate5, + ɵɵclassMapInterpolate6, + ɵɵclassMapInterpolate7, + ɵɵclassMapInterpolate8, + ɵɵclassMapInterpolateV, + ɵɵclassProp, + ɵɵComponentDefWithMeta, + ɵɵcomponentHostSyntheticListener, + ɵɵcontainer, + ɵɵcontainerRefreshEnd, + ɵɵcontainerRefreshStart, + ɵɵcontentQuery, + ɵɵCopyDefinitionFeature, ɵɵdefineComponent, ɵɵdefineDirective, - ɵɵdefinePipe, ɵɵdefineNgModule, - detectChanges as ɵdetectChanges, - renderComponent as ɵrenderComponent, - AttributeMarker as ɵAttributeMarker, - ComponentType as ɵComponentType, - ComponentFactory as ɵRender3ComponentFactory, - ComponentRef as ɵRender3ComponentRef, - DirectiveType as ɵDirectiveType, - RenderFlags as ɵRenderFlags, + ɵɵdefinePipe, + ɵɵDirectiveDefWithMeta, ɵɵdirectiveInject, - ɵɵinjectAttribute, - ɵɵinjectPipeChangeDetectorRef, - ɵɵinvalidFactory, + ɵɵdisableBindings, + ɵɵelement, + ɵɵelementContainer, + ɵɵelementContainerEnd, + ɵɵelementContainerStart, + ɵɵelementEnd, + ɵɵelementStart, + ɵɵembeddedViewEnd, + ɵɵembeddedViewStart, + ɵɵenableBindings, + ɵɵFactoryDef, + ɵɵgetCurrentView, ɵɵgetFactoryOf, ɵɵgetInheritedFactory, - ɵɵsetComponentScope, - ɵɵsetNgModuleScope, - ɵɵtemplateRefExtractor, - ɵɵProvidersFeature, - ɵɵCopyDefinitionFeature, + ɵɵhostProperty, + ɵɵi18n, + ɵɵi18nApply, + ɵɵi18nAttributes, + ɵɵi18nEnd, + ɵɵi18nExp, + ɵɵi18nPostprocess, + ɵɵi18nStart, ɵɵInheritDefinitionFeature, - ɵɵNgOnChangesFeature, - LifecycleHooksFeature as ɵLifecycleHooksFeature, - NgModuleType as ɵNgModuleType, - NgModuleRef as ɵRender3NgModuleRef, - CssSelectorList as ɵCssSelectorList, - markDirty as ɵmarkDirty, - NgModuleFactory as ɵNgModuleFactory, - NO_CHANGE as ɵNO_CHANGE, - ɵɵcontainer, - ɵɵnextContext, - ɵɵelementStart, + ɵɵinjectAttribute, + ɵɵinjectPipeChangeDetectorRef, + ɵɵinvalidFactory, + ɵɵlistener, + ɵɵloadQuery, ɵɵnamespaceHTML, ɵɵnamespaceMathML, ɵɵnamespaceSVG, - ɵɵelement, - ɵɵlistener, - ɵɵtext, - ɵɵtextInterpolate, - ɵɵtextInterpolate1, - ɵɵtextInterpolate2, - ɵɵtextInterpolate3, - ɵɵtextInterpolate4, - ɵɵtextInterpolate5, - ɵɵtextInterpolate6, - ɵɵtextInterpolate7, - ɵɵtextInterpolate8, - ɵɵtextInterpolateV, - ɵɵembeddedViewStart, - ɵɵprojection, + ɵɵnextContext, + ɵɵNgOnChangesFeature, + ɵɵpipe, ɵɵpipeBind1, ɵɵpipeBind2, ɵɵpipeBind3, ɵɵpipeBind4, ɵɵpipeBindV, - ɵɵpureFunction0, - ɵɵpureFunction1, - ɵɵpureFunction2, - ɵɵpureFunction3, - ɵɵpureFunction4, - ɵɵpureFunction5, - ɵɵpureFunction6, - ɵɵpureFunction7, - ɵɵpureFunction8, - ɵɵpureFunctionV, - ɵɵgetCurrentView, - getDirectives as ɵgetDirectives, - getHostElement as ɵgetHostElement, - ɵɵrestoreView, - ɵɵcontainerRefreshStart, - ɵɵcontainerRefreshEnd, - ɵɵqueryRefresh, - ɵɵviewQuery, - ɵɵstaticViewQuery, - ɵɵstaticContentQuery, - ɵɵcontentQuery, - ɵɵloadQuery, - ɵɵelementEnd, - ɵɵhostProperty, + ɵɵPipeDefWithMeta, + ɵɵprojection, + ɵɵprojectionDef, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, @@ -111,15 +189,29 @@ export { ɵɵpropertyInterpolate7, ɵɵpropertyInterpolate8, ɵɵpropertyInterpolateV, - ɵɵupdateSyntheticHostBinding, - ɵɵcomponentHostSyntheticListener, - ɵɵprojectionDef, + ɵɵProvidersFeature, + ɵɵpureFunction0, + ɵɵpureFunction1, + ɵɵpureFunction2, + ɵɵpureFunction3, + ɵɵpureFunction4, + ɵɵpureFunction5, + ɵɵpureFunction6, + ɵɵpureFunction7, + ɵɵpureFunction8, + ɵɵpureFunctionV, + ɵɵqueryRefresh, ɵɵreference, - ɵɵenableBindings, - ɵɵdisableBindings, - ɵɵelementContainerStart, - ɵɵelementContainerEnd, - ɵɵelementContainer, + ɵɵresolveBody, + ɵɵresolveDocument, + ɵɵresolveWindow, + ɵɵrestoreView, + + ɵɵselect, + ɵɵsetComponentScope, + ɵɵsetNgModuleScope, + ɵɵstaticContentQuery, + ɵɵstaticViewQuery, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, @@ -130,17 +222,6 @@ export { ɵɵstyleMapInterpolate7, ɵɵstyleMapInterpolate8, ɵɵstyleMapInterpolateV, - ɵɵstyleSanitizer, - ɵɵclassMap, - ɵɵclassMapInterpolate1, - ɵɵclassMapInterpolate2, - ɵɵclassMapInterpolate3, - ɵɵclassMapInterpolate4, - ɵɵclassMapInterpolate5, - ɵɵclassMapInterpolate6, - ɵɵclassMapInterpolate7, - ɵɵclassMapInterpolate8, - ɵɵclassMapInterpolateV, ɵɵstyleProp, ɵɵstylePropInterpolate1, ɵɵstylePropInterpolate2, @@ -151,170 +232,72 @@ export { ɵɵstylePropInterpolate7, ɵɵstylePropInterpolate8, ɵɵstylePropInterpolateV, - ɵɵclassProp, - - ɵɵselect, - ɵɵadvance, + ɵɵstyleSanitizer, ɵɵtemplate, - ɵɵembeddedViewEnd, - store as ɵstore, - ɵɵpipe, - ComponentDef as ɵComponentDef, - ɵɵComponentDefWithMeta, - ɵɵFactoryDef, - DirectiveDef as ɵDirectiveDef, - ɵɵDirectiveDefWithMeta, - PipeDef as ɵPipeDef, - ɵɵPipeDefWithMeta, - whenRendered as ɵwhenRendered, - ɵɵi18n, - ɵɵi18nAttributes, - ɵɵi18nExp, - ɵɵi18nStart, - ɵɵi18nEnd, - ɵɵi18nApply, - ɵɵi18nPostprocess, - setLocaleId as ɵsetLocaleId, - setClassMetadata as ɵsetClassMetadata, - ɵɵresolveWindow, - ɵɵresolveDocument, - ɵɵresolveBody, + ɵɵtemplateRefExtractor, + ɵɵtext, + ɵɵtextInterpolate, + ɵɵtextInterpolate1, + ɵɵtextInterpolate2, + ɵɵtextInterpolate3, + ɵɵtextInterpolate4, + ɵɵtextInterpolate5, + ɵɵtextInterpolate6, + ɵɵtextInterpolate7, + ɵɵtextInterpolate8, + ɵɵtextInterpolateV, + ɵɵupdateSyntheticHostBinding, + ɵɵviewQuery, } from './render3/index'; - - +export { + LContext as ɵLContext, +} from './render3/interfaces/context'; +export { + setDocument as ɵsetDocument +} from './render3/interfaces/document'; +export { + Player as ɵPlayer, + PlayerFactory as ɵPlayerFactory, + PlayerHandler as ɵPlayerHandler, + PlayState as ɵPlayState, +} from './render3/interfaces/player'; export { compileComponent as ɵcompileComponent, compileDirective as ɵcompileDirective, } from './render3/jit/directive'; +export { + resetJitOptions as ɵresetJitOptions, +} from './render3/jit/jit_options'; export { compileNgModule as ɵcompileNgModule, compileNgModuleDefs as ɵcompileNgModuleDefs, + flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, patchComponentDefWithScope as ɵpatchComponentDefWithScope, resetCompiledComponents as ɵresetCompiledComponents, - flushModuleScopingQueueAsMuchAsPossible as ɵflushModuleScopingQueueAsMuchAsPossible, transitiveScopesFor as ɵtransitiveScopesFor, } from './render3/jit/module'; export { compilePipe as ɵcompilePipe, } from './render3/jit/pipe'; export { - resetJitOptions as ɵresetJitOptions, -} from './render3/jit/jit_options'; - + publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils +, + publishGlobalUtil as ɵpublishGlobalUtil} from './render3/util/global_utils'; export { - NgModuleDef as ɵNgModuleDef, - ɵɵNgModuleDefWithMeta, - NgModuleTransitiveScopes as ɵNgModuleTransitiveScopes, -} from './metadata/ng_module'; - + bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, + bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, + bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, + bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, + bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, +} from './sanitization/bypass'; export { - ɵɵsanitizeHtml, - ɵɵsanitizeStyle, ɵɵdefaultStyleSanitizer, + ɵɵsanitizeHtml, + ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, + ɵɵsanitizeStyle, ɵɵsanitizeUrl, - ɵɵsanitizeResourceUrl, ɵɵsanitizeUrlOrResourceUrl, } from './sanitization/sanitization'; -export { - bypassSanitizationTrustHtml as ɵbypassSanitizationTrustHtml, - bypassSanitizationTrustStyle as ɵbypassSanitizationTrustStyle, - bypassSanitizationTrustScript as ɵbypassSanitizationTrustScript, - bypassSanitizationTrustUrl as ɵbypassSanitizationTrustUrl, - bypassSanitizationTrustResourceUrl as ɵbypassSanitizationTrustResourceUrl, -} from './sanitization/bypass'; - -export { - getLContext as ɵgetLContext -} from './render3/context_discovery'; - -export { - NG_ELEMENT_ID as ɵNG_ELEMENT_ID, - NG_COMP_DEF as ɵNG_COMP_DEF, - NG_DIR_DEF as ɵNG_DIR_DEF, - NG_PIPE_DEF as ɵNG_PIPE_DEF, - NG_MOD_DEF as ɵNG_MOD_DEF, -} from './render3/fields'; - -export { - NG_PROV_DEF as ɵNG_PROV_DEF, - NG_INJ_DEF as ɵNG_INJ_DEF, -} from './di/interface/defs'; - -export { - Player as ɵPlayer, - PlayerFactory as ɵPlayerFactory, - PlayState as ɵPlayState, - PlayerHandler as ɵPlayerHandler, -} from './render3/interfaces/player'; - -export { - LContext as ɵLContext, -} from './render3/interfaces/context'; - -export { - setDocument as ɵsetDocument -} from './render3/interfaces/document'; - -// we reexport these symbols just so that they are retained during the dead code elimination -// performed by rollup while it's creating fesm files. -// -// no code actually imports these symbols from the @angular/core entry point -export { - compileNgModuleFactory__POST_R3__ as ɵcompileNgModuleFactory__POST_R3__, - isBoundToModule__POST_R3__ as ɵisBoundToModule__POST_R3__ -} from './application_ref'; -export { - SWITCH_COMPILE_COMPONENT__POST_R3__ as ɵSWITCH_COMPILE_COMPONENT__POST_R3__, - SWITCH_COMPILE_DIRECTIVE__POST_R3__ as ɵSWITCH_COMPILE_DIRECTIVE__POST_R3__, - SWITCH_COMPILE_PIPE__POST_R3__ as ɵSWITCH_COMPILE_PIPE__POST_R3__, -} from './metadata/directives'; -export { - SWITCH_COMPILE_NGMODULE__POST_R3__ as ɵSWITCH_COMPILE_NGMODULE__POST_R3__, -} from './metadata/ng_module'; -export { - getDebugNode__POST_R3__ as ɵgetDebugNode__POST_R3__, -} from './debug/debug_node'; -export { - SWITCH_COMPILE_INJECTABLE__POST_R3__ as ɵSWITCH_COMPILE_INJECTABLE__POST_R3__, -} from './di/injectable'; -export { - SWITCH_IVY_ENABLED__POST_R3__ as ɵSWITCH_IVY_ENABLED__POST_R3__, -} from './ivy_switch'; -export { - SWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__ as ɵSWITCH_CHANGE_DETECTOR_REF_FACTORY__POST_R3__, -} from './change_detection/change_detector_ref'; -export { - Compiler_compileModuleSync__POST_R3__ as ɵCompiler_compileModuleSync__POST_R3__, - Compiler_compileModuleAsync__POST_R3__ as ɵCompiler_compileModuleAsync__POST_R3__, - Compiler_compileModuleAndAllComponentsSync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsSync__POST_R3__, - Compiler_compileModuleAndAllComponentsAsync__POST_R3__ as ɵCompiler_compileModuleAndAllComponentsAsync__POST_R3__, -} from './linker/compiler'; -export { - SWITCH_ELEMENT_REF_FACTORY__POST_R3__ as ɵSWITCH_ELEMENT_REF_FACTORY__POST_R3__, -} from './linker/element_ref'; -export { - SWITCH_TEMPLATE_REF_FACTORY__POST_R3__ as ɵSWITCH_TEMPLATE_REF_FACTORY__POST_R3__, -} from './linker/template_ref'; -export { - SWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__ as ɵSWITCH_VIEW_CONTAINER_REF_FACTORY__POST_R3__, -} from './linker/view_container_ref'; -export { - SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__, -} from './render/api'; - -export { getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__ } from './linker/ng_module_factory_loader'; - -export { registerNgModuleType as ɵregisterNgModuleType } from './linker/ng_module_factory_registration'; - -export { - publishGlobalUtil as ɵpublishGlobalUtil, - publishDefaultGlobalUtils as ɵpublishDefaultGlobalUtils -} from './render3/util/global_utils'; - -export {createInjector as ɵcreateInjector} from './di/r3_injector'; - -export {INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__} from './di/injector'; - // clang-format on diff --git a/packages/core/src/debug/debug_node.ts b/packages/core/src/debug/debug_node.ts index 3270a568f13be..c6161dbe81110 100644 --- a/packages/core/src/debug/debug_node.ts +++ b/packages/core/src/debug/debug_node.ts @@ -10,7 +10,7 @@ import {Injector} from '../di'; import {CONTAINER_HEADER_OFFSET, LContainer, NATIVE} from '../render3/interfaces/container'; import {TElementNode, TNode, TNodeFlags, TNodeType} from '../render3/interfaces/node'; import {isComponentHost, isLContainer} from '../render3/interfaces/type_checks'; -import {DECLARATION_COMPONENT_VIEW, LView, PARENT, TData, TVIEW, T_HOST} from '../render3/interfaces/view'; +import {DECLARATION_COMPONENT_VIEW, LView, PARENT, T_HOST, TData, TVIEW} from '../render3/interfaces/view'; import {getComponent, getContext, getInjectionTokens, getInjector, getListeners, getLocalRefs, getOwningComponent, loadLContext} from '../render3/util/discovery_utils'; import {INTERPOLATION_DELIMITER, renderStringify} from '../render3/util/misc_utils'; import {getComponentLViewByIndex, getNativeByTNodeOrNull} from '../render3/util/view_utils'; @@ -53,15 +53,25 @@ export class DebugNode__PRE_R3__ { } } - get injector(): Injector { return this._debugContext.injector; } + get injector(): Injector { + return this._debugContext.injector; + } - get componentInstance(): any { return this._debugContext.component; } + get componentInstance(): any { + return this._debugContext.component; + } - get context(): any { return this._debugContext.context; } + get context(): any { + return this._debugContext.context; + } - get references(): {[key: string]: any} { return this._debugContext.references; } + get references(): {[key: string]: any} { + return this._debugContext.references; + } - get providerTokens(): any[] { return this._debugContext.providerTokens; } + get providerTokens(): any[] { + return this._debugContext.providerTokens; + } } /** @@ -70,9 +80,9 @@ export class DebugNode__PRE_R3__ { export interface DebugElement extends DebugNode { readonly name: string; readonly properties: {[key: string]: any}; - readonly attributes: {[key: string]: string | null}; + readonly attributes: {[key: string]: string|null}; readonly classes: {[key: string]: boolean}; - readonly styles: {[key: string]: string | null}; + readonly styles: {[key: string]: string|null}; readonly childNodes: DebugNode[]; readonly nativeElement: any; readonly children: DebugElement[]; @@ -83,11 +93,11 @@ export interface DebugElement extends DebugNode { triggerEventHandler(eventName: string, eventObj: any): void; } export class DebugElement__PRE_R3__ extends DebugNode__PRE_R3__ implements DebugElement { - readonly name !: string; + readonly name!: string; readonly properties: {[key: string]: any} = {}; - readonly attributes: {[key: string]: string | null} = {}; + readonly attributes: {[key: string]: string|null} = {}; readonly classes: {[key: string]: boolean} = {}; - readonly styles: {[key: string]: string | null} = {}; + readonly styles: {[key: string]: string|null} = {}; readonly childNodes: DebugNode[] = []; readonly nativeElement: any; @@ -99,14 +109,14 @@ export class DebugElement__PRE_R3__ extends DebugNode__PRE_R3__ implements Debug addChild(child: DebugNode) { if (child) { this.childNodes.push(child); - (child as{parent: DebugNode}).parent = this; + (child as {parent: DebugNode}).parent = this; } } removeChild(child: DebugNode) { const childIndex = this.childNodes.indexOf(child); if (childIndex !== -1) { - (child as{parent: DebugNode | null}).parent = null; + (child as {parent: DebugNode | null}).parent = null; this.childNodes.splice(childIndex, 1); } } @@ -119,7 +129,7 @@ export class DebugElement__PRE_R3__ extends DebugNode__PRE_R3__ implements Debug if (c.parent) { (c.parent as DebugElement__PRE_R3__).removeChild(c); } - (child as{parent: DebugNode}).parent = this; + (child as {parent: DebugNode}).parent = this; }); } } @@ -132,7 +142,7 @@ export class DebugElement__PRE_R3__ extends DebugNode__PRE_R3__ implements Debug if (newChild.parent) { (newChild.parent as DebugElement__PRE_R3__).removeChild(newChild); } - (newChild as{parent: DebugNode}).parent = this; + (newChild as {parent: DebugNode}).parent = this; this.childNodes.splice(refIndex, 0, newChild); } } @@ -155,9 +165,8 @@ export class DebugElement__PRE_R3__ extends DebugNode__PRE_R3__ implements Debug } get children(): DebugElement[] { - return this - .childNodes // - .filter((node) => node instanceof DebugElement__PRE_R3__) as DebugElement[]; + return this.childNodes // + .filter((node) => node instanceof DebugElement__PRE_R3__) as DebugElement[]; } triggerEventHandler(eventName: string, eventObj: any) { @@ -205,14 +214,18 @@ function _queryNodeChildren( class DebugNode__POST_R3__ implements DebugNode { readonly nativeNode: Node; - constructor(nativeNode: Node) { this.nativeNode = nativeNode; } + constructor(nativeNode: Node) { + this.nativeNode = nativeNode; + } get parent(): DebugElement|null { const parent = this.nativeNode.parentNode as Element; return parent ? new DebugElement__POST_R3__(parent) : null; } - get injector(): Injector { return getInjector(this.nativeNode); } + get injector(): Injector { + return getInjector(this.nativeNode); + } get componentInstance(): any { const nativeElement = this.nativeNode; @@ -227,9 +240,13 @@ class DebugNode__POST_R3__ implements DebugNode { return getListeners(this.nativeNode as Element).filter(listener => listener.type === 'dom'); } - get references(): {[key: string]: any;} { return getLocalRefs(this.nativeNode); } + get references(): {[key: string]: any;} { + return getLocalRefs(this.nativeNode); + } - get providerTokens(): any[] { return getInjectionTokens(this.nativeNode as Element); } + get providerTokens(): any[] { + return getInjectionTokens(this.nativeNode as Element); + } } class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugElement { @@ -244,11 +261,11 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme get name(): string { try { - const context = loadLContext(this.nativeNode) !; + const context = loadLContext(this.nativeNode)!; const lView = context.lView; const tData = lView[TVIEW].data; const tNode = tData[context.nodeIndex] as TNode; - return tNode.tagName !; + return tNode.tagName!; } catch (e) { return this.nativeNode.nodeName; } @@ -285,8 +302,8 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme return properties; } - get attributes(): {[key: string]: string | null;} { - const attributes: {[key: string]: string | null;} = {}; + get attributes(): {[key: string]: string|null;} { + const attributes: {[key: string]: string|null;} = {}; const element = this.nativeElement; if (!element) { @@ -343,9 +360,9 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme return attributes; } - get styles(): {[key: string]: string | null} { + get styles(): {[key: string]: string|null} { if (this.nativeElement && (this.nativeElement as HTMLElement).style) { - return (this.nativeElement as HTMLElement).style as{[key: string]: any}; + return (this.nativeElement as HTMLElement).style as {[key: string]: any}; } return {}; } @@ -438,7 +455,7 @@ class DebugElement__POST_R3__ extends DebugNode__POST_R3__ implements DebugEleme } } -function copyDomProperties(element: Element | null, properties: {[name: string]: string}): void { +function copyDomProperties(element: Element|null, properties: {[name: string]: string}): void { if (element) { // Skip own properties (as those are patched) let obj = Object.getPrototypeOf(element); @@ -481,8 +498,8 @@ function _queryAllR3( parentElement: DebugElement, predicate: Predicate<DebugNode>, matches: DebugNode[], elementsOnly: false): void; function _queryAllR3( - parentElement: DebugElement, predicate: Predicate<DebugElement>| Predicate<DebugNode>, - matches: DebugElement[] | DebugNode[], elementsOnly: boolean) { + parentElement: DebugElement, predicate: Predicate<DebugElement>|Predicate<DebugNode>, + matches: DebugElement[]|DebugNode[], elementsOnly: boolean) { const context = loadLContext(parentElement.nativeNode, false); if (context !== null) { const parentTNode = context.lView[TVIEW].data[context.nodeIndex] as TNode; @@ -506,8 +523,8 @@ function _queryAllR3( * @param rootNativeNode the root native node on which predicate should not be matched */ function _queryNodeChildrenR3( - tNode: TNode, lView: LView, predicate: Predicate<DebugElement>| Predicate<DebugNode>, - matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any) { + tNode: TNode, lView: LView, predicate: Predicate<DebugElement>|Predicate<DebugNode>, + matches: DebugElement[]|DebugNode[], elementsOnly: boolean, rootNativeNode: any) { const nativeNode = getNativeByTNodeOrNull(tNode, lView); // For each type of TNode, specific logic is executed. if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) { @@ -520,7 +537,7 @@ function _queryNodeChildrenR3( const componentView = getComponentLViewByIndex(tNode.index, lView); if (componentView && componentView[TVIEW].firstChild) { _queryNodeChildrenR3( - componentView[TVIEW].firstChild !, componentView, predicate, matches, elementsOnly, + componentView[TVIEW].firstChild!, componentView, predicate, matches, elementsOnly, rootNativeNode); } } else { @@ -556,17 +573,17 @@ function _queryNodeChildrenR3( } else if (tNode.type === TNodeType.Projection) { // Case 3: the TNode is a projection insertion point (i.e. a <ng-content>). // The nodes projected at this location all need to be processed. - const componentView = lView ![DECLARATION_COMPONENT_VIEW]; + const componentView = lView![DECLARATION_COMPONENT_VIEW]; const componentHost = componentView[T_HOST] as TElementNode; const head: TNode|null = - (componentHost.projection as(TNode | null)[])[tNode.projection as number]; + (componentHost.projection as (TNode | null)[])[tNode.projection as number]; if (Array.isArray(head)) { for (let nativeNode of head) { _addQueryMatchR3(nativeNode, predicate, matches, elementsOnly, rootNativeNode); } } else if (head) { - const nextLView = componentView[PARENT] !as LView; + const nextLView = componentView[PARENT]! as LView; const nextTNode = nextLView[TVIEW].data[head.index] as TNode; _queryNodeChildrenR3(nextTNode, nextLView, predicate, matches, elementsOnly, rootNativeNode); } @@ -596,12 +613,12 @@ function _queryNodeChildrenR3( * @param rootNativeNode the root native node on which predicate should not be matched */ function _queryNodeChildrenInContainerR3( - lContainer: LContainer, predicate: Predicate<DebugElement>| Predicate<DebugNode>, - matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any) { + lContainer: LContainer, predicate: Predicate<DebugElement>|Predicate<DebugNode>, + matches: DebugElement[]|DebugNode[], elementsOnly: boolean, rootNativeNode: any) { for (let i = CONTAINER_HEADER_OFFSET; i < lContainer.length; i++) { const childView = lContainer[i]; _queryNodeChildrenR3( - childView[TVIEW].node !, childView, predicate, matches, elementsOnly, rootNativeNode); + childView[TVIEW].node!, childView, predicate, matches, elementsOnly, rootNativeNode); } } @@ -615,8 +632,8 @@ function _queryNodeChildrenInContainerR3( * @param rootNativeNode the root native node on which predicate should not be matched */ function _addQueryMatchR3( - nativeNode: any, predicate: Predicate<DebugElement>| Predicate<DebugNode>, - matches: DebugElement[] | DebugNode[], elementsOnly: boolean, rootNativeNode: any) { + nativeNode: any, predicate: Predicate<DebugElement>|Predicate<DebugNode>, + matches: DebugElement[]|DebugNode[], elementsOnly: boolean, rootNativeNode: any) { if (rootNativeNode !== nativeNode) { const debugNode = getDebugNode(nativeNode); if (!debugNode) { @@ -645,8 +662,8 @@ function _addQueryMatchR3( * @param elementsOnly whether only elements should be searched */ function _queryNativeNodeDescendants( - parentNode: any, predicate: Predicate<DebugElement>| Predicate<DebugNode>, - matches: DebugElement[] | DebugNode[], elementsOnly: boolean) { + parentNode: any, predicate: Predicate<DebugElement>|Predicate<DebugNode>, + matches: DebugElement[]|DebugNode[], elementsOnly: boolean) { const nodes = parentNode.childNodes; const length = nodes.length; @@ -757,7 +774,9 @@ export function removeDebugNodeFromIndex(node: DebugNode) { * * @publicApi */ -export interface Predicate<T> { (value: T): boolean; } +export interface Predicate<T> { + (value: T): boolean; +} /** * @publicApi diff --git a/packages/core/src/di/forward_ref.ts b/packages/core/src/di/forward_ref.ts index 65708c7a4dc53..e13705b91a6a0 100644 --- a/packages/core/src/di/forward_ref.ts +++ b/packages/core/src/di/forward_ref.ts @@ -21,7 +21,9 @@ import {stringify} from '../util/stringify'; * {@example core/di/ts/forward_ref/forward_ref_spec.ts region='forward_ref_fn'} * @publicApi */ -export interface ForwardRefFn { (): any; } +export interface ForwardRefFn { + (): any; +} const __forward_ref__ = getClosureSafeProperty({__forward_ref__: getClosureSafeProperty}); @@ -39,7 +41,9 @@ const __forward_ref__ = getClosureSafeProperty({__forward_ref__: getClosureSafeP */ export function forwardRef(forwardRefFn: ForwardRefFn): Type<any> { (<any>forwardRefFn).__forward_ref__ = forwardRef; - (<any>forwardRefFn).toString = function() { return stringify(this()); }; + (<any>forwardRefFn).toString = function() { + return stringify(this()); + }; return (<Type<any>><any>forwardRefFn); } diff --git a/packages/core/src/di/injectable.ts b/packages/core/src/di/injectable.ts index e6a3c10050104..fc20a2a2697a3 100644 --- a/packages/core/src/di/injectable.ts +++ b/packages/core/src/di/injectable.ts @@ -7,9 +7,9 @@ */ import {Type} from '../interface/type'; -import {TypeDecorator, makeDecorator} from '../util/decorators'; +import {makeDecorator, TypeDecorator} from '../util/decorators'; -import {InjectableType, getInjectableDef, ɵɵdefineInjectable} from './interface/defs'; +import {getInjectableDef, InjectableType, ɵɵdefineInjectable} from './interface/defs'; import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueSansProvider} from './interface/provider'; import {compileInjectable as render3CompileInjectable} from './jit/injectable'; import {convertInjectableProviderToFactory} from './util'; @@ -21,8 +21,8 @@ import {convertInjectableProviderToFactory} from './util'; * * @publicApi */ -export type InjectableProvider = ValueSansProvider | ExistingSansProvider | - StaticClassSansProvider | ConstructorSansProvider | FactorySansProvider | ClassSansProvider; +export type InjectableProvider = ValueSansProvider|ExistingSansProvider|StaticClassSansProvider| + ConstructorSansProvider|FactorySansProvider|ClassSansProvider; /** * Type of the Injectable decorator / constructor function. @@ -50,11 +50,11 @@ export interface InjectableDecorator { * */ (): TypeDecorator; - (options?: {providedIn: Type<any>| 'root' | 'platform' | 'any' | null}& + (options?: {providedIn: Type<any>|'root'|'platform'|'any'|null}& InjectableProvider): TypeDecorator; - new (): Injectable; - new (options?: {providedIn: Type<any>| 'root' | 'platform' | 'any' | null}& - InjectableProvider): Injectable; + new(): Injectable; + new(options?: {providedIn: Type<any>|'root'|'platform'|'any'|null}& + InjectableProvider): Injectable; } /** @@ -91,9 +91,9 @@ export const Injectable: InjectableDecorator = makeDecorator( /** * Supports @Injectable() in JIT mode for Render2. */ -function render2CompileInjectable(injectableType: Type<any>, options?: { - providedIn?: Type<any>| 'root' | 'platform' | 'any' | null -} & InjectableProvider): void { +function render2CompileInjectable( + injectableType: Type<any>, + options?: {providedIn?: Type<any>|'root'|'platform'|'any'|null}&InjectableProvider): void { if (options && options.providedIn !== undefined && !getInjectableDef(injectableType)) { (injectableType as InjectableType<any>).ɵprov = ɵɵdefineInjectable({ token: injectableType, diff --git a/packages/core/src/di/injection_token.ts b/packages/core/src/di/injection_token.ts index 5a3a6feb4eed3..f45c903ce6df7 100644 --- a/packages/core/src/di/injection_token.ts +++ b/packages/core/src/di/injection_token.ts @@ -57,8 +57,7 @@ export class InjectionToken<T> { readonly ɵprov: never|undefined; constructor(protected _desc: string, options?: { - providedIn?: Type<any>| 'root' | 'platform' | 'any' | null, - factory: () => T + providedIn?: Type<any>|'root'|'platform'|'any'|null, factory: () => T }) { this.ɵprov = undefined; if (typeof options == 'number') { @@ -75,7 +74,11 @@ export class InjectionToken<T> { } } - toString(): string { return `InjectionToken ${this._desc}`; } + toString(): string { + return `InjectionToken ${this._desc}`; + } } -export interface InjectableDefToken<T> extends InjectionToken<T> { ɵprov: never; } +export interface InjectableDefToken<T> extends InjectionToken<T> { + ɵprov: never; +} diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index e88b36d9a4753..607b610613bfb 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -11,7 +11,7 @@ import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, formatError, setCurrentInjector, ɵɵinject} from './injector_compatibility'; +import {catchInjectorError, formatError, INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, setCurrentInjector, THROW_IF_NOT_FOUND, USE_VALUE, ɵɵinject} from './injector_compatibility'; import {getInjectableDef, ɵɵdefineInjectable} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './interface/provider'; @@ -20,12 +20,12 @@ import {createInjector} from './r3_injector'; import {INJECTOR_SCOPE} from './scope'; export function INJECTOR_IMPL__PRE_R3__( - providers: StaticProvider[], parent: Injector | undefined, name: string) { + providers: StaticProvider[], parent: Injector|undefined, name: string) { return new StaticInjector(providers, parent, name); } export function INJECTOR_IMPL__POST_R3__( - providers: StaticProvider[], parent: Injector | undefined, name: string) { + providers: StaticProvider[], parent: Injector|undefined, name: string) { return createInjector({name: name}, parent, providers, name); } @@ -166,8 +166,9 @@ export class StaticInjector implements Injector { const providedIn = injectableDef && injectableDef.providedIn; if (providedIn === 'any' || providedIn != null && providedIn === this.scope) { records.set( - token, record = resolveProvider( - {provide: token, useFactory: injectableDef.factory, deps: EMPTY})); + token, + record = resolveProvider( + {provide: token, useFactory: injectableDef.factory, deps: EMPTY})); } } if (record === undefined) { @@ -193,7 +194,7 @@ export class StaticInjector implements Injector { } type SupportedProvider = - ValueProvider | ExistingProvider | StaticClassProvider | ConstructorProvider | FactoryProvider; + ValueProvider|ExistingProvider|StaticClassProvider|ConstructorProvider|FactoryProvider; interface Record { fn: Function; @@ -293,7 +294,7 @@ function recursivelyProcessProviders(records: Map<any, Record>, provider: Static } function tryResolveToken( - token: any, record: Record | undefined | null, records: Map<any, Record|null>, parent: Injector, + token: any, record: Record|undefined|null, records: Map<any, Record|null>, parent: Injector, notFoundValue: any, flags: InjectFlags): any { try { return resolveToken(token, record, records, parent, notFoundValue, flags); @@ -313,7 +314,7 @@ function tryResolveToken( } function resolveToken( - token: any, record: Record | undefined | null, records: Map<any, Record|null>, parent: Injector, + token: any, record: Record|undefined|null, records: Map<any, Record|null>, parent: Injector, notFoundValue: any, flags: InjectFlags): any { let value; if (record && !(flags & InjectFlags.SkipSelf)) { diff --git a/packages/core/src/di/injector_compatibility.ts b/packages/core/src/di/injector_compatibility.ts index bb420a7b23b17..2bef2aa01d486 100644 --- a/packages/core/src/di/injector_compatibility.ts +++ b/packages/core/src/di/injector_compatibility.ts @@ -33,7 +33,7 @@ import {Inject, Optional, Self, SkipSelf} from './metadata'; export const INJECTOR = new InjectionToken<Injector>( 'INJECTOR', -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. - ); +); const _THROW_IF_NOT_FOUND = {}; export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; @@ -55,7 +55,7 @@ export const USE_VALUE = */ let _currentInjector: Injector|undefined|null = undefined; -export function setCurrentInjector(injector: Injector | null | undefined): Injector|undefined|null { +export function setCurrentInjector(injector: Injector|null|undefined): Injector|undefined|null { const former = _currentInjector; _currentInjector = injector; return former; @@ -70,25 +70,25 @@ export function setCurrentInjector(injector: Injector | null | undefined): Injec * 1. `Injector` should not depend on ivy logic. * 2. To maintain tree shake-ability we don't want to bring in unnecessary code. */ -let _injectImplementation: - (<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined; +let _injectImplementation: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)| + undefined; /** * Sets the current inject implementation. */ export function setInjectImplementation( - impl: (<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null) | undefined): - (<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined { + impl: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)| + undefined): (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined { const previous = _injectImplementation; _injectImplementation = impl; return previous; } -export function injectInjectorOnly<T>(token: Type<T>| InjectionToken<T>): T; -export function injectInjectorOnly<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T| +export function injectInjectorOnly<T>(token: Type<T>|InjectionToken<T>): T; +export function injectInjectorOnly<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T| null; export function injectInjectorOnly<T>( - token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null { + token: Type<T>|InjectionToken<T>, flags = InjectFlags.Default): T|null { if (_currentInjector === undefined) { throw new Error(`inject() must be called from an injection context`); } else if (_currentInjector === null) { @@ -104,15 +104,15 @@ export function injectInjectorOnly<T>( * Must be used in the context of a factory function such as one defined for an * `InjectionToken`. Throws an error if not called from such a context. * - * (Additional documentation moved to `inject`, as it is the public API, and an alias for this instruction) + * (Additional documentation moved to `inject`, as it is the public API, and an alias for this + * instruction) * * @see inject * @codeGenApi */ -export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>): T; -export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags?: InjectFlags): T|null; -export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T| - null { +export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>): T; +export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T|null; +export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags = InjectFlags.Default): T|null { return (_injectImplementation || injectInjectorOnly)(resolveForwardRef(token), flags); } @@ -130,10 +130,12 @@ export function ɵɵinject<T>(token: Type<T>| InjectionToken<T>, flags = InjectF */ export function ɵɵinvalidFactoryDep(index: number): never { const msg = ngDevMode ? - `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${index} of the parameter list is invalid. + `This constructor is not compatible with Angular Dependency Injection because its dependency at index ${ + index} of the parameter list is invalid. This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator. -Please check that 1) the type for the parameter at index ${index} is correct and 2) the correct Angular decorators are defined for this class and its ancestors.` : +Please check that 1) the type for the parameter at index ${ + index} is correct and 2) the correct Angular decorators are defined for this class and its ancestors.` : 'invalid'; throw new Error(msg); } @@ -172,7 +174,7 @@ export const inject = ɵɵinject; * `InjectableDef`. */ export function injectRootLimpMode<T>( - token: Type<T>| InjectionToken<T>, notFoundValue: T | undefined, flags: InjectFlags): T|null { + token: Type<T>|InjectionToken<T>, notFoundValue: T|undefined, flags: InjectFlags): T|null { const injectableDef: ɵɵInjectableDef<T>|null = getInjectableDef(token); if (injectableDef && injectableDef.providedIn == 'root') { return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() : @@ -183,7 +185,7 @@ export function injectRootLimpMode<T>( throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`); } -export function injectArgs(types: (Type<any>| InjectionToken<any>| any[])[]): any[] { +export function injectArgs(types: (Type<any>|InjectionToken<any>|any[])[]): any[] { const args: any[] = []; for (let i = 0; i < types.length; i++) { const arg = resolveForwardRef(types[i]); @@ -210,7 +212,7 @@ export function injectArgs(types: (Type<any>| InjectionToken<any>| any[])[]): an } } - args.push(ɵɵinject(type !, flags)); + args.push(ɵɵinject(type!, flags)); } else { args.push(ɵɵinject(arg)); } @@ -236,7 +238,7 @@ export class NullInjector implements Injector { export function catchInjectorError( - e: any, token: any, injectorErrorName: string, source: string | null): never { + e: any, token: any, injectorErrorName: string, source: string|null): never { const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; if (token[SOURCE]) { tokenPath.unshift(token[SOURCE]); @@ -248,7 +250,7 @@ export function catchInjectorError( } export function formatError( - text: string, obj: any, injectorErrorName: string, source: string | null = null): string { + text: string, obj: any, injectorErrorName: string, source: string|null = null): string { text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; let context = stringify(obj); if (Array.isArray(obj)) { @@ -264,5 +266,6 @@ export function formatError( } context = `{${parts.join(', ')}}`; } - return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; + return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${ + text.replace(NEW_LINE, '\n ')}`; } diff --git a/packages/core/src/di/interface/defs.ts b/packages/core/src/di/interface/defs.ts index f30abbdd09bc5..b2d5bae5a84f4 100644 --- a/packages/core/src/di/interface/defs.ts +++ b/packages/core/src/di/interface/defs.ts @@ -140,13 +140,14 @@ export interface InjectorTypeWithProviders<T> { */ export function ɵɵdefineInjectable<T>(opts: { token: unknown, - providedIn?: Type<any>| 'root' | 'platform' | 'any' | null, - factory: () => T, + providedIn?: Type<any>|'root'|'platform'|'any'|null, factory: () => T, }): never { return ({ - token: opts.token, providedIn: opts.providedIn as any || null, factory: opts.factory, - value: undefined, - } as ɵɵInjectableDef<T>) as never; + token: opts.token, + providedIn: opts.providedIn as any || null, + factory: opts.factory, + value: undefined, + } as ɵɵInjectableDef<T>) as never; } /** @@ -179,8 +180,10 @@ export const defineInjectable = ɵɵdefineInjectable; export function ɵɵdefineInjector(options: {factory: () => any, providers?: any[], imports?: any[]}): never { return ({ - factory: options.factory, providers: options.providers || [], imports: options.imports || [], - } as ɵɵInjectorDef<any>) as never; + factory: options.factory, + providers: options.providers || [], + imports: options.imports || [], + } as ɵɵInjectorDef<any>) as never; } /** @@ -219,15 +222,17 @@ function getOwnDefinition<T>(type: any, def: ɵɵInjectableDef<T>): ɵɵInjectab */ export function getInheritedInjectableDef<T>(type: any): ɵɵInjectableDef<T>|null { // See `jit/injectable.ts#compileInjectable` for context on NG_PROV_DEF_FALLBACK. - const def = type && (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF] || - (type[NG_PROV_DEF_FALLBACK] && type[NG_PROV_DEF_FALLBACK]())); + const def = type && + (type[NG_PROV_DEF] || type[NG_INJECTABLE_DEF] || + (type[NG_PROV_DEF_FALLBACK] && type[NG_PROV_DEF_FALLBACK]())); if (def) { const typeName = getTypeName(type); // TODO(FW-1307): Re-add ngDevMode when closure can handle it // ngDevMode && console.warn( - `DEPRECATED: DI is instantiating a token "${typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` + + `DEPRECATED: DI is instantiating a token "${ + typeName}" that inherits its @Injectable decorator but does not provide one itself.\n` + `This will become an error in v10. Please add @Injectable() to the "${typeName}" class.`); return def; } else { diff --git a/packages/core/src/di/interface/provider.ts b/packages/core/src/di/interface/provider.ts index ec8720d089ac2..486ed494d0979 100644 --- a/packages/core/src/di/interface/provider.ts +++ b/packages/core/src/di/interface/provider.ts @@ -255,8 +255,8 @@ export interface FactoryProvider extends FactorySansProvider { * * @publicApi */ -export type StaticProvider = ValueProvider | ExistingProvider | StaticClassProvider | - ConstructorProvider | FactoryProvider | any[]; +export type StaticProvider = + ValueProvider|ExistingProvider|StaticClassProvider|ConstructorProvider|FactoryProvider|any[]; /** @@ -329,8 +329,8 @@ export interface ClassProvider extends ClassSansProvider { * * @publicApi */ -export type Provider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | - ExistingProvider | FactoryProvider | any[]; +export type Provider = TypeProvider|ValueProvider|ClassProvider|ConstructorProvider| + ExistingProvider|FactoryProvider|any[]; /** * Describes a function that is used to process provider lists (such as provider diff --git a/packages/core/src/di/jit/environment.ts b/packages/core/src/di/jit/environment.ts index d544fcc446443..a89bbf0e6901e 100644 --- a/packages/core/src/di/jit/environment.ts +++ b/packages/core/src/di/jit/environment.ts @@ -31,9 +31,9 @@ function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null { if (isForwardRef(type)) { return (() => { - const factory = getFactoryOf<T>(resolveForwardRef(typeAny)); - return factory ? factory() : null; - }) as any; + const factory = getFactoryOf<T>(resolveForwardRef(typeAny)); + return factory ? factory() : null; + }) as any; } const def = getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny); diff --git a/packages/core/src/di/jit/injectable.ts b/packages/core/src/di/jit/injectable.ts index e8419d3a470c5..e21ab787e29cc 100644 --- a/packages/core/src/di/jit/injectable.ts +++ b/packages/core/src/di/jit/injectable.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {R3InjectableMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {getCompilerFacade, R3InjectableMetadataFacade} from '../../compiler/compiler_facade'; import {Type} from '../../interface/type'; import {NG_FACTORY_DEF} from '../../render3/fields'; import {getClosureSafeProperty} from '../../util/property'; @@ -76,7 +76,7 @@ export function compileInjectable(type: Type<any>, srcMeta?: Injectable): void { } } -type UseClassProvider = Injectable & ClassSansProvider & {deps?: any[]}; +type UseClassProvider = Injectable&ClassSansProvider&{deps?: any[]}; const USE_VALUE = getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty}); diff --git a/packages/core/src/di/jit/util.ts b/packages/core/src/di/jit/util.ts index ae81dcb89bd59..ab0a61cd85180 100644 --- a/packages/core/src/di/jit/util.ts +++ b/packages/core/src/di/jit/util.ts @@ -7,7 +7,7 @@ */ import {ChangeDetectorRef} from '../../change_detection/change_detector_ref'; -import {CompilerFacade, R3DependencyMetadataFacade, R3ResolvedDependencyType, getCompilerFacade} from '../../compiler/compiler_facade'; +import {CompilerFacade, getCompilerFacade, R3DependencyMetadataFacade, R3ResolvedDependencyType} from '../../compiler/compiler_facade'; import {Type} from '../../interface/type'; import {ReflectionCapabilities} from '../../reflection/reflection_capabilities'; import {Attribute, Host, Inject, Optional, Self, SkipSelf} from '../metadata'; @@ -27,7 +27,7 @@ export function convertDependencies(deps: any[]): R3DependencyMetadataFacade[] { return deps.map(dep => reflectDependency(compiler, dep)); } -function reflectDependency(compiler: CompilerFacade, dep: any | any[]): R3DependencyMetadataFacade { +function reflectDependency(compiler: CompilerFacade, dep: any|any[]): R3DependencyMetadataFacade { const meta: R3DependencyMetadataFacade = { token: null, host: false, diff --git a/packages/core/src/di/metadata.ts b/packages/core/src/di/metadata.ts index c572f235342a6..b29c5b4ac0653 100644 --- a/packages/core/src/di/metadata.ts +++ b/packages/core/src/di/metadata.ts @@ -33,7 +33,7 @@ export interface InjectDecorator { * </code-example> */ (token: any): any; - new (token: any): Inject; + new(token: any): Inject; } /** @@ -82,7 +82,7 @@ export interface OptionalDecorator { * */ (): any; - new (): Optional; + new(): Optional; } /** @@ -128,7 +128,7 @@ export interface SelfDecorator { * */ (): any; - new (): Self; + new(): Self; } /** @@ -175,7 +175,7 @@ export interface SkipSelfDecorator { * */ (): any; - new (): SkipSelf; + new(): SkipSelf; } /** @@ -215,7 +215,7 @@ export interface HostDecorator { * </code-example> */ (): any; - new (): Host; + new(): Host; } /** @@ -262,7 +262,7 @@ export interface AttributeDecorator { * */ (name: string): any; - new (name: string): Attribute; + new(name: string): Attribute; } /** diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index 10fc23852cc5b..bbe401037c4a4 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -15,11 +15,12 @@ import {throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiPr import {FactoryFn} from '../render3/interfaces/definition'; import {deepForEach, newArray} from '../util/array_utils'; import {stringify} from '../util/stringify'; + import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; import {Injector} from './injector'; -import {INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, injectArgs, setCurrentInjector, ɵɵinject} from './injector_compatibility'; -import {InjectorType, InjectorTypeWithProviders, getInheritedInjectableDef, getInjectableDef, getInjectorDef, ɵɵInjectableDef} from './interface/defs'; +import {catchInjectorError, injectArgs, INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, setCurrentInjector, THROW_IF_NOT_FOUND, USE_VALUE, ɵɵinject} from './injector_compatibility'; +import {getInheritedInjectableDef, getInjectableDef, getInjectorDef, InjectorType, InjectorTypeWithProviders, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './interface/provider'; import {INJECTOR_SCOPE} from './scope'; @@ -29,8 +30,8 @@ import {INJECTOR_SCOPE} from './scope'; /** * Internal type for a single provider in a deep provider array. */ -type SingleProvider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | - ExistingProvider | FactoryProvider | StaticClassProvider; +type SingleProvider = TypeProvider|ValueProvider|ClassProvider|ConstructorProvider|ExistingProvider| + FactoryProvider|StaticClassProvider; /** * Marker which indicates that a value has not yet been created from the factory function. @@ -76,8 +77,8 @@ interface Record<T> { * @publicApi */ export function createInjector( - defType: /* InjectorType<any> */ any, parent: Injector | null = null, - additionalProviders: StaticProvider[] | null = null, name?: string): Injector { + defType: /* InjectorType<any> */ any, parent: Injector|null = null, + additionalProviders: StaticProvider[]|null = null, name?: string): Injector { const injector = createInjectorWithoutInjectorInstances(defType, parent, additionalProviders, name); injector._resolveInjectorDefTypes(); @@ -90,8 +91,8 @@ export function createInjector( * should be resolved at a later point by calling `_resolveInjectorDefTypes`. */ export function createInjectorWithoutInjectorInstances( - defType: /* InjectorType<any> */ any, parent: Injector | null = null, - additionalProviders: StaticProvider[] | null = null, name?: string): R3Injector { + defType: /* InjectorType<any> */ any, parent: Injector|null = null, + additionalProviders: StaticProvider[]|null = null, name?: string): R3Injector { return new R3Injector(defType, additionalProviders, parent || getNullInjector(), name); } @@ -124,7 +125,9 @@ export class R3Injector { /** * Flag indicating that this injector was previously destroyed. */ - get destroyed(): boolean { return this._destroyed; } + get destroyed(): boolean { + return this._destroyed; + } private _destroyed = false; constructor( @@ -135,9 +138,10 @@ export class R3Injector { // Start off by creating Records for every provider declared in every InjectorType // included transitively in additional providers then do the same for `def`. This order is // important because `def` may include providers that override ones in additionalProviders. - additionalProviders && deepForEach( - additionalProviders, provider => this.processProvider( - provider, def, additionalProviders)); + additionalProviders && + deepForEach( + additionalProviders, + provider => this.processProvider(provider, def, additionalProviders)); deepForEach([def], injectorDef => this.processInjectorType(injectorDef, [], dedupStack)); @@ -235,7 +239,9 @@ export class R3Injector { } /** @internal */ - _resolveInjectorDefTypes() { this.injectorDefTypes.forEach(defType => this.get(defType)); } + _resolveInjectorDefTypes() { + this.injectorDefTypes.forEach(defType => this.get(defType)); + } toString() { const tokens = <string[]>[], records = this.records; @@ -285,8 +291,8 @@ export class R3Injector { // Check for circular dependencies. if (ngDevMode && parents.indexOf(defType) !== -1) { const defName = stringify(defType); - throw new Error( - `Circular dependency in DI detected for type ${defName}. Dependency path: ${parents.map(defType => stringify(defType)).join(' > ')} > ${defName}.`); + throw new Error(`Circular dependency in DI detected for type ${defName}. Dependency path: ${ + parents.map(defType => stringify(defType)).join(' > ')} > ${defName}.`); } // Check for multiple imports of the same module @@ -335,7 +341,7 @@ export class R3Injector { for (let i = 0; i < importTypesWithProviders.length; i++) { const {ngModule, providers} = importTypesWithProviders[i]; deepForEach( - providers !, + providers!, provider => this.processProvider(provider, ngModule, providers || EMPTY_ARRAY)); } } @@ -383,11 +389,11 @@ export class R3Injector { } } else { multiRecord = makeRecord(undefined, NOT_YET, true); - multiRecord.factory = () => injectArgs(multiRecord !.multi !); + multiRecord.factory = () => injectArgs(multiRecord!.multi!); this.records.set(token, multiRecord); } token = provider; - multiRecord.multi !.push(provider); + multiRecord.multi!.push(provider); } else { const existing = this.records.get(token); if (existing && existing.multi !== undefined) { @@ -402,7 +408,7 @@ export class R3Injector { throwCyclicDependencyError(stringify(token)); } else if (record.value === NOT_YET) { record.value = CIRCULAR; - record.value = record.factory !(); + record.value = record.factory!(); } if (typeof record.value === 'object' && record.value && hasOnDestroy(record.value)) { this.onDestroy.add(record.value); @@ -421,7 +427,7 @@ export class R3Injector { } } -function injectableDefOrInjectorDefFactory(token: Type<any>| InjectionToken<any>): FactoryFn<any> { +function injectableDefOrInjectorDefFactory(token: Type<any>|InjectionToken<any>): FactoryFn<any> { // Most tokens will have an injectable def directly on them, which specifies a factory directly. const injectableDef = getInjectableDef(token); const factory = injectableDef !== null ? injectableDef.factory : getFactoryDef(token); @@ -519,7 +525,7 @@ export function providerToFactory( } function makeRecord<T>( - factory: (() => T) | undefined, value: T | {}, multi: boolean = false): Record<T> { + factory: (() => T)|undefined, value: T|{}, multi: boolean = false): Record<T> { return { factory: factory, value: value, @@ -547,14 +553,14 @@ export function isClassProvider(value: SingleProvider): value is ClassProvider { return !!(value as StaticClassProvider | ClassProvider).useClass; } -function hasDeps(value: ClassProvider | ConstructorProvider | StaticClassProvider): - value is ClassProvider&{deps: any[]} { +function hasDeps(value: ClassProvider|ConstructorProvider| + StaticClassProvider): value is ClassProvider&{deps: any[]} { return !!(value as any).deps; } function hasOnDestroy(value: any): value is OnDestroy { return value !== null && typeof value === 'object' && - typeof(value as OnDestroy).ngOnDestroy === 'function'; + typeof (value as OnDestroy).ngOnDestroy === 'function'; } function couldBeInjectableType(value: any): value is Type<any>|InjectionToken<any> { diff --git a/packages/core/src/di/reflective_errors.ts b/packages/core/src/di/reflective_errors.ts index 584b863fedf0e..4a45534f46912 100644 --- a/packages/core/src/di/reflective_errors.ts +++ b/packages/core/src/di/reflective_errors.ts @@ -143,7 +143,8 @@ export function instantiationError( key: ReflectiveKey): InjectionError { return injectionError(injector, key, function(keys: ReflectiveKey[]) { const first = stringify(keys[0].token); - return `${originalException.message}: Error during instantiation of ${first}!${constructResolvingPath(keys)}.`; + return `${originalException.message}: Error during instantiation of ${first}!${ + constructResolvingPath(keys)}.`; }, originalException); } @@ -193,7 +194,7 @@ export function invalidProviderError(provider: any) { * ``` * */ -export function noAnnotationError(typeOrFunc: Type<any>| Function, params: any[][]): Error { +export function noAnnotationError(typeOrFunc: Type<any>|Function, params: any[][]): Error { const signature: string[] = []; for (let i = 0, ii = params.length; i < ii; i++) { const parameter = params[i]; diff --git a/packages/core/src/di/reflective_injector.ts b/packages/core/src/di/reflective_injector.ts index 6b979b8f4df41..c6c5d30a78cd4 100644 --- a/packages/core/src/di/reflective_injector.ts +++ b/packages/core/src/di/reflective_injector.ts @@ -308,7 +308,7 @@ export class ReflectiveInjector_ implements ReflectiveInjector { createChildFromResolved(providers: ResolvedReflectiveProvider[]): ReflectiveInjector { const inj = new ReflectiveInjector_(providers); - (inj as{parent: Injector | null}).parent = this; + (inj as {parent: Injector | null}).parent = this; return inj; } @@ -335,7 +335,9 @@ export class ReflectiveInjector_ implements ReflectiveInjector { return this._instantiateProvider(provider); } - private _getMaxNumberOfObjects(): number { return this.objs.length; } + private _getMaxNumberOfObjects(): number { + return this.objs.length; + } private _instantiateProvider(provider: ResolvedReflectiveProvider): any { if (provider.multiProvider) { @@ -451,7 +453,9 @@ export class ReflectiveInjector_ implements ReflectiveInjector { return `ReflectiveInjector(providers: [${providers}])`; } - toString(): string { return this.displayName; } + toString(): string { + return this.displayName; + } } function _mapProviders(injector: ReflectiveInjector_, fn: Function): any[] { diff --git a/packages/core/src/di/reflective_key.ts b/packages/core/src/di/reflective_key.ts index f7219f60f57d0..6de91cad9bcb2 100644 --- a/packages/core/src/di/reflective_key.ts +++ b/packages/core/src/di/reflective_key.ts @@ -50,7 +50,9 @@ export class ReflectiveKey { /** * @returns the number of keys registered in the system. */ - static get numberOfKeys(): number { return _globalKeyRegistry.numberOfKeys; } + static get numberOfKeys(): number { + return _globalKeyRegistry.numberOfKeys; + } } export class KeyRegistry { @@ -60,7 +62,7 @@ export class KeyRegistry { if (token instanceof ReflectiveKey) return token; if (this._allKeys.has(token)) { - return this._allKeys.get(token) !; + return this._allKeys.get(token)!; } const newKey = new ReflectiveKey(token, ReflectiveKey.numberOfKeys); @@ -68,7 +70,9 @@ export class KeyRegistry { return newKey; } - get numberOfKeys(): number { return this._allKeys.size; } + get numberOfKeys(): number { + return this._allKeys.size; + } } const _globalKeyRegistry = new KeyRegistry(); diff --git a/packages/core/src/di/reflective_provider.ts b/packages/core/src/di/reflective_provider.ts index 11ff4445552b9..c794bfb878d27 100644 --- a/packages/core/src/di/reflective_provider.ts +++ b/packages/core/src/di/reflective_provider.ts @@ -18,7 +18,7 @@ import {ReflectiveKey} from './reflective_key'; interface NormalizedProvider extends TypeProvider, ValueProvider, ClassProvider, ExistingProvider, - FactoryProvider {} + FactoryProvider {} /** * `Dependency` is used by the framework to extend DI. @@ -184,7 +184,7 @@ function _normalizeProviders( providers: Provider[], res: NormalizedProvider[]): NormalizedProvider[] { providers.forEach(b => { if (b instanceof Type) { - res.push({ provide: b, useClass: b } as NormalizedProvider); + res.push({provide: b, useClass: b} as NormalizedProvider); } else if (b && typeof b == 'object' && (b as any).provide !== undefined) { res.push(b as NormalizedProvider); @@ -221,7 +221,7 @@ function _dependenciesFor(typeOrFunc: any): ReflectiveDependency[] { } function _extractToken( - typeOrFunc: any, metadata: any[] | any, params: any[][]): ReflectiveDependency { + typeOrFunc: any, metadata: any[]|any, params: any[][]): ReflectiveDependency { let token: any = null; let optional = false; @@ -264,6 +264,6 @@ function _extractToken( } function _createDependency( - token: any, optional: boolean, visibility: Self | SkipSelf | null): ReflectiveDependency { + token: any, optional: boolean, visibility: Self|SkipSelf|null): ReflectiveDependency { return new ReflectiveDependency(ReflectiveKey.get(token), optional, visibility); } diff --git a/packages/core/src/di/util.ts b/packages/core/src/di/util.ts index 32b5bc595365a..dd5bf2c0aed8e 100644 --- a/packages/core/src/di/util.ts +++ b/packages/core/src/di/util.ts @@ -19,8 +19,9 @@ const USE_VALUE = const EMPTY_ARRAY: any[] = []; export function convertInjectableProviderToFactory( - type: Type<any>, provider?: ValueSansProvider | ExistingSansProvider | StaticClassSansProvider | - ConstructorSansProvider | FactorySansProvider | ClassSansProvider): () => any { + type: Type<any>, + provider?: ValueSansProvider|ExistingSansProvider|StaticClassSansProvider| + ConstructorSansProvider|FactorySansProvider|ClassSansProvider): () => any { if (!provider) { const reflectionCapabilities = new ReflectionCapabilities(); const deps = reflectionCapabilities.parameters(type); @@ -51,6 +52,6 @@ export function convertInjectableProviderToFactory( const reflectionCapabilities = new ReflectionCapabilities(); deps = reflectionCapabilities.parameters(type); } - return () => new type(...injectArgs(deps !)); + return () => new type(...injectArgs(deps!)); } } diff --git a/packages/core/src/event_emitter.ts b/packages/core/src/event_emitter.ts index 07143d9774a9e..02397f378d62e 100644 --- a/packages/core/src/event_emitter.ts +++ b/packages/core/src/event_emitter.ts @@ -83,7 +83,9 @@ export class EventEmitter<T extends any> extends Subject<T> { * Emits an event containing a given value. * @param value The value to emit. */ - emit(value?: T) { super.next(value); } + emit(value?: T) { + super.next(value); + } /** * Registers handlers for events emitted by this instance. @@ -101,29 +103,46 @@ export class EventEmitter<T extends any> extends Subject<T> { if (generatorOrNext && typeof generatorOrNext === 'object') { schedulerFn = this.__isAsync ? (value: any) => { setTimeout(() => generatorOrNext.next(value)); - } : (value: any) => { generatorOrNext.next(value); }; + } : (value: any) => { + generatorOrNext.next(value); + }; if (generatorOrNext.error) { - errorFn = this.__isAsync ? (err) => { setTimeout(() => generatorOrNext.error(err)); } : - (err) => { generatorOrNext.error(err); }; + errorFn = this.__isAsync ? (err) => { + setTimeout(() => generatorOrNext.error(err)); + } : (err) => { + generatorOrNext.error(err); + }; } if (generatorOrNext.complete) { - completeFn = this.__isAsync ? () => { setTimeout(() => generatorOrNext.complete()); } : - () => { generatorOrNext.complete(); }; + completeFn = this.__isAsync ? () => { + setTimeout(() => generatorOrNext.complete()); + } : () => { + generatorOrNext.complete(); + }; } } else { - schedulerFn = this.__isAsync ? (value: any) => { setTimeout(() => generatorOrNext(value)); } : - (value: any) => { generatorOrNext(value); }; + schedulerFn = this.__isAsync ? (value: any) => { + setTimeout(() => generatorOrNext(value)); + } : (value: any) => { + generatorOrNext(value); + }; if (error) { - errorFn = - this.__isAsync ? (err) => { setTimeout(() => error(err)); } : (err) => { error(err); }; + errorFn = this.__isAsync ? (err) => { + setTimeout(() => error(err)); + } : (err) => { + error(err); + }; } if (complete) { - completeFn = - this.__isAsync ? () => { setTimeout(() => complete()); } : () => { complete(); }; + completeFn = this.__isAsync ? () => { + setTimeout(() => complete()); + } : () => { + complete(); + }; } } diff --git a/packages/core/src/i18n/locale_data_api.ts b/packages/core/src/i18n/locale_data_api.ts index 63816bba38eea..75c9082080054 100644 --- a/packages/core/src/i18n/locale_data_api.ts +++ b/packages/core/src/i18n/locale_data_api.ts @@ -5,9 +5,10 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import localeEn from './locale_en'; import {global} from '../util/global'; +import localeEn from './locale_en'; + /** * This const is used to store the locale data registered with `registerLocaleData` */ @@ -19,7 +20,7 @@ let LOCALE_DATA: {[localeId: string]: any} = {}; * * The signature `registerLocaleData(data: any, extraData?: any)` is deprecated since v5.1 */ -export function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void { +export function registerLocaleData(data: any, localeId?: string|any, extraData?: any): void { if (typeof localeId !== 'string') { extraData = localeId; localeId = data[LocaleDataIndex.LocaleId]; @@ -151,7 +152,11 @@ export const enum ExtraLocaleDataIndex { /** * Index of each value in currency data (used to describe CURRENCIES_EN in currencies.ts) */ -export const enum CurrencyIndex {Symbol = 0, SymbolNarrow, NbOfDigits} +export const enum CurrencyIndex { + Symbol = 0, + SymbolNarrow, + NbOfDigits +} /** * Returns the canonical form of a locale name - lowercase with `_` replaced with `-`. diff --git a/packages/core/src/interface/lifecycle_hooks.ts b/packages/core/src/interface/lifecycle_hooks.ts index 0beb6d97086eb..45414583a9397 100644 --- a/packages/core/src/interface/lifecycle_hooks.ts +++ b/packages/core/src/interface/lifecycle_hooks.ts @@ -90,12 +90,12 @@ export interface OnInit { */ export interface DoCheck { /** - * A callback method that performs change-detection, invoked - * after the default change-detector runs. - * See `KeyValueDiffers` and `IterableDiffers` for implementing - * custom change checking for collections. - * - */ + * A callback method that performs change-detection, invoked + * after the default change-detector runs. + * See `KeyValueDiffers` and `IterableDiffers` for implementing + * custom change checking for collections. + * + */ ngDoCheck(): void; } diff --git a/packages/core/src/interface/simple_change.ts b/packages/core/src/interface/simple_change.ts index 6152cbd7ad506..081967868e54f 100644 --- a/packages/core/src/interface/simple_change.ts +++ b/packages/core/src/interface/simple_change.ts @@ -20,7 +20,9 @@ export class SimpleChange { /** * Check whether the new value is the first value assigned. */ - isFirstChange(): boolean { return this.firstChange; } + isFirstChange(): boolean { + return this.firstChange; + } } /** @@ -32,4 +34,6 @@ export class SimpleChange { * * @publicApi */ -export interface SimpleChanges { [propName: string]: SimpleChange; } +export interface SimpleChanges { + [propName: string]: SimpleChange; +} diff --git a/packages/core/src/interface/type.ts b/packages/core/src/interface/type.ts index e8b0188042593..a8c3f6a51be09 100644 --- a/packages/core/src/interface/type.ts +++ b/packages/core/src/interface/type.ts @@ -30,11 +30,15 @@ export function isType(v: any): v is Type<any> { * * @publicApi */ -export interface AbstractType<T> extends Function { prototype: T; } +export interface AbstractType<T> extends Function { + prototype: T; +} -export interface Type<T> extends Function { new (...args: any[]): T; } +export interface Type<T> extends Function { + new(...args: any[]): T; +} -export type Mutable<T extends{[x: string]: any}, K extends string> = { +export type Mutable<T extends {[x: string]: any}, K extends string> = { [P in K]: T[P]; }; diff --git a/packages/core/src/linker.ts b/packages/core/src/linker.ts index b3b25b222ece8..4e34360e945f3 100644 --- a/packages/core/src/linker.ts +++ b/packages/core/src/linker.ts @@ -7,12 +7,12 @@ */ // Public API for compiler -export {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, ModuleWithComponentFactories} from './linker/compiler'; +export {Compiler, COMPILER_OPTIONS, CompilerFactory, CompilerOptions, ModuleWithComponentFactories} from './linker/compiler'; export {ComponentFactory, ComponentRef} from './linker/component_factory'; export {ComponentFactoryResolver} from './linker/component_factory_resolver'; export {ElementRef} from './linker/element_ref'; export {NgModuleFactory, NgModuleRef} from './linker/ng_module_factory'; -export {NgModuleFactoryLoader, getModuleFactory} from './linker/ng_module_factory_loader'; +export {getModuleFactory, NgModuleFactoryLoader} from './linker/ng_module_factory_loader'; export {QueryList} from './linker/query_list'; export {SystemJsNgModuleLoader, SystemJsNgModuleLoaderConfig} from './linker/system_js_ng_module_factory_loader'; export {TemplateRef} from './linker/template_ref'; diff --git a/packages/core/src/linker/compiler.ts b/packages/core/src/linker/compiler.ts index c6ad53f774d96..8d063b5e44834 100644 --- a/packages/core/src/linker/compiler.ts +++ b/packages/core/src/linker/compiler.ts @@ -60,7 +60,7 @@ export const Compiler_compileModuleAndAllComponentsSync__POST_R3__: <T>(moduleTy ModuleWithComponentFactories<T> = function<T>(moduleType: Type<T>): ModuleWithComponentFactories<T> { const ngModuleFactory = Compiler_compileModuleSync__POST_R3__(moduleType); - const moduleDef = getNgModuleDef(moduleType) !; + const moduleDef = getNgModuleDef(moduleType)!; const componentFactories = maybeUnwrapFn(moduleDef.declarations) .reduce((factories: ComponentFactory<any>[], declaration: Type<any>) => { @@ -133,7 +133,9 @@ export class Compiler { /** * Returns the id for a given NgModule, if one is defined and known to the compiler. */ - getModuleId(moduleType: Type<any>): string|undefined { return undefined; } + getModuleId(moduleType: Type<any>): string|undefined { + return undefined; + } } /** diff --git a/packages/core/src/linker/component_factory_resolver.ts b/packages/core/src/linker/component_factory_resolver.ts index 90cdd073cf960..6d84307ddd9fb 100644 --- a/packages/core/src/linker/component_factory_resolver.ts +++ b/packages/core/src/linker/component_factory_resolver.ts @@ -14,8 +14,8 @@ import {ComponentFactory, ComponentRef} from './component_factory'; import {NgModuleRef} from './ng_module_factory'; export function noComponentFactoryError(component: Function) { - const error = Error( - `No component factory found for ${stringify(component)}. Did you add it to @NgModule.entryComponents?`); + const error = Error(`No component factory found for ${ + stringify(component)}. Did you add it to @NgModule.entryComponents?`); (error as any)[ERROR_COMPONENT] = component; return error; } @@ -28,7 +28,7 @@ export function getComponent(error: Error): Type<any> { class _NullComponentFactoryResolver implements ComponentFactoryResolver { - resolveComponentFactory<T>(component: {new (...args: any[]): T}): ComponentFactory<T> { + resolveComponentFactory<T>(component: {new(...args: any[]): T}): ComponentFactory<T> { throw noComponentFactoryError(component); } } @@ -63,7 +63,7 @@ export class CodegenComponentFactoryResolver implements ComponentFactoryResolver } } - resolveComponentFactory<T>(component: {new (...args: any[]): T}): ComponentFactory<T> { + resolveComponentFactory<T>(component: {new(...args: any[]): T}): ComponentFactory<T> { let factory = this._factories.get(component); if (!factory && this._parent) { factory = this._parent.resolveComponentFactory(component); diff --git a/packages/core/src/linker/element_ref.ts b/packages/core/src/linker/element_ref.ts index 81eb088558b18..c357e307a33d3 100644 --- a/packages/core/src/linker/element_ref.ts +++ b/packages/core/src/linker/element_ref.ts @@ -48,7 +48,9 @@ export class ElementRef<T extends any = any> { */ public nativeElement: T; - constructor(nativeElement: T) { this.nativeElement = nativeElement; } + constructor(nativeElement: T) { + this.nativeElement = nativeElement; + } /** * @internal diff --git a/packages/core/src/linker/ng_module_factory_loader.ts b/packages/core/src/linker/ng_module_factory_loader.ts index 2f6f710c6e08b..717a3ab8821d5 100644 --- a/packages/core/src/linker/ng_module_factory_loader.ts +++ b/packages/core/src/linker/ng_module_factory_loader.ts @@ -43,6 +43,8 @@ export function getModuleFactory__POST_R3__(id: string): NgModuleFactory<any> { */ export const getModuleFactory: (id: string) => NgModuleFactory<any> = getModuleFactory__PRE_R3__; -function noModuleError(id: string, ): Error { +function noModuleError( + id: string, + ): Error { return new Error(`No module with ID ${id} loaded`); } diff --git a/packages/core/src/linker/ng_module_factory_registration.ts b/packages/core/src/linker/ng_module_factory_registration.ts index 3008d8434a825..639a772fb6e91 100644 --- a/packages/core/src/linker/ng_module_factory_registration.ts +++ b/packages/core/src/linker/ng_module_factory_registration.ts @@ -32,7 +32,7 @@ export function registerModuleFactory(id: string, factory: NgModuleFactory<any>) modules.set(id, factory); } -function assertSameOrNotExisting(id: string, type: Type<any>| null, incoming: Type<any>): void { +function assertSameOrNotExisting(id: string, type: Type<any>|null, incoming: Type<any>): void { if (type && type !== incoming) { throw new Error( `Duplicate module registered for ${id} - ${stringify(type)} vs ${stringify(type.name)}`); diff --git a/packages/core/src/linker/query_list.ts b/packages/core/src/linker/query_list.ts index f89d35cd42200..855ad74c3e9c9 100644 --- a/packages/core/src/linker/query_list.ts +++ b/packages/core/src/linker/query_list.ts @@ -13,7 +13,7 @@ import {flatten} from '../util/array_utils'; import {getSymbolIterator} from '../util/symbol'; function symbolIterator<T>(this: QueryList<T>): Iterator<T> { - return ((this as any as{_results: Array<T>})._results as any)[getSymbolIterator()](); + return ((this as any as {_results: Array<T>})._results as any)[getSymbolIterator()](); } /** @@ -49,9 +49,9 @@ export class QueryList<T> implements Iterable<T> { readonly length: number = 0; // TODO(issue/24571): remove '!'. - readonly first !: T; + readonly first!: T; // TODO(issue/24571): remove '!'. - readonly last !: T; + readonly last!: T; constructor() { // This function should be declared on the prototype, but doing so there will cause the class @@ -67,7 +67,9 @@ export class QueryList<T> implements Iterable<T> { * See * [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) */ - map<U>(fn: (item: T, index: number, array: T[]) => U): U[] { return this._results.map(fn); } + map<U>(fn: (item: T, index: number, array: T[]) => U): U[] { + return this._results.map(fn); + } /** * See @@ -97,7 +99,9 @@ export class QueryList<T> implements Iterable<T> { * See * [Array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) */ - forEach(fn: (item: T, index: number, array: T[]) => void): void { this._results.forEach(fn); } + forEach(fn: (item: T, index: number, array: T[]) => void): void { + this._results.forEach(fn); + } /** * See @@ -110,9 +114,13 @@ export class QueryList<T> implements Iterable<T> { /** * Returns a copy of the internal results list as an Array. */ - toArray(): T[] { return this._results.slice(); } + toArray(): T[] { + return this._results.slice(); + } - toString(): string { return this._results.toString(); } + toString(): string { + return this._results.toString(); + } /** * Updates the stored data of the query list, and resets the `dirty` flag to `false`, so that @@ -123,19 +131,23 @@ export class QueryList<T> implements Iterable<T> { */ reset(resultsTree: Array<T|any[]>): void { this._results = flatten(resultsTree); - (this as{dirty: boolean}).dirty = false; - (this as{length: number}).length = this._results.length; - (this as{last: T}).last = this._results[this.length - 1]; - (this as{first: T}).first = this._results[0]; + (this as {dirty: boolean}).dirty = false; + (this as {length: number}).length = this._results.length; + (this as {last: T}).last = this._results[this.length - 1]; + (this as {first: T}).first = this._results[0]; } /** * Triggers a change event by emitting on the `changes` {@link EventEmitter}. */ - notifyOnChanges(): void { (this.changes as EventEmitter<any>).emit(this); } + notifyOnChanges(): void { + (this.changes as EventEmitter<any>).emit(this); + } /** internal */ - setDirty() { (this as{dirty: boolean}).dirty = true; } + setDirty() { + (this as {dirty: boolean}).dirty = true; + } /** internal */ destroy(): void { @@ -148,5 +160,5 @@ export class QueryList<T> implements Iterable<T> { // there) and this declaration is left here to ensure that TypeScript considers QueryList to // implement the Iterable interface. This is required for template type-checking of NgFor loops // over QueryLists to work correctly, since QueryList must be assignable to NgIterable. - [Symbol.iterator] !: () => Iterator<T>; + [Symbol.iterator]!: () => Iterator<T>; } diff --git a/packages/core/src/linker/system_js_ng_module_factory_loader.ts b/packages/core/src/linker/system_js_ng_module_factory_loader.ts index 6221d6733377c..9b0075807c588 100644 --- a/packages/core/src/linker/system_js_ng_module_factory_loader.ts +++ b/packages/core/src/linker/system_js_ng_module_factory_loader.ts @@ -32,13 +32,13 @@ export abstract class SystemJsNgModuleLoaderConfig { * Prefix to add when computing the name of the factory module for a given module name. */ // TODO(issue/24571): remove '!'. - factoryPathPrefix !: string; + factoryPathPrefix!: string; /** * Suffix to add when computing the name of the factory module for a given module name. */ // TODO(issue/24571): remove '!'. - factoryPathSuffix !: string; + factoryPathSuffix!: string; } const DEFAULT_CONFIG: SystemJsNgModuleLoaderConfig = { diff --git a/packages/core/src/metadata/di.ts b/packages/core/src/metadata/di.ts index 3702f4e60b8af..fd7c10b799df1 100644 --- a/packages/core/src/metadata/di.ts +++ b/packages/core/src/metadata/di.ts @@ -75,7 +75,7 @@ export interface AttributeDecorator { * @publicApi */ (name: string): any; - new (name: string): Attribute; + new(name: string): Attribute; } @@ -158,7 +158,7 @@ export interface ContentChildrenDecorator { * @Annotation */ (selector: Type<any>|Function|string, opts?: {descendants?: boolean, read?: any}): any; - new (selector: Type<any>|Function|string, opts?: {descendants?: boolean, read?: any}): Query; + new(selector: Type<any>|Function|string, opts?: {descendants?: boolean, read?: any}): Query; } /** @@ -219,7 +219,7 @@ export interface ContentChildDecorator { * @Annotation */ (selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): any; - new (selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): ContentChild; + new(selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): ContentChild; } /** @@ -238,8 +238,9 @@ export type ContentChild = Query; * @publicApi */ export const ContentChild: ContentChildDecorator = makePropDecorator( - 'ContentChild', (selector?: any, data: any = {}) => - ({selector, first: true, isViewQuery: false, descendants: true, ...data}), + 'ContentChild', + (selector?: any, data: any = {}) => + ({selector, first: true, isViewQuery: false, descendants: true, ...data}), Query); /** @@ -275,7 +276,7 @@ export interface ViewChildrenDecorator { * @Annotation */ (selector: Type<any>|Function|string, opts?: {read?: any}): any; - new (selector: Type<any>|Function|string, opts?: {read?: any}): ViewChildren; + new(selector: Type<any>|Function|string, opts?: {read?: any}): ViewChildren; } /** @@ -292,8 +293,9 @@ export type ViewChildren = Query; * @publicApi */ export const ViewChildren: ViewChildrenDecorator = makePropDecorator( - 'ViewChildren', (selector?: any, data: any = {}) => - ({selector, first: false, isViewQuery: true, descendants: true, ...data}), + 'ViewChildren', + (selector?: any, data: any = {}) => + ({selector, first: false, isViewQuery: true, descendants: true, ...data}), Query); /** @@ -342,7 +344,7 @@ export interface ViewChildDecorator { * @Annotation */ (selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): any; - new (selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): ViewChild; + new(selector: Type<any>|Function|string, opts?: {read?: any, static?: boolean}): ViewChild; } /** @@ -359,6 +361,7 @@ export type ViewChild = Query; * @publicApi */ export const ViewChild: ViewChildDecorator = makePropDecorator( - 'ViewChild', (selector: any, data: any) => - ({selector, first: true, isViewQuery: true, descendants: true, ...data}), + 'ViewChild', + (selector: any, data: any) => + ({selector, first: true, isViewQuery: true, descendants: true, ...data}), Query); diff --git a/packages/core/src/metadata/directives.ts b/packages/core/src/metadata/directives.ts index 08646edc27fbc..74cda20f57def 100644 --- a/packages/core/src/metadata/directives.ts +++ b/packages/core/src/metadata/directives.ts @@ -11,7 +11,7 @@ import {Provider} from '../di'; import {Type} from '../interface/type'; import {compileComponent as render3CompileComponent, compileDirective as render3CompileDirective} from '../render3/jit/directive'; import {compilePipe as render3CompilePipe} from '../render3/jit/pipe'; -import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators'; +import {makeDecorator, makePropDecorator, TypeDecorator} from '../util/decorators'; import {noop} from '../util/noop'; import {ViewEncapsulation} from './view'; @@ -73,7 +73,7 @@ export interface DirectiveDecorator { /** * See the `Directive` decorator. */ - new (obj?: Directive): Directive; + new(obj?: Directive): Directive; } /** @@ -445,7 +445,7 @@ export interface ComponentDecorator { /** * See the `Component` decorator. */ - new (obj: Component): Component; + new(obj: Component): Component; } /** @@ -598,7 +598,7 @@ export interface PipeDecorator { /** * See the `Pipe` decorator. */ - new (obj: Pipe): Pipe; + new(obj: Pipe): Pipe; } /** @@ -641,52 +641,52 @@ export const Pipe: PipeDecorator = makeDecorator( */ export interface InputDecorator { /** - * Decorator that marks a class field as an input property and supplies configuration metadata. - * The input property is bound to a DOM property in the template. During change detection, - * Angular automatically updates the data property with the DOM property's value. - * - * @usageNotes - * - * You can supply an optional name to use in templates when the - * component is instantiated, that maps to the - * name of the bound property. By default, the original - * name of the bound property is used for input binding. - * - * The following example creates a component with two input properties, - * one of which is given a special binding name. - * - * ```typescript - * @Component({ - * selector: 'bank-account', - * template: ` - * Bank Name: {{bankName}} - * Account Id: {{id}} - * ` - * }) - * class BankAccount { - * // This property is bound using its original name. - * @Input() bankName: string; - * // this property value is bound to a different property name - * // when this component is instantiated in a template. - * @Input('account-id') id: string; - * - * // this property is not bound, and is not automatically updated by Angular - * normalizedBankName: string; - * } - * - * @Component({ - * selector: 'app', - * template: ` - * <bank-account bankName="RBC" account-id="4747"></bank-account> - * ` - * }) - * class App {} - * ``` - * - * @see [Input and Output properties](guide/template-syntax#input-and-output-properties) - */ + * Decorator that marks a class field as an input property and supplies configuration metadata. + * The input property is bound to a DOM property in the template. During change detection, + * Angular automatically updates the data property with the DOM property's value. + * + * @usageNotes + * + * You can supply an optional name to use in templates when the + * component is instantiated, that maps to the + * name of the bound property. By default, the original + * name of the bound property is used for input binding. + * + * The following example creates a component with two input properties, + * one of which is given a special binding name. + * + * ```typescript + * @Component({ + * selector: 'bank-account', + * template: ` + * Bank Name: {{bankName}} + * Account Id: {{id}} + * ` + * }) + * class BankAccount { + * // This property is bound using its original name. + * @Input() bankName: string; + * // this property value is bound to a different property name + * // when this component is instantiated in a template. + * @Input('account-id') id: string; + * + * // this property is not bound, and is not automatically updated by Angular + * normalizedBankName: string; + * } + * + * @Component({ + * selector: 'app', + * template: ` + * <bank-account bankName="RBC" account-id="4747"></bank-account> + * ` + * }) + * class App {} + * ``` + * + * @see [Input and Output properties](guide/template-syntax#input-and-output-properties) + */ (bindingPropertyName?: string): any; - new (bindingPropertyName?: string): any; + new(bindingPropertyName?: string): any; } /** @@ -715,23 +715,23 @@ export const Input: InputDecorator = */ export interface OutputDecorator { /** - * Decorator that marks a class field as an output property and supplies configuration metadata. - * The DOM property bound to the output property is automatically updated during change detection. - * - * @usageNotes - * - * You can supply an optional name to use in templates when the - * component is instantiated, that maps to the - * name of the bound property. By default, the original - * name of the bound property is used for output binding. - * - * See `Input` decorator for an example of providing a binding name. - * - * @see [Input and Output properties](guide/template-syntax#input-and-output-properties) - * - */ + * Decorator that marks a class field as an output property and supplies configuration metadata. + * The DOM property bound to the output property is automatically updated during change detection. + * + * @usageNotes + * + * You can supply an optional name to use in templates when the + * component is instantiated, that maps to the + * name of the bound property. By default, the original + * name of the bound property is used for output binding. + * + * See `Input` decorator for an example of providing a binding name. + * + * @see [Input and Output properties](guide/template-syntax#input-and-output-properties) + * + */ (bindingPropertyName?: string): any; - new (bindingPropertyName?: string): any; + new(bindingPropertyName?: string): any; } /** @@ -741,8 +741,8 @@ export interface OutputDecorator { */ export interface Output { /** - * The name of the DOM property to which the output property is bound. - */ + * The name of the DOM property to which the output property is bound. + */ bindingPropertyName?: string; } @@ -791,7 +791,7 @@ export interface HostBindingDecorator { * */ (hostPropertyName?: string): any; - new (hostPropertyName?: string): any; + new(hostPropertyName?: string): any; } /** @@ -825,7 +825,7 @@ export interface HostListenerDecorator { * and provides a handler method to run when that event occurs. */ (eventName: string, args?: string[]): any; - new (eventName: string, args?: string[]): any; + new(eventName: string, args?: string[]): any; } /** diff --git a/packages/core/src/metadata/ng_module.ts b/packages/core/src/metadata/ng_module.ts index 9a8303228ae65..2d947c53fc3c7 100644 --- a/packages/core/src/metadata/ng_module.ts +++ b/packages/core/src/metadata/ng_module.ts @@ -13,7 +13,7 @@ import {convertInjectableProviderToFactory} from '../di/util'; import {Type} from '../interface/type'; import {SchemaMetadata} from '../metadata/schema'; import {compileNgModule as render3CompileNgModule} from '../render3/jit/module'; -import {TypeDecorator, makeDecorator} from '../util/decorators'; +import {makeDecorator, TypeDecorator} from '../util/decorators'; /** @@ -107,7 +107,7 @@ export interface NgModuleDecorator { * Decorator that marks a class as an NgModule and supplies configuration metadata. */ (obj?: NgModule): TypeDecorator; - new (obj?: NgModule): NgModule; + new(obj?: NgModule): NgModule; } /** @@ -345,7 +345,9 @@ export const NgModule: NgModuleDecorator = makeDecorator( * * @publicApi */ -export interface DoBootstrap { ngDoBootstrap(appRef: ApplicationRef): void; } +export interface DoBootstrap { + ngDoBootstrap(appRef: ApplicationRef): void; +} function preR3NgModuleCompile(moduleType: Type<any>, metadata?: NgModule): void { let imports = (metadata && metadata.imports) || []; diff --git a/packages/core/src/metadata/resource_loading.ts b/packages/core/src/metadata/resource_loading.ts index 0aed1c1cd381a..e1b8bc7eb76c3 100644 --- a/packages/core/src/metadata/resource_loading.ts +++ b/packages/core/src/metadata/resource_loading.ts @@ -122,7 +122,7 @@ export function isComponentResourceResolutionQueueEmpty() { return componentResourceResolutionQueue.size === 0; } -function unwrapResponse(response: string | {text(): Promise<string>}): string|Promise<string> { +function unwrapResponse(response: string|{text(): Promise<string>}): string|Promise<string> { return typeof response == 'string' ? response : response.text(); } diff --git a/packages/core/src/metadata/schema.ts b/packages/core/src/metadata/schema.ts index 54c3d56dbe56e..7fa3e3f1b0a73 100644 --- a/packages/core/src/metadata/schema.ts +++ b/packages/core/src/metadata/schema.ts @@ -16,7 +16,9 @@ * * @publicApi */ -export interface SchemaMetadata { name: string; } +export interface SchemaMetadata { + name: string; +} /** * Defines a schema that allows an NgModule to contain the following: diff --git a/packages/core/src/platform_core_providers.ts b/packages/core/src/platform_core_providers.ts index aeae1d103a414..2d8e7d38fc28b 100644 --- a/packages/core/src/platform_core_providers.ts +++ b/packages/core/src/platform_core_providers.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {PlatformRef, createPlatformFactory} from './application_ref'; +import {createPlatformFactory, PlatformRef} from './application_ref'; import {PLATFORM_ID} from './application_tokens'; import {Console} from './console'; import {Injector, StaticProvider} from './di'; diff --git a/packages/core/src/r3_symbols.ts b/packages/core/src/r3_symbols.ts index 66771f54db9a6..28833b367bf1b 100644 --- a/packages/core/src/r3_symbols.ts +++ b/packages/core/src/r3_symbols.ts @@ -22,7 +22,7 @@ */ export {ɵɵinject} from './di/injector_compatibility'; -export {ɵɵInjectableDef, ɵɵInjectorDef, ɵɵdefineInjectable, ɵɵdefineInjector} from './di/interface/defs'; +export {ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵInjectableDef, ɵɵInjectorDef} from './di/interface/defs'; export {NgModuleDef, ɵɵNgModuleDefWithMeta} from './metadata/ng_module'; export {ɵɵdefineNgModule} from './render3/definition'; export {ɵɵFactoryDef} from './render3/interfaces/definition'; diff --git a/packages/core/src/reflection/reflection_capabilities.ts b/packages/core/src/reflection/reflection_capabilities.ts index 0aac8ca00cedc..32a5112659c7f 100644 --- a/packages/core/src/reflection/reflection_capabilities.ts +++ b/packages/core/src/reflection/reflection_capabilities.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {Type, isType} from '../interface/type'; +import {isType, Type} from '../interface/type'; import {newArray} from '../util/array_utils'; import {ANNOTATIONS, PARAMETERS, PROP_METADATA} from '../util/decorators'; import {global} from '../util/global'; import {stringify} from '../util/stringify'; + import {PlatformReflectionCapabilities} from './platform_reflection_capabilities'; import {GetterFn, MethodFn, SetterFn} from './types'; @@ -42,11 +43,17 @@ export function isDelegateCtor(typeStr: string): boolean { export class ReflectionCapabilities implements PlatformReflectionCapabilities { private _reflect: any; - constructor(reflect?: any) { this._reflect = reflect || global['Reflect']; } + constructor(reflect?: any) { + this._reflect = reflect || global['Reflect']; + } - isReflectionEnabled(): boolean { return true; } + isReflectionEnabled(): boolean { + return true; + } - factory<T>(t: Type<T>): (args: any[]) => T { return (...args: any[]) => new t(...args); } + factory<T>(t: Type<T>): (args: any[]) => T { + return (...args: any[]) => new t(...args); + } /** @internal */ _zipTypesAndAnnotations(paramTypes: any[], paramAnnotations: any[]): any[][] { @@ -235,9 +242,13 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities { return type instanceof Type && lcProperty in type.prototype; } - guards(type: any): {[key: string]: any} { return {}; } + guards(type: any): {[key: string]: any} { + return {}; + } - getter(name: string): GetterFn { return <GetterFn>new Function('o', 'return o.' + name + ';'); } + getter(name: string): GetterFn { + return <GetterFn>new Function('o', 'return o.' + name + ';'); + } setter(name: string): SetterFn { return <SetterFn>new Function('o', 'v', 'return o.' + name + ' = v;'); @@ -259,12 +270,16 @@ export class ReflectionCapabilities implements PlatformReflectionCapabilities { return `./${stringify(type)}`; } - resourceUri(type: any): string { return `./${stringify(type)}`; } + resourceUri(type: any): string { + return `./${stringify(type)}`; + } resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any { return runtime; } - resolveEnum(enumIdentifier: any, name: string): any { return enumIdentifier[name]; } + resolveEnum(enumIdentifier: any, name: string): any { + return enumIdentifier[name]; + } } function convertTsickleDecoratorIntoMetadata(decoratorInvocations: any[]): any[] { diff --git a/packages/core/src/reflection/reflector.ts b/packages/core/src/reflection/reflector.ts index 6d7b8634f03d0..c8ec7710dfe56 100644 --- a/packages/core/src/reflection/reflector.ts +++ b/packages/core/src/reflection/reflector.ts @@ -20,9 +20,13 @@ export {GetterFn, MethodFn, SetterFn}; export class Reflector { constructor(public reflectionCapabilities: PlatformReflectionCapabilities) {} - updateCapabilities(caps: PlatformReflectionCapabilities) { this.reflectionCapabilities = caps; } + updateCapabilities(caps: PlatformReflectionCapabilities) { + this.reflectionCapabilities = caps; + } - factory(type: Type<any>): Function { return this.reflectionCapabilities.factory(type); } + factory(type: Type<any>): Function { + return this.reflectionCapabilities.factory(type); + } parameters(typeOrFunc: Type<any>): any[][] { return this.reflectionCapabilities.parameters(typeOrFunc); @@ -40,15 +44,25 @@ export class Reflector { return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty); } - getter(name: string): GetterFn { return this.reflectionCapabilities.getter(name); } + getter(name: string): GetterFn { + return this.reflectionCapabilities.getter(name); + } - setter(name: string): SetterFn { return this.reflectionCapabilities.setter(name); } + setter(name: string): SetterFn { + return this.reflectionCapabilities.setter(name); + } - method(name: string): MethodFn { return this.reflectionCapabilities.method(name); } + method(name: string): MethodFn { + return this.reflectionCapabilities.method(name); + } - importUri(type: any): string { return this.reflectionCapabilities.importUri(type); } + importUri(type: any): string { + return this.reflectionCapabilities.importUri(type); + } - resourceUri(type: any): string { return this.reflectionCapabilities.resourceUri(type); } + resourceUri(type: any): string { + return this.reflectionCapabilities.resourceUri(type); + } resolveIdentifier(name: string, moduleUrl: string, members: string[], runtime: any): any { return this.reflectionCapabilities.resolveIdentifier(name, moduleUrl, members, runtime); diff --git a/packages/core/src/render/api.ts b/packages/core/src/render/api.ts index f03f26eaf3442..36fcc6df541da 100644 --- a/packages/core/src/render/api.ts +++ b/packages/core/src/render/api.ts @@ -145,7 +145,7 @@ export abstract class Renderer2 { * This is used as a performance optimization for production mode. */ // TODO(issue/24571): remove '!'. - destroyNode !: ((node: any) => void) | null; + destroyNode!: ((node: any) => void)|null; /** * Appends a child to a given parent node in the host element DOM. * @param parent The parent node. diff --git a/packages/core/src/render3/assert.ts b/packages/core/src/render3/assert.ts index 186b0fde7766a..56c74663d5946 100644 --- a/packages/core/src/render3/assert.ts +++ b/packages/core/src/render3/assert.ts @@ -20,9 +20,10 @@ import {LView, TVIEW, TView} from './interfaces/view'; export function assertTNodeForLView(tNode: TNode, lView: LView) { - tNode.hasOwnProperty('tView_') && assertEqual( - (tNode as any as{tView_: TView}).tView_, lView[TVIEW], - 'This TNode does not belong to this LView.'); + tNode.hasOwnProperty('tView_') && + assertEqual( + (tNode as any as {tView_: TView}).tView_, lView[TVIEW], + 'This TNode does not belong to this LView.'); } export function assertComponentType( @@ -45,9 +46,9 @@ export function assertPreviousIsParent(isParent: boolean) { assertEqual(isParent, true, 'previousOrParentTNode should be a parent'); } -export function assertHasParent(tNode: TNode | null) { +export function assertHasParent(tNode: TNode|null) { assertDefined(tNode, 'previousOrParentTNode should exist!'); - assertDefined(tNode !.parent, 'previousOrParentTNode should have a parent'); + assertDefined(tNode!.parent, 'previousOrParentTNode should have a parent'); } export function assertDataNext(lView: LView, index: number, arr?: any[]) { diff --git a/packages/core/src/render3/component.ts b/packages/core/src/render3/component.ts index 892e49bd38108..c923209584084 100644 --- a/packages/core/src/render3/component.ts +++ b/packages/core/src/render3/component.ts @@ -12,15 +12,16 @@ import {Type} from '../core'; import {Injector} from '../di/injector'; import {Sanitizer} from '../sanitization/sanitizer'; import {assertDataInRange} from '../util/assert'; + import {assertComponentType} from './assert'; import {getComponentDef} from './definition'; import {diPublicInInjector, getOrCreateNodeInjectorForNode} from './di'; import {registerPostOrderHooks} from './hooks'; -import {CLEAN_PROMISE, addHostBindingsToExpandoInstructions, addToViewTree, createLView, createTView, getOrCreateTComponentView, getOrCreateTNode, growHostVarsSpace, initTNodeFlags, instantiateRootComponent, invokeHostBindingsInCreationMode, locateHostElement, markAsComponentHost, refreshView, renderView} from './instructions/shared'; +import {addHostBindingsToExpandoInstructions, addToViewTree, CLEAN_PROMISE, createLView, createTView, getOrCreateTComponentView, getOrCreateTNode, growHostVarsSpace, initTNodeFlags, instantiateRootComponent, invokeHostBindingsInCreationMode, locateHostElement, markAsComponentHost, refreshView, renderView} from './instructions/shared'; import {ComponentDef, ComponentType, RenderFlags} from './interfaces/definition'; import {TElementNode, TNode, TNodeType} from './interfaces/node'; import {PlayerHandler} from './interfaces/player'; -import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; +import {domRendererFactory3, RElement, Renderer3, RendererFactory3} from './interfaces/renderer'; import {CONTEXT, HEADER_OFFSET, LView, LViewFlags, RootContext, RootContextFlags, TVIEW, TViewType} from './interfaces/view'; import {writeDirectClass, writeDirectStyle} from './node_manipulation'; import {enterView, getPreviousOrParentTNode, leaveView, setSelectedIndex} from './state'; @@ -107,7 +108,7 @@ export const NULL_INJECTOR: Injector = { */ export function renderComponent<T>( componentType: ComponentType<T>| - Type<T>/* Type as workaround for: Microsoft/TypeScript/issues/4881 */ + Type<T>/* Type as workaround for: Microsoft/TypeScript/issues/4881 */ , opts: CreateComponentOptions = {}): T { ngDevMode && publishDefaultGlobalUtils(); @@ -115,11 +116,11 @@ export function renderComponent<T>( const rendererFactory = opts.rendererFactory || domRendererFactory3; const sanitizer = opts.sanitizer || null; - const componentDef = getComponentDef<T>(componentType) !; - if (componentDef.type != componentType) (componentDef as{type: Type<any>}).type = componentType; + const componentDef = getComponentDef<T>(componentType)!; + if (componentDef.type != componentType) (componentDef as {type: Type<any>}).type = componentType; // The first index of the first selector is the tag name. - const componentTag = componentDef.selectors ![0] ![0] as string; + const componentTag = componentDef.selectors![0]![0] as string; const hostRenderer = rendererFactory.createRenderer(null, null); const hostRNode = locateHostElement(hostRenderer, opts.host || componentTag, componentDef.encapsulation); @@ -168,9 +169,8 @@ export function renderComponent<T>( * @returns Component view created */ export function createRootComponentView( - rNode: RElement | null, def: ComponentDef<any>, rootView: LView, - rendererFactory: RendererFactory3, hostRenderer: Renderer3, - sanitizer?: Sanitizer | null): LView { + rNode: RElement|null, def: ComponentDef<any>, rootView: LView, + rendererFactory: RendererFactory3, hostRenderer: Renderer3, sanitizer?: Sanitizer|null): LView { const tView = rootView[TVIEW]; ngDevMode && assertDataInRange(rootView, 0 + HEADER_OFFSET); rootView[0 + HEADER_OFFSET] = rNode; @@ -213,7 +213,7 @@ export function createRootComponentView( */ export function createRootComponent<T>( componentView: LView, componentDef: ComponentDef<T>, rootLView: LView, rootContext: RootContext, - hostFeatures: HostFeature[] | null): any { + hostFeatures: HostFeature[]|null): any { const tView = rootLView[TVIEW]; // Create directive instance with factory() and store at next index in viewData const component = instantiateRootComponent(tView, rootLView, componentDef); @@ -270,13 +270,13 @@ export function createRootContext( * ``` */ export function LifecycleHooksFeature(component: any, def: ComponentDef<any>): void { - const rootTView = readPatchedLView(component) ![TVIEW]; + const rootTView = readPatchedLView(component)![TVIEW]; const dirIndex = rootTView.data.length - 1; // TODO(misko): replace `as TNode` with createTNode call. (needs refactoring to lose dep on // LNode). registerPostOrderHooks( - rootTView, { directiveStart: dirIndex, directiveEnd: dirIndex + 1 } as TNode); + rootTView, {directiveStart: dirIndex, directiveEnd: dirIndex + 1} as TNode); } /** diff --git a/packages/core/src/render3/component_ref.ts b/packages/core/src/render3/component_ref.ts index 7655bbfa33352..86f9908b8a817 100644 --- a/packages/core/src/render3/component_ref.ts +++ b/packages/core/src/render3/component_ref.ts @@ -21,13 +21,13 @@ import {VERSION} from '../version'; import {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from '../view/provider'; import {assertComponentType} from './assert'; -import {LifecycleHooksFeature, createRootComponent, createRootComponentView, createRootContext} from './component'; +import {createRootComponent, createRootComponentView, createRootContext, LifecycleHooksFeature} from './component'; import {getComponentDef} from './definition'; import {NodeInjector} from './di'; import {assignTViewNodeToLView, createLView, createTView, elementCreate, locateHostElement, renderView} from './instructions/shared'; import {ComponentDef} from './interfaces/definition'; import {TContainerNode, TElementContainerNode, TElementNode} from './interfaces/node'; -import {RNode, RendererFactory3, domRendererFactory3} from './interfaces/renderer'; +import {domRendererFactory3, RendererFactory3, RNode} from './interfaces/renderer'; import {LView, LViewFlags, TVIEW, TViewType} from './interfaces/view'; import {MATH_ML_NAMESPACE, SVG_NAMESPACE} from './namespaces'; import {writeDirectClass} from './node_manipulation'; @@ -43,11 +43,13 @@ export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolve /** * @param ngModule The NgModuleRef to which all resolved factories are bound. */ - constructor(private ngModule?: viewEngine_NgModuleRef<any>) { super(); } + constructor(private ngModule?: viewEngine_NgModuleRef<any>) { + super(); + } resolveComponentFactory<T>(component: Type<T>): viewEngine_ComponentFactory<T> { ngDevMode && assertComponentType(component); - const componentDef = getComponentDef(component) !; + const componentDef = getComponentDef(component)!; return new ComponentFactory(componentDef, this.ngModule); } } @@ -79,7 +81,7 @@ export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDUL function createChainedInjector(rootViewInjector: Injector, moduleInjector: Injector): Injector { return { - get: <T>(token: Type<T>| InjectionToken<T>, notFoundValue?: T, flags?: InjectFlags): T => { + get: <T>(token: Type<T>|InjectionToken<T>, notFoundValue?: T, flags?: InjectFlags): T => { const value = rootViewInjector.get(token, NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as T, flags); if (value !== NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR || @@ -205,8 +207,9 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> { // projectable nodes can be passed as array of arrays or an array of iterables (ngUpgrade // case). Here we do normalize passed data structure to be an array of arrays to avoid // complex checks down the line. - tElementNode.projection = - projectableNodes.map((nodesforSlot: RNode[]) => { return Array.from(nodesforSlot); }); + tElementNode.projection = projectableNodes.map((nodesforSlot: RNode[]) => { + return Array.from(nodesforSlot); + }); } // TODO: should LifecycleHooksFeature and other host features be generated by the compiler and @@ -227,7 +230,7 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> { if (!rootSelectorOrNode || isIsolated) { // The host element of the internal or isolated root view is attached to the component's host // view node. - componentRef.hostView._tViewNode !.child = tElementNode; + componentRef.hostView._tViewNode!.child = tElementNode; } return componentRef; } @@ -272,7 +275,9 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> { this.componentType = componentType; } - get injector(): Injector { return new NodeInjector(this._tNode, this._rootLView); } + get injector(): Injector { + return new NodeInjector(this._tNode, this._rootLView); + } destroy(): void { if (this.destroyCbs) { diff --git a/packages/core/src/render3/context_discovery.ts b/packages/core/src/render3/context_discovery.ts index 5429aba0edc79..c7da4fc3abb7b 100644 --- a/packages/core/src/render3/context_discovery.ts +++ b/packages/core/src/render3/context_discovery.ts @@ -18,7 +18,8 @@ import {getComponentLViewByIndex, getNativeByTNodeOrNull, readPatchedData, unwra -/** Returns the matching `LContext` data for a given DOM node, directive or component instance. +/** + * Returns the matching `LContext` data for a given DOM node, directive or component instance. * * This function will examine the provided DOM element, component, or directive instance\'s * monkey-patched property to derive the `LContext` data. Once called then the monkey-patched @@ -43,7 +44,7 @@ export function getLContext(target: any): LContext|null { // only when it's an array is it considered an LView instance // ... otherwise it's an already constructed LContext instance if (Array.isArray(mpValue)) { - const lView: LView = mpValue !; + const lView: LView = mpValue!; let nodeIndex: number; let component: any = undefined; let directives: any[]|null|undefined = undefined; @@ -173,7 +174,7 @@ export function getComponentViewByInstance(componentInstance: {}): LView { * Assigns the given data to the given target (which could be a component, * directive or DOM node instance) using monkey-patching. */ -export function attachPatchData(target: any, data: LView | LContext) { +export function attachPatchData(target: any, data: LView|LContext) { target[MONKEY_PATCH_KEY_NAME] = data; } @@ -191,7 +192,7 @@ export function isDirectiveInstance(instance: any): boolean { function findViaNativeElement(lView: LView, target: RElement): number { let tNode = lView[TVIEW].firstChild; while (tNode) { - const native = getNativeByTNodeOrNull(tNode, lView) !; + const native = getNativeByTNodeOrNull(tNode, lView)!; if (native === target) { return tNode.index; } diff --git a/packages/core/src/render3/definition.ts b/packages/core/src/render3/definition.ts index 3b1215be9f44c..f4a7fedce7488 100644 --- a/packages/core/src/render3/definition.ts +++ b/packages/core/src/render3/definition.ts @@ -303,7 +303,7 @@ export function ɵɵdefineComponent<T>(componentDefinition: { decls: componentDefinition.decls, vars: componentDefinition.vars, factory: null, - template: componentDefinition.template || null !, + template: componentDefinition.template || null!, consts: componentDefinition.consts || null, ngContentSelectors: componentDefinition.ngContentSelectors, hostBindings: componentDefinition.hostBindings || null, @@ -311,8 +311,8 @@ export function ɵɵdefineComponent<T>(componentDefinition: { hostAttrs: componentDefinition.hostAttrs || null, contentQueries: componentDefinition.contentQueries || null, declaredInputs: declaredInputs, - inputs: null !, // assigned in noSideEffects - outputs: null !, // assigned in noSideEffects + inputs: null!, // assigned in noSideEffects + outputs: null!, // assigned in noSideEffects exportAs: componentDefinition.exportAs || null, onChanges: null, onInit: typePrototype.ngOnInit || null, @@ -323,8 +323,8 @@ export function ɵɵdefineComponent<T>(componentDefinition: { afterViewChecked: typePrototype.ngAfterViewChecked || null, onDestroy: typePrototype.ngOnDestroy || null, onPush: componentDefinition.changeDetection === ChangeDetectionStrategy.OnPush, - directiveDefs: null !, // assigned in noSideEffects - pipeDefs: null !, // assigned in noSideEffects + directiveDefs: null!, // assigned in noSideEffects + pipeDefs: null!, // assigned in noSideEffects selectors: componentDefinition.selectors || EMPTY_ARRAY, viewQuery: componentDefinition.viewQuery || null, features: componentDefinition.features as DirectiveDefFeature[] || null, @@ -339,9 +339,9 @@ export function ɵɵdefineComponent<T>(componentDefinition: { schemas: componentDefinition.schemas || null, tView: null, }; - const directiveTypes = componentDefinition.directives !; + const directiveTypes = componentDefinition.directives!; const feature = componentDefinition.features; - const pipeTypes = componentDefinition.pipes !; + const pipeTypes = componentDefinition.pipes!; def.id += _renderCompCount++; def.inputs = invertObject(componentDefinition.inputs, declaredInputs), def.outputs = invertObject(componentDefinition.outputs), @@ -373,7 +373,7 @@ export function extractDirectiveDef(type: Type<any>): DirectiveDef<any>|Componen if (ngDevMode && !def) { throw new Error(`'${type.name}' is neither 'ComponentType' or 'DirectiveType'.`); } - return def !; + return def!; } export function extractPipeDef(type: Type<any>): PipeDef<any> { @@ -381,7 +381,7 @@ export function extractPipeDef(type: Type<any>): PipeDef<any> { if (ngDevMode && !def) { throw new Error(`'${type.name}' is not a 'PipeType'.`); } - return def !; + return def!; } export const autoRegisterModuleById: {[id: string]: NgModuleType} = {}; @@ -425,8 +425,9 @@ export function ɵɵdefineNgModule<T>(def: { id: def.id || null, }; if (def.id != null) { - noSideEffects( - () => { autoRegisterModuleById[def.id !] = def.type as unknown as NgModuleType; }); + noSideEffects(() => { + autoRegisterModuleById[def.id!] = def.type as unknown as NgModuleType; + }); } return res as never; } @@ -443,7 +444,7 @@ export function ɵɵdefineNgModule<T>(def: { */ export function ɵɵsetNgModuleScope(type: any, scope: { /** List of components, directives, and pipes declared by this module. */ - declarations?: Type<any>[] | (() => Type<any>[]); + declarations?: Type<any>[]|(() => Type<any>[]); /** List of modules or `ModuleWithProviders` imported by this module. */ imports?: Type<any>[] | (() => Type<any>[]); @@ -455,11 +456,11 @@ export function ɵɵsetNgModuleScope(type: any, scope: { exports?: Type<any>[] | (() => Type<any>[]); }): void { return noSideEffects(() => { - const ngModuleDef = getNgModuleDef(type, true); - ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY; - ngModuleDef.imports = scope.imports || EMPTY_ARRAY; - ngModuleDef.exports = scope.exports || EMPTY_ARRAY; - }) as never; + const ngModuleDef = getNgModuleDef(type, true); + ngModuleDef.declarations = scope.declarations || EMPTY_ARRAY; + ngModuleDef.imports = scope.imports || EMPTY_ARRAY; + ngModuleDef.exports = scope.exports || EMPTY_ARRAY; + }) as never; } /** @@ -518,13 +519,13 @@ export function ɵɵsetNgModuleScope(type: any, scope: { */ function invertObject<T>( - obj?: {[P in keyof T]?: string | [string, string]}, + obj?: {[P in keyof T]?: string|[string, string]}, secondary?: {[key: string]: string}): {[P in keyof T]: string} { if (obj == null) return EMPTY_OBJ as any; const newLookup: any = {}; for (const minifiedKey in obj) { if (obj.hasOwnProperty(minifiedKey)) { - let publicName: string|[string, string] = obj[minifiedKey] !; + let publicName: string|[string, string] = obj[minifiedKey]!; let declaredName = publicName; if (Array.isArray(publicName)) { declaredName = publicName[1]; @@ -555,142 +556,143 @@ function invertObject<T>( * * @codeGenApi */ -export const ɵɵdefineDirective = ɵɵdefineComponent as any as<T>(directiveDefinition: { - /** - * Directive type, needed to configure the injector. - */ - type: Type<T>; - - /** The selectors that will be used to match nodes to this directive. */ - selectors?: CssSelectorList; - - /** - * A map of input names. - * - * The format is in: `{[actualPropertyName: string]:(string|[string, string])}`. - * - * Given: - * ``` - * class MyComponent { - * @Input() - * publicInput1: string; - * - * @Input('publicInput2') - * declaredInput2: string; - * } - * ``` - * - * is described as: - * ``` - * { - * publicInput1: 'publicInput1', - * declaredInput2: ['declaredInput2', 'publicInput2'], - * } - * ``` - * - * Which the minifier may translate to: - * ``` - * { - * minifiedPublicInput1: 'publicInput1', - * minifiedDeclaredInput2: [ 'publicInput2', 'declaredInput2'], - * } - * ``` - * - * This allows the render to re-construct the minified, public, and declared names - * of properties. - * - * NOTE: - * - Because declared and public name are usually same we only generate the array - * `['declared', 'public']` format when they differ. - * - The reason why this API and `outputs` API is not the same is that `NgOnChanges` has - * inconsistent behavior in that it uses declared names rather than minified or public. For - * this reason `NgOnChanges` will be deprecated and removed in future version and this - * API will be simplified to be consistent with `output`. - */ - inputs?: {[P in keyof T]?: string | [string, string]}; - - /** - * A map of output names. - * - * The format is in: `{[actualPropertyName: string]:string}`. - * - * Which the minifier may translate to: `{[minifiedPropertyName: string]:string}`. - * - * This allows the render to re-construct the minified and non-minified names - * of properties. - */ - outputs?: {[P in keyof T]?: string}; - - /** - * A list of optional features to apply. - * - * See: {@link NgOnChangesFeature}, {@link ProvidersFeature}, {@link InheritDefinitionFeature} - */ - features?: DirectiveDefFeature[]; - - /** - * Function executed by the parent template to allow child directive to apply host bindings. - */ - hostBindings?: HostBindingsFunction<T>; - - /** - * The number of bindings in this directive `hostBindings` (including pure fn bindings). - * - * Used to calculate the length of the component's LView array, so we - * can pre-fill the array and set the host binding start index. - */ - hostVars?: number; - - /** - * Assign static attribute values to a host element. - * - * This property will assign static attribute values as well as class and style - * values to a host element. Since attribute values can consist of different types of values, the - * `hostAttrs` array must include the values in the following format: - * - * attrs = [ - * // static attributes (like `title`, `name`, `id`...) - * attr1, value1, attr2, value, - * - * // a single namespace value (like `x:id`) - * NAMESPACE_MARKER, namespaceUri1, name1, value1, - * - * // another single namespace value (like `x:name`) - * NAMESPACE_MARKER, namespaceUri2, name2, value2, - * - * // a series of CSS classes that will be applied to the element (no spaces) - * CLASSES_MARKER, class1, class2, class3, - * - * // a series of CSS styles (property + value) that will be applied to the element - * STYLES_MARKER, prop1, value1, prop2, value2 - * ] - * - * All non-class and non-style attributes must be defined at the start of the list - * first before all class and style values are set. When there is a change in value - * type (like when classes and styles are introduced) a marker must be used to separate - * the entries. The marker values themselves are set via entries found in the - * [AttributeMarker] enum. - */ - hostAttrs?: TAttributes; - - /** - * Function to create instances of content queries associated with a given directive. - */ - contentQueries?: ContentQueriesFunction<T>; - - /** - * Additional set of instructions specific to view query processing. This could be seen as a - * set of instructions to be inserted into the template function. - */ - viewQuery?: ViewQueriesFunction<T>| null; - - /** - * Defines the name that can be used in the template to assign this directive to a variable. - * - * See: {@link Directive.exportAs} - */ - exportAs?: string[]; -}) => never; +export const ɵɵdefineDirective = + ɵɵdefineComponent as any as<T>(directiveDefinition: { + /** + * Directive type, needed to configure the injector. + */ + type: Type<T>; + + /** The selectors that will be used to match nodes to this directive. */ + selectors?: CssSelectorList; + + /** + * A map of input names. + * + * The format is in: `{[actualPropertyName: string]:(string|[string, string])}`. + * + * Given: + * ``` + * class MyComponent { + * @Input() + * publicInput1: string; + * + * @Input('publicInput2') + * declaredInput2: string; + * } + * ``` + * + * is described as: + * ``` + * { + * publicInput1: 'publicInput1', + * declaredInput2: ['declaredInput2', 'publicInput2'], + * } + * ``` + * + * Which the minifier may translate to: + * ``` + * { + * minifiedPublicInput1: 'publicInput1', + * minifiedDeclaredInput2: [ 'publicInput2', 'declaredInput2'], + * } + * ``` + * + * This allows the render to re-construct the minified, public, and declared names + * of properties. + * + * NOTE: + * - Because declared and public name are usually same we only generate the array + * `['declared', 'public']` format when they differ. + * - The reason why this API and `outputs` API is not the same is that `NgOnChanges` has + * inconsistent behavior in that it uses declared names rather than minified or public. For + * this reason `NgOnChanges` will be deprecated and removed in future version and this + * API will be simplified to be consistent with `output`. + */ + inputs?: {[P in keyof T]?: string | [string, string]}; + + /** + * A map of output names. + * + * The format is in: `{[actualPropertyName: string]:string}`. + * + * Which the minifier may translate to: `{[minifiedPropertyName: string]:string}`. + * + * This allows the render to re-construct the minified and non-minified names + * of properties. + */ + outputs?: {[P in keyof T]?: string}; + + /** + * A list of optional features to apply. + * + * See: {@link NgOnChangesFeature}, {@link ProvidersFeature}, {@link InheritDefinitionFeature} + */ + features?: DirectiveDefFeature[]; + + /** + * Function executed by the parent template to allow child directive to apply host bindings. + */ + hostBindings?: HostBindingsFunction<T>; + + /** + * The number of bindings in this directive `hostBindings` (including pure fn bindings). + * + * Used to calculate the length of the component's LView array, so we + * can pre-fill the array and set the host binding start index. + */ + hostVars?: number; + + /** + * Assign static attribute values to a host element. + * + * This property will assign static attribute values as well as class and style + * values to a host element. Since attribute values can consist of different types of values, + * the `hostAttrs` array must include the values in the following format: + * + * attrs = [ + * // static attributes (like `title`, `name`, `id`...) + * attr1, value1, attr2, value, + * + * // a single namespace value (like `x:id`) + * NAMESPACE_MARKER, namespaceUri1, name1, value1, + * + * // another single namespace value (like `x:name`) + * NAMESPACE_MARKER, namespaceUri2, name2, value2, + * + * // a series of CSS classes that will be applied to the element (no spaces) + * CLASSES_MARKER, class1, class2, class3, + * + * // a series of CSS styles (property + value) that will be applied to the element + * STYLES_MARKER, prop1, value1, prop2, value2 + * ] + * + * All non-class and non-style attributes must be defined at the start of the list + * first before all class and style values are set. When there is a change in value + * type (like when classes and styles are introduced) a marker must be used to separate + * the entries. The marker values themselves are set via entries found in the + * [AttributeMarker] enum. + */ + hostAttrs?: TAttributes; + + /** + * Function to create instances of content queries associated with a given directive. + */ + contentQueries?: ContentQueriesFunction<T>; + + /** + * Additional set of instructions specific to view query processing. This could be seen as a + * set of instructions to be inserted into the template function. + */ + viewQuery?: ViewQueriesFunction<T>| null; + + /** + * Defines the name that can be used in the template to assign this directive to a variable. + * + * See: {@link Directive.exportAs} + */ + exportAs?: string[]; + }) => never; /** * Create a pipe definition object. @@ -719,12 +721,12 @@ export function ɵɵdefinePipe<T>(pipeDef: { pure?: boolean }): never { return (<PipeDef<T>>{ - type: pipeDef.type, - name: pipeDef.name, - factory: null, - pure: pipeDef.pure !== false, - onDestroy: pipeDef.type.prototype.ngOnDestroy || null - }) as never; + type: pipeDef.type, + name: pipeDef.name, + factory: null, + pure: pipeDef.pure !== false, + onDestroy: pipeDef.type.prototype.ngOnDestroy || null + }) as never; } /** diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index c70505a2d1e6d..3b6eca4d6e872 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -21,10 +21,10 @@ import {getFactoryDef} from './definition'; import {NG_ELEMENT_ID, NG_FACTORY_DEF} from './fields'; import {registerPreOrderHooks} from './hooks'; import {DirectiveDef, FactoryFn} from './interfaces/definition'; -import {NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE, isFactory} from './interfaces/injector'; +import {isFactory, NO_PARENT_INJECTOR, NodeInjectorFactory, PARENT_INJECTOR, RelativeInjectorLocation, RelativeInjectorLocationFlags, TNODE} from './interfaces/injector'; import {AttributeMarker, TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeProviderIndexes, TNodeType} from './interfaces/node'; import {isComponentDef, isComponentHost} from './interfaces/type_checks'; -import {DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, INJECTOR, LView, TData, TVIEW, TView, T_HOST} from './interfaces/view'; +import {DECLARATION_COMPONENT_VIEW, DECLARATION_VIEW, INJECTOR, LView, T_HOST, TData, TVIEW, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {enterDI, leaveDI} from './state'; import {isNameOnlyAttributeMarker} from './util/attrs_utils'; @@ -97,7 +97,7 @@ let nextNgElementId = 0; * @param type The directive token to register */ export function bloomAdd( - injectorIndex: number, tView: TView, type: Type<any>| InjectionToken<any>| string): void { + injectorIndex: number, tView: TView, type: Type<any>|InjectionToken<any>|string): void { ngDevMode && assertEqual(tView.firstCreatePass, true, 'expected firstCreatePass to be true'); let id: number|undefined = typeof type !== 'string' ? (type as any)[NG_ELEMENT_ID] : type.charCodeAt(0) || 0; @@ -141,7 +141,7 @@ export function bloomAdd( * @returns Node injector */ export function getOrCreateNodeInjectorForNode( - tNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LView): number { + tNode: TElementNode|TContainerNode|TElementContainerNode, hostView: LView): number { const existingInjectorIndex = getInjectorIndex(tNode, hostView); if (existingInjectorIndex !== -1) { return existingInjectorIndex; @@ -175,7 +175,7 @@ export function getOrCreateNodeInjectorForNode( return injectorIndex; } -function insertBloom(arr: any[], footer: TNode | null): void { +function insertBloom(arr: any[], footer: TNode|null): void { arr.push(0, 0, 0, 0, 0, 0, 0, 0, footer); } @@ -211,7 +211,7 @@ export function getParentInjectorLocation(tNode: TNode, view: LView): RelativeIn let hostTNode = view[T_HOST]; let viewOffset = 1; while (hostTNode && hostTNode.injectorIndex === -1) { - view = view[DECLARATION_VIEW] !; + view = view[DECLARATION_VIEW]!; hostTNode = view ? view[T_HOST] : null; viewOffset++; } @@ -229,7 +229,7 @@ export function getParentInjectorLocation(tNode: TNode, view: LView): RelativeIn * @param token The type or the injection token to be made public */ export function diPublicInInjector( - injectorIndex: number, tView: TView, token: InjectionToken<any>| Type<any>): void { + injectorIndex: number, tView: TView, token: InjectionToken<any>|Type<any>): void { bloomAdd(injectorIndex, tView, token); } @@ -265,8 +265,9 @@ export function diPublicInInjector( * @publicApi */ export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): string|null { - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); ngDevMode && assertDefined(tNode, 'expecting tNode'); if (attrNameToInject === 'class') { return tNode.classes; @@ -327,7 +328,7 @@ export function injectAttributeImpl(tNode: TNode, attrNameToInject: string): str * @returns the value from the injector, `null` when not found, or `notFoundValue` if provided */ export function getOrCreateInjectable<T>( - tNode: TDirectiveHostNode | null, lView: LView, token: Type<T>| InjectionToken<T>, + tNode: TDirectiveHostNode|null, lView: LView, token: Type<T>|InjectionToken<T>, flags: InjectFlags = InjectFlags.Default, notFoundValue?: any): T|null { if (tNode !== null) { const bloomHash = bloomHashBitOrFactory(token); @@ -443,8 +444,8 @@ export function getOrCreateInjectable<T>( const NOT_FOUND = {}; function searchTokensOnInjector<T>( - injectorIndex: number, lView: LView, token: Type<T>| InjectionToken<T>, - previousTView: TView | null, flags: InjectFlags, hostTElementNode: TNode | null) { + injectorIndex: number, lView: LView, token: Type<T>|InjectionToken<T>, + previousTView: TView|null, flags: InjectFlags, hostTElementNode: TNode|null) { const currentTView = lView[TVIEW]; const tNode = currentTView.data[injectorIndex + TNODE] as TNode; // First, we need to determine if view providers can be accessed by the starting element. @@ -490,8 +491,8 @@ function searchTokensOnInjector<T>( * @returns Index of a found directive or provider, or null when none found. */ export function locateDirectiveOrProvider<T>( - tNode: TNode, tView: TView, token: Type<T>| InjectionToken<T>, canAccessViewProviders: boolean, - isHostSpecialCase: boolean | number): number|null { + tNode: TNode, tView: TView, token: Type<T>|InjectionToken<T>, canAccessViewProviders: boolean, + isHostSpecialCase: boolean|number): number|null { const nodeProviderIndexes = tNode.providerIndexes; const tInjectables = tView.data; @@ -521,12 +522,12 @@ export function locateDirectiveOrProvider<T>( } /** -* Retrieve or instantiate the injectable from the `LView` at particular `index`. -* -* This function checks to see if the value has already been instantiated and if so returns the -* cached `injectable`. Otherwise if it detects that the value is still a factory it -* instantiates the `injectable` and caches the value. -*/ + * Retrieve or instantiate the injectable from the `LView` at particular `index`. + * + * This function checks to see if the value has already been instantiated and if so returns the + * cached `injectable`. Otherwise if it detects that the value is still a factory it + * instantiates the `injectable` and caches the value. + */ export function getNodeInjectable( lView: LView, tView: TView, index: number, tNode: TDirectiveHostNode): any { let value = lView[index]; @@ -577,8 +578,8 @@ export function getNodeInjectable( * @returns the matching bit to check in the bloom filter or `null` if the token is not known. * When the returned value is negative then it represents special values such as `Injector`. */ -export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>| string): number| - Function|undefined { +export function bloomHashBitOrFactory(token: Type<any>|InjectionToken<any>|string): number|Function| + undefined { ngDevMode && assertDefined(token, 'token must be defined'); if (typeof token === 'string') { return token.charCodeAt(0) || 0; @@ -588,8 +589,7 @@ export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>| str return (typeof tokenId === 'number' && tokenId > 0) ? tokenId & BLOOM_MASK : tokenId; } -export function bloomHasToken( - bloomHash: number, injectorIndex: number, injectorView: LView | TData) { +export function bloomHasToken(bloomHash: number, injectorIndex: number, injectorView: LView|TData) { // Create a mask that targets the specific bit associated with the directive we're looking for. // JS bit operations are 32 bits, so this will be a number between 2^0 and 2^31, corresponding // to bit positions 0 - 31 in a 32 bit integer. @@ -639,9 +639,9 @@ export function ɵɵgetFactoryOf<T>(type: Type<any>): FactoryFn<T>|null { if (isForwardRef(type)) { return (() => { - const factory = ɵɵgetFactoryOf<T>(resolveForwardRef(typeAny)); - return factory ? factory() : null; - }) as any; + const factory = ɵɵgetFactoryOf<T>(resolveForwardRef(typeAny)); + return factory ? factory() : null; + }) as any; } let factory = getFactoryDef<T>(typeAny); diff --git a/packages/core/src/render3/empty.ts b/packages/core/src/render3/empty.ts index 36be572fbe5d1..fa7af07343e6f 100644 --- a/packages/core/src/render3/empty.ts +++ b/packages/core/src/render3/empty.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {initNgDevMode} from '../util/ng_dev_mode'; /** diff --git a/packages/core/src/render3/errors.ts b/packages/core/src/render3/errors.ts index d92cb4ebc27e1..b1fc6a6457e2c 100644 --- a/packages/core/src/render3/errors.ts +++ b/packages/core/src/render3/errors.ts @@ -47,7 +47,8 @@ export function throwErrorIfNoChangesMode( creationMode: boolean, oldValue: any, currValue: any, propName?: string): never|void { const field = propName ? ` for '${propName}'` : ''; let msg = - `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${field}: '${oldValue}'. Current value: '${currValue}'.`; + `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value${ + field}: '${oldValue}'. Current value: '${currValue}'.`; if (creationMode) { msg += ` It seems like the view has been created after its parent and its children have been dirty checked.` + diff --git a/packages/core/src/render3/features/copy_definition_feature.ts b/packages/core/src/render3/features/copy_definition_feature.ts index 3d4bc0f2569c0..4cad1d4446cca 100644 --- a/packages/core/src/render3/features/copy_definition_feature.ts +++ b/packages/core/src/render3/features/copy_definition_feature.ts @@ -64,16 +64,16 @@ const COPY_COMPONENT_FIELDS: Exclude<keyof ComponentDef<unknown>, keyof Directiv * * @codeGenApi */ -export function ɵɵCopyDefinitionFeature(definition: DirectiveDef<any>| ComponentDef<any>): void { - let superType = getSuperType(definition.type) !; +export function ɵɵCopyDefinitionFeature(definition: DirectiveDef<any>|ComponentDef<any>): void { + let superType = getSuperType(definition.type)!; let superDef: DirectiveDef<any>|ComponentDef<any>|undefined = undefined; if (isComponentDef(definition)) { // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance. - superDef = superType.ɵcmp !; + superDef = superType.ɵcmp!; } else { // Don't use getComponentDef/getDirectiveDef. This logic relies on inheritance. - superDef = superType.ɵdir !; + superDef = superType.ɵdir!; } // Needed because `definition` fields are readonly. diff --git a/packages/core/src/render3/features/inherit_definition_feature.ts b/packages/core/src/render3/features/inherit_definition_feature.ts index 4d96eafef300c..66b0f689fb8a6 100644 --- a/packages/core/src/render3/features/inherit_definition_feature.ts +++ b/packages/core/src/render3/features/inherit_definition_feature.ts @@ -27,7 +27,7 @@ type WritableDef = Writable<DirectiveDef<any>|ComponentDef<any>>; * * @codeGenApi */ -export function ɵɵInheritDefinitionFeature(definition: DirectiveDef<any>| ComponentDef<any>): void { +export function ɵɵInheritDefinitionFeature(definition: DirectiveDef<any>|ComponentDef<any>): void { let superType = getSuperType(definition.type); let shouldInheritFields = true; const inheritanceChain: WritableDef[] = [definition]; diff --git a/packages/core/src/render3/features/ng_onchanges_feature.ts b/packages/core/src/render3/features/ng_onchanges_feature.ts index 7d749c624fdd7..3e7bf13830688 100644 --- a/packages/core/src/render3/features/ng_onchanges_feature.ts +++ b/packages/core/src/render3/features/ng_onchanges_feature.ts @@ -13,7 +13,7 @@ import {DirectiveDef, DirectiveDefFeature} from '../interfaces/definition'; const PRIVATE_PREFIX = '__ngOnChanges_'; -type OnChangesExpando = OnChanges & { +type OnChangesExpando = OnChanges&{ __ngOnChanges_: SimpleChanges|null|undefined; // tslint:disable-next-line:no-any Can hold any value [key: string]: any; @@ -45,7 +45,7 @@ type OnChangesExpando = OnChanges & { export function ɵɵNgOnChangesFeature<T>(definition: DirectiveDef<T>): void { if (definition.type.prototype.ngOnChanges) { definition.setInput = ngOnChangesSetInput; - (definition as{onChanges: Function}).onChanges = wrapOnChanges(); + (definition as {onChanges: Function}).onChanges = wrapOnChanges(); } } @@ -61,9 +61,9 @@ function wrapOnChanges() { const current = simpleChangesStore && simpleChangesStore.current; if (current) { - const previous = simpleChangesStore !.previous; + const previous = simpleChangesStore!.previous; if (previous === EMPTY_OBJ) { - simpleChangesStore !.previous = current; + simpleChangesStore!.previous = current; } else { // New changes are copied to the previous store, so that we don't lose history for inputs // which were not changed this time @@ -71,7 +71,7 @@ function wrapOnChanges() { previous[key] = current[key]; } } - simpleChangesStore !.current = null; + simpleChangesStore!.current = null; this.ngOnChanges(current); } }; @@ -84,7 +84,7 @@ function ngOnChangesSetInput<T>( const current = simpleChangesStore.current || (simpleChangesStore.current = {}); const previous = simpleChangesStore.previous; - const declaredName = (this.declaredInputs as{[key: string]: string})[publicName]; + const declaredName = (this.declaredInputs as {[key: string]: string})[publicName]; const previousChange = previous[declaredName]; current[declaredName] = new SimpleChange( previousChange && previousChange.currentValue, value, previous === EMPTY_OBJ); diff --git a/packages/core/src/render3/global_utils_api.ts b/packages/core/src/render3/global_utils_api.ts index 330918cf0369f..feb419de1d3ae 100644 --- a/packages/core/src/render3/global_utils_api.ts +++ b/packages/core/src/render3/global_utils_api.ts @@ -16,4 +16,4 @@ */ export {applyChanges} from './util/change_detection_utils'; -export {Listener, getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getOwningComponent, getRootComponents} from './util/discovery_utils'; +export {getComponent, getContext, getDirectives, getHostElement, getInjector, getListeners, getOwningComponent, getRootComponents, Listener} from './util/discovery_utils'; diff --git a/packages/core/src/render3/hooks.ts b/packages/core/src/render3/hooks.ts index eebaed60aa362..0667d62e23b51 100644 --- a/packages/core/src/render3/hooks.ts +++ b/packages/core/src/render3/hooks.ts @@ -79,8 +79,8 @@ export function registerPostOrderHooks(tView: TView, tNode: TNode): void { if (directiveDef.afterContentChecked) { (tView.contentHooks || (tView.contentHooks = [])).push(i, directiveDef.afterContentChecked); - (tView.contentCheckHooks || (tView.contentCheckHooks = [ - ])).push(i, directiveDef.afterContentChecked); + (tView.contentCheckHooks || (tView.contentCheckHooks = [])) + .push(i, directiveDef.afterContentChecked); } if (directiveDef.afterViewInit) { @@ -132,7 +132,7 @@ export function registerPostOrderHooks(tView: TView, tNode: TNode): void { * - number: execute hooks only from the saved index until that node index exclusive (pre-order * case, when executing select(number)) */ -export function executeCheckHooks(lView: LView, hooks: HookData, nodeIndex?: number | null) { +export function executeCheckHooks(lView: LView, hooks: HookData, nodeIndex?: number|null) { callHooks(lView, hooks, InitPhaseState.InitPhaseCompleted, nodeIndex); } @@ -150,10 +150,11 @@ export function executeCheckHooks(lView: LView, hooks: HookData, nodeIndex?: num * case, when executing select(number)) */ export function executeInitAndCheckHooks( - lView: LView, hooks: HookData, initPhase: InitPhaseState, nodeIndex?: number | null) { - ngDevMode && assertNotEqual( - initPhase, InitPhaseState.InitPhaseCompleted, - 'Init pre-order hooks should not be called more than once'); + lView: LView, hooks: HookData, initPhase: InitPhaseState, nodeIndex?: number|null) { + ngDevMode && + assertNotEqual( + initPhase, InitPhaseState.InitPhaseCompleted, + 'Init pre-order hooks should not be called more than once'); if ((lView[FLAGS] & LViewFlags.InitPhaseStateMask) === initPhase) { callHooks(lView, hooks, initPhase, nodeIndex); } @@ -188,17 +189,18 @@ export function incrementInitPhaseFlags(lView: LView, initPhase: InitPhaseState) */ function callHooks( currentView: LView, arr: HookData, initPhase: InitPhaseState, - currentNodeIndex: number | null | undefined): void { - ngDevMode && assertEqual( - getCheckNoChangesMode(), false, - 'Hooks should never be run in the check no changes mode.'); + currentNodeIndex: number|null|undefined): void { + ngDevMode && + assertEqual( + getCheckNoChangesMode(), false, + 'Hooks should never be run in the check no changes mode.'); const startIndex = currentNodeIndex !== undefined ? (currentView[PREORDER_HOOK_FLAGS] & PreOrderHookFlags.IndexOfTheNextPreOrderHookMaskMask) : 0; const nodeIndexLimit = currentNodeIndex != null ? currentNodeIndex : -1; let lastNodeIndexFound = 0; for (let i = startIndex; i < arr.length; i++) { - const hook = arr[i + 1] as() => void; + const hook = arr[i + 1] as () => void; if (typeof hook === 'number') { lastNodeIndexFound = arr[i] as number; if (currentNodeIndex != null && lastNodeIndexFound >= currentNodeIndex) { @@ -229,7 +231,7 @@ function callHooks( */ function callHook(currentView: LView, initPhase: InitPhaseState, arr: HookData, i: number) { const isInitHook = arr[i] < 0; - const hook = arr[i + 1] as() => void; + const hook = arr[i + 1] as () => void; const directiveIndex = isInitHook ? -arr[i] : arr[i] as number; const directive = currentView[directiveIndex]; if (isInitHook) { diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index 640c3eefd9b7b..f947dd3942b8c 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -8,11 +8,12 @@ import '../util/ng_i18n_closure_mode'; import {DEFAULT_LOCALE_ID, getPluralCase} from '../i18n/localization'; -import {SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS, getTemplateContent} from '../sanitization/html_sanitizer'; +import {getTemplateContent, SRCSET_ATTRS, URI_ATTRS, VALID_ATTRS, VALID_ELEMENTS} from '../sanitization/html_sanitizer'; import {InertBodyHelper} from '../sanitization/inert_body'; import {_sanitizeUrl, sanitizeSrcset} from '../sanitization/url_sanitizer'; import {addAllToArray} from '../util/array_utils'; import {assertDataInRange, assertDefined, assertEqual} from '../util/assert'; + import {bindingUpdated} from './bindings'; import {attachPatchData} from './context_discovery'; import {setDelayProjection} from './instructions/all'; @@ -25,7 +26,7 @@ import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjecti import {RComment, RElement, RText} from './interfaces/renderer'; import {SanitizerFn} from './interfaces/sanitization'; import {isLContainer} from './interfaces/type_checks'; -import {HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from './interfaces/view'; +import {HEADER_OFFSET, LView, RENDERER, T_HOST, TVIEW, TView} from './interfaces/view'; import {appendChild, applyProjection, createTextNode, nativeRemoveNode} from './node_manipulation'; import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, getTView, nextBindingIndex, setIsNotParent, setPreviousOrParentTNode} from './state'; import {renderStringify} from './util/misc_utils'; @@ -105,14 +106,14 @@ interface IcuCase { * @param pattern (sub)Pattern to be broken. * */ -function extractParts(pattern: string): (string | IcuExpression)[] { +function extractParts(pattern: string): (string|IcuExpression)[] { if (!pattern) { return []; } let prevPos = 0; const braceStack = []; - const results: (string | IcuExpression)[] = []; + const results: (string|IcuExpression)[] = []; const braces = /[{}]/g; // lastIndex doesn't get set to 0 so we have to. braces.lastIndex = 0; @@ -158,7 +159,7 @@ function extractParts(pattern: string): (string | IcuExpression)[] { */ function parseICUBlock(pattern: string): IcuExpression { const cases = []; - const values: (string | IcuExpression)[][] = []; + const values: (string|IcuExpression)[][] = []; let icuType = IcuType.plural; let mainBinding = 0; pattern = pattern.replace(ICU_BLOCK_REGEXP, function(str: string, binding: string, type: string) { @@ -219,7 +220,8 @@ function removeInnerTemplateTranslation(message: string): string { ngDevMode && assertEqual( inTemplate, false, - `Tag mismatch: unable to find the end of the sub-template in the translation "${message}"`); + `Tag mismatch: unable to find the end of the sub-template in the translation "${ + message}"`); res += message.substr(index); return res; @@ -263,7 +265,7 @@ export function getTranslationForTemplate(message: string, subTemplateIndex?: nu */ function generateBindingUpdateOpCodes( str: string, destinationNode: number, attrName?: string, - sanitizeFn: SanitizerFn | null = null): I18nUpdateOpCodes { + sanitizeFn: SanitizerFn|null = null): I18nUpdateOpCodes { const updateOpCodes: I18nUpdateOpCodes = [null, null]; // Alloc space for mask and size const textParts = str.split(BINDING_REGEXP); let mask = 0; @@ -508,7 +510,7 @@ function i18nStartFirstPass( } function appendI18nNode( - tView: TView, tNode: TNode, parentTNode: TNode, previousTNode: TNode | null, + tView: TView, tNode: TNode, parentTNode: TNode, previousTNode: TNode|null, lView: LView): TNode { ngDevMode && ngDevMode.rendererMoveNode++; const nextNode = tNode.next; @@ -577,7 +579,7 @@ function appendI18nNode( * @codeGenApi */ export function ɵɵi18nPostprocess( - message: string, replacements: {[key: string]: (string | string[])} = {}): string { + message: string, replacements: {[key: string]: (string|string[])} = {}): string { /** * Step 1: resolve all multi-value placeholders like [�#5�|�*1:1��#2:1�|�#4:1�] * @@ -660,7 +662,7 @@ export function ɵɵi18nPostprocess( if (!list.length) { throw new Error(`i18n postprocess: unmatched ICU - ${match} with key: ${key}`); } - return list.shift() !; + return list.shift()!; } return match; }); @@ -687,9 +689,10 @@ export function ɵɵi18nEnd(): void { * See `i18nEnd` above. */ function i18nEndFirstPass(tView: TView, lView: LView) { - ngDevMode && assertEqual( - getBindingIndex(), tView.bindingStartIndex, - 'i18nEnd should be called before any binding'); + ngDevMode && + assertEqual( + getBindingIndex(), tView.bindingStartIndex, + 'i18nEnd should be called before any binding'); const rootIndex = i18nIndexStack[i18nIndexStackPointer--]; const tI18n = tView.data[rootIndex + HEADER_OFFSET] as TI18n; @@ -709,8 +712,9 @@ function i18nEndFirstPass(tView: TView, lView: LView) { } // Check if an element has any local refs and skip them const tNode = getTNode(tView, index); - if (tNode && (tNode.type === TNodeType.Container || tNode.type === TNodeType.Element || - tNode.type === TNodeType.ElementContainer) && + if (tNode && + (tNode.type === TNodeType.Container || tNode.type === TNodeType.Element || + tNode.type === TNodeType.ElementContainer) && tNode.localNames !== null) { // Divide by 2 to get the number of local refs, // since they are stored as an array that also includes directive indexes, @@ -725,8 +729,8 @@ function i18nEndFirstPass(tView: TView, lView: LView) { * Creates and stores the dynamic TNode, and unhooks it from the tree for now. */ function createDynamicNodeAtIndex( - tView: TView, lView: LView, index: number, type: TNodeType, native: RElement | RText | null, - name: string | null): TElementNode|TIcuContainerNode { + tView: TView, lView: LView, index: number, type: TNodeType, native: RElement|RText|null, + name: string|null): TElementNode|TIcuContainerNode { const previousOrParentTNode = getPreviousOrParentTNode(); ngDevMode && assertDataInRange(lView, index + HEADER_OFFSET); lView[index + HEADER_OFFSET] = native; @@ -766,16 +770,16 @@ function readCreateOpCodes( if (destinationNodeIndex === index) { // If the destination node is `i18nStart`, we don't have a // top-level node and we should use the host node instead - destinationTNode = lView[T_HOST] !; + destinationTNode = lView[T_HOST]!; } else { destinationTNode = getTNode(tView, destinationNodeIndex); } ngDevMode && assertDefined( - currentTNode !, + currentTNode!, `You need to create or select a node before you can insert it into the DOM`); previousTNode = - appendI18nNode(tView, currentTNode !, destinationTNode, previousTNode, lView); + appendI18nNode(tView, currentTNode!, destinationTNode, previousTNode, lView); break; case I18nMutateOpCode.Select: // Negative indicies indicate that a given TNode is a sibling node, not a parent node @@ -811,9 +815,10 @@ function readCreateOpCodes( case COMMENT_MARKER: const commentValue = createOpCodes[++i] as string; const commentNodeIndex = createOpCodes[++i] as number; - ngDevMode && assertEqual( - typeof commentValue, 'string', - `Expected "${commentValue}" to be a comment node value`); + ngDevMode && + assertEqual( + typeof commentValue, 'string', + `Expected "${commentValue}" to be a comment node value`); const commentRNode = renderer.createComment(commentValue); ngDevMode && ngDevMode.rendererCreateComment++; previousTNode = currentTNode; @@ -828,9 +833,10 @@ function readCreateOpCodes( case ELEMENT_MARKER: const tagNameValue = createOpCodes[++i] as string; const elementNodeIndex = createOpCodes[++i] as number; - ngDevMode && assertEqual( - typeof tagNameValue, 'string', - `Expected "${tagNameValue}" to be an element node tag name`); + ngDevMode && + assertEqual( + typeof tagNameValue, 'string', + `Expected "${tagNameValue}" to be an element node tag name`); const elementRNode = renderer.createElement(tagNameValue); ngDevMode && ngDevMode.rendererCreateElement++; previousTNode = currentTNode; @@ -850,7 +856,7 @@ function readCreateOpCodes( } function readUpdateOpCodes( - updateOpCodes: I18nUpdateOpCodes, icus: TIcu[] | null, bindingsStartIndex: number, + updateOpCodes: I18nUpdateOpCodes, icus: TIcu[]|null, bindingsStartIndex: number, changeMask: number, tView: TView, lView: LView, bypassCheckBit = false) { let caseCreated = false; for (let i = 0; i < updateOpCodes.length; i++) { @@ -887,7 +893,7 @@ function readUpdateOpCodes( break; case I18nUpdateOpCode.IcuSwitch: tIcuIndex = updateOpCodes[++j] as number; - tIcu = icus ![tIcuIndex]; + tIcu = icus![tIcuIndex]; icuTNode = getTNode(tView, nodeIndex) as TIcuContainerNode; // If there is an active case, delete the old nodes if (icuTNode.activeCaseIndex !== null) { @@ -910,7 +916,7 @@ function readUpdateOpCodes( const activeIndex = nestedIcuTNode.activeCaseIndex; if (activeIndex !== null) { const nestedIcuTIndex = removeOpCode >>> I18nMutateOpCode.SHIFT_REF; - const nestedTIcu = icus ![nestedIcuTIndex]; + const nestedTIcu = icus![nestedIcuTIndex]; addAllToArray(nestedTIcu.remove[activeIndex], removeCodes); } break; @@ -929,7 +935,7 @@ function readUpdateOpCodes( break; case I18nUpdateOpCode.IcuUpdate: tIcuIndex = updateOpCodes[++j] as number; - tIcu = icus ![tIcuIndex]; + tIcu = icus![tIcuIndex]; icuTNode = getTNode(tView, nodeIndex) as TIcuContainerNode; if (icuTNode.activeCaseIndex !== null) { readUpdateOpCodes( @@ -1215,7 +1221,7 @@ function parseIcuCase( if (!inertBodyElement) { throw new Error('Unable to generate inert body element'); } - const wrapper = getTemplateContent(inertBodyElement !) as Element || inertBodyElement; + const wrapper = getTemplateContent(inertBodyElement!) as Element || inertBodyElement; const opCodes: IcuCase = {vars: 0, childIcus: [], create: [], remove: [], update: []}; parseNodes(wrapper.firstChild, opCodes, parentIndex, nestedIcus, tIcus, expandoStartIndex); return opCodes; @@ -1234,7 +1240,7 @@ const NESTED_ICU = /�(\d+)�/; * @param expandoStartIndex Expando start index for the current ICU expression */ function parseNodes( - currentNode: Node | null, icuCase: IcuCase, parentIndex: number, nestedIcus: IcuExpression[], + currentNode: Node|null, icuCase: IcuCase, parentIndex: number, nestedIcus: IcuExpression[], tIcus: TIcu[], expandoStartIndex: number) { if (currentNode) { const nestedIcusToCreate: [IcuExpression, number][] = []; @@ -1254,7 +1260,7 @@ function parseNodes( parentIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild); const elAttrs = element.attributes; for (let i = 0; i < elAttrs.length; i++) { - const attr = elAttrs.item(i) !; + const attr = elAttrs.item(i)!; const lowerAttrName = attr.name.toLowerCase(); const hasBinding = !!attr.value.match(BINDING_REGEXP); // we assume the input string is safe, unless it's using a binding @@ -1276,8 +1282,8 @@ function parseNodes( } } else { ngDevMode && - console.warn( - `WARNING: ignoring unsafe attribute value ${lowerAttrName} on element ${tagName} (see http://g.co/ng/security#xss)`); + console.warn(`WARNING: ignoring unsafe attribute value ${ + lowerAttrName} on element ${tagName} (see http://g.co/ng/security#xss)`); } } else { icuCase.create.push( @@ -1324,7 +1330,7 @@ function parseNodes( // We do not handle any other type of element icuCase.vars--; } - currentNode = nextNode !; + currentNode = nextNode!; } for (let i = 0; i < nestedIcusToCreate.length; i++) { diff --git a/packages/core/src/render3/index.ts b/packages/core/src/render3/index.ts index d88585000efae..cea4adee29992 100644 --- a/packages/core/src/render3/index.ts +++ b/packages/core/src/render3/index.ts @@ -16,13 +16,14 @@ import {getComponent, getDirectives, getHostElement, getRenderedText} from './ut export {ComponentFactory, ComponentFactoryResolver, ComponentRef, injectComponentFactoryResolver} from './component_ref'; export {ɵɵgetFactoryOf, ɵɵgetInheritedFactory} from './di'; - +export {getLocaleId, setLocaleId, ɵɵi18n, ɵɵi18nApply, ɵɵi18nAttributes, ɵɵi18nEnd, ɵɵi18nExp, ɵɵi18nPostprocess, ɵɵi18nStart,} from './i18n'; // clang-format off export { detectChanges, markDirty, store, tick, + ɵɵadvance, ɵɵattribute, ɵɵattributeInterpolate1, @@ -54,7 +55,6 @@ export { ɵɵcontainerRefreshStart, ɵɵdirectiveInject, - ɵɵinvalidFactory, ɵɵelement, ɵɵelementContainer, @@ -69,7 +69,9 @@ export { ɵɵembeddedViewStart, ɵɵgetCurrentView, + ɵɵhostProperty, ɵɵinjectAttribute, + ɵɵinvalidFactory, ɵɵlistener, @@ -81,7 +83,6 @@ export { ɵɵprojection, ɵɵprojectionDef, - ɵɵhostProperty, ɵɵproperty, ɵɵpropertyInterpolate, ɵɵpropertyInterpolate1, @@ -98,7 +99,6 @@ export { // TODO: remove `select` once we've refactored all of the tests not to use it. ɵɵselect, - ɵɵadvance, ɵɵstyleMap, ɵɵstyleMapInterpolate1, ɵɵstyleMapInterpolate2, @@ -139,37 +139,14 @@ export { ɵɵupdateSyntheticHostBinding, } from './instructions/all'; export {RenderFlags} from './interfaces/definition'; -export {CssSelectorList, ProjectionSlots} from './interfaces/projection'; - -export { - ɵɵrestoreView, - - ɵɵenableBindings, - ɵɵdisableBindings, -} from './state'; - -export { - ɵɵi18n, - ɵɵi18nAttributes, - ɵɵi18nExp, - ɵɵi18nStart, - ɵɵi18nEnd, - ɵɵi18nApply, - ɵɵi18nPostprocess, - getLocaleId, - setLocaleId, -} from './i18n'; - -export {NgModuleFactory, NgModuleRef, NgModuleType} from './ng_module_ref'; - export { AttributeMarker } from './interfaces/node'; - +export {CssSelectorList, ProjectionSlots} from './interfaces/projection'; export { setClassMetadata, } from './metadata'; - +export {NgModuleFactory, NgModuleRef, NgModuleType} from './ng_module_ref'; export { ɵɵpipe, ɵɵpipeBind1, @@ -178,16 +155,6 @@ export { ɵɵpipeBind4, ɵɵpipeBindV, } from './pipe'; - -export { - ɵɵqueryRefresh, - ɵɵviewQuery, - ɵɵstaticViewQuery, - ɵɵloadQuery, - ɵɵcontentQuery, - ɵɵstaticContentQuery -} from './query'; - export { ɵɵpureFunction0, ɵɵpureFunction1, @@ -200,41 +167,51 @@ export { ɵɵpureFunction8, ɵɵpureFunctionV, } from './pure_function'; +export { + ɵɵcontentQuery, + ɵɵloadQuery, + ɵɵqueryRefresh, + ɵɵstaticContentQuery +, + ɵɵstaticViewQuery, + ɵɵviewQuery} from './query'; +export { + ɵɵdisableBindings, -export {ɵɵtemplateRefExtractor, ɵɵinjectPipeChangeDetectorRef} from './view_engine_compatibility_prebound'; - -export {ɵɵresolveWindow, ɵɵresolveDocument, ɵɵresolveBody} from './util/misc_utils'; - + ɵɵenableBindings, + ɵɵrestoreView, +} from './state'; +export {NO_CHANGE} from './tokens'; +export { ɵɵresolveBody, ɵɵresolveDocument,ɵɵresolveWindow} from './util/misc_utils'; +export { ɵɵinjectPipeChangeDetectorRef,ɵɵtemplateRefExtractor} from './view_engine_compatibility_prebound'; // clang-format on export { ComponentDef, - ɵɵComponentDefWithMeta, - ɵɵFactoryDef, ComponentTemplate, ComponentType, DirectiveDef, - ɵɵDirectiveDefWithMeta, DirectiveType, - ɵɵNgOnChangesFeature, - ɵɵCopyDefinitionFeature, - ɵɵInheritDefinitionFeature, - ɵɵProvidersFeature, - PipeDef, - ɵɵPipeDefWithMeta, + getComponent, + getDirectives, + getHostElement, + getRenderedText, LifecycleHooksFeature, + PipeDef, + renderComponent, + whenRendered, + ɵɵComponentDefWithMeta, + ɵɵCopyDefinitionFeature, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdefineNgModule, ɵɵdefinePipe, - getHostElement, - getComponent, - getDirectives, - getRenderedText, - renderComponent, + ɵɵDirectiveDefWithMeta, + ɵɵFactoryDef, + ɵɵInheritDefinitionFeature, + ɵɵNgOnChangesFeature, + ɵɵPipeDefWithMeta, + ɵɵProvidersFeature, ɵɵsetComponentScope, ɵɵsetNgModuleScope, - whenRendered, }; - -export {NO_CHANGE} from './tokens'; diff --git a/packages/core/src/render3/instructions/advance.ts b/packages/core/src/render3/instructions/advance.ts index 551de37caf1fa..a4eabdd557bd6 100644 --- a/packages/core/src/render3/instructions/advance.ts +++ b/packages/core/src/render3/instructions/advance.ts @@ -19,21 +19,21 @@ import {getCheckNoChangesMode, getLView, getSelectedIndex, getTView, setSelected * * ```ts * (rf: RenderFlags, ctx: any) => { - * if (rf & 1) { - * text(0, 'Hello'); - * text(1, 'Goodbye') - * element(2, 'div'); - * } - * if (rf & 2) { - * advance(2); // Advance twice to the <div>. - * property('title', 'test'); - * } - * } - * ``` - * @param delta Number of elements to advance forwards by. - * - * @codeGenApi - */ + * if (rf & 1) { + * text(0, 'Hello'); + * text(1, 'Goodbye') + * element(2, 'div'); + * } + * if (rf & 2) { + * advance(2); // Advance twice to the <div>. + * property('title', 'test'); + * } + * } + * ``` + * @param delta Number of elements to advance forwards by. + * + * @codeGenApi + */ export function ɵɵadvance(delta: number): void { ngDevMode && assertGreaterThan(delta, 0, 'Can only advance forward'); selectIndexInternal(getTView(), getLView(), getSelectedIndex() + delta, getCheckNoChangesMode()); diff --git a/packages/core/src/render3/instructions/attribute.ts b/packages/core/src/render3/instructions/attribute.ts index a3a2bfab8fba8..380eec1ba23f3 100644 --- a/packages/core/src/render3/instructions/attribute.ts +++ b/packages/core/src/render3/instructions/attribute.ts @@ -26,7 +26,7 @@ import {elementAttributeInternal, storePropertyBindingMetadata} from './shared'; * @codeGenApi */ export function ɵɵattribute( - name: string, value: any, sanitizer?: SanitizerFn | null, + name: string, value: any, sanitizer?: SanitizerFn|null, namespace?: string): typeof ɵɵattribute { const lView = getLView(); const bindingIndex = nextBindingIndex(); diff --git a/packages/core/src/render3/instructions/attribute_interpolation.ts b/packages/core/src/render3/instructions/attribute_interpolation.ts index 96f7e8b01e1a4..0de336c78af0f 100644 --- a/packages/core/src/render3/instructions/attribute_interpolation.ts +++ b/packages/core/src/render3/instructions/attribute_interpolation.ts @@ -130,9 +130,10 @@ export function ɵɵattributeInterpolate3( if (interpolatedValue !== NO_CHANGE) { const tNode = getSelectedTNode(); elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, - i1, suffix); + ngDevMode && + storePropertyBindingMetadata( + getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 3, prefix, i0, i1, + suffix); } return ɵɵattributeInterpolate3; } @@ -177,9 +178,10 @@ export function ɵɵattributeInterpolate4( if (interpolatedValue !== NO_CHANGE) { const tNode = getSelectedTNode(); elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, - i1, i2, suffix); + ngDevMode && + storePropertyBindingMetadata( + getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 4, prefix, i0, i1, i2, + suffix); } return ɵɵattributeInterpolate4; } @@ -227,9 +229,10 @@ export function ɵɵattributeInterpolate5( if (interpolatedValue !== NO_CHANGE) { const tNode = getSelectedTNode(); elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, - i1, i2, i3, suffix); + ngDevMode && + storePropertyBindingMetadata( + getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 5, prefix, i0, i1, i2, + i3, suffix); } return ɵɵattributeInterpolate5; } @@ -279,9 +282,10 @@ export function ɵɵattributeInterpolate6( if (interpolatedValue !== NO_CHANGE) { const tNode = getSelectedTNode(); elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, - i1, i2, i3, i4, suffix); + ngDevMode && + storePropertyBindingMetadata( + getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 6, prefix, i0, i1, i2, + i3, i4, suffix); } return ɵɵattributeInterpolate6; } @@ -333,9 +337,10 @@ export function ɵɵattributeInterpolate7( if (interpolatedValue !== NO_CHANGE) { const tNode = getSelectedTNode(); elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, - i1, i2, i3, i4, i5, suffix); + ngDevMode && + storePropertyBindingMetadata( + getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 7, prefix, i0, i1, i2, + i3, i4, i5, suffix); } return ɵɵattributeInterpolate7; } @@ -389,9 +394,10 @@ export function ɵɵattributeInterpolate8( if (interpolatedValue !== NO_CHANGE) { const tNode = getSelectedTNode(); elementAttributeInternal(tNode, lView, attrName, interpolatedValue, sanitizer, namespace); - ngDevMode && storePropertyBindingMetadata( - getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, - i1, i2, i3, i4, i5, i6, suffix); + ngDevMode && + storePropertyBindingMetadata( + getTView().data, tNode, 'attr.' + attrName, getBindingIndex() - 8, prefix, i0, i1, i2, + i3, i4, i5, i6, suffix); } return ɵɵattributeInterpolate8; } diff --git a/packages/core/src/render3/instructions/change_detection.ts b/packages/core/src/render3/instructions/change_detection.ts index 3a78623e3c91e..c667cfac7c67d 100644 --- a/packages/core/src/render3/instructions/change_detection.ts +++ b/packages/core/src/render3/instructions/change_detection.ts @@ -35,7 +35,7 @@ export function detectChanges(component: {}): void { */ export function markDirty(component: {}): void { ngDevMode && assertDefined(component, 'component'); - const rootView = markViewDirty(getComponentViewByInstance(component)) !; + const rootView = markViewDirty(getComponentViewByInstance(component))!; ngDevMode && assertDefined(rootView[CONTEXT], 'rootContext should be defined'); scheduleTick(rootView[CONTEXT] as RootContext, RootContextFlags.DetectChanges); diff --git a/packages/core/src/render3/instructions/container.ts b/packages/core/src/render3/instructions/container.ts index 70c0ce0cd888c..4685b665c2d14 100644 --- a/packages/core/src/render3/instructions/container.ts +++ b/packages/core/src/render3/instructions/container.ts @@ -13,11 +13,12 @@ import {ACTIVE_INDEX, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/c import {ComponentTemplate} from '../interfaces/definition'; import {LocalRefExtractor, TAttributes, TContainerNode, TNode, TNodeType, TViewNode} from '../interfaces/node'; import {isDirectiveHost} from '../interfaces/type_checks'; -import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, TView, TViewType, T_HOST} from '../interfaces/view'; +import {FLAGS, HEADER_OFFSET, InitPhaseState, LView, LViewFlags, RENDERER, T_HOST, TView, TViewType} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild, removeView} from '../node_manipulation'; import {getBindingIndex, getCheckNoChangesMode, getIsParent, getLView, getPreviousOrParentTNode, getTView, setIsNotParent, setPreviousOrParentTNode} from '../state'; import {getConstant, getLContainerActiveIndex, load} from '../util/view_utils'; + import {addToViewTree, createDirectivesInstances, createLContainer, createTNode, createTView, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared'; @@ -45,9 +46,9 @@ export function ɵɵcontainer(index: number): void { } function templateFirstCreatePass( - index: number, tView: TView, lView: LView, templateFn: ComponentTemplate<any>| null, - decls: number, vars: number, tagName?: string | null, attrsIndex?: number | null, - localRefsIndex?: number | null): TContainerNode { + index: number, tView: TView, lView: LView, templateFn: ComponentTemplate<any>|null, + decls: number, vars: number, tagName?: string|null, attrsIndex?: number|null, + localRefsIndex?: number|null): TContainerNode { ngDevMode && assertFirstCreatePass(tView); ngDevMode && ngDevMode.firstCreatePass++; const tViewConsts = tView.consts; @@ -94,8 +95,8 @@ function templateFirstCreatePass( * @codeGenApi */ export function ɵɵtemplate( - index: number, templateFn: ComponentTemplate<any>| null, decls: number, vars: number, - tagName?: string | null, attrsIndex?: number | null, localRefsIndex?: number | null, + index: number, templateFn: ComponentTemplate<any>|null, decls: number, vars: number, + tagName?: string|null, attrsIndex?: number|null, localRefsIndex?: number|null, localRefExtractor?: LocalRefExtractor) { const lView = getLView(); const tView = getTView(); @@ -172,7 +173,7 @@ export function ɵɵcontainerRefreshEnd(): void { } else { ngDevMode && assertNodeType(previousOrParentTNode, TNodeType.View); ngDevMode && assertHasParent(previousOrParentTNode); - previousOrParentTNode = previousOrParentTNode.parent !; + previousOrParentTNode = previousOrParentTNode.parent!; setPreviousOrParentTNode(previousOrParentTNode, false); } @@ -188,11 +189,12 @@ export function ɵɵcontainerRefreshEnd(): void { } function containerInternal( - tView: TView, lView: LView, nodeIndex: number, tagName: string | null, - attrs: TAttributes | null): TContainerNode { - ngDevMode && assertEqual( - getBindingIndex(), tView.bindingStartIndex, - 'container nodes should be created before any bindings'); + tView: TView, lView: LView, nodeIndex: number, tagName: string|null, + attrs: TAttributes|null): TContainerNode { + ngDevMode && + assertEqual( + getBindingIndex(), tView.bindingStartIndex, + 'container nodes should be created before any bindings'); const adjustedIndex = nodeIndex + HEADER_OFFSET; ngDevMode && assertDataInRange(lView, nodeIndex + HEADER_OFFSET); diff --git a/packages/core/src/render3/instructions/di.ts b/packages/core/src/render3/instructions/di.ts index 71a2f8b6d910b..5c0be8f07962a 100644 --- a/packages/core/src/render3/instructions/di.ts +++ b/packages/core/src/render3/instructions/di.ts @@ -37,10 +37,10 @@ import {getLView, getPreviousOrParentTNode} from '../state'; * * @codeGenApi */ -export function ɵɵdirectiveInject<T>(token: Type<T>| InjectionToken<T>): T; -export function ɵɵdirectiveInject<T>(token: Type<T>| InjectionToken<T>, flags: InjectFlags): T; +export function ɵɵdirectiveInject<T>(token: Type<T>|InjectionToken<T>): T; +export function ɵɵdirectiveInject<T>(token: Type<T>|InjectionToken<T>, flags: InjectFlags): T; export function ɵɵdirectiveInject<T>( - token: Type<T>| InjectionToken<T>, flags = InjectFlags.Default): T|null { + token: Type<T>|InjectionToken<T>, flags = InjectFlags.Default): T|null { const lView = getLView(); // Fall back to inject() if view hasn't been created. This situation can happen in tests // if inject utilities are used before bootstrapping. diff --git a/packages/core/src/render3/instructions/element.ts b/packages/core/src/render3/instructions/element.ts index 52eda6249bcef..2810fa4073da6 100644 --- a/packages/core/src/render3/instructions/element.ts +++ b/packages/core/src/render3/instructions/element.ts @@ -10,23 +10,24 @@ import {assertDataInRange, assertDefined, assertEqual} from '../../util/assert'; import {assertFirstCreatePass, assertHasParent} from '../assert'; import {attachPatchData} from '../context_discovery'; import {registerPostOrderHooks} from '../hooks'; -import {TAttributes, TElementNode, TNode, TNodeType, hasClassInput, hasStyleInput} from '../interfaces/node'; +import {hasClassInput, hasStyleInput, TAttributes, TElementNode, TNode, TNodeType} from '../interfaces/node'; import {RElement} from '../interfaces/renderer'; import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks'; -import {HEADER_OFFSET, LView, RENDERER, TVIEW, TView, T_HOST} from '../interfaces/view'; +import {HEADER_OFFSET, LView, RENDERER, T_HOST, TVIEW, TView} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild, writeDirectClass, writeDirectStyle} from '../node_manipulation'; import {decreaseElementDepthCount, getBindingIndex, getElementDepthCount, getIsParent, getLView, getNamespace, getPreviousOrParentTNode, getTView, increaseElementDepthCount, setIsNotParent, setPreviousOrParentTNode} from '../state'; import {computeStaticStyling} from '../styling/static_styling'; import {setUpAttributes} from '../util/attrs_utils'; import {getConstant} from '../util/view_utils'; + import {setDirectiveInputsWhichShadowsStyling} from './property'; import {createDirectivesInstances, elementCreate, executeContentQueries, getOrCreateTNode, matchingSchemas, resolveDirectives, saveResolvedLocalsInData} from './shared'; function elementStartFirstCreatePass( index: number, tView: TView, lView: LView, native: RElement, name: string, - attrsIndex?: number | null, localRefsIndex?: number): TElementNode { + attrsIndex?: number|null, localRefsIndex?: number): TElementNode { ngDevMode && assertFirstCreatePass(tView); ngDevMode && ngDevMode.firstCreatePass++; @@ -64,14 +65,15 @@ function elementStartFirstCreatePass( * @codeGenApi */ export function ɵɵelementStart( - index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void { + index: number, name: string, attrsIndex?: number|null, localRefsIndex?: number): void { const lView = getLView(); const tView = getTView(); const adjustedIndex = HEADER_OFFSET + index; - ngDevMode && assertEqual( - getBindingIndex(), tView.bindingStartIndex, - 'elements should be created before any bindings'); + ngDevMode && + assertEqual( + getBindingIndex(), tView.bindingStartIndex, + 'elements should be created before any bindings'); ngDevMode && ngDevMode.rendererCreateElement++; ngDevMode && assertDataInRange(lView, adjustedIndex); @@ -128,7 +130,7 @@ export function ɵɵelementEnd(): void { setIsNotParent(); } else { ngDevMode && assertHasParent(getPreviousOrParentTNode()); - previousOrParentTNode = previousOrParentTNode.parent !; + previousOrParentTNode = previousOrParentTNode.parent!; setPreviousOrParentTNode(previousOrParentTNode, false); } @@ -142,7 +144,7 @@ export function ɵɵelementEnd(): void { if (tView.firstCreatePass) { registerPostOrderHooks(tView, previousOrParentTNode); if (isContentQueryHost(previousOrParentTNode)) { - tView.queries !.elementEnd(previousOrParentTNode); + tView.queries!.elementEnd(previousOrParentTNode); } } @@ -166,7 +168,7 @@ export function ɵɵelementEnd(): void { * @codeGenApi */ export function ɵɵelement( - index: number, name: string, attrsIndex?: number | null, localRefsIndex?: number): void { + index: number, name: string, attrsIndex?: number|null, localRefsIndex?: number): void { ɵɵelementStart(index, name, attrsIndex, localRefsIndex); ɵɵelementEnd(); } @@ -198,11 +200,11 @@ function warnAboutUnknownElement( if (isUnknown && !matchingSchemas(tView, lView, tagName)) { let warning = `'${tagName}' is not a known element:\n`; - warning += - `1. If '${tagName}' is an Angular component, then verify that it is part of this module.\n`; + warning += `1. If '${ + tagName}' is an Angular component, then verify that it is part of this module.\n`; if (tagName && tagName.indexOf('-') > -1) { - warning += - `2. If '${tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; + warning += `2. If '${ + tagName}' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.`; } else { warning += `2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component.`; diff --git a/packages/core/src/render3/instructions/element_container.ts b/packages/core/src/render3/instructions/element_container.ts index 54f1cd9dd31b9..d7e3549c6175b 100644 --- a/packages/core/src/render3/instructions/element_container.ts +++ b/packages/core/src/render3/instructions/element_container.ts @@ -11,7 +11,7 @@ import {attachPatchData} from '../context_discovery'; import {registerPostOrderHooks} from '../hooks'; import {TAttributes, TElementContainerNode, TNodeType} from '../interfaces/node'; import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks'; -import {HEADER_OFFSET, LView, RENDERER, TView, T_HOST} from '../interfaces/view'; +import {HEADER_OFFSET, LView, RENDERER, T_HOST, TView} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {appendChild} from '../node_manipulation'; import {getBindingIndex, getIsParent, getLView, getPreviousOrParentTNode, getTView, setIsNotParent, setPreviousOrParentTNode} from '../state'; @@ -21,7 +21,7 @@ import {getConstant} from '../util/view_utils'; import {createDirectivesInstances, executeContentQueries, getOrCreateTNode, resolveDirectives, saveResolvedLocalsInData} from './shared'; function elementContainerStartFirstCreatePass( - index: number, tView: TView, lView: LView, attrsIndex?: number | null, + index: number, tView: TView, lView: LView, attrsIndex?: number|null, localRefsIndex?: number): TElementContainerNode { ngDevMode && ngDevMode.firstCreatePass++; @@ -61,15 +61,16 @@ function elementContainerStartFirstCreatePass( * @codeGenApi */ export function ɵɵelementContainerStart( - index: number, attrsIndex?: number | null, localRefsIndex?: number): void { + index: number, attrsIndex?: number|null, localRefsIndex?: number): void { const lView = getLView(); const tView = getTView(); const adjustedIndex = index + HEADER_OFFSET; ngDevMode && assertDataInRange(lView, adjustedIndex); - ngDevMode && assertEqual( - getBindingIndex(), tView.bindingStartIndex, - 'element containers should be created before any bindings'); + ngDevMode && + assertEqual( + getBindingIndex(), tView.bindingStartIndex, + 'element containers should be created before any bindings'); const tNode = tView.firstCreatePass ? elementContainerStartFirstCreatePass(index, tView, lView, attrsIndex, localRefsIndex) : @@ -104,7 +105,7 @@ export function ɵɵelementContainerEnd(): void { setIsNotParent(); } else { ngDevMode && assertHasParent(previousOrParentTNode); - previousOrParentTNode = previousOrParentTNode.parent !; + previousOrParentTNode = previousOrParentTNode.parent!; setPreviousOrParentTNode(previousOrParentTNode, false); } @@ -113,7 +114,7 @@ export function ɵɵelementContainerEnd(): void { if (tView.firstCreatePass) { registerPostOrderHooks(tView, previousOrParentTNode); if (isContentQueryHost(previousOrParentTNode)) { - tView.queries !.elementEnd(previousOrParentTNode); + tView.queries!.elementEnd(previousOrParentTNode); } } } @@ -129,7 +130,7 @@ export function ɵɵelementContainerEnd(): void { * @codeGenApi */ export function ɵɵelementContainer( - index: number, attrsIndex?: number | null, localRefsIndex?: number): void { + index: number, attrsIndex?: number|null, localRefsIndex?: number): void { ɵɵelementContainerStart(index, attrsIndex, localRefsIndex); ɵɵelementContainerEnd(); } diff --git a/packages/core/src/render3/instructions/embedded_view.ts b/packages/core/src/render3/instructions/embedded_view.ts index 777d22911baa2..971d04214f954 100644 --- a/packages/core/src/render3/instructions/embedded_view.ts +++ b/packages/core/src/render3/instructions/embedded_view.ts @@ -11,7 +11,7 @@ import {assertLContainerOrUndefined} from '../assert'; import {ACTIVE_INDEX, ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container'; import {RenderFlags} from '../interfaces/definition'; import {TContainerNode, TNodeType} from '../interfaces/node'; -import {CONTEXT, LView, LViewFlags, PARENT, TVIEW, TView, TViewType, T_HOST} from '../interfaces/view'; +import {CONTEXT, LView, LViewFlags, PARENT, T_HOST, TVIEW, TView, TViewType} from '../interfaces/view'; import {assertNodeType} from '../node_assert'; import {insertView, removeView} from '../node_manipulation'; import {enterView, getIsParent, getLView, getPreviousOrParentTNode, getTView, leaveView, setIsParent, setPreviousOrParentTNode} from '../state'; @@ -34,7 +34,7 @@ export function ɵɵembeddedViewStart(viewBlockId: number, decls: number, vars: const previousOrParentTNode = getPreviousOrParentTNode(); // The previous node can be a view node if we are processing an inline for loop const containerTNode = previousOrParentTNode.type === TNodeType.View ? - previousOrParentTNode.parent ! : + previousOrParentTNode.parent! : previousOrParentTNode; const lContainer = lView[containerTNode.index] as LContainer; @@ -141,5 +141,5 @@ export function ɵɵembeddedViewEnd(): void { const lContainer = lView[PARENT] as LContainer; ngDevMode && assertLContainerOrUndefined(lContainer); leaveView(); - setPreviousOrParentTNode(viewHost !, false); + setPreviousOrParentTNode(viewHost!, false); } diff --git a/packages/core/src/render3/instructions/host_property.ts b/packages/core/src/render3/instructions/host_property.ts index cc662152dcc16..800519c932450 100644 --- a/packages/core/src/render3/instructions/host_property.ts +++ b/packages/core/src/render3/instructions/host_property.ts @@ -28,7 +28,7 @@ import {elementPropertyInternal, loadComponentRenderer, storePropertyBindingMeta * @codeGenApi */ export function ɵɵhostProperty<T>( - propName: string, value: T, sanitizer?: SanitizerFn | null): typeof ɵɵhostProperty { + propName: string, value: T, sanitizer?: SanitizerFn|null): typeof ɵɵhostProperty { const lView = getLView(); const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { @@ -63,8 +63,8 @@ export function ɵɵhostProperty<T>( * @codeGenApi */ export function ɵɵupdateSyntheticHostBinding<T>( - propName: string, value: T | NO_CHANGE, - sanitizer?: SanitizerFn | null): typeof ɵɵupdateSyntheticHostBinding { + propName: string, value: T|NO_CHANGE, + sanitizer?: SanitizerFn|null): typeof ɵɵupdateSyntheticHostBinding { const lView = getLView(); const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { diff --git a/packages/core/src/render3/instructions/interpolation.ts b/packages/core/src/render3/instructions/interpolation.ts index 21ef666c231aa..8b775b6691ece 100644 --- a/packages/core/src/render3/instructions/interpolation.ts +++ b/packages/core/src/render3/instructions/interpolation.ts @@ -102,10 +102,9 @@ export function interpolation4( const different = bindingUpdated4(lView, bindingIndex, v0, v1, v2, v3); incrementBindingIndex(4); - return different ? - prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + - renderStringify(v3) + suffix : - NO_CHANGE; + return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + + renderStringify(v2) + i2 + renderStringify(v3) + suffix : + NO_CHANGE; } /** @@ -119,10 +118,9 @@ export function interpolation5( different = bindingUpdated(lView, bindingIndex + 4, v4) || different; incrementBindingIndex(5); - return different ? - prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + - renderStringify(v3) + i3 + renderStringify(v4) + suffix : - NO_CHANGE; + return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + + renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + suffix : + NO_CHANGE; } /** @@ -154,11 +152,10 @@ export function interpolation7( different = bindingUpdated3(lView, bindingIndex + 4, v4, v5, v6) || different; incrementBindingIndex(7); - return different ? - prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + - renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 + - renderStringify(v6) + suffix : - NO_CHANGE; + return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + + renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 + + renderStringify(v5) + i5 + renderStringify(v6) + suffix : + NO_CHANGE; } /** @@ -173,9 +170,8 @@ export function interpolation8( different = bindingUpdated4(lView, bindingIndex + 4, v4, v5, v6, v7) || different; incrementBindingIndex(8); - return different ? - prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + renderStringify(v2) + i2 + - renderStringify(v3) + i3 + renderStringify(v4) + i4 + renderStringify(v5) + i5 + - renderStringify(v6) + i6 + renderStringify(v7) + suffix : - NO_CHANGE; + return different ? prefix + renderStringify(v0) + i0 + renderStringify(v1) + i1 + + renderStringify(v2) + i2 + renderStringify(v3) + i3 + renderStringify(v4) + i4 + + renderStringify(v5) + i5 + renderStringify(v6) + i6 + renderStringify(v7) + suffix : + NO_CHANGE; } diff --git a/packages/core/src/render3/instructions/listener.ts b/packages/core/src/render3/instructions/listener.ts index 981924a988033..dc7cc4faefa18 100644 --- a/packages/core/src/render3/instructions/listener.ts +++ b/packages/core/src/render3/instructions/listener.ts @@ -11,12 +11,13 @@ import {assertDataInRange} from '../../util/assert'; import {isObservable} from '../../util/lang'; import {EMPTY_OBJ} from '../empty'; import {PropertyAliasValue, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; -import {GlobalTargetResolver, RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer'; +import {GlobalTargetResolver, isProceduralRenderer, RElement, Renderer3} from '../interfaces/renderer'; import {isDirectiveHost} from '../interfaces/type_checks'; import {CLEANUP, FLAGS, LView, LViewFlags, RENDERER, TView} from '../interfaces/view'; import {assertNodeOfPossibleTypes} from '../node_assert'; import {getLView, getPreviousOrParentTNode, getTView} from '../state'; import {getComponentLViewByIndex, getNativeByTNode, unwrapRNode} from '../util/view_utils'; + import {getLCleanup, handleError, loadComponentRenderer, markViewDirty} from './shared'; @@ -47,26 +48,26 @@ export function ɵɵlistener( } /** -* Registers a synthetic host listener (e.g. `(@foo.start)`) on a component. -* -* This instruction is for compatibility purposes and is designed to ensure that a -* synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered -* in the component's renderer. Normally all host listeners are evaluated with the -* parent component's renderer, but, in the case of animation @triggers, they need -* to be evaluated with the sub component's renderer (because that's where the -* animation triggers are defined). -* -* Do not use this instruction as a replacement for `listener`. This instruction -* only exists to ensure compatibility with the ViewEngine's host binding behavior. -* -* @param eventName Name of the event -* @param listenerFn The function to be called when event emits -* @param useCapture Whether or not to use capture in event listener -* @param eventTargetResolver Function that returns global target information in case this listener -* should be attached to a global object like window, document or body + * Registers a synthetic host listener (e.g. `(@foo.start)`) on a component. + * + * This instruction is for compatibility purposes and is designed to ensure that a + * synthetic host listener (e.g. `@HostListener('@foo.start')`) properly gets rendered + * in the component's renderer. Normally all host listeners are evaluated with the + * parent component's renderer, but, in the case of animation @triggers, they need + * to be evaluated with the sub component's renderer (because that's where the + * animation triggers are defined). + * + * Do not use this instruction as a replacement for `listener`. This instruction + * only exists to ensure compatibility with the ViewEngine's host binding behavior. + * + * @param eventName Name of the event + * @param listenerFn The function to be called when event emits + * @param useCapture Whether or not to use capture in event listener + * @param eventTargetResolver Function that returns global target information in case this listener + * should be attached to a global object like window, document or body * * @codeGenApi -*/ + */ export function ɵɵcomponentHostSyntheticListener( eventName: string, listenerFn: (e?: any) => any, useCapture = false, eventTargetResolver?: GlobalTargetResolver): typeof ɵɵcomponentHostSyntheticListener { @@ -94,7 +95,7 @@ function findExistingListener( // We have found a matching event name on the same node but it might not have been // registered yet, so we must explicitly verify entries in the LView cleanup data // structures. - const lCleanup = lView[CLEANUP] !; + const lCleanup = lView[CLEANUP]!; const listenerIdxInLCleanup = tCleanup[i + 2]; return lCleanup.length > listenerIdxInLCleanup ? lCleanup[listenerIdxInLCleanup] : null; } @@ -124,8 +125,9 @@ function listenerInternal( // register a listener and store its cleanup function on LView. const lCleanup = getLCleanup(lView); - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); let processOutputs = true; @@ -207,8 +209,8 @@ function listenerInternal( const output = directiveInstance[minifiedName]; if (ngDevMode && !isObservable(output)) { - throw new Error( - `@Output ${minifiedName} not initialized in '${directiveInstance.constructor.name}'.`); + throw new Error(`@Output ${minifiedName} not initialized in '${ + directiveInstance.constructor.name}'.`); } const subscription = output.subscribe(listenerFn); diff --git a/packages/core/src/render3/instructions/projection.ts b/packages/core/src/render3/instructions/projection.ts index b432a37d646d8..c6ded02f7a6bd 100644 --- a/packages/core/src/render3/instructions/projection.ts +++ b/packages/core/src/render3/instructions/projection.ts @@ -79,9 +79,9 @@ export function ɵɵprojectionDef(projectionSlots?: ProjectionSlots): void { // If no explicit projection slots are defined, fall back to a single // projection slot with the wildcard selector. const numProjectionSlots = projectionSlots ? projectionSlots.length : 1; - const projectionHeads: (TNode | null)[] = componentNode.projection = - newArray(numProjectionSlots, null !as TNode); - const tails: (TNode | null)[] = projectionHeads.slice(); + const projectionHeads: (TNode|null)[] = componentNode.projection = + newArray(numProjectionSlots, null! as TNode); + const tails: (TNode|null)[] = projectionHeads.slice(); let componentChild: TNode|null = componentNode.child; @@ -91,7 +91,7 @@ export function ɵɵprojectionDef(projectionSlots?: ProjectionSlots): void { if (slotIndex !== null) { if (tails[slotIndex]) { - tails[slotIndex] !.projectionNext = componentChild; + tails[slotIndex]!.projectionNext = componentChild; } else { projectionHeads[slotIndex] = componentChild; } @@ -119,7 +119,7 @@ export function setDelayProjection(value: boolean) { * - 1 based index of the selector from the {@link projectionDef} * * @codeGenApi -*/ + */ export function ɵɵprojection( nodeIndex: number, selectorIndex: number = 0, attrs?: TAttributes): void { const lView = getLView(); diff --git a/packages/core/src/render3/instructions/property.ts b/packages/core/src/render3/instructions/property.ts index 5867fc9eca8e0..ab79a35bcdd12 100644 --- a/packages/core/src/render3/instructions/property.ts +++ b/packages/core/src/render3/instructions/property.ts @@ -33,7 +33,7 @@ import {elementPropertyInternal, setInputsForProperty, storePropertyBindingMetad * @codeGenApi */ export function ɵɵproperty<T>( - propName: string, value: T, sanitizer?: SanitizerFn | null): typeof ɵɵproperty { + propName: string, value: T, sanitizer?: SanitizerFn|null): typeof ɵɵproperty { const lView = getLView(); const bindingIndex = nextBindingIndex(); if (bindingUpdated(lView, bindingIndex, value)) { @@ -52,7 +52,7 @@ export function ɵɵproperty<T>( */ export function setDirectiveInputsWhichShadowsStyling( tView: TView, tNode: TNode, lView: LView, value: any, isClassBased: boolean) { - const inputs = tNode.inputs !; + const inputs = tNode.inputs!; const property = isClassBased ? 'class' : 'style'; // We support both 'class' and `className` hence the fallback. setInputsForProperty(tView, lView, inputs[property], property, value); diff --git a/packages/core/src/render3/instructions/property_interpolation.ts b/packages/core/src/render3/instructions/property_interpolation.ts index 373f5912116bd..6059d1985b003 100644 --- a/packages/core/src/render3/instructions/property_interpolation.ts +++ b/packages/core/src/render3/instructions/property_interpolation.ts @@ -88,8 +88,9 @@ export function ɵɵpropertyInterpolate1( const tNode = getSelectedTNode(); elementPropertyInternal( tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false); - ngDevMode && storePropertyBindingMetadata( - tView.data, tNode, propName, getBindingIndex() - 1, prefix, suffix); + ngDevMode && + storePropertyBindingMetadata( + tView.data, tNode, propName, getBindingIndex() - 1, prefix, suffix); } return ɵɵpropertyInterpolate1; } @@ -134,8 +135,9 @@ export function ɵɵpropertyInterpolate2( const tNode = getSelectedTNode(); elementPropertyInternal( tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false); - ngDevMode && storePropertyBindingMetadata( - tView.data, tNode, propName, getBindingIndex() - 2, prefix, i0, suffix); + ngDevMode && + storePropertyBindingMetadata( + tView.data, tNode, propName, getBindingIndex() - 2, prefix, i0, suffix); } return ɵɵpropertyInterpolate2; } @@ -183,8 +185,9 @@ export function ɵɵpropertyInterpolate3( const tNode = getSelectedTNode(); elementPropertyInternal( tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false); - ngDevMode && storePropertyBindingMetadata( - tView.data, tNode, propName, getBindingIndex() - 3, prefix, i0, i1, suffix); + ngDevMode && + storePropertyBindingMetadata( + tView.data, tNode, propName, getBindingIndex() - 3, prefix, i0, i1, suffix); } return ɵɵpropertyInterpolate3; } @@ -408,9 +411,10 @@ export function ɵɵpropertyInterpolate7( const tNode = getSelectedTNode(); elementPropertyInternal( tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false); - ngDevMode && storePropertyBindingMetadata( - tView.data, tNode, propName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, - i5, suffix); + ngDevMode && + storePropertyBindingMetadata( + tView.data, tNode, propName, getBindingIndex() - 7, prefix, i0, i1, i2, i3, i4, i5, + suffix); } return ɵɵpropertyInterpolate7; } @@ -470,9 +474,10 @@ export function ɵɵpropertyInterpolate8( const tNode = getSelectedTNode(); elementPropertyInternal( tView, tNode, lView, propName, interpolatedValue, lView[RENDERER], sanitizer, false); - ngDevMode && storePropertyBindingMetadata( - tView.data, tNode, propName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, - i5, i6, suffix); + ngDevMode && + storePropertyBindingMetadata( + tView.data, tNode, propName, getBindingIndex() - 8, prefix, i0, i1, i2, i3, i4, i5, i6, + suffix); } return ɵɵpropertyInterpolate8; } diff --git a/packages/core/src/render3/instructions/style_prop_interpolation.ts b/packages/core/src/render3/instructions/style_prop_interpolation.ts index cde0b3335b559..86eaff4cb5c8d 100644 --- a/packages/core/src/render3/instructions/style_prop_interpolation.ts +++ b/packages/core/src/render3/instructions/style_prop_interpolation.ts @@ -39,7 +39,7 @@ import {checkStylingProperty} from './styling'; */ export function ɵɵstylePropInterpolate1( prop: string, prefix: string, v0: any, suffix: string, - valueSuffix?: string | null): typeof ɵɵstylePropInterpolate1 { + valueSuffix?: string|null): typeof ɵɵstylePropInterpolate1 { const lView = getLView(); const interpolatedValue = interpolation1(lView, prefix, v0, suffix); checkStylingProperty(prop, interpolatedValue, valueSuffix, false); @@ -76,7 +76,7 @@ export function ɵɵstylePropInterpolate1( */ export function ɵɵstylePropInterpolate2( prop: string, prefix: string, v0: any, i0: string, v1: any, suffix: string, - valueSuffix?: string | null): typeof ɵɵstylePropInterpolate2 { + valueSuffix?: string|null): typeof ɵɵstylePropInterpolate2 { const lView = getLView(); const interpolatedValue = interpolation2(lView, prefix, v0, i0, v1, suffix); checkStylingProperty(prop, interpolatedValue, valueSuffix, false); @@ -115,7 +115,7 @@ export function ɵɵstylePropInterpolate2( */ export function ɵɵstylePropInterpolate3( prop: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string, - valueSuffix?: string | null): typeof ɵɵstylePropInterpolate3 { + valueSuffix?: string|null): typeof ɵɵstylePropInterpolate3 { const lView = getLView(); const interpolatedValue = interpolation3(lView, prefix, v0, i0, v1, i1, v2, suffix); checkStylingProperty(prop, interpolatedValue, valueSuffix, false); @@ -156,7 +156,7 @@ export function ɵɵstylePropInterpolate3( */ export function ɵɵstylePropInterpolate4( prop: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, - v3: any, suffix: string, valueSuffix?: string | null): typeof ɵɵstylePropInterpolate4 { + v3: any, suffix: string, valueSuffix?: string|null): typeof ɵɵstylePropInterpolate4 { const lView = getLView(); const interpolatedValue = interpolation4(lView, prefix, v0, i0, v1, i1, v2, i2, v3, suffix); checkStylingProperty(prop, interpolatedValue, valueSuffix, false); @@ -200,7 +200,7 @@ export function ɵɵstylePropInterpolate4( export function ɵɵstylePropInterpolate5( prop: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, suffix: string, - valueSuffix?: string | null): typeof ɵɵstylePropInterpolate5 { + valueSuffix?: string|null): typeof ɵɵstylePropInterpolate5 { const lView = getLView(); const interpolatedValue = interpolation5(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, suffix); @@ -247,7 +247,7 @@ export function ɵɵstylePropInterpolate5( export function ɵɵstylePropInterpolate6( prop: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, suffix: string, - valueSuffix?: string | null): typeof ɵɵstylePropInterpolate6 { + valueSuffix?: string|null): typeof ɵɵstylePropInterpolate6 { const lView = getLView(); const interpolatedValue = interpolation6(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, suffix); @@ -297,7 +297,7 @@ export function ɵɵstylePropInterpolate6( export function ɵɵstylePropInterpolate7( prop: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string, - valueSuffix?: string | null): typeof ɵɵstylePropInterpolate7 { + valueSuffix?: string|null): typeof ɵɵstylePropInterpolate7 { const lView = getLView(); const interpolatedValue = interpolation7(lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, suffix); @@ -349,7 +349,7 @@ export function ɵɵstylePropInterpolate7( export function ɵɵstylePropInterpolate8( prop: string, prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any, i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any, - suffix: string, valueSuffix?: string | null): typeof ɵɵstylePropInterpolate8 { + suffix: string, valueSuffix?: string|null): typeof ɵɵstylePropInterpolate8 { const lView = getLView(); const interpolatedValue = interpolation8( lView, prefix, v0, i0, v1, i1, v2, i2, v3, i3, v4, i4, v5, i5, v6, i6, v7, suffix); @@ -388,7 +388,7 @@ export function ɵɵstylePropInterpolate8( * @codeGenApi */ export function ɵɵstylePropInterpolateV( - prop: string, values: any[], valueSuffix?: string | null): typeof ɵɵstylePropInterpolateV { + prop: string, values: any[], valueSuffix?: string|null): typeof ɵɵstylePropInterpolateV { const lView = getLView(); const interpolatedValue = interpolationV(lView, values); checkStylingProperty(prop, interpolatedValue, valueSuffix, false); diff --git a/packages/core/src/render3/instructions/styling.ts b/packages/core/src/render3/instructions/styling.ts index 6370ebd952b3d..16c53d4f2796e 100644 --- a/packages/core/src/render3/instructions/styling.ts +++ b/packages/core/src/render3/instructions/styling.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {SafeValue, unwrapSafeValue} from '../../sanitization/bypass'; import {stylePropNeedsSanitization, ɵɵsanitizeStyle} from '../../sanitization/sanitization'; @@ -19,7 +19,7 @@ import {DirectiveDef} from '../interfaces/definition'; import {AttributeMarker, TAttributes, TNode, TNodeFlags, TNodeType} from '../interfaces/node'; import {RElement, Renderer3} from '../interfaces/renderer'; import {SanitizerFn} from '../interfaces/sanitization'; -import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '../interfaces/styling'; +import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '../interfaces/styling'; import {HEADER_OFFSET, LView, RENDERER, TData, TView} from '../interfaces/view'; import {applyStyling} from '../node_manipulation'; import {getCurrentDirectiveIndex, getCurrentStyleSanitizer, getLView, getSelectedIndex, getTView, incrementBindingIndex, setCurrentStyleSanitizer} from '../state'; @@ -27,6 +27,7 @@ import {insertTStylingBinding} from '../styling/style_binding_list'; import {getLastParsedKey, getLastParsedValue, parseClassName, parseClassNameNext, parseStyle, parseStyleNext} from '../styling/styling_parser'; import {NO_CHANGE} from '../tokens'; import {getNativeByIndex} from '../util/view_utils'; + import {setDirectiveInputsWhichShadowsStyling} from './property'; @@ -46,7 +47,7 @@ import {setDirectiveInputsWhichShadowsStyling} from './property'; * * @codeGenApi */ -export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void { +export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn|null): void { setCurrentStyleSanitizer(sanitizer); } @@ -72,8 +73,8 @@ export function ɵɵstyleSanitizer(sanitizer: StyleSanitizeFn | null): void { * @codeGenApi */ export function ɵɵstyleProp( - prop: string, value: string | number | SafeValue | undefined | null, - suffix?: string | null): typeof ɵɵstyleProp { + prop: string, value: string|number|SafeValue|undefined|null, + suffix?: string|null): typeof ɵɵstyleProp { checkStylingProperty(prop, value, suffix, false); return ɵɵstyleProp; } @@ -93,8 +94,7 @@ export function ɵɵstyleProp( * * @codeGenApi */ -export function ɵɵclassProp( - className: string, value: boolean | undefined | null): typeof ɵɵclassProp { +export function ɵɵclassProp(className: string, value: boolean|undefined|null): typeof ɵɵclassProp { checkStylingProperty(className, value, null, true); return ɵɵclassProp; } @@ -119,7 +119,7 @@ export function ɵɵclassProp( * * @codeGenApi */ -export function ɵɵstyleMap(styles: {[styleName: string]: any} | string | undefined | null): void { +export function ɵɵstyleMap(styles: {[styleName: string]: any}|string|undefined|null): void { checkStylingMap(styleKeyValueArraySet, styleStringParser, styles, false); } @@ -158,8 +158,8 @@ export function styleStringParser(keyValueArray: KeyValueArray<any>, text: strin * * @codeGenApi */ -export function ɵɵclassMap( - classes: {[className: string]: boolean | undefined | null} | string | undefined | null): void { +export function ɵɵclassMap(classes: {[className: string]: boolean|undefined|null}|string|undefined| + null): void { checkStylingMap(keyValueArraySet, classStringParser, classes, true); } @@ -187,8 +187,8 @@ export function classStringParser(keyValueArray: KeyValueArray<any>, text: strin * @param isClassBased `true` if `class` change (`false` if `style`) */ export function checkStylingProperty( - prop: string, value: any | NO_CHANGE, - suffixOrSanitizer: SanitizerFn | string | undefined | null, isClassBased: boolean): void { + prop: string, value: any|NO_CHANGE, suffixOrSanitizer: SanitizerFn|string|undefined|null, + isClassBased: boolean): void { const lView = getLView(); const tView = getTView(); // Styling instructions use 2 slots per binding. @@ -289,14 +289,14 @@ function isInHostBindings(tView: TView, bindingIndex: number): boolean { } /** -* Collects the necessary information to insert the binding into a linked list of style bindings -* using `insertTStylingBinding`. -* -* @param tView `TView` where the binding linked list will be stored. -* @param tStylingKey Property/key of the binding. -* @param bindingIndex Index of binding associated with the `prop` -* @param isClassBased `true` if `class` change (`false` if `style`) -*/ + * Collects the necessary information to insert the binding into a linked list of style bindings + * using `insertTStylingBinding`. + * + * @param tView `TView` where the binding linked list will be stored. + * @param tStylingKey Property/key of the binding. + * @param bindingIndex Index of binding associated with the `prop` + * @param isClassBased `true` if `class` change (`false` if `style`) + */ function stylingFirstUpdatePass( tView: TView, tStylingKey: TStylingKey, bindingIndex: number, isClassBased: boolean): void { ngDevMode && assertFirstUpdatePass(tView); @@ -477,9 +477,10 @@ function getTemplateHeadTStylingKey(tData: TData, tNode: TNode, isClassBased: bo function setTemplateHeadTStylingKey( tData: TData, tNode: TNode, isClassBased: boolean, tStylingKey: TStylingKey): void { const bindings = isClassBased ? tNode.classBindings : tNode.styleBindings; - ngDevMode && assertNotEqual( - getTStylingRangeNext(bindings), 0, - 'Expecting to have at least one template styling binding.'); + ngDevMode && + assertNotEqual( + getTStylingRangeNext(bindings), 0, + 'Expecting to have at least one template styling binding.'); tData[getTStylingRangePrev(bindings)] = tStylingKey; } @@ -523,7 +524,7 @@ function collectResidual(tData: TData, tNode: TNode, isClassBased: boolean): Key * @param isClassBased `true` if `class` (`false` if `style`) */ function collectStylingFromDirectives( - hostDirectiveDef: DirectiveDef<any>| null, tData: TData, tNode: TNode, stylingKey: TStylingKey, + hostDirectiveDef: DirectiveDef<any>|null, tData: TData, tNode: TNode, stylingKey: TStylingKey, isClassBased: boolean): TStylingKey { // We need to loop because there can be directives which have `hostAttrs` but don't have // `hostBindings` so this loop catches up to the current directive.. @@ -559,7 +560,7 @@ function collectStylingFromDirectives( * @param isClassBased `true` if `class` (`false` if `style`) */ function collectStylingFromTAttrs( - stylingKey: TStylingKey | undefined, attrs: TAttributes | null, + stylingKey: TStylingKey|undefined, attrs: TAttributes|null, isClassBased: boolean): TStylingKey { const desiredMarker = isClassBased ? AttributeMarker.Classes : AttributeMarker.Styles; let currentMarker = AttributeMarker.ImplicitAttributes; @@ -711,7 +712,7 @@ function updateStylingMap( setKey = newKey; setValue = newValue; } - } else if (newKey === null || oldKey !== null && oldKey < newKey !) { + } else if (newKey === null || oldKey !== null && oldKey < newKey!) { // DELETE: oldKey key is missing or we did not find the oldKey in the newValue // (because the keyValueArray is sorted and `newKey` is found later alphabetically). // `"background" < "color"` so we need to delete `"background"` because it is not found in the @@ -754,7 +755,7 @@ function updateStylingMap( */ function updateStyling( tView: TView, tNode: TNode, lView: LView, renderer: Renderer3, prop: string, - value: string | undefined | null | boolean, isClassBased: boolean, bindingIndex: number) { + value: string|undefined|null|boolean, isClassBased: boolean, bindingIndex: number) { if (tNode.type !== TNodeType.Element) { // It is possible to have styling on non-elements (such as ng-container). // This is rare, but it does happen. In such a case, just ignore the binding. @@ -811,7 +812,7 @@ function updateStyling( * @param isClassBased `true` if `class` (`false` if `style`) */ function findStylingValue( - tData: TData, tNode: TNode | null, lView: LView, prop: string, index: number, + tData: TData, tNode: TNode|null, lView: LView, prop: string, index: number, isClassBased: boolean): any { // `TNode` to use for resolving static styling. Also controls search direction. // - `TNode` search next and quit as soon as `isStylingValuePresent(value)` is true. @@ -856,7 +857,7 @@ function findStylingValue( // consult residual styling let residual = isClassBased ? tNode.residualClasses : tNode.residualStyles; if (residual != null /** OR residual !=== undefined */) { - value = keyValueArrayGet(residual !, prop); + value = keyValueArrayGet(residual!, prop); } } return value; @@ -884,7 +885,7 @@ function isStylingValuePresent(value: any): boolean { * @param suffixOrSanitizer */ function normalizeAndApplySuffixOrSanitizer( - value: any, suffixOrSanitizer: SanitizerFn | string | undefined | null): string|null|undefined| + value: any, suffixOrSanitizer: SanitizerFn|string|undefined|null): string|null|undefined| boolean { if (value == null /** || value === undefined */) { // do nothing diff --git a/packages/core/src/render3/instructions/text.ts b/packages/core/src/render3/instructions/text.ts index b7b1c909060bb..a6ab9338223b3 100644 --- a/packages/core/src/render3/instructions/text.ts +++ b/packages/core/src/render3/instructions/text.ts @@ -27,9 +27,10 @@ export function ɵɵtext(index: number, value: string = ''): void { const tView = getTView(); const adjustedIndex = index + HEADER_OFFSET; - ngDevMode && assertEqual( - getBindingIndex(), tView.bindingStartIndex, - 'text nodes should be created before any bindings'); + ngDevMode && + assertEqual( + getBindingIndex(), tView.bindingStartIndex, + 'text nodes should be created before any bindings'); ngDevMode && assertDataInRange(lView, adjustedIndex); const tNode = tView.firstCreatePass ? diff --git a/packages/core/src/render3/interfaces/definition.ts b/packages/core/src/render3/interfaces/definition.ts index f89895e2d880f..31ea33b9da1fb 100644 --- a/packages/core/src/render3/interfaces/definition.ts +++ b/packages/core/src/render3/interfaces/definition.ts @@ -22,7 +22,7 @@ export type ComponentTemplate<T> = { // Note: the ctx parameter is typed as T|U, as using only U would prevent a template with // e.g. ctx: {} from being assigned to ComponentTemplate<any> as TypeScript won't infer U = any // in that scenario. By including T this incompatibility is resolved. - <U extends T>(rf: RenderFlags, ctx: T | U): void; + <U extends T>(rf: RenderFlags, ctx: T|U): void; }; /** @@ -72,7 +72,9 @@ export const enum RenderFlags { * A subclass of `Type` which has a static `ɵcmp`:`ComponentDef` field making it * consumable for rendering. */ -export interface ComponentType<T> extends Type<T> { ɵcmp: never; } +export interface ComponentType<T> extends Type<T> { + ɵcmp: never; +} /** * A subclass of `Type` which has a static `ɵdir`:`DirectiveDef` field making it @@ -87,7 +89,9 @@ export interface DirectiveType<T> extends Type<T> { * A subclass of `Type` which has a static `ɵpipe`:`PipeDef` field making it * consumable for rendering. */ -export interface PipeType<T> extends Type<T> { ɵpipe: never; } +export interface PipeType<T> extends Type<T> { + ɵpipe: never; +} /** * An object literal of this type is used to represent the metadata of a constructor dependency. @@ -99,7 +103,7 @@ export type CtorDependency = { * attribute name is a dynamic expression instead of a string literal, this will be the unknown * type. */ - attribute?: string | unknown; + attribute?: string|unknown; /** * If `@Optional()` is used, this key is set to true. @@ -120,14 +124,17 @@ export type CtorDependency = { * If `@SkipSelf` is used, this key is set to true. */ skipSelf?: true; -} | null; +}|null; /** * @codeGenApi */ export type ɵɵDirectiveDefWithMeta< - T, Selector extends string, ExportAs extends string[], InputMap extends{[key: string]: string}, - OutputMap extends{[key: string]: string}, QueryFields extends string[]> = DirectiveDef<T>; + T, Selector extends string, ExportAs extends + string[], InputMap extends {[key: string]: string}, + OutputMap extends {[key: string]: string}, + QueryFields extends string[]> = + DirectiveDef<T>; /** * Runtime link information for Directives. @@ -268,9 +275,10 @@ export interface DirectiveDef<T> { * @codeGenApi */ export type ɵɵComponentDefWithMeta< - T, Selector extends String, ExportAs extends string[], InputMap extends{[key: string]: string}, - OutputMap extends{[key: string]: string}, QueryFields extends string[], - NgContentSelectors extends string[]> = ComponentDef<T>; + T, Selector extends String, ExportAs extends + string[], InputMap extends {[key: string]: string}, + OutputMap extends {[key: string]: string}, QueryFields extends + string[], NgContentSelectors extends string[]> = ComponentDef<T>; /** * @codeGenApi @@ -467,14 +475,14 @@ export interface ComponentDefFeature { * * The function is necessary to be able to support forward declarations. */ -export type DirectiveDefListOrFactory = (() => DirectiveDefList) | DirectiveDefList; +export type DirectiveDefListOrFactory = (() => DirectiveDefList)|DirectiveDefList; -export type DirectiveDefList = (DirectiveDef<any>| ComponentDef<any>)[]; +export type DirectiveDefList = (DirectiveDef<any>|ComponentDef<any>)[]; -export type DirectiveTypesOrFactory = (() => DirectiveTypeList) | DirectiveTypeList; +export type DirectiveTypesOrFactory = (() => DirectiveTypeList)|DirectiveTypeList; export type DirectiveTypeList = - (DirectiveType<any>| ComponentType<any>| + (DirectiveType<any>|ComponentType<any>| Type<any>/* Type as workaround for: Microsoft/TypeScript/issues/4881 */)[]; export type HostBindingsFunction<T> = <U extends T>(rf: RenderFlags, ctx: U) => void; @@ -484,14 +492,14 @@ export type HostBindingsFunction<T> = <U extends T>(rf: RenderFlags, ctx: U) => * * The function is necessary to be able to support forward declarations. */ -export type PipeDefListOrFactory = (() => PipeDefList) | PipeDefList; +export type PipeDefListOrFactory = (() => PipeDefList)|PipeDefList; export type PipeDefList = PipeDef<any>[]; -export type PipeTypesOrFactory = (() => PipeTypeList) | PipeTypeList; +export type PipeTypesOrFactory = (() => PipeTypeList)|PipeTypeList; export type PipeTypeList = - (PipeType<any>| Type<any>/* Type as workaround for: Microsoft/TypeScript/issues/4881 */)[]; + (PipeType<any>|Type<any>/* Type as workaround for: Microsoft/TypeScript/issues/4881 */)[]; // Note: This hack is necessary so we don't erroneously get a circular dependency diff --git a/packages/core/src/render3/interfaces/document.ts b/packages/core/src/render3/interfaces/document.ts index 3e630c38ee458..30ca7fbf0fab1 100644 --- a/packages/core/src/render3/interfaces/document.ts +++ b/packages/core/src/render3/interfaces/document.ts @@ -31,7 +31,7 @@ let DOCUMENT: Document|undefined = undefined; * * @param document The object representing the global `document` in this environment. */ -export function setDocument(document: Document | undefined): void { +export function setDocument(document: Document|undefined): void { DOCUMENT = document; } @@ -52,5 +52,5 @@ export function getDocument(): Document { // this should not happen in Angular apps. // Once we support running ivy outside of Angular we will need to publish `setDocument()` as a // public API. Meanwhile we just return `undefined` and let the application fail. - return undefined !; + return undefined!; } diff --git a/packages/core/src/render3/interfaces/i18n.ts b/packages/core/src/render3/interfaces/i18n.ts index 98da1ca9c4298..4143415f42f1c 100644 --- a/packages/core/src/render3/interfaces/i18n.ts +++ b/packages/core/src/render3/interfaces/i18n.ts @@ -66,7 +66,9 @@ export const enum I18nMutateOpCode { export const ELEMENT_MARKER: ELEMENT_MARKER = { marker: 'element' }; -export interface ELEMENT_MARKER { marker: 'element'; } +export interface ELEMENT_MARKER { + marker: 'element'; +} /** * Marks that the next string is for comment. @@ -77,7 +79,9 @@ export const COMMENT_MARKER: COMMENT_MARKER = { marker: 'comment' }; -export interface COMMENT_MARKER { marker: 'comment'; } +export interface COMMENT_MARKER { + marker: 'comment'; +} /** * Array storing OpCode for dynamically creating `i18n` blocks. diff --git a/packages/core/src/render3/interfaces/injector.ts b/packages/core/src/render3/interfaces/injector.ts index a4324225394ed..270c38b8160c5 100644 --- a/packages/core/src/render3/interfaces/injector.ts +++ b/packages/core/src/render3/interfaces/injector.ts @@ -23,7 +23,9 @@ export const INJECTOR_BLOOM_PARENT_SIZE = 9; * The interfaces encodes number of parents `LView`s to traverse and index in the `LView` * pointing to the parent injector. */ -export interface RelativeInjectorLocation { __brand__: 'RelativeInjectorLocationFlags'; } +export interface RelativeInjectorLocation { + __brand__: 'RelativeInjectorLocationFlags'; +} export const enum RelativeInjectorLocationFlags { InjectorIndexMask = 0b111111111111111, @@ -114,20 +116,20 @@ export const NO_PARENT_INJECTOR: RelativeInjectorLocation = -1 as any; */ /** -* Factory for creating instances of injectors in the NodeInjector. -* -* This factory is complicated by the fact that it can resolve `multi` factories as well. -* -* NOTE: Some of the fields are optional which means that this class has two hidden classes. -* - One without `multi` support (most common) -* - One with `multi` values, (rare). -* -* Since VMs can cache up to 4 inline hidden classes this is OK. -* -* - Single factory: Only `resolving` and `factory` is defined. -* - `providers` factory: `componentProviders` is a number and `index = -1`. -* - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`. -*/ + * Factory for creating instances of injectors in the NodeInjector. + * + * This factory is complicated by the fact that it can resolve `multi` factories as well. + * + * NOTE: Some of the fields are optional which means that this class has two hidden classes. + * - One without `multi` support (most common) + * - One with `multi` values, (rare). + * + * Since VMs can cache up to 4 inline hidden classes this is OK. + * + * - Single factory: Only `resolving` and `factory` is defined. + * - `providers` factory: `componentProviders` is a number and `index = -1`. + * - `viewProviders` factory: `componentProviders` is a number and `index` points to `providers`. + */ export class NodeInjectorFactory { /** * The inject implementation to be activated when using the factory. @@ -234,7 +236,8 @@ export class NodeInjectorFactory { /** * Set to `true` if the token is declared in `viewProviders` (or if it is component). */ - isViewProvider: boolean, injectImplementation: null| + isViewProvider: boolean, + injectImplementation: null| (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T)) { this.canSeeViewProviders = isViewProvider; this.injectImpl = injectImplementation; diff --git a/packages/core/src/render3/interfaces/node.ts b/packages/core/src/render3/interfaces/node.ts index e2d662f517c80..a60d7d5f80d42 100644 --- a/packages/core/src/render3/interfaces/node.ts +++ b/packages/core/src/render3/interfaces/node.ts @@ -90,8 +90,10 @@ export const enum TNodeProviderIndexes { /** The index of the first provider on this node is encoded on the least significant bits */ ProvidersStartIndexMask = 0b00000000000000001111111111111111, - /** The count of view providers from the component on this node is encoded on the 16 most - significant bits */ + /** + The count of view providers from the component on this node is encoded on the 16 most + significant bits + */ CptViewProvidersCountShift = 16, CptViewProvidersCountShifter = 0b00000000000000010000000000000000, } @@ -117,21 +119,21 @@ export const enum AttributeMarker { NamespaceURI = 0, /** - * Signals class declaration. - * - * Each value following `Classes` designates a class name to include on the element. - * ## Example: - * - * Given: - * ``` - * <div class="foo bar baz">...<d/vi> - * ``` - * - * the generated code is: - * ``` - * var _c1 = [AttributeMarker.Classes, 'foo', 'bar', 'baz']; - * ``` - */ + * Signals class declaration. + * + * Each value following `Classes` designates a class name to include on the element. + * ## Example: + * + * Given: + * ``` + * <div class="foo bar baz">...<d/vi> + * ``` + * + * the generated code is: + * ``` + * var _c1 = [AttributeMarker.Classes, 'foo', 'bar', 'baz']; + * ``` + */ Classes = 1, /** @@ -235,14 +237,14 @@ export const enum AttributeMarker { * - Special markers acting as flags to alter attributes processing. * - Parsed ngProjectAs selectors. */ -export type TAttributes = (string | AttributeMarker | CssSelector)[]; +export type TAttributes = (string|AttributeMarker|CssSelector)[]; /** * Constants that are associated with a view. Includes: * - Attribute arrays. * - Local definition arrays. */ -export type TConstants = (TAttributes | string)[]; +export type TConstants = (TAttributes|string)[]; /** * Binding data (flyweight) for a particular node that is shared between all templates @@ -700,7 +702,7 @@ export interface TProjectionNode extends TNode { /** * A union type representing all TNode types that can host a directive. */ -export type TDirectiveHostNode = TElementNode | TContainerNode | TElementContainerNode; +export type TDirectiveHostNode = TElementNode|TContainerNode|TElementContainerNode; /** * This mapping is necessary so we can set input properties and output listeners @@ -725,7 +727,7 @@ export type PropertyAliases = { * * e.g. [0, 'change-minified'] */ -export type PropertyAliasValue = (number | string)[]; +export type PropertyAliasValue = (number|string)[]; /** * This array contains information about input properties that @@ -745,7 +747,7 @@ export type PropertyAliasValue = (number | string)[]; * * e.g. [null, ['role-min', 'minified-input', 'button']] */ -export type InitialInputData = (InitialInputs | null)[]; +export type InitialInputData = (InitialInputs|null)[]; /** * Used by InitialInputData to store input properties @@ -766,7 +768,7 @@ export const unusedValueExportToPlacateAjd = 1; /** * Type representing a set of TNodes that can have local refs (`#foo`) placed on them. */ -export type TNodeWithLocalRefs = TContainerNode | TElementNode | TElementContainerNode; +export type TNodeWithLocalRefs = TContainerNode|TElementNode|TElementContainerNode; /** * Type for a function that extracts a value for a local refs. diff --git a/packages/core/src/render3/interfaces/player.ts b/packages/core/src/render3/interfaces/player.ts index 518aba8d28aca..37620de2118b4 100644 --- a/packages/core/src/render3/interfaces/player.ts +++ b/packages/core/src/render3/interfaces/player.ts @@ -25,7 +25,9 @@ export const enum BindingType { Style = 2, } -export interface BindingStore { setValue(prop: string, value: any): void; } +export interface BindingStore { + setValue(prop: string, value: any): void; +} /** * Defines the shape which produces the Player. @@ -50,7 +52,9 @@ export interface PlayerFactoryBuildFn { * `[style]`, `[style.prop]`, `[class]` and `[class.name]` template bindings * all accept a `PlayerFactory` as input and this player factories. */ -export interface PlayerFactory { '__brand__': 'Brand for PlayerFactory that nothing will match'; } +export interface PlayerFactory { + '__brand__': 'Brand for PlayerFactory that nothing will match'; +} export interface PlayerBuilder extends BindingStore { buildPlayer(currentPlayer: Player|null, isFirstRender: boolean): Player|undefined|null; @@ -63,7 +67,13 @@ export interface PlayerBuilder extends BindingStore { * code may compare state by checking if a number is higher or lower than * a certain numeric value. */ -export const enum PlayState {Pending = 0, Running = 1, Paused = 2, Finished = 100, Destroyed = 200} +export const enum PlayState { + Pending = 0, + Running = 1, + Paused = 2, + Finished = 100, + Destroyed = 200 +} /** * The context that stores all the active players and queued player factories present on an element. diff --git a/packages/core/src/render3/interfaces/projection.ts b/packages/core/src/render3/interfaces/projection.ts index 6657ab7ff9527..1ef2c6bca43cc 100644 --- a/packages/core/src/render3/interfaces/projection.ts +++ b/packages/core/src/render3/interfaces/projection.ts @@ -37,7 +37,7 @@ * * See more examples in node_selector_matcher_spec.ts */ -export type CssSelector = (string | SelectorFlags)[]; +export type CssSelector = (string|SelectorFlags)[]; /** * A list of CssSelectors. @@ -58,7 +58,7 @@ export type CssSelectorList = CssSelector[]; * using {@link ViewContainerRef#createComponent}. The last slot that specifies the * wildcard selector will retrieve all projectable nodes which do not match any selector. */ -export type ProjectionSlots = (CssSelectorList | '*')[]; +export type ProjectionSlots = (CssSelectorList|'*')[]; /** Flags used to build up CssSelectors */ export const enum SelectorFlags { diff --git a/packages/core/src/render3/interfaces/query.ts b/packages/core/src/render3/interfaces/query.ts index 2c5d14df12d6a..e184fa42566ff 100644 --- a/packages/core/src/render3/interfaces/query.ts +++ b/packages/core/src/render3/interfaces/query.ts @@ -145,7 +145,7 @@ export interface TQueries { template(tView: TView, tNode: TNode): void; /** - * A proxy method that iterates over all the TQueries in a given TView and calls the corresponding + * A proxy method that iterates over all the TQueries in a given TView and calls the corresponding * `embeddedTView` on each and every TQuery. * @param tNode */ diff --git a/packages/core/src/render3/interfaces/renderer.ts b/packages/core/src/render3/interfaces/renderer.ts index a61d7c4a90462..b34f5195eb297 100644 --- a/packages/core/src/render3/interfaces/renderer.ts +++ b/packages/core/src/render3/interfaces/renderer.ts @@ -24,9 +24,9 @@ export enum RendererStyleFlags3 { DashCase = 1 << 1 } -export type Renderer3 = ObjectOrientedRenderer3 | ProceduralRenderer3; +export type Renderer3 = ObjectOrientedRenderer3|ProceduralRenderer3; -export type GlobalTargetName = 'document' | 'window' | 'body'; +export type GlobalTargetName = 'document'|'window'|'body'; export type GlobalTargetResolver = (element: any) => { name: GlobalTargetName, target: EventTarget @@ -49,8 +49,8 @@ export interface ObjectOrientedRenderer3 { } /** Returns whether the `renderer` is a `ProceduralRenderer3` */ -export function isProceduralRenderer(renderer: ProceduralRenderer3 | ObjectOrientedRenderer3): - renderer is ProceduralRenderer3 { +export function isProceduralRenderer(renderer: ProceduralRenderer3| + ObjectOrientedRenderer3): renderer is ProceduralRenderer3 { return !!((renderer as any).listen); } @@ -104,8 +104,9 @@ export interface RendererFactory3 { } export const domRendererFactory3: RendererFactory3 = { - createRenderer: (hostElement: RElement | null, rendererType: RendererType2 | null): - Renderer3 => { return getDocument();} + createRenderer: (hostElement: RElement|null, rendererType: RendererType2|null): Renderer3 => { + return getDocument(); + } }; /** Subset of API needed for appending elements and text nodes. */ @@ -175,9 +176,13 @@ export interface RDomTokenList { remove(token: string): void; } -export interface RText extends RNode { textContent: string|null; } +export interface RText extends RNode { + textContent: string|null; +} -export interface RComment extends RNode { textContent: string|null; } +export interface RComment extends RNode { + textContent: string|null; +} // Note: This hack is necessary so we don't erroneously get a circular dependency // failure based on types. diff --git a/packages/core/src/render3/interfaces/styling.ts b/packages/core/src/render3/interfaces/styling.ts index e80ed1fbaee43..050b9756a321c 100644 --- a/packages/core/src/render3/interfaces/styling.ts +++ b/packages/core/src/render3/interfaces/styling.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {KeyValueArray} from '../../util/array_utils'; import {assertNumber, assertNumberInRange} from '../../util/assert'; @@ -14,7 +14,7 @@ import {assertNumber, assertNumberInRange} from '../../util/assert'; * * See: `TStylingKeyPrimitive` and `TStylingStatic` */ -export type TStylingKey = TStylingKeyPrimitive | TStylingStatic; +export type TStylingKey = TStylingKeyPrimitive|TStylingStatic; /** @@ -27,7 +27,7 @@ export type TStylingKey = TStylingKeyPrimitive | TStylingStatic; * is combined with directive which shadows its input `@Input('class')`. That way the binding * should not participate in the styling resolution. */ -export type TStylingKeyPrimitive = string | null | false; +export type TStylingKeyPrimitive = string|null|false; /** * Store the static values for the styling binding. @@ -119,7 +119,9 @@ export interface TStylingStatic extends KeyValueArray<any> {} * * NOTE: `0` has special significance and represents `null` as in no additional pointer. */ -export interface TStylingRange { __brand__: 'TStylingRange'; } +export interface TStylingRange { + __brand__: 'TStylingRange'; +} /** * Shift and masks constants for encoding two numbers into and duplicate info into a single number. @@ -177,9 +179,8 @@ export function setTStylingRangePrev( tStylingRange: TStylingRange, previous: number): TStylingRange { ngDevMode && assertNumber(tStylingRange, 'expected number'); ngDevMode && assertNumberInRange(previous, 0, StylingRange.UNSIGNED_MASK); - return ( - ((tStylingRange as any as number) & ~StylingRange.PREV_MASK) | - (previous << StylingRange.PREV_SHIFT)) as any; + return (((tStylingRange as any as number) & ~StylingRange.PREV_MASK) | + (previous << StylingRange.PREV_SHIFT)) as any; } export function setTStylingRangePrevDuplicate(tStylingRange: TStylingRange): TStylingRange { @@ -195,9 +196,8 @@ export function getTStylingRangeNext(tStylingRange: TStylingRange): number { export function setTStylingRangeNext(tStylingRange: TStylingRange, next: number): TStylingRange { ngDevMode && assertNumber(tStylingRange, 'expected number'); ngDevMode && assertNumberInRange(next, 0, StylingRange.UNSIGNED_MASK); - return ( - ((tStylingRange as any as number) & ~StylingRange.NEXT_MASK) | // - next << StylingRange.NEXT_SHIFT) as any; + return (((tStylingRange as any as number) & ~StylingRange.NEXT_MASK) | // + next << StylingRange.NEXT_SHIFT) as any; } export function getTStylingRangeNextDuplicate(tStylingRange: TStylingRange): boolean { diff --git a/packages/core/src/render3/interfaces/type_checks.ts b/packages/core/src/render3/interfaces/type_checks.ts index eca8324340cb2..875c409466b49 100644 --- a/packages/core/src/render3/interfaces/type_checks.ts +++ b/packages/core/src/render3/interfaces/type_checks.ts @@ -15,10 +15,10 @@ import {FLAGS, LView, LViewFlags} from './view'; /** -* True if `value` is `LView`. -* @param value wrapped value of `RNode`, `LView`, `LContainer` -*/ -export function isLView(value: RNode | LView | LContainer | {} | null): value is LView { + * True if `value` is `LView`. + * @param value wrapped value of `RNode`, `LView`, `LContainer` + */ +export function isLView(value: RNode|LView|LContainer|{}|null): value is LView { return Array.isArray(value) && typeof value[TYPE] === 'object'; } @@ -26,7 +26,7 @@ export function isLView(value: RNode | LView | LContainer | {} | null): value is * True if `value` is `LContainer`. * @param value wrapped value of `RNode`, `LView`, `LContainer` */ -export function isLContainer(value: RNode | LView | LContainer | {} | null): value is LContainer { +export function isLContainer(value: RNode|LView|LContainer|{}|null): value is LContainer { return Array.isArray(value) && value[TYPE] === true; } diff --git a/packages/core/src/render3/jit/directive.ts b/packages/core/src/render3/jit/directive.ts index 06398cb75cb02..0397485773e37 100644 --- a/packages/core/src/render3/jit/directive.ts +++ b/packages/core/src/render3/jit/directive.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {R3DirectiveMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {getCompilerFacade, R3DirectiveMetadataFacade} from '../../compiler/compiler_facade'; import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from '../../compiler/compiler_facade_interface'; import {resolveForwardRef} from '../../di/forward_ref'; import {getReflect, reflectDependencies} from '../../di/jit/util'; @@ -95,12 +95,14 @@ export function compileComponent(type: Type<any>, metadata: Component): void { const meta: R3ComponentMetadataFacade = { ...directiveMetadata(type, metadata), typeSourceSpan: compiler.createParseSourceSpan('Component', type.name, templateUrl), - template: metadata.template || '', preserveWhitespaces, + template: metadata.template || '', + preserveWhitespaces, styles: metadata.styles || EMPTY_ARRAY, animations: metadata.animations, directives: [], changeDetection: metadata.changeDetection, - pipes: new Map(), encapsulation, + pipes: new Map(), + encapsulation, interpolation: metadata.interpolation, viewProviders: metadata.viewProviders || null, }; @@ -135,7 +137,7 @@ export function compileComponent(type: Type<any>, metadata: Component): void { function hasSelectorScope<T>(component: Type<T>): component is Type<T>& {ngSelectorScope: Type<any>} { - return (component as{ngSelectorScope?: any}).ngSelectorScope !== undefined; + return (component as {ngSelectorScope?: any}).ngSelectorScope !== undefined; } /** @@ -145,7 +147,7 @@ function hasSelectorScope<T>(component: Type<T>): component is Type<T>& * In the event that compilation is not immediate, `compileDirective` will return a `Promise` which * will resolve when compilation completes and the directive becomes usable. */ -export function compileDirective(type: Type<any>, directive: Directive | null): void { +export function compileDirective(type: Type<any>, directive: Directive|null): void { let ngDirectiveDef: any = null; addDirectiveFactoryDef(type, directive || {}); @@ -179,7 +181,7 @@ function getDirectiveMetadata(type: Type<any>, metadata: Directive) { return {metadata: facade, sourceMapUrl}; } -function addDirectiveFactoryDef(type: Type<any>, metadata: Directive | Component) { +function addDirectiveFactoryDef(type: Type<any>, metadata: Directive|Component) { let ngFactoryDef: any = null; Object.defineProperty(type, NG_FACTORY_DEF, { @@ -225,7 +227,7 @@ export function directiveMetadata(type: Type<any>, metadata: Directive): R3Direc outputs: metadata.outputs || EMPTY_ARRAY, queries: extractQueriesMetadata(type, propMetadata, isContentQuery), lifecycle: {usesOnChanges: reflect.hasLifecycleHook(type, 'ngOnChanges')}, - typeSourceSpan: null !, + typeSourceSpan: null!, usesInheritance: !extendsDirectlyFromObject(type), exportAs: extractExportAs(metadata.exportAs), providers: metadata.providers || null, @@ -291,7 +293,7 @@ function extractQueriesMetadata( return queriesMeta; } -function extractExportAs(exportAs: string | undefined): string[]|null { +function extractExportAs(exportAs: string|undefined): string[]|null { return exportAs === undefined ? null : splitByComma(exportAs); } diff --git a/packages/core/src/render3/jit/module.ts b/packages/core/src/render3/jit/module.ts index 49b93eefd19f0..375c17322de5d 100644 --- a/packages/core/src/render3/jit/module.ts +++ b/packages/core/src/render3/jit/module.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {R3InjectorMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {getCompilerFacade, R3InjectorMetadataFacade} from '../../compiler/compiler_facade'; import {resolveForwardRef} from '../../di/forward_ref'; import {NG_INJ_DEF} from '../../di/interface/defs'; import {reflectDependencies} from '../../di/jit/util'; @@ -70,7 +70,7 @@ export function flushModuleScopingQueueAsMuchAsPossible() { * an array of declarations, it will recurse to check each declaration in that array * (which may also be arrays). */ -function isResolvedDeclaration(declaration: any[] | Type<any>): boolean { +function isResolvedDeclaration(declaration: any[]|Type<any>): boolean { if (Array.isArray(declaration)) { return declaration.every(isResolvedDeclaration); } @@ -144,8 +144,9 @@ export function compileNgModuleDefs( Object.defineProperty(moduleType, NG_INJ_DEF, { get: () => { if (ngInjectorDef === null) { - ngDevMode && verifySemanticsOfNgModuleDef( - moduleType as any as NgModuleType, allowDuplicateDeclarationsInRoot); + ngDevMode && + verifySemanticsOfNgModuleDef( + moduleType as any as NgModuleType, allowDuplicateDeclarationsInRoot); const meta: R3InjectorMetadataFacade = { name: moduleType.name, type: moduleType, @@ -174,10 +175,10 @@ function verifySemanticsOfNgModuleDef( moduleType = resolveForwardRef(moduleType); let ngModuleDef: NgModuleDef<any>; if (importingModule) { - ngModuleDef = getNgModuleDef(moduleType) !; + ngModuleDef = getNgModuleDef(moduleType)!; if (!ngModuleDef) { - throw new Error( - `Unexpected value '${moduleType.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`); + throw new Error(`Unexpected value '${moduleType.name}' imported by the module '${ + importingModule.name}'. Please add an @NgModule annotation.`); } } else { ngModuleDef = getNgModuleDef(moduleType, true); @@ -222,8 +223,8 @@ function verifySemanticsOfNgModuleDef( type = resolveForwardRef(type); const def = getComponentDef(type) || getDirectiveDef(type) || getPipeDef(type); if (!def) { - errors.push( - `Unexpected value '${stringifyForError(type)}' declared by the module '${stringifyForError(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`); + errors.push(`Unexpected value '${stringifyForError(type)}' declared by the module '${ + stringifyForError(moduleType)}'. Please add a @Pipe/@Directive/@Component annotation.`); } } @@ -244,8 +245,8 @@ function verifySemanticsOfNgModuleDef( // Modules don't need to be declared or imported. if (combinedDeclarations.lastIndexOf(type) === -1) { // We are exporting something which we don't explicitly declare or import. - errors.push( - `Can't export ${kind} ${stringifyForError(type)} from ${stringifyForError(moduleType)} as it was neither declared nor imported!`); + errors.push(`Can't export ${kind} ${stringifyForError(type)} from ${ + stringifyForError(moduleType)} as it was neither declared nor imported!`); } } } @@ -257,9 +258,13 @@ function verifySemanticsOfNgModuleDef( if (!suppressErrors) { const modules = [existingModule, moduleType].map(stringifyForError).sort(); errors.push( - `Type ${stringifyForError(type)} is part of the declarations of 2 modules: ${modules[0]} and ${modules[1]}! ` + - `Please consider moving ${stringifyForError(type)} to a higher module that imports ${modules[0]} and ${modules[1]}. ` + - `You can also create a new NgModule that exports and includes ${stringifyForError(type)} then import that NgModule in ${modules[0]} and ${modules[1]}.`); + `Type ${stringifyForError(type)} is part of the declarations of 2 modules: ${ + modules[0]} and ${modules[1]}! ` + + `Please consider moving ${stringifyForError(type)} to a higher module that imports ${ + modules[0]} and ${modules[1]}. ` + + `You can also create a new NgModule that exports and includes ${ + stringifyForError( + type)} then import that NgModule in ${modules[0]} and ${modules[1]}.`); } } else { // Mark type as having owner. @@ -271,8 +276,9 @@ function verifySemanticsOfNgModuleDef( type = resolveForwardRef(type); const existingModule = ownerNgModule.get(type); if (!existingModule) { - errors.push( - `Component ${stringifyForError(type)} is not part of any NgModule or the module has not been imported into your module.`); + errors.push(`Component ${ + stringifyForError( + type)} is not part of any NgModule or the module has not been imported into your module.`); } } @@ -298,19 +304,19 @@ function verifySemanticsOfNgModuleDef( type = resolveForwardRef(type); if (getComponentDef(type) || getDirectiveDef(type)) { - throw new Error( - `Unexpected directive '${type.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`); + throw new Error(`Unexpected directive '${type.name}' imported by the module '${ + importingModule.name}'. Please add an @NgModule annotation.`); } if (getPipeDef(type)) { - throw new Error( - `Unexpected pipe '${type.name}' imported by the module '${importingModule.name}'. Please add an @NgModule annotation.`); + throw new Error(`Unexpected pipe '${type.name}' imported by the module '${ + importingModule.name}'. Please add an @NgModule annotation.`); } } } -function unwrapModuleWithProvidersImports( - typeOrWithProviders: NgModuleType<any>| {ngModule: NgModuleType<any>}): NgModuleType<any> { +function unwrapModuleWithProvidersImports(typeOrWithProviders: NgModuleType<any>| + {ngModule: NgModuleType<any>}): NgModuleType<any> { typeOrWithProviders = resolveForwardRef(typeOrWithProviders); return (typeOrWithProviders as any).ngModule || typeOrWithProviders; } @@ -321,7 +327,7 @@ function getAnnotation<T>(type: any, name: string): T|null { collect(type.decorators); return annotation; - function collect(annotations: any[] | null) { + function collect(annotations: any[]|null) { if (annotations) { annotations.forEach(readAnnotation); } @@ -391,7 +397,7 @@ function setScopeOnDeclaredComponents(moduleType: Type<any>, ngModule: NgModule) if (declaration.hasOwnProperty(NG_COMP_DEF)) { // A `ɵcmp` field exists - go ahead and patch the component directly. const component = declaration as Type<any>& {ɵcmp: ComponentDef<any>}; - const componentDef = getComponentDef(component) !; + const componentDef = getComponentDef(component)!; patchComponentDefWithScope(componentDef, transitiveScopes); } else if ( !declaration.hasOwnProperty(NG_DIR_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) { @@ -410,11 +416,11 @@ export function patchComponentDefWithScope<C>( componentDef.directiveDefs = () => Array.from(transitiveScopes.compilation.directives) .map( - dir => - dir.hasOwnProperty(NG_COMP_DEF) ? getComponentDef(dir) ! : getDirectiveDef(dir) !) + dir => dir.hasOwnProperty(NG_COMP_DEF) ? getComponentDef(dir)! : getDirectiveDef(dir)! + ) .filter(def => !!def); componentDef.pipeDefs = () => - Array.from(transitiveScopes.compilation.pipes).map(pipe => getPipeDef(pipe) !); + Array.from(transitiveScopes.compilation.pipes).map(pipe => getPipeDef(pipe)!); componentDef.schemas = transitiveScopes.schemas; // Since we avoid Components/Directives/Pipes recompiling in case there are no overrides, we @@ -437,7 +443,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS if (!isNgModule(moduleType)) { throw new Error(`${moduleType.name} does not have a module def (ɵmod property)`); } - const def = getNgModuleDef(moduleType) !; + const def = getNgModuleDef(moduleType)!; if (def.transitiveCompileScopes !== null) { return def.transitiveCompileScopes; @@ -473,7 +479,9 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS }); maybeUnwrapFn(def.declarations).forEach(declared => { - const declaredWithDefs = declared as Type<any>& { ɵpipe?: any; }; + const declaredWithDefs = declared as Type<any>& { + ɵpipe?: any; + }; if (getPipeDef(declaredWithDefs)) { scopes.compilation.pipes.add(declared); @@ -519,7 +527,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS return scopes; } -function expandModuleWithProviders(value: Type<any>| ModuleWithProviders<{}>): Type<any> { +function expandModuleWithProviders(value: Type<any>|ModuleWithProviders<{}>): Type<any> { if (isModuleWithProviders(value)) { return value.ngModule; } @@ -527,7 +535,7 @@ function expandModuleWithProviders(value: Type<any>| ModuleWithProviders<{}>): T } function isModuleWithProviders(value: any): value is ModuleWithProviders<{}> { - return (value as{ngModule?: any}).ngModule !== undefined; + return (value as {ngModule?: any}).ngModule !== undefined; } function isNgModule<T>(value: Type<T>): value is Type<T>&{ɵmod: NgModuleDef<T>} { diff --git a/packages/core/src/render3/jit/pipe.ts b/packages/core/src/render3/jit/pipe.ts index 2ecd57799f07d..46975ae2ba55a 100644 --- a/packages/core/src/render3/jit/pipe.ts +++ b/packages/core/src/render3/jit/pipe.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {R3PipeMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade'; +import {getCompilerFacade, R3PipeMetadataFacade} from '../../compiler/compiler_facade'; import {reflectDependencies} from '../../di/jit/util'; import {Type} from '../../interface/type'; import {Pipe} from '../../metadata/directives'; diff --git a/packages/core/src/render3/metadata.ts b/packages/core/src/render3/metadata.ts index 4927c671e0fab..919b4ed375ae4 100644 --- a/packages/core/src/render3/metadata.ts +++ b/packages/core/src/render3/metadata.ts @@ -25,43 +25,46 @@ interface TypeWithMetadata extends Type<any> { * tree-shaken away during production builds. */ export function setClassMetadata( - type: Type<any>, decorators: any[] | null, ctorParameters: (() => any[]) | null, - propDecorators: {[field: string]: any} | null): void { + type: Type<any>, decorators: any[]|null, ctorParameters: (() => any[])|null, + propDecorators: {[field: string]: any}|null): void { return noSideEffects(() => { - const clazz = type as TypeWithMetadata; + const clazz = type as TypeWithMetadata; - // We determine whether a class has its own metadata by taking the metadata from the parent - // constructor and checking whether it's the same as the subclass metadata below. We can't use - // `hasOwnProperty` here because it doesn't work correctly in IE10 for static fields that are - // defined by TS. See https://github.com/angular/angular/pull/28439#issuecomment-459349218. - const parentPrototype = clazz.prototype ? Object.getPrototypeOf(clazz.prototype) : null; - const parentConstructor: TypeWithMetadata|null = parentPrototype && parentPrototype.constructor; + // We determine whether a class has its own metadata by taking the metadata from the + // parent constructor and checking whether it's the same as the subclass metadata below. + // We can't use `hasOwnProperty` here because it doesn't work correctly in IE10 for + // static fields that are defined by TS. See + // https://github.com/angular/angular/pull/28439#issuecomment-459349218. + const parentPrototype = clazz.prototype ? Object.getPrototypeOf(clazz.prototype) : null; + const parentConstructor: TypeWithMetadata|null = + parentPrototype && parentPrototype.constructor; - if (decorators !== null) { - if (clazz.decorators !== undefined && - (!parentConstructor || parentConstructor.decorators !== clazz.decorators)) { - clazz.decorators.push(...decorators); - } else { - clazz.decorators = decorators; - } - } - if (ctorParameters !== null) { - // Rather than merging, clobber the existing parameters. If other projects exist which use - // tsickle-style annotations and reflect over them in the same way, this could cause issues, - // but that is vanishingly unlikely. - clazz.ctorParameters = ctorParameters; - } - if (propDecorators !== null) { - // The property decorator objects are merged as it is possible different fields have different - // decorator types. Decorators on individual fields are not merged, as it's also incredibly - // unlikely that a field will be decorated both with an Angular decorator and a non-Angular - // decorator that's also been downleveled. - if (clazz.propDecorators !== undefined && - (!parentConstructor || parentConstructor.propDecorators !== clazz.propDecorators)) { - clazz.propDecorators = {...clazz.propDecorators, ...propDecorators}; - } else { - clazz.propDecorators = propDecorators; - } - } - }) as never; + if (decorators !== null) { + if (clazz.decorators !== undefined && + (!parentConstructor || parentConstructor.decorators !== clazz.decorators)) { + clazz.decorators.push(...decorators); + } else { + clazz.decorators = decorators; + } + } + if (ctorParameters !== null) { + // Rather than merging, clobber the existing parameters. If other projects exist which + // use tsickle-style annotations and reflect over them in the same way, this could + // cause issues, but that is vanishingly unlikely. + clazz.ctorParameters = ctorParameters; + } + if (propDecorators !== null) { + // The property decorator objects are merged as it is possible different fields have + // different decorator types. Decorators on individual fields are not merged, as it's + // also incredibly unlikely that a field will be decorated both with an Angular + // decorator and a non-Angular decorator that's also been downleveled. + if (clazz.propDecorators !== undefined && + (!parentConstructor || + parentConstructor.propDecorators !== clazz.propDecorators)) { + clazz.propDecorators = {...clazz.propDecorators, ...propDecorators}; + } else { + clazz.propDecorators = propDecorators; + } + } + }) as never; } diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index e3c3326082f6a..5c6a8c8403ffe 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -9,7 +9,7 @@ import {Injector} from '../di/injector'; import {INJECTOR} from '../di/injector_compatibility'; import {InjectFlags} from '../di/interface/injector'; -import {R3Injector, createInjectorWithoutInjectorInstances} from '../di/r3_injector'; +import {createInjectorWithoutInjectorInstances, R3Injector} from '../di/r3_injector'; import {Type} from '../interface/type'; import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver'; import {InternalNgModuleRef, NgModuleFactory as viewEngine_NgModuleFactory, NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory'; @@ -23,7 +23,9 @@ import {getNgLocaleIdDef, getNgModuleDef} from './definition'; import {setLocaleId} from './i18n'; import {maybeUnwrapFn} from './util/misc_utils'; -export interface NgModuleType<T = any> extends Type<T> { ɵmod: NgModuleDef<T>; } +export interface NgModuleType<T = any> extends Type<T> { + ɵmod: NgModuleDef<T>; +} export class NgModuleRef<T> extends viewEngine_NgModuleRef<T> implements InternalNgModuleRef<T> { // tslint:disable-next-line:require-internal-with-underscore @@ -45,20 +47,23 @@ export class NgModuleRef<T> extends viewEngine_NgModuleRef<T> implements Interna constructor(ngModuleType: Type<T>, public _parent: Injector|null) { super(); const ngModuleDef = getNgModuleDef(ngModuleType); - ngDevMode && assertDefined( - ngModuleDef, - `NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`); + ngDevMode && + assertDefined( + ngModuleDef, + `NgModule '${stringify(ngModuleType)}' is not a subtype of 'NgModuleType'.`); const ngLocaleIdDef = getNgLocaleIdDef(ngModuleType); ngLocaleIdDef && setLocaleId(ngLocaleIdDef); - this._bootstrapComponents = maybeUnwrapFn(ngModuleDef !.bootstrap); + this._bootstrapComponents = maybeUnwrapFn(ngModuleDef!.bootstrap); this._r3Injector = createInjectorWithoutInjectorInstances( - ngModuleType, _parent, - [ - {provide: viewEngine_NgModuleRef, useValue: this}, - {provide: viewEngine_ComponentFactoryResolver, useValue: this.componentFactoryResolver} - ], - stringify(ngModuleType)) as R3Injector; + ngModuleType, _parent, + [ + {provide: viewEngine_NgModuleRef, useValue: this}, { + provide: viewEngine_ComponentFactoryResolver, + useValue: this.componentFactoryResolver + } + ], + stringify(ngModuleType)) as R3Injector; // We need to resolve the injector types separately from the injector creation, because // the module might be trying to use this ref in its contructor for DI which will cause a @@ -79,12 +84,12 @@ export class NgModuleRef<T> extends viewEngine_NgModuleRef<T> implements Interna ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); const injector = this._r3Injector; !injector.destroyed && injector.destroy(); - this.destroyCbs !.forEach(fn => fn()); + this.destroyCbs!.forEach(fn => fn()); this.destroyCbs = null; } onDestroy(callback: () => void): void { ngDevMode && assertDefined(this.destroyCbs, 'NgModule already destroyed'); - this.destroyCbs !.push(callback); + this.destroyCbs!.push(callback); } } diff --git a/packages/core/src/render3/node_selector_matcher.ts b/packages/core/src/render3/node_selector_matcher.ts index 8b539d5bbcb85..5d724774b3814 100644 --- a/packages/core/src/render3/node_selector_matcher.ts +++ b/packages/core/src/render3/node_selector_matcher.ts @@ -46,7 +46,7 @@ function isCssClassMatching( } } else if (item === AttributeMarker.Classes) { // We found the classes section. Start searching for the class. - while (i < attrs.length && typeof(item = attrs[i++]) == 'string') { + while (i < attrs.length && typeof (item = attrs[i++]) == 'string') { // while we have strings if (item.toLowerCase() === cssClassToMatch) return true; } @@ -151,9 +151,10 @@ export function isNodeMatchingSelector( if (attrIndexInNode > nameOnlyMarkerIdx) { nodeAttrValue = ''; } else { - ngDevMode && assertNotEqual( - nodeAttrs[attrIndexInNode], AttributeMarker.NamespaceURI, - 'We do not match directives on namespaced attributes'); + ngDevMode && + assertNotEqual( + nodeAttrs[attrIndexInNode], AttributeMarker.NamespaceURI, + 'We do not match directives on namespaced attributes'); // we lowercase the attribute value to be able to match // selectors without case-sensitivity // (selectors are already in lowercase when generated) @@ -208,7 +209,7 @@ function isPositive(mode: SelectorFlags): boolean { * matching against directives. */ function findAttrIndexInNode( - name: string, attrs: TAttributes | null, isInlineTemplate: boolean, + name: string, attrs: TAttributes|null, isInlineTemplate: boolean, isProjectionMode: boolean): number { if (attrs === null) return -1; diff --git a/packages/core/src/render3/node_util.ts b/packages/core/src/render3/node_util.ts index 8f750ea399050..39865239908e8 100644 --- a/packages/core/src/render3/node_util.ts +++ b/packages/core/src/render3/node_util.ts @@ -43,7 +43,7 @@ export function getParentInjectorTNode( let parentTNode = startView[T_HOST] as TElementNode; // view offset is superior to 1 while (viewOffset > 1) { - parentView = parentView[DECLARATION_VIEW] !; + parentView = parentView[DECLARATION_VIEW]!; parentTNode = parentView[T_HOST] as TElementNode; viewOffset--; } diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index d7e79f0dbdb06..60a4ec490e0d4 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -61,7 +61,7 @@ export function ɵɵpipe(index: number, pipeName: string): any { * @param registry Full list of available pipes * @returns Matching PipeDef */ -function getPipeDef(name: string, registry: PipeDefList | null): PipeDef<any> { +function getPipeDef(name: string, registry: PipeDefList|null): PipeDef<any> { if (registry) { for (let i = registry.length - 1; i >= 0; i--) { const pipeDef = registry[i]; @@ -89,7 +89,8 @@ export function ɵɵpipeBind1(index: number, slotOffset: number, v1: any): any { const lView = getLView(); const pipeInstance = load<PipeTransform>(lView, index); return unwrapValue( - lView, isPure(lView, index) ? + lView, + isPure(lView, index) ? pureFunction1Internal( lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, pipeInstance) : pipeInstance.transform(v1)); @@ -112,7 +113,8 @@ export function ɵɵpipeBind2(index: number, slotOffset: number, v1: any, v2: an const lView = getLView(); const pipeInstance = load<PipeTransform>(lView, index); return unwrapValue( - lView, isPure(lView, index) ? + lView, + isPure(lView, index) ? pureFunction2Internal( lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, v2, pipeInstance) : pipeInstance.transform(v1, v2)); @@ -136,10 +138,11 @@ export function ɵɵpipeBind3(index: number, slotOffset: number, v1: any, v2: an const lView = getLView(); const pipeInstance = load<PipeTransform>(lView, index); return unwrapValue( - lView, isPure(lView, index) ? pureFunction3Internal( - lView, getBindingRoot(), slotOffset, pipeInstance.transform, - v1, v2, v3, pipeInstance) : - pipeInstance.transform(v1, v2, v3)); + lView, + isPure(lView, index) ? pureFunction3Internal( + lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, + v2, v3, pipeInstance) : + pipeInstance.transform(v1, v2, v3)); } /** @@ -162,10 +165,11 @@ export function ɵɵpipeBind4( const lView = getLView(); const pipeInstance = load<PipeTransform>(lView, index); return unwrapValue( - lView, isPure(lView, index) ? pureFunction4Internal( - lView, getBindingRoot(), slotOffset, pipeInstance.transform, - v1, v2, v3, v4, pipeInstance) : - pipeInstance.transform(v1, v2, v3, v4)); + lView, + isPure(lView, index) ? pureFunction4Internal( + lView, getBindingRoot(), slotOffset, pipeInstance.transform, v1, + v2, v3, v4, pipeInstance) : + pipeInstance.transform(v1, v2, v3, v4)); } /** @@ -184,7 +188,8 @@ export function ɵɵpipeBindV(index: number, slotOffset: number, values: [any, . const lView = getLView(); const pipeInstance = load<PipeTransform>(lView, index); return unwrapValue( - lView, isPure(lView, index) ? + lView, + isPure(lView, index) ? pureFunctionVInternal( lView, getBindingRoot(), slotOffset, pipeInstance.transform, values, pipeInstance) : pipeInstance.transform.apply(pipeInstance, values)); diff --git a/packages/core/src/render3/pure_function.ts b/packages/core/src/render3/pure_function.ts index 2594661166792..762837c866916 100644 --- a/packages/core/src/render3/pure_function.ts +++ b/packages/core/src/render3/pure_function.ts @@ -154,8 +154,9 @@ export function ɵɵpureFunction5( const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated(lView, bindingIndex + 4, exp5) || different ? updateBinding( - lView, bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) : - pureFn(exp1, exp2, exp3, exp4, exp5)) : + lView, bindingIndex + 5, + thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) : + pureFn(exp1, exp2, exp3, exp4, exp5)) : getBinding(lView, bindingIndex + 5); } @@ -184,9 +185,9 @@ export function ɵɵpureFunction6( const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated2(lView, bindingIndex + 4, exp5, exp6) || different ? updateBinding( - lView, bindingIndex + 6, thisArg ? - pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) : - pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) : + lView, bindingIndex + 6, + thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) : + pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) : getBinding(lView, bindingIndex + 6); } @@ -217,9 +218,9 @@ export function ɵɵpureFunction7( let different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated3(lView, bindingIndex + 4, exp5, exp6, exp7) || different ? updateBinding( - lView, bindingIndex + 7, thisArg ? - pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) : - pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) : + lView, bindingIndex + 7, + thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) : + pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) : getBinding(lView, bindingIndex + 7); } @@ -252,9 +253,9 @@ export function ɵɵpureFunction8( const different = bindingUpdated4(lView, bindingIndex, exp1, exp2, exp3, exp4); return bindingUpdated4(lView, bindingIndex + 4, exp5, exp6, exp7, exp8) || different ? updateBinding( - lView, bindingIndex + 8, thisArg ? - pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) : - pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) : + lView, bindingIndex + 8, + thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) : + pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) : getBinding(lView, bindingIndex + 8); } diff --git a/packages/core/src/render3/query.ts b/packages/core/src/render3/query.ts index ca1b736a1ba3a..3286f439b0436 100644 --- a/packages/core/src/render3/query.ts +++ b/packages/core/src/render3/query.ts @@ -36,8 +36,12 @@ const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4; class LQuery_<T> implements LQuery<T> { matches: (T|null)[]|null = null; constructor(public queryList: QueryList<T>) {} - clone(): LQuery<T> { return new LQuery_(this.queryList); } - setDirty(): void { this.queryList.setDirty(); } + clone(): LQuery<T> { + return new LQuery_(this.queryList); + } + setDirty(): void { + this.queryList.setDirty(); + } } class LQueries_ implements LQueries { @@ -66,9 +70,13 @@ class LQueries_ implements LQueries { return null; } - insertView(tView: TView): void { this.dirtyQueriesWithMatches(tView); } + insertView(tView: TView): void { + this.dirtyQueriesWithMatches(tView); + } - detachView(tView: TView): void { this.dirtyQueriesWithMatches(tView); } + detachView(tView: TView): void { + this.dirtyQueriesWithMatches(tView); + } private dirtyQueriesWithMatches(tView: TView) { for (let i = 0; i < this.queries.length; i++) { @@ -89,8 +97,9 @@ class TQueries_ implements TQueries { constructor(private queries: TQuery[] = []) {} elementStart(tView: TView, tNode: TNode): void { - ngDevMode && assertFirstCreatePass( - tView, 'Queries should collect results on the first template pass only'); + ngDevMode && + assertFirstCreatePass( + tView, 'Queries should collect results on the first template pass only'); for (let i = 0; i < this.queries.length; i++) { this.queries[i].elementStart(tView, tNode); } @@ -121,8 +130,9 @@ class TQueries_ implements TQueries { } template(tView: TView, tNode: TNode): void { - ngDevMode && assertFirstCreatePass( - tView, 'Queries should collect results on the first template pass only'); + ngDevMode && + assertFirstCreatePass( + tView, 'Queries should collect results on the first template pass only'); for (let i = 0; i < this.queries.length; i++) { this.queries[i].template(tView, tNode); } @@ -133,9 +143,13 @@ class TQueries_ implements TQueries { return this.queries[index]; } - get length(): number { return this.queries.length; } + get length(): number { + return this.queries.length; + } - track(tquery: TQuery): void { this.queries.push(tquery); } + track(tquery: TQuery): void { + this.queries.push(tquery); + } } class TQuery_ implements TQuery { @@ -173,7 +187,9 @@ class TQuery_ implements TQuery { } } - template(tView: TView, tNode: TNode): void { this.elementStart(tView, tNode); } + template(tView: TView, tNode: TNode): void { + this.elementStart(tView, tNode); + } embeddedTView(tNode: TNode, childQueryIndex: number): TQuery|null { if (this.isApplyingToNode(tNode)) { @@ -307,15 +323,17 @@ function createSpecialToken(lView: LView, tNode: TNode, read: any): any { } else if (read === ViewEngine_TemplateRef) { return createTemplateRef(ViewEngine_TemplateRef, ViewEngine_ElementRef, tNode, lView); } else if (read === ViewContainerRef) { - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Element, TNodeType.Container, TNodeType.ElementContainer); return createContainerRef( ViewContainerRef, ViewEngine_ElementRef, tNode as TElementNode | TContainerNode | TElementContainerNode, lView); } else { ngDevMode && throwError( - `Special token to read should be one of ElementRef, TemplateRef or ViewContainerRef but got ${stringify(read)}.`); + `Special token to read should be one of ElementRef, TemplateRef or ViewContainerRef but got ${ + stringify(read)}.`); } } @@ -325,11 +343,11 @@ function createSpecialToken(lView: LView, tNode: TNode, read: any): any { * doesn't change). */ function materializeViewResults<T>( - tView: TView, lView: LView, tQuery: TQuery, queryIndex: number): (T | null)[] { - const lQuery = lView[QUERIES] !.queries ![queryIndex]; + tView: TView, lView: LView, tQuery: TQuery, queryIndex: number): (T|null)[] { + const lQuery = lView[QUERIES]!.queries![queryIndex]; if (lQuery.matches === null) { const tViewData = tView.data; - const tQueryMatches = tQuery.matches !; + const tQueryMatches = tQuery.matches!; const result: T|null[] = []; for (let i = 0; i < tQueryMatches.length; i += 2) { const matchedNodeIdx = tQueryMatches[i]; @@ -355,7 +373,7 @@ function materializeViewResults<T>( * starting with a provided LView. */ function collectQueryResults<T>(tView: TView, lView: LView, queryIndex: number, result: T[]): T[] { - const tQuery = tView.queries !.getByIndex(queryIndex); + const tQuery = tView.queries!.getByIndex(queryIndex); const tQueryMatches = tQuery.matches; if (tQueryMatches !== null) { const lViewResults = materializeViewResults<T>(tView, lView, tQuery, queryIndex); @@ -381,7 +399,7 @@ function collectQueryResults<T>(tView: TView, lView: LView, queryIndex: number, // collect matches for views created from this declaration container and inserted into // different containers if (declarationLContainer[MOVED_VIEWS] !== null) { - const embeddedLViews = declarationLContainer[MOVED_VIEWS] !; + const embeddedLViews = declarationLContainer[MOVED_VIEWS]!; for (let i = 0; i < embeddedLViews.length; i++) { const embeddedLView = embeddedLViews[i]; collectQueryResults(embeddedLView[TVIEW], embeddedLView, childQueryIndex, result); @@ -436,7 +454,7 @@ export function ɵɵqueryRefresh(queryList: QueryList<any>): boolean { * @codeGenApi */ export function ɵɵstaticViewQuery<T>( - predicate: Type<any>| string[], descend: boolean, read?: any): void { + predicate: Type<any>|string[], descend: boolean, read?: any): void { viewQueryInternal(getTView(), getLView(), predicate, descend, read, true); } @@ -449,12 +467,12 @@ export function ɵɵstaticViewQuery<T>( * * @codeGenApi */ -export function ɵɵviewQuery<T>(predicate: Type<any>| string[], descend: boolean, read?: any): void { +export function ɵɵviewQuery<T>(predicate: Type<any>|string[], descend: boolean, read?: any): void { viewQueryInternal(getTView(), getLView(), predicate, descend, read, false); } function viewQueryInternal<T>( - tView: TView, lView: LView, predicate: Type<any>| string[], descend: boolean, read: any, + tView: TView, lView: LView, predicate: Type<any>|string[], descend: boolean, read: any, isStatic: boolean): void { if (tView.firstCreatePass) { createTQuery(tView, new TQueryMetadata_(predicate, descend, isStatic, read), -1); @@ -478,7 +496,7 @@ function viewQueryInternal<T>( * @codeGenApi */ export function ɵɵcontentQuery<T>( - directiveIndex: number, predicate: Type<any>| string[], descend: boolean, read?: any): void { + directiveIndex: number, predicate: Type<any>|string[], descend: boolean, read?: any): void { contentQueryInternal( getTView(), getLView(), predicate, descend, read, false, getPreviousOrParentTNode(), directiveIndex); @@ -497,14 +515,14 @@ export function ɵɵcontentQuery<T>( * @codeGenApi */ export function ɵɵstaticContentQuery<T>( - directiveIndex: number, predicate: Type<any>| string[], descend: boolean, read?: any): void { + directiveIndex: number, predicate: Type<any>|string[], descend: boolean, read?: any): void { contentQueryInternal( getTView(), getLView(), predicate, descend, read, true, getPreviousOrParentTNode(), directiveIndex); } function contentQueryInternal<T>( - tView: TView, lView: LView, predicate: Type<any>| string[], descend: boolean, read: any, + tView: TView, lView: LView, predicate: Type<any>|string[], descend: boolean, read: any, isStatic: boolean, tNode: TNode, directiveIndex: number): void { if (tView.firstCreatePass) { createTQuery(tView, new TQueryMetadata_(predicate, descend, isStatic, read), tNode.index); @@ -529,8 +547,8 @@ export function ɵɵloadQuery<T>(): QueryList<T> { function loadQueryInternal<T>(lView: LView, queryIndex: number): QueryList<T> { ngDevMode && assertDefined(lView[QUERIES], 'LQueries should be defined when trying to load a query'); - ngDevMode && assertDataInRange(lView[QUERIES] !.queries, queryIndex); - return lView[QUERIES] !.queries[queryIndex].queryList; + ngDevMode && assertDataInRange(lView[QUERIES]!.queries, queryIndex); + return lView[QUERIES]!.queries[queryIndex].queryList; } function createLQuery<T>(tView: TView, lView: LView) { @@ -538,7 +556,7 @@ function createLQuery<T>(tView: TView, lView: LView) { storeCleanupWithContext(tView, lView, queryList, queryList.destroy); if (lView[QUERIES] === null) lView[QUERIES] = new LQueries_(); - lView[QUERIES] !.queries.push(new LQuery_(queryList)); + lView[QUERIES]!.queries.push(new LQuery_(queryList)); } function createTQuery(tView: TView, metadata: TQueryMetadata, nodeIndex: number): void { @@ -551,11 +569,11 @@ function saveContentQueryAndDirectiveIndex(tView: TView, directiveIndex: number) const lastSavedDirectiveIndex = tView.contentQueries.length ? tViewContentQueries[tViewContentQueries.length - 1] : -1; if (directiveIndex !== lastSavedDirectiveIndex) { - tViewContentQueries.push(tView.queries !.length - 1, directiveIndex); + tViewContentQueries.push(tView.queries!.length - 1, directiveIndex); } } function getTQuery(tView: TView, index: number): TQuery { ngDevMode && assertDefined(tView.queries, 'TQueries must be defined to retrieve a TQuery'); - return tView.queries !.getByIndex(index); + return tView.queries!.getByIndex(index); } diff --git a/packages/core/src/render3/state.ts b/packages/core/src/render3/state.ts index 2a45f8c6019d9..79210bb34e1c1 100644 --- a/packages/core/src/render3/state.ts +++ b/packages/core/src/render3/state.ts @@ -373,7 +373,7 @@ export function enterDI(newView: LView, tNode: TNode) { ngDevMode && assertLViewOrUndefined(newView); const newLFrame = allocLFrame(); instructionState.lFrame = newLFrame; - newLFrame.previousOrParentTNode = tNode !; + newLFrame.previousOrParentTNode = tNode!; newLFrame.lView = newView; } @@ -389,7 +389,7 @@ export function enterDI(newView: LView, tNode: TNode) { * @param tNode Element to which the View is a child of * @returns the previously active lView; */ -export function enterView(newView: LView, tNode: TNode | null): void { +export function enterView(newView: LView, tNode: TNode|null): void { ngDevMode && assertLViewOrUndefined(newView); const newLFrame = allocLFrame(); if (ngDevMode) { @@ -406,10 +406,10 @@ export function enterView(newView: LView, tNode: TNode | null): void { } const tView = newView[TVIEW]; instructionState.lFrame = newLFrame; - newLFrame.previousOrParentTNode = tNode !; + newLFrame.previousOrParentTNode = tNode!; newLFrame.lView = newView; newLFrame.tView = tView; - newLFrame.contextLView = newView !; + newLFrame.contextLView = newView!; newLFrame.bindingIndex = tView.bindingStartIndex; } @@ -423,23 +423,23 @@ function allocLFrame() { return newLFrame; } -function createLFrame(parent: LFrame | null): LFrame { +function createLFrame(parent: LFrame|null): LFrame { const lFrame: LFrame = { - previousOrParentTNode: null !, // - isParent: true, // - lView: null !, // - tView: null !, // - selectedIndex: 0, // - contextLView: null !, // - elementDepthCount: 0, // - currentNamespace: null, // - currentSanitizer: null, // - currentDirectiveIndex: -1, // - bindingRootIndex: -1, // - bindingIndex: -1, // - currentQueryIndex: 0, // - parent: parent !, // - child: null, // + previousOrParentTNode: null!, // + isParent: true, // + lView: null!, // + tView: null!, // + selectedIndex: 0, // + contextLView: null!, // + elementDepthCount: 0, // + currentNamespace: null, // + currentSanitizer: null, // + currentDirectiveIndex: -1, // + bindingRootIndex: -1, // + bindingIndex: -1, // + currentQueryIndex: 0, // + parent: parent!, // + child: null, // }; parent !== null && (parent.child = lFrame); // link the new LFrame for reuse. return lFrame; @@ -457,8 +457,8 @@ function createLFrame(parent: LFrame | null): LFrame { function leaveViewLight(): LFrame { const oldLFrame = instructionState.lFrame; instructionState.lFrame = oldLFrame.parent; - oldLFrame.previousOrParentTNode = null !; - oldLFrame.lView = null !; + oldLFrame.previousOrParentTNode = null!; + oldLFrame.lView = null!; return oldLFrame; } @@ -481,9 +481,9 @@ export const leaveDI: () => void = leaveViewLight; export function leaveView() { const oldLFrame = leaveViewLight(); oldLFrame.isParent = true; - oldLFrame.tView = null !; + oldLFrame.tView = null!; oldLFrame.selectedIndex = 0; - oldLFrame.contextLView = null !; + oldLFrame.contextLView = null!; oldLFrame.elementDepthCount = 0; oldLFrame.currentDirectiveIndex = -1; oldLFrame.currentNamespace = null; @@ -495,16 +495,17 @@ export function leaveView() { export function nextContextImpl<T = any>(level: number): T { const contextLView = instructionState.lFrame.contextLView = - walkUpViews(level, instructionState.lFrame.contextLView !); + walkUpViews(level, instructionState.lFrame.contextLView!); return contextLView[CONTEXT] as T; } function walkUpViews(nestingLevel: number, currentView: LView): LView { while (nestingLevel > 0) { - ngDevMode && assertDefined( - currentView[DECLARATION_VIEW], - 'Declaration view should be defined if nesting level is greater than 0.'); - currentView = currentView[DECLARATION_VIEW] !; + ngDevMode && + assertDefined( + currentView[DECLARATION_VIEW], + 'Declaration view should be defined if nesting level is greater than 0.'); + currentView = currentView[DECLARATION_VIEW]!; nestingLevel--; } return currentView; @@ -581,7 +582,7 @@ export function getNamespace(): string|null { return instructionState.lFrame.currentNamespace; } -export function setCurrentStyleSanitizer(sanitizer: StyleSanitizeFn | null) { +export function setCurrentStyleSanitizer(sanitizer: StyleSanitizeFn|null) { instructionState.lFrame.currentSanitizer = sanitizer; } diff --git a/packages/core/src/render3/styling/class_differ.ts b/packages/core/src/render3/styling/class_differ.ts index 36b8f05c0b0f0..3f3f5e8f8fc5f 100644 --- a/packages/core/src/render3/styling/class_differ.ts +++ b/packages/core/src/render3/styling/class_differ.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {assertNotEqual} from '../../util/assert'; import {CharCode} from '../../util/char_code'; diff --git a/packages/core/src/render3/styling/static_styling.ts b/packages/core/src/render3/styling/static_styling.ts index 9a54073ac9e8f..d27fa5519181a 100644 --- a/packages/core/src/render3/styling/static_styling.ts +++ b/packages/core/src/render3/styling/static_styling.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {concatStringsWithSpace} from '../../util/stringify'; import {assertFirstCreatePass} from '../assert'; diff --git a/packages/core/src/render3/styling/style_binding_list.ts b/packages/core/src/render3/styling/style_binding_list.ts index 808e4e11eb98b..636cce8de520b 100644 --- a/packages/core/src/render3/styling/style_binding_list.ts +++ b/packages/core/src/render3/styling/style_binding_list.ts @@ -1,16 +1,16 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {KeyValueArray, keyValueArrayIndexOf} from '../../util/array_utils'; import {assertDataInRange, assertEqual, assertNotEqual} from '../../util/assert'; import {assertFirstUpdatePass} from '../assert'; import {TNode} from '../interfaces/node'; -import {TStylingKey, TStylingKeyPrimitive, TStylingRange, getTStylingRangeNext, getTStylingRangePrev, setTStylingRangeNext, setTStylingRangeNextDuplicate, setTStylingRangePrev, setTStylingRangePrevDuplicate, toTStylingRange} from '../interfaces/styling'; +import {getTStylingRangeNext, getTStylingRangePrev, setTStylingRangeNext, setTStylingRangeNextDuplicate, setTStylingRangePrev, setTStylingRangePrevDuplicate, toTStylingRange, TStylingKey, TStylingKeyPrimitive, TStylingRange} from '../interfaces/styling'; import {TData} from '../interfaces/view'; import {getTView} from '../state'; @@ -249,9 +249,10 @@ export function insertTStylingBinding( // We are inserting in template section. // We need to set this binding's "previous" to the current template tail tData[index + 1] = toTStylingRange(tmplTail, 0); - ngDevMode && assertEqual( - tmplHead !== 0 && tmplTail === 0, false, - 'Adding template bindings after hostBindings is not allowed.'); + ngDevMode && + assertEqual( + tmplHead !== 0 && tmplTail === 0, false, + 'Adding template bindings after hostBindings is not allowed.'); if (tmplHead === 0) { tmplHead = index; } else { @@ -409,13 +410,14 @@ function isStylingMatch(tStylingKeyCursor: TStylingKey, tStylingKey: TStylingKey ngDevMode && assertNotEqual( Array.isArray(tStylingKey), true, 'Expected that \'tStylingKey\' has been unwrapped'); - if (tStylingKeyCursor === null || // If the cursor is `null` it means that we have map at that + if ( + tStylingKeyCursor === null || // If the cursor is `null` it means that we have map at that // location so we must assume that we have a match. tStylingKey == null || // If `tStylingKey` is `null` then it is a map therefor assume that it // contains a match. (Array.isArray(tStylingKeyCursor) ? tStylingKeyCursor[1] : tStylingKeyCursor) === tStylingKey // If the keys match explicitly than we are a match. - ) { + ) { return true; } else if (Array.isArray(tStylingKeyCursor) && typeof tStylingKey === 'string') { // if we did not find a match, but `tStylingKeyCursor` is `KeyValueArray` that means cursor has diff --git a/packages/core/src/render3/styling/styling_parser.ts b/packages/core/src/render3/styling/styling_parser.ts index 89f24757a14db..1d97f51c8ff5b 100644 --- a/packages/core/src/render3/styling/styling_parser.ts +++ b/packages/core/src/render3/styling/styling_parser.ts @@ -244,7 +244,7 @@ export function consumeSeparator( * @param startIndex Starting index of character where the scan should start. * @param endIndex Ending index of character where the scan should end. * @returns Index after last style value character. -*/ + */ export function consumeStyleValue(text: string, startIndex: number, endIndex: number): number { let ch1 = -1; // 1st previous character let ch2 = -1; // 2nd previous character diff --git a/packages/core/src/render3/util/attrs_utils.ts b/packages/core/src/render3/util/attrs_utils.ts index 4b6201dfa45c0..e9b6939602db4 100644 --- a/packages/core/src/render3/util/attrs_utils.ts +++ b/packages/core/src/render3/util/attrs_utils.ts @@ -8,7 +8,7 @@ import {CharCode} from '../../util/char_code'; import {AttributeMarker, TAttributes} from '../interfaces/node'; import {CssSelector} from '../interfaces/projection'; -import {ProceduralRenderer3, RElement, Renderer3, isProceduralRenderer} from '../interfaces/renderer'; +import {isProceduralRenderer, ProceduralRenderer3, RElement, Renderer3} from '../interfaces/renderer'; @@ -96,7 +96,7 @@ export function setUpAttributes(renderer: Renderer3, native: RElement, attrs: TA * @param marker The attribute marker to test. * @returns true if the marker is a "name-only" marker (e.g. `Bindings`, `Template` or `I18n`). */ -export function isNameOnlyAttributeMarker(marker: string | AttributeMarker | CssSelector) { +export function isNameOnlyAttributeMarker(marker: string|AttributeMarker|CssSelector) { return marker === AttributeMarker.Bindings || marker === AttributeMarker.Template || marker === AttributeMarker.I18n; } @@ -116,7 +116,7 @@ export function isAnimationProp(name: string): boolean { * @param dst Location of where the merged `TAttributes` should end up. * @param src `TAttributes` which should be appended to `dst` */ -export function mergeHostAttrs(dst: TAttributes | null, src: TAttributes | null): TAttributes|null { +export function mergeHostAttrs(dst: TAttributes|null, src: TAttributes|null): TAttributes|null { if (src === null || src.length === 0) { // do nothing } else if (dst === null || dst.length === 0) { @@ -156,8 +156,8 @@ export function mergeHostAttrs(dst: TAttributes | null, src: TAttributes | null) * @param value Value to add or to overwrite to `TAttributes` Only used if `marker` is not Class. */ export function mergeHostAttribute( - dst: TAttributes, marker: AttributeMarker, key1: string, key2: string | null, - value: string | null): void { + dst: TAttributes, marker: AttributeMarker, key1: string, key2: string|null, + value: string|null): void { let i = 0; // Assume that new markers will be inserted at the end. let markerInsertPosition = dst.length; @@ -195,7 +195,7 @@ export function mergeHostAttribute( } return; } else if (key2 === dst[i + 1]) { - dst[i + 2] = value !; + dst[i + 2] = value!; return; } } diff --git a/packages/core/src/render3/util/discovery_utils.ts b/packages/core/src/render3/util/discovery_utils.ts index 695d2899ff405..41b4ba81d193d 100644 --- a/packages/core/src/render3/util/discovery_utils.ts +++ b/packages/core/src/render3/util/discovery_utils.ts @@ -10,12 +10,13 @@ import {Injector} from '../../di/injector'; import {assertLView} from '../assert'; import {discoverLocalRefs, getComponentAtNodeIndex, getDirectivesAtNodeIndex, getLContext} from '../context_discovery'; import {NodeInjector} from '../di'; -import {DebugNode, buildDebugNode} from '../instructions/lview_debug'; +import {buildDebugNode, DebugNode} from '../instructions/lview_debug'; import {LContext} from '../interfaces/context'; import {DirectiveDef} from '../interfaces/definition'; import {TElementNode, TNode, TNodeProviderIndexes} from '../interfaces/node'; import {isLView} from '../interfaces/type_checks'; -import {CLEANUP, CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, TVIEW, T_HOST} from '../interfaces/view'; +import {CLEANUP, CONTEXT, FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, T_HOST, TVIEW} from '../interfaces/view'; + import {stringifyForError} from './misc_utils'; import {getLViewParent, getRootContext} from './view_traversal_utils'; import {getTNode, unwrapRNode} from './view_utils'; @@ -93,14 +94,14 @@ export function getContext<T>(element: Element): T|null { * @publicApi * @globalApi ng */ -export function getOwningComponent<T>(elementOrDir: Element | {}): T|null { +export function getOwningComponent<T>(elementOrDir: Element|{}): T|null { const context = loadLContext(elementOrDir, false); if (context === null) return null; let lView = context.lView; let parent: LView|null; ngDevMode && assertLView(lView); - while (lView[HOST] === null && (parent = getLViewParent(lView) !)) { + while (lView[HOST] === null && (parent = getLViewParent(lView)!)) { // As long as lView[HOST] is null we know we are part of sub-template such as `*ngIf` lView = parent; } @@ -118,7 +119,7 @@ export function getOwningComponent<T>(elementOrDir: Element | {}): T|null { * @publicApi * @globalApi ng */ -export function getRootComponents(elementOrDir: Element | {}): {}[] { +export function getRootComponents(elementOrDir: Element|{}): {}[] { return [...getRootContext(elementOrDir).components]; } @@ -132,7 +133,7 @@ export function getRootComponents(elementOrDir: Element | {}): {}[] { * @publicApi * @globalApi ng */ -export function getInjector(elementOrDir: Element | {}): Injector { +export function getInjector(elementOrDir: Element|{}): Injector { const context = loadLContext(elementOrDir, false); if (context === null) return Injector.NULL; @@ -192,7 +193,7 @@ export function getInjectionTokens(element: Element): any[] { * @globalApi ng */ export function getDirectives(element: Element): {}[] { - const context = loadLContext(element) !; + const context = loadLContext(element)!; if (context.directives === undefined) { context.directives = getDirectivesAtNodeIndex(context.nodeIndex, context.lView, false); @@ -250,7 +251,7 @@ export function getLocalRefs(target: {}): {[key: string]: any} { * @globalApi ng */ export function getHostElement(componentOrDirective: {}): Element { - return getLContext(componentOrDirective) !.native as never as Element; + return getLContext(componentOrDirective)!.native as never as Element; } /** @@ -270,7 +271,7 @@ export function getRenderedText(component: any): string { export function loadLContextFromNode(node: Node): LContext { if (!(node instanceof Node)) throw new Error('Expecting instance of DOM Element'); - return loadLContext(node) !; + return loadLContext(node)!; } /** diff --git a/packages/core/src/render3/util/injector_utils.ts b/packages/core/src/render3/util/injector_utils.ts index 0de9682a56404..4d77357745db9 100644 --- a/packages/core/src/render3/util/injector_utils.ts +++ b/packages/core/src/render3/util/injector_utils.ts @@ -37,7 +37,7 @@ export function getParentInjectorView(location: RelativeInjectorLocation, startV // <ng-template> tags or inline views, where the parent injector might live many views // above the child injector. while (viewOffset > 0) { - parentView = parentView[DECLARATION_VIEW] !; + parentView = parentView[DECLARATION_VIEW]!; viewOffset--; } return parentView; diff --git a/packages/core/src/render3/util/misc_utils.ts b/packages/core/src/render3/util/misc_utils.ts index 5d0b9ea648cec..d2805739e1546 100644 --- a/packages/core/src/render3/util/misc_utils.ts +++ b/packages/core/src/render3/util/misc_utils.ts @@ -37,16 +37,18 @@ export function stringifyForError(value: any): string { export const defaultScheduler = - (() => - (typeof requestAnimationFrame !== 'undefined' && requestAnimationFrame || // browser only - setTimeout // everything else - ).bind(global))(); + (() => ( + typeof requestAnimationFrame !== 'undefined' && + requestAnimationFrame || // browser only + setTimeout // everything else + ) + .bind(global))(); /** * * @codeGenApi */ -export function ɵɵresolveWindow(element: RElement & {ownerDocument: Document}) { +export function ɵɵresolveWindow(element: RElement&{ownerDocument: Document}) { return {name: 'window', target: element.ownerDocument.defaultView}; } @@ -54,7 +56,7 @@ export function ɵɵresolveWindow(element: RElement & {ownerDocument: Document}) * * @codeGenApi */ -export function ɵɵresolveDocument(element: RElement & {ownerDocument: Document}) { +export function ɵɵresolveDocument(element: RElement&{ownerDocument: Document}) { return {name: 'document', target: element.ownerDocument}; } @@ -62,7 +64,7 @@ export function ɵɵresolveDocument(element: RElement & {ownerDocument: Document * * @codeGenApi */ -export function ɵɵresolveBody(element: RElement & {ownerDocument: Document}) { +export function ɵɵresolveBody(element: RElement&{ownerDocument: Document}) { return {name: 'body', target: element.ownerDocument.body}; } @@ -85,7 +87,7 @@ export const INTERPOLATION_DELIMITER = `�`; /** * Unwrap a value which might be behind a closure (for forward declaration reasons). */ -export function maybeUnwrapFn<T>(value: T | (() => T)): T { +export function maybeUnwrapFn<T>(value: T|(() => T)): T { if (value instanceof Function) { return value(); } else { diff --git a/packages/core/src/render3/util/view_traversal_utils.ts b/packages/core/src/render3/util/view_traversal_utils.ts index 0be540c9f9ef1..7cda0ad9656f1 100644 --- a/packages/core/src/render3/util/view_traversal_utils.ts +++ b/packages/core/src/render3/util/view_traversal_utils.ts @@ -21,7 +21,7 @@ import {readPatchedLView} from './view_utils'; export function getLViewParent(lView: LView): LView|null { ngDevMode && assertLView(lView); const parent = lView[PARENT]; - return isLContainer(parent) ? parent[PARENT] ! : parent; + return isLContainer(parent) ? parent[PARENT]! : parent; } /** @@ -30,11 +30,11 @@ export function getLViewParent(lView: LView): LView|null { * * @param componentOrLView any component or `LView` */ -export function getRootView(componentOrLView: LView | {}): LView { +export function getRootView(componentOrLView: LView|{}): LView { ngDevMode && assertDefined(componentOrLView, 'component'); - let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView) !; + let lView = isLView(componentOrLView) ? componentOrLView : readPatchedLView(componentOrLView)!; while (lView && !(lView[FLAGS] & LViewFlags.IsRoot)) { - lView = getLViewParent(lView) !; + lView = getLViewParent(lView)!; } ngDevMode && assertLView(lView); return lView; @@ -47,7 +47,7 @@ export function getRootView(componentOrLView: LView | {}): LView { * * @param viewOrComponent the `LView` or component to get the root context for. */ -export function getRootContext(viewOrComponent: LView | {}): RootContext { +export function getRootContext(viewOrComponent: LView|{}): RootContext { const rootView = getRootView(viewOrComponent); ngDevMode && assertDefined(rootView[CONTEXT], 'RootView has no context. Perhaps it is disconnected?'); diff --git a/packages/core/src/render3/util/view_utils.ts b/packages/core/src/render3/util/view_utils.ts index d98c91f825c69..54fe62be011fe 100644 --- a/packages/core/src/render3/util/view_utils.ts +++ b/packages/core/src/render3/util/view_utils.ts @@ -11,7 +11,7 @@ import {assertTNodeForLView} from '../assert'; import {ACTIVE_INDEX, ActiveIndexFlag, LContainer, TYPE} from '../interfaces/container'; import {LContext, MONKEY_PATCH_KEY_NAME} from '../interfaces/context'; import {TConstants, TNode} from '../interfaces/node'; -import {RNode, isProceduralRenderer} from '../interfaces/renderer'; +import {isProceduralRenderer, RNode} from '../interfaces/renderer'; import {isLContainer, isLView} from '../interfaces/type_checks'; import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, PREORDER_HOOK_FLAGS, RENDERER, TData, TView} from '../interfaces/view'; @@ -38,7 +38,7 @@ import {FLAGS, HEADER_OFFSET, HOST, LView, LViewFlags, PARENT, PREORDER_HOOK_FLA * Returns `RNode`. * @param value wrapped value of `RNode`, `LView`, `LContainer` */ -export function unwrapRNode(value: RNode | LView | LContainer): RNode { +export function unwrapRNode(value: RNode|LView|LContainer): RNode { while (Array.isArray(value)) { value = value[HOST] as any; } @@ -49,7 +49,7 @@ export function unwrapRNode(value: RNode | LView | LContainer): RNode { * Returns `LView` or `null` if not found. * @param value wrapped value of `RNode`, `LView`, `LContainer` */ -export function unwrapLView(value: RNode | LView | LContainer): LView|null { +export function unwrapLView(value: RNode|LView|LContainer): LView|null { while (Array.isArray(value)) { // This check is same as `isLView()` but we don't call at as we don't want to call // `Array.isArray()` twice and give JITer more work for inlining. @@ -63,7 +63,7 @@ export function unwrapLView(value: RNode | LView | LContainer): LView|null { * Returns `LContainer` or `null` if not found. * @param value wrapped value of `RNode`, `LView`, `LContainer` */ -export function unwrapLContainer(value: RNode | LView | LContainer): LContainer|null { +export function unwrapLContainer(value: RNode|LView|LContainer): LContainer|null { while (Array.isArray(value)) { // This check is same as `isLContainer()` but we don't call at as we don't want to call // `Array.isArray()` twice and give JITer more work for inlining. @@ -124,7 +124,7 @@ export function getTNode(tView: TView, index: number): TNode { } /** Retrieves a value from any `LView` or `TData`. */ -export function load<T>(view: LView | TData, index: number): T { +export function load<T>(view: LView|TData, index: number): T { ngDevMode && assertDataInRange(view, index + HEADER_OFFSET); return view[index + HEADER_OFFSET]; } @@ -176,8 +176,7 @@ export function viewAttachedToContainer(view: LView): boolean { } /** Returns a constant from `TConstants` instance. */ -export function getConstant<T>(consts: TConstants | null, index: number | null | undefined): T| - null { +export function getConstant<T>(consts: TConstants|null, index: number|null|undefined): T|null { return consts === null || index == null ? null : consts[index] as unknown as T; } diff --git a/packages/core/src/render3/view_engine_compatibility.ts b/packages/core/src/render3/view_engine_compatibility.ts index 36c9aa2b75626..5727db3f30639 100644 --- a/packages/core/src/render3/view_engine_compatibility.ts +++ b/packages/core/src/render3/view_engine_compatibility.ts @@ -19,13 +19,13 @@ import {addToArray, removeFromArray} from '../util/array_utils'; import {assertDefined, assertEqual, assertGreaterThan, assertLessThan} from '../util/assert'; import {assertLContainer} from './assert'; -import {NodeInjector, getParentInjectorLocation} from './di'; +import {getParentInjectorLocation, NodeInjector} from './di'; import {addToViewTree, createLContainer, createLView, renderView} from './instructions/shared'; import {ActiveIndexFlag, CONTAINER_HEADER_OFFSET, LContainer, VIEW_REFS} from './interfaces/container'; import {TContainerNode, TDirectiveHostNode, TElementContainerNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node'; -import {RComment, RElement, isProceduralRenderer} from './interfaces/renderer'; +import {isProceduralRenderer, RComment, RElement} from './interfaces/renderer'; import {isComponentHost, isLContainer, isLView, isRootView} from './interfaces/type_checks'; -import {DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, LView, LViewFlags, PARENT, QUERIES, RENDERER, TVIEW, TView, T_HOST} from './interfaces/view'; +import {DECLARATION_COMPONENT_VIEW, DECLARATION_LCONTAINER, LView, LViewFlags, PARENT, QUERIES, RENDERER, T_HOST, TVIEW, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {addRemoveViewFromContainer, appendChild, detachView, getBeforeNodeForView, insertView, nativeInsertBefore, nativeNextSibling, nativeParentNode, removeView} from './node_manipulation'; import {getParentInjectorTNode} from './node_util'; @@ -46,7 +46,7 @@ export function injectElementRef(ElementRefToken: typeof ViewEngine_ElementRef): return createElementRef(ElementRefToken, getPreviousOrParentTNode(), getLView()); } -let R3ElementRef: {new (native: RElement | RComment): ViewEngine_ElementRef}; +let R3ElementRef: {new (native: RElement|RComment): ViewEngine_ElementRef}; /** * Creates an ElementRef given a node. @@ -95,7 +95,7 @@ export function createTemplateRef<T>( TemplateRefToken: typeof ViewEngine_TemplateRef, ElementRefToken: typeof ViewEngine_ElementRef, hostTNode: TNode, hostView: LView): ViewEngine_TemplateRef<T>|null { if (!R3TemplateRef) { - R3TemplateRef = class TemplateRef<T> extends TemplateRefToken<T> { + R3TemplateRef = class TemplateRef<T> extends TemplateRefToken<T>{ constructor( private _declarationView: LView, private _declarationTContainer: TContainerNode, readonly elementRef: ViewEngine_ElementRef) { @@ -138,7 +138,7 @@ export function createTemplateRef<T>( let R3ViewContainerRef: { new ( - lContainer: LContainer, hostTNode: TElementNode | TContainerNode | TElementContainerNode, + lContainer: LContainer, hostTNode: TElementNode|TContainerNode|TElementContainerNode, hostView: LView): ViewEngine_ViewContainerRef }; @@ -183,7 +183,9 @@ export function createContainerRef( return createElementRef(ElementRefToken, this._hostTNode, this._hostView); } - get injector(): Injector { return new NodeInjector(this._hostTNode, this._hostView); } + get injector(): Injector { + return new NodeInjector(this._hostTNode, this._hostView); + } /** @deprecated No replacement */ get parentInjector(): Injector { @@ -203,10 +205,12 @@ export function createContainerRef( } get(index: number): viewEngine_ViewRef|null { - return this._lContainer[VIEW_REFS] !== null && this._lContainer[VIEW_REFS] ![index] || null; + return this._lContainer[VIEW_REFS] !== null && this._lContainer[VIEW_REFS]![index] || null; } - get length(): number { return this._lContainer.length - CONTAINER_HEADER_OFFSET; } + get length(): number { + return this._lContainer.length - CONTAINER_HEADER_OFFSET; + } createEmbeddedView<C>(templateRef: ViewEngine_TemplateRef<C>, context?: C, index?: number): viewEngine_EmbeddedViewRef<C> { @@ -237,7 +241,7 @@ export function createContainerRef( } insert(viewRef: viewEngine_ViewRef, index?: number): viewEngine_ViewRef { - const lView = (viewRef as ViewRef<any>)._lView !; + const lView = (viewRef as ViewRef<any>)._lView!; const tView = lView[TVIEW]; if (viewRef.destroyed) { @@ -259,9 +263,10 @@ export function createContainerRef( this.detach(prevIdx); } else { const prevLContainer = lView[PARENT] as LContainer; - ngDevMode && assertEqual( - isLContainer(prevLContainer), true, - 'An attached view should have its PARENT point to a container.'); + ngDevMode && + assertEqual( + isLContainer(prevLContainer), true, + 'An attached view should have its PARENT point to a container.'); // We need to re-create a R3ViewContainerRef instance since those are not stored on @@ -281,7 +286,7 @@ export function createContainerRef( addRemoveViewFromContainer(tView, lView, true, beforeNode); (viewRef as ViewRef<any>).attachToViewContainerRef(this); - addToArray(this._lContainer[VIEW_REFS] !, adjustedIdx, viewRef); + addToArray(this._lContainer[VIEW_REFS]!, adjustedIdx, viewRef); return viewRef; } @@ -302,7 +307,7 @@ export function createContainerRef( this.allocateContainerIfNeeded(); const adjustedIdx = this._adjustIndex(index, -1); removeView(this._lContainer, adjustedIdx); - removeFromArray(this._lContainer[VIEW_REFS] !, adjustedIdx); + removeFromArray(this._lContainer[VIEW_REFS]!, adjustedIdx); } detach(index?: number): viewEngine_ViewRef|null { @@ -311,8 +316,8 @@ export function createContainerRef( const view = detachView(this._lContainer, adjustedIdx); const wasDetached = - view && removeFromArray(this._lContainer[VIEW_REFS] !, adjustedIdx) != null; - return wasDetached ? new ViewRef(view !) : null; + view && removeFromArray(this._lContainer[VIEW_REFS]!, adjustedIdx) != null; + return wasDetached ? new ViewRef(view!) : null; } private _adjustIndex(index?: number, shift: number = 0) { @@ -335,8 +340,9 @@ export function createContainerRef( }; } - ngDevMode && assertNodeOfPossibleTypes( - hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); + ngDevMode && + assertNodeOfPossibleTypes( + hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer); let lContainer: LContainer; const slotValue = hostView[hostTNode.index]; @@ -363,10 +369,10 @@ export function createContainerRef( // node. if (isRootView(hostView)) { const renderer = hostView[RENDERER]; - const hostNative = getNativeByTNode(hostTNode, hostView) !; + const hostNative = getNativeByTNode(hostTNode, hostView)!; const parentOfHostNative = nativeParentNode(renderer, hostNative); nativeInsertBefore( - renderer, parentOfHostNative !, commentNode, nativeNextSibling(renderer, hostNative)); + renderer, parentOfHostNative!, commentNode, nativeNextSibling(renderer, hostNative)); } else { appendChild(hostView[TVIEW], hostView, commentNode, hostTNode); } @@ -412,7 +418,7 @@ function createViewRef(tNode: TNode, lView: LView, isPipe: boolean): ViewEngine_ const hostComponentView = lView[DECLARATION_COMPONENT_VIEW]; // look up return new ViewRef(hostComponentView, lView); } - return null !; + return null!; } /** Returns a Renderer2 (or throws when application was bootstrapped with Renderer3) */ diff --git a/packages/core/src/render3/view_ref.ts b/packages/core/src/render3/view_ref.ts index 722733dbb4940..10f67c6b66b31 100644 --- a/packages/core/src/render3/view_ref.ts +++ b/packages/core/src/render3/view_ref.ts @@ -10,11 +10,12 @@ import {ApplicationRef} from '../application_ref'; import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref'; import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref'; import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref'; + import {checkNoChangesInRootView, checkNoChangesInternal, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupFn} from './instructions/shared'; import {CONTAINER_HEADER_OFFSET} from './interfaces/container'; import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node'; import {isLContainer} from './interfaces/type_checks'; -import {CONTEXT, DECLARATION_COMPONENT_VIEW, FLAGS, HOST, LView, LViewFlags, TVIEW, TView, T_HOST} from './interfaces/view'; +import {CONTEXT, DECLARATION_COMPONENT_VIEW, FLAGS, HOST, LView, LViewFlags, T_HOST, TVIEW, TView} from './interfaces/view'; import {assertNodeOfPossibleTypes} from './node_assert'; import {destroyLView, renderDetachView} from './node_manipulation'; import {getLViewParent} from './util/view_traversal_utils'; @@ -28,7 +29,7 @@ import {unwrapRNode} from './util/view_utils'; export interface viewEngine_ChangeDetectorRef_interface extends viewEngine_ChangeDetectorRef {} export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_InternalViewRef, - viewEngine_ChangeDetectorRef_interface { + viewEngine_ChangeDetectorRef_interface { private _appRef: ApplicationRef|null = null; private _viewContainerRef: viewEngine_ViewContainerRef|null = null; @@ -68,7 +69,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int */ private _cdRefInjectingView?: LView) {} - get context(): T { return this._lView[CONTEXT] as T; } + get context(): T { + return this._lView[CONTEXT] as T; + } get destroyed(): boolean { return (this._lView[FLAGS] & LViewFlags.Destroyed) === LViewFlags.Destroyed; @@ -89,7 +92,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int destroyLView(this._lView[TVIEW], this._lView); } - onDestroy(callback: Function) { storeCleanupFn(this._lView[TVIEW], this._lView, callback); } + onDestroy(callback: Function) { + storeCleanupFn(this._lView[TVIEW], this._lView, callback); + } /** * Marks a view and all of its ancestors dirty. @@ -125,7 +130,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int * } * ``` */ - markForCheck(): void { markViewDirty(this._cdRefInjectingView || this._lView); } + markForCheck(): void { + markViewDirty(this._cdRefInjectingView || this._lView); + } /** * Detaches the view from the change detection tree. @@ -180,7 +187,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int * } * ``` */ - detach(): void { this._lView[FLAGS] &= ~LViewFlags.Attached; } + detach(): void { + this._lView[FLAGS] &= ~LViewFlags.Attached; + } /** * Re-attaches a view to the change detection tree. @@ -238,7 +247,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int * } * ``` */ - reattach(): void { this._lView[FLAGS] |= LViewFlags.Attached; } + reattach(): void { + this._lView[FLAGS] |= LViewFlags.Attached; + } /** * Checks the view and its children. @@ -261,7 +272,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int * * See {@link ChangeDetectorRef#detach detach} for more information. */ - detectChanges(): void { detectChangesInternal(this._lView[TVIEW], this._lView, this.context); } + detectChanges(): void { + detectChangesInternal(this._lView[TVIEW], this._lView, this.context); + } /** * Checks the change detector and its children, and throws if any changes are detected. @@ -269,7 +282,9 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int * This is used in development mode to verify that running change detection doesn't * introduce other changes. */ - checkNoChanges(): void { checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context); } + checkNoChanges(): void { + checkNoChangesInternal(this._lView[TVIEW], this._lView, this.context); + } attachToViewContainerRef(vcRef: viewEngine_ViewContainerRef) { if (this._appRef) { @@ -293,22 +308,31 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int /** @internal */ export class RootViewRef<T> extends ViewRef<T> { - constructor(public _view: LView) { super(_view); } + constructor(public _view: LView) { + super(_view); + } - detectChanges(): void { detectChangesInRootView(this._view); } + detectChanges(): void { + detectChangesInRootView(this._view); + } - checkNoChanges(): void { checkNoChangesInRootView(this._view); } + checkNoChanges(): void { + checkNoChangesInRootView(this._view); + } - get context(): T { return null !; } + get context(): T { + return null!; + } } function collectNativeNodes( - tView: TView, lView: LView, tNode: TNode | null, result: any[], + tView: TView, lView: LView, tNode: TNode|null, result: any[], isProjection: boolean = false): any[] { while (tNode !== null) { - ngDevMode && assertNodeOfPossibleTypes( - tNode, TNodeType.Element, TNodeType.Container, TNodeType.Projection, - TNodeType.ElementContainer, TNodeType.IcuContainer); + ngDevMode && + assertNodeOfPossibleTypes( + tNode, TNodeType.Element, TNodeType.Container, TNodeType.Projection, + TNodeType.ElementContainer, TNodeType.IcuContainer); const lNode = lView[tNode.index]; if (lNode !== null) { @@ -337,7 +361,7 @@ function collectNativeNodes( const componentHost = componentView[T_HOST] as TElementNode; const parentView = getLViewParent(componentView); let firstProjectedNode: TNode|null = - (componentHost.projection as(TNode | null)[])[tNode.projection as number]; + (componentHost.projection as (TNode | null)[])[tNode.projection as number]; if (firstProjectedNode !== null && parentView !== null) { collectNativeNodes(parentView[TVIEW], parentView, firstProjectedNode, result, true); } diff --git a/packages/core/src/sanitization/bypass.ts b/packages/core/src/sanitization/bypass.ts index 7a0272cd301cc..01287ad15caed 100644 --- a/packages/core/src/sanitization/bypass.ts +++ b/packages/core/src/sanitization/bypass.ts @@ -70,24 +70,34 @@ abstract class SafeValueImpl implements SafeValue { } class SafeHtmlImpl extends SafeValueImpl implements SafeHtml { - getTypeName() { return BypassType.Html; } + getTypeName() { + return BypassType.Html; + } } class SafeStyleImpl extends SafeValueImpl implements SafeStyle { - getTypeName() { return BypassType.Style; } + getTypeName() { + return BypassType.Style; + } } class SafeScriptImpl extends SafeValueImpl implements SafeScript { - getTypeName() { return BypassType.Script; } + getTypeName() { + return BypassType.Script; + } } class SafeUrlImpl extends SafeValueImpl implements SafeUrl { - getTypeName() { return BypassType.Url; } + getTypeName() { + return BypassType.Url; + } } class SafeResourceUrlImpl extends SafeValueImpl implements SafeResourceUrl { - getTypeName() { return BypassType.ResourceUrl; } + getTypeName() { + return BypassType.ResourceUrl; + } } export function unwrapSafeValue(value: SafeValue): string; export function unwrapSafeValue<T>(value: T): T; -export function unwrapSafeValue<T>(value: T | SafeValue): T { +export function unwrapSafeValue<T>(value: T|SafeValue): T { return value instanceof SafeValueImpl ? value.changingThisBreaksApplicationSecurity as any as T : value as any as T; } diff --git a/packages/core/src/sanitization/html_sanitizer.ts b/packages/core/src/sanitization/html_sanitizer.ts index faf6ce328786f..7a8e710eea068 100644 --- a/packages/core/src/sanitization/html_sanitizer.ts +++ b/packages/core/src/sanitization/html_sanitizer.ts @@ -114,19 +114,19 @@ class SanitizingHtmlSerializer { // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters. // However this code never accesses properties off of `document` before deleting its contents // again, so it shouldn't be vulnerable to DOM clobbering. - let current: Node = el.firstChild !; + let current: Node = el.firstChild!; let traverseContent = true; while (current) { if (current.nodeType === Node.ELEMENT_NODE) { traverseContent = this.startElement(current as Element); } else if (current.nodeType === Node.TEXT_NODE) { - this.chars(current.nodeValue !); + this.chars(current.nodeValue!); } else { // Strip non-element, non-text nodes. this.sanitizedSomething = true; } if (traverseContent && current.firstChild) { - current = current.firstChild !; + current = current.firstChild!; continue; } while (current) { @@ -135,14 +135,14 @@ class SanitizingHtmlSerializer { this.endElement(current as Element); } - let next = this.checkClobberedElement(current, current.nextSibling !); + let next = this.checkClobberedElement(current, current.nextSibling!); if (next) { current = next; break; } - current = this.checkClobberedElement(current, current.parentNode !); + current = this.checkClobberedElement(current, current.parentNode!); } } return this.buf.join(''); @@ -167,13 +167,13 @@ class SanitizingHtmlSerializer { const elAttrs = element.attributes; for (let i = 0; i < elAttrs.length; i++) { const elAttr = elAttrs.item(i); - const attrName = elAttr !.name; + const attrName = elAttr!.name; const lower = attrName.toLowerCase(); if (!VALID_ATTRS.hasOwnProperty(lower)) { this.sanitizedSomething = true; continue; } - let value = elAttr !.value; + let value = elAttr!.value; // TODO(martinprobst): Special case image URIs for data:image/... if (URI_ATTRS[lower]) value = _sanitizeUrl(value); if (SRCSET_ATTRS[lower]) value = sanitizeSrcset(value); @@ -192,14 +192,16 @@ class SanitizingHtmlSerializer { } } - private chars(chars: string) { this.buf.push(encodeEntities(chars)); } + private chars(chars: string) { + this.buf.push(encodeEntities(chars)); + } checkClobberedElement(node: Node, nextNode: Node): Node { if (nextNode && (node.compareDocumentPosition(nextNode) & Node.DOCUMENT_POSITION_CONTAINED_BY) === Node.DOCUMENT_POSITION_CONTAINED_BY) { - throw new Error( - `Failed to sanitize html because the element is clobbered: ${(node as Element).outerHTML}`); + throw new Error(`Failed to sanitize html because the element is clobbered: ${ + (node as Element).outerHTML}`); } return nextNode; } @@ -227,7 +229,9 @@ function encodeEntities(value: string) { }) .replace( NON_ALPHANUMERIC_REGEXP, - function(match: string) { return '&#' + match.charCodeAt(0) + ';'; }) + function(match: string) { + return '&#' + match.charCodeAt(0) + ';'; + }) .replace(/</g, '<') .replace(/>/g, '>'); } @@ -258,13 +262,13 @@ export function _sanitizeHtml(defaultDoc: any, unsafeHtmlInput: string): string mXSSAttempts--; unsafeHtml = parsedHtml; - parsedHtml = inertBodyElement !.innerHTML; + parsedHtml = inertBodyElement!.innerHTML; inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml); } while (unsafeHtml !== parsedHtml); const sanitizer = new SanitizingHtmlSerializer(); const safeHtml = sanitizer.sanitizeChildren( - getTemplateContent(inertBodyElement !) as Element || inertBodyElement); + getTemplateContent(inertBodyElement!) as Element || inertBodyElement); if (isDevMode() && sanitizer.sanitizedSomething) { console.warn( 'WARNING: sanitizing HTML stripped some content, see http://g.co/ng/security#xss'); diff --git a/packages/core/src/sanitization/inert_body.ts b/packages/core/src/sanitization/inert_body.ts index 37fc574b66c55..e79311fd08145 100644 --- a/packages/core/src/sanitization/inert_body.ts +++ b/packages/core/src/sanitization/inert_body.ts @@ -80,7 +80,7 @@ export class InertBodyHelper { xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false); xhr.send(undefined); const body: HTMLBodyElement = xhr.response.body; - body.removeChild(body.firstChild !); + body.removeChild(body.firstChild!); return body; } @@ -95,11 +95,9 @@ export class InertBodyHelper { // `<head>` tag. html = '<body><remove></remove>' + html + '</body>'; try { - const body = new (window as any) - .DOMParser() - .parseFromString(html, 'text/html') - .body as HTMLBodyElement; - body.removeChild(body.firstChild !); + const body = new (window as any).DOMParser().parseFromString(html, 'text/html').body as + HTMLBodyElement; + body.removeChild(body.firstChild!); return body; } catch { return null; @@ -152,7 +150,7 @@ export class InertBodyHelper { // loop backwards so that we can support removals. for (let i = elAttrs.length - 1; 0 < i; i--) { const attrib = elAttrs.item(i); - const attrName = attrib !.name; + const attrName = attrib!.name; if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) { el.removeAttribute(attrName); } diff --git a/packages/core/src/sanitization/sanitization.ts b/packages/core/src/sanitization/sanitization.ts index 653f5a5b69ceb..cf9a3a4562579 100644 --- a/packages/core/src/sanitization/sanitization.ts +++ b/packages/core/src/sanitization/sanitization.ts @@ -11,11 +11,11 @@ import {SANITIZER} from '../render3/interfaces/view'; import {getLView} from '../render3/state'; import {renderStringify} from '../render3/util/misc_utils'; -import {BypassType, allowSanitizationBypassAndThrow, unwrapSafeValue} from './bypass'; +import {allowSanitizationBypassAndThrow, BypassType, unwrapSafeValue} from './bypass'; import {_sanitizeHtml as _sanitizeHtml} from './html_sanitizer'; import {Sanitizer} from './sanitizer'; import {SecurityContext} from './security'; -import {StyleSanitizeFn, StyleSanitizeMode, _sanitizeStyle} from './style_sanitizer'; +import {_sanitizeStyle, StyleSanitizeFn, StyleSanitizeMode} from './style_sanitizer'; import {_sanitizeUrl as _sanitizeUrl} from './url_sanitizer'; @@ -152,8 +152,9 @@ export function ɵɵsanitizeScript(unsafeScript: any): string { * If tag and prop names don't match Resource URL schema, use URL sanitizer. */ export function getUrlSanitizer(tag: string, prop: string) { - if ((prop === 'src' && (tag === 'embed' || tag === 'frame' || tag === 'iframe' || - tag === 'media' || tag === 'script')) || + if ((prop === 'src' && + (tag === 'embed' || tag === 'frame' || tag === 'iframe' || tag === 'media' || + tag === 'script')) || (prop === 'href' && (tag === 'base' || tag === 'link'))) { return ɵɵsanitizeResourceUrl; } @@ -186,7 +187,7 @@ export function ɵɵsanitizeUrlOrResourceUrl(unsafeUrl: any, tag: string, prop: * @publicApi */ export const ɵɵdefaultStyleSanitizer = - (function(prop: string, value: string|null, mode?: StyleSanitizeMode): string | boolean | null { + (function(prop: string, value: string|null, mode?: StyleSanitizeMode): string|boolean|null { if (value === undefined && mode === undefined) { // This is a workaround for the fact that `StyleSanitizeFn` should not exist once PR#34480 // lands. For now the `StyleSanitizeFn` and should act like `(value: any) => string` as a diff --git a/packages/core/src/testability/testability.ts b/packages/core/src/testability/testability.ts index 05cfc9c53644b..d4309947a17c7 100644 --- a/packages/core/src/testability/testability.ts +++ b/packages/core/src/testability/testability.ts @@ -133,7 +133,7 @@ export class Testability implements PublicTestability { // Schedules the call backs in a new frame so that it is always async. scheduleMicroTask(() => { while (this._callbacks.length !== 0) { - let cb = this._callbacks.pop() !; + let cb = this._callbacks.pop()!; clearTimeout(cb.timeoutId); cb.doneCb(this._didWork); } @@ -210,7 +210,9 @@ export class Testability implements PublicTestability { * Get the number of pending requests * @deprecated pending requests are now tracked with zones */ - getPendingRequestCount(): number { return this._pendingCount; } + getPendingRequestCount(): number { + return this._pendingCount; + } /** * Find providers by name @@ -233,7 +235,9 @@ export class TestabilityRegistry { /** @internal */ _applications = new Map<any, Testability>(); - constructor() { _testabilityGetter.addToWindow(this); } + constructor() { + _testabilityGetter.addToWindow(this); + } /** * Registers an application with a testability hook so that it can be tracked @@ -248,28 +252,38 @@ export class TestabilityRegistry { * Unregisters an application. * @param token token of application, root element */ - unregisterApplication(token: any) { this._applications.delete(token); } + unregisterApplication(token: any) { + this._applications.delete(token); + } /** * Unregisters all applications */ - unregisterAllApplications() { this._applications.clear(); } + unregisterAllApplications() { + this._applications.clear(); + } /** * Get a testability hook associated with the application * @param elem root element */ - getTestability(elem: any): Testability|null { return this._applications.get(elem) || null; } + getTestability(elem: any): Testability|null { + return this._applications.get(elem) || null; + } /** * Get all registered testabilities */ - getAllTestabilities(): Testability[] { return Array.from(this._applications.values()); } + getAllTestabilities(): Testability[] { + return Array.from(this._applications.values()); + } /** * Get all registered applications(root elements) */ - getAllRootElements(): any[] { return Array.from(this._applications.keys()); } + getAllRootElements(): any[] { + return Array.from(this._applications.keys()); + } /** * Find testability of a node in the Tree diff --git a/packages/core/src/util/WrappedValue.ts b/packages/core/src/util/WrappedValue.ts index 48e5e3f76b33d..a19003474f3ed 100644 --- a/packages/core/src/util/WrappedValue.ts +++ b/packages/core/src/util/WrappedValue.ts @@ -30,17 +30,25 @@ export class WrappedValue { /** @deprecated from 5.3, use `unwrap()` instead - will switch to protected */ wrapped: any; - constructor(value: any) { this.wrapped = value; } + constructor(value: any) { + this.wrapped = value; + } /** Creates a wrapped value. */ - static wrap(value: any): WrappedValue { return new WrappedValue(value); } + static wrap(value: any): WrappedValue { + return new WrappedValue(value); + } /** * Returns the underlying value of a wrapped value. * Returns the given `value` when it is not wrapped. **/ - static unwrap(value: any): any { return WrappedValue.isWrapped(value) ? value.wrapped : value; } + static unwrap(value: any): any { + return WrappedValue.isWrapped(value) ? value.wrapped : value; + } /** Returns true if `value` is a wrapped value. */ - static isWrapped(value: any): value is WrappedValue { return value instanceof WrappedValue; } + static isWrapped(value: any): value is WrappedValue { + return value instanceof WrappedValue; + } } diff --git a/packages/core/src/util/array_utils.ts b/packages/core/src/util/array_utils.ts index 78b1723350b23..08bf5e8b87223 100644 --- a/packages/core/src/util/array_utils.ts +++ b/packages/core/src/util/array_utils.ts @@ -9,11 +9,11 @@ import {assertEqual, assertLessThanOrEqual} from './assert'; /** -* Equivalent to ES6 spread, add each item to an array. -* -* @param items The items to add -* @param arr The array to which you want to add the items -*/ + * Equivalent to ES6 spread, add each item to an array. + * + * @param items The items to add + * @param arr The array to which you want to add the items + */ export function addAllToArray(items: any[], arr: any[]) { for (let i = 0; i < items.length; i++) { arr.push(items[i]); @@ -42,7 +42,7 @@ export function flatten(list: any[], dst?: any[]): any[] { return dst; } -export function deepForEach<T>(input: (T | any[])[], fn: (value: T) => void): void { +export function deepForEach<T>(input: (T|any[])[], fn: (value: T) => void): void { input.forEach(value => Array.isArray(value) ? deepForEach(value, fn) : fn(value)); } @@ -69,7 +69,7 @@ export function newArray<T>(size: number, value: T): T[]; export function newArray<T>(size: number, value?: T): T[] { const list: T[] = []; for (let i = 0; i < size; i++) { - list.push(value !); + list.push(value!); } return list; } @@ -228,7 +228,9 @@ export function arrayIndexOfSorted(array: string[], value: string): number { * * See: `keyValueArraySet`, `keyValueArrayGet`, `keyValueArrayIndexOf`, `keyValueArrayDelete`. */ -export interface KeyValueArray<VALUE> extends Array<VALUE|string> { __brand__: 'array-map'; } +export interface KeyValueArray<VALUE> extends Array<VALUE|string> { + __brand__: 'array-map'; +} /** * Set a `value` for a `key`. @@ -253,7 +255,7 @@ export function keyValueArraySet<V>( /** * Retrieve a `value` for a `key` (on `undefined` if not found.) - * + * * @param keyValueArray to search. * @param key The key to locate. * @return The `value` stored at the `key` location or `undefined if not found. diff --git a/packages/core/src/util/char_code.ts b/packages/core/src/util/char_code.ts index 18a023dec43c4..5523acd44f558 100644 --- a/packages/core/src/util/char_code.ts +++ b/packages/core/src/util/char_code.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ /** * List ASCII char codes to be used with `String.charCodeAt` diff --git a/packages/core/src/util/decorators.ts b/packages/core/src/util/decorators.ts index 7ffb8fe56539d..757b6e81d6e90 100644 --- a/packages/core/src/util/decorators.ts +++ b/packages/core/src/util/decorators.ts @@ -52,7 +52,7 @@ export function makeDecorator<T>( const metaCtor = makeMetadataCtor(props); function DecoratorFactory( - this: unknown | typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any { + this: unknown|typeof DecoratorFactory, ...args: any[]): (cls: Type<T>) => any { if (this instanceof DecoratorFactory) { metaCtor.call(this, ...args); return this as typeof DecoratorFactory; @@ -101,7 +101,7 @@ export function makeParamDecorator( return noSideEffects(() => { const metaCtor = makeMetadataCtor(props); function ParamDecoratorFactory( - this: unknown | typeof ParamDecoratorFactory, ...args: any[]): any { + this: unknown|typeof ParamDecoratorFactory, ...args: any[]): any { if (this instanceof ParamDecoratorFactory) { metaCtor.apply(this, args); return this; @@ -143,8 +143,7 @@ export function makePropDecorator( return noSideEffects(() => { const metaCtor = makeMetadataCtor(props); - function PropDecoratorFactory( - this: unknown | typeof PropDecoratorFactory, ...args: any[]): any { + function PropDecoratorFactory(this: unknown|typeof PropDecoratorFactory, ...args: any[]): any { if (this instanceof PropDecoratorFactory) { metaCtor.apply(this, args); return this; diff --git a/packages/core/src/util/empty.ts b/packages/core/src/util/empty.ts index d30b12e7720a8..0db2000237238 100644 --- a/packages/core/src/util/empty.ts +++ b/packages/core/src/util/empty.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {initNgDevMode} from './ng_dev_mode'; /** diff --git a/packages/core/src/util/errors.ts b/packages/core/src/util/errors.ts index 7f895c4420573..6e0eb9d1247b2 100644 --- a/packages/core/src/util/errors.ts +++ b/packages/core/src/util/errors.ts @@ -13,8 +13,8 @@ export const ERROR_LOGGER = 'ngErrorLogger'; export function wrappedError(message: string, originalError: any): Error { - const msg = - `${message} caused by: ${originalError instanceof Error ? originalError.message: originalError }`; + const msg = `${message} caused by: ${ + originalError instanceof Error ? originalError.message : originalError}`; const error = Error(msg); (error as any)[ERROR_ORIGINAL_ERROR] = originalError; return error; diff --git a/packages/core/src/util/lang.ts b/packages/core/src/util/lang.ts index d69c39a1465ec..056a61b4cfb9a 100644 --- a/packages/core/src/util/lang.ts +++ b/packages/core/src/util/lang.ts @@ -20,7 +20,7 @@ export function isPromise<T = any>(obj: any): obj is Promise<T> { /** * Determine if the argument is an Observable */ -export function isObservable(obj: any | Observable<any>): obj is Observable<any> { +export function isObservable(obj: any|Observable<any>): obj is Observable<any> { // TODO: use isObservable once we update pass rxjs 6.1 // https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#610-2018-05-03 return !!obj && typeof obj.subscribe === 'function'; diff --git a/packages/core/src/util/microtask.ts b/packages/core/src/util/microtask.ts index fdc8a2b4f6443..4cda89fac18b8 100644 --- a/packages/core/src/util/microtask.ts +++ b/packages/core/src/util/microtask.ts @@ -13,7 +13,9 @@ declare const Zone: any; export function scheduleMicroTask(fn: Function) { if (typeof Zone === 'undefined') { // use promise to schedule microTask instead of use Zone - promise.then(() => { fn && fn.apply(null, null); }); + promise.then(() => { + fn && fn.apply(null, null); + }); } else { Zone.current.scheduleMicroTask('scheduleMicrotask', fn); } diff --git a/packages/core/src/util/stringify.ts b/packages/core/src/util/stringify.ts index 11c5f331f858a..519be71f5e2c3 100644 --- a/packages/core/src/util/stringify.ts +++ b/packages/core/src/util/stringify.ts @@ -45,7 +45,7 @@ export function stringify(token: any): string { * @param after after string. * @returns concatenated string. */ -export function concatStringsWithSpace(before: string | null, after: string | null): string { +export function concatStringsWithSpace(before: string|null, after: string|null): string { return (before == null || before === '') ? (after === null ? '' : after) : ((after == null || after === '') ? before : before + ' ' + after); diff --git a/packages/core/src/view/element.ts b/packages/core/src/view/element.ts index ed4b9f71c03d5..d31d5b43f41d3 100644 --- a/packages/core/src/view/element.ts +++ b/packages/core/src/view/element.ts @@ -10,12 +10,12 @@ import {ViewEncapsulation} from '../metadata/view'; import {RendererType2} from '../render/api'; import {SecurityContext} from '../sanitization/security'; -import {BindingDef, BindingFlags, ElementData, ElementHandleEventFn, NodeDef, NodeFlags, OutputDef, OutputType, QueryValueType, ViewData, ViewDefinitionFactory, asElementData} from './types'; -import {NOOP, calcBindingFlags, checkAndUpdateBinding, dispatchEvent, elementEventFullName, getParentRenderElement, resolveDefinition, resolveRendererType2, splitMatchedQueriesDsl, splitNamespace} from './util'; +import {asElementData, BindingDef, BindingFlags, ElementData, ElementHandleEventFn, NodeDef, NodeFlags, OutputDef, OutputType, QueryValueType, ViewData, ViewDefinitionFactory} from './types'; +import {calcBindingFlags, checkAndUpdateBinding, dispatchEvent, elementEventFullName, getParentRenderElement, NOOP, resolveDefinition, resolveRendererType2, splitMatchedQueriesDsl, splitNamespace} from './util'; export function anchorDef( - flags: NodeFlags, matchedQueriesDsl: null | [string | number, QueryValueType][], - ngContentIndex: null | number, childCount: number, handleEvent?: null | ElementHandleEventFn, + flags: NodeFlags, matchedQueriesDsl: null|[string | number, QueryValueType][], + ngContentIndex: null|number, childCount: number, handleEvent?: null|ElementHandleEventFn, templateFactory?: ViewDefinitionFactory): NodeDef { flags |= NodeFlags.TypeElement; const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl); @@ -33,14 +33,20 @@ export function anchorDef( checkIndex: -1, childFlags: 0, directChildFlags: 0, - childMatchedQueries: 0, matchedQueries, matchedQueryIds, references, ngContentIndex, childCount, + childMatchedQueries: 0, + matchedQueries, + matchedQueryIds, + references, + ngContentIndex, + childCount, bindings: [], bindingFlags: 0, outputs: [], element: { ns: null, name: null, - attrs: null, template, + attrs: null, + template, componentProvider: null, componentView: null, componentRendererType: null, @@ -57,18 +63,18 @@ export function anchorDef( export function elementDef( checkIndex: number, flags: NodeFlags, - matchedQueriesDsl: null | [string | number, QueryValueType][], ngContentIndex: null | number, - childCount: number, namespaceAndName: string | null, fixedAttrs: null | [string, string][] = [], - bindings?: null | [BindingFlags, string, string | SecurityContext | null][], - outputs?: null | ([string, string])[], handleEvent?: null | ElementHandleEventFn, - componentView?: null | ViewDefinitionFactory, - componentRendererType?: RendererType2 | null): NodeDef { + matchedQueriesDsl: null|[string | number, QueryValueType][], ngContentIndex: null|number, + childCount: number, namespaceAndName: string|null, fixedAttrs: null|[string, string][] = [], + bindings?: null|[BindingFlags, string, string | SecurityContext | null][], + outputs?: null|([string, string])[], handleEvent?: null|ElementHandleEventFn, + componentView?: null|ViewDefinitionFactory, + componentRendererType?: RendererType2|null): NodeDef { if (!handleEvent) { handleEvent = NOOP; } const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl); - let ns: string = null !; - let name: string = null !; + let ns: string = null!; + let name: string = null!; if (namespaceAndName) { [ns, name] = splitNamespace(namespaceAndName); } @@ -78,8 +84,8 @@ export function elementDef( const [bindingFlags, namespaceAndName, suffixOrSecurityContext] = bindings[i]; const [ns, name] = splitNamespace(namespaceAndName); - let securityContext: SecurityContext = undefined !; - let suffix: string = undefined !; + let securityContext: SecurityContext = undefined!; + let suffix: string = undefined!; switch (bindingFlags & BindingFlags.Types) { case BindingFlags.TypeElementStyle: suffix = <string>suffixOrSecurityContext; @@ -96,11 +102,8 @@ export function elementDef( const outputDefs: OutputDef[] = []; for (let i = 0; i < outputs.length; i++) { const [target, eventName] = outputs[i]; - outputDefs[i] = { - type: OutputType.ElementOutput, - target: <any>target, eventName, - propName: null - }; + outputDefs[i] = + {type: OutputType.ElementOutput, target: <any>target, eventName, propName: null}; } fixedAttrs = fixedAttrs || []; const attrs = <[string, string, string][]>fixedAttrs.map(([namespaceAndName, value]) => { @@ -124,7 +127,12 @@ export function elementDef( flags, childFlags: 0, directChildFlags: 0, - childMatchedQueries: 0, matchedQueries, matchedQueryIds, references, ngContentIndex, childCount, + childMatchedQueries: 0, + matchedQueries, + matchedQueryIds, + references, + ngContentIndex, + childCount, bindings: bindingDefs, bindingFlags: calcBindingFlags(bindingDefs), outputs: outputDefs, @@ -149,7 +157,7 @@ export function elementDef( } export function createElement(view: ViewData, renderHost: any, def: NodeDef): ElementData { - const elDef = def.element !; + const elDef = def.element!; const rootSelectorOrNode = view.root.selectorOrNode; const renderer = view.renderer; let el: any; @@ -192,7 +200,7 @@ export function listenToElementOutputs(view: ViewData, compView: ViewData, def: } const disposable = <any>listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure); - view.disposables ![def.outputIndex + i] = disposable; + view.disposables![def.outputIndex + i] = disposable; } } @@ -234,7 +242,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu const binding = def.bindings[bindingIdx]; const elData = asElementData(view, def.nodeIndex); const renderNode = elData.renderElement; - const name = binding.name !; + const name = binding.name!; switch (binding.flags & BindingFlags.Types) { case BindingFlags.TypeElementAttribute: setElementAttribute(view, binding, renderNode, binding.ns, name, value); @@ -257,7 +265,7 @@ function checkAndUpdateElementValue(view: ViewData, def: NodeDef, bindingIdx: nu } function setElementAttribute( - view: ViewData, binding: BindingDef, renderNode: any, ns: string | null, name: string, + view: ViewData, binding: BindingDef, renderNode: any, ns: string|null, name: string, value: any) { const securityContext = binding.securityContext; let renderValue = securityContext ? view.root.sanitizer.sanitize(securityContext, value) : value; @@ -282,7 +290,7 @@ function setElementClass(view: ViewData, renderNode: any, name: string, value: b function setElementStyle( view: ViewData, binding: BindingDef, renderNode: any, name: string, value: any) { let renderValue: string|null = - view.root.sanitizer.sanitize(SecurityContext.STYLE, value as{} | string); + view.root.sanitizer.sanitize(SecurityContext.STYLE, value as {} | string); if (renderValue != null) { renderValue = renderValue.toString(); const unit = binding.suffix; diff --git a/packages/core/src/view/entrypoint.ts b/packages/core/src/view/entrypoint.ts index ae1cb7004eb7d..db14d4d7f1e86 100644 --- a/packages/core/src/view/entrypoint.ts +++ b/packages/core/src/view/entrypoint.ts @@ -48,7 +48,10 @@ function cloneNgModuleDefinition(def: NgModuleDefinition): NgModuleDefinition { return { factory: def.factory, - scope: def.scope, providers, modules, providersByKey, + scope: def.scope, + providers, + modules, + providersByKey, }; } diff --git a/packages/core/src/view/errors.ts b/packages/core/src/view/errors.ts index d7ded67a01add..1e78713982eeb 100644 --- a/packages/core/src/view/errors.ts +++ b/packages/core/src/view/errors.ts @@ -14,7 +14,8 @@ import {DebugContext} from './types'; export function expressionChangedAfterItHasBeenCheckedError( context: DebugContext, oldValue: any, currValue: any, isFirstCheck: boolean): Error { let msg = - `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '${oldValue}'. Current value: '${currValue}'.`; + `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: '${ + oldValue}'. Current value: '${currValue}'.`; if (isFirstCheck) { msg += ` It seems like the view has been created after its parent and its children have been dirty checked.` + diff --git a/packages/core/src/view/index.ts b/packages/core/src/view/index.ts index 28b0947d26ab6..563f307784083 100644 --- a/packages/core/src/view/index.ts +++ b/packages/core/src/view/index.ts @@ -13,10 +13,10 @@ export {moduleDef, moduleProvideDef} from './ng_module'; export {directiveDef, pipeDef, providerDef} from './provider'; export {pureArrayDef, pureObjectDef, purePipeDef} from './pure_expression'; export {queryDef} from './query'; -export {ViewRef_, createComponentFactory, getComponentViewDefinitionFactory, nodeValue} from './refs'; +export {createComponentFactory, getComponentViewDefinitionFactory, nodeValue, ViewRef_} from './refs'; export {initServicesIfNeeded} from './services'; export {textDef} from './text'; -export {EMPTY_ARRAY, EMPTY_MAP, createRendererType2, elementEventFullName, inlineInterpolate, interpolate, rootRenderNodes, tokenKey, unwrapValue} from './util'; +export {createRendererType2, elementEventFullName, EMPTY_ARRAY, EMPTY_MAP, inlineInterpolate, interpolate, rootRenderNodes, tokenKey, unwrapValue} from './util'; export {viewDef} from './view'; export {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView} from './view_attach'; diff --git a/packages/core/src/view/ng_content.ts b/packages/core/src/view/ng_content.ts index fd7ce7e9fcedc..a566c8f25a40a 100644 --- a/packages/core/src/view/ng_content.ts +++ b/packages/core/src/view/ng_content.ts @@ -7,9 +7,9 @@ */ import {NodeDef, NodeFlags, ViewData} from './types'; -import {RenderNodeAction, getParentRenderElement, visitProjectedRenderNodes} from './util'; +import {getParentRenderElement, RenderNodeAction, visitProjectedRenderNodes} from './util'; -export function ngContentDef(ngContentIndex: null | number, index: number): NodeDef { +export function ngContentDef(ngContentIndex: null|number, index: number): NodeDef { return { // will bet set by the view definition nodeIndex: -1, @@ -25,7 +25,8 @@ export function ngContentDef(ngContentIndex: null | number, index: number): Node childMatchedQueries: 0, matchedQueries: {}, matchedQueryIds: 0, - references: {}, ngContentIndex, + references: {}, + ngContentIndex, childCount: 0, bindings: [], bindingFlags: 0, @@ -44,7 +45,7 @@ export function appendNgContent(view: ViewData, renderHost: any, def: NodeDef) { // Nothing to do if there is no parent element. return; } - const ngContentIndex = def.ngContent !.index; + const ngContentIndex = def.ngContent!.index; visitProjectedRenderNodes( view, ngContentIndex, RenderNodeAction.AppendChild, parentEl, null, undefined); } diff --git a/packages/core/src/view/ng_module.ts b/packages/core/src/view/ng_module.ts index 4700396465509..cc44b4b1ea476 100644 --- a/packages/core/src/view/ng_module.ts +++ b/packages/core/src/view/ng_module.ts @@ -25,8 +25,7 @@ const INJECTORRefTokenKey = tokenKey(INJECTOR); const NgModuleRefTokenKey = tokenKey(NgModuleRef); export function moduleProvideDef( - flags: NodeFlags, token: any, value: any, - deps: ([DepFlags, any] | any)[]): NgModuleProviderDef { + flags: NodeFlags, token: any, value: any, deps: ([DepFlags, any]|any)[]): NgModuleProviderDef { // Need to resolve forwardRefs as e.g. for `useValue` we // lowered the expression and then stopped evaluating it, // i.e. also didn't unwrap it. @@ -35,7 +34,10 @@ export function moduleProvideDef( return { // will bet set by the module definition index: -1, - deps: depDefs, flags, token, value + deps: depDefs, + flags, + token, + value }; } @@ -113,7 +115,8 @@ export function resolveNgModuleDep( data._def.providers[index] = data._def.providersByKey[depDef.tokenKey] = { flags: NodeFlags.TypeFactoryProvider | NodeFlags.LazyProvider, value: injectableDef.factory, - deps: [], index, + deps: [], + index, token: depDef.token, }; data._providers[index] = UNDEFINED_VALUE; @@ -135,8 +138,9 @@ function moduleTransitivelyPresent(ngModule: NgModuleData, scope: any): boolean function targetsModule(ngModule: NgModuleData, def: ɵɵInjectableDef<any>): boolean { const providedIn = def.providedIn; - return providedIn != null && (providedIn === 'any' || providedIn === ngModule._def.scope || - moduleTransitivelyPresent(ngModule, providedIn)); + return providedIn != null && + (providedIn === 'any' || providedIn === ngModule._def.scope || + moduleTransitivelyPresent(ngModule, providedIn)); } function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModuleProviderDef): any { diff --git a/packages/core/src/view/provider.ts b/packages/core/src/view/provider.ts index f8421a03bc821..338af6969ef72 100644 --- a/packages/core/src/view/provider.ts +++ b/packages/core/src/view/provider.ts @@ -16,7 +16,7 @@ import {isObservable} from '../util/lang'; import {stringify} from '../util/stringify'; import {createChangeDetectorRef, createInjector} from './refs'; -import {BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, ViewData, ViewFlags, ViewState, asElementData, asProviderData, shouldCallLifecycleInitHook} from './types'; +import {asElementData, asProviderData, BindingDef, BindingFlags, DepDef, DepFlags, NodeDef, NodeFlags, OutputDef, OutputType, ProviderData, QueryValueType, Services, shouldCallLifecycleInitHook, ViewData, ViewFlags, ViewState} from './types'; import {calcBindingFlags, checkBinding, dispatchEvent, isComponentView, splitDepsDsl, splitMatchedQueriesDsl, tokenKey, viewParentEl} from './util'; const Renderer2TokenKey = tokenKey(Renderer2); @@ -28,17 +28,18 @@ const InjectorRefTokenKey = tokenKey(Injector); const INJECTORRefTokenKey = tokenKey(INJECTOR); export function directiveDef( - checkIndex: number, flags: NodeFlags, - matchedQueries: null | [string | number, QueryValueType][], childCount: number, ctor: any, - deps: ([DepFlags, any] | any)[], props?: null | {[name: string]: [number, string]}, - outputs?: null | {[name: string]: string}): NodeDef { + checkIndex: number, flags: NodeFlags, matchedQueries: null|[string | number, QueryValueType][], + childCount: number, ctor: any, deps: ([DepFlags, any]|any)[], + props?: null|{[name: string]: [number, string]}, + outputs?: null|{[name: string]: string}): NodeDef { const bindings: BindingDef[] = []; if (props) { for (let prop in props) { const [bindingIndex, nonMinifiedName] = props[prop]; bindings[bindingIndex] = { flags: BindingFlags.TypeProperty, - name: prop, nonMinifiedName, + name: prop, + nonMinifiedName, ns: null, securityContext: null, suffix: null @@ -57,22 +58,21 @@ export function directiveDef( checkIndex, flags, matchedQueries, childCount, ctor, ctor, deps, bindings, outputDefs); } -export function pipeDef(flags: NodeFlags, ctor: any, deps: ([DepFlags, any] | any)[]): NodeDef { +export function pipeDef(flags: NodeFlags, ctor: any, deps: ([DepFlags, any]|any)[]): NodeDef { flags |= NodeFlags.TypePipe; return _def(-1, flags, null, 0, ctor, ctor, deps); } export function providerDef( - flags: NodeFlags, matchedQueries: null | [string | number, QueryValueType][], token: any, - value: any, deps: ([DepFlags, any] | any)[]): NodeDef { + flags: NodeFlags, matchedQueries: null|[string | number, QueryValueType][], token: any, + value: any, deps: ([DepFlags, any]|any)[]): NodeDef { return _def(-1, flags, matchedQueries, 0, token, value, deps); } export function _def( - checkIndex: number, flags: NodeFlags, - matchedQueriesDsl: [string | number, QueryValueType][] | null, childCount: number, token: any, - value: any, deps: ([DepFlags, any] | any)[], bindings?: BindingDef[], - outputs?: OutputDef[]): NodeDef { + checkIndex: number, flags: NodeFlags, matchedQueriesDsl: [string|number, QueryValueType][]|null, + childCount: number, token: any, value: any, deps: ([DepFlags, any]|any)[], + bindings?: BindingDef[], outputs?: OutputDef[]): NodeDef { const {matchedQueries, references, matchedQueryIds} = splitMatchedQueriesDsl(matchedQueriesDsl); if (!outputs) { outputs = []; @@ -99,9 +99,15 @@ export function _def( flags, childFlags: 0, directChildFlags: 0, - childMatchedQueries: 0, matchedQueries, matchedQueryIds, references, - ngContentIndex: -1, childCount, bindings, - bindingFlags: calcBindingFlags(bindings), outputs, + childMatchedQueries: 0, + matchedQueries, + matchedQueryIds, + references, + ngContentIndex: -1, + childCount, + bindings, + bindingFlags: calcBindingFlags(bindings), + outputs, element: null, provider: {token, value, deps: depDefs}, text: null, @@ -124,24 +130,24 @@ export function createPipeInstance(view: ViewData, def: NodeDef): any { const allowPrivateServices = true; // pipes are always eager and classes! return createClass( - compView.parent !, viewParentEl(compView) !, allowPrivateServices, def.provider !.value, - def.provider !.deps); + compView.parent!, viewParentEl(compView)!, allowPrivateServices, def.provider!.value, + def.provider!.deps); } export function createDirectiveInstance(view: ViewData, def: NodeDef): any { // components can see other private services, other directives can't. const allowPrivateServices = (def.flags & NodeFlags.Component) > 0; // directives are always eager and classes! - const instance = createClass( - view, def.parent !, allowPrivateServices, def.provider !.value, def.provider !.deps); + const instance = + createClass(view, def.parent!, allowPrivateServices, def.provider!.value, def.provider!.deps); if (def.outputs.length) { for (let i = 0; i < def.outputs.length; i++) { const output = def.outputs[i]; - const outputObservable = instance[output.propName !]; + const outputObservable = instance[output.propName!]; if (isObservable(outputObservable)) { const subscription = outputObservable.subscribe( - eventHandlerClosure(view, def.parent !.nodeIndex, output.eventName)); - view.disposables ![def.outputIndex + i] = subscription.unsubscribe.bind(subscription); + eventHandlerClosure(view, def.parent!.nodeIndex, output.eventName)); + view.disposables![def.outputIndex + i] = subscription.unsubscribe.bind(subscription); } else { throw new Error( `@Output ${output.propName} not initialized in '${instance.constructor.name}'.`); @@ -161,7 +167,7 @@ export function checkAndUpdateDirectiveInline( const providerData = asProviderData(view, def.nodeIndex); const directive = providerData.instance; let changed = false; - let changes: SimpleChanges = undefined !; + let changes: SimpleChanges = undefined!; const bindLen = def.bindings.length; if (bindLen > 0 && checkBinding(view, def, 0, v0)) { changed = true; @@ -221,7 +227,7 @@ export function checkAndUpdateDirectiveDynamic( const providerData = asProviderData(view, def.nodeIndex); const directive = providerData.instance; let changed = false; - let changes: SimpleChanges = undefined !; + let changes: SimpleChanges = undefined!; for (let i = 0; i < values.length; i++) { if (checkBinding(view, def, i, values[i])) { changed = true; @@ -248,14 +254,14 @@ function _createProviderInstance(view: ViewData, def: NodeDef): any { switch (def.flags & NodeFlags.Types) { case NodeFlags.TypeClassProvider: return createClass( - view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps); + view, def.parent!, allowPrivateServices, providerDef!.value, providerDef!.deps); case NodeFlags.TypeFactoryProvider: return callFactory( - view, def.parent !, allowPrivateServices, providerDef !.value, providerDef !.deps); + view, def.parent!, allowPrivateServices, providerDef!.value, providerDef!.deps); case NodeFlags.TypeUseExistingProvider: - return resolveDep(view, def.parent !, allowPrivateServices, providerDef !.deps[0]); + return resolveDep(view, def.parent!, allowPrivateServices, providerDef!.deps[0]); case NodeFlags.TypeValueProvider: - return providerDef !.value; + return providerDef!.value; } } @@ -346,12 +352,12 @@ export function resolveDep( if (tokenKey === ChangeDetectorRefTokenKey) { // directives on the same element as a component should be able to control the change detector // of that component as well. - allowPrivateServices = !!(elDef && elDef.element !.componentView); + allowPrivateServices = !!(elDef && elDef.element!.componentView); } if (elDef && (depDef.flags & DepFlags.SkipSelf)) { allowPrivateServices = false; - elDef = elDef.parent !; + elDef = elDef.parent!; } let searchView: ViewData|null = view; @@ -367,7 +373,7 @@ export function resolveDep( case ViewContainerRefTokenKey: return asElementData(searchView, elDef.nodeIndex).viewContainer; case TemplateRefTokenKey: { - if (elDef.element !.template) { + if (elDef.element!.template) { return asElementData(searchView, elDef.nodeIndex).template; } break; @@ -381,8 +387,8 @@ export function resolveDep( return createInjector(searchView, elDef); default: const providerDef = - (allowPrivateServices ? elDef.element !.allProviders : - elDef.element !.publicProviders) ![tokenKey]; + (allowPrivateServices ? elDef.element!.allProviders : + elDef.element!.publicProviders)![tokenKey]; if (providerDef) { let providerData = asProviderData(searchView, providerDef.nodeIndex); if (!providerData) { @@ -395,8 +401,8 @@ export function resolveDep( } allowPrivateServices = isComponentView(searchView); - elDef = viewParentEl(searchView) !; - searchView = searchView.parent !; + elDef = viewParentEl(searchView)!; + searchView = searchView.parent!; if (depDef.flags & DepFlags.Self) { searchView = null; @@ -435,13 +441,13 @@ function updateProp( view: ViewData, providerData: ProviderData, def: NodeDef, bindingIdx: number, value: any, changes: SimpleChanges): SimpleChanges { if (def.flags & NodeFlags.Component) { - const compView = asElementData(view, def.parent !.nodeIndex).componentView; + const compView = asElementData(view, def.parent!.nodeIndex).componentView; if (compView.def.flags & ViewFlags.OnPush) { compView.state |= ViewState.ChecksEnabled; } } const binding = def.bindings[bindingIdx]; - const propName = binding.name !; + const propName = binding.name!; // Note: This is still safe with Closure Compiler as // the user passed in the property name as an object has to `providerDef`, // so Closure Compiler will have renamed the property correctly already. @@ -450,7 +456,7 @@ function updateProp( changes = changes || {}; const oldValue = WrappedValue.unwrap(view.oldValues[def.bindingIndex + bindingIdx]); const binding = def.bindings[bindingIdx]; - changes[binding.nonMinifiedName !] = + changes[binding.nonMinifiedName!] = new SimpleChange(oldValue, value, (view.state & ViewState.FirstCheck) !== 0); } view.oldValues[def.bindingIndex + bindingIdx] = value; diff --git a/packages/core/src/view/pure_expression.ts b/packages/core/src/view/pure_expression.ts index 1cbcae3558d16..c8b300913a639 100644 --- a/packages/core/src/view/pure_expression.ts +++ b/packages/core/src/view/pure_expression.ts @@ -8,7 +8,7 @@ import {newArray} from '../util/array_utils'; -import {BindingDef, BindingFlags, NodeDef, NodeFlags, PureExpressionData, ViewData, asPureExpressionData} from './types'; +import {asPureExpressionData, BindingDef, BindingFlags, NodeDef, NodeFlags, PureExpressionData, ViewData} from './types'; import {calcBindingFlags, checkAndUpdateBinding} from './util'; export function purePipeDef(checkIndex: number, argCount: number): NodeDef { @@ -64,7 +64,8 @@ function _pureExpressionDef( matchedQueryIds: 0, references: {}, ngContentIndex: -1, - childCount: 0, bindings, + childCount: 0, + bindings, bindingFlags: calcBindingFlags(bindings), outputs: [], element: null, @@ -115,16 +116,16 @@ export function checkAndUpdatePureExpressionInline( break; case NodeFlags.TypePureObject: value = {}; - if (bindLen > 0) value[bindings[0].name !] = v0; - if (bindLen > 1) value[bindings[1].name !] = v1; - if (bindLen > 2) value[bindings[2].name !] = v2; - if (bindLen > 3) value[bindings[3].name !] = v3; - if (bindLen > 4) value[bindings[4].name !] = v4; - if (bindLen > 5) value[bindings[5].name !] = v5; - if (bindLen > 6) value[bindings[6].name !] = v6; - if (bindLen > 7) value[bindings[7].name !] = v7; - if (bindLen > 8) value[bindings[8].name !] = v8; - if (bindLen > 9) value[bindings[9].name !] = v9; + if (bindLen > 0) value[bindings[0].name!] = v0; + if (bindLen > 1) value[bindings[1].name!] = v1; + if (bindLen > 2) value[bindings[2].name!] = v2; + if (bindLen > 3) value[bindings[3].name!] = v3; + if (bindLen > 4) value[bindings[4].name!] = v4; + if (bindLen > 5) value[bindings[5].name!] = v5; + if (bindLen > 6) value[bindings[6].name!] = v6; + if (bindLen > 7) value[bindings[7].name!] = v7; + if (bindLen > 8) value[bindings[8].name!] = v8; + if (bindLen > 9) value[bindings[9].name!] = v9; break; case NodeFlags.TypePurePipe: const pipe = v0; @@ -188,7 +189,7 @@ export function checkAndUpdatePureExpressionDynamic( case NodeFlags.TypePureObject: value = {}; for (let i = 0; i < values.length; i++) { - value[bindings[i].name !] = values[i]; + value[bindings[i].name!] = values[i]; } break; case NodeFlags.TypePurePipe: diff --git a/packages/core/src/view/query.ts b/packages/core/src/view/query.ts index 9e734b4be33d8..d462885d56994 100644 --- a/packages/core/src/view/query.ts +++ b/packages/core/src/view/query.ts @@ -9,7 +9,7 @@ import {ElementRef} from '../linker/element_ref'; import {QueryList} from '../linker/query_list'; -import {NodeDef, NodeFlags, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, ViewData, asElementData, asProviderData, asQueryList} from './types'; +import {asElementData, asProviderData, asQueryList, NodeDef, NodeFlags, QueryBindingDef, QueryBindingType, QueryDef, QueryValueType, ViewData} from './types'; import {declaredViewContainer, filterQueryId, isEmbeddedView} from './util'; export function queryDef( @@ -29,7 +29,8 @@ export function queryDef( outputIndex: -1, // regular values // TODO(vicb): check - checkIndex: -1, flags, + checkIndex: -1, + flags, childFlags: 0, directChildFlags: 0, childMatchedQueries: 0, @@ -56,7 +57,7 @@ export function createQuery(): QueryList<any> { export function dirtyParentQueries(view: ViewData) { const queryIds = view.def.nodeMatchedQueries; while (view.parent && isEmbeddedView(view)) { - let tplDef = view.parentNodeDef !; + let tplDef = view.parentNodeDef!; view = view.parent; // content queries const end = tplDef.nodeIndex + tplDef.childCount; @@ -64,7 +65,7 @@ export function dirtyParentQueries(view: ViewData) { const nodeDef = view.def.nodes[i]; if ((nodeDef.flags & NodeFlags.TypeContentQuery) && (nodeDef.flags & NodeFlags.DynamicQuery) && - (nodeDef.query !.filterId & queryIds) === nodeDef.query !.filterId) { + (nodeDef.query!.filterId & queryIds) === nodeDef.query!.filterId) { asQueryList(view, i).setDirty(); } if ((nodeDef.flags & NodeFlags.TypeElement && i + nodeDef.childCount < tplDef.nodeIndex) || @@ -95,19 +96,19 @@ export function checkAndUpdateQuery(view: ViewData, nodeDef: NodeDef) { return; } let directiveInstance: any; - let newValues: any[] = undefined !; + let newValues: any[] = undefined!; if (nodeDef.flags & NodeFlags.TypeContentQuery) { - const elementDef = nodeDef.parent !.parent !; + const elementDef = nodeDef.parent!.parent!; newValues = calcQueryValues( - view, elementDef.nodeIndex, elementDef.nodeIndex + elementDef.childCount, nodeDef.query !, + view, elementDef.nodeIndex, elementDef.nodeIndex + elementDef.childCount, nodeDef.query!, []); - directiveInstance = asProviderData(view, nodeDef.parent !.nodeIndex).instance; + directiveInstance = asProviderData(view, nodeDef.parent!.nodeIndex).instance; } else if (nodeDef.flags & NodeFlags.TypeViewQuery) { - newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query !, []); + newValues = calcQueryValues(view, 0, view.def.nodes.length - 1, nodeDef.query!, []); directiveInstance = view.component; } queryList.reset(newValues); - const bindings = nodeDef.query !.bindings; + const bindings = nodeDef.query!.bindings; let notify = false; for (let i = 0; i < bindings.length; i++) { const binding = bindings[i]; @@ -137,8 +138,8 @@ function calcQueryValues( if (valueType != null) { values.push(getQueryValue(view, nodeDef, valueType)); } - if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element !.template && - (nodeDef.element !.template !.nodeMatchedQueries & queryDef.filterId) === + if (nodeDef.flags & NodeFlags.TypeElement && nodeDef.element!.template && + (nodeDef.element!.template !.nodeMatchedQueries & queryDef.filterId) === queryDef.filterId) { const elementData = asElementData(view, i); // check embedded views that were attached at the place of their template, @@ -148,7 +149,7 @@ function calcQueryValues( i += nodeDef.childCount; } if (nodeDef.flags & NodeFlags.EmbeddedViews) { - const embeddedViews = elementData.viewContainer !._embeddedViews; + const embeddedViews = elementData.viewContainer!._embeddedViews; for (let k = 0; k < embeddedViews.length; k++) { const embeddedView = embeddedViews[k]; const dvc = declaredViewContainer(embeddedView); diff --git a/packages/core/src/view/refs.ts b/packages/core/src/view/refs.ts index 4fe9a5d731fff..36fe5cfa8616e 100644 --- a/packages/core/src/view/refs.ts +++ b/packages/core/src/view/refs.ts @@ -22,7 +22,7 @@ import {stringify} from '../util/stringify'; import {VERSION} from '../version'; import {callNgModuleLifecycle, initNgModule, resolveNgModuleDep} from './ng_module'; -import {DepFlags, ElementData, NgModuleData, NgModuleDefinition, NodeDef, NodeFlags, Services, TemplateData, ViewContainerData, ViewData, ViewDefinitionFactory, ViewState, asElementData, asProviderData, asTextData} from './types'; +import {asElementData, asProviderData, asTextData, DepFlags, ElementData, NgModuleData, NgModuleDefinition, NodeDef, NodeFlags, Services, TemplateData, ViewContainerData, ViewData, ViewDefinitionFactory, ViewState} from './types'; import {markParentViewsForCheck, resolveDefinition, rootRenderNodes, splitNamespace, tokenKey, viewParentEl} from './util'; import {attachEmbeddedView, detachEmbeddedView, moveEmbeddedView, renderDetachView} from './view_attach'; @@ -32,7 +32,7 @@ const EMPTY_CONTEXT = {}; // Putting any logic in here will destroy closure tree shaking! export function createComponentFactory( selector: string, componentType: Type<any>, viewDefFactory: ViewDefinitionFactory, - inputs: {[propName: string]: string} | null, outputs: {[propName: string]: string}, + inputs: {[propName: string]: string}|null, outputs: {[propName: string]: string}, ngContentSelectors: string[]): ComponentFactory<any> { return new ComponentFactory_( selector, componentType, viewDefFactory, inputs, outputs, ngContentSelectors); @@ -61,7 +61,7 @@ class ComponentFactory_ extends ComponentFactory<any> { get inputs() { const inputsArr: {propName: string, templateName: string}[] = []; - const inputs = this._inputs !; + const inputs = this._inputs!; for (let propName in inputs) { const templateName = inputs[propName]; inputsArr.push({propName, templateName}); @@ -88,7 +88,7 @@ class ComponentFactory_ extends ComponentFactory<any> { throw new Error('ngModule should be provided'); } const viewDef = resolveDefinition(this.viewDefFactory); - const componentNodeIndex = viewDef.nodes[0].element !.componentProvider !.nodeIndex; + const componentNodeIndex = viewDef.nodes[0].element!.componentProvider!.nodeIndex; const view = Services.createRootView( injector, projectableNodes || [], rootSelectorOrNode, viewDef, ngModule, EMPTY_CONTEXT); const component = asProviderData(view, componentNodeIndex).instance; @@ -115,11 +115,19 @@ class ComponentRef_ extends ComponentRef<any> { get location(): ElementRef { return new ElementRef(asElementData(this._view, this._elDef.nodeIndex).renderElement); } - get injector(): Injector { return new Injector_(this._view, this._elDef); } - get componentType(): Type<any> { return <any>this._component.constructor; } + get injector(): Injector { + return new Injector_(this._view, this._elDef); + } + get componentType(): Type<any> { + return <any>this._component.constructor; + } - destroy(): void { this._viewRef.destroy(); } - onDestroy(callback: Function): void { this._viewRef.onDestroy(callback); } + destroy(): void { + this._viewRef.destroy(); + } + onDestroy(callback: Function): void { + this._viewRef.onDestroy(callback); + } } export function createViewContainerData( @@ -134,9 +142,13 @@ class ViewContainerRef_ implements ViewContainerData { _embeddedViews: ViewData[] = []; constructor(private _view: ViewData, private _elDef: NodeDef, private _data: ElementData) {} - get element(): ElementRef { return new ElementRef(this._data.renderElement); } + get element(): ElementRef { + return new ElementRef(this._data.renderElement); + } - get injector(): Injector { return new Injector_(this._view, this._elDef); } + get injector(): Injector { + return new Injector_(this._view, this._elDef); + } /** @deprecated No replacement */ get parentInjector(): Injector { @@ -144,7 +156,7 @@ class ViewContainerRef_ implements ViewContainerData { let elDef = this._elDef.parent; while (!elDef && view) { elDef = viewParentEl(view); - view = view.parent !; + view = view.parent!; } return view ? new Injector_(view, elDef) : new Injector_(this._view, null); @@ -153,7 +165,7 @@ class ViewContainerRef_ implements ViewContainerData { clear(): void { const len = this._embeddedViews.length; for (let i = len - 1; i >= 0; i--) { - const view = detachEmbeddedView(this._data, i) !; + const view = detachEmbeddedView(this._data, i)!; Services.destroyView(view); } } @@ -168,7 +180,9 @@ class ViewContainerRef_ implements ViewContainerData { return null; } - get length(): number { return this._embeddedViews.length; } + get length(): number { + return this._embeddedViews.length; + } createEmbeddedView<C>(templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C> { @@ -243,14 +257,24 @@ export class ViewRef_ implements EmbeddedViewRef<any>, InternalViewRef { this._appRef = null; } - get rootNodes(): any[] { return rootRenderNodes(this._view); } + get rootNodes(): any[] { + return rootRenderNodes(this._view); + } - get context() { return this._view.context; } + get context() { + return this._view.context; + } - get destroyed(): boolean { return (this._view.state & ViewState.Destroyed) !== 0; } + get destroyed(): boolean { + return (this._view.state & ViewState.Destroyed) !== 0; + } - markForCheck(): void { markParentViewsForCheck(this._view); } - detach(): void { this._view.state &= ~ViewState.Attached; } + markForCheck(): void { + markParentViewsForCheck(this._view); + } + detach(): void { + this._view.state &= ~ViewState.Attached; + } detectChanges(): void { const fs = this._view.root.rendererFactory; if (fs.begin) { @@ -264,9 +288,13 @@ export class ViewRef_ implements EmbeddedViewRef<any>, InternalViewRef { } } } - checkNoChanges(): void { Services.checkNoChangesView(this._view); } + checkNoChanges(): void { + Services.checkNoChangesView(this._view); + } - reattach(): void { this._view.state |= ViewState.Attached; } + reattach(): void { + this._view.state |= ViewState.Attached; + } onDestroy(callback: Function) { if (!this._view.disposables) { this._view.disposables = []; @@ -313,13 +341,15 @@ class TemplateRef_ extends TemplateRef<any> implements TemplateData { * @internal */ // TODO(issue/24571): remove '!'. - _projectedViews !: ViewData[]; + _projectedViews!: ViewData[]; - constructor(private _parentView: ViewData, private _def: NodeDef) { super(); } + constructor(private _parentView: ViewData, private _def: NodeDef) { + super(); + } createEmbeddedView(context: any): EmbeddedViewRef<any> { return new ViewRef_(Services.createEmbeddedView( - this._parentView, this._def, this._def.element !.template !, context)); + this._parentView, this._def, this._def.element!.template !, context)); } get elementRef(): ElementRef { @@ -346,7 +376,7 @@ export function nodeValue(view: ViewData, index: number): any { const def = view.def.nodes[index]; if (def.flags & NodeFlags.TypeElement) { const elData = asElementData(view, def.nodeIndex); - return def.element !.template ? elData.template : elData.renderElement; + return def.element!.template ? elData.template : elData.renderElement; } else if (def.flags & NodeFlags.TypeText) { return asTextData(view, def.nodeIndex).renderText; } else if (def.flags & (NodeFlags.CatProvider | NodeFlags.TypePipe)) { @@ -366,10 +396,10 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> { private _destroyed: boolean = false; /** @internal */ // TODO(issue/24571): remove '!'. - _providers !: any[]; + _providers!: any[]; /** @internal */ // TODO(issue/24571): remove '!'. - _modules !: any[]; + _modules!: any[]; readonly injector: Injector = this; @@ -391,9 +421,13 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> { this, {token: token, tokenKey: tokenKey(token), flags: flags}, notFoundValue); } - get instance() { return this.get(this._moduleType); } + get instance() { + return this.get(this._moduleType); + } - get componentFactoryResolver() { return this.get(ComponentFactoryResolver); } + get componentFactoryResolver() { + return this.get(ComponentFactoryResolver); + } destroy(): void { if (this._destroyed) { @@ -405,5 +439,7 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> { this._destroyListeners.forEach((listener) => listener()); } - onDestroy(callback: () => void): void { this._destroyListeners.push(callback); } + onDestroy(callback: () => void): void { + this._destroyListeners.push(callback); + } } diff --git a/packages/core/src/view/services.ts b/packages/core/src/view/services.ts index 82caa09c75a4c..97b9f2bf9208d 100644 --- a/packages/core/src/view/services.ts +++ b/packages/core/src/view/services.ts @@ -8,7 +8,7 @@ import {DebugElement__PRE_R3__, DebugEventListener, DebugNode__PRE_R3__, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node'; import {Injector} from '../di'; -import {InjectableType, getInjectableDef, ɵɵInjectableDef} from '../di/interface/defs'; +import {getInjectableDef, InjectableType, ɵɵInjectableDef} from '../di/interface/defs'; import {ErrorHandler} from '../error_handler'; import {Type} from '../interface/type'; import {ComponentFactory} from '../linker/component_factory'; @@ -22,8 +22,8 @@ import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './err import {resolveDep} from './provider'; import {dirtyParentQueries, getQueryValue} from './query'; import {createInjector, createNgModuleRef, getComponentViewDefinitionFactory} from './refs'; -import {ArgumentType, BindingFlags, CheckType, DebugContext, ElementData, NgModuleDefinition, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState, asElementData, asPureExpressionData} from './types'; -import {NOOP, isComponentView, renderNode, resolveDefinition, splitDepsDsl, tokenKey, viewParentEl} from './util'; +import {ArgumentType, asElementData, asPureExpressionData, BindingFlags, CheckType, DebugContext, ElementData, NgModuleDefinition, NodeDef, NodeFlags, NodeLogger, ProviderOverride, RootData, Services, ViewData, ViewDefinition, ViewState} from './types'; +import {isComponentView, NOOP, renderNode, resolveDefinition, splitDepsDsl, tokenKey, viewParentEl} from './util'; import {checkAndUpdateNode, checkAndUpdateView, checkNoChangesNode, checkNoChangesView, createComponentView, createEmbeddedView, createRootView, destroyView} from './view'; @@ -69,15 +69,13 @@ function createProdServices() { destroyView: destroyView, createDebugContext: (view: ViewData, nodeIndex: number) => new DebugContext_(view, nodeIndex), handleEvent: (view: ViewData, nodeIndex: number, eventName: string, event: any) => - view.def.handleEvent(view, nodeIndex, eventName, event), + view.def.handleEvent(view, nodeIndex, eventName, event), updateDirectives: (view: ViewData, checkType: CheckType) => view.def.updateDirectives( - checkType === CheckType.CheckAndUpdate ? prodCheckAndUpdateNode : - prodCheckNoChangesNode, - view), + checkType === CheckType.CheckAndUpdate ? prodCheckAndUpdateNode : prodCheckNoChangesNode, + view), updateRenderer: (view: ViewData, checkType: CheckType) => view.def.updateRenderer( - checkType === CheckType.CheckAndUpdate ? prodCheckAndUpdateNode : - prodCheckNoChangesNode, - view), + checkType === CheckType.CheckAndUpdate ? prodCheckAndUpdateNode : prodCheckNoChangesNode, + view), }; } @@ -102,7 +100,7 @@ function createDebugServices() { } function createProdRootView( - elInjector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any, + elInjector: Injector, projectableNodes: any[][], rootSelectorOrNode: string|any, def: ViewDefinition, ngModule: NgModuleRef<any>, context?: any): ViewData { const rendererFactory: RendererFactory2 = ngModule.injector.get(RendererFactory2); return createRootView( @@ -111,7 +109,7 @@ function createProdRootView( } function debugCreateRootView( - elInjector: Injector, projectableNodes: any[][], rootSelectorOrNode: string | any, + elInjector: Injector, projectableNodes: any[][], rootSelectorOrNode: string|any, def: ViewDefinition, ngModule: NgModuleRef<any>, context?: any): ViewData { const rendererFactory: RendererFactory2 = ngModule.injector.get(RendererFactory2); const root = createRootData( @@ -130,8 +128,13 @@ function createRootData( const renderer = rendererFactory.createRenderer(null, null); return { ngModule, - injector: elInjector, projectableNodes, - selectorOrNode: rootSelectorOrNode, sanitizer, rendererFactory, renderer, errorHandler + injector: elInjector, + projectableNodes, + selectorOrNode: rootSelectorOrNode, + sanitizer, + rendererFactory, + renderer, + errorHandler }; } @@ -146,7 +149,7 @@ function debugCreateEmbeddedView( function debugCreateComponentView( parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData { const overrideComponentView = - viewDefOverrides.get(nodeDef.element !.componentProvider !.provider !.token); + viewDefOverrides.get(nodeDef.element!.componentProvider!.provider!.token); if (overrideComponentView) { viewDef = overrideComponentView; } else { @@ -178,7 +181,7 @@ function debugOverrideProvider(override: ProviderOverride) { function debugOverrideComponentView(comp: any, compFactory: ComponentFactory<any>) { const hostViewDef = resolveDefinition(getComponentViewDefinitionFactory(compFactory)); - const compViewDef = resolveDefinition(hostViewDef.nodes[0].element !.componentView !); + const compViewDef = resolveDefinition(hostViewDef.nodes[0].element!.componentView!); viewDefOverrides.set(comp, compViewDef); } @@ -204,7 +207,7 @@ function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition { } // clone the whole view definition, // as it maintains references between the nodes that are hard to update. - def = def.factory !(() => NOOP); + def = def.factory!(() => NOOP); for (let i = 0; i < elementIndicesWithOverwrittenProviders.length; i++) { applyProviderOverridesToElement(def, elementIndicesWithOverwrittenProviders[i]); } @@ -219,8 +222,8 @@ function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition { lastElementDef = nodeDef; } if (lastElementDef && nodeDef.flags & NodeFlags.CatProviderNoDirective && - providerOverrides.has(nodeDef.provider !.token)) { - elIndicesWithOverwrittenProviders.push(lastElementDef !.nodeIndex); + providerOverrides.has(nodeDef.provider!.token)) { + elIndicesWithOverwrittenProviders.push(lastElementDef!.nodeIndex); lastElementDef = null; } } @@ -235,7 +238,7 @@ function applyProviderOverridesToView(def: ViewDefinition): ViewDefinition { return; } if (nodeDef.flags & NodeFlags.CatProviderNoDirective) { - const provider = nodeDef.provider !; + const provider = nodeDef.provider!; const override = providerOverrides.get(provider.token); if (override) { nodeDef.flags = (nodeDef.flags & ~NodeFlags.CatProviderNoDirective) | override.flags; @@ -257,7 +260,7 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi } // clone the whole view definition, // as it maintains references between the nodes that are hard to update. - def = def.factory !(() => NOOP); + def = def.factory!(() => NOOP); applyProviderOverrides(def); return def; @@ -277,7 +280,7 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi }); def.modules.forEach(module => { providerOverridesWithScope.forEach((override, token) => { - if (getInjectableDef(token) !.providedIn === module) { + if (getInjectableDef(token)!.providedIn === module) { hasOverrides = true; hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior; } @@ -305,7 +308,7 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi if (providerOverridesWithScope.size > 0) { let moduleSet = new Set<any>(def.modules); providerOverridesWithScope.forEach((override, token) => { - if (moduleSet.has(getInjectableDef(token) !.providedIn)) { + if (moduleSet.has(getInjectableDef(token)!.providedIn)) { let provider = { token: token, flags: @@ -366,7 +369,7 @@ let _currentAction: DebugAction; let _currentView: ViewData; let _currentNodeIndex: number|null; -function debugSetCurrentNode(view: ViewData, nodeIndex: number | null) { +function debugSetCurrentNode(view: ViewData, nodeIndex: number|null) { _currentView = view; _currentNodeIndex = nodeIndex; } @@ -436,13 +439,13 @@ function debugCheckAndUpdateNode( const binding = nodeDef.bindings[i]; const value = values[i]; if (binding.flags & BindingFlags.TypeProperty) { - bindingValues[normalizeDebugBindingName(binding.nonMinifiedName !)] = + bindingValues[normalizeDebugBindingName(binding.nonMinifiedName!)] = normalizeDebugBindingValue(value); } } - const elDef = nodeDef.parent !; + const elDef = nodeDef.parent!; const el = asElementData(view, elDef.nodeIndex).renderElement; - if (!elDef.element !.name) { + if (!elDef.element!.name) { // a comment. view.renderer.setValue(el, `bindings=${JSON.stringify(bindingValues, null, 2)}`); } else { @@ -498,12 +501,12 @@ class DebugContext_ implements DebugContext { let elDef = this.nodeDef; let elView = view; while (elDef && (elDef.flags & NodeFlags.TypeElement) === 0) { - elDef = elDef.parent !; + elDef = elDef.parent!; } if (!elDef) { while (!elDef && elView) { - elDef = viewParentEl(elView) !; - elView = elView.parent !; + elDef = viewParentEl(elView)!; + elView = elView.parent!; } } this.elDef = elDef; @@ -515,11 +518,17 @@ class DebugContext_ implements DebugContext { return asElementData(this.elView, this.elDef.nodeIndex).componentView || this.view; } - get injector(): Injector { return createInjector(this.elView, this.elDef); } + get injector(): Injector { + return createInjector(this.elView, this.elDef); + } - get component(): any { return this.elOrCompView.component; } + get component(): any { + return this.elOrCompView.component; + } - get context(): any { return this.elOrCompView.context; } + get context(): any { + return this.elOrCompView.context; + } get providerTokens(): any[] { const tokens: any[] = []; @@ -528,7 +537,7 @@ class DebugContext_ implements DebugContext { i++) { const childDef = this.elView.def.nodes[i]; if (childDef.flags & NodeFlags.CatProvider) { - tokens.push(childDef.provider !.token); + tokens.push(childDef.provider!.token); } i += childDef.childCount; } @@ -585,7 +594,7 @@ class DebugContext_ implements DebugContext { return NOOP; } }; - logViewDef.factory !(nodeLogger); + logViewDef.factory!(nodeLogger); if (currRenderNodeIndex < renderNodeIndex) { console.error('Illegal state: the ViewDefinitionFactory did not call the logger!'); (<any>console.error)(...values); @@ -606,10 +615,10 @@ function getRenderNodeIndex(viewDef: ViewDefinition, nodeIndex: number): number function findHostElement(view: ViewData): ElementData|null { while (view && !isComponentView(view)) { - view = view.parent !; + view = view.parent!; } if (view.parent) { - return asElementData(view.parent, viewParentEl(view) !.nodeIndex); + return asElementData(view.parent, viewParentEl(view)!.nodeIndex); } return null; } @@ -635,7 +644,7 @@ function callWithDebugContext(action: DebugAction, fn: any, self: any, args: any if (isViewDebugError(e) || !_currentView) { throw e; } - throw viewWrappedDebugError(e, getCurrentDebugContext() !); + throw viewWrappedDebugError(e, getCurrentDebugContext()!); } } @@ -672,7 +681,9 @@ export class DebugRendererFactory2 implements RendererFactory2 { export class DebugRenderer2 implements Renderer2 { readonly data: {[key: string]: any}; - private createDebugContext(nativeElement: any) { return this.debugContextFactory(nativeElement); } + private createDebugContext(nativeElement: any) { + return this.debugContextFactory(nativeElement); + } /** * Factory function used to create a `DebugContext` when a node is created. @@ -684,10 +695,12 @@ export class DebugRenderer2 implements Renderer2 { */ debugContextFactory: (nativeElement?: any) => DebugContext | null = getCurrentDebugContext; - constructor(private delegate: Renderer2) { this.data = this.delegate.data; } + constructor(private delegate: Renderer2) { + this.data = this.delegate.data; + } destroyNode(node: any) { - const debugNode = getDebugNode(node) !; + const debugNode = getDebugNode(node)!; removeDebugNodeFromIndex(debugNode); if (debugNode instanceof DebugNode__PRE_R3__) { debugNode.listeners.length = 0; @@ -697,14 +710,16 @@ export class DebugRenderer2 implements Renderer2 { } } - destroy() { this.delegate.destroy(); } + destroy() { + this.delegate.destroy(); + } createElement(name: string, namespace?: string): any { const el = this.delegate.createElement(name, namespace); const debugCtx = this.createDebugContext(el); if (debugCtx) { const debugEl = new DebugElement__PRE_R3__(el, null, debugCtx); - (debugEl as{name: string}).name = name; + (debugEl as {name: string}).name = name; indexDebugNode(debugEl); } return el; @@ -740,7 +755,7 @@ export class DebugRenderer2 implements Renderer2 { insertBefore(parent: any, newChild: any, refChild: any): void { const debugEl = getDebugNode(parent); const debugChildEl = getDebugNode(newChild); - const debugRefEl = getDebugNode(refChild) !; + const debugRefEl = getDebugNode(refChild)!; if (debugEl && debugChildEl && debugEl instanceof DebugElement__PRE_R3__) { debugEl.insertBefore(debugRefEl, debugChildEl); } @@ -837,7 +852,13 @@ export class DebugRenderer2 implements Renderer2 { return this.delegate.listen(target, eventName, callback); } - parentNode(node: any): any { return this.delegate.parentNode(node); } - nextSibling(node: any): any { return this.delegate.nextSibling(node); } - setValue(node: any, value: string): void { return this.delegate.setValue(node, value); } + parentNode(node: any): any { + return this.delegate.parentNode(node); + } + nextSibling(node: any): any { + return this.delegate.nextSibling(node); + } + setValue(node: any, value: string): void { + return this.delegate.setValue(node, value); + } } diff --git a/packages/core/src/view/text.ts b/packages/core/src/view/text.ts index 7067d7fe43de2..51f31e25c7e83 100644 --- a/packages/core/src/view/text.ts +++ b/packages/core/src/view/text.ts @@ -6,11 +6,11 @@ * found in the LICENSE file at https://angular.io/license */ -import {BindingDef, BindingFlags, NodeDef, NodeFlags, TextData, ViewData, asTextData} from './types'; +import {asTextData, BindingDef, BindingFlags, NodeDef, NodeFlags, TextData, ViewData} from './types'; import {checkAndUpdateBinding, getParentRenderElement} from './util'; export function textDef( - checkIndex: number, ngContentIndex: number | null, staticText: string[]): NodeDef { + checkIndex: number, ngContentIndex: number|null, staticText: string[]): NodeDef { const bindings: BindingDef[] = []; for (let i = 1; i < staticText.length; i++) { bindings[i - 1] = { @@ -38,8 +38,10 @@ export function textDef( childMatchedQueries: 0, matchedQueries: {}, matchedQueryIds: 0, - references: {}, ngContentIndex, - childCount: 0, bindings, + references: {}, + ngContentIndex, + childCount: 0, + bindings, bindingFlags: BindingFlags.TypeProperty, outputs: [], element: null, @@ -53,7 +55,7 @@ export function textDef( export function createText(view: ViewData, renderHost: any, def: NodeDef): TextData { let renderNode: any; const renderer = view.renderer; - renderNode = renderer.createText(def.text !.prefix); + renderNode = renderer.createText(def.text!.prefix); const parentEl = getParentRenderElement(view, renderHost, def); if (parentEl) { renderer.appendChild(parentEl, renderNode); @@ -79,7 +81,7 @@ export function checkAndUpdateTextInline( if (bindLen > 9 && checkAndUpdateBinding(view, def, 9, v9)) changed = true; if (changed) { - let value = def.text !.prefix; + let value = def.text!.prefix; if (bindLen > 0) value += _addInterpolationPart(v0, bindings[0]); if (bindLen > 1) value += _addInterpolationPart(v1, bindings[1]); if (bindLen > 2) value += _addInterpolationPart(v2, bindings[2]); @@ -111,7 +113,7 @@ export function checkAndUpdateTextDynamic(view: ViewData, def: NodeDef, values: for (let i = 0; i < values.length; i++) { value = value + _addInterpolationPart(values[i], bindings[i]); } - value = def.text !.prefix + value; + value = def.text!.prefix + value; const renderNode = asTextData(view, def.nodeIndex).renderText; view.renderer.setValue(renderNode, value); } diff --git a/packages/core/src/view/types.ts b/packages/core/src/view/types.ts index 3172afa33bc79..da23eb3675d6a 100644 --- a/packages/core/src/view/types.ts +++ b/packages/core/src/view/types.ts @@ -30,16 +30,22 @@ import {SecurityContext} from '../sanitization/security'; * function to log the error from the definition of the node, which is shown in all browser * logs. */ -export interface DefinitionFactory<D extends Definition<any>> { (logger: NodeLogger): D; } +export interface DefinitionFactory<D extends Definition<any>> { + (logger: NodeLogger): D; +} /** * Function to call console.error at the right source location. This is an indirection * via another function as browser will log the location that actually called * `console.error`. */ -export interface NodeLogger { (): () => void; } +export interface NodeLogger { + (): () => void; +} -export interface Definition<DF extends DefinitionFactory<any>> { factory: DF|null; } +export interface Definition<DF extends DefinitionFactory<any>> { + factory: DF|null; +} export interface NgModuleDefinition extends Definition<NgModuleDefinitionFactory> { providers: NgModuleProviderDef[]; @@ -77,7 +83,9 @@ export interface ViewDefinition extends Definition<ViewDefinitionFactory> { export interface ViewDefinitionFactory extends DefinitionFactory<ViewDefinition> {} -export interface ViewUpdateFn { (check: NodeCheckFn, view: ViewData): void; } +export interface ViewUpdateFn { + (check: NodeCheckFn, view: ViewData): void; +} // helper functions to create an overloaded function type. export interface NodeCheckFn { @@ -87,7 +95,10 @@ export interface NodeCheckFn { v3?: any, v4?: any, v5?: any, v6?: any, v7?: any, v8?: any, v9?: any): any; } -export const enum ArgumentType {Inline = 0, Dynamic = 1} +export const enum ArgumentType { + Inline = 0, + Dynamic = 1 +} export interface ViewHandleEventFn { (view: ViewData, nodeIndex: number, eventName: string, event: any): boolean; @@ -232,7 +243,10 @@ export interface OutputDef { propName: string|null; } -export const enum OutputType {ElementOutput, DirectiveOutput} +export const enum OutputType { + ElementOutput, + DirectiveOutput +} export const enum QueryValueType { ElementRef = 0, @@ -266,7 +280,9 @@ export interface ElementDef { handleEvent: ElementHandleEventFn|null; } -export interface ElementHandleEventFn { (view: ViewData, eventName: string, event: any): boolean; } +export interface ElementHandleEventFn { + (view: ViewData, eventName: string, event: any): boolean; +} export interface ProviderDef { token: any; @@ -299,7 +315,9 @@ export const enum DepFlags { Value = 1 << 3, } -export interface TextDef { prefix: string; } +export interface TextDef { + prefix: string; +} export interface QueryDef { id: number; @@ -313,7 +331,10 @@ export interface QueryBindingDef { bindingType: QueryBindingType; } -export const enum QueryBindingType {First = 0, All = 1} +export const enum QueryBindingType { + First = 0, + All = 1 +} export interface NgContentDef { /** @@ -424,7 +445,9 @@ export function shouldCallLifecycleInitHook( return false; } -export interface DisposableFn { (): void; } +export interface DisposableFn { + (): void; +} /** * Node instance data. @@ -437,14 +460,18 @@ export interface DisposableFn { (): void; } * This way, no usage site can get a `NodeData` from view.nodes and then use it for different * purposes. */ -export class NodeData { private __brand: any; } +export class NodeData { + private __brand: any; +} /** * Data for an instantiated NodeType.Text. * * Attention: Adding fields to this is performance sensitive! */ -export interface TextData { renderText: any; } +export interface TextData { + renderText: any; +} /** * Accessor for view.nodes, enforcing that every usage site stays monomorphic. @@ -494,7 +521,9 @@ export function asElementData(view: ViewData, index: number): ElementData { * * Attention: Adding fields to this is performance sensitive! */ -export interface ProviderData { instance: any; } +export interface ProviderData { + instance: any; +} /** * Accessor for view.nodes, enforcing that every usage site stays monomorphic. @@ -508,7 +537,9 @@ export function asProviderData(view: ViewData, index: number): ProviderData { * * Attention: Adding fields to this is performance sensitive! */ -export interface PureExpressionData { value: any; } +export interface PureExpressionData { + value: any; +} /** * Accessor for view.nodes, enforcing that every usage site stays monomorphic. @@ -552,7 +583,10 @@ export abstract class DebugContext { // Other // ------------------------------------- -export const enum CheckType {CheckAndUpdate, CheckNoChanges} +export const enum CheckType { + CheckAndUpdate, + CheckNoChanges +} export interface ProviderOverride { token: any; @@ -595,21 +629,21 @@ export interface Services { * debug mode can hook it. It is lazily filled when `isDevMode` is known. */ export const Services: Services = { - setCurrentNode: undefined !, - createRootView: undefined !, - createEmbeddedView: undefined !, - createComponentView: undefined !, - createNgModuleRef: undefined !, - overrideProvider: undefined !, - overrideComponentView: undefined !, - clearOverrides: undefined !, - checkAndUpdateView: undefined !, - checkNoChangesView: undefined !, - destroyView: undefined !, - resolveDep: undefined !, - createDebugContext: undefined !, - handleEvent: undefined !, - updateDirectives: undefined !, - updateRenderer: undefined !, - dirtyParentQueries: undefined !, + setCurrentNode: undefined!, + createRootView: undefined!, + createEmbeddedView: undefined!, + createComponentView: undefined!, + createNgModuleRef: undefined!, + overrideProvider: undefined!, + overrideComponentView: undefined!, + clearOverrides: undefined!, + checkAndUpdateView: undefined!, + checkNoChangesView: undefined!, + destroyView: undefined!, + resolveDep: undefined!, + createDebugContext: undefined!, + handleEvent: undefined!, + updateDirectives: undefined!, + updateRenderer: undefined!, + dirtyParentQueries: undefined!, }; diff --git a/packages/core/src/view/util.ts b/packages/core/src/view/util.ts index 5e88b2124bf6b..29077efb69212 100644 --- a/packages/core/src/view/util.ts +++ b/packages/core/src/view/util.ts @@ -6,14 +6,15 @@ * found in the LICENSE file at https://angular.io/license */ -import {WrappedValue, devModeEqual} from '../change_detection/change_detection'; +import {devModeEqual, WrappedValue} from '../change_detection/change_detection'; import {SOURCE} from '../di/injector_compatibility'; import {ViewEncapsulation} from '../metadata/view'; import {RendererType2} from '../render/api'; import {looseIdentical} from '../util/comparison'; import {stringify} from '../util/stringify'; + import {expressionChangedAfterItHasBeenCheckedError} from './errors'; -import {BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState, asElementData, asTextData} from './types'; +import {asElementData, asTextData, BindingDef, BindingFlags, Definition, DefinitionFactory, DepDef, DepFlags, ElementData, NodeDef, NodeFlags, QueryValueType, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewState} from './types'; export const NOOP: any = () => {}; @@ -44,7 +45,7 @@ const EMPTY_RENDERER_TYPE_ID = '$$empty'; // Attention: this function is called as top level function. // Putting any logic in here will destroy closure tree shaking! export function createRendererType2(values: { - styles: (string | any[])[], + styles: (string|any[])[], encapsulation: ViewEncapsulation, data: {[kind: string]: any[]} }): RendererType2 { @@ -58,7 +59,7 @@ export function createRendererType2(values: { let _renderCompCount = 0; -export function resolveRendererType2(type?: RendererType2 | null): RendererType2|null { +export function resolveRendererType2(type?: RendererType2|null): RendererType2|null { if (type && type.id === UNDEFINED_RENDERER_TYPE_ID) { // first time we see this RendererType2. Initialize it... const isFilled = @@ -142,7 +143,7 @@ export function dispatchEvent( export function declaredViewContainer(view: ViewData): ElementData|null { if (view.parent) { const parentView = view.parent; - return asElementData(parentView, view.parentNodeDef !.nodeIndex); + return asElementData(parentView, view.parentNodeDef!.nodeIndex); } return null; } @@ -155,7 +156,7 @@ export function declaredViewContainer(view: ViewData): ElementData|null { export function viewParentEl(view: ViewData): NodeDef|null { const parentView = view.parent; if (parentView) { - return view.parentNodeDef !.parent; + return view.parentNodeDef!.parent; } else { return null; } @@ -170,24 +171,23 @@ export function renderNode(view: ViewData, def: NodeDef): any { } } -export function elementEventFullName(target: string | null, name: string): string { +export function elementEventFullName(target: string|null, name: string): string { return target ? `${target}:${name}` : name; } export function isComponentView(view: ViewData): boolean { - return !!view.parent && !!(view.parentNodeDef !.flags & NodeFlags.Component); + return !!view.parent && !!(view.parentNodeDef!.flags & NodeFlags.Component); } export function isEmbeddedView(view: ViewData): boolean { - return !!view.parent && !(view.parentNodeDef !.flags & NodeFlags.Component); + return !!view.parent && !(view.parentNodeDef!.flags & NodeFlags.Component); } export function filterQueryId(queryId: number): number { return 1 << (queryId % 32); } -export function splitMatchedQueriesDsl( - matchedQueriesDsl: [string | number, QueryValueType][] | null): { +export function splitMatchedQueriesDsl(matchedQueriesDsl: [string|number, QueryValueType][]|null): { matchedQueries: {[queryId: string]: QueryValueType}, references: {[refId: string]: QueryValueType}, matchedQueryIds: number @@ -208,7 +208,7 @@ export function splitMatchedQueriesDsl( return {matchedQueries, references, matchedQueryIds}; } -export function splitDepsDsl(deps: ([DepFlags, any] | any)[], sourceName?: string): DepDef[] { +export function splitDepsDsl(deps: ([DepFlags, any]|any)[], sourceName?: string): DepDef[] { return deps.map(value => { let token: any; let flags: DepFlags; @@ -230,12 +230,11 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod if (renderParent) { if ((renderParent.flags & NodeFlags.TypeElement) === 0 || (renderParent.flags & NodeFlags.ComponentView) === 0 || - (renderParent.element !.componentRendererType && - renderParent.element !.componentRendererType !.encapsulation === - ViewEncapsulation.Native)) { + (renderParent.element!.componentRendererType && + renderParent.element!.componentRendererType!.encapsulation === ViewEncapsulation.Native)) { // only children of non components, or children of components with native encapsulation should // be attached. - return asElementData(view, def.renderParent !.nodeIndex).renderElement; + return asElementData(view, def.renderParent!.nodeIndex).renderElement; } } else { return renderHost; @@ -245,7 +244,7 @@ export function getParentRenderElement(view: ViewData, renderHost: any, def: Nod const DEFINITION_CACHE = new WeakMap<any, Definition<any>>(); export function resolveDefinition<D extends Definition<any>>(factory: DefinitionFactory<D>): D { - let value = DEFINITION_CACHE.get(factory) !as D; + let value = DEFINITION_CACHE.get(factory)! as D; if (!value) { value = factory(() => NOOP); value.factory = factory; @@ -260,13 +259,18 @@ export function rootRenderNodes(view: ViewData): any[] { return renderNodes; } -export const enum RenderNodeAction {Collect, AppendChild, InsertBefore, RemoveChild} +export const enum RenderNodeAction { + Collect, + AppendChild, + InsertBefore, + RemoveChild +} export function visitRootRenderNodes( view: ViewData, action: RenderNodeAction, parentNode: any, nextSibling: any, target?: any[]) { // We need to re-compute the parent node in case the nodes have been moved around manually if (action === RenderNodeAction.RemoveChild) { - parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRenderRootNode !)); + parentNode = view.renderer.parentNode(renderNode(view, view.def.lastRenderRootNode!)); } visitSiblingRenderNodes( view, action, 0, view.def.nodes.length - 1, parentNode, nextSibling, target); @@ -292,19 +296,19 @@ export function visitProjectedRenderNodes( while (compView && !isComponentView(compView)) { compView = compView.parent; } - const hostView = compView !.parent; - const hostElDef = viewParentEl(compView !); - const startIndex = hostElDef !.nodeIndex + 1; - const endIndex = hostElDef !.nodeIndex + hostElDef !.childCount; + const hostView = compView!.parent; + const hostElDef = viewParentEl(compView!); + const startIndex = hostElDef!.nodeIndex + 1; + const endIndex = hostElDef!.nodeIndex + hostElDef!.childCount; for (let i = startIndex; i <= endIndex; i++) { - const nodeDef = hostView !.def.nodes[i]; + const nodeDef = hostView!.def.nodes[i]; if (nodeDef.ngContentIndex === ngContentIndex) { - visitRenderNode(hostView !, nodeDef, action, parentNode, nextSibling, target); + visitRenderNode(hostView!, nodeDef, action, parentNode, nextSibling, target); } // jump to next sibling i += nodeDef.childCount; } - if (!hostView !.parent) { + if (!hostView!.parent) { // a root view const projectedNodes = view.root.projectableNodes[ngContentIndex]; if (projectedNodes) { @@ -320,7 +324,7 @@ function visitRenderNode( target?: any[]) { if (nodeDef.flags & NodeFlags.TypeNgContent) { visitProjectedRenderNodes( - view, nodeDef.ngContent !.index, action, parentNode, nextSibling, target); + view, nodeDef.ngContent!.index, action, parentNode, nextSibling, target); } else { const rn = renderNode(view, nodeDef); if (action === RenderNodeAction.RemoveChild && (nodeDef.flags & NodeFlags.ComponentView) && @@ -337,12 +341,12 @@ function visitRenderNode( execRenderNodeAction(view, rn, action, parentNode, nextSibling, target); } if (nodeDef.flags & NodeFlags.EmbeddedViews) { - const embeddedViews = asElementData(view, nodeDef.nodeIndex).viewContainer !._embeddedViews; + const embeddedViews = asElementData(view, nodeDef.nodeIndex).viewContainer!._embeddedViews; for (let k = 0; k < embeddedViews.length; k++) { visitRootRenderNodes(embeddedViews[k], action, parentNode, nextSibling, target); } } - if (nodeDef.flags & NodeFlags.TypeElement && !nodeDef.element !.name) { + if (nodeDef.flags & NodeFlags.TypeElement && !nodeDef.element!.name) { visitSiblingRenderNodes( view, action, nodeDef.nodeIndex + 1, nodeDef.nodeIndex + nodeDef.childCount, parentNode, nextSibling, target); @@ -365,7 +369,7 @@ function execRenderNodeAction( renderer.removeChild(parentNode, renderNode); break; case RenderNodeAction.Collect: - target !.push(renderNode); + target!.push(renderNode); break; } } @@ -374,7 +378,7 @@ const NS_PREFIX_RE = /^:([^:]+):(.+)$/; export function splitNamespace(name: string): string[] { if (name[0] === ':') { - const match = name.match(NS_PREFIX_RE) !; + const match = name.match(NS_PREFIX_RE)!; return [match[1], match[2]]; } return ['', name]; diff --git a/packages/core/src/view/view.ts b/packages/core/src/view/view.ts index 434473f435def..a9cc1e13e3590 100644 --- a/packages/core/src/view/view.ts +++ b/packages/core/src/view/view.ts @@ -16,13 +16,13 @@ import {checkAndUpdatePureExpressionDynamic, checkAndUpdatePureExpressionInline, import {checkAndUpdateQuery, createQuery} from './query'; import {createTemplateData, createViewContainerData} from './refs'; import {checkAndUpdateTextDynamic, checkAndUpdateTextInline, createText} from './text'; -import {ArgumentType, CheckType, ElementData, NodeData, NodeDef, NodeFlags, ProviderData, RootData, Services, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn, asElementData, asQueryList, asTextData, shiftInitState} from './types'; -import {NOOP, checkBindingNoChanges, isComponentView, markParentViewsForCheckProjectedViews, resolveDefinition, tokenKey} from './util'; +import {ArgumentType, asElementData, asQueryList, asTextData, CheckType, ElementData, NodeData, NodeDef, NodeFlags, ProviderData, RootData, Services, shiftInitState, ViewData, ViewDefinition, ViewFlags, ViewHandleEventFn, ViewState, ViewUpdateFn} from './types'; +import {checkBindingNoChanges, isComponentView, markParentViewsForCheckProjectedViews, NOOP, resolveDefinition, tokenKey} from './util'; import {detachProjectedView} from './view_attach'; export function viewDef( - flags: ViewFlags, nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, - updateRenderer?: null | ViewUpdateFn): ViewDefinition { + flags: ViewFlags, nodes: NodeDef[], updateDirectives?: null|ViewUpdateFn, + updateRenderer?: null|ViewUpdateFn): ViewDefinition { // clone nodes and set auto calculated values let viewBindingCount = 0; let viewDisposableCount = 0; @@ -48,7 +48,7 @@ export function viewDef( if (node.element) { const elDef = node.element; elDef.publicProviders = - currentParent ? currentParent.element !.publicProviders : Object.create(null); + currentParent ? currentParent.element!.publicProviders : Object.create(null); elDef.allProviders = elDef.publicProviders; // Note: We assume that all providers of an element are before any child element! currentElementHasPublicProviders = false; @@ -72,25 +72,25 @@ export function viewDef( if (!currentElementHasPublicProviders) { currentElementHasPublicProviders = true; // Use prototypical inheritance to not get O(n^2) complexity... - currentParent !.element !.publicProviders = - Object.create(currentParent !.element !.publicProviders); - currentParent !.element !.allProviders = currentParent !.element !.publicProviders; + currentParent!.element!.publicProviders = + Object.create(currentParent!.element!.publicProviders); + currentParent!.element!.allProviders = currentParent!.element!.publicProviders; } const isPrivateService = (node.flags & NodeFlags.PrivateProvider) !== 0; const isComponent = (node.flags & NodeFlags.Component) !== 0; if (!isPrivateService || isComponent) { - currentParent !.element !.publicProviders ![tokenKey(node.provider !.token)] = node; + currentParent!.element!.publicProviders![tokenKey(node.provider!.token)] = node; } else { if (!currentElementHasPrivateProviders) { currentElementHasPrivateProviders = true; // Use prototypical inheritance to not get O(n^2) complexity... - currentParent !.element !.allProviders = - Object.create(currentParent !.element !.publicProviders); + currentParent!.element!.allProviders = + Object.create(currentParent!.element!.publicProviders); } - currentParent !.element !.allProviders ![tokenKey(node.provider !.token)] = node; + currentParent!.element!.allProviders![tokenKey(node.provider!.token)] = node; } if (isComponent) { - currentParent !.element !.componentProvider = node; + currentParent!.element!.componentProvider = node; } } @@ -135,27 +135,30 @@ export function viewDef( } const handleEvent: ViewHandleEventFn = (view, nodeIndex, eventName, event) => - nodes[nodeIndex].element !.handleEvent !(view, eventName, event); + nodes[nodeIndex].element!.handleEvent!(view, eventName, event); return { // Will be filled later... factory: null, nodeFlags: viewNodeFlags, rootNodeFlags: viewRootNodeFlags, - nodeMatchedQueries: viewMatchedQueries, flags, + nodeMatchedQueries: viewMatchedQueries, + flags, nodes: nodes, updateDirectives: updateDirectives || NOOP, - updateRenderer: updateRenderer || NOOP, handleEvent, + updateRenderer: updateRenderer || NOOP, + handleEvent, bindingCount: viewBindingCount, - outputCount: viewDisposableCount, lastRenderRootNode + outputCount: viewDisposableCount, + lastRenderRootNode }; } function isNgContainer(node: NodeDef): boolean { - return (node.flags & NodeFlags.TypeElement) !== 0 && node.element !.name === null; + return (node.flags & NodeFlags.TypeElement) !== 0 && node.element!.name === null; } -function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number) { +function validateNode(parent: NodeDef|null, node: NodeDef, nodeCount: number) { const template = node.element && node.element.template; if (template) { if (!template.lastRenderRootNode) { @@ -164,25 +167,28 @@ function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number) if (template.lastRenderRootNode && template.lastRenderRootNode.flags & NodeFlags.EmbeddedViews) { throw new Error( - `Illegal State: Last root node of a template can't have embedded views, at index ${node.nodeIndex}!`); + `Illegal State: Last root node of a template can't have embedded views, at index ${ + node.nodeIndex}!`); } } if (node.flags & NodeFlags.CatProvider) { const parentFlags = parent ? parent.flags : 0; if ((parentFlags & NodeFlags.TypeElement) === 0) { throw new Error( - `Illegal State: StaticProvider/Directive nodes need to be children of elements or anchors, at index ${node.nodeIndex}!`); + `Illegal State: StaticProvider/Directive nodes need to be children of elements or anchors, at index ${ + node.nodeIndex}!`); } } if (node.query) { if (node.flags & NodeFlags.TypeContentQuery && (!parent || (parent.flags & NodeFlags.TypeDirective) === 0)) { throw new Error( - `Illegal State: Content Query nodes need to be children of directives, at index ${node.nodeIndex}!`); + `Illegal State: Content Query nodes need to be children of directives, at index ${ + node.nodeIndex}!`); } if (node.flags & NodeFlags.TypeViewQuery && parent) { - throw new Error( - `Illegal State: View Query nodes have to be top level nodes, at index ${node.nodeIndex}!`); + throw new Error(`Illegal State: View Query nodes have to be top level nodes, at index ${ + node.nodeIndex}!`); } } if (node.childCount) { @@ -213,7 +219,7 @@ export function createRootView(root: RootData, def: ViewDefinition, context?: an export function createComponentView( parentView: ViewData, nodeDef: NodeDef, viewDef: ViewDefinition, hostElement: any): ViewData { - const rendererType = nodeDef.element !.componentRendererType; + const rendererType = nodeDef.element!.componentRendererType; let compRenderer: Renderer2; if (!rendererType) { compRenderer = parentView.root.renderer; @@ -221,22 +227,27 @@ export function createComponentView( compRenderer = parentView.root.rendererFactory.createRenderer(hostElement, rendererType); } return createView( - parentView.root, compRenderer, parentView, nodeDef.element !.componentProvider, viewDef); + parentView.root, compRenderer, parentView, nodeDef.element!.componentProvider, viewDef); } function createView( - root: RootData, renderer: Renderer2, parent: ViewData | null, parentNodeDef: NodeDef | null, + root: RootData, renderer: Renderer2, parent: ViewData|null, parentNodeDef: NodeDef|null, def: ViewDefinition): ViewData { const nodes: NodeData[] = new Array(def.nodes.length); const disposables = def.outputCount ? new Array(def.outputCount) : null; const view: ViewData = { def, parent, - viewContainerParent: null, parentNodeDef, + viewContainerParent: null, + parentNodeDef, context: null, - component: null, nodes, - state: ViewState.CatInit, root, renderer, - oldValues: new Array(def.bindingCount), disposables, + component: null, + nodes, + state: ViewState.CatInit, + root, + renderer, + oldValues: new Array(def.bindingCount), + disposables, initIndex: -1 }; return view; @@ -251,7 +262,7 @@ function createViewNodes(view: ViewData) { let renderHost: any; if (isComponentView(view)) { const hostDef = view.parentNodeDef; - renderHost = asElementData(view.parent !, hostDef !.parent !.nodeIndex).renderElement; + renderHost = asElementData(view.parent!, hostDef!.parent!.nodeIndex).renderElement; } const def = view.def; const nodes = view.nodes; @@ -262,9 +273,9 @@ function createViewNodes(view: ViewData) { switch (nodeDef.flags & NodeFlags.Types) { case NodeFlags.TypeElement: const el = createElement(view, renderHost, nodeDef) as any; - let componentView: ViewData = undefined !; + let componentView: ViewData = undefined!; if (nodeDef.flags & NodeFlags.ComponentView) { - const compViewDef = resolveDefinition(nodeDef.element !.componentView !); + const compViewDef = resolveDefinition(nodeDef.element!.componentView!); componentView = Services.createComponentView(view, nodeDef, compViewDef, el); } listenToElementOutputs(view, componentView, nodeDef, el); @@ -272,7 +283,7 @@ function createViewNodes(view: ViewData) { renderElement: el, componentView, viewContainer: null, - template: nodeDef.element !.template ? createTemplateData(view, nodeDef) : undefined + template: nodeDef.element!.template ? createTemplateData(view, nodeDef) : undefined }; if (nodeDef.flags & NodeFlags.EmbeddedViews) { nodeData.viewContainer = createViewContainerData(view, nodeDef, nodeData); @@ -304,7 +315,7 @@ function createViewNodes(view: ViewData) { nodeData = <ProviderData>{instance}; } if (nodeDef.flags & NodeFlags.Component) { - const compView = asElementData(view, nodeDef.parent !.nodeIndex).componentView; + const compView = asElementData(view, nodeDef.parent!.nodeIndex).componentView; initView(compView, nodeData.instance, nodeData.instance); } break; @@ -529,9 +540,9 @@ function destroyViewNodes(view: ViewData) { for (let i = 0; i < len; i++) { const def = view.def.nodes[i]; if (def.flags & NodeFlags.TypeElement) { - view.renderer.destroyNode !(asElementData(view, i).renderElement); + view.renderer.destroyNode!(asElementData(view, i).renderElement); } else if (def.flags & NodeFlags.TypeText) { - view.renderer.destroyNode !(asTextData(view, i).renderText); + view.renderer.destroyNode!(asTextData(view, i).renderText); } else if (def.flags & NodeFlags.TypeContentQuery || def.flags & NodeFlags.TypeViewQuery) { asQueryList(view, i).destroy(); } @@ -575,7 +586,7 @@ function execEmbeddedViewsAction(view: ViewData, action: ViewAction) { const nodeDef = def.nodes[i]; if (nodeDef.flags & NodeFlags.EmbeddedViews) { // a leaf - const embeddedViews = asElementData(view, i).viewContainer !._embeddedViews; + const embeddedViews = asElementData(view, i).viewContainer!._embeddedViews; for (let k = 0; k < embeddedViews.length; k++) { callViewAction(embeddedViews[k], action); } diff --git a/packages/core/src/view/view_attach.ts b/packages/core/src/view/view_attach.ts index ea86b9a4276ca..81c392d9f4edc 100644 --- a/packages/core/src/view/view_attach.ts +++ b/packages/core/src/view/view_attach.ts @@ -7,23 +7,24 @@ */ import {addToArray, removeFromArray} from '../util/array_utils'; + import {ElementData, NodeDef, NodeFlags, Services, ViewData, ViewDefinition, ViewState} from './types'; -import {RenderNodeAction, declaredViewContainer, renderNode, visitRootRenderNodes} from './util'; +import {declaredViewContainer, renderNode, RenderNodeAction, visitRootRenderNodes} from './util'; export function attachEmbeddedView( - parentView: ViewData, elementData: ElementData, viewIndex: number | undefined | null, + parentView: ViewData, elementData: ElementData, viewIndex: number|undefined|null, view: ViewData) { - let embeddedViews = elementData.viewContainer !._embeddedViews; + let embeddedViews = elementData.viewContainer!._embeddedViews; if (viewIndex === null || viewIndex === undefined) { viewIndex = embeddedViews.length; } view.viewContainerParent = parentView; - addToArray(embeddedViews, viewIndex !, view); + addToArray(embeddedViews, viewIndex!, view); attachProjectedView(elementData, view); Services.dirtyParentQueries(view); - const prevView = viewIndex ! > 0 ? embeddedViews[viewIndex ! - 1] : null; + const prevView = viewIndex! > 0 ? embeddedViews[viewIndex! - 1] : null; renderAttachEmbeddedView(elementData, prevView, view); } @@ -48,7 +49,7 @@ function attachProjectedView(vcElementData: ElementData, view: ViewData) { projectedViews.push(view); // Note: we are changing the NodeDef here as we cannot calculate // the fact whether a template is used for projection during compilation. - markNodeAsProjectedTemplate(view.parent !.def, view.parentNodeDef !); + markNodeAsProjectedTemplate(view.parent!.def, view.parentNodeDef!); } function markNodeAsProjectedTemplate(viewDef: ViewDefinition, nodeDef: NodeDef) { @@ -65,7 +66,7 @@ function markNodeAsProjectedTemplate(viewDef: ViewDefinition, nodeDef: NodeDef) } export function detachEmbeddedView(elementData: ElementData, viewIndex?: number): ViewData|null { - const embeddedViews = elementData.viewContainer !._embeddedViews; + const embeddedViews = elementData.viewContainer!._embeddedViews; if (viewIndex == null || viewIndex >= embeddedViews.length) { viewIndex = embeddedViews.length - 1; } @@ -100,7 +101,7 @@ export function detachProjectedView(view: ViewData) { export function moveEmbeddedView( elementData: ElementData, oldViewIndex: number, newViewIndex: number): ViewData { - const embeddedViews = elementData.viewContainer !._embeddedViews; + const embeddedViews = elementData.viewContainer!._embeddedViews; const view = embeddedViews[oldViewIndex]; removeFromArray(embeddedViews, oldViewIndex); if (newViewIndex == null) { @@ -121,9 +122,9 @@ export function moveEmbeddedView( } function renderAttachEmbeddedView( - elementData: ElementData, prevView: ViewData | null, view: ViewData) { - const prevRenderNode = prevView ? renderNode(prevView, prevView.def.lastRenderRootNode !) : - elementData.renderElement; + elementData: ElementData, prevView: ViewData|null, view: ViewData) { + const prevRenderNode = + prevView ? renderNode(prevView, prevView.def.lastRenderRootNode!) : elementData.renderElement; const parentNode = view.renderer.parentNode(prevRenderNode); const nextSibling = view.renderer.nextSibling(prevRenderNode); // Note: We can't check if `nextSibling` is present, as on WebWorkers it will always be! diff --git a/packages/core/src/zone/ng_zone.ts b/packages/core/src/zone/ng_zone.ts index bfca86e193850..a5387e4cdb5be 100644 --- a/packages/core/src/zone/ng_zone.ts +++ b/packages/core/src/zone/ng_zone.ts @@ -148,7 +148,9 @@ export class NgZone { forkInnerZoneWithAngularBehavior(self); } - static isInAngularZone(): boolean { return Zone.current.get('isAngularZone') === true; } + static isInAngularZone(): boolean { + return Zone.current.get('isAngularZone') === true; + } static assertInAngularZone(): void { if (!NgZone.isInAngularZone()) { @@ -274,36 +276,40 @@ function delayChangeDetectionForEvents(zone: NgZonePrivate) { } function forkInnerZoneWithAngularBehavior(zone: NgZonePrivate) { - const delayChangeDetectionForEventsDelegate = () => { delayChangeDetectionForEvents(zone); }; + const delayChangeDetectionForEventsDelegate = () => { + delayChangeDetectionForEvents(zone); + }; const maybeDelayChangeDetection = !!zone.shouldCoalesceEventChangeDetection && zone.nativeRequestAnimationFrame && delayChangeDetectionForEventsDelegate; zone._inner = zone._inner.fork({ name: 'angular', properties: <any>{'isAngularZone': true, 'maybeDelayChangeDetection': maybeDelayChangeDetection}, - onInvokeTask: (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any, - applyArgs: any): any => { - try { - onEnter(zone); - return delegate.invokeTask(target, task, applyThis, applyArgs); - } finally { - if (maybeDelayChangeDetection && task.type === 'eventTask') { - maybeDelayChangeDetection(); - } - onLeave(zone); - } - }, + onInvokeTask: + (delegate: ZoneDelegate, current: Zone, target: Zone, task: Task, applyThis: any, + applyArgs: any): any => { + try { + onEnter(zone); + return delegate.invokeTask(target, task, applyThis, applyArgs); + } finally { + if (maybeDelayChangeDetection && task.type === 'eventTask') { + maybeDelayChangeDetection(); + } + onLeave(zone); + } + }, - onInvoke: (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function, - applyThis: any, applyArgs?: any[], source?: string): any => { - try { - onEnter(zone); - return delegate.invoke(target, callback, applyThis, applyArgs, source); - } finally { - onLeave(zone); - } - }, + onInvoke: + (delegate: ZoneDelegate, current: Zone, target: Zone, callback: Function, applyThis: any, + applyArgs?: any[], source?: string): any => { + try { + onEnter(zone); + return delegate.invoke(target, callback, applyThis, applyArgs, source); + } finally { + onLeave(zone); + } + }, onHasTask: (delegate: ZoneDelegate, current: Zone, target: Zone, hasTaskState: HasTaskState) => { @@ -372,7 +378,9 @@ export class NoopNgZone implements NgZone { return fn.apply(applyThis, applyArgs); } - runOutsideAngular(fn: (...args: any[]) => any): any { return fn(); } + runOutsideAngular(fn: (...args: any[]) => any): any { + return fn(); + } runTask(fn: (...args: any[]) => any, applyThis?: any, applyArgs?: any, name?: string): any { return fn.apply(applyThis, applyArgs); diff --git a/packages/core/test/acceptance/bootstrap_spec.ts b/packages/core/test/acceptance/bootstrap_spec.ts index 91dd57d46b1fa..a2fc8ced6f4e3 100644 --- a/packages/core/test/acceptance/bootstrap_spec.ts +++ b/packages/core/test/acceptance/bootstrap_spec.ts @@ -6,18 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -import {COMPILER_OPTIONS, Component, NgModule, ViewEncapsulation, destroyPlatform} from '@angular/core'; +import {COMPILER_OPTIONS, Component, destroyPlatform, NgModule, ViewEncapsulation} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {onlyInIvy, withBody} from '@angular/private/testing'; describe('bootstrap', () => { - beforeEach(destroyPlatform); afterEach(destroyPlatform); it('should bootstrap using #id selector', - withBody('<div>before|</div><button id="my-app"></button>', async() => { + withBody('<div>before|</div><button id="my-app"></button>', async () => { try { const ngModuleRef = await platformBrowserDynamic().bootstrapModule(IdSelectorAppModule); expect(document.body.textContent).toEqual('before|works!'); @@ -28,7 +27,7 @@ describe('bootstrap', () => { })); it('should bootstrap using one of selectors from the list', - withBody('<div>before|</div><div class="bar"></div>', async() => { + withBody('<div>before|</div><div class="bar"></div>', async () => { try { const ngModuleRef = await platformBrowserDynamic().bootstrapModule(MultipleSelectorsAppModule); @@ -66,7 +65,7 @@ describe('bootstrap', () => { } it('should use ViewEncapsulation.Emulated as default', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); @@ -75,7 +74,7 @@ describe('bootstrap', () => { })); it('should allow setting defaultEncapsulation using bootstrap option', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( @@ -86,7 +85,7 @@ describe('bootstrap', () => { })); it('should allow setting defaultEncapsulation using compiler option', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic([{ @@ -100,7 +99,7 @@ describe('bootstrap', () => { })); it('should prefer encapsulation on component over bootstrap option', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule({encapsulation: ViewEncapsulation.Emulated}); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( @@ -110,7 +109,7 @@ describe('bootstrap', () => { })); it('should use preserveWhitespaces: false as default', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule(TestModule); @@ -119,7 +118,7 @@ describe('bootstrap', () => { })); it('should allow setting preserveWhitespaces using bootstrap option', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( @@ -129,7 +128,7 @@ describe('bootstrap', () => { })); it('should allow setting preserveWhitespaces using compiler option', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const ngModuleRef = @@ -141,7 +140,7 @@ describe('bootstrap', () => { })); it('should prefer preserveWhitespaces on component over bootstrap option', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule({preserveWhitespaces: false}); const ngModuleRef = await platformBrowserDynamic().bootstrapModule( @@ -151,10 +150,12 @@ describe('bootstrap', () => { })); onlyInIvy('options cannot be changed in Ivy').describe('changing bootstrap options', () => { - beforeEach(() => { spyOn(console, 'error'); }); + beforeEach(() => { + spyOn(console, 'error'); + }); it('should log an error when changing defaultEncapsulation bootstrap options', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const platformRef = platformBrowserDynamic(); @@ -175,7 +176,7 @@ describe('bootstrap', () => { })); it('should log an error when changing preserveWhitespaces bootstrap options', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const platformRef = platformBrowserDynamic(); @@ -196,7 +197,7 @@ describe('bootstrap', () => { })); it('should log an error when changing defaultEncapsulation to its default', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const platformRef = platformBrowserDynamic(); @@ -215,7 +216,7 @@ describe('bootstrap', () => { })); it('should log an error when changing preserveWhitespaces to its default', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const platformRef = platformBrowserDynamic(); @@ -234,7 +235,7 @@ describe('bootstrap', () => { })); it('should not log an error when passing identical bootstrap options', - withBody('<my-app></my-app>', async() => { + withBody('<my-app></my-app>', async () => { const TestModule = createComponentAndModule(); const platformRef = platformBrowserDynamic(); diff --git a/packages/core/test/acceptance/change_detection_spec.ts b/packages/core/test/acceptance/change_detection_spec.ts index a5d6b41b2ef3a..9e9643ddbc917 100644 --- a/packages/core/test/acceptance/change_detection_spec.ts +++ b/packages/core/test/acceptance/change_detection_spec.ts @@ -16,16 +16,16 @@ import {ivyEnabled} from '@angular/private/testing'; import {BehaviorSubject} from 'rxjs'; describe('change detection', () => { - describe('embedded views', () => { - @Directive({selector: '[viewManipulation]', exportAs: 'vm'}) class ViewManipulation { constructor( private _tplRef: TemplateRef<{}>, public vcRef: ViewContainerRef, private _appRef: ApplicationRef) {} - insertIntoVcRef() { return this.vcRef.createEmbeddedView(this._tplRef); } + insertIntoVcRef() { + return this.vcRef.createEmbeddedView(this._tplRef); + } insertIntoAppRef(): EmbeddedViewRef<{}> { const viewRef = this._tplRef.createEmbeddedView({}); @@ -80,7 +80,9 @@ describe('change detection', () => { changeDetection: ChangeDetectionStrategy.OnPush }) class App { - increment(counter: 'componentView'|'embeddedView') { counters[counter]++; } + increment(counter: 'componentView'|'embeddedView') { + counters[counter]++; + } noop() {} } @@ -129,7 +131,9 @@ describe('change detection', () => { changeDetection: ChangeDetectionStrategy.OnPush }) class DynamicComp { - increment() { counter++; } + increment() { + counter++; + } noop() {} } @@ -170,13 +174,10 @@ describe('change detection', () => { expect(counter).toBe(3); }); - }); describe('markForCheck', () => { - it('should mark OnPush ancestor of dynamically created component views as dirty', () => { - @Component({ selector: `test-cmpt`, template: `{{counter}}|<ng-template #vc></ng-template>`, @@ -184,7 +185,7 @@ describe('change detection', () => { }) class TestCmpt { counter = 0; - @ViewChild('vc', {read: ViewContainerRef}) vcRef !: ViewContainerRef; + @ViewChild('vc', {read: ViewContainerRef}) vcRef!: ViewContainerRef; constructor(private _cfr: ComponentFactoryResolver) {} @@ -252,11 +253,13 @@ describe('change detection', () => { /** * @internal */ - private _input !: number; + private _input!: number; constructor(private cdr: ChangeDetectorRef) {} - get input() { return this._input; } + get input() { + return this._input; + } set input(value: number) { this._input = value; @@ -286,18 +289,19 @@ describe('change detection', () => { template: `{{ doCheckCount }} - {{ name }} <button (click)="onClick()"></button>` }) class MyComponent implements DoCheck { - @Input() - name = 'Nancy'; + @Input() name = 'Nancy'; doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + ngDoCheck(): void { + this.doCheckCount++; + } onClick() {} } @Component({selector: 'my-app', template: '<my-comp [name]="name"></my-comp>'}) class MyApp { - @ViewChild(MyComponent) comp !: MyComponent; + @ViewChild(MyComponent) comp!: MyComponent; name: string = 'Nancy'; } @@ -369,7 +373,7 @@ describe('change detection', () => { expect(fixture.componentInstance.comp.doCheckCount).toEqual(1); expect(fixture.nativeElement.textContent.trim()).toEqual('1 - Nancy'); - const button = fixture.nativeElement.querySelector('button') !; + const button = fixture.nativeElement.querySelector('button')!; button.click(); // No ticks should have been scheduled. @@ -389,7 +393,7 @@ describe('change detection', () => { template: '<my-comp></my-comp><button id="parent" (click)="noop()"></button>' }) class ButtonParent { - @ViewChild(MyComponent) comp !: MyComponent; + @ViewChild(MyComponent) comp!: MyComponent; noop() {} } @@ -415,16 +419,18 @@ describe('change detection', () => { changeDetection: ChangeDetectionStrategy.OnPush }) class ButtonParent implements DoCheck { - @ViewChild(MyComponent) comp !: MyComponent; + @ViewChild(MyComponent) comp!: MyComponent; noop() {} doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + ngDoCheck(): void { + this.doCheckCount++; + } } @Component({selector: 'my-button-app', template: '<button-parent></button-parent>'}) class MyButtonApp { - @ViewChild(ButtonParent) parent !: ButtonParent; + @ViewChild(ButtonParent) parent!: ButtonParent; } TestBed.configureTestingModule({declarations: [MyButtonApp, MyComponent, ButtonParent]}); @@ -456,7 +462,6 @@ describe('change detection', () => { expect(comp.doCheckCount).toEqual(2); expect(fixture.nativeElement.textContent.trim()).toEqual('3 - 2 - Nancy'); }); - }); describe('ChangeDetectorRef', () => { @@ -472,18 +477,22 @@ describe('change detection', () => { constructor(public cdr: ChangeDetectorRef) {} - ngDoCheck() { this.doCheckCount++; } + ngDoCheck() { + this.doCheckCount++; + } } @Component({selector: 'parent-comp', template: `{{ doCheckCount}} - <my-comp></my-comp>`}) class ParentComp implements DoCheck { - @ViewChild(MyComp) myComp !: MyComp; + @ViewChild(MyComp) myComp!: MyComp; doCheckCount = 0; constructor(public cdr: ChangeDetectorRef) {} - ngDoCheck() { this.doCheckCount++; } + ngDoCheck() { + this.doCheckCount++; + } } @Directive({selector: '[dir]'}) @@ -562,8 +571,8 @@ describe('change detection', () => { it('should check component view when called by directive on component node', () => { @Component({template: '<my-comp dir></my-comp>'}) class MyApp { - @ViewChild(MyComp) myComp !: MyComp; - @ViewChild(Dir) dir !: Dir; + @ViewChild(MyComp) myComp!: MyComp; + @ViewChild(Dir) dir!: Dir; } TestBed.configureTestingModule({declarations: [MyComp, Dir, MyApp]}); @@ -580,8 +589,8 @@ describe('change detection', () => { it('should check host component when called by directive on element node', () => { @Component({template: '{{ value }}<div dir></div>'}) class MyApp { - @ViewChild(MyComp) myComp !: MyComp; - @ViewChild(Dir) dir !: Dir; + @ViewChild(MyComp) myComp!: MyComp; + @ViewChild(Dir) dir!: Dir; value = ''; } @@ -601,7 +610,7 @@ describe('change detection', () => { it('should check the host component when called from EmbeddedViewRef', () => { @Component({template: '{{ name }}<div *ngIf="showing" dir></div>'}) class MyApp { - @ViewChild(Dir) dir !: Dir; + @ViewChild(Dir) dir!: Dir; showing = true; name = 'Amelia'; } @@ -642,21 +651,30 @@ describe('change detection', () => { @Component({template: '<child-comp [inp]="true"></child-comp>'}) class ParentComp { constructor(public cdr: ChangeDetectorRef) {} - triggerChangeDetection() { this.cdr.detectChanges(); } + triggerChangeDetection() { + this.cdr.detectChanges(); + } } @Component({template: '{{inp}}', selector: 'child-comp'}) class ChildComp { - @Input() - inp: any = ''; + @Input() inp: any = ''; count = 0; constructor(public parentComp: ParentComp) {} - ngOnInit() { this.check('OnInit'); } - ngAfterContentInit() { this.check('AfterContentInit'); } - ngAfterViewInit() { this.check('AfterViewInit'); } - ngOnChanges() { this.check('OnChanges'); } + ngOnInit() { + this.check('OnInit'); + } + ngAfterContentInit() { + this.check('AfterContentInit'); + } + ngAfterViewInit() { + this.check('AfterViewInit'); + } + ngOnChanges() { + this.check('OnChanges'); + } check(h: string) { if (h === hook) { @@ -704,8 +722,7 @@ describe('change detection', () => { ` }) class App { - @ViewChildren('ref') - ref !: QueryList<any>; + @ViewChildren('ref') ref!: QueryList<any>; visible = false; @@ -737,13 +754,14 @@ describe('change detection', () => { describe('dynamic views', () => { @Component({selector: 'structural-comp', template: '{{ value }}'}) class StructuralComp { - @Input() - tmp !: TemplateRef<any>; + @Input() tmp!: TemplateRef<any>; value = 'one'; constructor(public vcr: ViewContainerRef) {} - create() { return this.vcr.createEmbeddedView(this.tmp, {ctx: this}); } + create() { + return this.vcr.createEmbeddedView(this.tmp, {ctx: this}); + } } it('should support ViewRef.detectChanges()', () => { @@ -752,7 +770,7 @@ describe('change detection', () => { '<ng-template #foo let-ctx="ctx">{{ ctx.value }}</ng-template><structural-comp [tmp]="foo"></structural-comp>' }) class App { - @ViewChild(StructuralComp) structuralComp !: StructuralComp; + @ViewChild(StructuralComp) structuralComp!: StructuralComp; } TestBed.configureTestingModule({declarations: [App, StructuralComp]}); @@ -781,7 +799,7 @@ describe('change detection', () => { template: '<ng-template #foo>Template text</ng-template><structural-comp [tmp]="foo">' }) class App { - @ViewChild(StructuralComp) structuralComp !: StructuralComp; + @ViewChild(StructuralComp) structuralComp!: StructuralComp; } TestBed.configureTestingModule({declarations: [App, StructuralComp]}); @@ -794,9 +812,7 @@ describe('change detection', () => { viewRef.detectChanges(); expect(fixture.nativeElement.textContent).toEqual('oneTemplate text'); }); - }); - }); describe('attach/detach', () => { @@ -807,12 +823,14 @@ describe('change detection', () => { constructor(public cdr: ChangeDetectorRef) {} - ngDoCheck() { this.doCheckCount++; } + ngDoCheck() { + this.doCheckCount++; + } } @Component({template: '<detached-comp></detached-comp>'}) class MyApp { - @ViewChild(DetachedComp) comp !: DetachedComp; + @ViewChild(DetachedComp) comp!: DetachedComp; constructor(public cdr: ChangeDetectorRef) {} } @@ -908,22 +926,20 @@ describe('change detection', () => { }); it('should detach OnPush components properly', () => { - @Component({ selector: 'on-push-comp', template: '{{ value }}', changeDetection: ChangeDetectionStrategy.OnPush }) class OnPushComp { - @Input() - value !: string; + @Input() value!: string; constructor(public cdr: ChangeDetectorRef) {} } @Component({template: '<on-push-comp [value]="value"></on-push-comp>'}) class OnPushApp { - @ViewChild(OnPushComp) onPushComp !: OnPushComp; + @ViewChild(OnPushComp) onPushComp!: OnPushComp; value = ''; } @@ -946,7 +962,6 @@ describe('change detection', () => { fixture.detectChanges(); expect(fixture.nativeElement.textContent).toEqual('two'); }); - }); describe('markForCheck()', () => { @@ -962,7 +977,9 @@ describe('change detection', () => { constructor(public cdr: ChangeDetectorRef) {} - ngDoCheck() { this.doCheckCount++; } + ngDoCheck() { + this.doCheckCount++; + } } @Component({ @@ -970,7 +987,7 @@ describe('change detection', () => { changeDetection: ChangeDetectionStrategy.OnPush }) class OnPushParent { - @ViewChild(OnPushComp) comp !: OnPushComp; + @ViewChild(OnPushComp) comp!: OnPushComp; value = 'one'; } @@ -1023,7 +1040,6 @@ describe('change detection', () => { fixture.componentInstance.comp.cdr.markForCheck(); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toEqual('two - one'); - }); it('should ensure OnPush components in embedded views are checked', () => { @@ -1032,7 +1048,7 @@ describe('change detection', () => { changeDetection: ChangeDetectionStrategy.OnPush }) class EmbeddedViewParent { - @ViewChild(OnPushComp) comp !: OnPushComp; + @ViewChild(OnPushComp) comp!: OnPushComp; value = 'one'; showing = true; } @@ -1112,13 +1128,21 @@ describe('change detection', () => { contentCheckCount = 0; viewCheckCount = 0; - ngDoCheck() { this.doCheckCount++; } + ngDoCheck() { + this.doCheckCount++; + } - ngAfterContentChecked() { this.contentCheckCount++; } + ngAfterContentChecked() { + this.contentCheckCount++; + } - ngAfterViewChecked() { this.viewCheckCount++; } + ngAfterViewChecked() { + this.viewCheckCount++; + } - constructor(public cdr: ChangeDetectorRef) { comp = this; } + constructor(public cdr: ChangeDetectorRef) { + comp = this; + } } @Component({template: '{{ value }} - <no-changes-comp></no-changes-comp>'}) @@ -1131,7 +1155,9 @@ describe('change detection', () => { // Custom error handler that just rethrows all the errors from the // view, rather than logging them out. Used to keep our logs clean. class RethrowErrorHandler extends ErrorHandler { - handleError(error: any) { throw error; } + handleError(error: any) { + throw error; + } } it('should throw if bindings in current view have changed', () => { @@ -1141,7 +1167,9 @@ describe('change detection', () => { }); const fixture = TestBed.createComponent(NoChangesComp); - expect(() => { fixture.componentInstance.cdr.checkNoChanges(); }) + expect(() => { + fixture.componentInstance.cdr.checkNoChanges(); + }) .toThrowError( /ExpressionChangedAfterItHasBeenCheckedError: .+ Previous value: '.*undefined'. Current value: '.*1'/gi); }); @@ -1196,9 +1224,7 @@ describe('change detection', () => { expect(comp.contentCheckCount).toEqual(1); expect(comp.viewCheckCount).toEqual(1); }); - }); - }); describe('transplanted views', () => { @@ -1216,13 +1242,20 @@ describe('change detection', () => { </div> ` }) - class InsertComp implements DoCheck, - AfterViewChecked { - get template(): TemplateRef<any> { return declareComp.myTmpl; } + class InsertComp implements DoCheck, AfterViewChecked { + get template(): TemplateRef<any> { + return declareComp.myTmpl; + } greeting: string = 'Hello'; - constructor(public changeDetectorRef: ChangeDetectorRef) { insertComp = this; } - ngDoCheck(): void { logValue = 'Insert'; } - ngAfterViewChecked(): void { logValue = null; } + constructor(public changeDetectorRef: ChangeDetectorRef) { + insertComp = this; + } + ngDoCheck(): void { + logValue = 'Insert'; + } + ngAfterViewChecked(): void { + logValue = null; + } } @Component({ @@ -1234,20 +1267,24 @@ describe('change detection', () => { </ng-template> ` }) - class DeclareComp implements DoCheck, - AfterViewChecked { - @ViewChild('myTmpl') - myTmpl !: TemplateRef<any>; + class DeclareComp implements DoCheck, AfterViewChecked { + @ViewChild('myTmpl') myTmpl!: TemplateRef<any>; name: string = 'world'; - constructor() { declareComp = this; } - ngDoCheck(): void { logValue = 'Declare'; } + constructor() { + declareComp = this; + } + ngDoCheck(): void { + logValue = 'Declare'; + } logName() { // This will log when the embedded view gets CD. The `logValue` will show if the CD was from // `Insert` or from `Declare` component. - log.push(logValue !); + log.push(logValue!); return this.name; } - ngAfterViewChecked(): void { logValue = null; } + ngAfterViewChecked(): void { + logValue = null; + } } @Component({ @@ -1259,15 +1296,17 @@ describe('change detection', () => { class AppComp { showDeclare: boolean = true; showInsert: boolean = true; - constructor() { appComp = this; } + constructor() { + appComp = this; + } } - let log !: string[]; - let logValue !: string | null; - let fixture !: ComponentFixture<AppComp>; - let appComp !: AppComp; - let insertComp !: InsertComp; - let declareComp !: DeclareComp; + let log!: string[]; + let logValue!: string|null; + let fixture!: ComponentFixture<AppComp>; + let appComp!: AppComp; + let insertComp!: InsertComp; + let declareComp!: DeclareComp; beforeEach(() => { TestBed.configureTestingModule({ @@ -1376,16 +1415,16 @@ describe('change detection', () => { class OnPushComp { text = 'initial'; - constructor(private _cdRef: ChangeDetectorRef){} + constructor(private _cdRef: ChangeDetectorRef) {} - [hookName]() { + [hookName]() { this._cdRef.markForCheck(); } } @Component({template: `<on-push-comp></on-push-comp>`}) class TestApp { - @ViewChild(OnPushComp) onPushComp !: OnPushComp; + @ViewChild(OnPushComp) onPushComp!: OnPushComp; } TestBed.configureTestingModule( @@ -1419,16 +1458,16 @@ describe('change detection', () => { class OnPushComp { text = 'initial'; - constructor(private _cdRef: ChangeDetectorRef){} + constructor(private _cdRef: ChangeDetectorRef) {} - [hookName]() { + [hookName]() { this._cdRef.markForCheck(); } } @Component({template: `<on-push-comp></on-push-comp>`}) class TestApp { - @ViewChild(OnPushComp) onPushComp !: OnPushComp; + @ViewChild(OnPushComp) onPushComp!: OnPushComp; } TestBed.configureTestingModule( @@ -1478,7 +1517,9 @@ describe('change detection', () => { return fixture; } - function initWithTemplate(template: string) { return initComponent({template}); } + function initWithTemplate(template: string) { + return initComponent({template}); + } function initWithHostBindings(bindings: {[key: string]: string}) { return initComponent({host: bindings}); } @@ -1612,6 +1653,6 @@ describe('change detection', () => { }); }); -function trim(text: string | null): string { +function trim(text: string|null): string { return text ? text.replace(/[\s\n]+/gm, ' ').trim() : ''; } diff --git a/packages/core/test/acceptance/common_integration_spec.ts b/packages/core/test/acceptance/common_integration_spec.ts index 14615fb8f6100..307d8da888e32 100644 --- a/packages/core/test/acceptance/common_integration_spec.ts +++ b/packages/core/test/acceptance/common_integration_spec.ts @@ -11,7 +11,6 @@ import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; describe('@angular/common integration', () => { - describe('NgForOf', () => { @Directive({selector: '[dir]'}) class MyDirective { @@ -244,7 +243,9 @@ describe('@angular/common integration', () => { name = 'app'; events: string[] = []; - onClick(value: string, name: string) { this.events.push(value, name); } + onClick(value: string, name: string) { + this.events.push(value, name); + } } TestBed.configureTestingModule({declarations: [MultiLevelWithListenerComponent]}); @@ -485,7 +486,6 @@ describe('@angular/common integration', () => { }); describe('NgTemplateOutlet', () => { - it('should create and remove embedded views', () => { @Component({ selector: 'app-multi', diff --git a/packages/core/test/acceptance/component_spec.ts b/packages/core/test/acceptance/component_spec.ts index 352cb57ce841a..dfb34d294a4a6 100644 --- a/packages/core/test/acceptance/component_spec.ts +++ b/packages/core/test/acceptance/component_spec.ts @@ -28,7 +28,9 @@ describe('component', () => { providers: [{provide: testToken, useExisting: ParentWithOnDestroy}] }) class ParentWithOnDestroy { - ngOnDestroy() { destroyCalls++; } + ngOnDestroy() { + destroyCalls++; + } } @Component({selector: 'child', template: ''}) @@ -75,7 +77,7 @@ describe('component', () => { entryComponents: [OtherComponent] }) class TestComponent { - @ViewChild('vc', {read: ViewContainerRef, static: true}) vcref !: ViewContainerRef; + @ViewChild('vc', {read: ViewContainerRef, static: true}) vcref!: ViewContainerRef; constructor(private _cfr: ComponentFactoryResolver) {} @@ -152,7 +154,8 @@ describe('component', () => { expect(match).toBeDefined(); expect(match.length).toEqual(2); expect(html).toMatch( - `<leaf ${match[0].replace('_nghost', '_ngcontent')}="" ${match[1]}=""><span ${match[1].replace('_nghost', '_ngcontent')}="">bar</span></leaf></div>`); + `<leaf ${match[0].replace('_nghost', '_ngcontent')}="" ${match[1]}=""><span ${ + match[1].replace('_nghost', '_ngcontent')}="">bar</span></leaf></div>`); }); }); @@ -162,7 +165,9 @@ describe('component', () => { @Component({selector: 'comp-with-destroy', template: ``}) class ComponentWithOnDestroy implements OnDestroy { - ngOnDestroy() { wasOnDestroyCalled = true; } + ngOnDestroy() { + wasOnDestroyCalled = true; + } } // This test asserts that the view tree is set up correctly based on the knowledge that this @@ -244,7 +249,7 @@ describe('component', () => { encapsulation: ViewEncapsulation.Emulated, }) class Parent { - @ViewChild(Child) childInstance !: Child; + @ViewChild(Child) childInstance!: Child; constructor(public renderer: Renderer2) {} } @@ -266,7 +271,9 @@ describe('component', () => { }) class CompA { @Input() a: string = ''; - ngDoCheck() { log.push('CompA:ngDoCheck'); } + ngDoCheck() { + log.push('CompA:ngDoCheck'); + } } @Component({ @@ -275,7 +282,9 @@ describe('component', () => { }) class CompB { @Input() b: string = ''; - ngDoCheck() { log.push('CompB:ngDoCheck'); } + ngDoCheck() { + log.push('CompB:ngDoCheck'); + } } @Component({template: `<span></span>`}) @@ -435,14 +444,14 @@ describe('component', () => { fixture.detectChanges(); // Create an instance of DynamicComponent and provide host element *reference* - let targetEl = document.getElementById('dynamic-comp-root-a') !; + let targetEl = document.getElementById('dynamic-comp-root-a')!; fixture.componentInstance.createDynamicComponent(targetEl); fixture.detectChanges(); expect(targetEl.innerHTML).not.toContain('Existing content in slot A'); expect(targetEl.innerHTML).toContain('DynamicComponent Content'); // Create an instance of DynamicComponent and provide host element *selector* - targetEl = document.getElementById('dynamic-comp-root-b') !; + targetEl = document.getElementById('dynamic-comp-root-b')!; fixture.componentInstance.createDynamicComponent('#dynamic-comp-root-b'); fixture.detectChanges(); expect(targetEl.innerHTML).not.toContain('Existing content in slot B'); @@ -453,7 +462,8 @@ describe('component', () => { () => runTestWithRenderer([{provide: RendererFactory2, useClass: DomRendererFactory2}])); onlyInIvy('Renderer3 is supported only in Ivy') - .it('with Renderer3', () => runTestWithRenderer( - [{provide: RendererFactory2, useValue: domRendererFactory3}])); + .it('with Renderer3', + () => + runTestWithRenderer([{provide: RendererFactory2, useValue: domRendererFactory3}])); }); }); diff --git a/packages/core/test/acceptance/content_spec.ts b/packages/core/test/acceptance/content_spec.ts index 9aef0532a49d7..d9116753c6386 100644 --- a/packages/core/test/acceptance/content_spec.ts +++ b/packages/core/test/acceptance/content_spec.ts @@ -14,7 +14,6 @@ import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('projection', () => { - function getElementHtml(element: HTMLElement) { return element.innerHTML.replace(/<!--(\W|\w)*?-->/g, '') .replace(/\sng-reflect-\S*="[^"]*"/g, ''); @@ -328,11 +327,13 @@ describe('projection', () => { @Directive({selector: '[trigger]'}) class Trigger { - @Input() trigger !: Comp; + @Input() trigger!: Comp; constructor(public vcr: ViewContainerRef) {} - open() { this.vcr.createEmbeddedView(this.trigger.template); } + open() { + this.vcr.createEmbeddedView(this.trigger.template); + } } @Component({ @@ -861,7 +862,6 @@ describe('projection', () => { expect(getElementHtml(fixture.nativeElement)) .toEqual('<child><span title="Some title">Has title</span></child>'); - }); it('should match selectors against projected containers', () => { @@ -934,7 +934,9 @@ describe('projection', () => { it('should project content if the change detector has been detached', () => { @Component({selector: 'my-comp', template: '<ng-content></ng-content>'}) class MyComp { - constructor(changeDetectorRef: ChangeDetectorRef) { changeDetectorRef.detach(); } + constructor(changeDetectorRef: ChangeDetectorRef) { + changeDetectorRef.detach(); + } } @Component({ @@ -1108,7 +1110,9 @@ describe('projection', () => { @Directive({selector: 'div'}) class DivDirective { - constructor() { divDirectives++; } + constructor() { + divDirectives++; + } } @Component({ @@ -1135,7 +1139,9 @@ describe('projection', () => { @Directive({selector: '[x]'}) class XDirective { - constructor() { xDirectives++; } + constructor() { + xDirectives++; + } } @Component({ @@ -1162,7 +1168,9 @@ describe('projection', () => { @Directive({selector: '.x'}) class XDirective { - constructor() { xDirectives++; } + constructor() { + xDirectives++; + } } @Component({ @@ -1199,7 +1207,9 @@ describe('projection', () => { {id: 2, name: 'two'}, {id: 3, name: 'three'}, ]; - getItemId(item: {id: number}) { return item.id; } + getItemId(item: {id: number}) { + return item.id; + } } TestBed.configureTestingModule({declarations: [SelectedNgContentComp, SelectorMainComp]}); @@ -1265,7 +1275,9 @@ describe('projection', () => { @Directive({selector: '[x]'}) class XDirective { - constructor() { xDirectives++; } + constructor() { + xDirectives++; + } } @Component({ @@ -1293,7 +1305,9 @@ describe('projection', () => { @Directive({selector: '.x'}) class XDirective { - constructor() { xDirectives++; } + constructor() { + xDirectives++; + } } @Component({ diff --git a/packages/core/test/acceptance/copy_definition_feature_spec.ts b/packages/core/test/acceptance/copy_definition_feature_spec.ts index ea4c220c70179..c200ad6f41e4f 100644 --- a/packages/core/test/acceptance/copy_definition_feature_spec.ts +++ b/packages/core/test/acceptance/copy_definition_feature_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, NgModule, ɵɵCopyDefinitionFeature as CopyDefinitionFeature, ɵɵInheritDefinitionFeature as InheritDefinitionFeature, ɵɵdefineComponent as defineComponent} from '@angular/core'; +import {Component, NgModule, ɵɵCopyDefinitionFeature as CopyDefinitionFeature, ɵɵdefineComponent as defineComponent, ɵɵInheritDefinitionFeature as InheritDefinitionFeature} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {onlyInIvy} from '@angular/private/testing'; @@ -14,20 +14,22 @@ describe('Ivy CopyDefinitionFeature', () => { onlyInIvy('this feature is not required in View Engine') .it('should copy the template function of a component definition from parent to child', () => { - // It would be nice if the base component could be JIT compiled. However, this creates // a getter for ɵcmp which precludes adding a static definition of that field for the // child class. // TODO(alxhub): see if there's a cleaner way to do this. class BaseComponent { - name !: string; + name!: string; static ɵcmp = defineComponent({ type: BaseComponent, selectors: [['some-cmp']], decls: 0, vars: 0, inputs: {name: 'name'}, - template: function BaseComponent_Template(rf, ctx) { ctx.rendered = true; }, + template: + function BaseComponent_Template(rf, ctx) { + ctx.rendered = true; + }, encapsulation: 2 }); static ɵfac = function BaseComponent_Factory(t: any) { diff --git a/packages/core/test/acceptance/debug_spec.ts b/packages/core/test/acceptance/debug_spec.ts index d4bfa91531d79..5cdb0ea011e47 100644 --- a/packages/core/test/acceptance/debug_spec.ts +++ b/packages/core/test/acceptance/debug_spec.ts @@ -14,9 +14,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; import {onlyInIvy} from '@angular/private/testing'; describe('Debug Representation', () => { - onlyInIvy('Ivy specific').it('should generate a human readable version', () => { - @Component({selector: 'my-comp', template: '<div id="123">Hello World</div>'}) class MyComponent { } @@ -25,11 +23,11 @@ describe('Debug Representation', () => { const fixture = TestBed.createComponent(MyComponent); fixture.detectChanges(); - const hostView = toDebug(getLContext(fixture.componentInstance) !.lView); + const hostView = toDebug(getLContext(fixture.componentInstance)!.lView); expect(hostView.host).toEqual(null); const myCompView = hostView.childViews[0] as LViewDebug; expect(myCompView.host).toContain('<div id="123">Hello World</div>'); - expect(myCompView.nodes ![0].html).toEqual('<div id="123">'); - expect(myCompView.nodes ![0].nodes ![0].html).toEqual('Hello World'); + expect(myCompView.nodes![0].html).toEqual('<div id="123">'); + expect(myCompView.nodes![0].nodes![0].html).toEqual('Hello World'); }); }); diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts index 23d319de03617..31e7c1a1dd1a1 100644 --- a/packages/core/test/acceptance/di_spec.ts +++ b/packages/core/test/acceptance/di_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, Host, HostBinding, INJECTOR, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, forwardRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core'; +import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, forwardRef, Host, HostBinding, Inject, Injectable, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core'; import {ɵINJECTOR_SCOPE} from '@angular/core/src/core'; import {ViewRef} from '@angular/core/src/render3/view_ref'; import {TestBed} from '@angular/core/testing'; @@ -60,14 +60,15 @@ describe('di', () => { }); describe('directive injection', () => { - let log: string[] = []; @Directive({selector: '[dirB]', exportAs: 'dirB'}) class DirectiveB { @Input() value = 'DirB'; - constructor() { log.push(this.value); } + constructor() { + log.push(this.value); + } } beforeEach(() => log = []); @@ -82,7 +83,9 @@ describe('di', () => { class DirectiveC { value: string; - constructor(dirA: DirectiveA, dirB: DirectiveB) { this.value = dirA.value + dirB.value; } + constructor(dirA: DirectiveA, dirB: DirectiveB) { + this.value = dirA.value + dirB.value; + } } @Component({ @@ -108,7 +111,9 @@ describe('di', () => { class DirectiveA { value = 'dirA'; - constructor(dirB: DirectiveB) { log.push(`DirA (dep: ${dirB.value})`); } + constructor(dirB: DirectiveB) { + log.push(`DirA (dep: ${dirB.value})`); + } } @Component({template: '<div dirA dirB></div>'}) @@ -127,7 +132,9 @@ describe('di', () => { class DirectiveA { value = 'dirA'; - constructor(dirB: DirectiveB) { log.push(`DirA (dep: ${dirB.value})`); } + constructor(dirB: DirectiveB) { + log.push(`DirA (dep: ${dirB.value})`); + } } // - dirB is know to the node injectors @@ -150,7 +157,9 @@ describe('di', () => { it('should instantiate injected directives before components', () => { @Component({selector: 'my-comp', template: ''}) class MyComp { - constructor(dirB: DirectiveB) { log.push(`Comp (dep: ${dirB.value})`); } + constructor(dirB: DirectiveB) { + log.push(`Comp (dep: ${dirB.value})`); + } } @Component({template: '<my-comp dirB></my-comp>'}) @@ -167,7 +176,9 @@ describe('di', () => { it('should inject directives in the correct order in a for loop', () => { @Directive({selector: '[dirA]'}) class DirectiveA { - constructor(dir: DirectiveB) { log.push(`DirA (dep: ${dir.value})`); } + constructor(dir: DirectiveB) { + log.push(`DirA (dep: ${dir.value})`); + } } @Component({template: '<div dirA dirB *ngFor="let i of array"></div>'}) @@ -188,14 +199,18 @@ describe('di', () => { class DirectiveA { value = 'DirA'; - constructor() { log.push(this.value); } + constructor() { + log.push(this.value); + } } @Directive({selector: '[dirC]'}) class DirectiveC { value = 'DirC'; - constructor() { log.push(this.value); } + constructor() { + log.push(this.value); + } } @Directive({selector: '[dirB]'}) @@ -221,26 +236,34 @@ describe('di', () => { class DirectiveC { value = 'DirC'; - constructor(dirB: DirectiveB) { log.push(`DirC (dep: ${dirB.value})`); } + constructor(dirB: DirectiveB) { + log.push(`DirC (dep: ${dirB.value})`); + } } @Directive({selector: '[dirA]'}) class DirectiveA { value = 'DirA'; - constructor(dirC: DirectiveC) { log.push(`DirA (dep: ${dirC.value})`); } + constructor(dirC: DirectiveC) { + log.push(`DirA (dep: ${dirC.value})`); + } } @Directive({selector: '[dirD]'}) class DirectiveD { value = 'DirD'; - constructor(dirA: DirectiveA) { log.push(`DirD (dep: ${dirA.value})`); } + constructor(dirA: DirectiveA) { + log.push(`DirD (dep: ${dirA.value})`); + } } @Component({selector: 'my-comp', template: ''}) class MyComp { - constructor(dirD: DirectiveD) { log.push(`Comp (dep: ${dirD.value})`); } + constructor(dirD: DirectiveD) { + log.push(`Comp (dep: ${dirD.value})`); + } } @Component({template: '<my-comp dirA dirB dirC dirD></my-comp>'}) @@ -291,7 +314,9 @@ describe('di', () => { @Directive({selector: '[dirA]'}) class DirectiveA { - constructor(dirB: DirectiveB) { log.push(`DirA (dep: DirB - ${dirB.count})`); } + constructor(dirB: DirectiveB) { + log.push(`DirA (dep: DirB - ${dirB.count})`); + } } @Component({selector: 'my-comp', template: '<div dirA dirB></div>'}) @@ -310,7 +335,6 @@ describe('di', () => { }); describe('dependencies in parent views', () => { - @Directive({selector: '[dirA]', exportAs: 'dirA'}) class DirectiveA { injector: Injector; @@ -385,11 +409,13 @@ describe('di', () => { it('should find dependencies in declaration tree of ng-template (not insertion tree)', () => { @Directive({selector: '[structuralDir]'}) class StructuralDirective { - @Input() tmp !: TemplateRef<any>; + @Input() tmp!: TemplateRef<any>; constructor(public vcr: ViewContainerRef) {} - create() { this.vcr.createEmbeddedView(this.tmp); } + create() { + this.vcr.createEmbeddedView(this.tmp); + } } @Component({ @@ -405,7 +431,7 @@ describe('di', () => { </div>` }) class MyComp { - @ViewChild(StructuralDirective) structuralDir !: StructuralDirective; + @ViewChild(StructuralDirective) structuralDir!: StructuralDirective; } TestBed.configureTestingModule( @@ -449,8 +475,8 @@ describe('di', () => { </div>` }) class MyApp { - @ViewChild(HostBindingDirective) hostBindingDir !: HostBindingDirective; - @ViewChild(DirectiveA) dirA !: DirectiveA; + @ViewChild(HostBindingDirective) hostBindingDir!: HostBindingDirective; + @ViewChild(DirectiveA) dirA!: DirectiveA; } TestBed.configureTestingModule( @@ -501,15 +527,19 @@ describe('di', () => { }) class MyApp { @ViewChild('childOrigin', {read: ViewContainerRef, static: true}) - childOrigin !: ViewContainerRef; + childOrigin!: ViewContainerRef; @ViewChild('childOriginWithDirB', {read: ViewContainerRef, static: true}) - childOriginWithDirB !: ViewContainerRef; + childOriginWithDirB!: ViewContainerRef; childFactory = this.resolver.resolveComponentFactory(Child); constructor(readonly resolver: ComponentFactoryResolver, readonly injector: Injector) {} - addChild() { return this.childOrigin.createComponent(this.childFactory); } - addChildWithDirB() { return this.childOriginWithDirB.createComponent(this.childFactory); } + addChild() { + return this.childOrigin.createComponent(this.childFactory); + } + addChildWithDirB() { + return this.childOriginWithDirB.createComponent(this.childFactory); + } } const fixture = @@ -604,24 +634,21 @@ describe('di', () => { }); describe('flags', () => { - @Directive({selector: '[dirB]'}) class DirectiveB { @Input('dirB') value = ''; } describe('Optional', () => { - @Directive({selector: '[dirA]'}) class DirectiveA { constructor(@Optional() public dirB: DirectiveB) {} } it('should not throw if dependency is @Optional (module injector)', () => { - @Component({template: '<div dirA></div>'}) class MyComp { - @ViewChild(DirectiveA) dirA !: DirectiveA; + @ViewChild(DirectiveA) dirA!: DirectiveA; } TestBed.configureTestingModule({declarations: [DirectiveA, DirectiveB, MyComp]}); @@ -633,7 +660,6 @@ describe('di', () => { }); it('should return null if @Optional dependency has @Self flag', () => { - @Directive({selector: '[dirC]'}) class DirectiveC { constructor(@Optional() @Self() public dirB: DirectiveB) {} @@ -641,7 +667,7 @@ describe('di', () => { @Component({template: '<div dirC></div>'}) class MyComp { - @ViewChild(DirectiveC) dirC !: DirectiveC; + @ViewChild(DirectiveC) dirC!: DirectiveC; } TestBed.configureTestingModule({declarations: [DirectiveC, MyComp]}); @@ -653,7 +679,6 @@ describe('di', () => { }); it('should not throw if dependency is @Optional but defined elsewhere', () => { - @Directive({selector: '[dirC]'}) class DirectiveC { constructor(@Optional() public dirB: DirectiveB) {} @@ -661,7 +686,7 @@ describe('di', () => { @Component({template: '<div dirB></div><div dirC></div>'}) class MyComp { - @ViewChild(DirectiveC) dirC !: DirectiveC; + @ViewChild(DirectiveC) dirC!: DirectiveC; } TestBed.configureTestingModule({declarations: [DirectiveB, DirectiveC, MyComp]}); @@ -674,7 +699,6 @@ describe('di', () => { }); it('should skip the current node with @SkipSelf', () => { - @Directive({selector: '[dirA]'}) class DirectiveA { constructor(@SkipSelf() public dirB: DirectiveB) {} @@ -682,12 +706,12 @@ describe('di', () => { @Component({selector: 'my-comp', template: '<div dirA dirB="self"></div>'}) class MyComp { - @ViewChild(DirectiveA) dirA !: DirectiveA; + @ViewChild(DirectiveA) dirA!: DirectiveA; } @Component({template: '<my-comp dirB="parent"></my-comp>'}) class MyApp { - @ViewChild(MyComp) myComp !: MyComp; + @ViewChild(MyComp) myComp!: MyComp; } TestBed.configureTestingModule({declarations: [DirectiveA, DirectiveB, MyComp, MyApp]}); @@ -700,7 +724,6 @@ describe('di', () => { onlyInIvy('Ivy has different error message when dependency is not found') .it('should check only the current node with @Self', () => { - @Directive({selector: '[dirA]'}) class DirectiveA { constructor(@Self() public dirB: DirectiveB) {} @@ -732,12 +755,12 @@ describe('di', () => { viewProviders: [{provide: String, useValue: 'Foo'}] }) class MyComp { - @ViewChild(DirectiveString) dirString !: DirectiveString; + @ViewChild(DirectiveString) dirString!: DirectiveString; } @Component({template: '<my-comp></my-comp>'}) class MyApp { - @ViewChild(MyComp) myComp !: MyComp; + @ViewChild(MyComp) myComp!: MyComp; } TestBed.configureTestingModule({declarations: [DirectiveString, MyComp, MyApp]}); @@ -756,12 +779,12 @@ describe('di', () => { @Component({selector: 'my-comp', template: '<div dirComp></div>'}) class MyComp { - @ViewChild(DirectiveComp) dirComp !: DirectiveComp; + @ViewChild(DirectiveComp) dirComp!: DirectiveComp; } @Component({template: '<my-comp></my-comp>'}) class MyApp { - @ViewChild(MyComp) myComp !: MyComp; + @ViewChild(MyComp) myComp!: MyComp; } TestBed.configureTestingModule({declarations: [DirectiveComp, MyComp, MyApp]}); @@ -820,7 +843,7 @@ describe('di', () => { @Component({template: '<my-comp dirB></my-comp>'}) class MyApp { - @ViewChild(MyComp) myComp !: MyComp; + @ViewChild(MyComp) myComp!: MyComp; } TestBed.configureTestingModule( @@ -837,8 +860,8 @@ describe('di', () => { @Component({template: '<div dirB><div *ngIf="showing" dirA></div></div>'}) class MyApp { showing = false; - @ViewChild(DirectiveA) dirA !: DirectiveA; - @ViewChild(DirectiveB) dirB !: DirectiveB; + @ViewChild(DirectiveA) dirA!: DirectiveA; + @ViewChild(DirectiveB) dirB!: DirectiveB; } TestBed.configureTestingModule({declarations: [DirectiveA, DirectiveB, MyApp]}); @@ -885,7 +908,9 @@ describe('di', () => { providers: [{provide: ControlContainer, useExisting: GroupDirective}] }) class GroupDirective { - constructor() { controlContainers.push(this); } + constructor() { + controlContainers.push(this); + } } @Directive({selector: '[control]'}) @@ -919,7 +944,7 @@ describe('di', () => { const fixture = TestBed.createComponent(MyApp); expect(fixture.nativeElement.innerHTML) .toBe('<div group=""><my-comp><input control=""></my-comp></div>'); - expect(controlContainers).toEqual([injectedControlContainer !]); + expect(controlContainers).toEqual([injectedControlContainer!]); }); }); }); @@ -958,7 +983,6 @@ describe('di', () => { }); describe('service injection', () => { - it('should create instance even when no injector present', () => { @Injectable({providedIn: 'root'}) class MyService { @@ -1063,7 +1087,6 @@ describe('di', () => { expect(fixture.componentInstance.myService instanceof MyService).toBe(true); expect(fixture.componentInstance.myOtherService instanceof MyOtherService).toBe(true); }); - }); describe('service injection with useClass', () => { @@ -1075,7 +1098,9 @@ describe('di', () => { @Injectable({providedIn: 'root'}) class BarService { constructor(public dep: BarServiceDep) {} - getMessage() { return 'bar'; } + getMessage() { + return 'bar'; + } } @Injectable({providedIn: 'root'}) @@ -1086,7 +1111,9 @@ describe('di', () => { @Injectable({providedIn: 'root', useClass: BarService}) class FooService { constructor(public dep: FooServiceDep) {} - getMessage() { return 'foo'; } + getMessage() { + return 'foo'; + } } it('should use @Injectable useClass config when token is not provided', () => { @@ -1094,18 +1121,20 @@ describe('di', () => { @Component({template: ''}) class App { - constructor(service: FooService) { provider = service; } + constructor(service: FooService) { + provider = service; + } } TestBed.configureTestingModule({declarations: [App]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(provider !.getMessage()).toBe('bar'); + expect(provider!.getMessage()).toBe('bar'); // ViewEngine incorrectly uses the original class DI config, instead of the one from useClass. if (ivyEnabled) { - expect(provider !.dep.name).toBe('BarServiceDep'); + expect(provider!.dep.name).toBe('BarServiceDep'); } }); @@ -1115,7 +1144,9 @@ describe('di', () => { @Component({template: ''}) class App { - constructor(service: FooService) { provider = service; } + constructor(service: FooService) { + provider = service; + } } TestBed.configureTestingModule( @@ -1123,7 +1154,7 @@ describe('di', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(provider !.getMessage()).toBe('foo'); + expect(provider!.getMessage()).toBe('foo'); }); @@ -1144,13 +1175,13 @@ describe('di', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(directProvider !.getMessage()).toBe('bar'); - expect(overriddenProvider !.getMessage()).toBe('foo'); + expect(directProvider!.getMessage()).toBe('bar'); + expect(overriddenProvider!.getMessage()).toBe('foo'); // ViewEngine incorrectly uses the original class DI config, instead of the one from useClass. if (ivyEnabled) { - expect(directProvider !.dep.name).toBe('BarServiceDep'); - expect(overriddenProvider !.dep.name).toBe('FooServiceDep'); + expect(directProvider!.dep.name).toBe('BarServiceDep'); + expect(overriddenProvider!.dep.name).toBe('FooServiceDep'); } }); @@ -1160,20 +1191,21 @@ describe('di', () => { @Component({template: ''}) class App { - constructor(service: FooService) { provider = service; } + constructor(service: FooService) { + provider = service; + } } TestBed.configureTestingModule({declarations: [App], providers: [FooService]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(provider !.getMessage()).toBe('foo'); - expect(provider !.dep.name).toBe('FooServiceDep'); + expect(provider!.getMessage()).toBe('foo'); + expect(provider!.dep.name).toBe('FooServiceDep'); }); }); describe('inject', () => { - it('should inject from parent view', () => { @Directive({selector: '[parentDir]'}) class ParentDirective { @@ -1182,7 +1214,9 @@ describe('di', () => { @Directive({selector: '[childDir]', exportAs: 'childDir'}) class ChildDirective { value: string; - constructor(public parent: ParentDirective) { this.value = parent.constructor.name; } + constructor(public parent: ParentDirective) { + this.value = parent.constructor.name; + } } @Directive({selector: '[child2Dir]', exportAs: 'child2Dir'}) @@ -1214,9 +1248,7 @@ describe('di', () => { }); describe('Special tokens', () => { - describe('Injector', () => { - it('should inject the injector', () => { @Directive({selector: '[injectorDir]'}) class InjectorDir { @@ -1230,8 +1262,8 @@ describe('di', () => { @Component({template: '<div injectorDir otherInjectorDir></div>'}) class MyComp { - @ViewChild(InjectorDir) injectorDir !: InjectorDir; - @ViewChild(OtherInjectorDir) otherInjectorDir !: OtherInjectorDir; + @ViewChild(InjectorDir) injectorDir!: InjectorDir; + @ViewChild(OtherInjectorDir) otherInjectorDir!: OtherInjectorDir; } TestBed.configureTestingModule({declarations: [InjectorDir, OtherInjectorDir, MyComp]}); @@ -1256,7 +1288,7 @@ describe('di', () => { @Component({template: '<div injectorDir></div>'}) class MyComp { - @ViewChild(InjectorDir) injectorDir !: InjectorDir; + @ViewChild(InjectorDir) injectorDir!: InjectorDir; } TestBed.configureTestingModule({declarations: [InjectorDir, MyComp]}); @@ -1273,7 +1305,6 @@ describe('di', () => { }); describe('ElementRef', () => { - it('should create directive with ElementRef dependencies', () => { @Directive({selector: '[dir]'}) class MyDir { @@ -1293,8 +1324,8 @@ describe('di', () => { @Component({template: '<div dir otherDir></div>'}) class MyComp { - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyDir, MyOtherDir, MyComp]}); @@ -1325,7 +1356,7 @@ describe('di', () => { @Component({template: '<ng-template dir></ng-template>'}) class MyComp { - @ViewChild(MyDir) directive !: MyDir; + @ViewChild(MyDir) directive!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -1346,7 +1377,9 @@ describe('di', () => { constructor(protected zone: NgZone) { this.subject = new BehaviorSubject<any>(1); // trigger change detection - zone.run(() => { this.subject.next(2); }); + zone.run(() => { + this.subject.next(2); + }); } } @@ -1360,7 +1393,7 @@ describe('di', () => { template: `<div id="test-id" dir></div>`, }) class ChildComp { - @ViewChild(DirectiveA) directive !: DirectiveA; + @ViewChild(DirectiveA) directive!: DirectiveA; } @Component({ @@ -1368,7 +1401,7 @@ describe('di', () => { template: '...', }) class RootComp { - public childCompRef !: ComponentRef<ChildComp>; + public childCompRef!: ComponentRef<ChildComp>; constructor( public factoryResolver: ComponentFactoryResolver, public vcr: ViewContainerRef) {} @@ -1404,7 +1437,6 @@ describe('di', () => { }); describe('TemplateRef', () => { - @Directive({selector: '[dir]', exportAs: 'dir'}) class MyDir { value: string; @@ -1426,8 +1458,8 @@ describe('di', () => { template: '<ng-template dir otherDir #dir="dir" #otherDir="otherDir"></ng-template>' }) class MyComp { - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyDir, MyOtherDir, MyComp]}); @@ -1470,7 +1502,7 @@ describe('di', () => { } @Component({template: '<div optionalDir></div>'}) class MyComp { - @ViewChild(OptionalDir) directive !: OptionalDir; + @ViewChild(OptionalDir) directive!: OptionalDir; } TestBed.configureTestingModule({declarations: [OptionalDir, MyComp]}); @@ -1499,8 +1531,8 @@ describe('di', () => { } @Component({template: '<div dir otherDir #dir="dir" #otherDir="otherDir"></div>'}) class MyComp { - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyDir, MyOtherDir, MyComp]}); @@ -1524,12 +1556,13 @@ describe('di', () => { template: `<ng-template #tmpl>Test</ng-template>`, }) class Root { - @ViewChild(TemplateRef, {static: true}) - tmpl !: TemplateRef<any>; + @ViewChild(TemplateRef, {static: true}) tmpl!: TemplateRef<any>; constructor(public vcr: ViewContainerRef, public vcr2: ViewContainerRef) {} - ngOnInit(): void { this.vcr.createEmbeddedView(this.tmpl); } + ngOnInit(): void { + this.vcr.createEmbeddedView(this.tmpl); + } } TestBed.configureTestingModule({ @@ -1551,11 +1584,12 @@ describe('di', () => { }); describe('ChangeDetectorRef', () => { - @Directive({selector: '[dir]', exportAs: 'dir'}) class MyDir { value: string; - constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; } + constructor(public cdr: ChangeDetectorRef) { + this.value = (cdr.constructor as any).name; + } } @Directive({selector: '[otherDir]', exportAs: 'otherDir'}) class MyOtherDir { @@ -1571,9 +1605,13 @@ describe('di', () => { @Pipe({name: 'pipe'}) class MyPipe implements PipeTransform { - constructor(public cdr: ChangeDetectorRef) { pipeInstance = this; } + constructor(public cdr: ChangeDetectorRef) { + pipeInstance = this; + } - transform(value: any): any { return value; } + transform(value: any): any { + return value; + } } @Component({ @@ -1589,29 +1627,29 @@ describe('di', () => { TestBed.configureTestingModule({declarations: [MyApp, MyPipe], imports: [CommonModule]}); const fixture = TestBed.createComponent(MyApp); fixture.detectChanges(); - expect((pipeInstance !.cdr as ViewRef<MyApp>).context).toBe(fixture.componentInstance); + expect((pipeInstance!.cdr as ViewRef<MyApp>).context).toBe(fixture.componentInstance); }); it('should inject current component ChangeDetectorRef into directives on the same node as components', () => { @Component({selector: 'my-app', template: '<my-comp dir otherDir #dir="dir"></my-comp>'}) class MyApp { - @ViewChild(MyComp) component !: MyComp; - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyComp) component!: MyComp; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyApp, MyComp, MyDir, MyOtherDir]}); const fixture = TestBed.createComponent(MyApp); fixture.detectChanges(); const app = fixture.componentInstance; const comp = fixture.componentInstance.component; - expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp); + expect((comp!.cdr as ViewRef<MyComp>).context).toBe(comp); // ChangeDetectorRef is the token, ViewRef has historically been the constructor expect(app.directive.value).toContain('ViewRef'); // Each ChangeDetectorRef instance should be unique - expect(app.directive !.cdr).not.toBe(comp !.cdr); - expect(app.directive !.cdr).not.toBe(app.otherDirective !.cdr); + expect(app.directive!.cdr).not.toBe(comp!.cdr); + expect(app.directive!.cdr).not.toBe(app.otherDirective!.cdr); }); it('should inject host component ChangeDetectorRef into directives on normal elements', @@ -1619,20 +1657,20 @@ describe('di', () => { @Component({selector: 'my-comp', template: '<div dir otherDir #dir="dir"></div>'}) class MyComp { constructor(public cdr: ChangeDetectorRef) {} - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyOtherDir]}); const fixture = TestBed.createComponent(MyComp); fixture.detectChanges(); const comp = fixture.componentInstance; - expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp); + expect((comp!.cdr as ViewRef<MyComp>).context).toBe(comp); // ChangeDetectorRef is the token, ViewRef has historically been the constructor expect(comp.directive.value).toContain('ViewRef'); // Each ChangeDetectorRef instance should be unique - expect(comp.directive !.cdr).not.toBe(comp.cdr); - expect(comp.directive !.cdr).not.toBe(comp.otherDirective !.cdr); + expect(comp.directive!.cdr).not.toBe(comp.cdr); + expect(comp.directive!.cdr).not.toBe(comp.otherDirective!.cdr); }); it('should inject host component ChangeDetectorRef into directives in a component\'s ContentChildren', @@ -1646,22 +1684,22 @@ describe('di', () => { }) class MyApp { constructor(public cdr: ChangeDetectorRef) {} - @ViewChild(MyComp) component !: MyComp; - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyComp) component!: MyComp; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyApp, MyComp, MyDir, MyOtherDir]}); const fixture = TestBed.createComponent(MyApp); fixture.detectChanges(); const app = fixture.componentInstance; - expect((app !.cdr as ViewRef<MyApp>).context).toBe(app); + expect((app!.cdr as ViewRef<MyApp>).context).toBe(app); const comp = fixture.componentInstance.component; // ChangeDetectorRef is the token, ViewRef has historically been the constructor expect(app.directive.value).toContain('ViewRef'); // Each ChangeDetectorRef instance should be unique - expect(app.directive !.cdr).not.toBe(comp.cdr); - expect(app.directive !.cdr).not.toBe(app.otherDirective !.cdr); + expect(app.directive!.cdr).not.toBe(comp.cdr); + expect(app.directive!.cdr).not.toBe(app.otherDirective!.cdr); }); it('should inject host component ChangeDetectorRef into directives in embedded views', () => { @@ -1674,21 +1712,21 @@ describe('di', () => { class MyComp { showing = true; constructor(public cdr: ChangeDetectorRef) {} - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyOtherDir]}); const fixture = TestBed.createComponent(MyComp); fixture.detectChanges(); const comp = fixture.componentInstance; - expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp); + expect((comp!.cdr as ViewRef<MyComp>).context).toBe(comp); // ChangeDetectorRef is the token, ViewRef has historically been the constructor expect(comp.directive.value).toContain('ViewRef'); // Each ChangeDetectorRef instance should be unique - expect(comp.directive !.cdr).not.toBe(comp.cdr); - expect(comp.directive !.cdr).not.toBe(comp.otherDirective !.cdr); + expect(comp.directive!.cdr).not.toBe(comp.cdr); + expect(comp.directive!.cdr).not.toBe(comp.otherDirective!.cdr); }); it('should inject host component ChangeDetectorRef into directives on containers', () => { @@ -1697,21 +1735,21 @@ describe('di', () => { class MyComp { showing = true; constructor(public cdr: ChangeDetectorRef) {} - @ViewChild(MyDir) directive !: MyDir; - @ViewChild(MyOtherDir) otherDirective !: MyOtherDir; + @ViewChild(MyDir) directive!: MyDir; + @ViewChild(MyOtherDir) otherDirective!: MyOtherDir; } TestBed.configureTestingModule({declarations: [MyComp, MyDir, MyOtherDir]}); const fixture = TestBed.createComponent(MyComp); fixture.detectChanges(); const comp = fixture.componentInstance; - expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp); + expect((comp!.cdr as ViewRef<MyComp>).context).toBe(comp); // ChangeDetectorRef is the token, ViewRef has historically been the constructor expect(comp.directive.value).toContain('ViewRef'); // Each ChangeDetectorRef instance should be unique - expect(comp.directive !.cdr).not.toBe(comp.cdr); - expect(comp.directive !.cdr).not.toBe(comp.otherDirective !.cdr); + expect(comp.directive!.cdr).not.toBe(comp.cdr); + expect(comp.directive!.cdr).not.toBe(comp.otherDirective!.cdr); }); it('should inject host component ChangeDetectorRef into directives on ng-container', () => { @@ -1719,7 +1757,9 @@ describe('di', () => { @Directive({selector: '[getCDR]'}) class MyDirective { - constructor(public cdr: ChangeDetectorRef) { dirInstance = this; } + constructor(public cdr: ChangeDetectorRef) { + dirInstance = this; + } } @Component({ @@ -1733,7 +1773,7 @@ describe('di', () => { TestBed.configureTestingModule({declarations: [MyApp, MyDirective]}); const fixture = TestBed.createComponent(MyApp); fixture.detectChanges(); - expect((dirInstance !.cdr as ViewRef<MyApp>).context).toBe(fixture.componentInstance); + expect((dirInstance!.cdr as ViewRef<MyApp>).context).toBe(fixture.componentInstance); }); }); }); @@ -1747,7 +1787,7 @@ describe('di', () => { @Component({template: '<div injectorDir></div>'}) class MyComp { - @ViewChild(InjectorDir) injectorDirInstance !: InjectorDir; + @ViewChild(InjectorDir) injectorDirInstance!: InjectorDir; } TestBed.configureTestingModule({declarations: [InjectorDir, MyComp]}); @@ -1840,7 +1880,7 @@ describe('di', () => { providers: [{provide: LOCALE_ID, useValue: 'en-GB'}] }) class MyComp { - @ViewChild(MyDir) myDir !: MyDir; + @ViewChild(MyDir) myDir!: MyDir; constructor(@Inject(LOCALE_ID) public localeId: string) {} } @@ -1851,7 +1891,6 @@ describe('di', () => { }); describe('@Attribute', () => { - it('should inject attributes', () => { @Directive({selector: '[dir]'}) class MyDir { @@ -1862,7 +1901,7 @@ describe('di', () => { @Component({template: '<div dir exist="existValue" other="ignore"></div>'}) class MyComp { - @ViewChild(MyDir) directiveInstance !: MyDir; + @ViewChild(MyDir) directiveInstance!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -1886,7 +1925,7 @@ describe('di', () => { @Component( {template: '<ng-template dir="initial" exist="existValue" other="ignore"></ng-template>'}) class MyComp { - @ViewChild(MyDir) directiveInstance !: MyDir; + @ViewChild(MyDir) directiveInstance!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -1911,7 +1950,7 @@ describe('di', () => { template: '<ng-container dir="initial" exist="existValue" other="ignore"></ng-container>' }) class MyComp { - @ViewChild(MyDir) directiveInstance !: MyDir; + @ViewChild(MyDir) directiveInstance!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -1938,7 +1977,7 @@ describe('di', () => { '<div dir style="margin: 1px; color: red;" class="hello there" other-attr="value"></div>' }) class MyComp { - @ViewChild(MyDir) directiveInstance !: MyDir; + @ViewChild(MyDir) directiveInstance!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -1966,7 +2005,7 @@ describe('di', () => { template: '<div dir exist="existValue" svg:exist="testExistValue" other="otherValue"></div>' }) class MyComp { - @ViewChild(MyDir) directiveInstance !: MyDir; + @ViewChild(MyDir) directiveInstance!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -1983,7 +2022,7 @@ describe('di', () => { it('should not inject attributes representing bindings and outputs', () => { @Directive({selector: '[dir]'}) class MyDir { - @Input() binding !: string; + @Input() binding!: string; @Output() output = new EventEmitter(); constructor( @Attribute('exist') public exist: string, @@ -1997,7 +2036,7 @@ describe('di', () => { '<div dir exist="existValue" [binding]="bindingValue" (output)="outputValue" other="otherValue" ignore="ignoreValue"></div>' }) class MyComp { - @ViewChild(MyDir) directiveInstance !: MyDir; + @ViewChild(MyDir) directiveInstance!: MyDir; } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -2016,13 +2055,17 @@ describe('di', () => { it('should support dependencies in Pipes used inside ICUs', () => { @Injectable() class MyService { - transform(value: string): string { return `${value} (transformed)`; } + transform(value: string): string { + return `${value} (transformed)`; + } } @Pipe({name: 'somePipe'}) class MyPipe { constructor(private service: MyService) {} - transform(value: any): any { return this.service.transform(value); } + transform(value: any): any { + return this.service.transform(value); + } } @Component({ @@ -2051,13 +2094,17 @@ describe('di', () => { it('should support dependencies in Pipes used inside i18n blocks', () => { @Injectable() class MyService { - transform(value: string): string { return `${value} (transformed)`; } + transform(value: string): string { + return `${value} (transformed)`; + } } @Pipe({name: 'somePipe'}) class MyPipe { constructor(private service: MyService) {} - transform(value: any): any { return this.service.transform(value); } + transform(value: any): any { + return this.service.transform(value); + } } @Component({ @@ -2071,10 +2118,12 @@ describe('di', () => { class MyComp { count = '2'; - @ViewChild('target', {read: ViewContainerRef}) target !: ViewContainerRef; - @ViewChild('source', {read: TemplateRef}) source !: TemplateRef<any>; + @ViewChild('target', {read: ViewContainerRef}) target!: ViewContainerRef; + @ViewChild('source', {read: TemplateRef}) source!: TemplateRef<any>; - create() { this.target.createEmbeddedView(this.source); } + create() { + this.target.createEmbeddedView(this.source); + } } TestBed.configureTestingModule({ @@ -2109,8 +2158,8 @@ describe('di', () => { @Component({template: `<div dirA> <child></child> </div>`}) class App { - @ViewChild(DirA) dirA !: DirA; - @ViewChild(Child) child !: Child; + @ViewChild(DirA) dirA!: DirA; + @ViewChild(Child) child!: Child; } const fixture = TestBed.configureTestingModule({declarations: [DirA, DirB, App, Child]}) diff --git a/packages/core/test/acceptance/directive_spec.ts b/packages/core/test/acceptance/directive_spec.ts index 437cf825f23c4..f8174f08a39c9 100644 --- a/packages/core/test/acceptance/directive_spec.ts +++ b/packages/core/test/acceptance/directive_spec.ts @@ -13,9 +13,7 @@ import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; describe('directives', () => { - describe('matching', () => { - @Directive({selector: 'ng-template[test]'}) class TestDirective { constructor(public templateRef: TemplateRef<any>) {} @@ -241,7 +239,9 @@ describe('directives', () => { @Directive({selector: '[dir]'}) class MyDir { - ngOnInit() { calls.push('MyDir.ngOnInit'); } + ngOnInit() { + calls.push('MyDir.ngOnInit'); + } } @Component({ @@ -266,7 +266,9 @@ describe('directives', () => { @Directive({selector: 'svg[dir]'}) class MyDir { constructor(private el: ElementRef) {} - ngOnInit() { calls.push(`MyDir.ngOnInit: ${this.el.nativeElement.tagName}`); } + ngOnInit() { + calls.push(`MyDir.ngOnInit: ${this.el.nativeElement.tagName}`); + } } @Component({ @@ -289,7 +291,9 @@ describe('directives', () => { @Directive({selector: 'text[dir]'}) class MyDir { constructor(private el: ElementRef) {} - ngOnInit() { calls.push(`MyDir.ngOnInit: ${this.el.nativeElement.tagName}`); } + ngOnInit() { + calls.push(`MyDir.ngOnInit: ${this.el.nativeElement.tagName}`); + } } @Component({ @@ -311,13 +315,13 @@ describe('directives', () => { @Directive({selector: '[test]'}) class MyDir { - constructor() { logs.push('MyDir.contructor'); } + constructor() { + logs.push('MyDir.contructor'); + } - @Input('test') - myInput = ''; + @Input('test') myInput = ''; - @Input('disabled') - myInput2 = ''; + @Input('disabled') myInput2 = ''; } @Component({ @@ -338,7 +342,6 @@ describe('directives', () => { expect(logs).toEqual(['MyDir.contructor']); }); - }); describe('inputs', () => { @@ -346,7 +349,9 @@ describe('directives', () => { let dirInstance: WithInput; @Directive({selector: '[dir]'}) class WithInput { - constructor() { dirInstance = this; } + constructor() { + dirInstance = this; + } @Input() dir: string = ''; } @@ -362,14 +367,16 @@ describe('directives', () => { const fixture = TestBed.createComponent(TestComp); fixture.detectChanges(); - expect(dirInstance !.dir).toBe('Hello'); + expect(dirInstance!.dir).toBe('Hello'); }); it('should allow directive inputs (as an interpolated prop) on <ng-template>', () => { let dirInstance: WithInput; @Directive({selector: '[dir]'}) class WithInput { - constructor() { dirInstance = this; } + constructor() { + dirInstance = this; + } @Input() dir: string = ''; } @@ -385,7 +392,7 @@ describe('directives', () => { const fixture = TestBed.createComponent(TestComp); fixture.detectChanges(); - expect(dirInstance !.dir).toBe('Hello'); + expect(dirInstance!.dir).toBe('Hello'); }); it('should allow directive inputs (as an interpolated prop) on <ng-template> with structural directives', @@ -393,7 +400,9 @@ describe('directives', () => { let dirInstance: WithInput; @Directive({selector: '[dir]'}) class WithInput { - constructor() { dirInstance = this; } + constructor() { + dirInstance = this; + } @Input() dir: string = ''; } @@ -409,7 +418,7 @@ describe('directives', () => { const fixture = TestBed.createComponent(TestComp); fixture.detectChanges(); - expect(dirInstance !.dir).toBe('Hello'); + expect(dirInstance!.dir).toBe('Hello'); }); }); @@ -433,7 +442,7 @@ describe('directives', () => { expect(fixture.componentInstance.testDir).toBeTruthy(); expect(fixture.componentInstance.value).toBe(false); - fixture.componentInstance.testDir !.out.emit(); + fixture.componentInstance.testDir!.out.emit(); fixture.detectChanges(); expect(fixture.componentInstance.value).toBe(true); }); @@ -459,7 +468,6 @@ describe('directives', () => { fixture.detectChanges(); expect(fixture.componentInstance.value).toBeTruthy(); }); - }); describe('attribute shadowing behaviors', () => { @@ -471,8 +479,7 @@ describe('directives', () => { selector: '[dir-with-title]', }) class DirWithTitle { - @Input() - title = ''; + @Input() title = ''; } it('should set both the div attribute and the directive input for `title="value"`', () => { @@ -711,8 +718,12 @@ describe('directives', () => { const log: string[] = []; @Directive({selector: '[dir]'}) class DirectiveA { - constructor() { log.push('DirectiveA.constructor'); } - ngOnInit() { log.push('DirectiveA.ngOnInit'); } + constructor() { + log.push('DirectiveA.constructor'); + } + ngOnInit() { + log.push('DirectiveA.ngOnInit'); + } } @NgModule({ @@ -724,8 +735,12 @@ describe('directives', () => { @Directive({selector: '[dir]'}) class DirectiveB { - constructor() { log.push('DirectiveB.constructor'); } - ngOnInit() { log.push('DirectiveB.ngOnInit'); } + constructor() { + log.push('DirectiveB.constructor'); + } + ngOnInit() { + log.push('DirectiveB.ngOnInit'); + } } @Component({ @@ -752,8 +767,12 @@ describe('directives', () => { const log: string[] = []; @Directive({selector: '[dir]'}) class DirectiveA { - constructor() { log.push('DirectiveA.constructor'); } - ngOnInit() { log.push('DirectiveA.ngOnInit'); } + constructor() { + log.push('DirectiveA.constructor'); + } + ngOnInit() { + log.push('DirectiveA.ngOnInit'); + } } @NgModule({ @@ -765,8 +784,12 @@ describe('directives', () => { @Directive({selector: '[dir]'}) class DirectiveB { - constructor() { log.push('DirectiveB.constructor'); } - ngOnInit() { log.push('DirectiveB.ngOnInit'); } + constructor() { + log.push('DirectiveB.constructor'); + } + ngOnInit() { + log.push('DirectiveB.ngOnInit'); + } } @NgModule({ @@ -795,6 +818,5 @@ describe('directives', () => { 'DirectiveB.ngOnInit' ]); }); - }); }); diff --git a/packages/core/test/acceptance/discover_utils_spec.ts b/packages/core/test/acceptance/discover_utils_spec.ts index 101750b3d1eec..9bbebc4fda6c8 100644 --- a/packages/core/test/acceptance/discover_utils_spec.ts +++ b/packages/core/test/acceptance/discover_utils_spec.ts @@ -48,12 +48,16 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { @Component( {selector: 'child', template: '<p></p>', providers: [{provide: String, useValue: 'Child'}]}) class Child { - constructor() { childComponent.push(this); } + constructor() { + childComponent.push(this); + } } @Directive({selector: '[dirA]', exportAs: 'dirA'}) class DirectiveA { - constructor() { dirA.push(this); } + constructor() { + dirA.push(this); + } } @Component({ @@ -69,9 +73,13 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { }) class MyApp { text: string = 'INIT'; - constructor() { myApp = this; } + constructor() { + myApp = this; + } - log(event: any) { log.push(event); } + log(event: any) { + log.push(event); + } } describe('getComponent', () => { @@ -112,7 +120,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { }); it('should return context from element', () => { expect(getContext<MyApp>(child[0])).toEqual(myApp); - expect(getContext<{$implicit: boolean}>(child[2]) !.$implicit).toEqual(true); + expect(getContext<{$implicit: boolean}>(child[2])!.$implicit).toEqual(true); expect(getContext<Child>(p[0])).toEqual(childComponent[0]); }); }); @@ -264,7 +272,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { it('should work on templates', () => { const templateComment = Array.from((fixture.nativeElement as HTMLElement).childNodes) - .find((node: ChildNode) => node.nodeType === Node.COMMENT_NODE) !; + .find((node: ChildNode) => node.nodeType === Node.COMMENT_NODE)!; const lContext = loadLContext(templateComment); expect(lContext).toBeDefined(); expect(lContext.native as any).toBe(templateComment); @@ -274,7 +282,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { const ngContainerComment = Array.from((fixture.nativeElement as HTMLElement).childNodes) .find( (node: ChildNode) => node.nodeType === Node.COMMENT_NODE && - node.textContent === `ng-container`) !; + node.textContent === `ng-container`)!; const lContext = loadLContext(ngContainerComment); expect(lContext).toBeDefined(); expect(lContext.native as any).toBe(ngContainerComment); @@ -285,7 +293,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils', () => { onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => { describe('getRootComponents()', () => { it('should return a list of the root components of the application from an element', () => { - @Component({selector: 'inner-comp', template: '<div></div>'}) class InnerComp { } @@ -299,13 +306,13 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => fixture.detectChanges(); const hostElm = fixture.nativeElement; - const innerElm = hostElm.querySelector('inner-comp') !; - const divElm = hostElm.querySelector('div') !; + const innerElm = hostElm.querySelector('inner-comp')!; + const divElm = hostElm.querySelector('div')!; const component = fixture.componentInstance; - expect(getRootComponents(hostElm) !).toEqual([component]); - expect(getRootComponents(innerElm) !).toEqual([component]); - expect(getRootComponents(divElm) !).toEqual([component]); + expect(getRootComponents(hostElm)!).toEqual([component]); + expect(getRootComponents(innerElm)!).toEqual([component]); + expect(getRootComponents(divElm)!).toEqual([component]); }); }); @@ -331,9 +338,9 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => ` }) class Comp { - @ViewChild(MyDir1) myDir1Instance !: MyDir1; - @ViewChild(MyDir2) myDir2Instance !: MyDir2; - @ViewChild(MyDir3) myDir3Instance !: MyDir3; + @ViewChild(MyDir1) myDir1Instance!: MyDir1; + @ViewChild(MyDir2) myDir2Instance!: MyDir2; + @ViewChild(MyDir3) myDir3Instance!: MyDir3; } TestBed.configureTestingModule({declarations: [Comp, MyDir1, MyDir2, MyDir3]}); @@ -345,19 +352,17 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => const elm1 = elements[0]; const elm1Dirs = getDirectives(elm1); - expect(elm1Dirs).toContain(fixture.componentInstance.myDir1Instance !); - expect(elm1Dirs).toContain(fixture.componentInstance.myDir2Instance !); + expect(elm1Dirs).toContain(fixture.componentInstance.myDir1Instance!); + expect(elm1Dirs).toContain(fixture.componentInstance.myDir2Instance!); const elm2 = elements[1]; const elm2Dirs = getDirectives(elm2); - expect(elm2Dirs).toContain(fixture.componentInstance.myDir3Instance !); + expect(elm2Dirs).toContain(fixture.componentInstance.myDir3Instance!); }); }); describe('getInjector', () => { - it('should return an injector that can return directive instances', () => { - @Component({template: ''}) class Comp { } @@ -386,7 +391,6 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => describe('getLocalRefs', () => { it('should return a map of local refs for an element', () => { - @Directive({selector: '[myDir]', exportAs: 'myDir'}) class MyDir { } @@ -399,7 +403,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => const fixture = TestBed.createComponent(Comp); fixture.detectChanges(); - const divEl = fixture.nativeElement.querySelector('div') !; + const divEl = fixture.nativeElement.querySelector('div')!; const localRefs = getLocalRefs(divEl); expect(localRefs.elRef.tagName.toLowerCase()).toBe('div'); @@ -416,7 +420,7 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => const fixture = TestBed.createComponent(Comp); fixture.detectChanges(); - const divEl = fixture.nativeElement.querySelector('div') !; + const divEl = fixture.nativeElement.querySelector('div')!; const localRefs = getLocalRefs(divEl); expect(localRefs.elRef.tagName.toLowerCase()).toBe('div'); @@ -439,11 +443,11 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => const fixture = TestBed.createComponent(Comp); fixture.detectChanges(); - const parent = fixture.nativeElement.querySelector('.parent') !; - const child = fixture.nativeElement.querySelector('.child') !; + const parent = fixture.nativeElement.querySelector('.parent')!; + const child = fixture.nativeElement.querySelector('.child')!; - const parentDebug = getDebugNode(parent) !; - const childDebug = getDebugNode(child) !; + const parentDebug = getDebugNode(parent)!; + const childDebug = getDebugNode(child)!; expect(parentDebug.native).toBe(parent); expect(childDebug.native).toBe(child); @@ -472,8 +476,8 @@ onlyInIvy('Ivy-specific utilities').describe('discovery utils deprecated', () => const fixture = TestBed.createComponent(Comp); fixture.detectChanges(); - const child = fixture.nativeElement.querySelector('child-comp') !; - const childDebug = getDebugNode(child) !; + const child = fixture.nativeElement.querySelector('child-comp')!; + const childDebug = getDebugNode(child)!; expect(childDebug.native).toBe(child); expect(getElementStyles(child)).toEqual({ diff --git a/packages/core/test/acceptance/embedded_views_spec.ts b/packages/core/test/acceptance/embedded_views_spec.ts index a4fd8ba31bd1e..d0f17974e0f8d 100644 --- a/packages/core/test/acceptance/embedded_views_spec.ts +++ b/packages/core/test/acceptance/embedded_views_spec.ts @@ -10,7 +10,6 @@ import {Component, Input} from '@angular/core'; import {TestBed} from '@angular/core/testing'; describe('embedded views', () => { - it('should correctly resolve the implicit receiver in expressions', () => { const items: string[] = []; @@ -27,7 +26,9 @@ describe('embedded views', () => { }) class TestCmp { item: string = 'CmpItem'; - addItem() { items.push(this.item); } + addItem() { + items.push(this.item); + } } TestBed.configureTestingModule({declarations: [ChildCmp, TestCmp]}); @@ -36,8 +37,8 @@ describe('embedded views', () => { const childCmp: ChildCmp = fixture.debugElement.children[0].componentInstance; - childCmp.addItemFn !(); - childCmp.addItemFn !(); + childCmp.addItemFn!(); + childCmp.addItemFn!(); expect(items).toEqual(['CmpItem', 'CmpItem']); }); @@ -71,5 +72,4 @@ describe('embedded views', () => { expect(fixture.nativeElement.textContent).toBe('HelloHello'); }); - }); diff --git a/packages/core/test/acceptance/exports_spec.ts b/packages/core/test/acceptance/exports_spec.ts index 41921f280557b..1513528a13bd0 100644 --- a/packages/core/test/acceptance/exports_spec.ts +++ b/packages/core/test/acceptance/exports_spec.ts @@ -247,7 +247,13 @@ class DirWithCompInput { class DirToReferenceWithPreOrderHooks implements OnInit, OnChanges, DoCheck { @Input() in : any = null; name = 'Drew'; - ngOnChanges(changes: SimpleChanges) { this.name += '!'; } - ngOnInit() { this.name += '?'; } - ngDoCheck() { this.name += '@'; } + ngOnChanges(changes: SimpleChanges) { + this.name += '!'; + } + ngOnInit() { + this.name += '?'; + } + ngDoCheck() { + this.name += '@'; + } } diff --git a/packages/core/test/acceptance/host_binding_spec.ts b/packages/core/test/acceptance/host_binding_spec.ts index 6ed40776605c3..8457bf06d03c3 100644 --- a/packages/core/test/acceptance/host_binding_spec.ts +++ b/packages/core/test/acceptance/host_binding_spec.ts @@ -121,10 +121,9 @@ describe('host bindings', () => { class ParentCmp { private _prop = ''; - @ViewChild('template', {read: ViewContainerRef}) - vcr: ViewContainerRef = null !; + @ViewChild('template', {read: ViewContainerRef}) vcr: ViewContainerRef = null!; - private child: ComponentRef<ChildCmp> = null !; + private child: ComponentRef<ChildCmp> = null!; @Input() set prop(value: string) { @@ -137,10 +136,11 @@ describe('host bindings', () => { } } - get prop() { return this._prop; } + get prop() { + return this._prop; + } - @Input() - prop2 = 0; + @Input() prop2 = 0; ngAfterViewInit() { const factory = this.componentFactoryResolver.resolveComponentFactory(ChildCmp); @@ -212,7 +212,6 @@ describe('host bindings', () => { onlyInIvy('[style.prop] and [class.name] prioritization is a new feature') .it('should prioritize styling present in the order of directive hostBinding evaluation, but consider sub-classed directive styling to be the most important', () => { - @Component({template: '<div child-dir sibling-dir></div>'}) class MyApp { } @@ -220,37 +219,55 @@ describe('host bindings', () => { @Directive({selector: '[parent-dir]'}) class ParentDir { @HostBinding('style.width') - get width1() { return '100px'; } + get width1() { + return '100px'; + } @HostBinding('style.height') - get height1() { return '100px'; } + get height1() { + return '100px'; + } @HostBinding('style.color') - get color1() { return 'red'; } + get color1() { + return 'red'; + } } @Directive({selector: '[child-dir]'}) class ChildDir extends ParentDir { @HostBinding('style.width') - get width2() { return '200px'; } + get width2() { + return '200px'; + } @HostBinding('style.height') - get height2() { return '200px'; } + get height2() { + return '200px'; + } } @Directive({selector: '[sibling-dir]'}) class SiblingDir { @HostBinding('style.width') - get width3() { return '300px'; } + get width3() { + return '300px'; + } @HostBinding('style.height') - get height3() { return '300px'; } + get height3() { + return '300px'; + } @HostBinding('style.opacity') - get opacity3() { return '0.5'; } + get opacity3() { + return '0.5'; + } @HostBinding('style.color') - get color1() { return 'blue'; } + get color1() { + return 'blue'; + } } TestBed.configureTestingModule( @@ -295,25 +312,22 @@ describe('host bindings', () => { fixture.detectChanges(); }).not.toThrow(); }); - }); @Directive({selector: '[hostBindingDir]'}) class HostBindingDir { - @HostBinding() - id = 'foo'; + @HostBinding() id = 'foo'; } it('should support host bindings in directives', () => { @Directive({selector: '[dir]'}) class Dir { - @HostBinding('className') - klass = 'foo'; + @HostBinding('className') klass = 'foo'; } @Component({template: '<span dir></span>'}) class App { - @ViewChild(Dir) directiveInstance !: Dir; + @ViewChild(Dir) directiveInstance!: Dir; } TestBed.configureTestingModule({declarations: [App, Dir]}); @@ -333,8 +347,7 @@ describe('host bindings', () => { it('should support host bindings on root component', () => { @Component({template: ''}) class HostBindingComp { - @HostBinding() - title = 'my-title'; + @HostBinding() title = 'my-title'; } TestBed.configureTestingModule({declarations: [HostBindingComp]}); @@ -365,8 +378,7 @@ describe('host bindings', () => { class App { constructor(public serviceOne: ServiceOne, public serviceTwo: ServiceTwo) {} - @HostBinding() - title = 'my-title'; + @HostBinding() title = 'my-title'; } TestBed.configureTestingModule({declarations: [App]}); @@ -390,8 +402,7 @@ describe('host bindings', () => { @Component({selector: 'host-title-comp', template: ''}) class HostTitleComp { - @HostBinding() - title = 'my-title'; + @HostBinding() title = 'my-title'; } @Component({ @@ -402,7 +413,7 @@ describe('host bindings', () => { ` }) class App { - @ViewChild(HostBindingDir) hostBindingDir !: HostBindingDir; + @ViewChild(HostBindingDir) hostBindingDir!: HostBindingDir; } TestBed.configureTestingModule({declarations: [App, SomeDir, HostTitleComp, HostBindingDir]}); @@ -415,7 +426,7 @@ describe('host bindings', () => { expect(hostBindingDiv.id).toEqual('foo'); expect(hostTitleComp.title).toEqual('my-title'); - fixture.componentInstance.hostBindingDir !.id = 'bar'; + fixture.componentInstance.hostBindingDir!.id = 'bar'; fixture.detectChanges(); expect(hostBindingDiv.id).toEqual('bar'); }); @@ -423,8 +434,7 @@ describe('host bindings', () => { it('should support consecutive components with host bindings', () => { @Component({selector: 'host-binding-comp', template: ''}) class HostBindingComp { - @HostBinding() - id = 'blue'; + @HostBinding() id = 'blue'; } @Component({ @@ -434,7 +444,7 @@ describe('host bindings', () => { ` }) class App { - @ViewChildren(HostBindingComp) hostBindingComp !: QueryList<HostBindingComp>; + @ViewChildren(HostBindingComp) hostBindingComp!: QueryList<HostBindingComp>; } TestBed.configureTestingModule({declarations: [App, HostBindingComp]}); @@ -470,7 +480,7 @@ describe('host bindings', () => { @Component({template: '<div someDir hostBindingDir></div>'}) class App { - @ViewChild(HostBindingDir) hostBindingDir !: HostBindingDir; + @ViewChild(HostBindingDir) hostBindingDir!: HostBindingDir; } TestBed.configureTestingModule({declarations: [App, SomeDir, HostBindingDir]}); @@ -480,7 +490,7 @@ describe('host bindings', () => { const hostBindingDiv = fixture.nativeElement.querySelector('div') as HTMLElement; expect(hostBindingDiv.id).toEqual('foo'); - fixture.componentInstance.hostBindingDir !.id = 'bar'; + fixture.componentInstance.hostBindingDir!.id = 'bar'; fixture.detectChanges(); expect(hostBindingDiv.id).toEqual('bar'); }); @@ -490,18 +500,23 @@ describe('host bindings', () => { it('should support host bindings that rely on values from init hooks', () => { @Component({template: '', selector: 'init-hook-comp'}) class InitHookComp implements OnInit, OnChanges, DoCheck { - @Input() - inputValue = ''; + @Input() inputValue = ''; changesValue = ''; initValue = ''; checkValue = ''; - ngOnChanges() { this.changesValue = 'changes'; } + ngOnChanges() { + this.changesValue = 'changes'; + } - ngOnInit() { this.initValue = 'init'; } + ngOnInit() { + this.initValue = 'init'; + } - ngDoCheck() { this.checkValue = 'check'; } + ngDoCheck() { + this.checkValue = 'check'; + } @HostBinding('title') get value() { @@ -529,16 +544,14 @@ describe('host bindings', () => { it('should support host bindings with the same name as inputs', () => { @Directive({selector: '[hostBindingDir]'}) class HostBindingInputDir { - @Input() - disabled = false; + @Input() disabled = false; - @HostBinding('disabled') - hostDisabled = false; + @HostBinding('disabled') hostDisabled = false; } @Component({template: '<input hostBindingDir [disabled]="isDisabled">'}) class App { - @ViewChild(HostBindingInputDir) hostBindingInputDir !: HostBindingInputDir; + @ViewChild(HostBindingInputDir) hostBindingInputDir!: HostBindingInputDir; isDisabled = true; } @@ -611,14 +624,12 @@ describe('host bindings', () => { it('should support component with host bindings and array literals', () => { @Component({selector: 'host-binding-comp', template: ''}) class HostBindingComp { - @HostBinding() - id = 'my-id'; + @HostBinding() id = 'my-id'; } @Component({selector: 'name-comp', template: ''}) class NameComp { - @Input() - names !: string[]; + @Input() names!: string[]; } @Component({ @@ -628,7 +639,7 @@ describe('host bindings', () => { ` }) class App { - @ViewChild(NameComp) nameComp !: NameComp; + @ViewChild(NameComp) nameComp!: NameComp; name = ''; } @@ -661,8 +672,7 @@ describe('host bindings', () => { it('should support host bindings that contain array literals', () => { @Component({selector: 'name-comp', template: ''}) class NameComp { - @Input() - names !: string[]; + @Input() names!: string[]; } @Component({ @@ -684,8 +694,8 @@ describe('host bindings', () => { ` }) class App { - @ViewChild(HostBindingComp) hostBindingComp !: HostBindingComp; - @ViewChild(NameComp) nameComp !: NameComp; + @ViewChild(HostBindingComp) hostBindingComp!: HostBindingComp; + @ViewChild(NameComp) nameComp!: NameComp; name = ''; otherName = ''; } @@ -703,11 +713,11 @@ describe('host bindings', () => { expect(hostBindingEl.id).toBe('red,blue'); expect(hostBindingEl.dir).toBe('ltr'); expect(hostBindingEl.title).toBe('my title,other title'); - expect(nameComp !.names).toEqual(['Frank', 'Nancy', 'Joe']); + expect(nameComp!.names).toEqual(['Frank', 'Nancy', 'Joe']); - const firstArray = nameComp !.names; + const firstArray = nameComp!.names; fixture.detectChanges(); - expect(firstArray).toBe(nameComp !.names); + expect(firstArray).toBe(nameComp!.names); hostBindingComp.id = 'green'; hostBindingComp.dir = 'rtl'; @@ -729,7 +739,9 @@ describe('host bindings', () => { @Directive({selector: '[hostListenerDir]'}) class HostListenerDir { @HostListener('click') - onClick() { events.push('click!'); } + onClick() { + events.push('click!'); + } } @Component({template: '<button hostListenerDir hostDir>Click</button>'}) @@ -740,7 +752,7 @@ describe('host bindings', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - const button = fixture.nativeElement.querySelector('button') !; + const button = fixture.nativeElement.querySelector('button')!; button.click(); expect(events).toEqual(['click!']); expect(button.title).toEqual('my title,other title'); @@ -759,8 +771,8 @@ describe('host bindings', () => { @Component({template: '<host-binding-comp hostDir></host-binding-comp>'}) class App { - @ViewChild(HostBindingComp) hostBindingComp !: HostBindingComp; - @ViewChild(HostBindingDir) hostBindingDir !: HostBindingDir; + @ViewChild(HostBindingComp) hostBindingComp!: HostBindingComp; + @ViewChild(HostBindingDir) hostBindingDir!: HostBindingDir; } TestBed.configureTestingModule({declarations: [App, HostBindingComp, HostBindingDir]}); @@ -798,7 +810,7 @@ describe('host bindings', () => { @Component({template: `<host-binding-comp></host-binding-comp>{{ name }}`}) class App { - @ViewChild(HostBindingComp) hostBindingComp !: HostBindingComp; + @ViewChild(HostBindingComp) hostBindingComp!: HostBindingComp; name = ''; } @@ -872,8 +884,8 @@ describe('host bindings', () => { ` }) class App { - @ViewChild(SubDirective) subDir !: SubDirective; - @ViewChild(SuperDirective) superDir !: SuperDirective; + @ViewChild(SubDirective) subDir!: SubDirective; + @ViewChild(SuperDirective) superDir!: SuperDirective; } TestBed.configureTestingModule({declarations: [App, SuperDirective, SubDirective]}); @@ -927,8 +939,7 @@ describe('host bindings', () => { host: {'[id]': 'foos.length'} }) class HostBindingWithContentChildren { - @ContentChildren('foo') - foos !: QueryList<any>; + @ContentChildren('foo') foos!: QueryList<any>; } @Component({ @@ -955,7 +966,9 @@ describe('host bindings', () => { class HostBindingWithContentHooks implements AfterContentInit { myValue = 'initial'; - ngAfterContentInit() { this.myValue = 'after-content'; } + ngAfterContentInit() { + this.myValue = 'after-content'; + } } @Component({template: '<host-binding-comp></host-binding-comp>'}) @@ -971,7 +984,6 @@ describe('host bindings', () => { }); describe('styles', () => { - it('should bind to host styles', () => { @Component( {selector: 'host-binding-to-styles', host: {'[style.width.px]': 'width'}, template: ''}) @@ -981,7 +993,7 @@ describe('host bindings', () => { @Component({template: '<host-binding-to-styles></host-binding-to-styles>'}) class App { - @ViewChild(HostBindingToStyles) hostBindingDir !: HostBindingToStyles; + @ViewChild(HostBindingToStyles) hostBindingDir!: HostBindingToStyles; } TestBed.configureTestingModule({declarations: [App, HostBindingToStyles]}); @@ -1010,7 +1022,7 @@ describe('host bindings', () => { @Component({template: '<div hostStyles containerDir></div>'}) class App { - @ViewChild(HostBindingToStyles) hostBindingDir !: HostBindingToStyles; + @ViewChild(HostBindingToStyles) hostBindingDir!: HostBindingToStyles; } TestBed.configureTestingModule({declarations: [App, HostBindingToStyles, ContainerDir]}); @@ -1044,10 +1056,12 @@ describe('host bindings', () => { }); describe('sanitization', () => { - function identity(value: any) { return value; } - function verify( - tag: string, prop: string, value: any, expectedSanitizedValue: any, bypassFn: Function, - isAttribute: boolean = true, throws: boolean = false) { + function identity(value: any) { + return value; + } + function verify(tag: string, prop: string, value: any, expectedSanitizedValue: any, + bypassFn: Function, isAttribute: boolean = true, + throws: boolean = false) { it(`should sanitize <${tag} ${prop}> ${isAttribute ? 'properties' : 'attributes'}`, () => { @Directive({ selector: '[unsafeUrlHostBindingDir]', @@ -1061,13 +1075,13 @@ describe('host bindings', () => { @Component({template: `<${tag} unsafeUrlHostBindingDir></${tag}>`}) class App { - @ViewChild(UnsafeDir) unsafeDir !: UnsafeDir; + @ViewChild(UnsafeDir) unsafeDir!: UnsafeDir; } TestBed.configureTestingModule({declarations: [App, UnsafeDir]}); const fixture = TestBed.createComponent(App); fixture.detectChanges(); - const el = fixture.nativeElement.querySelector(tag) !; + const el = fixture.nativeElement.querySelector(tag)!; const current = () => isAttribute ? el.getAttribute(prop) : (el as any)[prop]; fixture.componentInstance.unsafeDir.value = value; @@ -1103,5 +1117,4 @@ describe('host bindings', () => { '<img src="unsafe:javascript:alert(3)">', bypassSanitizationTrustHtml, /* isAttribute */ false); }); - }); diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts index bf598a8868976..846cb6b0d02f9 100644 --- a/packages/core/test/acceptance/i18n_spec.ts +++ b/packages/core/test/acceptance/i18n_spec.ts @@ -8,16 +8,17 @@ // Make the `$localize()` global function available to the compiled templates, and the direct calls // below. This would normally be done inside the application `polyfills.ts` file. import '@angular/localize/init'; + import {CommonModule, registerLocaleData} from '@angular/common'; import localeRo from '@angular/common/locales/ro'; -import {Component, ContentChild, ElementRef, ContentChildren, Directive, HostBinding, Input, LOCALE_ID, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef, Pipe, PipeTransform, NO_ERRORS_SCHEMA} from '@angular/core'; +import {computeMsgId} from '@angular/compiler'; +import {Component, ContentChild, ContentChildren, Directive, ElementRef, HostBinding, Input, LOCALE_ID, NO_ERRORS_SCHEMA, Pipe, PipeTransform, QueryList, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core'; import {setDelayProjection} from '@angular/core/src/render3/instructions/projection'; import {TestBed} from '@angular/core/testing'; -import {loadTranslations, clearTranslations} from '@angular/localize'; +import {clearTranslations, loadTranslations} from '@angular/localize'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {onlyInIvy} from '@angular/private/testing'; -import {computeMsgId} from '@angular/compiler'; import {BehaviorSubject} from 'rxjs'; @@ -72,7 +73,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { it('should support interpolations with custom interpolation config', () => { loadTranslations({[computeMsgId('Hello {$INTERPOLATION}')]: 'Bonjour {$INTERPOLATION}'}); - const interpolation = ['{%', '%}'] as[string, string]; + const interpolation = ['{%', '%}'] as [string, string]; TestBed.overrideComponent(AppComp, {set: {interpolation}}); const fixture = initWithTemplate(AppComp, `<div i18n>Hello {% name %}</div>`); @@ -277,7 +278,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { name = `Angular`; clicks = 0; - onClick() { this.clicks++; } + onClick() { + this.clicks++; + } } TestBed.configureTestingModule({declarations: [ListenerComp]}); @@ -619,7 +622,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { [computeMsgId('{VAR_SELECT, select, 10 {ten} other {{INTERPOLATION}}}')]: '{VAR_SELECT, select, 10 {dix} other {{INTERPOLATION}}}' }); - const interpolation = ['{%', '%}'] as[string, string]; + const interpolation = ['{%', '%}'] as [string, string]; TestBed.overrideComponent(AppComp, {set: {interpolation}}); const fixture = initWithTemplate(AppComp, `<div i18n>{count, select, 10 {ten} other {{% name %}}}</div>`); @@ -704,7 +707,8 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { '{VAR_SELECT, select, 10 {dix} 20 {vingt} other {autre}}' }); const fixture = initWithTemplate( - AppComp, ` + AppComp, + ` <ng-template i18n tplRef>` + `{count, select, 10 {ten} 20 {twenty} other {other}}` + `</ng-template> @@ -864,7 +868,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { private readonly viewContainerRef: ViewContainerRef, private readonly templateRef: TemplateRef<any>) {} - ngOnInit() { this.viewContainerRef.createEmbeddedView(this.templateRef); } + ngOnInit() { + this.viewContainerRef.createEmbeddedView(this.templateRef); + } } @Component({ @@ -941,7 +947,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { dir = this; } - attachEmbeddedView() { this.viewContainerRef.createEmbeddedView(this.templateRef); } + attachEmbeddedView() { + this.viewContainerRef.createEmbeddedView(this.templateRef); + } } @Component({ @@ -983,7 +991,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(fixture.debugElement.nativeElement.innerHTML) .toBe('<my-cmp><!--container--></my-cmp>'); - dir !.attachEmbeddedView(); + dir!.attachEmbeddedView(); fixture.detectChanges(); expect(fixture.debugElement.nativeElement.innerHTML) .toBe( @@ -1019,7 +1027,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { class Comp { type = 'A'; visible = true; - isVisible() { return true; } + isVisible() { + return true; + } } TestBed.configureTestingModule({declarations: [Comp]}); @@ -1042,7 +1052,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { '{VAR_SELECT, select, A {A - {PH_A}} ' + 'B {B - {PH_B}} other {other - {PH_WITH_SPACES}}}')]: '{VAR_SELECT, select, A {A (translated) - {PH_A}} ' + - 'B {B (translated) - {PH_B}} other {other (translated) - {PH_WITH_SPACES}}}', + 'B {B (translated) - {PH_B}} other {other (translated) - {PH_WITH_SPACES}}}', }); @Component({ selector: 'comp', @@ -1326,7 +1336,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { it('with custom interpolation config', () => { loadTranslations({[computeMsgId('Hello {$INTERPOLATION}', 'm')]: 'Bonjour {$INTERPOLATION}'}); - const interpolation = ['{%', '%}'] as[string, string]; + const interpolation = ['{%', '%}'] as [string, string]; TestBed.overrideComponent(AppComp, {set: {interpolation}}); const fixture = initWithTemplate(AppComp, `<div i18n-title="m|d" title="Hello {% name %}"></div>`); @@ -1367,7 +1377,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { }) class TitleDir { @Input() title = ''; - constructor() { titleDirInstances.push(this); } + constructor() { + titleDirInstances.push(this); + } } @Component({ @@ -1397,7 +1409,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { @Directive({selector: '[title]'}) class TitleDir { @Input() title: string = ''; - constructor(public elRef: ElementRef) { titleDirInstances.push(this); } + constructor(public elRef: ElementRef) { + titleDirInstances.push(this); + } } @Component({ @@ -1429,7 +1443,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { let dirInstance: WithInput; @Directive({selector: '[dir]'}) class WithInput { - constructor() { dirInstance = this; } + constructor() { + dirInstance = this; + } @Input() dir: string = ''; } @@ -1445,7 +1461,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { const fixture = TestBed.createComponent(TestComp); fixture.detectChanges(); - expect(dirInstance !.dir).toBe('Bonjour Angular'); + expect(dirInstance!.dir).toBe('Bonjour Angular'); }); it('should allow directive inputs (as interpolated props)' + @@ -1456,7 +1472,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { let dirInstance: WithInput; @Directive({selector: '[dir]'}) class WithInput { - constructor() { dirInstance = this; } + constructor() { + dirInstance = this; + } @Input() dir: string = ''; } @@ -1472,7 +1490,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { const fixture = TestBed.createComponent(TestComp); fixture.detectChanges(); - expect(dirInstance !.dir).toBe('Bonjour Angular'); + expect(dirInstance!.dir).toBe('Bonjour Angular'); }); it('should apply i18n attributes during second template pass', () => { @@ -1537,7 +1555,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { template: '{{ messageText }}', }) class WelcomeComp { - @Input() messageText !: string; + @Input() messageText!: string; } @Component({ @@ -1598,10 +1616,11 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { @Directive({selector: '[test]'}) class ClsDir { - @HostBinding('className') - klass = 'foo'; + @HostBinding('className') klass = 'foo'; - constructor() { directiveInstances.push(this); } + constructor() { + directiveInstances.push(this); + } } @Component({ @@ -1641,7 +1660,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { // but IE does not. expect(outerDiv.getAttribute('title')).toBe('début 2 milieu 1 fin'); expect(outerDiv.getAttribute('class')).toBe('foo'); - expect(outerDiv.textContent !.trim()).toBe('traduction: un email'); + expect(outerDiv.textContent!.trim()).toBe('traduction: un email'); expect(innerDiv.getAttribute('class')).toBe('foo'); directiveInstances.forEach(instance => instance.klass = 'bar'); @@ -1651,7 +1670,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(outerDiv.getAttribute('title')).toBe('début 3 milieu 2 fin'); expect(outerDiv.getAttribute('class')).toBe('bar'); - expect(outerDiv.textContent !.trim()).toBe('traduction: 2 emails'); + expect(outerDiv.textContent!.trim()).toBe('traduction: 2 emails'); expect(innerDiv.getAttribute('class')).toBe('bar'); }); @@ -1660,21 +1679,25 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { let calledValue = false; @Component({selector: 'my-comp', template: ''}) class MyComp { - t !: string; + t!: string; @Input() - get title() { return this.t; } + get title() { + return this.t; + } set title(title) { calledTitle = true; this.t = title; } @Input() - get value() { return this.val; } + get value() { + return this.val; + } set value(value: string) { calledValue = true; this.val = value; } - val !: string; + val!: string; } TestBed.configureTestingModule({declarations: [AppComp, MyComp]}); @@ -2050,7 +2073,6 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { }); it('should display/destroy projected i18n content', () => { - loadTranslations({ [computeMsgId('{VAR_SELECT, select, A {A} B {B} other {other}}')]: '{VAR_SELECT, select, A {A} B {B} other {other}}' @@ -2109,7 +2131,7 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { @Directive({selector: '[text]', inputs: ['text'], exportAs: 'textDir'}) class TextDirective { // TODO(issue/24571): remove '!'. - text !: string; + text!: string; constructor() {} } @@ -2119,16 +2141,18 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { @ContentChild(TemplateRef, {static: true}) template !: TemplateRef<any>; // TODO(issue/24571): remove '!'. - @ViewChild('vc', {read: ViewContainerRef, static: true}) - vc !: ViewContainerRef; + @ViewChild('vc', {read: ViewContainerRef, static: true}) vc!: ViewContainerRef; // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective, {descendants: true}) - query !: QueryList<TextDirective>; + @ContentChildren(TextDirective, {descendants: true}) query!: QueryList<TextDirective>; - create() { this.vc.createEmbeddedView(this.template); } + create() { + this.vc.createEmbeddedView(this.template); + } - destroy() { this.vc.clear(); } + destroy() { + this.vc.clear(); + } } TestBed.configureTestingModule({declarations: [TextDirective, DivQuery]}); @@ -2224,7 +2248,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { @Directive({selector: 'input'}) class InputsDir { constructor(private elementRef: ElementRef) {} - ngOnInit() { this.elementRef.nativeElement.value = 'value set in Directive.ngOnInit'; } + ngOnInit() { + this.elementRef.nativeElement.value = 'value set in Directive.ngOnInit'; + } } @Component({ @@ -2248,7 +2274,9 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { @Directive({selector: 'input'}) class InputsDir { constructor(private elementRef: ElementRef) {} - ngOnInit() { this.elementRef.nativeElement.value = 'value set in Directive.ngOnInit'; } + ngOnInit() { + this.elementRef.nativeElement.value = 'value set in Directive.ngOnInit'; + } } @Component({ @@ -2401,12 +2429,16 @@ class AppCompWithWhitespaces { }) class DirectiveWithTplRef { constructor(public vcRef: ViewContainerRef, public tplRef: TemplateRef<{}>) {} - ngOnInit() { this.vcRef.createEmbeddedView(this.tplRef, {}); } + ngOnInit() { + this.vcRef.createEmbeddedView(this.tplRef, {}); + } } @Pipe({name: 'uppercase'}) class UppercasePipe implements PipeTransform { - transform(value: string) { return value.toUpperCase(); } + transform(value: string) { + return value.toUpperCase(); + } } @Directive({selector: `[dialog]`}) diff --git a/packages/core/test/acceptance/inherit_definition_feature_spec.ts b/packages/core/test/acceptance/inherit_definition_feature_spec.ts index 91fc4dfa3d60d..42f69a2e7aa6c 100644 --- a/packages/core/test/acceptance/inherit_definition_feature_spec.ts +++ b/packages/core/test/acceptance/inherit_definition_feature_spec.ts @@ -118,10 +118,10 @@ describe('inheritance', () => { 'Base.backgroundColor', 'Super.color', 'Sub2.width', // ]); if (ivyEnabled) { - expect(getDirectiveDef(BaseDirective) !.hostVars).toEqual(2); - expect(getDirectiveDef(SuperDirective) !.hostVars).toEqual(4); - expect(getDirectiveDef(Sub1Directive) !.hostVars).toEqual(6); - expect(getDirectiveDef(Sub2Directive) !.hostVars).toEqual(6); + expect(getDirectiveDef(BaseDirective)!.hostVars).toEqual(2); + expect(getDirectiveDef(SuperDirective)!.hostVars).toEqual(4); + expect(getDirectiveDef(Sub1Directive)!.hostVars).toEqual(6); + expect(getDirectiveDef(Sub2Directive)!.hostVars).toEqual(6); } }); }); @@ -134,7 +134,9 @@ describe('inheritance', () => { class SuperDirective implements OnChanges { @Input() someInput = ''; - ngOnChanges() { log.push('on changes!'); } + ngOnChanges() { + log.push('on changes!'); + } } @Directive({selector: '[subDir]'}) @@ -158,7 +160,9 @@ describe('inheritance', () => { const log: string[] = []; class SuperClass { - ngOnChanges() { log.push('on changes!'); } + ngOnChanges() { + log.push('on changes!'); + } } @Directive({selector: '[subDir]'}) @@ -186,7 +190,9 @@ describe('inheritance', () => { class GrandSuperDirective implements OnChanges { @Input() someInput = ''; - ngOnChanges() { log.push('on changes!'); } + ngOnChanges() { + log.push('on changes!'); + } } @Directive({selector: '[superDir]'}) @@ -215,7 +221,9 @@ describe('inheritance', () => { const log: string[] = []; class GrandSuperClass { - ngOnChanges() { log.push('on changes!'); } + ngOnChanges() { + log.push('on changes!'); + } } @Directive({selector: '[superDir]'}) @@ -248,7 +256,9 @@ describe('inheritance', () => { class GrandSuperDirective implements OnChanges { @Input() someInput = ''; - ngOnChanges() { log.push('on changes!'); } + ngOnChanges() { + log.push('on changes!'); + } } class SuperClass extends GrandSuperDirective {} @@ -275,7 +285,9 @@ describe('inheritance', () => { const log: string[] = []; class GrandSuperClass { - ngOnChanges() { log.push('on changes!'); } + ngOnChanges() { + log.push('on changes!'); + } } class SuperClass extends GrandSuperClass {} @@ -310,7 +322,9 @@ describe('inheritance', () => { abstract class UndecoratedBase extends Base { abstract input: any; - ngOnChanges() { changes++; } + ngOnChanges() { + changes++; + } } @Component({selector: 'my-comp', template: ''}) @@ -339,13 +353,27 @@ describe('inheritance', () => { const fired: string[] = []; class SuperDirective { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } beforeEach(() => fired.length = 0); @@ -355,7 +383,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -394,7 +424,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -433,7 +465,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -472,7 +506,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -511,7 +547,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -550,7 +588,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -589,7 +629,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -631,25 +673,20 @@ describe('inheritance', () => { it('should inherit inputs', () => { class SuperDirective { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - bar = ''; + @Input() bar = ''; - @Input() - baz = ''; + @Input() baz = ''; } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<p sub-dir [foo]="a" [bar]="b" [baz]="c" [qux]="d"></p>`}) @@ -684,15 +721,16 @@ describe('inheritance', () => { it('should inherit outputs', () => { class SuperDirective { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - ngOnInit() { this.foo.emit('test'); } + ngOnInit() { + this.foo.emit('test'); + } } @Component({ @@ -703,7 +741,9 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } } TestBed.configureTestingModule({ @@ -722,11 +762,9 @@ describe('inheritance', () => { // TODO: sub and super HostBinding same binding on two different properties it('should compose host bindings for styles', () => { class SuperDirective { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Directive({ @@ -762,10 +800,11 @@ describe('inheritance', () => { it('should compose host bindings (non-style related)', () => { class SuperDirective { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } @Directive({ @@ -803,15 +842,16 @@ describe('inheritance', () => { } class SuperDirective { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -831,7 +871,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); }); @@ -873,13 +913,27 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } beforeEach(() => fired.length = 0); @@ -889,7 +943,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -928,7 +984,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -967,7 +1025,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -1006,7 +1066,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -1045,7 +1107,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -1084,7 +1148,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -1123,7 +1189,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -1166,25 +1234,20 @@ describe('inheritance', () => { it('should inherit inputs', () => { @Directive({selector: '[super-dir]'}) class SuperDirective { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - bar = ''; + @Input() bar = ''; - @Input() - baz = ''; + @Input() baz = ''; } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<p sub-dir [foo]="a" [bar]="b" [baz]="c" [qux]="d"></p>`}) @@ -1209,7 +1272,6 @@ describe('inheritance', () => { expect(subDir.baz).toBe('c'); expect(subDir.qux).toBe('d'); }); - }); describe('outputs', () => { @@ -1223,15 +1285,16 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - ngOnInit() { this.foo.emit('test'); } + ngOnInit() { + this.foo.emit('test'); + } } @Component({ @@ -1242,7 +1305,9 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } } TestBed.configureTestingModule({ @@ -1264,11 +1329,9 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Directive({ @@ -1307,10 +1370,11 @@ describe('inheritance', () => { }) class SuperDirective { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } @Directive({ @@ -1348,15 +1412,16 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -1376,7 +1441,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); xdescribe( @@ -1416,13 +1481,27 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperSuperDirective { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } class SuperDirective extends SuperSuperDirective {} @@ -1434,7 +1513,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -1473,7 +1554,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -1512,7 +1595,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -1551,7 +1636,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -1590,7 +1677,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -1629,7 +1718,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -1668,7 +1759,9 @@ describe('inheritance', () => { selector: '[subDir]', }) class SubDirective extends SuperDirective { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -1711,27 +1804,22 @@ describe('inheritance', () => { it('should inherit inputs', () => { @Directive({selector: '[super-dir]'}) class SuperSuperDirective { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - baz = ''; + @Input() baz = ''; } class SuperDirective extends SuperSuperDirective { - @Input() - bar = ''; + @Input() bar = ''; } @Directive({ selector: '[sub-dir]', }) class SubDirective extends SuperDirective { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({ @@ -1772,13 +1860,11 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperSuperDirective { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } class SuperDirective extends SuperSuperDirective { - @Output() - bar = new EventEmitter<string>(); + @Output() bar = new EventEmitter<string>(); } @Directive({ @@ -1801,9 +1887,13 @@ describe('inheritance', () => { bar = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } - handleBar(event: string) { this.bar = event; } + handleBar(event: string) { + this.bar = event; + } } TestBed.configureTestingModule({ @@ -1826,13 +1916,11 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperSuperDirective { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; } class SuperDirective extends SuperSuperDirective { - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Directive({ @@ -1871,18 +1959,20 @@ describe('inheritance', () => { }) class SuperSuperDirective { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } class SuperDirective extends SuperSuperDirective { @HostBinding('accessKey') - get boundAltKey() { return this.superAccessKey + '???'; } + get boundAltKey() { + return this.superAccessKey + '???'; + } - @Input() - superAccessKey = ''; + @Input() superAccessKey = ''; } @Directive({ @@ -1927,13 +2017,11 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperSuperDirective { - @ContentChildren(ChildDir1) - childDir1s !: QueryList<ChildDir1>; + @ContentChildren(ChildDir1) childDir1s!: QueryList<ChildDir1>; } class SuperDirective extends SuperSuperDirective { - @ContentChildren(ChildDir1) - childDir2s !: QueryList<ChildDir2>; + @ContentChildren(ChildDir1) childDir2s!: QueryList<ChildDir2>; } @Directive({ @@ -1964,8 +2052,8 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundChildDir1s !.length).toBe(2); - expect(foundChildDir2s !.length).toBe(2); + expect(foundChildDir1s!.length).toBe(2); + expect(foundChildDir2s!.length).toBe(2); }); xdescribe( @@ -2002,13 +2090,27 @@ describe('inheritance', () => { const fired: string[] = []; class SuperComponent { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } beforeEach(() => fired.length = 0); @@ -2016,7 +2118,9 @@ describe('inheritance', () => { it('ngOnInit', () => { @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends SuperComponent { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -2055,7 +2159,9 @@ describe('inheritance', () => { selector: 'my-comp', }) class MyComponent extends SuperComponent { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -2095,7 +2201,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -2135,7 +2243,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -2175,7 +2285,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -2215,7 +2327,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -2255,7 +2369,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -2297,23 +2413,18 @@ describe('inheritance', () => { it('should inherit inputs', () => { class SuperComponent { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - bar = ''; + @Input() bar = ''; - @Input() - baz = ''; + @Input() baz = ''; } @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends SuperComponent { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<my-comp [foo]="a" [bar]="b" [baz]="c" [qux]="d"></my-comp>`}) @@ -2338,7 +2449,6 @@ describe('inheritance', () => { expect(subDir.baz).toEqual('c'); expect(subDir.qux).toEqual('d'); }); - }); describe('outputs', () => { @@ -2349,8 +2459,7 @@ describe('inheritance', () => { it('should inherit outputs', () => { class SuperComponent { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } @Component({ @@ -2358,7 +2467,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnInit() { this.foo.emit('test'); } + ngOnInit() { + this.foo.emit('test'); + } } @Component({ @@ -2369,7 +2480,9 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } } TestBed.configureTestingModule({ @@ -2388,11 +2501,9 @@ describe('inheritance', () => { // TODO: sub and super HostBinding same binding on two different properties it('should compose host bindings for styles', () => { class SuperComponent { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Component({ @@ -2429,10 +2540,11 @@ describe('inheritance', () => { it('should compose host bindings (non-style related)', () => { class SuperComponent { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } @Component({ @@ -2468,13 +2580,14 @@ describe('inheritance', () => { } class SuperComponent { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({selector: 'my-comp', template: `<ul><ng-content></ng-content></ul>`}) class MyComponent extends SuperComponent { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -2494,7 +2607,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); xdescribe( @@ -2534,13 +2647,27 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } beforeEach(() => fired.length = 0); @@ -2548,7 +2675,9 @@ describe('inheritance', () => { it('ngOnInit', () => { @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends SuperDirective { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -2588,7 +2717,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -2628,7 +2759,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -2668,7 +2801,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -2708,7 +2843,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -2748,7 +2885,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -2788,7 +2927,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -2833,23 +2974,18 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - bar = ''; + @Input() bar = ''; - @Input() - baz = ''; + @Input() baz = ''; } @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends SuperDirective { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<my-comp [foo]="a" [bar]="b" [baz]="c" [qux]="d"></my-comp>`}) @@ -2887,8 +3023,7 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } @Component({ @@ -2896,7 +3031,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperDirective { - ngOnInit() { this.foo.emit('test'); } + ngOnInit() { + this.foo.emit('test'); + } } @Component({ @@ -2907,7 +3044,9 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } } TestBed.configureTestingModule({ @@ -2929,11 +3068,9 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Component({ @@ -2973,10 +3110,11 @@ describe('inheritance', () => { }) class SuperDirective { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } @Component({ @@ -3015,13 +3153,14 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({selector: 'my-comp', template: `<ul><ng-content></ng-content></ul>`}) class MyComponent extends SuperDirective { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -3041,7 +3180,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); it('should inherit ViewChildren queries', () => { @@ -3055,8 +3194,7 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @ViewChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ViewChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({ @@ -3069,7 +3207,9 @@ describe('inheritance', () => { }) class MyComponent extends SuperDirective { items = [1, 2, 3, 4, 5]; - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -3086,7 +3226,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(5); + expect(foundQueryList!.length).toBe(5); }); xdescribe( @@ -3126,13 +3266,27 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } class BareClass extends SuperDirective {} @@ -3142,7 +3296,9 @@ describe('inheritance', () => { it('ngOnInit', () => { @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends BareClass { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -3181,7 +3337,9 @@ describe('inheritance', () => { selector: 'my-comp', }) class MyComponent extends BareClass { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -3221,7 +3379,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends BareClass { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -3261,7 +3421,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends BareClass { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -3301,7 +3463,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends BareClass { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -3341,7 +3505,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends BareClass { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -3381,7 +3547,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends BareClass { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -3426,25 +3594,20 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - baz = ''; + @Input() baz = ''; } class BareClass extends SuperDirective { - @Input() - bar = ''; + @Input() bar = ''; } @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends BareClass { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<my-comp [foo]="a" [bar]="b" [baz]="c" [qux]="d"></my-comp>`}) @@ -3482,8 +3645,7 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } class BareClass extends SuperDirective {} @@ -3493,7 +3655,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends BareClass { - ngOnInit() { this.foo.emit('test'); } + ngOnInit() { + this.foo.emit('test'); + } } @Component({ @@ -3504,7 +3668,9 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } } TestBed.configureTestingModule({ @@ -3526,11 +3692,9 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } class BareClass extends SuperDirective {} @@ -3572,18 +3736,20 @@ describe('inheritance', () => { }) class SuperDirective { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } class BareClass extends SuperDirective { @HostBinding('accessKey') - get boundAccessKey() { return this.superAccessKey + '???'; } + get boundAccessKey() { + return this.superAccessKey + '???'; + } - @Input() - superAccessKey = ''; + @Input() superAccessKey = ''; } @Component({ @@ -3623,8 +3789,7 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } class BareClass extends SuperDirective {} @@ -3634,7 +3799,9 @@ describe('inheritance', () => { template: `<ul><ng-content></ng-content></ul>`, }) class MyComponent extends BareClass { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -3654,7 +3821,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); it('should inherit ViewChildren queries', () => { @@ -3668,8 +3835,7 @@ describe('inheritance', () => { selector: '[super-dir]', }) class SuperDirective { - @ViewChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ViewChildren(ChildDir) customDirs!: QueryList<ChildDir>; } class BareClass extends SuperDirective {} @@ -3684,7 +3850,9 @@ describe('inheritance', () => { }) class MyComponent extends BareClass { items = [1, 2, 3, 4, 5]; - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -3701,7 +3869,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(5); + expect(foundQueryList!.length).toBe(5); }); xdescribe( @@ -3742,13 +3910,27 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } beforeEach(() => fired.length = 0); @@ -3759,7 +3941,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -3799,7 +3983,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -3839,7 +4025,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -3879,7 +4067,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -3919,7 +4109,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -3959,7 +4151,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -3999,7 +4193,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -4045,23 +4241,18 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - bar = ''; + @Input() bar = ''; - @Input() - baz = ''; + @Input() baz = ''; } @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends SuperComponent { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<my-comp [foo]="a" [bar]="b" [baz]="c" [qux]="d"></my-comp>`}) @@ -4100,8 +4291,7 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } @Component({ @@ -4109,7 +4299,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnInit() { this.foo.emit('test'); } + ngOnInit() { + this.foo.emit('test'); + } } @Component({ @@ -4120,7 +4312,9 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } } TestBed.configureTestingModule({ @@ -4236,11 +4430,9 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Component({ @@ -4281,10 +4473,11 @@ describe('inheritance', () => { }) class SuperComponent { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } @Component({ @@ -4324,8 +4517,7 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({ @@ -4333,7 +4525,9 @@ describe('inheritance', () => { template: `<ul><ng-content></ng-content></ul>`, }) class MyComponent extends SuperComponent { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -4353,7 +4547,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); it('should inherit ViewChildren queries', () => { @@ -4368,8 +4562,7 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @ViewChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ViewChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({ @@ -4382,7 +4575,9 @@ describe('inheritance', () => { }) class MyComponent extends SuperComponent { items = [1, 2, 3, 4, 5]; - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -4399,7 +4594,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(5); + expect(foundQueryList!.length).toBe(5); }); it('should inherit host listeners from base class once', () => { @@ -4411,7 +4606,9 @@ describe('inheritance', () => { }) class BaseComponent { @HostListener('click') - clicked() { events.push('BaseComponent.clicked'); } + clicked() { + events.push('BaseComponent.clicked'); + } } @Component({ @@ -4423,9 +4620,12 @@ describe('inheritance', () => { // component def, which would trigger `hostBindings` functions merge operation in // InheritDefinitionFeature logic (merging Child and Base host binding functions) @HostListener('focus') - focused() {} + focused() { + } - clicked() { events.push('ChildComponent.clicked'); } + clicked() { + events.push('ChildComponent.clicked'); + } } @Component({ @@ -4437,9 +4637,12 @@ describe('inheritance', () => { // component def, which would trigger `hostBindings` functions merge operation in // InheritDefinitionFeature logic (merging GrandChild and Child host binding functions) @HostListener('blur') - blurred() {} + blurred() { + } - clicked() { events.push('GrandChildComponent.clicked'); } + clicked() { + events.push('GrandChildComponent.clicked'); + } } @Component({ @@ -4505,13 +4708,27 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperSuperComponent { - ngOnInit() { fired.push('super init'); } - ngOnDestroy() { fired.push('super destroy'); } - ngAfterContentInit() { fired.push('super after content init'); } - ngAfterContentChecked() { fired.push('super after content checked'); } - ngAfterViewInit() { fired.push('super after view init'); } - ngAfterViewChecked() { fired.push('super after view checked'); } - ngDoCheck() { fired.push('super do check'); } + ngOnInit() { + fired.push('super init'); + } + ngOnDestroy() { + fired.push('super destroy'); + } + ngAfterContentInit() { + fired.push('super after content init'); + } + ngAfterContentChecked() { + fired.push('super after content checked'); + } + ngAfterViewInit() { + fired.push('super after view init'); + } + ngAfterViewChecked() { + fired.push('super after view checked'); + } + ngDoCheck() { + fired.push('super do check'); + } } class SuperComponent extends SuperSuperComponent {} @@ -4524,7 +4741,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnInit() { fired.push('sub init'); } + ngOnInit() { + fired.push('sub init'); + } } @Component({ @@ -4564,7 +4783,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngDoCheck() { fired.push('sub do check'); } + ngDoCheck() { + fired.push('sub do check'); + } } @Component({ @@ -4604,7 +4825,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterContentInit() { fired.push('sub after content init'); } + ngAfterContentInit() { + fired.push('sub after content init'); + } } @Component({ @@ -4644,7 +4867,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterContentChecked() { fired.push('sub after content checked'); } + ngAfterContentChecked() { + fired.push('sub after content checked'); + } } @Component({ @@ -4684,7 +4909,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterViewInit() { fired.push('sub after view init'); } + ngAfterViewInit() { + fired.push('sub after view init'); + } } @Component({ @@ -4724,7 +4951,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngAfterViewChecked() { fired.push('sub after view checked'); } + ngAfterViewChecked() { + fired.push('sub after view checked'); + } } @Component({ @@ -4764,7 +4993,9 @@ describe('inheritance', () => { template: `<p>test</p>`, }) class MyComponent extends SuperComponent { - ngOnDestroy() { fired.push('sub destroy'); } + ngOnDestroy() { + fired.push('sub destroy'); + } } @Component({ @@ -4810,25 +5041,20 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperSuperComponent { - @Input() - foo = ''; + @Input() foo = ''; - @Input() - baz = ''; + @Input() baz = ''; } class BareClass extends SuperSuperComponent { - @Input() - bar = ''; + @Input() bar = ''; } @Component({selector: 'my-comp', template: `<p>test</p>`}) class MyComponent extends BareClass { - @Input() - baz = ''; + @Input() baz = ''; - @Input() - qux = ''; + @Input() qux = ''; } @Component({template: `<my-comp [foo]="a" [bar]="b" [baz]="c" [qux]="d"></my-comp>`}) @@ -4867,13 +5093,11 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperSuperComponent { - @Output() - foo = new EventEmitter<string>(); + @Output() foo = new EventEmitter<string>(); } class SuperComponent extends SuperSuperComponent { - @Output() - bar = new EventEmitter<string>(); + @Output() bar = new EventEmitter<string>(); } @Component({ @@ -4895,11 +5119,15 @@ describe('inheritance', () => { class App { foo = ''; - handleFoo(event: string) { this.foo = event; } + handleFoo(event: string) { + this.foo = event; + } bar = ''; - handleBar(event: string) { this.bar = event; } + handleBar(event: string) { + this.bar = event; + } } TestBed.configureTestingModule({ @@ -4987,13 +5215,11 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperSuperComponent { - @HostBinding('style.color') - color = 'red'; + @HostBinding('style.color') color = 'red'; } class SuperComponent extends SuperSuperComponent { - @HostBinding('style.backgroundColor') - bg = 'black'; + @HostBinding('style.backgroundColor') bg = 'black'; } @Component({ @@ -5034,18 +5260,20 @@ describe('inheritance', () => { }) class SuperSuperComponent { @HostBinding('title') - get boundTitle() { return this.superTitle + '!!!'; } + get boundTitle() { + return this.superTitle + '!!!'; + } - @Input() - superTitle = ''; + @Input() superTitle = ''; } class SuperComponent extends SuperSuperComponent { @HostBinding('accessKey') - get boundAccessKey() { return this.superAccessKey + '???'; } + get boundAccessKey() { + return this.superAccessKey + '???'; + } - @Input() - superAccessKey = ''; + @Input() superAccessKey = ''; } @Component({ @@ -5087,8 +5315,7 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @ContentChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ContentChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({ @@ -5096,7 +5323,9 @@ describe('inheritance', () => { template: `<ul><ng-content></ng-content></ul>`, }) class MyComponent extends SuperComponent { - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -5116,7 +5345,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(2); + expect(foundQueryList!.length).toBe(2); }); it('should inherit ViewChildren queries', () => { @@ -5131,8 +5360,7 @@ describe('inheritance', () => { template: `<p>super</p>`, }) class SuperComponent { - @ViewChildren(ChildDir) - customDirs !: QueryList<ChildDir>; + @ViewChildren(ChildDir) customDirs!: QueryList<ChildDir>; } @Component({ @@ -5145,7 +5373,9 @@ describe('inheritance', () => { }) class MyComponent extends SuperComponent { items = [1, 2, 3, 4, 5]; - ngAfterViewInit() { foundQueryList = this.customDirs; } + ngAfterViewInit() { + foundQueryList = this.customDirs; + } } @Component({ @@ -5162,7 +5392,7 @@ describe('inheritance', () => { const fixture = TestBed.createComponent(App); fixture.detectChanges(); - expect(foundQueryList !.length).toBe(5); + expect(foundQueryList!.length).toBe(5); }); xdescribe( diff --git a/packages/core/test/acceptance/integration_spec.ts b/packages/core/test/acceptance/integration_spec.ts index d53825871c82b..164550bdf5ca0 100644 --- a/packages/core/test/acceptance/integration_spec.ts +++ b/packages/core/test/acceptance/integration_spec.ts @@ -16,10 +16,11 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; describe('acceptance integration tests', () => { - function stripHtmlComments(str: string) { return str.replace(/<!--[\s\S]*?-->/g, ''); } + function stripHtmlComments(str: string) { + return str.replace(/<!--[\s\S]*?-->/g, ''); + } describe('render', () => { - it('should render basic template', () => { @Component({template: '<span title="Hello">Greetings</span>'}) class App { @@ -64,12 +65,10 @@ describe('acceptance integration tests', () => { tView: 2, tNode: 4, }); - }); }); describe('ng-container', () => { - it('should insert as a child of a regular element', () => { @Component( {template: '<div>before|<ng-container>Greetings<span></span></ng-container>|after</div>'}) @@ -108,7 +107,6 @@ describe('acceptance integration tests', () => { }); it('should add and remove DOM nodes when ng-container is a child of an embedded view', () => { - @Component({template: '<ng-container *ngIf="render">content</ng-container>'}) class App { render = false; @@ -131,21 +129,24 @@ describe('acceptance integration tests', () => { // https://stackblitz.com/edit/angular-tfhcz1?file=src%2Fapp%2Fapp.component.ts it('should add and remove DOM nodes when ng-container is a child of a delayed embedded view', () => { - @Directive({selector: '[testDirective]'}) class TestDirective { constructor(private _tplRef: TemplateRef<any>, private _vcRef: ViewContainerRef) {} - createAndInsert() { this._vcRef.insert(this._tplRef.createEmbeddedView({})); } + createAndInsert() { + this._vcRef.insert(this._tplRef.createEmbeddedView({})); + } - clear() { this._vcRef.clear(); } + clear() { + this._vcRef.clear(); + } } @Component({ template: '<ng-template testDirective><ng-container>content</ng-container></ng-template>' }) class App { - @ViewChild(TestDirective, {static: true}) testDirective !: TestDirective; + @ViewChild(TestDirective, {static: true}) testDirective!: TestDirective; } TestBed.configureTestingModule({declarations: [App, TestDirective]}); @@ -205,9 +206,13 @@ describe('acceptance integration tests', () => { class TestDirective { constructor(private _tplRef: TemplateRef<any>, private _vcRef: ViewContainerRef) {} - createAndInsert() { this._vcRef.insert(this._tplRef.createEmbeddedView({})); } + createAndInsert() { + this._vcRef.insert(this._tplRef.createEmbeddedView({})); + } - clear() { this._vcRef.clear(); } + clear() { + this._vcRef.clear(); + } } @Component({ @@ -215,7 +220,7 @@ describe('acceptance integration tests', () => { '<ng-template testDirective><ng-container><ng-container><ng-container>content</ng-container></ng-container></ng-container></ng-template>' }) class App { - @ViewChild(TestDirective, {static: true}) testDirective !: TestDirective; + @ViewChild(TestDirective, {static: true}) testDirective!: TestDirective; } TestBed.configureTestingModule({declarations: [App, TestDirective]}); @@ -245,7 +250,7 @@ describe('acceptance integration tests', () => { @Component({template: '<div><ng-container dir></ng-container></div>'}) class App { - @ViewChild(TestDirective) testDirective !: TestDirective; + @ViewChild(TestDirective) testDirective!: TestDirective; } TestBed.configureTestingModule({declarations: [App, TestDirective]}); @@ -260,14 +265,17 @@ describe('acceptance integration tests', () => { it('should support ViewContainerRef when ng-container is at the root of a view', () => { @Directive({selector: '[dir]'}) class TestDirective { - @Input() - contentTpl: TemplateRef<{}>|null = null; + @Input() contentTpl: TemplateRef<{}>|null = null; constructor(private _vcRef: ViewContainerRef) {} - insertView() { this._vcRef.createEmbeddedView(this.contentTpl as TemplateRef<{}>); } + insertView() { + this._vcRef.createEmbeddedView(this.contentTpl as TemplateRef<{}>); + } - clear() { this._vcRef.clear(); } + clear() { + this._vcRef.clear(); + } } @Component({ @@ -275,7 +283,7 @@ describe('acceptance integration tests', () => { '<ng-container dir [contentTpl]="content"><ng-template #content>Content</ng-template></ng-container>' }) class App { - @ViewChild(TestDirective) testDirective !: TestDirective; + @ViewChild(TestDirective) testDirective!: TestDirective; } TestBed.configureTestingModule({declarations: [App, TestDirective]}); @@ -298,14 +306,18 @@ describe('acceptance integration tests', () => { class TestDirective { constructor(private _tplRef: TemplateRef<{}>, private _vcRef: ViewContainerRef) {} - insertView() { this._vcRef.createEmbeddedView(this._tplRef); } + insertView() { + this._vcRef.createEmbeddedView(this._tplRef); + } - clear() { this._vcRef.clear(); } + clear() { + this._vcRef.clear(); + } } @Component({template: '<ng-container><ng-template dir>Content</ng-template></ng-container>'}) class App { - @ViewChild(TestDirective) testDirective !: TestDirective; + @ViewChild(TestDirective) testDirective!: TestDirective; } TestBed.configureTestingModule({declarations: [App, TestDirective]}); @@ -334,7 +346,6 @@ describe('acceptance integration tests', () => { expect(stripHtmlComments(fixture.nativeElement.innerHTML)).toEqual('<div></div>'); }); - }); describe('text bindings', () => { @@ -373,11 +384,12 @@ describe('acceptance integration tests', () => { expect(fixture.nativeElement.innerHTML).toEqual(''); }); - }); describe('ngNonBindable handling', () => { - function stripNgNonBindable(str: string) { return str.replace(/ ngnonbindable=""/i, ''); } + function stripNgNonBindable(str: string) { + return str.replace(/ ngnonbindable=""/i, ''); + } it('should keep local ref for host element', () => { @Component({ @@ -404,7 +416,9 @@ describe('acceptance integration tests', () => { @Directive({selector: '[directive]'}) class TestDirective implements OnInit { - ngOnInit() { directiveInvoked = true; } + ngOnInit() { + directiveInvoked = true; + } } @Component({ @@ -432,7 +446,9 @@ describe('acceptance integration tests', () => { @Directive({selector: '[directive]'}) class TestDirective implements OnInit { - ngOnInit() { directiveInvoked = true; } + ngOnInit() { + directiveInvoked = true; + } } @Component({ @@ -604,14 +620,12 @@ describe('acceptance integration tests', () => { it('should support a component with binding on host element', () => { @Component({selector: 'todo', template: '{{title}}'}) class TodoComponentHostBinding { - @HostBinding() - title = 'one'; + @HostBinding() title = 'one'; } @Component({template: '<todo></todo>'}) class App { - @ViewChild(TodoComponentHostBinding) - todoComponentHostBinding !: TodoComponentHostBinding; + @ViewChild(TodoComponentHostBinding) todoComponentHostBinding!: TodoComponentHostBinding; } TestBed.configureTestingModule({declarations: [App, TodoComponentHostBinding]}); @@ -658,8 +672,7 @@ describe('acceptance integration tests', () => { it('should support a component with sub-views', () => { @Component({selector: 'comp', template: '<div *ngIf="condition">text</div>'}) class MyComp { - @Input() - condition !: boolean; + @Input() condition!: boolean; } @Component({template: '<comp [condition]="condition"></comp>'}) @@ -680,7 +693,6 @@ describe('acceptance integration tests', () => { fixture.detectChanges(); expect(stripHtmlComments(compElement.innerHTML)).toEqual(''); }); - }); describe('element bindings', () => { @@ -814,7 +826,7 @@ describe('acceptance integration tests', () => { fixture.detectChanges(); const span: HTMLSpanElement = fixture.nativeElement.querySelector('span'); - const bold: HTMLElement = span.querySelector('b') !; + const bold: HTMLElement = span.querySelector('b')!; fixture.componentInstance.title = 'Hello'; fixture.detectChanges(); @@ -840,13 +852,12 @@ describe('acceptance integration tests', () => { it('should support host attribute bindings', () => { @Directive({selector: '[hostBindingDir]'}) class HostBindingDir { - @HostBinding('attr.aria-label') - label = 'some label'; + @HostBinding('attr.aria-label') label = 'some label'; } @Component({template: '<div hostBindingDir></div>'}) class App { - @ViewChild(HostBindingDir) hostBindingDir !: HostBindingDir; + @ViewChild(HostBindingDir) hostBindingDir!: HostBindingDir; } TestBed.configureTestingModule({declarations: [App, HostBindingDir]}); @@ -999,12 +1010,13 @@ describe('acceptance integration tests', () => { it('should apply classes properly when nodes have containers', () => { @Component({selector: 'structural-comp', template: 'Comp Content'}) class StructuralComp { - @Input() - tmp !: TemplateRef<any>; + @Input() tmp!: TemplateRef<any>; constructor(public vcr: ViewContainerRef) {} - create() { this.vcr.createEmbeddedView(this.tmp); } + create() { + this.vcr.createEmbeddedView(this.tmp); + } } @Component({ @@ -1014,7 +1026,7 @@ describe('acceptance integration tests', () => { ` }) class App { - @ViewChild(StructuralComp) structuralComp !: StructuralComp; + @ViewChild(StructuralComp) structuralComp!: StructuralComp; value: any; } @@ -1040,7 +1052,9 @@ describe('acceptance integration tests', () => { public classesVal: string = ''; @Input('class') - set klass(value: string) { this.classesVal = value; } + set klass(value: string) { + this.classesVal = value; + } } @Directive({selector: '[DirWithStyle]'}) @@ -1048,15 +1062,16 @@ describe('acceptance integration tests', () => { public stylesVal: any = ''; @Input() - set style(value: any) { this.stylesVal = value; } + set style(value: any) { + this.stylesVal = value; + } } it('should delegate initial classes to a [class] input binding if present on a directive on the same element', () => { @Component({template: '<div class="apple orange banana" DirWithClass></div>'}) class App { - @ViewChild(DirWithClassDirective) - mockClassDirective !: DirWithClassDirective; + @ViewChild(DirWithClassDirective) mockClassDirective!: DirWithClassDirective; } TestBed.configureTestingModule({declarations: [App, DirWithClassDirective]}); @@ -1073,8 +1088,7 @@ describe('acceptance integration tests', () => { () => { @Component({template: '<div style="width: 100px; height: 200px" DirWithStyle></div>'}) class App { - @ViewChild(DirWithStyleDirective) - mockStyleDirective !: DirWithStyleDirective; + @ViewChild(DirWithStyleDirective) mockStyleDirective!: DirWithStyleDirective; } TestBed.configureTestingModule({declarations: [App, DirWithStyleDirective]}); @@ -1092,8 +1106,7 @@ describe('acceptance integration tests', () => { () => { @Component({template: '<div DirWithClass [class]="value"></div>'}) class App { - @ViewChild(DirWithClassDirective) - mockClassDirective !: DirWithClassDirective; + @ViewChild(DirWithClassDirective) mockClassDirective!: DirWithClassDirective; value = ''; } @@ -1111,9 +1124,8 @@ describe('acceptance integration tests', () => { () => { @Component({template: '<div DirWithStyle [style]="value"></div>'}) class App { - @ViewChild(DirWithStyleDirective) - mockStyleDirective !: DirWithStyleDirective; - value !: {[key: string]: string}; + @ViewChild(DirWithStyleDirective) mockStyleDirective!: DirWithStyleDirective; + value!: {[key: string]: string}; } TestBed.configureTestingModule({declarations: [App, DirWithStyleDirective]}); @@ -1155,7 +1167,7 @@ describe('acceptance integration tests', () => { fixture.detectChanges(); const target: HTMLDivElement = fixture.nativeElement.querySelector('div'); - const classes = target.getAttribute('class') !.split(/\s+/).sort(); + const classes = target.getAttribute('class')!.split(/\s+/).sort(); expect(classes).toEqual(['big', 'golden', 'heavy']); expect(target.getAttribute('title')).toEqual('foo'); @@ -1189,7 +1201,7 @@ describe('acceptance integration tests', () => { }) class App { @ViewChild(DirWithSingleStylingBindings) - dirInstance !: DirWithSingleStylingBindings; + dirInstance!: DirWithSingleStylingBindings; } TestBed.configureTestingModule({declarations: [App, DirWithSingleStylingBindings]}); @@ -1244,8 +1256,8 @@ describe('acceptance integration tests', () => { @Component( {template: '<div Dir1WithStyle Dir2WithStyle [style.width]="width"></div>'}) class App { - @ViewChild(Dir1WithStyle) dir1Instance !: Dir1WithStyle; - @ViewChild(Dir2WithStyle) dir2Instance !: Dir2WithStyle; + @ViewChild(Dir1WithStyle) dir1Instance!: Dir1WithStyle; + @ViewChild(Dir2WithStyle) dir2Instance!: Dir2WithStyle; width: string|null|undefined = undefined; } @@ -1309,8 +1321,8 @@ describe('acceptance integration tests', () => { '<div Dir1WithStyling Dir2WithStyling [style]="stylesExp" [class]="classesExp"></div>' }) class App { - @ViewChild(Dir1WithStyling) dir1Instance !: Dir1WithStyling; - @ViewChild(Dir2WithStyling) dir2Instance !: Dir2WithStyling; + @ViewChild(Dir1WithStyling) dir1Instance!: Dir1WithStyling; + @ViewChild(Dir2WithStyling) dir2Instance!: Dir2WithStyling; stylesExp: any = {}; classesExp: any = {}; } @@ -1321,7 +1333,7 @@ describe('acceptance integration tests', () => { fixture.detectChanges(); const {dir1Instance, dir2Instance} = fixture.componentInstance; - const target = fixture.nativeElement.querySelector('div') !; + const target = fixture.nativeElement.querySelector('div')!; expect(target.style.getPropertyValue('width')).toEqual('111px'); const compInstance = fixture.componentInstance; @@ -1393,7 +1405,7 @@ describe('acceptance integration tests', () => { TestBed.configureTestingModule({declarations: [App]}); const fixture = TestBed.createComponent(App); - const target = fixture.nativeElement.querySelector('div') !; + const target = fixture.nativeElement.querySelector('div')!; expect(target.classList.contains('-fred-36-')).toBeFalsy(); @@ -1510,7 +1522,6 @@ describe('acceptance integration tests', () => { // The ViewEngine error has a typo, whereas the Ivy one fixes it. /^Unexpected value 'SomeModule' imported by the module 'ModuleWithImportedModule'\. Please add (a|an) @NgModule annotation\.$/); }); - }); it('should only call inherited host listeners once', () => { @@ -1519,7 +1530,9 @@ describe('acceptance integration tests', () => { @Component({template: ''}) class ButtonSuperClass { @HostListener('click') - clicked() { clicks++; } + clicked() { + clicks++; + } } @Component({selector: 'button[custom-button]', template: ''}) @@ -1548,7 +1561,7 @@ describe('acceptance integration tests', () => { @Component({template: '<div someDir></div>'}) class SuperComp { - @ViewChildren(SomeDir) dirs !: QueryList<SomeDir>; + @ViewChildren(SomeDir) dirs!: QueryList<SomeDir>; } @Component({selector: 'button[custom-button]', template: '<div someDir></div>'}) @@ -1576,7 +1589,9 @@ describe('acceptance integration tests', () => { private _isDestroyed = false; @Input() - get value() { return this._value; } + get value() { + return this._value; + } set value(newValue: any) { if (this._isDestroyed) { throw Error('Cannot assign to value after destroy.'); @@ -1586,7 +1601,9 @@ describe('acceptance integration tests', () => { } private _value: any; - ngOnDestroy() { this._isDestroyed = true; } + ngOnDestroy() { + this._isDestroyed = true; + } } @Component({template: '<div no-assign-after-destroy [value]="directiveValue"></div>'}) @@ -1608,7 +1625,7 @@ describe('acceptance integration tests', () => { @Component( {selector: 'test-component', template: `foo`, host: {'[attr.aria-disabled]': 'true'}}) class TestComponent { - @ContentChild(TemplateRef, {static: true}) tpl !: TemplateRef<any>; + @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>; } TestBed.configureTestingModule({declarations: [TestComponent]}); @@ -1621,7 +1638,7 @@ describe('acceptance integration tests', () => { it('should inherit inputs from undecorated superclasses', () => { class ButtonSuperClass { - @Input() isDisabled !: boolean; + @Input() isDisabled!: boolean; } @Component({selector: 'button[custom-button]', template: ''}) @@ -1651,7 +1668,9 @@ describe('acceptance integration tests', () => { class ButtonSuperClass { @Output() clicked = new EventEmitter<void>(); - emitClick() { this.clicked.emit(); } + emitClick() { + this.clicked.emit(); + } } @Component({selector: 'button[custom-button]', template: ''}) @@ -1660,7 +1679,9 @@ describe('acceptance integration tests', () => { @Component({template: '<button custom-button (clicked)="handleClick()"></button>'}) class MyApp { - handleClick() { clicks++; } + handleClick() { + clicks++; + } } TestBed.configureTestingModule({declarations: [MyApp, ButtonSubClass]}); @@ -1675,8 +1696,7 @@ describe('acceptance integration tests', () => { it('should inherit host bindings from undecorated superclasses', () => { class BaseButton { - @HostBinding('attr.tabindex') - tabindex = -1; + @HostBinding('attr.tabindex') tabindex = -1; } @Component({selector: '[sub-button]', template: '<ng-content></ng-content>'}) @@ -1702,8 +1722,7 @@ describe('acceptance integration tests', () => { it('should inherit host bindings from undecorated grand superclasses', () => { class SuperBaseButton { - @HostBinding('attr.tabindex') - tabindex = -1; + @HostBinding('attr.tabindex') tabindex = -1; } class BaseButton extends SuperBaseButton {} @@ -1734,7 +1753,9 @@ describe('acceptance integration tests', () => { class BaseButton { @HostListener('click') - handleClick() { clicks++; } + handleClick() { + clicks++; + } } @Component({selector: '[sub-button]', template: '<ng-content></ng-content>'}) @@ -1761,7 +1782,9 @@ describe('acceptance integration tests', () => { @Directive({selector: '[baseButton]'}) class BaseButton { @HostListener('click') - handleClick() { clicks++; } + handleClick() { + clicks++; + } } @Component({selector: '[subButton]', template: '<ng-content></ng-content>'}) @@ -1788,7 +1811,9 @@ describe('acceptance integration tests', () => { @Directive({selector: '[superBaseButton]'}) class SuperBaseButton { @HostListener('click') - handleClick() { clicks++; } + handleClick() { + clicks++; + } } @Directive({selector: '[baseButton]'}) @@ -1819,7 +1844,9 @@ describe('acceptance integration tests', () => { @Directive({selector: '[superSuperBaseButton]'}) class SuperSuperBaseButton { @HostListener('click') - handleClick() { clicks++; } + handleClick() { + clicks++; + } } @Directive({selector: '[superBaseButton]'}) @@ -1855,9 +1882,13 @@ describe('acceptance integration tests', () => { inputs: ['dir'], }) class Dir { - get dir(): any { return null; } + get dir(): any { + return null; + } - set dir(value: any) { throw new Error('this error is expected'); } + set dir(value: any) { + throw new Error('this error is expected'); + } } @Component({ @@ -1919,7 +1950,7 @@ describe('acceptance integration tests', () => { }); const fixture = TestBed.createComponent(Cmp); fixture.detectChanges(false); - const element = fixture.nativeElement.querySelector('div') !; + const element = fixture.nativeElement.querySelector('div')!; assertAttrValues(element, 'first-update-pass'); diff --git a/packages/core/test/acceptance/lifecycle_spec.ts b/packages/core/test/acceptance/lifecycle_spec.ts index ebfd9aa7f882a..ebccdf3fe4c4e 100644 --- a/packages/core/test/acceptance/lifecycle_spec.ts +++ b/packages/core/test/acceptance/lifecycle_spec.ts @@ -69,13 +69,13 @@ describe('onChanges', () => { template: `<p>test</p>`, }) class Comp { - @Input() - val1 = 'a'; + @Input() val1 = 'a'; - @Input('publicVal2') - val2 = 'b'; + @Input('publicVal2') val2 = 'b'; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp', changes}); + } } @Component({template: `<comp [val1]="val1" [publicVal2]="val2"></comp>`}) @@ -122,10 +122,11 @@ describe('onChanges', () => { template: `<child [val]="val"></child>`, }) class Parent { - @Input() - val = ''; + @Input() val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'parent', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'parent', changes}); + } } @Component({ @@ -133,10 +134,11 @@ describe('onChanges', () => { template: `<p>test</p>`, }) class Child { - @Input() - val = ''; + @Input() val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'child', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'child', changes}); + } } @Component({template: `<parent [val]="val"></parent>`}) @@ -193,13 +195,13 @@ describe('onChanges', () => { template: `<child [name]="name" [val]="val"></child>`, }) class Parent { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'parent ' + this.name, changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'parent ' + this.name, changes}); + } } @Component({ @@ -207,13 +209,13 @@ describe('onChanges', () => { template: `<p>test</p>`, }) class Child { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'child ' + this.name, changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'child ' + this.name, changes}); + } } @Component({ @@ -303,10 +305,11 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Comp { - @Input() - val = ''; + @Input() val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp', changes}); + } } @Component({template: `<comp *ngIf="show" [val]="val"></comp>`}) @@ -355,10 +358,11 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Projected { - @Input() - val = ''; + @Input() val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'projected', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'projected', changes}); + } } @Component({ @@ -366,10 +370,11 @@ describe('onChanges', () => { template: `<div><ng-content></ng-content></div>`, }) class Comp { - @Input() - val = ''; + @Input() val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp', changes}); + } } @Component({ @@ -427,11 +432,9 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Projected { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; ngOnChanges(changes: SimpleChanges) { events.push({name: 'projected ' + this.name, changes}); @@ -443,13 +446,13 @@ describe('onChanges', () => { template: `<div><ng-content></ng-content></div>`, }) class Comp { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp ' + this.name, changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp ' + this.name, changes}); + } } @Component({ @@ -542,10 +545,11 @@ describe('onChanges', () => { selector: '[dir]', }) class Dir { - @Input() - dir = ''; + @Input() dir = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'dir', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'dir', changes}); + } } @Component({ @@ -553,10 +557,11 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Comp { - @Input() - val = ''; + @Input() val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp', changes}); + } } @Component({ @@ -608,17 +613,17 @@ describe('onChanges', () => { }); it('should be called on directives before component if component injects directives', () => { - const events: any[] = []; @Directive({ selector: '[dir]', }) class Dir { - @Input() - dir = ''; + @Input() dir = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'dir', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'dir', changes}); + } } @Component({ @@ -626,12 +631,13 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Comp { - @Input() - val = ''; + @Input() val = ''; constructor(public dir: Dir) {} - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp', changes}); + } } @Component({ @@ -680,33 +686,33 @@ describe('onChanges', () => { } } ]); - }); it('should be called on multiple directives in injection order', () => { - const events: any[] = []; @Directive({ selector: '[dir]', }) class Dir { - @Input() - dir = ''; + @Input() dir = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'dir', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'dir', changes}); + } } @Directive({ selector: '[injectionDir]', }) class InjectionDir { - @Input() - injectionDir = ''; + @Input() injectionDir = ''; constructor(public dir: Dir) {} - ngOnChanges(changes: SimpleChanges) { events.push({name: 'injectionDir', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'injectionDir', changes}); + } } @Component({ @@ -746,13 +752,13 @@ describe('onChanges', () => { selector: '[dir]', }) class Dir { - @Input() - dir = ''; + @Input() dir = ''; - @Input('dir-val') - val = ''; + @Input('dir-val') val = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'dir', changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'dir', changes}); + } } @Component({template: `<div [dir]="val1" [dir-val]="val2"></div>`}) @@ -796,13 +802,13 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Comp { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'comp ' + this.name, changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'comp ' + this.name, changes}); + } } @Component({ @@ -909,11 +915,9 @@ describe('onChanges', () => { template: `<p>{{val}}</p>`, }) class Child { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; ngOnChanges(changes: SimpleChanges) { events.push({name: 'child of parent ' + this.name, changes}); @@ -925,13 +929,13 @@ describe('onChanges', () => { template: `<child [name]="name" [val]="val"></child>`, }) class Parent { - @Input() - val = ''; + @Input() val = ''; - @Input() - name = ''; + @Input() name = ''; - ngOnChanges(changes: SimpleChanges) { events.push({name: 'parent ' + this.name, changes}); } + ngOnChanges(changes: SimpleChanges) { + events.push({name: 'parent ' + this.name, changes}); + } } @Component({ @@ -1100,7 +1104,9 @@ describe('onChanges', () => { @Component({template: `<p>{{value}}</p>`}) class App { value = 'a'; - ngOnChanges(changes: SimpleChanges) { events.push(changes); } + ngOnChanges(changes: SimpleChanges) { + events.push(changes); + } } TestBed.configureTestingModule({ @@ -1125,15 +1131,31 @@ it('should call all hooks in correct order when several directives on same node' id: number = -1; /** @internal */ - private _log(hook: string, id: number) { log.push(hook + id); } - - ngOnChanges() { this._log('onChanges', this.id); } - ngOnInit() { this._log('onInit', this.id); } - ngDoCheck() { this._log('doCheck', this.id); } - ngAfterContentInit() { this._log('afterContentInit', this.id); } - ngAfterContentChecked() { this._log('afterContentChecked', this.id); } - ngAfterViewInit() { this._log('afterViewInit', this.id); } - ngAfterViewChecked() { this._log('afterViewChecked', this.id); } + private _log(hook: string, id: number) { + log.push(hook + id); + } + + ngOnChanges() { + this._log('onChanges', this.id); + } + ngOnInit() { + this._log('onInit', this.id); + } + ngDoCheck() { + this._log('doCheck', this.id); + } + ngAfterContentInit() { + this._log('afterContentInit', this.id); + } + ngAfterContentChecked() { + this._log('afterContentChecked', this.id); + } + ngAfterViewInit() { + this._log('afterViewInit', this.id); + } + ngAfterViewChecked() { + this._log('afterViewChecked', this.id); + } } @Directive({selector: 'div'}) @@ -1190,21 +1212,31 @@ it('should call hooks after setting directives inputs', () => { @Directive({selector: 'div'}) class DirA { @Input() a: number = 0; - ngOnInit() { log.push('onInitA' + this.a); } + ngOnInit() { + log.push('onInitA' + this.a); + } } @Directive({selector: 'div'}) class DirB { @Input() b: number = 0; - ngOnInit() { log.push('onInitB' + this.b); } - ngDoCheck() { log.push('doCheckB' + this.b); } + ngOnInit() { + log.push('onInitB' + this.b); + } + ngDoCheck() { + log.push('doCheckB' + this.b); + } } @Directive({selector: 'div'}) class DirC { @Input() c: number = 0; - ngOnInit() { log.push('onInitC' + this.c); } - ngDoCheck() { log.push('doCheckC' + this.c); } + ngOnInit() { + log.push('onInitC' + this.c); + } + ngDoCheck() { + log.push('doCheckC' + this.c); + } } @Component({ @@ -1240,11 +1272,9 @@ describe('onInit', () => { template: `<p>test</p>`, }) class MyComponent { - @Input() - input1 = ''; + @Input() input1 = ''; - @Input() - input2 = ''; + @Input() input2 = ''; ngOnInit() { input1Values.push(this.input1); @@ -1285,7 +1315,9 @@ describe('onInit', () => { @Component({template: ``}) class App { - ngOnInit() { onInitCalled++; } + ngOnInit() { + onInitCalled++; + } } TestBed.configureTestingModule({ @@ -1305,14 +1337,18 @@ describe('onInit', () => { template: `<p>child</p>`, }) class ChildComp { - ngOnInit() { initCalls.push('child'); } + ngOnInit() { + initCalls.push('child'); + } } @Component({ template: `<child-comp></child-comp>`, }) class ParentComp { - ngOnInit() { initCalls.push('parent'); } + ngOnInit() { + initCalls.push('parent'); + } } TestBed.configureTestingModule({ @@ -1332,10 +1368,11 @@ describe('onInit', () => { template: `<p>child</p>`, }) class ChildComp { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initCalls.push(`child of parent ${this.name}`); } + ngOnInit() { + initCalls.push(`child of parent ${this.name}`); + } } @Component({ @@ -1343,10 +1380,11 @@ describe('onInit', () => { template: `<child-comp [name]="name"></child-comp>`, }) class ParentComp { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initCalls.push(`parent ${this.name}`); } + ngOnInit() { + initCalls.push(`parent ${this.name}`); + } } @Component({ @@ -1372,7 +1410,9 @@ describe('onInit', () => { @Component({selector: 'my-comp', template: '<p>test</p>'}) class MyComp { - ngOnInit() { onInitCalls++; } + ngOnInit() { + onInitCalls++; + } } @Component({ @@ -1407,7 +1447,9 @@ describe('onInit', () => { class MyComp { onInitCalled = false; - ngOnInit() { this.onInitCalled = true; } + ngOnInit() { + this.onInitCalled = true; + } } @Component({ @@ -1425,8 +1467,7 @@ describe('onInit', () => { `, }) class App { - @ViewChild('container', {read: ViewContainerRef}) - viewContainerRef !: ViewContainerRef; + @ViewChild('container', {read: ViewContainerRef}) viewContainerRef!: ViewContainerRef; constructor(public compFactoryResolver: ComponentFactoryResolver) {} @@ -1464,7 +1505,9 @@ describe('onInit', () => { template: '', }) class Projected { - ngOnInit() { initialized.push('projected'); } + ngOnInit() { + initialized.push('projected'); + } } @Component({ @@ -1472,7 +1515,9 @@ describe('onInit', () => { template: `<ng-content></ng-content>`, }) class Comp { - ngOnInit() { initialized.push('comp'); } + ngOnInit() { + initialized.push('comp'); + } } @Component({ @@ -1483,7 +1528,9 @@ describe('onInit', () => { ` }) class App { - ngOnInit() { initialized.push('app'); } + ngOnInit() { + initialized.push('app'); + } } TestBed.configureTestingModule({ @@ -1504,10 +1551,11 @@ describe('onInit', () => { template: '', }) class Projected { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initialized.push('projected ' + this.name); } + ngOnInit() { + initialized.push('projected ' + this.name); + } } @Component({ @@ -1515,10 +1563,11 @@ describe('onInit', () => { template: `<ng-content></ng-content>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initialized.push('comp ' + this.name); } + ngOnInit() { + initialized.push('comp ' + this.name); + } } @Component({ @@ -1532,7 +1581,9 @@ describe('onInit', () => { ` }) class App { - ngOnInit() { initialized.push('app'); } + ngOnInit() { + initialized.push('app'); + } } TestBed.configureTestingModule({ @@ -1551,10 +1602,11 @@ describe('onInit', () => { selector: '[dir]', }) class Dir { - @Input('dir-name') - name = ''; + @Input('dir-name') name = ''; - ngOnInit() { initialized.push('dir ' + this.name); } + ngOnInit() { + initialized.push('dir ' + this.name); + } } @Component({ @@ -1562,10 +1614,11 @@ describe('onInit', () => { template: `<p></p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initialized.push('comp ' + this.name); } + ngOnInit() { + initialized.push('comp ' + this.name); + } } @Component({ @@ -1575,7 +1628,9 @@ describe('onInit', () => { ` }) class App { - ngOnInit() { initialized.push('app'); } + ngOnInit() { + initialized.push('app'); + } } TestBed.configureTestingModule({ @@ -1588,29 +1643,30 @@ describe('onInit', () => { }); it('should be called on multiple directives in injection order', () => { - const events: any[] = []; @Directive({ selector: '[dir]', }) class Dir { - @Input() - dir = ''; + @Input() dir = ''; - ngOnInit() { events.push('dir'); } + ngOnInit() { + events.push('dir'); + } } @Directive({ selector: '[injectionDir]', }) class InjectionDir { - @Input() - injectionDir = ''; + @Input() injectionDir = ''; constructor(public dir: Dir) {} - ngOnInit() { events.push('injectionDir'); } + ngOnInit() { + events.push('injectionDir'); + } } @Component({ @@ -1619,7 +1675,9 @@ describe('onInit', () => { class App { val = 'a'; - ngOnInit() { events.push('app'); } + ngOnInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -1638,10 +1696,11 @@ describe('onInit', () => { selector: '[dir]', }) class Dir { - @Input('dir-name') - name = ''; + @Input('dir-name') name = ''; - ngOnInit() { initialized.push('dir ' + this.name); } + ngOnInit() { + initialized.push('dir ' + this.name); + } } @Component({ @@ -1649,12 +1708,13 @@ describe('onInit', () => { template: `<p></p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; constructor(public dir: Dir) {} - ngOnInit() { initialized.push('comp ' + this.name); } + ngOnInit() { + initialized.push('comp ' + this.name); + } } @Component({ @@ -1664,7 +1724,9 @@ describe('onInit', () => { ` }) class App { - ngOnInit() { initialized.push('app'); } + ngOnInit() { + initialized.push('app'); + } } TestBed.configureTestingModule({ @@ -1683,10 +1745,11 @@ describe('onInit', () => { selector: '[dir]', }) class Dir { - @Input('dir-name') - name = ''; + @Input('dir-name') name = ''; - ngOnInit() { initialized.push('dir ' + this.name); } + ngOnInit() { + initialized.push('dir ' + this.name); + } } @Component({ @@ -1696,7 +1759,9 @@ describe('onInit', () => { ` }) class App { - ngOnInit() { initialized.push('app'); } + ngOnInit() { + initialized.push('app'); + } } TestBed.configureTestingModule({ @@ -1717,10 +1782,11 @@ describe('onInit', () => { template: `<p></p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initialized.push('comp ' + this.name); } + ngOnInit() { + initialized.push('comp ' + this.name); + } } @Component({ @@ -1754,18 +1820,20 @@ describe('onInit', () => { template: `<p></p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initialized.push('child of parent ' + this.name); } + ngOnInit() { + initialized.push('child of parent ' + this.name); + } } @Component({selector: 'parent', template: '<child [name]="name"></child>'}) class Parent { - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { initialized.push('parent ' + this.name); } + ngOnInit() { + initialized.push('parent ' + this.name); + } } @Component({ @@ -1816,7 +1884,9 @@ describe('doCheck', () => { @Component({template: ``}) class App { - ngDoCheck() { doCheckCalled++; } + ngDoCheck() { + doCheckCalled++; + } } TestBed.configureTestingModule({ @@ -1840,7 +1910,9 @@ describe('doCheck', () => { template: `<child></child>`, }) class Parent { - ngDoCheck() { doChecks.push('parent'); } + ngDoCheck() { + doChecks.push('parent'); + } } @Component({ @@ -1848,12 +1920,16 @@ describe('doCheck', () => { template: ``, }) class Child { - ngDoCheck() { doChecks.push('child'); } + ngDoCheck() { + doChecks.push('child'); + } } @Component({template: `<parent></parent>`}) class App { - ngDoCheck() { doChecks.push('app'); } + ngDoCheck() { + doChecks.push('app'); + } } TestBed.configureTestingModule({ @@ -1869,9 +1945,13 @@ describe('doCheck', () => { const events: string[] = []; @Component({template: ``}) class App { - ngOnInit() { events.push('onInit'); } + ngOnInit() { + events.push('onInit'); + } - ngDoCheck() { events.push('doCheck'); } + ngDoCheck() { + events.push('doCheck'); + } } TestBed.configureTestingModule({ @@ -1889,10 +1969,11 @@ describe('doCheck', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngDoCheck() { doChecks.push('dir ' + this.name); } + ngDoCheck() { + doChecks.push('dir ' + this.name); + } } @Component({ @@ -1900,10 +1981,11 @@ describe('doCheck', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngDoCheck() { doChecks.push('comp ' + this.name); } + ngDoCheck() { + doChecks.push('comp ' + this.name); + } } @Component({ @@ -1913,7 +1995,9 @@ describe('doCheck', () => { ` }) class App { - ngDoCheck() { doChecks.push('app'); } + ngDoCheck() { + doChecks.push('app'); + } } TestBed.configureTestingModule({ @@ -1931,10 +2015,11 @@ describe('doCheck', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngDoCheck() { doChecks.push('dir ' + this.name); } + ngDoCheck() { + doChecks.push('dir ' + this.name); + } } @Component({ @@ -1942,12 +2027,13 @@ describe('doCheck', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; constructor(public dir: Dir) {} - ngDoCheck() { doChecks.push('comp ' + this.name); } + ngDoCheck() { + doChecks.push('comp ' + this.name); + } } @Component({ @@ -1957,7 +2043,9 @@ describe('doCheck', () => { ` }) class App { - ngDoCheck() { doChecks.push('app'); } + ngDoCheck() { + doChecks.push('app'); + } } TestBed.configureTestingModule({ @@ -1970,29 +2058,30 @@ describe('doCheck', () => { }); it('should be called on multiple directives in injection order', () => { - const events: any[] = []; @Directive({ selector: '[dir]', }) class Dir { - @Input() - dir = ''; + @Input() dir = ''; - ngDoCheck() { events.push('dir'); } + ngDoCheck() { + events.push('dir'); + } } @Directive({ selector: '[injectionDir]', }) class InjectionDir { - @Input() - injectionDir = ''; + @Input() injectionDir = ''; constructor(public dir: Dir) {} - ngDoCheck() { events.push('injectionDir'); } + ngDoCheck() { + events.push('injectionDir'); + } } @Component({ @@ -2001,7 +2090,9 @@ describe('doCheck', () => { class App { val = 'a'; - ngDoCheck() { events.push('app'); } + ngDoCheck() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2020,10 +2111,11 @@ describe('doCheck', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngDoCheck() { doChecks.push('dir ' + this.name); } + ngDoCheck() { + doChecks.push('dir ' + this.name); + } } @Component({ @@ -2033,7 +2125,9 @@ describe('doCheck', () => { ` }) class App { - ngDoCheck() { doChecks.push('app'); } + ngDoCheck() { + doChecks.push('app'); + } } TestBed.configureTestingModule({ @@ -2055,7 +2149,9 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class Comp { - ngAfterContentInit() { afterContentInitCalls++; } + ngAfterContentInit() { + afterContentInitCalls++; + } } @Component({template: `<comp></comp>`}) class App { @@ -2079,7 +2175,9 @@ describe('afterContentinit', () => { @Component({template: `<p>test</p>`}) class App { - ngAfterContentInit() { afterContentInitCalls++; } + ngAfterContentInit() { + afterContentInitCalls++; + } } TestBed.configureTestingModule({ @@ -2103,14 +2201,18 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class Comp { - ngAfterContentInit() { events.push('comp afterContentInit'); } + ngAfterContentInit() { + events.push('comp afterContentInit'); + } } @Component({template: `<comp *ngIf="show"></comp>`}) class App { show = true; - ngAfterContentInit() { events.push('app afterContentInit'); } + ngAfterContentInit() { + events.push('app afterContentInit'); + } } TestBed.configureTestingModule({ @@ -2143,10 +2245,11 @@ describe('afterContentinit', () => { template: `<child [name]="name"></child>`, }) class Parent { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('parent ' + this.name); } + ngAfterContentInit() { + events.push('parent ' + this.name); + } } @Component({ @@ -2154,10 +2257,11 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('child of parent ' + this.name); } + ngAfterContentInit() { + events.push('child of parent ' + this.name); + } } @Component({ @@ -2167,7 +2271,9 @@ describe('afterContentinit', () => { ` }) class App { - ngAfterContentInit() { events.push('app'); } + ngAfterContentInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2188,10 +2294,11 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class ProjectedChild { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('projected child ' + this.name); } + ngAfterContentInit() { + events.push('projected child ' + this.name); + } } @Component({ @@ -2199,10 +2306,11 @@ describe('afterContentinit', () => { template: `<div><ng-content></ng-content></div>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('comp ' + this.name); } + ngAfterContentInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2210,10 +2318,11 @@ describe('afterContentinit', () => { template: `<projected-child [name]=name></projected-child>`, }) class Projected { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('projected ' + this.name); } + ngAfterContentInit() { + events.push('projected ' + this.name); + } } @Component({ @@ -2229,7 +2338,9 @@ describe('afterContentinit', () => { ` }) class App { - ngAfterContentInit() { events.push('app'); } + ngAfterContentInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2267,10 +2378,11 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('comp ' + this.name); } + ngAfterContentInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2283,7 +2395,9 @@ describe('afterContentinit', () => { class App { numbers = [0, 1, 2, 3]; - ngAfterContentInit() { events.push('app'); } + ngAfterContentInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2304,10 +2418,11 @@ describe('afterContentinit', () => { template: `<child [name]=name></child>`, }) class Parent { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('parent ' + this.name); } + ngAfterContentInit() { + events.push('parent ' + this.name); + } } @Component({ @@ -2315,10 +2430,11 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('child of parent ' + this.name); } + ngAfterContentInit() { + events.push('child of parent ' + this.name); + } } @Component({ @@ -2330,7 +2446,9 @@ describe('afterContentinit', () => { }) class App { numbers = [0, 1, 2, 3]; - ngAfterContentInit() { events.push('app'); } + ngAfterContentInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2366,10 +2484,11 @@ describe('afterContentinit', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngAfterContentInit() { events.push('dir ' + this.name); } + ngAfterContentInit() { + events.push('dir ' + this.name); + } } @Component({ @@ -2377,10 +2496,11 @@ describe('afterContentinit', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterContentInit() { events.push('comp ' + this.name); } + ngAfterContentInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2390,7 +2510,9 @@ describe('afterContentinit', () => { ` }) class App { - ngAfterContentInit() { events.push('app'); } + ngAfterContentInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2418,16 +2540,24 @@ describe('afterContentChecked', () => { template: `<p>test</p>`, }) class Comp { - ngAfterContentInit() { events.push('comp afterContentInit'); } + ngAfterContentInit() { + events.push('comp afterContentInit'); + } - ngAfterContentChecked() { events.push('comp afterContentChecked'); } + ngAfterContentChecked() { + events.push('comp afterContentChecked'); + } } @Component({template: `<comp></comp>`}) class App { - ngAfterContentInit() { events.push('app afterContentInit'); } + ngAfterContentInit() { + events.push('app afterContentInit'); + } - ngAfterContentChecked() { events.push('app afterContentChecked'); } + ngAfterContentChecked() { + events.push('app afterContentChecked'); + } } TestBed.configureTestingModule({ @@ -2454,7 +2584,9 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Comp { - ngAfterViewInit() { afterViewInitCalls++; } + ngAfterViewInit() { + afterViewInitCalls++; + } } @Component({template: `<comp></comp>`}) @@ -2472,7 +2604,6 @@ describe('afterViewInit', () => { fixture.detectChanges(); expect(afterViewInitCalls).toBe(1); - }); it('should be called on root component in creation mode', () => { @@ -2480,7 +2611,9 @@ describe('afterViewInit', () => { @Component({template: `<p>test</p>`}) class App { - ngAfterViewInit() { afterViewInitCalls++; } + ngAfterViewInit() { + afterViewInitCalls++; + } } TestBed.configureTestingModule({ @@ -2504,7 +2637,9 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Comp { - ngAfterViewInit() { events.push('comp'); } + ngAfterViewInit() { + events.push('comp'); + } } @Component({ @@ -2513,7 +2648,9 @@ describe('afterViewInit', () => { class App { show = true; - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2543,10 +2680,11 @@ describe('afterViewInit', () => { template: `<child [name]=name></child>`, }) class Parent { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('parent ' + this.name); } + ngAfterViewInit() { + events.push('parent ' + this.name); + } } @Component({ @@ -2554,10 +2692,11 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('child of parent ' + this.name); } + ngAfterViewInit() { + events.push('child of parent ' + this.name); + } } @Component({ @@ -2567,7 +2706,9 @@ describe('afterViewInit', () => { ` }) class App { - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2593,10 +2734,11 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Projected { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('projected ' + this.name); } + ngAfterViewInit() { + events.push('projected ' + this.name); + } } @Component({ @@ -2604,10 +2746,11 @@ describe('afterViewInit', () => { template: `<ng-content></ng-content>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('comp ' + this.name); } + ngAfterViewInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2617,7 +2760,9 @@ describe('afterViewInit', () => { ` }) class App { - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2644,10 +2789,11 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class ProjectedChild { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('child of projected ' + this.name); } + ngAfterViewInit() { + events.push('child of projected ' + this.name); + } } @Component({ @@ -2655,10 +2801,11 @@ describe('afterViewInit', () => { template: `<projected-child [name]="name"></projected-child>`, }) class Projected { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('projected ' + this.name); } + ngAfterViewInit() { + events.push('projected ' + this.name); + } } @Component({ @@ -2666,10 +2813,11 @@ describe('afterViewInit', () => { template: `<div><ng-content></ng-content></div>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('comp ' + this.name); } + ngAfterViewInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2679,7 +2827,9 @@ describe('afterViewInit', () => { ` }) class App { - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2707,10 +2857,11 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('comp ' + this.name); } + ngAfterViewInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2723,7 +2874,9 @@ describe('afterViewInit', () => { class App { numbers = [0, 1, 2, 3]; - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2752,20 +2905,22 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('child of parent ' + this.name); } + ngAfterViewInit() { + events.push('child of parent ' + this.name); + } } @Component({ selector: 'parent', template: `<child [name]="name"></child>`, }) class Parent { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('parent ' + this.name); } + ngAfterViewInit() { + events.push('parent ' + this.name); + } } @Component({ @@ -2778,7 +2933,9 @@ describe('afterViewInit', () => { class App { numbers = [0, 1, 2, 3]; - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2812,10 +2969,11 @@ describe('afterViewInit', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngAfterViewInit() { events.push('dir ' + this.name); } + ngAfterViewInit() { + events.push('dir ' + this.name); + } } @Component({ @@ -2823,10 +2981,11 @@ describe('afterViewInit', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewInit() { events.push('comp ' + this.name); } + ngAfterViewInit() { + events.push('comp ' + this.name); + } } @Component({ @@ -2836,7 +2995,9 @@ describe('afterViewInit', () => { ` }) class App { - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2861,10 +3022,11 @@ describe('afterViewInit', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngAfterViewInit() { events.push('dir ' + this.name); } + ngAfterViewInit() { + events.push('dir ' + this.name); + } } @Component({ @@ -2874,7 +3036,9 @@ describe('afterViewInit', () => { ` }) class App { - ngAfterViewInit() { events.push('app'); } + ngAfterViewInit() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -2900,7 +3064,9 @@ describe('afterViewChecked', () => { template: `<p>test</p>`, }) class Comp { - ngAfterViewChecked() { afterViewCheckedCalls++; } + ngAfterViewChecked() { + afterViewCheckedCalls++; + } } @Component({template: `<comp></comp>`}) @@ -2927,7 +3093,9 @@ describe('afterViewChecked', () => { @Component({template: `<p>test</p>`}) class App { - ngAfterViewChecked() { afterViewCheckedCalls++; } + ngAfterViewChecked() { + afterViewCheckedCalls++; + } } TestBed.configureTestingModule({ @@ -2953,9 +3121,10 @@ describe('afterViewChecked', () => { template: `<p>{{value}}</p>`, }) class Comp { - @Input() - value = ''; - ngAfterViewChecked() { afterViewCheckedCalls++; } + @Input() value = ''; + ngAfterViewChecked() { + afterViewCheckedCalls++; + } } @Component({template: `<comp [value]="value"></comp>`}) @@ -2983,10 +3152,11 @@ describe('afterViewChecked', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewChecked() { events.push('child of parent ' + this.name); } + ngAfterViewChecked() { + events.push('child of parent ' + this.name); + } } @Component({ @@ -2994,10 +3164,11 @@ describe('afterViewChecked', () => { template: `<child [name]="name"></child>`, }) class Parent { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewChecked() { events.push('parent ' + this.name); } + ngAfterViewChecked() { + events.push('parent ' + this.name); + } } @Component({ @@ -3010,7 +3181,9 @@ describe('afterViewChecked', () => { class App { numbers = [0, 1, 2, 3]; - ngAfterViewChecked() { events.push('app'); } + ngAfterViewChecked() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -3043,10 +3216,11 @@ describe('afterViewChecked', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngAfterViewChecked() { events.push('dir ' + this.name); } + ngAfterViewChecked() { + events.push('dir ' + this.name); + } } @Component({ @@ -3054,10 +3228,11 @@ describe('afterViewChecked', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngAfterViewChecked() { events.push('comp ' + this.name); } + ngAfterViewChecked() { + events.push('comp ' + this.name); + } } @Component({ @@ -3067,7 +3242,9 @@ describe('afterViewChecked', () => { ` }) class App { - ngAfterViewChecked() { events.push('app'); } + ngAfterViewChecked() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -3092,10 +3269,11 @@ describe('afterViewChecked', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngAfterViewChecked() { events.push('dir ' + this.name); } + ngAfterViewChecked() { + events.push('dir ' + this.name); + } } @Component({ @@ -3105,7 +3283,9 @@ describe('afterViewChecked', () => { ` }) class App { - ngAfterViewChecked() { events.push('app'); } + ngAfterViewChecked() { + events.push('app'); + } } TestBed.configureTestingModule({ @@ -3120,12 +3300,9 @@ describe('afterViewChecked', () => { 'app', ]); }); - }); describe('onDestroy', () => { - - it('should call destroy when view is removed', () => { let destroyCalled = 0; @@ -3134,7 +3311,9 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Comp { - ngOnDestroy() { destroyCalled++; } + ngOnDestroy() { + destroyCalled++; + } } @Component({ @@ -3177,10 +3356,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('comp ' + this.name); } + ngOnDestroy() { + events.push('comp ' + this.name); + } } @Component({ @@ -3218,10 +3398,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('child of parent ' + this.name); } + ngOnDestroy() { + events.push('child of parent ' + this.name); + } } @Component({ @@ -3229,9 +3410,10 @@ describe('onDestroy', () => { template: `<child [name]="name"></child>`, }) class Parent { - @Input() - name = ''; - ngOnDestroy() { events.push('parent ' + this.name); } + @Input() name = ''; + ngOnDestroy() { + events.push('parent ' + this.name); + } } @Component({ @@ -3274,10 +3456,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Child { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('child ' + this.name); } + ngOnDestroy() { + events.push('child ' + this.name); + } } @Component({ @@ -3285,9 +3468,10 @@ describe('onDestroy', () => { template: `<child [name]="name"></child>`, }) class Parent { - @Input() - name = ''; - ngOnDestroy() { events.push('parent ' + this.name); } + @Input() name = ''; + ngOnDestroy() { + events.push('parent ' + this.name); + } } @Component({ @@ -3295,10 +3479,11 @@ describe('onDestroy', () => { template: `<parent [name]="name"></parent>`, }) class Grandparent { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('grandparent ' + this.name); } + ngOnDestroy() { + events.push('grandparent ' + this.name); + } } @Component({ template: ` @@ -3342,10 +3527,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Projected { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('projected ' + this.name); } + ngOnDestroy() { + events.push('projected ' + this.name); + } } @Component({ @@ -3353,10 +3539,11 @@ describe('onDestroy', () => { template: `<div><ng-content></ng-content></div>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('comp ' + this.name); } + ngOnDestroy() { + events.push('comp ' + this.name); + } } @Component({ @@ -3403,10 +3590,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('comp ' + this.name); } + ngOnDestroy() { + events.push('comp ' + this.name); + } } @Component({ @@ -3473,10 +3661,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('comp ' + this.name); } + ngOnDestroy() { + events.push('comp ' + this.name); + } } @Component({ @@ -3551,7 +3740,9 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Comp { - ngOnDestroy() { events.push('comp'); } + ngOnDestroy() { + events.push('comp'); + } } @Component({ template: ` @@ -3569,9 +3760,13 @@ describe('onDestroy', () => { clicksToButton2 = 0; - handleClick1() { this.clicksToButton1++; } + handleClick1() { + this.clicksToButton1++; + } - handleClick2() { this.clicksToButton2++; } + handleClick2() { + this.clicksToButton2++; + } } TestBed.configureTestingModule({ @@ -3604,7 +3799,7 @@ describe('onDestroy', () => { @Component({selector: 'parent', template: `<ng-content></ng-content>`}) class Parent { - @ContentChildren(Child, {descendants: true}) child !: QueryList<Child>; + @ContentChildren(Child, {descendants: true}) child!: QueryList<Child>; } @Component({ @@ -3619,13 +3814,13 @@ describe('onDestroy', () => { ` }) class App { - @ViewChild('container', {read: ViewContainerRef, static: true}) - container !: ViewContainerRef; + @ViewChild('container', {read: ViewContainerRef, static: true}) container!: ViewContainerRef; - @ViewChild('tpl', {read: TemplateRef, static: true}) - tpl !: TemplateRef<any>; + @ViewChild('tpl', {read: TemplateRef, static: true}) tpl!: TemplateRef<any>; - ngOnInit() { this.container.createEmbeddedView(this.tpl); } + ngOnInit() { + this.container.createEmbeddedView(this.tpl); + } } @Directive({selector: '[dir]'}) @@ -3659,10 +3854,11 @@ describe('onDestroy', () => { selector: '[dir]', }) class Dir { - @Input('dir') - name = ''; + @Input('dir') name = ''; - ngOnDestroy() { events.push('dir ' + this.name); } + ngOnDestroy() { + events.push('dir ' + this.name); + } } @Component({ @@ -3670,10 +3866,11 @@ describe('onDestroy', () => { template: `<p>test</p>`, }) class Comp { - @Input() - name = ''; + @Input() name = ''; - ngOnDestroy() { events.push('comp ' + this.name); } + ngOnDestroy() { + events.push('comp ' + this.name); + } } @Component({ @@ -3715,7 +3912,9 @@ describe('onDestroy', () => { selector: '[dir]', }) class Dir { - ngOnDestroy() { events.push('dir'); } + ngOnDestroy() { + events.push('dir'); + } } @Component({template: `<p *ngIf="show" dir></p>`}) @@ -3749,27 +3948,41 @@ describe('hook order', () => { template: `{{value}}<div><ng-content></ng-content></div>`, }) class Comp { - @Input() - value = ''; + @Input() value = ''; - @Input() - name = ''; + @Input() name = ''; - ngOnInit() { events.push(`${this.name} onInit`); } + ngOnInit() { + events.push(`${this.name} onInit`); + } - ngDoCheck() { events.push(`${this.name} doCheck`); } + ngDoCheck() { + events.push(`${this.name} doCheck`); + } - ngOnChanges() { events.push(`${this.name} onChanges`); } + ngOnChanges() { + events.push(`${this.name} onChanges`); + } - ngAfterContentInit() { events.push(`${this.name} afterContentInit`); } + ngAfterContentInit() { + events.push(`${this.name} afterContentInit`); + } - ngAfterContentChecked() { events.push(`${this.name} afterContentChecked`); } + ngAfterContentChecked() { + events.push(`${this.name} afterContentChecked`); + } - ngAfterViewInit() { events.push(`${this.name} afterViewInit`); } + ngAfterViewInit() { + events.push(`${this.name} afterViewInit`); + } - ngAfterViewChecked() { events.push(`${this.name} afterViewChecked`); } + ngAfterViewChecked() { + events.push(`${this.name} afterViewChecked`); + } - ngOnDestroy() { events.push(`${this.name} onDestroy`); } + ngOnDestroy() { + events.push(`${this.name} onDestroy`); + } } @Component({ @@ -4044,7 +4257,9 @@ describe('non-regression', () => { selector: '[onDestroyDir]', }) class OnDestroyDir { - ngOnDestroy() { destroyed = true; } + ngOnDestroy() { + destroyed = true; + } } @Component({ diff --git a/packages/core/test/acceptance/listener_spec.ts b/packages/core/test/acceptance/listener_spec.ts index 8c42981b12b81..7bb045800cd04 100644 --- a/packages/core/test/acceptance/listener_spec.ts +++ b/packages/core/test/acceptance/listener_spec.ts @@ -16,36 +16,40 @@ function getNoOfNativeListeners(): number { } describe('event listeners', () => { - describe('coalescing', () => { - @Component({ selector: 'with-clicks-cmpt', template: `<button likes-clicks (click)="count()" md-button>Click me!</button>` }) class WithClicksCmpt { counter = 0; - count() { this.counter++; } + count() { + this.counter++; + } } @Directive({selector: '[md-button]'}) class MdButton { counter = 0; @HostListener('click') - count() { this.counter++; } + count() { + this.counter++; + } } @Directive({selector: '[likes-clicks]'}) class LikesClicks { counter = 0; @HostListener('click') - count() { this.counter++; } + count() { + this.counter++; + } } @Directive({selector: '[returns-false]'}) class ReturnsFalse { counter = 0; - event !: Event; + event!: Event; handlerShouldReturn: boolean|undefined = undefined; @HostListener('click', ['$event']) @@ -65,7 +69,6 @@ describe('event listeners', () => { onlyInIvy('ngDevMode.rendererAddEventListener counters are only available in ivy') .it('should coalesce multiple event listeners for the same event on the same element', () => { - @Component({ selector: 'test-cmpt', template: @@ -107,7 +110,6 @@ describe('event listeners', () => { onlyInIvy('ngDevMode.rendererAddEventListener counters are only available in ivy') .it('should coalesce multiple event listeners in presence of queries', () => { - @Component({ selector: 'test-cmpt', template: `<button likes-clicks (click)="counter = counter+1">Click me!</button>` @@ -115,7 +117,7 @@ describe('event listeners', () => { class TestCmpt { counter = 0; - @ViewChildren('nothing') nothing !: QueryList<any>; + @ViewChildren('nothing') nothing!: QueryList<any>; } TestBed.configureTestingModule({declarations: [TestCmpt, LikesClicks]}); @@ -136,11 +138,12 @@ describe('event listeners', () => { it('should try to execute remaining coalesced listeners if one of the listeners throws', () => { - @Directive({selector: '[throws-on-clicks]'}) class ThrowsOnClicks { @HostListener('click') - dontCount() { throw new Error('I was clicked and I don\'t like it!'); } + dontCount() { + throw new Error('I was clicked and I don\'t like it!'); + } } @Component( @@ -151,7 +154,9 @@ describe('event listeners', () => { let noOfErrors = 0; class CountingErrorHandler extends ErrorHandler { - handleError(error: any): void { noOfErrors++; } + handleError(error: any): void { + noOfErrors++; + } } TestBed.configureTestingModule({ @@ -209,7 +214,9 @@ describe('event listeners', () => { @Input('foo') model: any; @Output('fooChange') update = new EventEmitter(); - updateValue(value: any) { this.update.emit(value); } + updateValue(value: any) { + this.update.emit(value); + } } @Component({ @@ -222,9 +229,13 @@ describe('event listeners', () => { @ViewChild(FooDirective) fooDirective: FooDirective|null = null; - fooChange() { this.count++; } + fooChange() { + this.count++; + } - triggerUpdate(value: any) { this.fooDirective !.updateValue(value); } + triggerUpdate(value: any) { + this.fooDirective!.updateValue(value); + } } TestBed.configureTestingModule({declarations: [TestComponent, FooDirective]}); @@ -247,19 +258,25 @@ describe('event listeners', () => { }) class MyComp { counter = 0; - count() { log.push('component.click'); } + count() { + log.push('component.click'); + } } @Directive({selector: '[dirA]'}) class DirA { @HostListener('click') - count() { log.push('dirA.click'); } + count() { + log.push('dirA.click'); + } } @Directive({selector: '[dirB]'}) class DirB { @HostListener('click') - count() { log.push('dirB.click'); } + count() { + log.push('dirB.click'); + } } TestBed.configureTestingModule({declarations: [MyComp, DirA, DirB]}); diff --git a/packages/core/test/acceptance/ng_module_spec.ts b/packages/core/test/acceptance/ng_module_spec.ts index e23031c32ed64..6c6d53643a8ad 100644 --- a/packages/core/test/acceptance/ng_module_spec.ts +++ b/packages/core/test/acceptance/ng_module_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {CUSTOM_ELEMENTS_SCHEMA, Component, Injectable, InjectionToken, NO_ERRORS_SCHEMA, NgModule, NgModuleRef, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵelement as element} from '@angular/core'; +import {Component, CUSTOM_ELEMENTS_SCHEMA, Injectable, InjectionToken, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵelement as element} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; @@ -84,12 +84,16 @@ describe('NgModule', () => { } @NgModule({providers: [Service]}) class RoutesModule { - constructor(service: Service) { service.initializations.push('RoutesModule'); } + constructor(service: Service) { + service.initializations.push('RoutesModule'); + } } @NgModule({imports: [RoutesModule]}) class AppModule { - constructor(service: Service) { service.initializations.push('AppModule'); } + constructor(service: Service) { + service.initializations.push('AppModule'); + } } TestBed.configureTestingModule({imports: [AppModule]}); @@ -188,7 +192,6 @@ describe('NgModule', () => { onlyInIvy('unknown element check logs a warning rather than throwing') .it('should warn about unknown element without CUSTOM_ELEMENTS_SCHEMA for element with dash in tag name', () => { - @Component({template: `<custom-el></custom-el>`}) class MyComp { } @@ -262,11 +265,12 @@ describe('NgModule', () => { selectors: [['comp']], decls: 1, vars: 0, - template: function MyComp_Template(rf, ctx) { - if (rf & 1) { - element(0, 'custom-el'); - } - }, + template: + function MyComp_Template(rf, ctx) { + if (rf & 1) { + element(0, 'custom-el'); + } + }, encapsulation: 2 }); } @@ -472,7 +476,6 @@ describe('NgModule', () => { fixture.detectChanges(); }).not.toThrow(); }); - }); it('should be able to use DI through the NgModuleRef inside the module constructor', () => { @@ -484,7 +487,9 @@ describe('NgModule', () => { providers: [{provide: token, useValue: 'foo'}], }) class TestModule { - constructor(ngRef: NgModuleRef<TestModule>) { value = ngRef.injector.get(token); } + constructor(ngRef: NgModuleRef<TestModule>) { + value = ngRef.injector.get(token); + } } TestBed.configureTestingModule({imports: [TestModule], declarations: [TestCmp]}); @@ -514,5 +519,4 @@ describe('NgModule', () => { TestBed.createComponent(TestCmp); expect(componentInstance).toBeAnInstanceOf(TestCmp); }); - }); diff --git a/packages/core/test/acceptance/ngdevmode_debug_spec.ts b/packages/core/test/acceptance/ngdevmode_debug_spec.ts index 44027dea6e27c..080c532098d5a 100644 --- a/packages/core/test/acceptance/ngdevmode_debug_spec.ts +++ b/packages/core/test/acceptance/ngdevmode_debug_spec.ts @@ -40,10 +40,9 @@ onlyInIvy('Debug information exist in ivy only').describe('ngDevMode debug', () const element: HTMLElement = fixture.nativeElement; fixture.detectChanges(); - const li = element.querySelector('li') !; + const li = element.querySelector('li')!; const embeddedLView = loadLContext(li).lView; expect(embeddedLView.constructor.name).toEqual('LEmbeddedView_MyApp_li_1'); - }); }); }); diff --git a/packages/core/test/acceptance/outputs_spec.ts b/packages/core/test/acceptance/outputs_spec.ts index 873b6633888f3..f99f3f26eff45 100644 --- a/packages/core/test/acceptance/outputs_spec.ts +++ b/packages/core/test/acceptance/outputs_spec.ts @@ -13,29 +13,27 @@ import {TestBed} from '@angular/core/testing'; describe('outputs', () => { @Component({selector: 'button-toggle', template: ''}) class ButtonToggle { - @Output('change') - change = new EventEmitter(); + @Output('change') change = new EventEmitter(); - @Output('reset') - resetStream = new EventEmitter(); + @Output('reset') resetStream = new EventEmitter(); } @Directive({selector: '[otherDir]'}) class OtherDir { - @Output('change') - changeStream = new EventEmitter(); + @Output('change') changeStream = new EventEmitter(); } @Component({selector: 'destroy-comp', template: ''}) class DestroyComp implements OnDestroy { events: string[] = []; - ngOnDestroy() { this.events.push('destroy'); } + ngOnDestroy() { + this.events.push('destroy'); + } } @Directive({selector: '[myButton]'}) class MyButton { - @Output() - click = new EventEmitter(); + @Output() click = new EventEmitter(); } it('should call component output function when event is emitted', () => { @@ -43,8 +41,10 @@ describe('outputs', () => { @Component({template: '<button-toggle (change)="onChange()"></button-toggle>'}) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; - onChange() { counter++; } + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; + onChange() { + counter++; + } } TestBed.configureTestingModule({declarations: [App, ButtonToggle]}); const fixture = TestBed.createComponent(App); @@ -64,9 +64,13 @@ describe('outputs', () => { @Component( {template: '<button-toggle (change)="onChange()" (reset)="onReset()"></button-toggle>'}) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; - onChange() { counter++; } - onReset() { resetCounter++; } + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; + onChange() { + counter++; + } + onReset() { + resetCounter++; + } } TestBed.configureTestingModule({declarations: [App, ButtonToggle]}); const fixture = TestBed.createComponent(App); @@ -82,7 +86,7 @@ describe('outputs', () => { it('should eval component output expression when event is emitted', () => { @Component({template: '<button-toggle (change)="counter = counter + 1"></button-toggle>'}) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; counter = 0; } TestBed.configureTestingModule({declarations: [App, ButtonToggle]}); @@ -102,10 +106,12 @@ describe('outputs', () => { @Component( {template: '<button-toggle *ngIf="condition" (change)="onChange()"></button-toggle>'}) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; condition = true; - onChange() { counter++; } + onChange() { + counter++; + } } TestBed.configureTestingModule({imports: [CommonModule], declarations: [App, ButtonToggle]}); const fixture = TestBed.createComponent(App); @@ -133,11 +139,13 @@ describe('outputs', () => { ` }) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; condition = true; condition2 = true; - onChange() { counter++; } + onChange() { + counter++; + } } TestBed.configureTestingModule({imports: [CommonModule], declarations: [App, ButtonToggle]}); const fixture = TestBed.createComponent(App); @@ -168,12 +176,16 @@ describe('outputs', () => { ` }) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; - @ViewChild(DestroyComp) destroyComp !: DestroyComp; + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; + @ViewChild(DestroyComp) destroyComp!: DestroyComp; condition = true; - onClick() { clickCounter++; } - onChange() { changeCounter++; } + onClick() { + clickCounter++; + } + onChange() { + changeCounter++; + } } TestBed.configureTestingModule( {imports: [CommonModule], declarations: [App, ButtonToggle, DestroyComp]}); @@ -206,8 +218,10 @@ describe('outputs', () => { @Component({template: '<button myButton (click)="onClick()">Click me</button>'}) class App { - @ViewChild(MyButton) buttonDir !: MyButton; - onClick() { counter++; } + @ViewChild(MyButton) buttonDir!: MyButton; + onClick() { + counter++; + } } TestBed.configureTestingModule({declarations: [App, MyButton]}); const fixture = TestBed.createComponent(App); @@ -228,9 +242,11 @@ describe('outputs', () => { @Component({template: '<button-toggle (change)="onChange()" otherDir></button-toggle>'}) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; - @ViewChild(OtherDir) otherDir !: OtherDir; - onChange() { counter++; } + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; + @ViewChild(OtherDir) otherDir!: OtherDir; + onChange() { + counter++; + } } TestBed.configureTestingModule({declarations: [App, ButtonToggle, OtherDir]}); const fixture = TestBed.createComponent(App); @@ -248,8 +264,7 @@ describe('outputs', () => { @Directive({selector: '[otherChangeDir]'}) class OtherChangeDir { - @Input() - change !: boolean; + @Input() change!: boolean; } @Component({ @@ -257,11 +272,13 @@ describe('outputs', () => { '<button-toggle (change)="onChange()" otherChangeDir [change]="change"></button-toggle>' }) class App { - @ViewChild(ButtonToggle) buttonToggle !: ButtonToggle; - @ViewChild(OtherChangeDir) otherDir !: OtherChangeDir; + @ViewChild(ButtonToggle) buttonToggle!: ButtonToggle; + @ViewChild(OtherChangeDir) otherDir!: OtherChangeDir; change = true; - onChange() { counter++; } + onChange() { + counter++; + } } TestBed.configureTestingModule({declarations: [App, ButtonToggle, OtherChangeDir]}); const fixture = TestBed.createComponent(App); @@ -278,5 +295,4 @@ describe('outputs', () => { buttonToggle.change.next(); expect(counter).toBe(1); }); - }); diff --git a/packages/core/test/acceptance/pipe_spec.ts b/packages/core/test/acceptance/pipe_spec.ts index 49c020337b9c3..f0e610921f10c 100644 --- a/packages/core/test/acceptance/pipe_spec.ts +++ b/packages/core/test/acceptance/pipe_spec.ts @@ -14,7 +14,9 @@ describe('pipe', () => { @Pipe({name: 'countingPipe'}) class CountingPipe implements PipeTransform { state: number = 0; - transform(value: any) { return `${value} state:${this.state++}`; } + transform(value: any) { + return `${value} state:${this.state++}`; + } } @Pipe({name: 'multiArgPipe'}) @@ -57,20 +59,21 @@ describe('pipe', () => { it('should support bindings', () => { @Directive({selector: '[my-dir]'}) class Dir { - @Input() - dirProp: string = ''; + @Input() dirProp: string = ''; } @Pipe({name: 'double'}) class DoublePipe implements PipeTransform { - transform(value: any) { return `${value}${value}`; } + transform(value: any) { + return `${value}${value}`; + } } @Component({ template: `<div my-dir [dirProp]="'a'|double"></div>`, }) class App { - @ViewChild(Dir) directive !: Dir; + @ViewChild(Dir) directive!: Dir; } TestBed.configureTestingModule({declarations: [App, DoublePipe, Dir]}); @@ -113,7 +116,9 @@ describe('pipe', () => { it('should pick a Pipe defined in `declarations` over imported Pipes', () => { @Pipe({name: 'number'}) class PipeA implements PipeTransform { - transform(value: any) { return `PipeA: ${value}`; } + transform(value: any) { + return `PipeA: ${value}`; + } } @NgModule({ @@ -125,7 +130,9 @@ describe('pipe', () => { @Pipe({name: 'number'}) class PipeB implements PipeTransform { - transform(value: any) { return `PipeB: ${value}`; } + transform(value: any) { + return `PipeB: ${value}`; + } } @Component({ @@ -150,7 +157,9 @@ describe('pipe', () => { () => { @Pipe({name: 'number'}) class PipeA implements PipeTransform { - transform(value: any) { return `PipeA: ${value}`; } + transform(value: any) { + return `PipeA: ${value}`; + } } @NgModule({ @@ -162,7 +171,9 @@ describe('pipe', () => { @Pipe({name: 'number'}) class PipeB implements PipeTransform { - transform(value: any) { return `PipeB: ${value}`; } + transform(value: any) { + return `PipeB: ${value}`; + } } @NgModule({ @@ -222,12 +233,16 @@ describe('pipe', () => { it('should support duplicates by using the later entry', () => { @Pipe({name: 'duplicatePipe'}) class DuplicatePipe1 implements PipeTransform { - transform(value: any) { return `${value} from duplicate 1`; } + transform(value: any) { + return `${value} from duplicate 1`; + } } @Pipe({name: 'duplicatePipe'}) class DuplicatePipe2 implements PipeTransform { - transform(value: any) { return `${value} from duplicate 2`; } + transform(value: any) { + return `${value} from duplicate 2`; + } } @Component({ @@ -247,7 +262,9 @@ describe('pipe', () => { it('should support pipe in context of ternary operator', () => { @Pipe({name: 'pipe'}) class MyPipe implements PipeTransform { - transform(value: any): any { return value; } + transform(value: any): any { + return value; + } } @Component({ @@ -313,8 +330,12 @@ describe('pipe', () => { @Pipe({name: 'countingImpurePipe', pure: false}) class CountingImpurePipe implements PipeTransform { state: number = 0; - transform(value: any) { return `${value} state:${this.state++}`; } - constructor() { impurePipeInstances.push(this); } + transform(value: any) { + return `${value} state:${this.state++}`; + } + constructor() { + impurePipeInstances.push(this); + } } beforeEach(() => impurePipeInstances = []); @@ -372,8 +393,12 @@ describe('pipe', () => { @Pipe({name: 'pipeWithOnDestroy'}) class PipeWithOnDestroy implements PipeTransform, OnDestroy { - ngOnDestroy() { destroyCalls++; } - transform(value: any): any { return null; } + ngOnDestroy() { + destroyCalls++; + } + transform(value: any): any { + return null; + } } @Component({ @@ -401,7 +426,9 @@ describe('pipe', () => { @Pipe({name: 'myConcatPipe'}) class ConcatPipe implements PipeTransform { constructor(public service: Service) {} - transform(value: string): string { return `${value} - ${this.service.title}`; } + transform(value: string): string { + return `${value} - ${this.service.title}`; + } } @Component({ @@ -428,7 +455,9 @@ describe('pipe', () => { @Pipe({name: 'myConcatPipe'}) class ConcatPipe implements PipeTransform { constructor(@Inject(token) public service: Service) {} - transform(value: string): string { return `${value} - ${this.service.title}`; } + transform(value: string): string { + return `${value} - ${this.service.title}`; + } } @Component({ @@ -461,7 +490,9 @@ describe('pipe', () => { @Pipe({name: 'myConcatPipe'}) class ConcatPipe implements PipeTransform { constructor(public service: Service) {} - transform(value: string): string { return `${value} - ${this.service.title}`; } + transform(value: string): string { + return `${value} - ${this.service.title}`; + } } @Component({ @@ -501,7 +532,7 @@ describe('pipe', () => { }) class App { @Input() something: any; - @ViewChild(SomeComp) comp !: SomeComp; + @ViewChild(SomeComp) comp!: SomeComp; pipeValue = 10; displayValue = 0; } @@ -512,7 +543,9 @@ describe('pipe', () => { pipeChangeDetectorRef = changeDetectorRef; } - transform() { return ''; } + transform() { + return ''; + } } TestBed.configureTestingModule({declarations: [App, SomeComp, TestPipe]}); @@ -521,7 +554,7 @@ describe('pipe', () => { fixture.componentInstance.displayValue = 1; fixture.componentInstance.comp.displayValue = 1; - pipeChangeDetectorRef !.markForCheck(); + pipeChangeDetectorRef!.markForCheck(); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Outer value: "1"'); @@ -553,7 +586,7 @@ describe('pipe', () => { }) class App { @Input() something: any; - @ViewChild(SomeComp) comp !: SomeComp; + @ViewChild(SomeComp) comp!: SomeComp; pipeValue = 10; displayValue = 0; } @@ -564,7 +597,9 @@ describe('pipe', () => { pipeChangeDetectorRef = changeDetectorRef; } - transform() { return ''; } + transform() { + return ''; + } } TestBed.configureTestingModule({declarations: [App, SomeComp, TestPipe]}); @@ -573,22 +608,21 @@ describe('pipe', () => { fixture.componentInstance.displayValue = 1; fixture.componentInstance.comp.displayValue = 1; - pipeChangeDetectorRef !.markForCheck(); + pipeChangeDetectorRef!.markForCheck(); fixture.detectChanges(); expect(fixture.nativeElement.textContent).toContain('Outer value: "1"'); expect(fixture.nativeElement.textContent).toContain('Inner value: "0"'); }); - }); describe('pure pipe error handling', () => { - it('should not re-invoke pure pipes if it fails initially', () => { - @Pipe({name: 'throwPipe', pure: true}) class ThrowPipe implements PipeTransform { - transform(): never { throw new Error('ThrowPipeError'); } + transform(): never { + throw new Error('ThrowPipeError'); + } } @Component({template: `{{val | throwPipe}}`}) class App { @@ -607,7 +641,6 @@ describe('pipe', () => { it('should display the last known result from a pure pipe when it throws', () => { - @Pipe({name: 'throwPipe', pure: true}) class ThrowPipe implements PipeTransform { transform(value: string): string { @@ -647,7 +680,8 @@ describe('pipe', () => { describe('pure pipe error handling with multiple arguments', () => { const args: string[] = new Array(10).fill(':0'); for (let numberOfPipeArgs = 0; numberOfPipeArgs < args.length; numberOfPipeArgs++) { - it(`should not invoke ${numberOfPipeArgs} argument pure pipe second time if it throws unless input changes`, + it(`should not invoke ${ + numberOfPipeArgs} argument pure pipe second time if it throws unless input changes`, () => { // https://stackblitz.com/edit/angular-mbx2pg const log: string[] = []; @@ -685,8 +719,5 @@ describe('pipe', () => { }); } }); - }); - - }); diff --git a/packages/core/test/acceptance/property_binding_spec.ts b/packages/core/test/acceptance/property_binding_spec.ts index a2343c9009ca2..5b465d1c05e73 100644 --- a/packages/core/test/acceptance/property_binding_spec.ts +++ b/packages/core/test/acceptance/property_binding_spec.ts @@ -91,7 +91,6 @@ describe('property bindings', () => { it('should not map properties whose names do not correspond to their attribute names, ' + 'if they correspond to inputs', () => { - @Component({template: '', selector: 'my-comp'}) class MyComp { @Input() for !:string; @@ -393,7 +392,6 @@ describe('property bindings', () => { }); describe('attributes and input properties', () => { - @Directive({selector: '[myDir]', exportAs: 'myDir'}) class MyDir { @Input() role: string|undefined; @@ -596,7 +594,6 @@ describe('property bindings', () => { expect(comp2.children[0].getAttribute('role')).toBe('button'); expect(comp2.textContent).toBe('role: button'); }); - }); it('should not throw on synthetic property bindings when a directive on the same element injects ViewContainerRef', @@ -626,5 +623,4 @@ describe('property bindings', () => { fixture.detectChanges(); }).not.toThrow(); }); - }); diff --git a/packages/core/test/acceptance/property_interpolation_spec.ts b/packages/core/test/acceptance/property_interpolation_spec.ts index 0330f08a2a8b7..c3b5dfb03014b 100644 --- a/packages/core/test/acceptance/property_interpolation_spec.ts +++ b/packages/core/test/acceptance/property_interpolation_spec.ts @@ -8,7 +8,7 @@ import {Component} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; -import {of } from 'rxjs'; +import {of} from 'rxjs'; describe('property interpolation', () => { it('should handle all flavors of interpolated properties', () => { @@ -67,7 +67,7 @@ describe('property interpolation', () => { ` }) class App { - details = of ({ + details = of({ title: 'cool image', url: 'http://somecooldomain:1234/cool_image.png', }); @@ -93,7 +93,11 @@ describe('property interpolation', () => { /** Clearly this is a doctor of heavy metals. */ leadSurgeon = { getCommonInfo() { - return {getPhotoUrl() { return 'http://somecooldomain:1234/cool_image.png'; }}; + return { + getPhotoUrl() { + return 'http://somecooldomain:1234/cool_image.png'; + } + }; } }; } diff --git a/packages/core/test/acceptance/pure_function_spec.ts b/packages/core/test/acceptance/pure_function_spec.ts index 8b03174a16681..406e8b185a7af 100644 --- a/packages/core/test/acceptance/pure_function_spec.ts +++ b/packages/core/test/acceptance/pure_function_spec.ts @@ -18,8 +18,7 @@ describe('components using pure function instructions internally', () => { template: ``, }) class MyComp { - @Input() - names: string[] = []; + @Input() names: string[] = []; } @@ -60,7 +59,7 @@ describe('components using pure function instructions internally', () => { myComp.names = ['should not be overwritten']; fixture.detectChanges(); - expect(myComp !.names).toEqual(['should not be overwritten']); + expect(myComp!.names).toEqual(['should not be overwritten']); }); @@ -91,11 +90,9 @@ describe('components using pure function instructions internally', () => { template: ``, }) class ManyPropComp { - @Input() - names1: string[] = []; + @Input() names1: string[] = []; - @Input() - names2: string[] = []; + @Input() names2: string[] = []; } @Component({ @@ -117,14 +114,14 @@ describe('components using pure function instructions internally', () => { fixture.detectChanges(); const manyPropComp = fixture.debugElement.query(By.directive(ManyPropComp)).componentInstance; - expect(manyPropComp !.names1).toEqual(['Nancy', 'Carson']); - expect(manyPropComp !.names2).toEqual(['George']); + expect(manyPropComp!.names1).toEqual(['Nancy', 'Carson']); + expect(manyPropComp!.names2).toEqual(['George']); fixture.componentInstance.customName = 'George'; fixture.componentInstance.customName2 = 'Carson'; fixture.detectChanges(); - expect(manyPropComp !.names1).toEqual(['Nancy', 'George']); - expect(manyPropComp !.names2).toEqual(['Carson']); + expect(manyPropComp!.names1).toEqual(['Nancy', 'George']); + expect(manyPropComp!.names2).toEqual(['Carson']); }); @@ -222,7 +219,6 @@ describe('components using pure function instructions internally', () => { it('should work up to 8 bindings', () => { - @Component({ template: ` <my-comp [names]="['a', 'b', 'c', 'd', 'e', 'f', 'g', v8]"></my-comp> @@ -346,8 +342,7 @@ describe('components using pure function instructions internally', () => { template: ``, }) class ObjectComp { - @Input() - config: any = []; + @Input() config: any = []; } it('should support an object literal', () => { @@ -495,7 +490,7 @@ describe('components using pure function instructions internally', () => { ` }) class App { - @ViewChildren(Dir) directives !: QueryList<Dir>; + @ViewChildren(Dir) directives!: QueryList<Dir>; } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -514,7 +509,7 @@ describe('components using pure function instructions internally', () => { ` }) class App { - @ViewChildren(Dir) directives !: QueryList<Dir>; + @ViewChildren(Dir) directives!: QueryList<Dir>; } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -528,7 +523,7 @@ describe('components using pure function instructions internally', () => { it('should not share object literals across component instances', () => { @Component({template: `<div [dir]="{}"></div>`}) class App { - @ViewChild(Dir) directive !: Dir; + @ViewChild(Dir) directive!: Dir; } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -545,7 +540,7 @@ describe('components using pure function instructions internally', () => { it('should not share array literals across component instances', () => { @Component({template: `<div [dir]="[]"></div>`}) class App { - @ViewChild(Dir) directive !: Dir; + @ViewChild(Dir) directive!: Dir; } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -567,7 +562,7 @@ describe('components using pure function instructions internally', () => { ` }) class App { - @ViewChildren(Dir) directives !: QueryList<Dir>; + @ViewChildren(Dir) directives!: QueryList<Dir>; } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -586,7 +581,7 @@ describe('components using pure function instructions internally', () => { ` }) class App { - @ViewChildren(Dir) directives !: QueryList<Dir>; + @ViewChildren(Dir) directives!: QueryList<Dir>; } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -605,8 +600,10 @@ describe('components using pure function instructions internally', () => { ` }) class App { - @ViewChildren(Dir) directives !: QueryList<Dir>; - getFoo() { return 'foo!'; } + @ViewChildren(Dir) directives!: QueryList<Dir>; + getFoo() { + return 'foo!'; + } } TestBed.configureTestingModule({declarations: [Dir, App]}); @@ -616,8 +613,5 @@ describe('components using pure function instructions internally', () => { expect(values).toEqual([{foo: null}, {foo: 'foo!'}]); }); - - - }); }); diff --git a/packages/core/test/acceptance/query_spec.ts b/packages/core/test/acceptance/query_spec.ts index 8ebe7aba626ef..c36f6027fb18b 100644 --- a/packages/core/test/acceptance/query_spec.ts +++ b/packages/core/test/acceptance/query_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {AfterViewInit, Component, ContentChild, ContentChildren, Directive, ElementRef, Input, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, ViewRef, forwardRef} from '@angular/core'; +import {AfterViewInit, Component, ContentChild, ContentChildren, Directive, ElementRef, forwardRef, Input, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, ViewRef} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -215,7 +215,7 @@ describe('query logic', () => { } class MyComp { - @ViewChildren(SomeDir) foo !: QueryList<SomeDir>; + @ViewChildren(SomeDir) foo!: QueryList<SomeDir>; } @Component({ @@ -242,7 +242,7 @@ describe('query logic', () => { } class MySuperComp { - @ViewChildren(SomeDir) foo !: QueryList<SomeDir>; + @ViewChildren(SomeDir) foo!: QueryList<SomeDir>; } class MyComp extends MySuperComp {} @@ -275,7 +275,7 @@ describe('query logic', () => { template: `<ng-container [ngTemplateOutlet]="content"></ng-container>` }) class Insertion { - @Input() content !: TemplateRef<{}>; + @Input() content!: TemplateRef<{}>; } @Component({ @@ -287,7 +287,7 @@ describe('query logic', () => { ` }) class App { - @ViewChild(Required) requiredEl !: Required; + @ViewChild(Required) requiredEl!: Required; viewChildAvailableInAfterViewInit?: boolean; ngAfterViewInit() { @@ -300,7 +300,6 @@ describe('query logic', () => { fixture.detectChanges(); expect(fixture.componentInstance.viewChildAvailableInAfterViewInit).toBe(true); }); - }); describe('content queries', () => { @@ -538,7 +537,7 @@ describe('query logic', () => { @Component({template: '<sub-comp><div #foo></div></sub-comp>'}) class App { - @ViewChild(SubComp) subComp !: SubComp; + @ViewChild(SubComp) subComp!: SubComp; } TestBed.configureTestingModule({declarations: [App, SubComp]}); @@ -561,7 +560,7 @@ describe('query logic', () => { @Component({template: '<sub-comp><div #foo></div></sub-comp>'}) class App { - @ViewChild(SubComp) subComp !: SubComp; + @ViewChild(SubComp) subComp!: SubComp; } TestBed.configureTestingModule({declarations: [App, SubComp]}); @@ -577,7 +576,7 @@ describe('query logic', () => { } class MyComp { - @ContentChildren(SomeDir) foo !: QueryList<SomeDir>; + @ContentChildren(SomeDir) foo!: QueryList<SomeDir>; } @Component({selector: 'sub-comp', template: '<ng-content></ng-content>'}) @@ -593,7 +592,7 @@ describe('query logic', () => { ` }) class App { - @ViewChild(SubComp) subComp !: SubComp; + @ViewChild(SubComp) subComp!: SubComp; } TestBed.configureTestingModule({declarations: [App, SubComp, SomeDir]}); @@ -610,7 +609,7 @@ describe('query logic', () => { } class MySuperComp { - @ContentChildren(SomeDir) foo !: QueryList<SomeDir>; + @ContentChildren(SomeDir) foo!: QueryList<SomeDir>; } class MyComp extends MySuperComp {} @@ -628,7 +627,7 @@ describe('query logic', () => { ` }) class App { - @ViewChild(SubComp) subComp !: SubComp; + @ViewChild(SubComp) subComp!: SubComp; } TestBed.configureTestingModule({declarations: [App, SubComp, SomeDir]}); @@ -657,7 +656,7 @@ describe('query logic', () => { template: '', }) class ShallowComp { - @ContentChildren('foo', {descendants: false}) foos !: QueryList<ElementRef>; + @ContentChildren('foo', {descendants: false}) foos!: QueryList<ElementRef>; } TestBed.configureTestingModule( @@ -666,7 +665,7 @@ describe('query logic', () => { fixture.detectChanges(); const shallowComp = fixture.debugElement.query(By.directive(ShallowComp)).componentInstance; - const queryList = shallowComp !.foos; + const queryList = shallowComp!.foos; expect(queryList.length).toBe(0); fixture.componentInstance.showing = true; @@ -691,24 +690,24 @@ describe('query logic', () => { }); describe('descendants: false (default)', () => { - /** * A helper function to check if a given object looks like ElementRef. It is used in place of * the `instanceof ElementRef` check since ivy returns a type that looks like ElementRef (have * the same properties but doesn't pass the instanceof ElementRef test) */ - function isElementRefLike(result: any): boolean { return result.nativeElement != null; } + function isElementRefLike(result: any): boolean { + return result.nativeElement != null; + } it('should match directives on elements that used to be wrapped by a required parent in HTML parser', () => { - @Directive({selector: '[myDef]'}) class MyDef { } @Component({selector: 'my-container', template: ``}) class MyContainer { - @ContentChildren(MyDef) myDefs !: QueryList<MyDef>; + @ContentChildren(MyDef) myDefs!: QueryList<MyDef>; } @Component( {selector: 'test-cmpt', template: `<my-container><tr myDef></tr></my-container>`}) @@ -724,10 +723,9 @@ describe('query logic', () => { }); it('should match elements with local refs inside <ng-container>', () => { - @Component({selector: 'needs-target', template: ``}) class NeedsTarget { - @ContentChildren('target') targets !: QueryList<ElementRef>; + @ContentChildren('target') targets!: QueryList<ElementRef>; } @Component({ selector: 'test-cmpt', @@ -752,10 +750,9 @@ describe('query logic', () => { }); it('should match elements with local refs inside nested <ng-container>', () => { - @Component({selector: 'needs-target', template: ``}) class NeedsTarget { - @ContentChildren('target') targets !: QueryList<ElementRef>; + @ContentChildren('target') targets!: QueryList<ElementRef>; } @Component({ @@ -791,7 +788,7 @@ describe('query logic', () => { @Component({selector: 'needs-target', template: ``}) class NeedsTarget { - @ContentChildren(TargetDir) targets !: QueryList<HTMLElement>; + @ContentChildren(TargetDir) targets!: QueryList<HTMLElement>; } @Component({ @@ -823,7 +820,7 @@ describe('query logic', () => { @Component({selector: 'needs-target', template: ``}) class NeedsTarget { - @ContentChildren(TargetDir) targets !: QueryList<HTMLElement>; + @ContentChildren(TargetDir) targets!: QueryList<HTMLElement>; } @Component({ @@ -859,7 +856,7 @@ describe('query logic', () => { @Directive({selector: '[needs-target]'}) class NeedsTarget { - @ContentChildren(TargetDir) targets !: QueryList<HTMLElement>; + @ContentChildren(TargetDir) targets!: QueryList<HTMLElement>; } @Component({ @@ -893,8 +890,8 @@ describe('query logic', () => { @Component({selector: 'needs-target', template: ``}) class NeedsTarget { - @ContentChildren(TargetDir) dirTargets !: QueryList<TargetDir>; - @ContentChildren('target') localRefsTargets !: QueryList<ElementRef>; + @ContentChildren(TargetDir) dirTargets!: QueryList<TargetDir>; + @ContentChildren('target') localRefsTargets!: QueryList<ElementRef>; } @Component({ @@ -931,7 +928,7 @@ describe('query logic', () => { @Component({selector: 'needs-target', template: ``}) class NeedsTarget { - @ContentChildren(TargetDir) targets !: QueryList<HTMLElement>; + @ContentChildren(TargetDir) targets!: QueryList<HTMLElement>; } @Component({ @@ -963,7 +960,6 @@ describe('query logic', () => { describe('observable interface', () => { - it('should allow observing changes to query list', () => { const fixture = TestBed.createComponent(QueryCompWithChanges); let changes = 0; @@ -983,13 +979,10 @@ describe('query logic', () => { fixture.detectChanges(); expect(changes).toBe(1); }); - }); describe('view boundaries', () => { - describe('ViewContainerRef', () => { - @Directive({selector: '[vc]', exportAs: 'vc'}) class ViewContainerManipulatorDirective { constructor(private _vcRef: ViewContainerRef) {} @@ -998,9 +991,13 @@ describe('query logic', () => { return this._vcRef.createEmbeddedView(tpl, ctx, idx); } - remove(index?: number) { this._vcRef.remove(index); } + remove(index?: number) { + this._vcRef.remove(index); + } - move(viewRef: ViewRef, index: number) { this._vcRef.move(viewRef, index); } + move(viewRef: ViewRef, index: number) { + this._vcRef.move(viewRef, index); + } } it('should report results in views inserted / removed by ngIf', () => { @@ -1014,7 +1011,7 @@ describe('query logic', () => { }) class TestComponent { value: boolean = false; - @ViewChildren('foo') query !: QueryList<any>; + @ViewChildren('foo') query!: QueryList<any>; } TestBed.configureTestingModule({declarations: [TestComponent]}); @@ -1045,7 +1042,7 @@ describe('query logic', () => { }) class TestComponent { value: string[]|undefined; - @ViewChildren('foo') query !: QueryList<any>; + @ViewChildren('foo') query!: QueryList<any>; } TestBed.configureTestingModule({declarations: [TestComponent]}); @@ -1082,7 +1079,6 @@ describe('query logic', () => { */ it('should notify on changes when a given view is removed and re-inserted at the same index', () => { - @Component({ selector: 'test-comp', template: ` @@ -1093,10 +1089,9 @@ describe('query logic', () => { class TestComponent implements AfterViewInit { queryListNotificationCounter = 0; - @ViewChild(ViewContainerManipulatorDirective) - vc !: ViewContainerManipulatorDirective; - @ViewChild('tpl') tpl !: TemplateRef<any>; - @ViewChildren('foo') query !: QueryList<any>; + @ViewChild(ViewContainerManipulatorDirective) vc!: ViewContainerManipulatorDirective; + @ViewChild('tpl') tpl!: TemplateRef<any>; + @ViewChildren('foo') query!: QueryList<any>; ngAfterViewInit() { this.query.changes.subscribe(() => this.queryListNotificationCounter++); @@ -1125,13 +1120,13 @@ describe('query logic', () => { it('should support a mix of content queries from the declaration and embedded view', () => { @Directive({selector: '[query-for-lots-of-content]'}) class QueryForLotsOfContent { - @ContentChildren('foo', {descendants: true}) foos1 !: QueryList<ElementRef>; - @ContentChildren('foo', {descendants: true}) foos2 !: QueryList<ElementRef>; + @ContentChildren('foo', {descendants: true}) foos1!: QueryList<ElementRef>; + @ContentChildren('foo', {descendants: true}) foos2!: QueryList<ElementRef>; } @Directive({selector: '[query-for-content]'}) class QueryForContent { - @ContentChildren('foo') foos !: QueryList<ElementRef>; + @ContentChildren('foo') foos!: QueryList<ElementRef>; } @Component({ @@ -1192,11 +1187,10 @@ describe('query logic', () => { `, }) class TestComponent { - @ViewChild(ViewContainerManipulatorDirective) - vc !: ViewContainerManipulatorDirective; - @ViewChild('tpl1') tpl1 !: TemplateRef<any>; - @ViewChild('tpl2') tpl2 !: TemplateRef<any>; - @ViewChildren('foo') query !: QueryList<any>; + @ViewChild(ViewContainerManipulatorDirective) vc!: ViewContainerManipulatorDirective; + @ViewChild('tpl1') tpl1!: TemplateRef<any>; + @ViewChild('tpl2') tpl2!: TemplateRef<any>; + @ViewChildren('foo') query!: QueryList<any>; } TestBed.configureTestingModule( @@ -1210,8 +1204,8 @@ describe('query logic', () => { expect(queryList.length).toBe(1); expect(queryList.first.nativeElement.getAttribute('id')).toBe('middle'); - vc.insertTpl(tpl1 !, {idx: 0}, 0); - vc.insertTpl(tpl2 !, {idx: 1}, 1); + vc.insertTpl(tpl1!, {idx: 0}, 0); + vc.insertTpl(tpl2!, {idx: 1}, 1); fixture.detectChanges(); expect(queryList.length).toBe(3); @@ -1220,7 +1214,7 @@ describe('query logic', () => { expect(qListArr[1].nativeElement.getAttribute('id')).toBe('middle'); expect(qListArr[2].nativeElement.getAttribute('id')).toBe('foo2_1'); - vc.insertTpl(tpl1 !, {idx: 1}, 1); + vc.insertTpl(tpl1!, {idx: 1}, 1); fixture.detectChanges(); expect(queryList.length).toBe(4); @@ -1264,10 +1258,10 @@ describe('query logic', () => { `, }) class TestComponent { - @ViewChild('tpl') tpl !: TemplateRef<any>; - @ViewChild('vi0') vi0 !: ViewContainerManipulatorDirective; - @ViewChild('vi1') vi1 !: ViewContainerManipulatorDirective; - @ViewChildren('foo') query !: QueryList<any>; + @ViewChild('tpl') tpl!: TemplateRef<any>; + @ViewChild('vi0') vi0!: ViewContainerManipulatorDirective; + @ViewChild('vi1') vi1!: ViewContainerManipulatorDirective; + @ViewChildren('foo') query!: QueryList<any>; } TestBed.configureTestingModule( @@ -1280,8 +1274,8 @@ describe('query logic', () => { expect(queryList.length).toBe(0); - vi0.insertTpl(tpl !, {idx: 0, container_idx: 0}, 0); - vi1.insertTpl(tpl !, {idx: 0, container_idx: 1}, 0); + vi0.insertTpl(tpl!, {idx: 0, container_idx: 0}, 0); + vi1.insertTpl(tpl!, {idx: 0, container_idx: 1}, 0); fixture.detectChanges(); expect(queryList.length).toBe(2); @@ -1315,7 +1309,7 @@ describe('query logic', () => { }) class MyApp { show = false; - @ViewChildren('foo') query !: QueryList<any>; + @ViewChildren('foo') query!: QueryList<any>; } TestBed.configureTestingModule({declarations: [MyApp], imports: [CommonModule]}); @@ -1334,14 +1328,11 @@ describe('query logic', () => { fixture.detectChanges(); expect(queryList.length).toBe(0); }); - }); }); describe('non-regression', () => { - it('should query by provider super-type in an embedded view', () => { - @Directive({selector: '[child]'}) class Child { } @@ -1356,7 +1347,7 @@ describe('query logic', () => { `<ng-template [ngIf]="true"><ng-template [ngIf]="true"><div parent></div></ng-template></ng-template>` }) class TestCmpt { - @ViewChildren(Child) instances !: QueryList<Child>; + @ViewChildren(Child) instances!: QueryList<Child>; } TestBed.configureTestingModule({declarations: [TestCmpt, Parent, Child]}); @@ -1367,7 +1358,6 @@ describe('query logic', () => { }); it('should flatten multi-provider results', () => { - class MyClass {} @Component({ @@ -1381,7 +1371,7 @@ describe('query logic', () => { @Component({selector: 'test-cmpt', template: `<with-multi-provider></with-multi-provider>`}) class TestCmpt { - @ViewChildren(MyClass) queryResults !: QueryList<WithMultiProvider>; + @ViewChildren(MyClass) queryResults!: QueryList<WithMultiProvider>; } TestBed.configureTestingModule({declarations: [TestCmpt, WithMultiProvider]}); @@ -1393,7 +1383,6 @@ describe('query logic', () => { }); it('should flatten multi-provider results when crossing ng-template', () => { - class MyClass {} @Component({ @@ -1413,7 +1402,7 @@ describe('query logic', () => { ` }) class TestCmpt { - @ViewChildren(MyClass) queryResults !: QueryList<WithMultiProvider>; + @ViewChildren(MyClass) queryResults!: QueryList<WithMultiProvider>; } TestBed.configureTestingModule({declarations: [TestCmpt, WithMultiProvider]}); @@ -1444,7 +1433,7 @@ describe('query logic', () => { ` }) class App { - @ViewChild(GroupDir) group !: GroupDir; + @ViewChild(GroupDir) group!: GroupDir; } TestBed.configureTestingModule( @@ -1481,7 +1470,7 @@ describe('query logic', () => { ` }) class App { - @ViewChildren(GroupDir) groups !: QueryList<GroupDir>; + @ViewChildren(GroupDir) groups!: QueryList<GroupDir>; } TestBed.configureTestingModule( @@ -1497,9 +1486,7 @@ describe('query logic', () => { expect(groups[1]).toBeAnInstanceOf(GroupDir); expect(groups[2]).toBeUndefined(); }); - }); - }); function initWithTemplate(compType: Type<any>, template: string) { @@ -1511,11 +1498,11 @@ function initWithTemplate(compType: Type<any>, template: string) { @Component({selector: 'local-ref-query-component', template: '<ng-content></ng-content>'}) class QueryComp { - @ViewChild('viewQuery') viewChild !: any; - @ContentChild('contentQuery') contentChild !: any; + @ViewChild('viewQuery') viewChild!: any; + @ContentChild('contentQuery') contentChild!: any; - @ViewChildren('viewQuery') viewChildren !: QueryList<any>; - @ContentChildren('contentQuery') contentChildren !: QueryList<any>; + @ViewChildren('viewQuery') viewChildren!: QueryList<any>; + @ContentChildren('contentQuery') contentChildren!: QueryList<any>; } @Component({selector: 'app-comp', template: ``}) @@ -1543,12 +1530,14 @@ class TextDirective { ` }) class StaticViewQueryComp { - private _textDir !: TextDirective; - private _foo !: ElementRef; + private _textDir!: TextDirective; + private _foo!: ElementRef; setEvents: string[] = []; @ViewChild(TextDirective, {static: true}) - get textDir(): TextDirective { return this._textDir; } + get textDir(): TextDirective { + return this._textDir; + } set textDir(value: TextDirective) { this.setEvents.push('textDir set'); @@ -1556,7 +1545,9 @@ class StaticViewQueryComp { } @ViewChild('foo') - get foo(): ElementRef { return this._foo; } + get foo(): ElementRef { + return this._foo; + } set foo(value: ElementRef) { this.setEvents.push('foo set'); @@ -1577,22 +1568,22 @@ class StaticViewQueryComp { ` }) class SubclassStaticViewQueryComp extends StaticViewQueryComp { - @ViewChild('bar', {static: true}) - bar !: ElementRef; + @ViewChild('bar', {static: true}) bar!: ElementRef; - @ViewChild('baz') - baz !: ElementRef; + @ViewChild('baz') baz!: ElementRef; } @Component({selector: 'static-content-query-comp', template: `<ng-content></ng-content>`}) class StaticContentQueryComp { - private _textDir !: TextDirective; - private _foo !: ElementRef; + private _textDir!: TextDirective; + private _foo!: ElementRef; setEvents: string[] = []; @ContentChild(TextDirective, {static: true}) - get textDir(): TextDirective { return this._textDir; } + get textDir(): TextDirective { + return this._textDir; + } set textDir(value: TextDirective) { this.setEvents.push('textDir set'); @@ -1600,7 +1591,9 @@ class StaticContentQueryComp { } @ContentChild('foo') - get foo(): ElementRef { return this._foo; } + get foo(): ElementRef { + return this._foo; + } set foo(value: ElementRef) { this.setEvents.push('foo set'); @@ -1610,12 +1603,14 @@ class StaticContentQueryComp { @Directive({selector: '[staticContentQueryDir]'}) class StaticContentQueryDir { - private _textDir !: TextDirective; - private _foo !: ElementRef; + private _textDir!: TextDirective; + private _foo!: ElementRef; setEvents: string[] = []; @ContentChild(TextDirective, {static: true}) - get textDir(): TextDirective { return this._textDir; } + get textDir(): TextDirective { + return this._textDir; + } set textDir(value: TextDirective) { this.setEvents.push('textDir set'); @@ -1623,7 +1618,9 @@ class StaticContentQueryDir { } @ContentChild('foo') - get foo(): ElementRef { return this._foo; } + get foo(): ElementRef { + return this._foo; + } set foo(value: ElementRef) { this.setEvents.push('foo set'); @@ -1633,11 +1630,9 @@ class StaticContentQueryDir { @Component({selector: 'subclass-static-content-query-comp', template: `<ng-content></ng-content>`}) class SubclassStaticContentQueryComp extends StaticContentQueryComp { - @ContentChild('bar', {static: true}) - bar !: ElementRef; + @ContentChild('bar', {static: true}) bar!: ElementRef; - @ContentChild('baz') - baz !: ElementRef; + @ContentChild('baz') baz!: ElementRef; } @Component({ @@ -1647,7 +1642,7 @@ class SubclassStaticContentQueryComp extends StaticContentQueryComp { ` }) export class QueryCompWithChanges { - @ViewChildren('foo') foos !: QueryList<any>; + @ViewChildren('foo') foos!: QueryList<any>; showing = false; } @@ -1658,7 +1653,7 @@ class SuperDirectiveQueryTarget { @Directive({selector: '[super-directive]'}) class SuperDirective { - @ViewChildren(SuperDirectiveQueryTarget) headers !: QueryList<SuperDirectiveQueryTarget>; + @ViewChildren(SuperDirectiveQueryTarget) headers!: QueryList<SuperDirectiveQueryTarget>; } @Component({ diff --git a/packages/core/test/acceptance/renderer_factory_spec.ts b/packages/core/test/acceptance/renderer_factory_spec.ts index f10269cf63b91..856997f47e8dc 100644 --- a/packages/core/test/acceptance/renderer_factory_spec.ts +++ b/packages/core/test/acceptance/renderer_factory_spec.ts @@ -24,19 +24,29 @@ describe('renderer factory lifecycle', () => { @Component({selector: 'some-component', template: `foo`}) class SomeComponent implements DoCheck { - ngOnInit() { logs.push('some_component create'); } - ngDoCheck() { logs.push('some_component update'); } + ngOnInit() { + logs.push('some_component create'); + } + ngDoCheck() { + logs.push('some_component update'); + } } @Component({selector: 'some-component-with-error', template: `With error`}) class SomeComponentWhichThrows { - ngOnInit() { throw new Error('SomeComponentWhichThrows threw'); } + ngOnInit() { + throw new Error('SomeComponentWhichThrows threw'); + } } @Component({selector: 'lol', template: `<some-component></some-component>`}) class TestComponent implements DoCheck { - ngOnInit() { logs.push('test_component create'); } - ngDoCheck() { logs.push('test_component update'); } + ngOnInit() { + logs.push('test_component create'); + } + ngDoCheck() { + logs.push('test_component update'); + } } /** Creates a patched renderer factory that pushes entries to the test log */ @@ -44,7 +54,7 @@ describe('renderer factory lifecycle', () => { let rendererFactory = getRendererFactory2(document); const createRender = rendererFactory.createRenderer; - rendererFactory.createRenderer = (hostElement: any, type: RendererType2 | null) => { + rendererFactory.createRenderer = (hostElement: any, type: RendererType2|null) => { logs.push('create'); return createRender.apply(rendererFactory, [hostElement, type]); }; @@ -168,7 +178,7 @@ describe('animation renderer factory', () => { ]); player.finish(); - rendererFactory !.whenRenderingDone !().then(() => { + rendererFactory!.whenRenderingDone!().then(() => { expect(eventLogs).toEqual(['void - start', 'void - done', 'on - start', 'on - done']); done(); }); diff --git a/packages/core/test/acceptance/styling_spec.ts b/packages/core/test/acceptance/styling_spec.ts index 02397afb41e43..8f1fc30b54320 100644 --- a/packages/core/test/acceptance/styling_spec.ts +++ b/packages/core/test/acceptance/styling_spec.ts @@ -440,11 +440,12 @@ describe('styling', () => { @Directive({selector: '[dir-shadows-class-input]'}) class DirectiveShadowsClassInput { - @Input('class') - klass: string|undefined; + @Input('class') klass: string|undefined; @HostBinding('class') - get hostClasses() { return `${this.klass} SUFFIX`; } + get hostClasses() { + return `${this.klass} SUFFIX`; + } } TestBed.configureTestingModule({declarations: [Cmp, DirectiveShadowsClassInput]}); @@ -671,7 +672,7 @@ describe('styling', () => { it('should be able to bind zero', () => { @Component({template: '<div #div [style.opacity]="opacity"></div>'}) class App { - @ViewChild('div') div !: ElementRef<HTMLElement>; + @ViewChild('div') div!: ElementRef<HTMLElement>; opacity = 0; } @@ -685,7 +686,7 @@ describe('styling', () => { it('should be able to bind a SafeValue to backgroundImage', () => { @Component({template: '<div [style.backgroundImage]="image"></div>'}) class Cmp { - image !: SafeStyle; + image!: SafeStyle; } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -724,7 +725,7 @@ describe('styling', () => { it('should be able to bind a SafeValue to clip-path', () => { @Component({template: '<div [style.clip-path]="path"></div>'}) class Cmp { - path !: SafeStyle; + path!: SafeStyle; } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -1011,15 +1012,15 @@ describe('styling', () => { expect(capturedClassBindingCount).toEqual(1); expect(capturedClassBindingValue as any).toEqual(null); expect(capturedMyClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); fixture.componentInstance.c = 'dynamic-value'; fixture.detectChanges(); expect(capturedClassBindingCount).toEqual(2); - expect(capturedClassBindingValue !).toEqual('dynamic-value'); + expect(capturedClassBindingValue!).toEqual('dynamic-value'); expect(capturedMyClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); fixture.componentInstance.c = null; fixture.detectChanges(); @@ -1027,7 +1028,7 @@ describe('styling', () => { expect(capturedClassBindingCount).toEqual(3); expect(capturedClassBindingValue as any).toEqual(null); expect(capturedMyClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); fixture.componentInstance.c = ''; fixture.detectChanges(); @@ -1035,7 +1036,7 @@ describe('styling', () => { expect(capturedClassBindingCount).toEqual(4); expect(capturedClassBindingValue as any).toEqual(''); expect(capturedMyClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); }); it('should write to [class] binding during `update` mode if there is an instantiation-level value', @@ -1069,7 +1070,7 @@ describe('styling', () => { fixture.detectChanges(); expect(capturedClassBindingCount).toEqual(2); - expect(capturedClassBindingValue !).toEqual('dynamic-bar'); + expect(capturedClassBindingValue!).toEqual('dynamic-bar'); }); it('should write to a `class` input binding if there is a static class value', () => { @@ -1102,9 +1103,9 @@ describe('styling', () => { const fixture = TestBed.createComponent(Cmp); fixture.detectChanges(); - expect(capturedClassBindingValue !).toEqual('static-val'); + expect(capturedClassBindingValue!).toEqual('static-val'); expect(capturedClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); expect(capturedMyClassBindingCount).toEqual(1); }); @@ -1195,19 +1196,19 @@ describe('styling', () => { // would check if we possibly have this situation on every `advance()` // instruction. We don't think this is worth it, and we are just going to live // with this. - ); - expect(capturedClassBindingValue !).toEqual('static-val'); + ); + expect(capturedClassBindingValue!).toEqual('static-val'); expect(capturedMyClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); capturedClassBindingCount = 0; fixture.componentInstance.c = 'dynamic-val'; fixture.detectChanges(); expect(capturedClassBindingCount).toEqual(1); - expect(capturedClassBindingValue !).toEqual('static-val dynamic-val'); + expect(capturedClassBindingValue!).toEqual('static-val dynamic-val'); expect(capturedMyClassBindingCount).toEqual(1); - expect(capturedMyClassBindingValue !).toEqual('foo'); + expect(capturedMyClassBindingValue!).toEqual('foo'); }); onlyInIvy('only ivy balances styling across directives and component host bindings') @@ -1240,7 +1241,6 @@ describe('styling', () => { }); describe('NgClass', () => { - // We had a bug where NgClass would not allocate sufficient slots for host bindings, // so it would overwrite information about other directives nearby. This test checks // that TestDir's injector is not overwritten by NgClass, so TestDir should still @@ -1297,7 +1297,7 @@ describe('styling', () => { template: '<span dir [classesInSchool]="classes" [styleOfClothing]="style"></span>', }) class App { - @ViewChild(Dir) dir !: Dir; + @ViewChild(Dir) dir!: Dir; classes = 'math'; style = '80s'; @@ -1315,8 +1315,7 @@ describe('styling', () => { it('should be able to bind to `className`', () => { @Component({template: ''}) class App { - @HostBinding('className') - klass = 'one two'; + @HostBinding('className') klass = 'one two'; } TestBed.configureTestingModule({declarations: [App]}); @@ -1471,8 +1470,7 @@ describe('styling', () => { opacity: string|null = '0.5'; @ViewChild(CompWithStyling, {static: true}) compWithStyling: CompWithStyling|null = null; - @ViewChild(DirWithStyling, {static: true}) - dirWithStyling: DirWithStyling|null = null; + @ViewChild(DirWithStyling, {static: true}) dirWithStyling: DirWithStyling|null = null; } TestBed.configureTestingModule({declarations: [Cmp, DirWithStyling, CompWithStyling]}); @@ -1488,13 +1486,13 @@ describe('styling', () => { expect(element.style.fontSize).toEqual('100px'); // once for the template flush and again for the host bindings - expect(ngDevMode !.rendererSetStyle).toEqual(4); + expect(ngDevMode!.rendererSetStyle).toEqual(4); ngDevModeResetPerfCounters(); component.opacity = '0.6'; - component.compWithStyling !.height = '100px'; - component.compWithStyling !.width = '100px'; - component.dirWithStyling !.fontSize = '50px'; + component.compWithStyling!.height = '100px'; + component.compWithStyling!.width = '100px'; + component.dirWithStyling!.fontSize = '50px'; fixture.detectChanges(); expect(element.style.opacity).toEqual('0.6'); @@ -1503,7 +1501,7 @@ describe('styling', () => { expect(element.style.fontSize).toEqual('50px'); // once for the template flush and again for the host bindings - expect(ngDevMode !.rendererSetStyle).toEqual(4); + expect(ngDevMode!.rendererSetStyle).toEqual(4); }); onlyInIvy('ivy resolves styling across directives, components and templates in unison') @@ -1634,8 +1632,12 @@ describe('styling', () => { public c: {[key: string]: any}|null = null; updateClasses(classes: string) { const c = this.c || (this.c = {}); - Object.keys(this.c).forEach(className => { c[className] = false; }); - classes.split(/\s+/).forEach(className => { c[className] = true; }); + Object.keys(this.c).forEach(className => { + c[className] = false; + }); + classes.split(/\s+/).forEach(className => { + c[className] = true; + }); } public s: {[key: string]: any}|null = null; @@ -1694,8 +1696,7 @@ describe('styling', () => { map: any = {width: '111px', opacity: '0.5'}; width: string|null|undefined = '555px'; - @ViewChild('dir', {read: DirThatSetsStyling, static: true}) - dir !: DirThatSetsStyling; + @ViewChild('dir', {read: DirThatSetsStyling, static: true}) dir!: DirThatSetsStyling; } TestBed.configureTestingModule({declarations: [Cmp, DirThatSetsStyling]}); @@ -1763,8 +1764,7 @@ describe('styling', () => { map: any = {width: '555px', height: '555px'}; - @ViewChild('dir', {read: DirThatSetsStyling, static: true}) - dir !: DirThatSetsStyling; + @ViewChild('dir', {read: DirThatSetsStyling, static: true}) dir!: DirThatSetsStyling; } TestBed.configureTestingModule({declarations: [Cmp, DirThatSetsStyling]}); @@ -1991,7 +1991,7 @@ describe('styling', () => { it('should be able to bind a SafeValue to clip-path', () => { @Component({template: '<div [style.clip-path]="path"></div>'}) class Cmp { - path !: SafeStyle; + path!: SafeStyle; } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -2028,12 +2028,22 @@ describe('styling', () => { public background: string = '1.png'; public color: string = 'red'; - private getSafeStyle(value: string) { return this.sanitizer.bypassSecurityTrustStyle(value); } + private getSafeStyle(value: string) { + return this.sanitizer.bypassSecurityTrustStyle(value); + } - getBackgroundSafe() { return this.getSafeStyle(`url("/${this.background}")`); } - getWidthSafe() { return this.getSafeStyle(this.width); } - getHeightSafe() { return this.getSafeStyle(this.height); } - getColorUnsafe() { return this.color; } + getBackgroundSafe() { + return this.getSafeStyle(`url("/${this.background}")`); + } + getWidthSafe() { + return this.getSafeStyle(this.width); + } + getHeightSafe() { + return this.getSafeStyle(this.height); + } + getColorUnsafe() { + return this.color; + } } TestBed.configureTestingModule({ @@ -2089,11 +2099,9 @@ describe('styling', () => { class Cmp { map: any = null; - @ViewChild('div', {read: DirWithStyleMap, static: true}) - dir1 !: DirWithStyleMap; + @ViewChild('div', {read: DirWithStyleMap, static: true}) dir1!: DirWithStyleMap; - @ViewChild('div', {read: DirWithStyleMapPart2, static: true}) - dir2 !: DirWithStyleMapPart2; + @ViewChild('div', {read: DirWithStyleMapPart2, static: true}) dir2!: DirWithStyleMapPart2; } TestBed.configureTestingModule( @@ -2352,8 +2360,8 @@ describe('styling', () => { @Component({template: '<div #target one two></div>'}) class Cmp { - @ViewChild('target', {read: DirOne, static: true}) one !: DirOne; - @ViewChild('target', {read: DirTwo, static: true}) two !: DirTwo; + @ViewChild('target', {read: DirOne, static: true}) one!: DirOne; + @ViewChild('target', {read: DirTwo, static: true}) two!: DirTwo; } TestBed.configureTestingModule({declarations: [Cmp, DirOne, DirTwo]}); @@ -2443,7 +2451,9 @@ describe('styling', () => { class Cmp { s: any = {opacity: '1'}; - clearStyle(): void { this.s = null; } + clearStyle(): void { + this.s = null; + } } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -2471,8 +2481,7 @@ describe('styling', () => { class ChildCmp { readyTpl = false; - @HostBinding('class.ready-host') - readyHost = false; + @HostBinding('class.ready-host') readyHost = false; } @Component({ @@ -2490,10 +2499,9 @@ describe('styling', () => { class ParentCmp { private _prop = ''; - @ViewChild('template', {read: ViewContainerRef}) - vcr: ViewContainerRef = null !; + @ViewChild('template', {read: ViewContainerRef}) vcr: ViewContainerRef = null!; - private child: ComponentRef<ChildCmp> = null !; + private child: ComponentRef<ChildCmp> = null!; @Input() set prop(value: string) { @@ -2505,7 +2513,9 @@ describe('styling', () => { } } - get prop() { return this._prop; } + get prop() { + return this._prop; + } ngAfterViewInit() { const factory = this.componentFactoryResolver.resolveComponentFactory(ChildCmp); @@ -2559,8 +2569,7 @@ describe('styling', () => { class ChildCmp { readyTpl = false; - @HostBinding('class.ready-host') - readyHost = false; + @HostBinding('class.ready-host') readyHost = false; } @Component({ @@ -2575,10 +2584,9 @@ describe('styling', () => { class ParentCmp { updateChild = false; - @ViewChild('template', {read: ViewContainerRef}) - vcr: ViewContainerRef = null !; + @ViewChild('template', {read: ViewContainerRef}) vcr: ViewContainerRef = null!; - private child: ComponentRef<ChildCmp> = null !; + private child: ComponentRef<ChildCmp> = null!; ngDoCheck() { if (this.updateChild) { @@ -2619,7 +2627,7 @@ describe('styling', () => { expect(readyHost).toBeFalsy(); expect(readyChild).toBeFalsy(); - const parent = fixture.componentInstance.parent !; + const parent = fixture.componentInstance.parent!; parent.updateChild = true; fixture.detectChanges(false); @@ -2675,7 +2683,9 @@ describe('styling', () => { selector: '[dir]', }) class Dir { - constructor(public elementRef: ElementRef, public renderer: Renderer2) { dirInstance = this; } + constructor(public elementRef: ElementRef, public renderer: Renderer2) { + dirInstance = this; + } setStyles() { const nativeEl = this.elementRef.nativeElement; @@ -2730,11 +2740,9 @@ describe('styling', () => { () => { @Directive({selector: '[blockStyles]'}) class StylesDirective { - @HostBinding('style.border') - border = '1px solid red'; + @HostBinding('style.border') border = '1px solid red'; - @HostBinding('style.background') - background = 'white'; + @HostBinding('style.background') background = 'white'; } @Component({ @@ -2863,7 +2871,7 @@ describe('styling', () => { TestBed.configureTestingModule({declarations: [MyComp]}).createComponent(MyComp); fixture.detectChanges(); - const div = fixture.nativeElement.querySelector('div') !; + const div = fixture.nativeElement.querySelector('div')!; div.className += ' abc'; expect(splitSortJoin(div.className)).toEqual('abc'); @@ -2877,7 +2885,9 @@ describe('styling', () => { expect(splitSortJoin(div.className)).toEqual('4 5 6 7 abc'); - function splitSortJoin(s: string) { return s.split(/\s+/).sort().join(' ').trim(); } + function splitSortJoin(s: string) { + return s.split(/\s+/).sort().join(' ').trim(); + } }); describe('ExpressionChangedAfterItHasBeenCheckedError', () => { @@ -2885,7 +2895,9 @@ describe('styling', () => { @Component({template: `<div [style.background-image]="iconSafe"></div>`}) class MyComp { icon = 'https://i.imgur.com/4AiXzf8.jpg'; - get iconSafe() { return this.sanitizer.bypassSecurityTrustStyle(`url("${this.icon}")`); } + get iconSafe() { + return this.sanitizer.bypassSecurityTrustStyle(`url("${this.icon}")`); + } constructor(private sanitizer: DomSanitizer) {} } @@ -2951,7 +2963,7 @@ describe('styling', () => { TestBed.configureTestingModule({declarations: [MyComp, DirThatSetsStyling]}) .createComponent(MyComp); fixture.detectChanges(); - const div = fixture.nativeElement.querySelector('div') !; + const div = fixture.nativeElement.querySelector('div')!; expect(div.style.getPropertyValue('width')).toEqual('100px'); expect(div.style.getPropertyValue('height')).toEqual('200px'); expect(div.style.getPropertyValue('font-size')).toEqual('300px'); @@ -3051,20 +3063,16 @@ describe('styling', () => { () => { @Component({selector: 'my-comp-with-styling', template: ''}) class MyCompWithStyling { - @HostBinding('style') - myStyles: any = {width: '300px'}; + @HostBinding('style') myStyles: any = {width: '300px'}; - @HostBinding('style.height') - myHeight: any = '305px'; + @HostBinding('style.height') myHeight: any = '305px'; } @Directive({selector: '[my-dir-with-styling]'}) class MyDirWithStyling { - @HostBinding('style') - myStyles: any = {width: '200px'}; + @HostBinding('style') myStyles: any = {width: '200px'}; - @HostBinding('style.height') - myHeight: any = '205px'; + @HostBinding('style.height') myHeight: any = '205px'; } @Component({ @@ -3081,15 +3089,15 @@ describe('styling', () => { myStyles: {width?: string} = {width: '100px'}; myHeight: string|null|undefined = '100px'; - @ViewChild(MyDirWithStyling) dir !: MyDirWithStyling; - @ViewChild(MyCompWithStyling) comp !: MyCompWithStyling; + @ViewChild(MyDirWithStyling) dir!: MyDirWithStyling; + @ViewChild(MyCompWithStyling) comp!: MyCompWithStyling; } TestBed.configureTestingModule( {declarations: [MyComp, MyCompWithStyling, MyDirWithStyling]}); const fixture = TestBed.createComponent(MyComp); const comp = fixture.componentInstance; - const elm = fixture.nativeElement.querySelector('my-comp-with-styling') !; + const elm = fixture.nativeElement.querySelector('my-comp-with-styling')!; fixture.detectChanges(); expect(elm.style.width).toEqual('100px'); @@ -3131,7 +3139,7 @@ describe('styling', () => { TestBed.configureTestingModule( {declarations: [MyComp, MyCompWithStyling, MyDirWithStyling]}); const fixture = TestBed.createComponent(MyComp); - const elm = fixture.nativeElement.querySelector('my-comp-with-styling') !; + const elm = fixture.nativeElement.querySelector('my-comp-with-styling')!; fixture.detectChanges(); expect(elm.style.color).toEqual('red'); @@ -3139,7 +3147,6 @@ describe('styling', () => { it('should combine host class.foo bindings from multiple directives', () => { - @Directive({ selector: '[dir-that-sets-one-two]', exportAs: 'one', @@ -3197,8 +3204,8 @@ describe('styling', () => { expect(div2.className).toBe(''); const comp = fixture.componentInstance; - comp.dirOneA !.one = comp.dirOneB !.one = true; - comp.dirOneA !.two = comp.dirOneB !.two = true; + comp.dirOneA!.one = comp.dirOneB!.one = true; + comp.dirOneA!.two = comp.dirOneB!.two = true; fixture.detectChanges(); expect(div1.classList.contains('one')).toBeTruthy(); @@ -3211,8 +3218,8 @@ describe('styling', () => { expect(div2.classList.contains('four')).toBeFalsy(); expect(div2.classList.contains('zero')).toBeFalsy(); - comp.dirTwoA !.three = comp.dirTwoB !.three = true; - comp.dirTwoA !.four = comp.dirTwoB !.four = true; + comp.dirTwoA!.three = comp.dirTwoB!.three = true; + comp.dirTwoA!.four = comp.dirTwoB!.four = true; fixture.detectChanges(); expect(div1.classList.contains('one')).toBeTruthy(); @@ -3242,7 +3249,9 @@ describe('styling', () => { it('should combine static host classes with component "class" host attribute', () => { @Component({selector: 'comp-with-classes', template: '', host: {'class': 'host'}}) class CompWithClasses { - constructor(ref: ElementRef) { ref.nativeElement.classList.add('custom'); } + constructor(ref: ElementRef) { + ref.nativeElement.classList.add('custom'); + } } @Component({ @@ -3282,8 +3291,7 @@ describe('styling', () => { @Directive({selector: '[single-host-style-dir]'}) class SingleHostStyleDir { - @HostBinding('style.width') - width = '100px'; + @HostBinding('style.width') width = '100px'; } TestBed.configureTestingModule({declarations: [Cmp, SingleHostStyleDir]}); @@ -3340,7 +3348,9 @@ describe('styling', () => { @Directive({selector: '[test]'}) class MyDir { @Input('class') - set className(value: string) { logs.push(value); } + set className(value: string) { + logs.push(value); + } } @Component({ @@ -3456,8 +3466,7 @@ describe('styling', () => { template: `className = {{className}}`, }) class MyCmp { - @Input() - className: string = 'unbound'; + @Input() className: string = 'unbound'; } @Component({template: `<my-cmp [class]="'bound'"></my-cmp>`}) class MyApp { @@ -3475,8 +3484,7 @@ describe('styling', () => { template: `className = {{className}}`, }) class MyCmp { - @Input() - className: string = 'unbound'; + @Input() className: string = 'unbound'; } @Component({template: `<my-cmp class="bound"></my-cmp>`}) class MyApp { @@ -3491,8 +3499,8 @@ describe('styling', () => { }); function assertStyleCounters(countForSet: number, countForRemove: number) { - expect(ngDevMode !.rendererSetStyle).toEqual(countForSet); - expect(ngDevMode !.rendererRemoveStyle).toEqual(countForRemove); + expect(ngDevMode!.rendererSetStyle).toEqual(countForSet); + expect(ngDevMode!.rendererRemoveStyle).toEqual(countForRemove); } function assertStyle(element: HTMLElement, prop: string, value: any) { diff --git a/packages/core/test/acceptance/template_ref_spec.ts b/packages/core/test/acceptance/template_ref_spec.ts index b55018e8ec91f..026dcc2c5a464 100644 --- a/packages/core/test/acceptance/template_ref_spec.ts +++ b/packages/core/test/acceptance/template_ref_spec.ts @@ -13,11 +13,9 @@ import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; describe('TemplateRef', () => { describe('rootNodes', () => { - @Component({template: `<ng-template #templateRef></ng-template>`}) class App { - @ViewChild('templateRef', {static: true}) - templateRef !: TemplateRef<any>; + @ViewChild('templateRef', {static: true}) templateRef!: TemplateRef<any>; minutes = 0; } @@ -80,7 +78,7 @@ describe('TemplateRef', () => { ` }) class App { - @ViewChild(MenuContent) content !: MenuContent; + @ViewChild(MenuContent) content!: MenuContent; constructor(public viewContainerRef: ViewContainerRef) {} } diff --git a/packages/core/test/acceptance/text_spec.ts b/packages/core/test/acceptance/text_spec.ts index 9f666ef49a9ac..ff16353b99595 100644 --- a/packages/core/test/acceptance/text_spec.ts +++ b/packages/core/test/acceptance/text_spec.ts @@ -7,7 +7,7 @@ */ import {Component} from '@angular/core'; import {TestBed} from '@angular/core/testing'; -import {of } from 'rxjs'; +import {of} from 'rxjs'; describe('text instructions', () => { it('should handle all flavors of interpolated text', () => { @@ -66,8 +66,8 @@ describe('text instructions', () => { ` }) class App { - who = of ('Sally'); - item = of ({ + who = of('Sally'); + item = of({ what: 'seashells', where: 'seashore', }); diff --git a/packages/core/test/acceptance/view_container_ref_spec.ts b/packages/core/test/acceptance/view_container_ref_spec.ts index 13f1a2c137dfb..cfa09f498bf37 100644 --- a/packages/core/test/acceptance/view_container_ref_spec.ts +++ b/packages/core/test/acceptance/view_container_ref_spec.ts @@ -8,7 +8,7 @@ import {CommonModule, DOCUMENT} from '@angular/common'; import {computeMsgId} from '@angular/compiler'; -import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, Injector, NO_ERRORS_SCHEMA, NgModule, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core'; +import {Compiler, Component, ComponentFactoryResolver, Directive, DoCheck, ElementRef, EmbeddedViewRef, ErrorHandler, Injector, NgModule, NO_ERRORS_SCHEMA, OnInit, Pipe, PipeTransform, QueryList, RendererFactory2, RendererType2, Sanitizer, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵsetDocument} from '@angular/core'; import {Input} from '@angular/core/src/metadata'; import {ngDevModeResetPerfCounters} from '@angular/core/src/util/ng_dev_mode'; import {TestBed, TestComponentRenderer} from '@angular/core/testing'; @@ -18,7 +18,6 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; describe('ViewContainerRef', () => { - /** * Gets the inner HTML of the given element with all HTML comments and Angular internal * reflect attributes omitted. This makes HTML comparisons easier and less verbose. @@ -40,7 +39,6 @@ describe('ViewContainerRef', () => { afterEach(() => clearTranslations()); describe('create', () => { - it('should support view queries inside embedded views created in dir constructors', () => { const fixture = TestBed.createComponent(ConstructorApp); fixture.detectChanges(); @@ -87,7 +85,7 @@ describe('ViewContainerRef', () => { ` }) class TestComp { - @ViewChild(VCRefDirective, {static: true}) vcRefDir !: VCRefDirective; + @ViewChild(VCRefDirective, {static: true}) vcRefDir!: VCRefDirective; } TestBed.configureTestingModule( @@ -141,7 +139,7 @@ describe('ViewContainerRef', () => { ` }) class TestComp { - @ViewChild('container', {read: ViewContainerRef}) vcRef !: ViewContainerRef; + @ViewChild('container', {read: ViewContainerRef}) vcRef!: ViewContainerRef; constructor(public cfr: ComponentFactoryResolver) {} @@ -196,8 +194,8 @@ describe('ViewContainerRef', () => { ` }) class TestComp { - @ViewChild('svg', {read: ViewContainerRef}) svgVCRef !: ViewContainerRef; - @ViewChild('mathml', {read: ViewContainerRef}) mathMLVCRef !: ViewContainerRef; + @ViewChild('svg', {read: ViewContainerRef}) svgVCRef!: ViewContainerRef; + @ViewChild('mathml', {read: ViewContainerRef}) mathMLVCRef!: ViewContainerRef; constructor(public cfr: ComponentFactoryResolver) {} @@ -273,7 +271,7 @@ describe('ViewContainerRef', () => { ` }) class TestComp { - @ViewChild('container', {read: ViewContainerRef}) vcRef !: ViewContainerRef; + @ViewChild('container', {read: ViewContainerRef}) vcRef!: ViewContainerRef; private helloCompFactory = this.cfr.resolveComponentFactory(HelloComp); @@ -357,7 +355,9 @@ describe('ViewContainerRef', () => { // Insert the view again at the same index viewContainerRef.insert(ref0, 0); - expect(() => { fixture.destroy(); }).not.toThrow(); + expect(() => { + fixture.destroy(); + }).not.toThrow(); expect(fixture.nativeElement.textContent).toEqual('0'); }); @@ -405,7 +405,6 @@ describe('ViewContainerRef', () => { }); it('should insert a view already inserted into another container', () => { - @Component({ selector: 'test-cmpt', template: ` @@ -414,9 +413,9 @@ describe('ViewContainerRef', () => { ` }) class TestComponent { - @ViewChild('t', {static: true}) t !: TemplateRef<{}>; - @ViewChild('c1', {static: true, read: ViewContainerRef}) c1 !: ViewContainerRef; - @ViewChild('c2', {static: true, read: ViewContainerRef}) c2 !: ViewContainerRef; + @ViewChild('t', {static: true}) t!: TemplateRef<{}>; + @ViewChild('c1', {static: true, read: ViewContainerRef}) c1!: ViewContainerRef; + @ViewChild('c2', {static: true, read: ViewContainerRef}) c2!: ViewContainerRef; } TestBed.configureTestingModule({declarations: [TestComponent]}); @@ -660,7 +659,6 @@ describe('ViewContainerRef', () => { }); describe('get and indexOf', () => { - beforeEach(() => { TestBed.configureTestingModule({declarations: [EmbeddedViewInsertionComp, VCRefDirective]}); }); @@ -677,13 +675,13 @@ describe('ViewContainerRef', () => { fixture.detectChanges(); let viewRef = vcRefDir.vcref.get(0); - expect(vcRefDir.vcref.indexOf(viewRef !)).toEqual(0); + expect(vcRefDir.vcref.indexOf(viewRef!)).toEqual(0); viewRef = vcRefDir.vcref.get(1); - expect(vcRefDir.vcref.indexOf(viewRef !)).toEqual(1); + expect(vcRefDir.vcref.indexOf(viewRef!)).toEqual(1); viewRef = vcRefDir.vcref.get(2); - expect(vcRefDir.vcref.indexOf(viewRef !)).toEqual(2); + expect(vcRefDir.vcref.indexOf(viewRef!)).toEqual(2); }); it('should handle out of bounds cases', () => { @@ -700,7 +698,7 @@ describe('ViewContainerRef', () => { const viewRef = vcRefDir.vcref.get(0); vcRefDir.vcref.remove(0); - expect(vcRefDir.vcref.indexOf(viewRef !)).toEqual(-1); + expect(vcRefDir.vcref.indexOf(viewRef!)).toEqual(-1); }); it('should return -1 as indexOf when no views were inserted', () => { @@ -742,21 +740,21 @@ describe('ViewContainerRef', () => { expect(getElementHtml(fixture.nativeElement)).toEqual('<p vcref=""></p>**A**BC'); let viewRef = vcRefDir.vcref.get(0); - vcRefDir.vcref.move(viewRef !, 2); + vcRefDir.vcref.move(viewRef!, 2); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)).toEqual('<p vcref=""></p>BC**A**'); - vcRefDir.vcref.move(viewRef !, 0); + vcRefDir.vcref.move(viewRef!, 0); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)).toEqual('<p vcref=""></p>**A**BC'); - vcRefDir.vcref.move(viewRef !, 1); + vcRefDir.vcref.move(viewRef!, 1); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)).toEqual('<p vcref=""></p>B**A**C'); // Invalid indices when detaching throws an exception in Ivy: FW-1330. - ivyEnabled && expect(() => vcRefDir.vcref.move(viewRef !, -1)).toThrow(); - ivyEnabled && expect(() => vcRefDir.vcref.move(viewRef !, 42)).toThrow(); + ivyEnabled && expect(() => vcRefDir.vcref.move(viewRef!, -1)).toThrow(); + ivyEnabled && expect(() => vcRefDir.vcref.move(viewRef!, 42)).toThrow(); }); }); @@ -769,7 +767,7 @@ describe('ViewContainerRef', () => { ` }) class TestComponent { - @ViewChild(VCRefDirective, {static: true}) vcRefDir !: VCRefDirective; + @ViewChild(VCRefDirective, {static: true}) vcRefDir!: VCRefDirective; } TestBed.configureTestingModule({declarations: [VCRefDirective, TestComponent]}); @@ -789,7 +787,6 @@ describe('ViewContainerRef', () => { }); describe('detach', () => { - beforeEach(() => { TestBed.configureTestingModule({declarations: [EmbeddedViewInsertionComp, VCRefDirective]}); @@ -825,7 +822,7 @@ describe('ViewContainerRef', () => { // Invalid indices when detaching throws an exception in Ivy: FW-1330. ivyEnabled && expect(() => vcRefDir.vcref.detach(-1)).toThrow(); ivyEnabled && expect(() => vcRefDir.vcref.detach(42)).toThrow(); - ivyEnabled && expect(ngDevMode !.rendererDestroyNode).toBe(0); + ivyEnabled && expect(ngDevMode!.rendererDestroyNode).toBe(0); }); it('should detach the last embedded view when no index is specified', () => { @@ -846,7 +843,7 @@ describe('ViewContainerRef', () => { fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)).toEqual('<p vcref=""></p>ABCD'); expect(viewE.destroyed).toBeFalsy(); - ivyEnabled && expect(ngDevMode !.rendererDestroyNode).toBe(0); + ivyEnabled && expect(ngDevMode!.rendererDestroyNode).toBe(0); }); }); @@ -895,7 +892,7 @@ describe('ViewContainerRef', () => { // Invalid indices when detaching throws an exception in Ivy: FW-1330. ivyEnabled && expect(() => vcRefDir.vcref.remove(-1)).toThrow(); ivyEnabled && expect(() => vcRefDir.vcref.remove(42)).toThrow(); - ivyEnabled && expect(ngDevMode !.rendererDestroyNode).toBe(2); + ivyEnabled && expect(ngDevMode!.rendererDestroyNode).toBe(2); }); it('should remove the last embedded view when no index is specified', () => { @@ -916,7 +913,7 @@ describe('ViewContainerRef', () => { fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)).toEqual('<p vcref=""></p>ABCD'); expect(viewE.destroyed).toBeTruthy(); - ivyEnabled && expect(ngDevMode !.rendererDestroyNode).toBe(1); + ivyEnabled && expect(ngDevMode!.rendererDestroyNode).toBe(1); }); it('should throw when trying to insert a removed or destroyed view', () => { @@ -1063,7 +1060,7 @@ describe('ViewContainerRef', () => { ` }) class TestComponent { - @ViewChild(VCRefDirective, {static: true}) vcRef !: VCRefDirective; + @ViewChild(VCRefDirective, {static: true}) vcRef!: VCRefDirective; } TestBed.configureTestingModule({declarations: [TestComponent, VCRefDirective]}); @@ -1087,8 +1084,8 @@ describe('ViewContainerRef', () => { expect(getElementHtml(fixture.nativeElement)).toEqual('YABC<footer></footer>'); // Invalid indices when detaching throws an exception in Ivy: FW-1330. - ivyEnabled && expect(() => vcRef !.createView('Z', -1)).toThrow(); - ivyEnabled && expect(() => vcRef !.createView('Z', 5)).toThrow(); + ivyEnabled && expect(() => vcRef!.createView('Z', -1)).toThrow(); + ivyEnabled && expect(() => vcRef!.createView('Z', 5)).toThrow(); }); it('should apply directives and pipes of the host view to the TemplateRef', () => { @@ -1099,7 +1096,9 @@ describe('ViewContainerRef', () => { @Pipe({name: 'starPipe'}) class StarPipe implements PipeTransform { - transform(value: any) { return `**${value}**`; } + transform(value: any) { + return `**${value}**`; + } } @Component({ @@ -1121,15 +1120,14 @@ describe('ViewContainerRef', () => { fixture.debugElement.query(By.directive(VCRefDirective)).injector.get(VCRefDirective); fixture.detectChanges(); - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)) .toEqual( '<child vcref="">**A**</child><child>**C**</child><child>**C**</child><child>**B**</child>'); }); - }); describe('createComponent', () => { @@ -1140,9 +1138,13 @@ describe('ViewContainerRef', () => { it('should work without Injector and NgModuleRef', () => { @Component({selector: 'embedded-cmp', template: `foo`}) class EmbeddedComponent implements DoCheck, OnInit { - ngOnInit() { templateExecutionCounter++; } + ngOnInit() { + templateExecutionCounter++; + } - ngDoCheck() { templateExecutionCounter++; } + ngDoCheck() { + templateExecutionCounter++; + } } @NgModule({entryComponents: [EmbeddedComponent], declarations: [EmbeddedComponent]}) @@ -1185,13 +1187,16 @@ describe('ViewContainerRef', () => { selector: 'embedded-cmp', template: `foo`, }) - class EmbeddedComponent implements DoCheck, - OnInit { + class EmbeddedComponent implements DoCheck, OnInit { constructor(public s: String) {} - ngOnInit() { templateExecutionCounter++; } + ngOnInit() { + templateExecutionCounter++; + } - ngDoCheck() { templateExecutionCounter++; } + ngDoCheck() { + templateExecutionCounter++; + } } @NgModule({entryComponents: [EmbeddedComponent], declarations: [EmbeddedComponent]}) @@ -1423,7 +1428,7 @@ describe('ViewContainerRef', () => { const makeComponentFactory = (componentType: any) => ({ create: () => TestBed.createComponent(componentType).componentRef, }); - this.viewContainerRef !.createComponent(makeComponentFactory(Child) as any); + this.viewContainerRef!.createComponent(makeComponentFactory(Child) as any); } } @@ -1493,8 +1498,8 @@ describe('ViewContainerRef', () => { `, }) class LoopComp { - @Input() tpl !: TemplateRef<any>; - @Input() rows !: any[]; + @Input() tpl!: TemplateRef<any>; + @Input() rows!: any[]; name = 'Loop'; } @@ -1715,7 +1720,6 @@ describe('ViewContainerRef', () => { }); describe('lifecycle hooks', () => { - // Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-vcref const log: string[] = []; @@ -1723,19 +1727,37 @@ describe('ViewContainerRef', () => { class ComponentWithHooks { @Input() name: string|undefined; - private log(msg: string) { log.push(msg); } + private log(msg: string) { + log.push(msg); + } - ngOnChanges() { this.log('onChanges-' + this.name); } - ngOnInit() { this.log('onInit-' + this.name); } - ngDoCheck() { this.log('doCheck-' + this.name); } + ngOnChanges() { + this.log('onChanges-' + this.name); + } + ngOnInit() { + this.log('onInit-' + this.name); + } + ngDoCheck() { + this.log('doCheck-' + this.name); + } - ngAfterContentInit() { this.log('afterContentInit-' + this.name); } - ngAfterContentChecked() { this.log('afterContentChecked-' + this.name); } + ngAfterContentInit() { + this.log('afterContentInit-' + this.name); + } + ngAfterContentChecked() { + this.log('afterContentChecked-' + this.name); + } - ngAfterViewInit() { this.log('afterViewInit-' + this.name); } - ngAfterViewChecked() { this.log('afterViewChecked-' + this.name); } + ngAfterViewInit() { + this.log('afterViewInit-' + this.name); + } + ngAfterViewChecked() { + this.log('afterViewChecked-' + this.name); + } - ngOnDestroy() { this.log('onDestroy-' + this.name); } + ngOnDestroy() { + this.log('onDestroy-' + this.name); + } } @NgModule({ @@ -1784,7 +1806,7 @@ describe('ViewContainerRef', () => { ]); log.length = 0; - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); expect(getElementHtml(fixture.nativeElement)) .toEqual('<hooks vcref="">A</hooks><hooks></hooks><hooks>B</hooks>'); expect(log).toEqual([]); @@ -1815,7 +1837,7 @@ describe('ViewContainerRef', () => { ]); log.length = 0; - vcRefDir.vcref.insert(viewRef !); + vcRefDir.vcref.insert(viewRef!); fixture.detectChanges(); expect(log).toEqual([ 'doCheck-A', 'doCheck-B', 'doCheck-C', 'afterContentChecked-C', 'afterViewChecked-C', @@ -1898,7 +1920,7 @@ describe('ViewContainerRef', () => { ]); log.length = 0; - vcRefDir.vcref.insert(viewRef !); + vcRefDir.vcref.insert(viewRef!); fixture.detectChanges(); expect(log).toEqual([ 'doCheck-A', 'doCheck-B', 'doCheck-D', 'afterContentChecked-D', 'afterViewChecked-D', @@ -1916,7 +1938,6 @@ describe('ViewContainerRef', () => { }); describe('host bindings', () => { - it('should support host bindings on dynamically created components', () => { @Component( {selector: 'host-bindings', host: {'id': 'attribute', '[title]': 'title'}, template: ``}) @@ -1926,7 +1947,7 @@ describe('ViewContainerRef', () => { @Component({template: `<ng-template vcref></ng-template>`}) class TestComponent { - @ViewChild(VCRefDirective, {static: true}) vcRefDir !: VCRefDirective; + @ViewChild(VCRefDirective, {static: true}) vcRefDir!: VCRefDirective; } @NgModule({declarations: [HostBindingCmpt], entryComponents: [HostBindingCmpt]}) @@ -1956,11 +1977,9 @@ describe('ViewContainerRef', () => { expect(fixture.nativeElement.children[0].getAttribute('id')).toBe('attribute'); expect(fixture.nativeElement.children[0].getAttribute('title')).toBe('changed'); }); - }); describe('projection', () => { - it('should project the ViewContainerRef content along its host, in an element', () => { @Component({selector: 'child', template: '<div><ng-content></ng-content></div>'}) class Child { @@ -1990,7 +2009,7 @@ describe('ViewContainerRef', () => { expect(getElementHtml(fixture.nativeElement)) .toEqual('<child><div><header vcref="">blah</header></div></child>'); - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)) .toEqual('<child><div><header vcref="">blah</header><span>bar</span></div></child>'); @@ -2031,7 +2050,7 @@ describe('ViewContainerRef', () => { .toEqual( '<child-with-view>Before (inside)- Before projected <header vcref="">blah</header> After projected -After (inside)</child-with-view>'); - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)) @@ -2067,7 +2086,6 @@ describe('ViewContainerRef', () => { }); describe('with select', () => { - @Component({ selector: 'child-with-selector', template: ` @@ -2105,7 +2123,7 @@ describe('ViewContainerRef', () => { .toEqual( '<child-with-selector><p class="a"><header vcref="">blah</header></p><p class="b"></p></child-with-selector>'); - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)) @@ -2132,13 +2150,13 @@ describe('ViewContainerRef', () => { ` }) class MyComp { - @ViewChild('source', {static: true}) - source !: TemplateRef<{}>; + @ViewChild('source', {static: true}) source!: TemplateRef<{}>; - @ViewChild('target', {read: ViewContainerRef, static: true}) - target !: ViewContainerRef; + @ViewChild('target', {read: ViewContainerRef, static: true}) target!: ViewContainerRef; - ngOnInit() { this.target.createEmbeddedView(this.source); } + ngOnInit() { + this.target.createEmbeddedView(this.source); + } } TestBed.configureTestingModule({declarations: [MyComp, ContentComp]}); @@ -2175,7 +2193,7 @@ describe('ViewContainerRef', () => { .toEqual( '<child-with-selector><p class="a"></p><p class="b"><footer vcref="">blah</footer></p></child-with-selector>'); - vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef !); + vcRefDir.vcref.createEmbeddedView(vcRefDir.tplRef!); fixture.detectChanges(); expect(getElementHtml(fixture.nativeElement)) @@ -2183,7 +2201,6 @@ describe('ViewContainerRef', () => { '<child-with-selector><p class="a"></p><p class="b"><footer vcref="">blah</footer><span>bar</span></p></child-with-selector>'); }); }); - }); describe('root view container ref', () => { @@ -2204,7 +2221,7 @@ describe('ViewContainerRef', () => { containerEl = document.createElement('div'); document.body.appendChild(containerEl); - containerEl !.appendChild(rootEl); + containerEl!.appendChild(rootEl); } }; } @@ -2223,7 +2240,9 @@ describe('ViewContainerRef', () => { class DynamicCompWithBindings implements DoCheck { checkCount = 0; - ngDoCheck() { this.checkCount++; } + ngDoCheck() { + this.checkCount++; + } } @Component({template: ``}) @@ -2248,21 +2267,21 @@ describe('ViewContainerRef', () => { // Ivy inserts a comment for the root view container ref instance. This is not // the case for view engine and we need to adjust the assertions. - expect(containerEl !.childNodes.length).toBe(ivyEnabled ? 2 : 1); - ivyEnabled && expect(containerEl !.childNodes[1].nodeType).toBe(Node.COMMENT_NODE); + expect(containerEl!.childNodes.length).toBe(ivyEnabled ? 2 : 1); + ivyEnabled && expect(containerEl!.childNodes[1].nodeType).toBe(Node.COMMENT_NODE); - expect((containerEl !.childNodes[0] as Element).tagName).toBe('DIV'); + expect((containerEl!.childNodes[0] as Element).tagName).toBe('DIV'); vcRef.createComponent(cfResolver.resolveComponentFactory(DynamicCompWithBindings)); fixture.detectChanges(); - expect(containerEl !.childNodes.length).toBe(ivyEnabled ? 3 : 2); - expect(containerEl !.childNodes[1].textContent).toBe('check count: 1'); + expect(containerEl!.childNodes.length).toBe(ivyEnabled ? 3 : 2); + expect(containerEl!.childNodes[1].textContent).toBe('check count: 1'); fixture.detectChanges(); - expect(containerEl !.childNodes.length).toBe(ivyEnabled ? 3 : 2); - expect(containerEl !.childNodes[1].textContent).toBe('check count: 2'); + expect(containerEl!.childNodes.length).toBe(ivyEnabled ? 3 : 2); + expect(containerEl!.childNodes[1].textContent).toBe('check count: 2'); }); it('should create deep DOM tree immediately for dynamically created components', () => { @@ -2299,21 +2318,21 @@ describe('ViewContainerRef', () => { // Ivy inserts a comment for the root view container ref instance. This is not // the case for view engine and we need to adjust the assertions. - expect(containerEl !.childNodes.length).toBe(ivyEnabled ? 2 : 1); - ivyEnabled && expect(containerEl !.childNodes[1].nodeType).toBe(Node.COMMENT_NODE); + expect(containerEl!.childNodes.length).toBe(ivyEnabled ? 2 : 1); + ivyEnabled && expect(containerEl!.childNodes[1].nodeType).toBe(Node.COMMENT_NODE); - expect((containerEl !.childNodes[0] as Element).tagName).toBe('DIV'); + expect((containerEl!.childNodes[0] as Element).tagName).toBe('DIV'); vcRef.createComponent(cfResolver.resolveComponentFactory(DynamicCompWithChildren)); - expect(containerEl !.childNodes.length).toBe(ivyEnabled ? 3 : 2); - expect(getElementHtml(containerEl !.childNodes[1] as Element)) + expect(containerEl!.childNodes.length).toBe(ivyEnabled ? 3 : 2); + expect(getElementHtml(containerEl!.childNodes[1] as Element)) .toBe('<child><div></div></child>'); fixture.detectChanges(); - expect(containerEl !.childNodes.length).toBe(ivyEnabled ? 3 : 2); - expect(getElementHtml(containerEl !.childNodes[1] as Element)) + expect(containerEl!.childNodes.length).toBe(ivyEnabled ? 3 : 2); + expect(getElementHtml(containerEl!.childNodes[1] as Element)) .toBe(`<child><div>text</div></child>`); }); }); @@ -2374,7 +2393,7 @@ class EmbeddedComponentWithNgZoneModule { ` }) class ViewContainerRefComp { - @ViewChildren(TemplateRef) templates !: QueryList<TemplateRef<any>>; + @ViewChildren(TemplateRef) templates!: QueryList<TemplateRef<any>>; constructor(public vcr: ViewContainerRef) {} } @@ -2386,21 +2405,25 @@ class ViewContainerRefComp { ` }) class ViewContainerRefApp { - @ViewChild(ViewContainerRefComp) vcrComp !: ViewContainerRefComp; + @ViewChild(ViewContainerRefComp) vcrComp!: ViewContainerRefComp; } @Directive({selector: '[structDir]'}) export class StructDir { constructor(private vcref: ViewContainerRef, private tplRef: TemplateRef<any>) {} - create() { this.vcref.createEmbeddedView(this.tplRef); } + create() { + this.vcref.createEmbeddedView(this.tplRef); + } - destroy() { this.vcref.clear(); } + destroy() { + this.vcref.clear(); + } } @Component({selector: 'destroy-cases', template: ` `}) class DestroyCasesComp { - @ViewChildren(StructDir) structDirs !: QueryList<StructDir>; + @ViewChildren(StructDir) structDirs!: QueryList<StructDir>; } @Directive({selector: '[constructorDir]'}) @@ -2419,7 +2442,7 @@ class ConstructorDir { ` }) class ConstructorApp { - @ViewChild('foo', {static: true}) foo !: ElementRef; + @ViewChild('foo', {static: true}) foo!: ElementRef; } @Component({ @@ -2431,5 +2454,5 @@ class ConstructorApp { ` }) class ConstructorAppWithQueries { - @ViewChild('foo', {static: true}) foo !: TemplateRef<any>; + @ViewChild('foo', {static: true}) foo!: TemplateRef<any>; } diff --git a/packages/core/test/acceptance/view_insertion_spec.ts b/packages/core/test/acceptance/view_insertion_spec.ts index 41099fd2478ab..265816486503b 100644 --- a/packages/core/test/acceptance/view_insertion_spec.ts +++ b/packages/core/test/acceptance/view_insertion_spec.ts @@ -33,15 +33,14 @@ describe('view insertion', () => { }) class App { @ViewChild('container', {read: ViewContainerRef, static: true}) - container: ViewContainerRef = null !; + container: ViewContainerRef = null!; - @ViewChild('simple', {read: TemplateRef, static: true}) - simple: TemplateRef<any> = null !; + @ViewChild('simple', {read: TemplateRef, static: true}) simple: TemplateRef<any> = null!; - view0: EmbeddedViewRef<any> = null !; - view1: EmbeddedViewRef<any> = null !; - view2: EmbeddedViewRef<any> = null !; - view3: EmbeddedViewRef<any> = null !; + view0: EmbeddedViewRef<any> = null!; + view1: EmbeddedViewRef<any> = null!; + view2: EmbeddedViewRef<any> = null!; + view3: EmbeddedViewRef<any> = null!; constructor(public changeDetector: ChangeDetectorRef) {} @@ -90,16 +89,14 @@ describe('view insertion', () => { ` }) class App { - @ViewChild('container', {read: ViewContainerRef}) - container: ViewContainerRef = null !; + @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef = null!; - @ViewChild('empty', {read: TemplateRef}) - empty: TemplateRef<any> = null !; + @ViewChild('empty', {read: TemplateRef}) empty: TemplateRef<any> = null!; - view0: EmbeddedViewRef<any> = null !; - view1: EmbeddedViewRef<any> = null !; - view2: EmbeddedViewRef<any> = null !; - view3: EmbeddedViewRef<any> = null !; + view0: EmbeddedViewRef<any> = null!; + view1: EmbeddedViewRef<any> = null!; + view2: EmbeddedViewRef<any> = null!; + view3: EmbeddedViewRef<any> = null!; ngAfterViewInit() { // insert at the front @@ -140,16 +137,14 @@ describe('view insertion', () => { ` }) class Comp { - @ViewChild('container', {read: ViewContainerRef}) - container: ViewContainerRef = null !; + @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef = null!; - @ViewChild('projection', {read: TemplateRef}) - projection: TemplateRef<any> = null !; + @ViewChild('projection', {read: TemplateRef}) projection: TemplateRef<any> = null!; - view0: EmbeddedViewRef<any> = null !; - view1: EmbeddedViewRef<any> = null !; - view2: EmbeddedViewRef<any> = null !; - view3: EmbeddedViewRef<any> = null !; + view0: EmbeddedViewRef<any> = null!; + view1: EmbeddedViewRef<any> = null!; + view2: EmbeddedViewRef<any> = null!; + view3: EmbeddedViewRef<any> = null!; ngAfterViewInit() { // insert at the front @@ -201,16 +196,14 @@ describe('view insertion', () => { ` }) class App { - @ViewChild('container', {read: ViewContainerRef}) - container: ViewContainerRef = null !; + @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef = null!; - @ViewChild('subContainer', {read: TemplateRef}) - subContainer: TemplateRef<any> = null !; + @ViewChild('subContainer', {read: TemplateRef}) subContainer: TemplateRef<any> = null!; - view0: EmbeddedViewRef<any> = null !; - view1: EmbeddedViewRef<any> = null !; - view2: EmbeddedViewRef<any> = null !; - view3: EmbeddedViewRef<any> = null !; + view0: EmbeddedViewRef<any> = null!; + view1: EmbeddedViewRef<any> = null!; + view2: EmbeddedViewRef<any> = null!; + view3: EmbeddedViewRef<any> = null!; constructor(public changeDetectorRef: ChangeDetectorRef) {} @@ -265,9 +258,9 @@ describe('view insertion', () => { describe('before embedded view', () => { @Component({selector: 'test-cmpt', template: ''}) class TestCmpt { - @ViewChild('before', {static: true}) beforeTpl !: TemplateRef<{}>; - @ViewChild('insert', {static: true}) insertTpl !: TemplateRef<{}>; - @ViewChild('vi', {static: true}) viewInsertingDir !: ViewInsertingDir; + @ViewChild('before', {static: true}) beforeTpl!: TemplateRef<{}>; + @ViewChild('insert', {static: true}) insertTpl!: TemplateRef<{}>; + @ViewChild('vi', {static: true}) viewInsertingDir!: ViewInsertingDir; minutes = 10; @@ -303,8 +296,9 @@ describe('view insertion', () => { } - it('should insert before a view with the text node as the first root node', - () => { expect(createAndInsertViews('|before').textContent).toBe('insert|before'); }); + it('should insert before a view with the text node as the first root node', () => { + expect(createAndInsertViews('|before').textContent).toBe('insert|before'); + }); it('should insert before a view with the element as the first root node', () => { expect(createAndInsertViews('<span>|before</span>').textContent).toBe('insert|before'); @@ -336,13 +330,11 @@ describe('view insertion', () => { it('should insert before a view with a container as the first root node', () => { expect(createAndInsertViews(`<ng-template [ngIf]="true">|before</ng-template>`).textContent) .toBe('insert|before'); - }); it('should insert before a view with an empty container as the first root node', () => { expect(createAndInsertViews(`<ng-template [ngIf]="true"></ng-template>|before`).textContent) .toBe('insert|before'); - }); onlyInIvy('VE incorrectly inserts views before ng-container content') @@ -353,7 +345,6 @@ describe('view insertion', () => { <ng-template #after>|after</ng-template> `).textContent) .toBe('insert|before|after'); - }); @@ -363,7 +354,6 @@ describe('view insertion', () => { <ng-template #after>|after</ng-template> `).textContent) .toBe('insert|before|after'); - }); it('should insert before a view with an empty projection as the first root node', () => { @@ -414,11 +404,9 @@ describe('view insertion', () => { fixture.detectChanges(); expect(fixture.debugElement.nativeElement.textContent).toBe('start|testtest|end'); }); - }); describe('before embedded view with projection', () => { - @Component({ selector: 'with-content', template: ` @@ -428,9 +416,9 @@ describe('view insertion', () => { ` }) class WithContentCmpt { - @ViewChild('insert', {static: true}) insertTpl !: TemplateRef<{}>; - @ViewChild('before', {static: true}) beforeTpl !: TemplateRef<{}>; - @ViewChild('vi', {static: true}) viewInsertingDir !: ViewInsertingDir; + @ViewChild('insert', {static: true}) insertTpl!: TemplateRef<{}>; + @ViewChild('before', {static: true}) beforeTpl!: TemplateRef<{}>; + @ViewChild('vi', {static: true}) viewInsertingDir!: ViewInsertingDir; insert() { const beforeView = this.beforeTpl.createEmbeddedView({}); @@ -442,7 +430,7 @@ describe('view insertion', () => { @Component({selector: 'test-cmpt', template: ''}) class TestCmpt { - @ViewChild('wc', {static: true}) withContentCmpt !: WithContentCmpt; + @ViewChild('wc', {static: true}) withContentCmpt!: WithContentCmpt; } beforeEach(() => { @@ -476,7 +464,6 @@ describe('view insertion', () => { expect(fixture.nativeElement.textContent).toBe('insert|before'); }); - }); describe('before component view', () => { @@ -503,8 +490,8 @@ describe('view insertion', () => { ` }) class TestCmpt { - @ViewChild('insert', {static: true}) insertTpl !: TemplateRef<{}>; - @ViewChild('vi', {static: true}) viewInsertingDir !: ViewInsertingDir; + @ViewChild('insert', {static: true}) insertTpl!: TemplateRef<{}>; + @ViewChild('vi', {static: true}) viewInsertingDir!: ViewInsertingDir; constructor(private _cfr: ComponentFactoryResolver, private _injector: Injector) {} @@ -537,16 +524,13 @@ describe('view insertion', () => { expect(fixture.nativeElement.textContent).toBe('insert|before'); }); - }); }); describe('non-regression', () => { - // https://github.com/angular/angular/issues/31971 it('should insert component views into ViewContainerRef injected by querying <ng-container>', () => { - @Component({selector: 'dynamic-cmpt', template: 'dynamic'}) class DynamicComponent { } @@ -562,8 +546,7 @@ describe('view insertion', () => { ` }) class AppComponent { - @ViewChild('container', {read: ViewContainerRef, static: true}) - vcr !: ViewContainerRef; + @ViewChild('container', {read: ViewContainerRef, static: true}) vcr!: ViewContainerRef; constructor(private _cfr: ComponentFactoryResolver) {} @@ -595,7 +578,6 @@ describe('view insertion', () => { // https://github.com/angular/angular/issues/33679 it('should insert embedded views into ViewContainerRef injected by querying <ng-container>', () => { - @Component({ selector: 'app-root', template: ` @@ -608,12 +590,13 @@ describe('view insertion', () => { ` }) class AppComponent { - @ViewChild('container', {read: ViewContainerRef, static: true}) - vcr !: ViewContainerRef; + @ViewChild('container', {read: ViewContainerRef, static: true}) vcr!: ViewContainerRef; @ViewChild('template', {read: TemplateRef, static: true}) template !: TemplateRef<any>; - click() { this.vcr.createEmbeddedView(this.template, undefined, 0); } + click() { + this.vcr.createEmbeddedView(this.template, undefined, 0); + } } TestBed.configureTestingModule({ @@ -659,6 +642,5 @@ describe('view insertion', () => { expect(fixture.nativeElement.textContent.trim()).toContain('2 1'); }); - }); }); diff --git a/packages/core/test/acceptance/view_ref_spec.ts b/packages/core/test/acceptance/view_ref_spec.ts index fcb1cf28f635b..04e2104ba902f 100644 --- a/packages/core/test/acceptance/view_ref_spec.ts +++ b/packages/core/test/acceptance/view_ref_spec.ts @@ -13,7 +13,6 @@ import {TestBed} from '@angular/core/testing'; describe('ViewRef', () => { it('should remove nodes from DOM when the view is detached from app ref', () => { - @Component({selector: 'dynamic-cpt', template: '<div></div>'}) class DynamicComponent { constructor(public elRef: ElementRef) {} @@ -21,7 +20,7 @@ describe('ViewRef', () => { @Component({template: `<span></span>`}) class App { - componentRef !: ComponentRef<DynamicComponent>; + componentRef!: ComponentRef<DynamicComponent>; constructor( public appRef: ApplicationRef, private cfr: ComponentFactoryResolver, private injector: Injector) {} @@ -33,7 +32,9 @@ describe('ViewRef', () => { document.body.appendChild(this.componentRef.instance.elRef.nativeElement); } - destroy() { (this.componentRef.hostView as InternalViewRef).detachFromAppRef(); } + destroy() { + (this.componentRef.hostView as InternalViewRef).detachFromAppRef(); + } } @NgModule({declarations: [App, DynamicComponent], entryComponents: [DynamicComponent]}) diff --git a/packages/core/test/animation/animation_integration_spec.ts b/packages/core/test/animation/animation_integration_spec.ts index d2034fb6a28d2..15ebcef106e24 100644 --- a/packages/core/test/animation/animation_integration_spec.ts +++ b/packages/core/test/animation/animation_integration_spec.ts @@ -5,12 +5,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AUTO_STYLE, AnimationEvent, AnimationOptions, animate, animateChild, group, keyframes, query, state, style, transition, trigger, ɵPRE_STYLE as PRE_STYLE} from '@angular/animations'; +import {animate, animateChild, AnimationEvent, AnimationOptions, AUTO_STYLE, group, keyframes, query, state, style, transition, trigger, ɵPRE_STYLE as PRE_STYLE} from '@angular/animations'; import {AnimationDriver, ɵAnimationEngine, ɵNoopAnimationDriver as NoopAnimationDriver} from '@angular/animations/browser'; import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing'; import {ɵgetDOM as getDOM} from '@angular/common'; import {ChangeDetectorRef, Component, HostBinding, HostListener, Inject, RendererFactory2, ViewChild} from '@angular/core'; -import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing'; import {ɵDomRendererFactory2} from '@angular/platform-browser'; import {ANIMATION_MODULE_TYPE, BrowserAnimationsModule, NoopAnimationsModule} from '@angular/platform-browser/animations'; import {hasStyle} from '@angular/platform-browser/testing/src/browser_util'; @@ -20,792 +20,853 @@ const DEFAULT_NAMESPACE_ID = 'id'; const DEFAULT_COMPONENT_ID = '1'; (function() { - // these tests are only mean't to be run within the DOM (for now) - if (isNode) return; +// these tests are only mean't to be run within the DOM (for now) +if (isNode) return; - describe('animation tests', function() { - function getLog(): MockAnimationPlayer[] { - return MockAnimationDriver.log as MockAnimationPlayer[]; - } +describe('animation tests', function() { + function getLog(): MockAnimationPlayer[] { + return MockAnimationDriver.log as MockAnimationPlayer[]; + } - function resetLog() { MockAnimationDriver.log = []; } + function resetLog() { + MockAnimationDriver.log = []; + } - beforeEach(() => { - resetLog(); - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}], - imports: [BrowserAnimationsModule] - }); + beforeEach(() => { + resetLog(); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}], + imports: [BrowserAnimationsModule] }); + }); - describe('animation modules', function() { - it('should hint at BrowserAnimationsModule being used', () => { - TestBed.resetTestingModule(); - TestBed.configureTestingModule( - {declarations: [SharedAnimationCmp], imports: [BrowserAnimationsModule]}); + describe('animation modules', function() { + it('should hint at BrowserAnimationsModule being used', () => { + TestBed.resetTestingModule(); + TestBed.configureTestingModule( + {declarations: [SharedAnimationCmp], imports: [BrowserAnimationsModule]}); - const fixture = TestBed.createComponent(SharedAnimationCmp); - const cmp = fixture.componentInstance; - expect(cmp.animationType).toEqual('BrowserAnimations'); - }); + const fixture = TestBed.createComponent(SharedAnimationCmp); + const cmp = fixture.componentInstance; + expect(cmp.animationType).toEqual('BrowserAnimations'); + }); - it('should hint at NoopAnimationsModule being used', () => { - TestBed.resetTestingModule(); - TestBed.configureTestingModule( - {declarations: [SharedAnimationCmp], imports: [NoopAnimationsModule]}); + it('should hint at NoopAnimationsModule being used', () => { + TestBed.resetTestingModule(); + TestBed.configureTestingModule( + {declarations: [SharedAnimationCmp], imports: [NoopAnimationsModule]}); - const fixture = TestBed.createComponent(SharedAnimationCmp); - const cmp = fixture.componentInstance; - expect(cmp.animationType).toEqual('NoopAnimations'); - }); + const fixture = TestBed.createComponent(SharedAnimationCmp); + const cmp = fixture.componentInstance; + expect(cmp.animationType).toEqual('NoopAnimations'); }); + }); - @Component({template: '<p>template text</p>'}) - class SharedAnimationCmp { - constructor(@Inject(ANIMATION_MODULE_TYPE) public animationType: 'NoopAnimations'| - 'BrowserAnimations') {} - } + @Component({template: '<p>template text</p>'}) + class SharedAnimationCmp { + constructor(@Inject(ANIMATION_MODULE_TYPE) public animationType: 'NoopAnimations'| + 'BrowserAnimations') {} + } - describe('fakeAsync testing', () => { - it('should only require one flushMicrotasks call to kick off animation callbacks', - fakeAsync(() => { + describe('fakeAsync testing', () => { + it('should only require one flushMicrotasks call to kick off animation callbacks', + fakeAsync(() => { + @Component({ + selector: 'cmp', + template: ` + <div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div> + `, + animations: [trigger( + 'myAnimation', + [transition('* => on, * => off', [animate(1000, style({opacity: 1}))])])] + }) + class Cmp { + exp: any = false; + status: string = ''; + cb(status: string) { + this.status = status; + } + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'on'; + fixture.detectChanges(); + expect(cmp.status).toEqual(''); + + flushMicrotasks(); + expect(cmp.status).toEqual('start'); + + let player = MockAnimationDriver.log.pop()!; + player.finish(); + expect(cmp.status).toEqual('done'); + + cmp.status = ''; + cmp.exp = 'off'; + fixture.detectChanges(); + expect(cmp.status).toEqual(''); + + player = MockAnimationDriver.log.pop()!; + player.finish(); + expect(cmp.status).toEqual(''); + flushMicrotasks(); + expect(cmp.status).toEqual('done'); + })); + + it('should always run .start callbacks before .done callbacks even for noop animations', + fakeAsync(() => { + @Component({ + selector: 'cmp', + template: ` + <div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div> + `, + animations: [ + trigger( + 'myAnimation', + [ + transition('* => go', []), + ]), + ] + }) + class Cmp { + exp: any = false; + log: string[] = []; + cb(status: string) { + this.log.push(status); + } + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + expect(cmp.log).toEqual([]); + + flushMicrotasks(); + expect(cmp.log).toEqual(['start', 'done']); + })); + + it('should emit the correct totalTime value for a noop-animation', fakeAsync(() => { + @Component({ + selector: 'cmp', + template: ` + <div [@myAnimation]="exp" (@myAnimation.start)="cb($event)" (@myAnimation.done)="cb($event)"></div> + `, + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + animate('1s', style({opacity: 0})), + ]), + ]), + ] + }) + class Cmp { + exp: any = false; + log: AnimationEvent[] = []; + cb(event: AnimationEvent) { + this.log.push(event); + } + } + + TestBed.configureTestingModule({ + declarations: [Cmp], + providers: [ + {provide: AnimationDriver, useClass: NoopAnimationDriver}, + ], + }); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + expect(cmp.log).toEqual([]); + + flushMicrotasks(); + expect(cmp.log.length).toEqual(2); + const [start, end] = cmp.log; + expect(start.totalTime).toEqual(1000); + expect(end.totalTime).toEqual(1000); + })); + }); + + describe('component fixture integration', () => { + describe('whenRenderingDone', () => { + it('should wait until the animations are finished until continuing', fakeAsync(() => { @Component({ selector: 'cmp', template: ` - <div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div> - `, + <div [@myAnimation]="exp"></div> + `, animations: [trigger( - 'myAnimation', - [transition('* => on, * => off', [animate(1000, style({opacity: 1}))])])] + 'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])] }) class Cmp { exp: any = false; - status: string = ''; - cb(status: string) { this.status = status; } } TestBed.configureTestingModule({declarations: [Cmp]}); + const engine = TestBed.inject(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; - cmp.exp = 'on'; - fixture.detectChanges(); - expect(cmp.status).toEqual(''); - - flushMicrotasks(); - expect(cmp.status).toEqual('start'); - let player = MockAnimationDriver.log.pop() !; - player.finish(); - expect(cmp.status).toEqual('done'); + let isDone = false; + fixture.whenRenderingDone().then(() => isDone = true); + expect(isDone).toBe(false); - cmp.status = ''; - cmp.exp = 'off'; + cmp.exp = 'on'; fixture.detectChanges(); - expect(cmp.status).toEqual(''); + engine.flush(); + expect(isDone).toBe(false); + + const players = engine.players; + expect(players.length).toEqual(1); + players[0].finish(); + expect(isDone).toBe(false); - player = MockAnimationDriver.log.pop() !; - player.finish(); - expect(cmp.status).toEqual(''); flushMicrotasks(); - expect(cmp.status).toEqual('done'); + expect(isDone).toBe(true); })); - it('should always run .start callbacks before .done callbacks even for noop animations', - fakeAsync(() => { + it('should wait for a noop animation to finish before continuing', fakeAsync(() => { @Component({ selector: 'cmp', template: ` - <div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div> - `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => go', []), - ]), - ] + <div [@myAnimation]="exp"></div> + `, + animations: [trigger( + 'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])] }) class Cmp { exp: any = false; - log: string[] = []; - cb(status: string) { this.log.push(status); } } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], + declarations: [Cmp] + }); + + const engine = TestBed.inject(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; - cmp.exp = 'go'; + + let isDone = false; + fixture.whenRenderingDone().then(() => isDone = true); + expect(isDone).toBe(false); + + cmp.exp = 'off'; fixture.detectChanges(); - expect(cmp.log).toEqual([]); + engine.flush(); + expect(isDone).toBe(false); flushMicrotasks(); - expect(cmp.log).toEqual(['start', 'done']); + expect(isDone).toBe(true); })); - it('should emit the correct totalTime value for a noop-animation', fakeAsync(() => { + it('should wait for active animations to finish even if they have already started', + fakeAsync(() => { @Component({ selector: 'cmp', template: ` - <div [@myAnimation]="exp" (@myAnimation.start)="cb($event)" (@myAnimation.done)="cb($event)"></div> - `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - animate('1s', style({opacity: 0})), - ]), - ]), - ] + <div [@myAnimation]="exp"></div> + `, + animations: [trigger( + 'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])] }) class Cmp { exp: any = false; - log: AnimationEvent[] = []; - cb(event: AnimationEvent) { this.log.push(event); } } - TestBed.configureTestingModule({ - declarations: [Cmp], - providers: [ - {provide: AnimationDriver, useClass: NoopAnimationDriver}, - ], - }); - + TestBed.configureTestingModule({declarations: [Cmp]}); + const engine = TestBed.inject(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; - cmp.exp = 'go'; + cmp.exp = 'on'; fixture.detectChanges(); - expect(cmp.log).toEqual([]); - - flushMicrotasks(); - expect(cmp.log.length).toEqual(2); - const [start, end] = cmp.log; - expect(start.totalTime).toEqual(1000); - expect(end.totalTime).toEqual(1000); - })); - }); - - describe('component fixture integration', () => { - describe('whenRenderingDone', () => { - it('should wait until the animations are finished until continuing', fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` - <div [@myAnimation]="exp"></div> - `, - animations: [trigger( - 'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - exp: any = false; - } + engine.flush(); - TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - let isDone = false; - fixture.whenRenderingDone().then(() => isDone = true); - expect(isDone).toBe(false); - - cmp.exp = 'on'; - fixture.detectChanges(); - engine.flush(); - expect(isDone).toBe(false); - - const players = engine.players; - expect(players.length).toEqual(1); - players[0].finish(); - expect(isDone).toBe(false); - - flushMicrotasks(); - expect(isDone).toBe(true); - })); - - it('should wait for a noop animation to finish before continuing', fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` - <div [@myAnimation]="exp"></div> - `, - animations: [trigger( - 'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - exp: any = false; - } + const players = engine.players; + expect(players.length).toEqual(1); - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], - declarations: [Cmp] - }); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - let isDone = false; - fixture.whenRenderingDone().then(() => isDone = true); - expect(isDone).toBe(false); - - cmp.exp = 'off'; - fixture.detectChanges(); - engine.flush(); - expect(isDone).toBe(false); - - flushMicrotasks(); - expect(isDone).toBe(true); - })); - - it('should wait for active animations to finish even if they have already started', - fakeAsync(() => { - @Component({ - selector: 'cmp', - template: ` - <div [@myAnimation]="exp"></div> - `, - animations: [trigger( - 'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - exp: any = false; - } + let isDone = false; + fixture.whenRenderingDone().then(() => isDone = true); + flushMicrotasks(); + expect(isDone).toBe(false); - TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'on'; - fixture.detectChanges(); - engine.flush(); - - const players = engine.players; - expect(players.length).toEqual(1); - - let isDone = false; - fixture.whenRenderingDone().then(() => isDone = true); - flushMicrotasks(); - expect(isDone).toBe(false); - - players[0].finish(); - flushMicrotasks(); - expect(isDone).toBe(true); - })); - }); + players[0].finish(); + flushMicrotasks(); + expect(isDone).toBe(true); + })); }); + }); - describe('animation triggers', () => { - it('should trigger a state change animation from void => state', () => { - @Component({ - selector: 'if-cmp', - template: ` + describe('animation triggers', () => { + it('should trigger a state change animation from void => state', () => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngIf="exp" [@myAnimation]="exp"></div> `, - animations: [trigger( - 'myAnimation', - [transition( - 'void => *', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); + animations: [trigger( + 'myAnimation', + [transition( + 'void => *', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + } - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); + TestBed.configureTestingModule({declarations: [Cmp]}); - expect(getLog().length).toEqual(1); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} - ]); - }); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); + + expect(getLog().length).toEqual(1); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} + ]); + }); - // https://github.com/angular/angular/issues/32794 - it('should support nested animation triggers', () => { - const REUSABLE_ANIMATION = [trigger( - 'myAnimation', - [transition( - 'void => *', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])]; + // https://github.com/angular/angular/issues/32794 + it('should support nested animation triggers', () => { + const REUSABLE_ANIMATION = [trigger('myAnimation', [ + transition('void => *', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))]) + ])]; - @Component({ - selector: 'if-cmp', - template: ` + @Component({ + selector: 'if-cmp', + template: ` <div @myAnimation></div> `, - animations: [REUSABLE_ANIMATION], - }) - class Cmp { - } - - TestBed.configureTestingModule({declarations: [Cmp]}); + animations: [REUSABLE_ANIMATION], + }) + class Cmp { + } - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - fixture.detectChanges(); - engine.flush(); + TestBed.configureTestingModule({declarations: [Cmp]}); - expect(getLog().length).toEqual(1); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} - ]); - }); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + fixture.detectChanges(); + engine.flush(); - it('should allow a transition to use a function to determine what method to run', () => { - let valueToMatch = ''; - let capturedElement: any; - const transitionFn = (fromState: string, toState: string, element: any) => { - capturedElement = element; - return toState == valueToMatch; - }; + expect(getLog().length).toEqual(1); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} + ]); + }); - @Component({ - selector: 'if-cmp', - template: '<div #element [@myAnimation]="exp"></div>', - animations: [ - trigger('myAnimation', [transition( - transitionFn, - [style({opacity: 0}), animate(1234, style({opacity: 1}))])]), - ] - }) - class Cmp { - @ViewChild('element') - element: any; - exp: any = ''; - } + it('should allow a transition to use a function to determine what method to run', () => { + let valueToMatch = ''; + let capturedElement: any; + const transitionFn = (fromState: string, toState: string, element: any) => { + capturedElement = element; + return toState == valueToMatch; + }; - TestBed.configureTestingModule({declarations: [Cmp]}); + @Component({ + selector: 'if-cmp', + template: '<div #element [@myAnimation]="exp"></div>', + animations: [ + trigger('myAnimation', [transition( + transitionFn, + [style({opacity: 0}), animate(1234, style({opacity: 1}))])]), + ] + }) + class Cmp { + @ViewChild('element') element: any; + exp: any = ''; + } - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - valueToMatch = cmp.exp = 'something'; - fixture.detectChanges(); - const element = cmp.element.nativeElement; + TestBed.configureTestingModule({declarations: [Cmp]}); - let players = getLog(); - expect(players.length).toEqual(1); - let [p1] = players; - expect(p1.totalTime).toEqual(1234); - expect(capturedElement).toEqual(element); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + valueToMatch = cmp.exp = 'something'; + fixture.detectChanges(); + const element = cmp.element.nativeElement; + + let players = getLog(); + expect(players.length).toEqual(1); + let [p1] = players; + expect(p1.totalTime).toEqual(1234); + expect(capturedElement).toEqual(element); + resetLog(); - valueToMatch = 'something-else'; - cmp.exp = 'this-wont-match'; - fixture.detectChanges(); + valueToMatch = 'something-else'; + cmp.exp = 'this-wont-match'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(0); - }); + players = getLog(); + expect(players.length).toEqual(0); + }); - it('should allow a transition to use a function to determine what method to run and expose any parameter values', - () => { - const transitionFn = - (fromState: string, toState: string, element?: any, - params?: {[key: string]: any}) => { return params !['doMatch'] == true; }; + it('should allow a transition to use a function to determine what method to run and expose any parameter values', + () => { + const transitionFn = + (fromState: string, toState: string, element?: any, params?: {[key: string]: any}) => { + return params!['doMatch'] == true; + }; - @Component({ - selector: 'if-cmp', - template: '<div [@myAnimation]="{value:exp, params: {doMatch:doMatch}}"></div>', - animations: [ - trigger( - 'myAnimation', - [transition( - transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]), - ] - }) - class Cmp { - doMatch = false; - exp: any = ''; - } + @Component({ + selector: 'if-cmp', + template: '<div [@myAnimation]="{value:exp, params: {doMatch:doMatch}}"></div>', + animations: [ + trigger( + 'myAnimation', + [transition( + transitionFn, [style({opacity: 0}), animate(3333, style({opacity: 1}))])]), + ] + }) + class Cmp { + doMatch = false; + exp: any = ''; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.doMatch = true; - fixture.detectChanges(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.doMatch = true; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(1); - let [p1] = players; - expect(p1.totalTime).toEqual(3333); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(1); + let [p1] = players; + expect(p1.totalTime).toEqual(3333); + resetLog(); - cmp.doMatch = false; - cmp.exp = 'this-wont-match'; - fixture.detectChanges(); + cmp.doMatch = false; + cmp.exp = 'this-wont-match'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(0); - }); + players = getLog(); + expect(players.length).toEqual(0); + }); - it('should allow a state value to be `0`', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should allow a state value to be `0`', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - '0 => 1', [style({height: '0px'}), animate(1234, style({height: '100px'}))]), - transition( - '* => 1', [style({width: '0px'}), animate(4567, style({width: '100px'}))]) - ])] - }) - class Cmp { - exp: any = false; - } + animations: [trigger( + 'myAnimation', + [ + transition( + '0 => 1', [style({height: '0px'}), animate(1234, style({height: '100px'}))]), + transition('* => 1', [style({width: '0px'}), animate(4567, style({width: '100px'}))]) + ])] + }) + class Cmp { + exp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 0; - fixture.detectChanges(); - engine.flush(); - resetLog(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 0; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp = 1; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 1; + fixture.detectChanges(); + engine.flush(); - expect(getLog().length).toEqual(1); - const player = getLog().pop() !; - expect(player.duration).toEqual(1234); - }); + expect(getLog().length).toEqual(1); + const player = getLog().pop()!; + expect(player.duration).toEqual(1234); + }); - it('should always cancel the previous transition if a follow-up transition is not matched', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should always cancel the previous transition if a follow-up transition is not matched', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp" (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div> `, - animations: [trigger( - 'myAnimation', - [transition( - 'a => b', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any; - startEvent: any; - doneEvent: any; - - callback(event: any) { - if (event.phaseName == 'done') { - this.doneEvent = event; - } else { - this.startEvent = event; - } + animations: [trigger( + 'myAnimation', + [transition( + 'a => b', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any; + startEvent: any; + doneEvent: any; + + callback(event: any) { + if (event.phaseName == 'done') { + this.doneEvent = event; + } else { + this.startEvent = event; } } + } - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'a'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - expect(engine.players.length).toEqual(0); + TestBed.configureTestingModule({declarations: [Cmp]}); - flushMicrotasks(); - expect(cmp.startEvent.toState).toEqual('a'); - expect(cmp.startEvent.totalTime).toEqual(0); - expect(cmp.startEvent.toState).toEqual('a'); - expect(cmp.startEvent.totalTime).toEqual(0); - resetLog(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'a'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); + expect(engine.players.length).toEqual(0); + + flushMicrotasks(); + expect(cmp.startEvent.toState).toEqual('a'); + expect(cmp.startEvent.totalTime).toEqual(0); + expect(cmp.startEvent.toState).toEqual('a'); + expect(cmp.startEvent.totalTime).toEqual(0); + resetLog(); + + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(1); - expect(engine.players.length).toEqual(1); + const players = getLog(); + expect(players.length).toEqual(1); + expect(engine.players.length).toEqual(1); - flushMicrotasks(); - expect(cmp.startEvent.toState).toEqual('b'); - expect(cmp.startEvent.totalTime).toEqual(500); - expect(cmp.startEvent.toState).toEqual('b'); - expect(cmp.startEvent.totalTime).toEqual(500); - resetLog(); + flushMicrotasks(); + expect(cmp.startEvent.toState).toEqual('b'); + expect(cmp.startEvent.totalTime).toEqual(500); + expect(cmp.startEvent.toState).toEqual('b'); + expect(cmp.startEvent.totalTime).toEqual(500); + resetLog(); - let completed = false; - players[0].onDone(() => completed = true); + let completed = false; + players[0].onDone(() => completed = true); - cmp.exp = 'c'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'c'; + fixture.detectChanges(); + engine.flush(); - expect(engine.players.length).toEqual(0); - expect(getLog().length).toEqual(0); + expect(engine.players.length).toEqual(0); + expect(getLog().length).toEqual(0); - flushMicrotasks(); - expect(cmp.startEvent.toState).toEqual('c'); - expect(cmp.startEvent.totalTime).toEqual(0); - expect(cmp.startEvent.toState).toEqual('c'); - expect(cmp.startEvent.totalTime).toEqual(0); + flushMicrotasks(); + expect(cmp.startEvent.toState).toEqual('c'); + expect(cmp.startEvent.totalTime).toEqual(0); + expect(cmp.startEvent.toState).toEqual('c'); + expect(cmp.startEvent.totalTime).toEqual(0); - expect(completed).toBe(true); - })); + expect(completed).toBe(true); + })); - it('should always fire inner callbacks even if no animation is fired when a view is inserted', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should always fire inner callbacks even if no animation is fired when a view is inserted', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngIf="exp"> <div @myAnimation (@myAnimation.start)="track($event)" (@myAnimation.done)="track($event)"></div> </div> `, - animations: [ - trigger('myAnimation', []), - ] - }) - class Cmp { - exp: any = false; - log: string[] = []; - track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } + animations: [ + trigger('myAnimation', []), + ] + }) + class Cmp { + exp: any = false; + log: string[] = []; + track(event: any) { + this.log.push(`${event.triggerName}-${event.phaseName}`); } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - flushMicrotasks(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual([]); + expect(cmp.log).toEqual([]); - cmp.exp = true; - fixture.detectChanges(); - flushMicrotasks(); + cmp.exp = true; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']); - })); + expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']); + })); - it('should only turn a view removal as into `void` state transition', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should only turn a view removal as into `void` state transition', () => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngIf="exp1" [@myAnimation]="exp2"></div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - 'void <=> *', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), - transition( - '* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]), - ])] - }) - class Cmp { - exp1: any = false; - exp2: any = false; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + animations: [trigger( + 'myAnimation', + [ + transition( + 'void <=> *', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), + transition( + '* => *', [style({height: '0px'}), animate(1000, style({height: '100px'}))]), + ])] + }) + class Cmp { + exp1: any = false; + exp2: any = false; + } - function resetState() { - cmp.exp2 = 'something'; - fixture.detectChanges(); - engine.flush(); - resetLog(); - } + TestBed.configureTestingModule({declarations: [Cmp]}); - cmp.exp1 = true; - cmp.exp2 = null; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + function resetState() { + cmp.exp2 = 'something'; fixture.detectChanges(); engine.flush(); + resetLog(); + } - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: 1, width: '100px'} - ]); + cmp.exp1 = true; + cmp.exp2 = null; - resetState(); - cmp.exp2 = false; + fixture.detectChanges(); + engine.flush(); - fixture.detectChanges(); - engine.flush(); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + resetState(); + cmp.exp2 = false; - resetState(); - cmp.exp2 = 0; + fixture.detectChanges(); + engine.flush(); - fixture.detectChanges(); - engine.flush(); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + resetState(); + cmp.exp2 = 0; - resetState(); - cmp.exp2 = ''; + fixture.detectChanges(); + engine.flush(); - fixture.detectChanges(); - engine.flush(); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + resetState(); + cmp.exp2 = ''; - resetState(); - cmp.exp2 = undefined; + fixture.detectChanges(); + engine.flush(); - fixture.detectChanges(); - engine.flush(); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, height: '0px'}, {offset: 1, height: '100px'} - ]); + resetState(); + cmp.exp2 = undefined; - resetState(); - cmp.exp1 = false; - cmp.exp2 = 'abc'; + fixture.detectChanges(); + engine.flush(); - fixture.detectChanges(); - engine.flush(); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, height: '0px'}, {offset: 1, height: '100px'} + ]); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, width: '0px'}, {offset: 1, width: '100px'} - ]); - }); + resetState(); + cmp.exp1 = false; + cmp.exp2 = 'abc'; - it('should stringify boolean triggers to `1` and `0`', () => { - @Component({ - selector: 'if-cmp', - template: ` + fixture.detectChanges(); + engine.flush(); + + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, width: '0px'}, {offset: 1, width: '100px'} + ]); + }); + + it('should stringify boolean triggers to `1` and `0`', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [trigger( - 'myAnimation', - [ - transition('void => 1', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), - transition('1 => 0', [style({opacity: 1}), animate(1000, style({opacity: 0}))]) - ])] - }) - class Cmp { - exp: any = false; - } + animations: [trigger( + 'myAnimation', + [ + transition('void => 1', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + transition('1 => 0', [style({opacity: 1}), animate(1000, style({opacity: 0}))]) + ])] + }) + class Cmp { + exp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} - ]); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, opacity: '0'}, {offset: 1, opacity: '1'} + ]); - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp = false; + fixture.detectChanges(); + engine.flush(); - expect(getLog().pop() !.keyframes).toEqual([ - {offset: 0, opacity: '1'}, {offset: 1, opacity: '0'} - ]); - }); + expect(getLog().pop()!.keyframes).toEqual([ + {offset: 0, opacity: '1'}, {offset: 1, opacity: '0'} + ]); + }); - it('should understand boolean values as `true` and `false` for transition animations', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should understand boolean values as `true` and `false` for transition animations', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - 'true => false', - [ - style({opacity: 0}), - animate(1234, style({opacity: 1})), - ]), - transition( - 'false => true', - [ - style({opacity: 1}), - animate(4567, style({opacity: 0})), - ]) - ]), - ] - }) - class Cmp { - exp: any = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + 'true => false', + [ + style({opacity: 0}), + animate(1234, style({opacity: 1})), + ]), + transition( + 'false => true', + [ + style({opacity: 1}), + animate(4567, style({opacity: 0})), + ]) + ]), + ] + }) + class Cmp { + exp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); + cmp.exp = true; + fixture.detectChanges(); - cmp.exp = false; - fixture.detectChanges(); + cmp.exp = false; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(1); - let [player] = players; + let players = getLog(); + expect(players.length).toEqual(1); + let [player] = players; - expect(player.duration).toEqual(1234); - }); + expect(player.duration).toEqual(1234); + }); - it('should understand boolean values as `true` and `false` for transition animations and apply the corresponding state() value', - () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should understand boolean values as `true` and `false` for transition animations and apply the corresponding state() value', + () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('true', style({color: 'red'})), - state('false', style({color: 'blue'})), - transition( - 'true <=> false', - [ - animate(1000, style({color: 'gold'})), - animate(1000), - ]), - ]), - ] + animations: [ + trigger( + 'myAnimation', + [ + state('true', style({color: 'red'})), + state('false', style({color: 'blue'})), + transition( + 'true <=> false', + [ + animate(1000, style({color: 'gold'})), + animate(1000), + ]), + ]), + ] + }) + class Cmp { + exp: any = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = false; + fixture.detectChanges(); + + cmp.exp = true; + fixture.detectChanges(); + + let players = getLog(); + expect(players.length).toEqual(1); + let [player] = players; + + expect(player.keyframes).toEqual([ + {color: 'blue', offset: 0}, + {color: 'gold', offset: 0.5}, + {color: 'red', offset: 1}, + ]); + }); + + it('should not throw an error if a trigger with the same name exists in separate components', + () => { + @Component({selector: 'cmp1', template: '...', animations: [trigger('trig', [])]}) + class Cmp1 { + } + + @Component({selector: 'cmp2', template: '...', animations: [trigger('trig', [])]}) + class Cmp2 { + } + + TestBed.configureTestingModule({declarations: [Cmp1, Cmp2]}); + const cmp1 = TestBed.createComponent(Cmp1); + const cmp2 = TestBed.createComponent(Cmp2); + }); + + describe('host bindings', () => { + it('should trigger a state change animation from state => state on the component host element', + fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: '...', + animations: [trigger( + 'myAnimation', + [transition( + 'a => b', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], }) class Cmp { - exp: any = false; + @HostBinding('@myAnimation') exp = 'a'; } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -813,435 +874,375 @@ const DEFAULT_COMPONENT_ID = '1'; const engine = TestBed.inject(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); - cmp.exp = false; + cmp.exp = 'b'; fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(1); + + const data = getLog().pop()!; + expect(data.element).toEqual(fixture.elementRef.nativeElement); + expect(data.keyframes).toEqual([{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}]); + })); + + it('should trigger a leave animation when the inner components host binding updates', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + template: ` + <child-cmp *ngIf="exp"></child-cmp> + ` + }) + class ParentCmp { + public exp = true; + } + + @Component({ + selector: 'child-cmp', + template: '...', + animations: [trigger( + 'host', + [transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])] + }) + class ChildCmp { + @HostBinding('@host') public hostAnimation = true; + } - cmp.exp = true; + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); - let players = getLog(); - expect(players.length).toEqual(1); - let [player] = players; + cmp.exp = false; + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.children.length).toBe(1); + engine.flush(); + expect(getLog().length).toEqual(1); + + const [player] = getLog(); expect(player.keyframes).toEqual([ - {color: 'blue', offset: 0}, - {color: 'gold', offset: 0.5}, - {color: 'red', offset: 1}, + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, ]); - }); - it('should not throw an error if a trigger with the same name exists in separate components', - () => { - @Component({selector: 'cmp1', template: '...', animations: [trigger('trig', [])]}) - class Cmp1 { + player.finish(); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); + })); + + it('should wait for child animations before removing parent', fakeAsync(() => { + @Component({ + template: '<child-cmp *ngIf="exp" @parentTrigger></child-cmp>', + animations: [trigger( + 'parentTrigger', [transition(':leave', [group([query('@*', animateChild())])])])] + }) + class ParentCmp { + exp = true; } - @Component({selector: 'cmp2', template: '...', animations: [trigger('trig', [])]}) - class Cmp2 { + @Component({ + selector: 'child-cmp', + template: '<p @childTrigger>Hello there</p>', + animations: [trigger( + 'childTrigger', + [transition( + ':leave', [style({opacity: 1}), animate('200ms', style({opacity: 0}))])])] + }) + class ChildCmp { } - TestBed.configureTestingModule({declarations: [Cmp1, Cmp2]}); - const cmp1 = TestBed.createComponent(Cmp1); - const cmp2 = TestBed.createComponent(Cmp2); - }); + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); - describe('host bindings', () => { - it('should trigger a state change animation from state => state on the component host element', - fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: '...', - animations: [trigger( - 'myAnimation', - [transition( - 'a => b', - [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - @HostBinding('@myAnimation') - exp = 'a'; - } + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toBe(0); - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(1); - - const data = getLog().pop() !; - expect(data.element).toEqual(fixture.elementRef.nativeElement); - expect(data.keyframes).toEqual([{offset: 0, opacity: '0'}, {offset: 1, opacity: '1'}]); - })); - - it('should trigger a leave animation when the inner components host binding updates', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - template: ` - <child-cmp *ngIf="exp"></child-cmp> - ` - }) - class ParentCmp { - public exp = true; - } + fixture.componentInstance.exp = false; + fixture.detectChanges(); + expect(fixture.nativeElement.children.length).toBe(1); - @Component({ - selector: 'child-cmp', - template: '...', - animations: [trigger( - 'host', - [transition( - ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])] - }) - class ChildCmp { - @HostBinding('@host') public hostAnimation = true; - } + engine.flush(); + expect(getLog().length).toBe(1); - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - - cmp.exp = false; - fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.children.length).toBe(1); - - engine.flush(); - expect(getLog().length).toEqual(1); - - const [player] = getLog(); - expect(player.keyframes).toEqual([ - {opacity: '1', offset: 0}, - {opacity: '0', offset: 1}, - ]); - - player.finish(); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - })); - - it('should wait for child animations before removing parent', fakeAsync(() => { - @Component({ - template: '<child-cmp *ngIf="exp" @parentTrigger></child-cmp>', - animations: [trigger( - 'parentTrigger', [transition(':leave', [group([query('@*', animateChild())])])])] - }) - class ParentCmp { - exp = true; - } + const player = getLog()[0]; + expect(player.keyframes).toEqual([ + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, + ]); - @Component({ - selector: 'child-cmp', - template: '<p @childTrigger>Hello there</p>', - animations: [trigger( - 'childTrigger', - [transition( - ':leave', [style({opacity: 1}), animate('200ms', style({opacity: 0}))])])] - }) - class ChildCmp { - } + player.finish(); + flushMicrotasks(); + expect(fixture.nativeElement.children.length).toBe(0); + })); - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toBe(0); - - fixture.componentInstance.exp = false; - fixture.detectChanges(); - expect(fixture.nativeElement.children.length).toBe(1); - - engine.flush(); - expect(getLog().length).toBe(1); - - const player = getLog()[0]; - expect(player.keyframes).toEqual([ - {opacity: '1', offset: 0}, - {opacity: '0', offset: 1}, - ]); - - player.finish(); - flushMicrotasks(); - expect(fixture.nativeElement.children.length).toBe(0); - })); - - // animationRenderer => nonAnimationRenderer - it('should trigger a leave animation when the outer components element binding updates on the host component element', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - animations: [trigger( - 'host', - [transition( - ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])], - template: ` + // animationRenderer => nonAnimationRenderer + it('should trigger a leave animation when the outer components element binding updates on the host component element', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + animations: [trigger( + 'host', + [transition( + ':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])], + template: ` <child-cmp *ngIf="exp" @host></child-cmp> ` - }) - class ParentCmp { - public exp = true; - } + }) + class ParentCmp { + public exp = true; + } - @Component({ - selector: 'child-cmp', - template: '...', - }) - class ChildCmp { - } + @Component({ + selector: 'child-cmp', + template: '...', + }) + class ChildCmp { + } - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - - cmp.exp = false; - fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.children.length).toBe(1); - - engine.flush(); - expect(getLog().length).toEqual(1); - - const [player] = getLog(); - expect(player.keyframes).toEqual([ - {opacity: '1', offset: 0}, - {opacity: '0', offset: 1}, - ]); - - player.finish(); - flushMicrotasks(); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - })); - - it('should trigger a leave animation when both the inner and outer components trigger on the same element', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - animations: [trigger( - 'host', - [transition( - ':leave', - [style({height: '100px'}), animate(1000, style({height: '0px'}))])])], - template: ` + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); + + cmp.exp = false; + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.children.length).toBe(1); + + engine.flush(); + expect(getLog().length).toEqual(1); + + const [player] = getLog(); + expect(player.keyframes).toEqual([ + {opacity: '1', offset: 0}, + {opacity: '0', offset: 1}, + ]); + + player.finish(); + flushMicrotasks(); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); + })); + + it('should trigger a leave animation when both the inner and outer components trigger on the same element', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + animations: [trigger( + 'host', [transition( + ':leave', + [style({height: '100px'}), animate(1000, style({height: '0px'}))])])], + template: ` <child-cmp *ngIf="exp" @host></child-cmp> ` - }) - class ParentCmp { - public exp = true; - } + }) + class ParentCmp { + public exp = true; + } - @Component({ - selector: 'child-cmp', - template: '...', - animations: [trigger( - 'host', [transition( - ':leave', - [style({width: '100px'}), animate(1000, style({width: '0px'}))])])] - }) - class ChildCmp { - @HostBinding('@host') public hostAnimation = true; - } + @Component({ + selector: 'child-cmp', + template: '...', + animations: [trigger( + 'host', + [transition( + ':leave', [style({width: '100px'}), animate(1000, style({width: '0px'}))])])] + }) + class ChildCmp { + @HostBinding('@host') public hostAnimation = true; + } - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - - cmp.exp = false; - fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.children.length).toBe(1); - - engine.flush(); - expect(getLog().length).toEqual(2); - - const [p1, p2] = getLog(); - expect(p1.keyframes).toEqual([ - {width: '100px', offset: 0}, - {width: '0px', offset: 1}, - ]); - - expect(p2.keyframes).toEqual([ - {height: '100px', offset: 0}, - {height: '0px', offset: 1}, - ]); - - p1.finish(); - p2.finish(); - flushMicrotasks(); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - })); - - it('should not throw when the host element is removed and no animation triggers', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - template: ` - <child-cmp *ngIf="exp"></child-cmp> - ` - }) - class ParentCmp { - public exp = true; - } + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - @Component({ - selector: 'child-cmp', - template: '...', - animations: [trigger('host', [transition('a => b', [style({height: '100px'})])])], - }) - class ChildCmp { - @HostBinding('@host') public hostAnimation = 'a'; - } + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - expect(fixture.debugElement.nativeElement.children.length).toBe(1); - - engine.flush(); - expect(getLog().length).toEqual(0); - - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); - flushMicrotasks(); - expect(getLog().length).toEqual(0); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - - flushMicrotasks(); - expect(fixture.debugElement.nativeElement.children.length).toBe(0); - })); - - it('should properly evaluate pre/auto-style values when components are inserted/removed which contain host animations', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - template: ` - <child-cmp *ngFor="let item of items"></child-cmp> - ` - }) - class ParentCmp { - items: any[] = [1, 2, 3, 4, 5]; - } + cmp.exp = false; + fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.children.length).toBe(1); - @Component({ - selector: 'child-cmp', - template: '... child ...', - animations: - [trigger('host', [transition(':leave', [animate(1000, style({opacity: 0}))])])] - }) - class ChildCmp { - @HostBinding('@host') public hostAnimation = 'a'; - } + engine.flush(); + expect(getLog().length).toEqual(2); - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + const [p1, p2] = getLog(); + expect(p1.keyframes).toEqual([ + {width: '100px', offset: 0}, + {width: '0px', offset: 1}, + ]); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - const element = fixture.nativeElement; - fixture.detectChanges(); + expect(p2.keyframes).toEqual([ + {height: '100px', offset: 0}, + {height: '0px', offset: 1}, + ]); - cmp.items = [0, 2, 4, 6]; // 1,3,5 get removed - fixture.detectChanges(); + p1.finish(); + p2.finish(); + flushMicrotasks(); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); + })); - const items = element.querySelectorAll('child-cmp'); - for (let i = 0; i < items.length; i++) { - const item = items[i]; - expect(item.style['display']).toBeFalsy(); - } - })); - }); + it('should not throw when the host element is removed and no animation triggers', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + template: ` + <child-cmp *ngIf="exp"></child-cmp> + ` + }) + class ParentCmp { + public exp = true; + } - it('should cancel and merge in mid-animation styles into the follow-up animation, but only for animation keyframes that start right away', - () => { @Component({ - selector: 'ani-cmp', - template: ` - <div [@myAnimation]="exp"></div> - `, - animations: [trigger( - 'myAnimation', - [ - transition( - 'a => b', - [ - style({'opacity': '0'}), - animate(500, style({'opacity': '1'})), - ]), - transition( - 'b => c', - [ - group([ - animate(500, style({'width': '100px'})), - animate(500, style({'height': '100px'})), - ]), - animate(500, keyframes([ - style({'opacity': '0'}), - style({'opacity': '1'}) - ])) - ]), - ])], - }) - class Cmp { - exp: any = false; + selector: 'child-cmp', + template: '...', + animations: [trigger('host', [transition('a => b', [style({height: '100px'})])])], + }) + class ChildCmp { + @HostBinding('@host') public hostAnimation = 'a'; } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); + const fixture = TestBed.createComponent(ParentCmp); const cmp = fixture.componentInstance; - - cmp.exp = 'a'; fixture.detectChanges(); + expect(fixture.debugElement.nativeElement.children.length).toBe(1); + engine.flush(); expect(getLog().length).toEqual(0); - resetLog(); - cmp.exp = 'b'; + cmp.exp = false; fixture.detectChanges(); engine.flush(); - expect(getLog().length).toEqual(1); - resetLog(); + flushMicrotasks(); + expect(getLog().length).toEqual(0); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); - cmp.exp = 'c'; - fixture.detectChanges(); - engine.flush(); + flushMicrotasks(); + expect(fixture.debugElement.nativeElement.children.length).toBe(0); + })); - const players = getLog(); - expect(players.length).toEqual(3); - const [p1, p2, p3] = players; - expect(p1.previousStyles).toEqual({opacity: AUTO_STYLE}); - expect(p2.previousStyles).toEqual({opacity: AUTO_STYLE}); - expect(p3.previousStyles).toEqual({}); - }); + it('should properly evaluate pre/auto-style values when components are inserted/removed which contain host animations', + fakeAsync(() => { + @Component({ + selector: 'parent-cmp', + template: ` + <child-cmp *ngFor="let item of items"></child-cmp> + ` + }) + class ParentCmp { + items: any[] = [1, 2, 3, 4, 5]; + } - it('should provide the styling of previous players that are grouped', () => { - @Component({ + @Component({ + selector: 'child-cmp', + template: '... child ...', + animations: + [trigger('host', [transition(':leave', [animate(1000, style({opacity: 0}))])])] + }) + class ChildCmp { + @HostBinding('@host') public hostAnimation = 'a'; + } + + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + const element = fixture.nativeElement; + fixture.detectChanges(); + + cmp.items = [0, 2, 4, 6]; // 1,3,5 get removed + fixture.detectChanges(); + + const items = element.querySelectorAll('child-cmp'); + for (let i = 0; i < items.length; i++) { + const item = items[i]; + expect(item.style['display']).toBeFalsy(); + } + })); + }); + + it('should cancel and merge in mid-animation styles into the follow-up animation, but only for animation keyframes that start right away', + () => { + @Component({ + selector: 'ani-cmp', + template: ` + <div [@myAnimation]="exp"></div> + `, + animations: [trigger( + 'myAnimation', + [ + transition( + 'a => b', + [ + style({'opacity': '0'}), + animate(500, style({'opacity': '1'})), + ]), + transition( + 'b => c', + [ + group([ + animate(500, style({'width': '100px'})), + animate(500, style({'height': '100px'})), + ]), + animate(500, keyframes([style({'opacity': '0'}), style({'opacity': '1'})])) + ]), + ])], + }) + class Cmp { + exp: any = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'a'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); + resetLog(); + + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(1); + resetLog(); + + cmp.exp = 'c'; + fixture.detectChanges(); + engine.flush(); + + const players = getLog(); + expect(players.length).toEqual(3); + const [p1, p2, p3] = players; + expect(p1.previousStyles).toEqual({opacity: AUTO_STYLE}); + expect(p2.previousStyles).toEqual({opacity: AUTO_STYLE}); + expect(p3.previousStyles).toEqual({}); + }); + + it('should provide the styling of previous players that are grouped', () => { + @Component({ selector: 'ani-cmp', template: ` <div [@myAnimation]="exp"></div> @@ -1270,1637 +1271,1641 @@ const DEFAULT_COMPONENT_ID = '1'; ])], }) class Cmp { - exp: any = false; - } + exp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - cmp.exp = '1'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - resetLog(); + cmp.exp = '1'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); + resetLog(); - cmp.exp = '2'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(3); - resetLog(); + cmp.exp = '2'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(3); + resetLog(); - cmp.exp = '3'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = '3'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(1); - const player = players[0] as MockAnimationPlayer; - const pp = player.previousPlayers as MockAnimationPlayer[]; + const players = getLog(); + expect(players.length).toEqual(1); + const player = players[0] as MockAnimationPlayer; + const pp = player.previousPlayers as MockAnimationPlayer[]; - expect(pp.length).toEqual(3); - expect(pp[0].currentSnapshot).toEqual({width: AUTO_STYLE}); - expect(pp[1].currentSnapshot).toEqual({height: AUTO_STYLE}); - expect(pp[2].currentSnapshot).toEqual({opacity: AUTO_STYLE}); - }); + expect(pp.length).toEqual(3); + expect(pp[0].currentSnapshot).toEqual({width: AUTO_STYLE}); + expect(pp[1].currentSnapshot).toEqual({height: AUTO_STYLE}); + expect(pp[2].currentSnapshot).toEqual({opacity: AUTO_STYLE}); + }); - it('should provide the styling of previous players that are grouped and queried and make sure match the players with the correct elements', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should provide the styling of previous players that are grouped and queried and make sure match the players with the correct elements', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div class="container" [@myAnimation]="exp"> <div class="inner"></div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '1 => 2', - [ - style({fontSize: '10px'}), - query( - '.inner', - [ - style({fontSize: '20px'}), - ]), - animate('1s', style({fontSize: '100px'})), - query( - '.inner', - [ - animate('1s', style({fontSize: '200px'})), - ]), - ]), - transition( - '2 => 3', - [ - animate('1s', style({fontSize: '0px'})), - query( - '.inner', - [ - animate('1s', style({fontSize: '0px'})), - ]), - ]), - ]), - ], - }) - class Cmp { - exp: any = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '1 => 2', + [ + style({fontSize: '10px'}), + query( + '.inner', + [ + style({fontSize: '20px'}), + ]), + animate('1s', style({fontSize: '100px'})), + query( + '.inner', + [ + animate('1s', style({fontSize: '200px'})), + ]), + ]), + transition( + '2 => 3', + [ + animate('1s', style({fontSize: '0px'})), + query( + '.inner', + [ + animate('1s', style({fontSize: '0px'})), + ]), + ]), + ]), + ], + }) + class Cmp { + exp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - fixture.detectChanges(); + fixture.detectChanges(); - cmp.exp = '1'; - fixture.detectChanges(); - resetLog(); + cmp.exp = '1'; + fixture.detectChanges(); + resetLog(); - cmp.exp = '2'; - fixture.detectChanges(); - resetLog(); + cmp.exp = '2'; + fixture.detectChanges(); + resetLog(); - cmp.exp = '3'; - fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); - const [p1, p2] = players as MockAnimationPlayer[]; - - const pp1 = p1.previousPlayers as MockAnimationPlayer[]; - expect(p1.element.classList.contains('container')).toBeTruthy(); - for (let i = 0; i < pp1.length; i++) { - expect(pp1[i].element).toEqual(p1.element); - } + cmp.exp = '3'; + fixture.detectChanges(); + const players = getLog(); + expect(players.length).toEqual(2); + const [p1, p2] = players as MockAnimationPlayer[]; + + const pp1 = p1.previousPlayers as MockAnimationPlayer[]; + expect(p1.element.classList.contains('container')).toBeTruthy(); + for (let i = 0; i < pp1.length; i++) { + expect(pp1[i].element).toEqual(p1.element); + } - const pp2 = p2.previousPlayers as MockAnimationPlayer[]; - expect(p2.element.classList.contains('inner')).toBeTruthy(); - for (let i = 0; i < pp2.length; i++) { - expect(pp2[i].element).toEqual(p2.element); - } - }); + const pp2 = p2.previousPlayers as MockAnimationPlayer[]; + expect(p2.element.classList.contains('inner')).toBeTruthy(); + for (let i = 0; i < pp2.length; i++) { + expect(pp2[i].element).toEqual(p2.element); + } + }); - it('should properly balance styles between states even if there are no destination state styles', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should properly balance styles between states even if there are no destination state styles', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @myAnimation *ngIf="exp"></div> `, - animations: [trigger( - 'myAnimation', - [ - state('void', style({opacity: 0, width: '0px', height: '0px'})), - transition(':enter', animate(1000)) - ])] - }) - class Cmp { - exp: boolean = false; - } + animations: [trigger( + 'myAnimation', + [ + state('void', style({opacity: 0, width: '0px', height: '0px'})), + transition(':enter', animate(1000)) + ])] + }) + class Cmp { + exp: boolean = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = true; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - const [p1] = getLog(); - expect(p1.keyframes).toEqual([ - {opacity: '0', width: '0px', height: '0px', offset: 0}, - {opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE, offset: 1} - ]); - }); + const [p1] = getLog(); + expect(p1.keyframes).toEqual([ + {opacity: '0', width: '0px', height: '0px', offset: 0}, + {opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE, offset: 1} + ]); + }); - it('should not apply the destination styles if the final animate step already contains styles', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should not apply the destination styles if the final animate step already contains styles', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @myAnimation *ngIf="exp"></div> `, - animations: [trigger( - 'myAnimation', - [ - state('void', style({color: 'red'})), state('*', style({color: 'blue'})), - transition( - ':enter', - [style({fontSize: '0px '}), animate(1000, style({fontSize: '100px'}))]) - ])] - }) - class Cmp { - exp: boolean = false; - } + animations: [trigger( + 'myAnimation', + [ + state('void', style({color: 'red'})), state('*', style({color: 'blue'})), + transition( + ':enter', + [style({fontSize: '0px '}), animate(1000, style({fontSize: '100px'}))]) + ])] + }) + class Cmp { + exp: boolean = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = true; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; - fixture.detectChanges(); - engine.flush(); + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(1); + const players = getLog(); + expect(players.length).toEqual(1); - // notice how the final color is NOT blue - expect(players[0].keyframes).toEqual([ - {fontSize: '0px', color: 'red', offset: 0}, - {fontSize: '100px', color: 'red', offset: 1} - ]); - }); + // notice how the final color is NOT blue + expect(players[0].keyframes).toEqual([ + {fontSize: '0px', color: 'red', offset: 0}, {fontSize: '100px', color: 'red', offset: 1} + ]); + }); - it('should invoke an animation trigger that is state-less', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should invoke an animation trigger that is state-less', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div *ngFor="let item of items" @myAnimation></div> `, - animations: [trigger( - 'myAnimation', - [transition(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - items: number[] = []; - } + animations: [trigger( + 'myAnimation', + [transition(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] + }) + class Cmp { + items: number[] = []; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.items = [1, 2, 3, 4, 5]; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(5); + cmp.items = [1, 2, 3, 4, 5]; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(5); - for (let i = 0; i < 5; i++) { - const item = getLog()[i]; - expect(item.duration).toEqual(1000); - expect(item.keyframes).toEqual([{opacity: '0', offset: 0}, {opacity: '1', offset: 1}]); - } - }); + for (let i = 0; i < 5; i++) { + const item = getLog()[i]; + expect(item.duration).toEqual(1000); + expect(item.keyframes).toEqual([{opacity: '0', offset: 0}, {opacity: '1', offset: 1}]); + } + }); - it('should retain styles on the element once the animation is complete', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should retain styles on the element once the animation is complete', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #green @green></div> `, - animations: [trigger( - 'green', - [ - state('*', style({backgroundColor: 'green'})), transition('* => *', animate(500)) - ])] - }) - class Cmp { - @ViewChild('green') public element: any; - } + animations: [trigger( + 'green', + [state('*', style({backgroundColor: 'green'})), transition('* => *', animate(500))])] + }) + class Cmp { + @ViewChild('green') public element: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - engine.flush(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + engine.flush(); - const player = engine.players.pop() !; - player.finish(); + const player = engine.players.pop()!; + player.finish(); - expect(hasStyle(cmp.element.nativeElement, 'background-color', 'green')).toBeTruthy(); - }); + expect(hasStyle(cmp.element.nativeElement, 'background-color', 'green')).toBeTruthy(); + }); - it('should retain state styles when the underlying DOM structure changes even if there are no insert/remove animations', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should retain state styles when the underlying DOM structure changes even if there are no insert/remove animations', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div class="item" *ngFor="let item of items" [@color]="colorExp"> {{ item }} </div> `, - animations: [trigger('color', [state('green', style({backgroundColor: 'green'}))])] - }) - class Cmp { - public colorExp = 'green'; - public items = [0, 1, 2, 3]; + animations: [trigger('color', [state('green', style({backgroundColor: 'green'}))])] + }) + class Cmp { + public colorExp = 'green'; + public items = [0, 1, 2, 3]; - reorder() { - const temp = this.items[0]; - this.items[0] = this.items[1]; - this.items[1] = temp; - } + reorder() { + const temp = this.items[0]; + this.items[0] = this.items[1]; + this.items[1] = temp; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); - let elements: HTMLElement[] = fixture.nativeElement.querySelectorAll('.item'); - assertBackgroundColor(elements[0], 'green'); - assertBackgroundColor(elements[1], 'green'); - assertBackgroundColor(elements[2], 'green'); - assertBackgroundColor(elements[3], 'green'); + let elements: HTMLElement[] = fixture.nativeElement.querySelectorAll('.item'); + assertBackgroundColor(elements[0], 'green'); + assertBackgroundColor(elements[1], 'green'); + assertBackgroundColor(elements[2], 'green'); + assertBackgroundColor(elements[3], 'green'); - elements[0].title = '0a'; - elements[1].title = '1a'; + elements[0].title = '0a'; + elements[1].title = '1a'; - cmp.reorder(); - fixture.detectChanges(); + cmp.reorder(); + fixture.detectChanges(); - elements = fixture.nativeElement.querySelectorAll('.item'); - assertBackgroundColor(elements[0], 'green'); - assertBackgroundColor(elements[1], 'green'); - assertBackgroundColor(elements[2], 'green'); - assertBackgroundColor(elements[3], 'green'); + elements = fixture.nativeElement.querySelectorAll('.item'); + assertBackgroundColor(elements[0], 'green'); + assertBackgroundColor(elements[1], 'green'); + assertBackgroundColor(elements[2], 'green'); + assertBackgroundColor(elements[3], 'green'); - function assertBackgroundColor(element: HTMLElement, color: string) { - expect(element.style.getPropertyValue('background-color')).toEqual(color); - } - }); + function assertBackgroundColor(element: HTMLElement, color: string) { + expect(element.style.getPropertyValue('background-color')).toEqual(color); + } + }); - it('should retain state styles when the underlying DOM structure changes even if there are insert/remove animations', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should retain state styles when the underlying DOM structure changes even if there are insert/remove animations', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div class="item" *ngFor="let item of items" [@color]="colorExp"> {{ item }} </div> `, - animations: [trigger( - 'color', - [ - transition('* => *', animate(500)), - state('green', style({backgroundColor: 'green'})) - ])] - }) - class Cmp { - public colorExp = 'green'; - public items = [0, 1, 2, 3]; + animations: [trigger( + 'color', + [ + transition('* => *', animate(500)), + state('green', style({backgroundColor: 'green'})) + ])] + }) + class Cmp { + public colorExp = 'green'; + public items = [0, 1, 2, 3]; - reorder() { - const temp = this.items[0]; - this.items[0] = this.items[1]; - this.items[1] = temp; - } + reorder() { + const temp = this.items[0]; + this.items[0] = this.items[1]; + this.items[1] = temp; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); - getLog().forEach(p => p.finish()); + getLog().forEach(p => p.finish()); - let elements: HTMLElement[] = fixture.nativeElement.querySelectorAll('.item'); - assertBackgroundColor(elements[0], 'green'); - assertBackgroundColor(elements[1], 'green'); - assertBackgroundColor(elements[2], 'green'); - assertBackgroundColor(elements[3], 'green'); + let elements: HTMLElement[] = fixture.nativeElement.querySelectorAll('.item'); + assertBackgroundColor(elements[0], 'green'); + assertBackgroundColor(elements[1], 'green'); + assertBackgroundColor(elements[2], 'green'); + assertBackgroundColor(elements[3], 'green'); - elements[0].title = '0a'; - elements[1].title = '1a'; + elements[0].title = '0a'; + elements[1].title = '1a'; - cmp.reorder(); - fixture.detectChanges(); + cmp.reorder(); + fixture.detectChanges(); - getLog().forEach(p => p.finish()); + getLog().forEach(p => p.finish()); - elements = fixture.nativeElement.querySelectorAll('.item'); - assertBackgroundColor(elements[0], 'green'); - assertBackgroundColor(elements[1], 'green'); - assertBackgroundColor(elements[2], 'green'); - assertBackgroundColor(elements[3], 'green'); + elements = fixture.nativeElement.querySelectorAll('.item'); + assertBackgroundColor(elements[0], 'green'); + assertBackgroundColor(elements[1], 'green'); + assertBackgroundColor(elements[2], 'green'); + assertBackgroundColor(elements[3], 'green'); - function assertBackgroundColor(element: HTMLElement, color: string) { - expect(element.style.getPropertyValue('background-color')).toEqual(color); - } - }); + function assertBackgroundColor(element: HTMLElement, color: string) { + expect(element.style.getPropertyValue('background-color')).toEqual(color); + } + }); - it('should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should animate removals of nodes to the `void` state for each animation trigger, but treat all auto styles as pre styles', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div *ngIf="exp" class="ng-if" [@trig1]="exp2" @trig2></div> `, - animations: [ - trigger( - 'trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]), - trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])]) - ] - }) - class Cmp { - public exp = true; - public exp2 = 'state'; - } + animations: [ + trigger('trig1', [transition('state => void', [animate(1000, style({opacity: 0}))])]), + trigger('trig2', [transition(':leave', [animate(1000, style({width: '0px'}))])]) + ] + }) + class Cmp { + public exp = true; + public exp2 = 'state'; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); - resetLog(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); + resetLog(); - const element = fixture.nativeElement.querySelector('.ng-if'); - assertHasParent(element, true); + const element = fixture.nativeElement.querySelector('.ng-if'); + assertHasParent(element, true); - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp = false; + fixture.detectChanges(); + engine.flush(); - assertHasParent(element, true); + assertHasParent(element, true); - expect(getLog().length).toEqual(2); + expect(getLog().length).toEqual(2); - const player2 = getLog().pop() !; - const player1 = getLog().pop() !; + const player2 = getLog().pop()!; + const player1 = getLog().pop()!; - expect(player2.keyframes).toEqual([ - {width: PRE_STYLE, offset: 0}, - {width: '0px', offset: 1}, - ]); + expect(player2.keyframes).toEqual([ + {width: PRE_STYLE, offset: 0}, + {width: '0px', offset: 1}, + ]); - expect(player1.keyframes).toEqual([ - {opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1} - ]); + expect(player1.keyframes).toEqual([ + {opacity: PRE_STYLE, offset: 0}, {opacity: '0', offset: 1} + ]); - player2.finish(); - player1.finish(); - assertHasParent(element, false); - }); + player2.finish(); + player1.finish(); + assertHasParent(element, false); + }); - it('should properly cancel all existing animations when a removal occurs', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should properly cancel all existing animations when a removal occurs', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div *ngIf="exp" [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), - ]), - ] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: string | null; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', [style({width: '0px'}), animate(1000, style({width: '100px'}))]), + ]), + ] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp!: string|null; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(1); - const [player1] = getLog(); - resetLog(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(1); + const [player1] = getLog(); + resetLog(); - let finished = false; - player1.onDone(() => finished = true); + let finished = false; + player1.onDone(() => finished = true); - let destroyed = false; - player1.onDestroy(() => destroyed = true); + let destroyed = false; + player1.onDestroy(() => destroyed = true); - cmp.exp = null; - fixture.detectChanges(); - engine.flush(); + cmp.exp = null; + fixture.detectChanges(); + engine.flush(); - expect(finished).toBeTruthy(); - expect(destroyed).toBeTruthy(); - }); + expect(finished).toBeTruthy(); + expect(destroyed).toBeTruthy(); + }); - it('should not run inner child animations when a parent is set to be removed', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should not run inner child animations when a parent is set to be removed', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div *ngIf="exp" class="parent" > <div [@myAnimation]="exp2"></div> </div> `, - animations: [trigger( - 'myAnimation', [transition('a => b', [animate(1000, style({width: '0px'}))])])] - }) - class Cmp { - public exp = true; - public exp2 = '0'; - } + animations: + [trigger('myAnimation', [transition('a => b', [animate(1000, style({width: '0px'}))])])] + }) + class Cmp { + public exp = true; + public exp2 = '0'; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = true; - cmp.exp2 = 'a'; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp = true; + cmp.exp2 = 'a'; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp = false; - cmp.exp2 = 'b'; - fixture.detectChanges(); - engine.flush(); - expect(getLog().length).toEqual(0); - }); + cmp.exp = false; + cmp.exp2 = 'b'; + fixture.detectChanges(); + engine.flush(); + expect(getLog().length).toEqual(0); + }); - it('should cancel all active inner child animations when a parent removal animation is set to go', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should cancel all active inner child animations when a parent removal animation is set to go', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div *ngIf="exp1" @parent> <div [@child]="exp2" class="child1"></div> <div [@child]="exp2" class="child2"></div> </div> `, - animations: [ - trigger('parent', [transition( - ':leave', - [style({opacity: 0}), animate(1000, style({opacity: 1}))])]), - trigger('child', [transition( - 'a => b', - [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) - ] - }) - class Cmp { - public exp1: any; - public exp2: any; - } + animations: [ + trigger( + 'parent', + [transition(':leave', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]), + trigger( + 'child', + [transition('a => b', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) + ] + }) + class Cmp { + public exp1: any; + public exp2: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = true; - cmp.exp2 = 'a'; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp1 = true; + cmp.exp2 = 'a'; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp2 = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp2 = 'b'; + fixture.detectChanges(); + engine.flush(); - let players = getLog(); - expect(players.length).toEqual(2); - const [p1, p2] = players; + let players = getLog(); + expect(players.length).toEqual(2); + const [p1, p2] = players; - let count = 0; - p1.onDone(() => count++); - p2.onDone(() => count++); + let count = 0; + p1.onDone(() => count++); + p2.onDone(() => count++); - cmp.exp1 = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = false; + fixture.detectChanges(); + engine.flush(); - expect(count).toEqual(2); - }); + expect(count).toEqual(2); + }); - it('should destroy inner animations when a parent node is set for removal', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should destroy inner animations when a parent node is set for removal', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #parent class="parent"> <div [@child]="exp" class="child1"></div> <div [@child]="exp" class="child2"></div> </div> `, - animations: [trigger( - 'child', - [transition('a => b', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - public exp: any; + animations: [trigger( + 'child', + [transition('a => b', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] + }) + class Cmp { + public exp: any; - @ViewChild('parent') public parentElement: any; - } + @ViewChild('parent') public parentElement: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - const someTrigger = trigger('someTrigger', []); - const hostElement = fixture.nativeElement; - engine.register(DEFAULT_NAMESPACE_ID, hostElement); - engine.registerTrigger( - DEFAULT_COMPONENT_ID, DEFAULT_NAMESPACE_ID, hostElement, someTrigger.name, someTrigger); + const someTrigger = trigger('someTrigger', []); + const hostElement = fixture.nativeElement; + engine.register(DEFAULT_NAMESPACE_ID, hostElement); + engine.registerTrigger( + DEFAULT_COMPONENT_ID, DEFAULT_NAMESPACE_ID, hostElement, someTrigger.name, someTrigger); - cmp.exp = 'a'; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp = 'a'; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - const players = getLog(); - expect(players.length).toEqual(2); - const [p1, p2] = players; + const players = getLog(); + expect(players.length).toEqual(2); + const [p1, p2] = players; - let count = 0; - p1.onDone(() => count++); - p2.onDone(() => count++); + let count = 0; + p1.onDone(() => count++); + p2.onDone(() => count++); - engine.onRemove(DEFAULT_NAMESPACE_ID, cmp.parentElement.nativeElement, null); - expect(count).toEqual(2); - }); + engine.onRemove(DEFAULT_NAMESPACE_ID, cmp.parentElement.nativeElement, null); + expect(count).toEqual(2); + }); - it('should allow inner removals to happen when a non removal-based parent animation is set to animate', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should allow inner removals to happen when a non removal-based parent animation is set to animate', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #parent [@parent]="exp1" class="parent"> <div #child *ngIf="exp2" class="child"></div> </div> `, - animations: [trigger( - 'parent', - [transition( - 'a => b', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - public exp1: any; - public exp2: any; + animations: [trigger( + 'parent', + [transition('a => b', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] + }) + class Cmp { + public exp1: any; + public exp2: any; - @ViewChild('parent') public parent: any; + @ViewChild('parent') public parent: any; - @ViewChild('child') public child: any; - } + @ViewChild('child') public child: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = 'a'; - cmp.exp2 = true; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp1 = 'a'; + cmp.exp2 = true; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp1 = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = 'b'; + fixture.detectChanges(); + engine.flush(); - const player = getLog()[0]; - const p = cmp.parent.nativeElement; - const c = cmp.child.nativeElement; + const player = getLog()[0]; + const p = cmp.parent.nativeElement; + const c = cmp.child.nativeElement; - expect(p.contains(c)).toBeTruthy(); + expect(p.contains(c)).toBeTruthy(); - cmp.exp2 = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp2 = false; + fixture.detectChanges(); + engine.flush(); - expect(p.contains(c)).toBeFalsy(); + expect(p.contains(c)).toBeFalsy(); - player.finish(); + player.finish(); - expect(p.contains(c)).toBeFalsy(); - }); + expect(p.contains(c)).toBeFalsy(); + }); - it('should make inner removals wait until a parent based removal animation has finished', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should make inner removals wait until a parent based removal animation has finished', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #parent *ngIf="exp1" @parent class="parent"> <div #child1 *ngIf="exp2" class="child1"></div> <div #child2 *ngIf="exp2" class="child2"></div> </div> `, - animations: [trigger( - 'parent', - [transition( - ':leave', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] - }) - class Cmp { - public exp1: any; - public exp2: any; + animations: [trigger( + 'parent', + [transition(':leave', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])] + }) + class Cmp { + public exp1: any; + public exp2: any; - @ViewChild('parent') public parent: any; + @ViewChild('parent') public parent: any; - @ViewChild('child1') public child1Elm: any; + @ViewChild('child1') public child1Elm: any; - @ViewChild('child2') public child2Elm: any; - } + @ViewChild('child2') public child2Elm: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = true; - cmp.exp2 = true; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp1 = true; + cmp.exp2 = true; + fixture.detectChanges(); + engine.flush(); + resetLog(); - const p = cmp.parent.nativeElement; - const c1 = cmp.child1Elm.nativeElement; - const c2 = cmp.child2Elm.nativeElement; + const p = cmp.parent.nativeElement; + const c1 = cmp.child1Elm.nativeElement; + const c2 = cmp.child2Elm.nativeElement; - cmp.exp1 = false; - cmp.exp2 = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = false; + cmp.exp2 = false; + fixture.detectChanges(); + engine.flush(); - expect(p.contains(c1)).toBeTruthy(); - expect(p.contains(c2)).toBeTruthy(); + expect(p.contains(c1)).toBeTruthy(); + expect(p.contains(c2)).toBeTruthy(); - cmp.exp2 = false; - fixture.detectChanges(); - engine.flush(); + cmp.exp2 = false; + fixture.detectChanges(); + engine.flush(); - expect(p.contains(c1)).toBeTruthy(); - expect(p.contains(c2)).toBeTruthy(); - }); + expect(p.contains(c1)).toBeTruthy(); + expect(p.contains(c2)).toBeTruthy(); + }); - it('should detect trigger changes based on object.value properties', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should detect trigger changes based on object.value properties', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="{value:exp}"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => 1', [animate(1234, style({opacity: 0}))]), - transition('* => 2', [animate(5678, style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - public exp: any; - } + animations: [ + trigger( + 'myAnimation', + [ + transition('* => 1', [animate(1234, style({opacity: 0}))]), + transition('* => 2', [animate(5678, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = '1'; - fixture.detectChanges(); - engine.flush(); - let players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - resetLog(); + cmp.exp = '1'; + fixture.detectChanges(); + engine.flush(); + let players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); + resetLog(); - cmp.exp = '2'; - fixture.detectChanges(); - engine.flush(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(5678); - }); + cmp.exp = '2'; + fixture.detectChanges(); + engine.flush(); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(5678); + }); - it('should not render animations when the object expression value is the same as it was previously', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should not render animations when the object expression value is the same as it was previously', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="{value:exp,params:params}"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition('* => *', [animate(1234, style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - public exp: any; - public params: any; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); + animations: [ + trigger( + 'myAnimation', + [ + transition('* => *', [animate(1234, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + public exp: any; + public params: any; + } - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + TestBed.configureTestingModule({declarations: [Cmp]}); - cmp.exp = '1'; - cmp.params = {}; - fixture.detectChanges(); - engine.flush(); - let players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - resetLog(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = '1'; - cmp.params = {}; - fixture.detectChanges(); - engine.flush(); - players = getLog(); - expect(players.length).toEqual(0); - }); + cmp.exp = '1'; + cmp.params = {}; + fixture.detectChanges(); + engine.flush(); + let players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); + resetLog(); + + cmp.exp = '1'; + cmp.params = {}; + fixture.detectChanges(); + engine.flush(); + players = getLog(); + expect(players.length).toEqual(0); + }); - it('should update the final state styles when params update even if the expression hasn\'t changed', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should update the final state styles when params update even if the expression hasn\'t changed', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="{value:exp,params:{color:color}}"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('*', style({color: '{{ color }}'}), {params: {color: 'black'}}), - transition('* => 1', animate(500)) - ]), - ] - }) - class Cmp { - public exp: any; - // TODO(issue/24571): remove '!'. - public color !: string | null; - } + animations: [ + trigger( + 'myAnimation', + [ + state('*', style({color: '{{ color }}'}), {params: {color: 'black'}}), + transition('* => 1', animate(500)) + ]), + ] + }) + class Cmp { + public exp: any; + // TODO(issue/24571): remove '!'. + public color!: string|null; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = '1'; - cmp.color = 'red'; - fixture.detectChanges(); - const player = getLog()[0] !; - const element = player.element; - player.finish(); + cmp.exp = '1'; + cmp.color = 'red'; + fixture.detectChanges(); + const player = getLog()[0]!; + const element = player.element; + player.finish(); - flushMicrotasks(); - expect(hasStyle(element, 'color', 'red')).toBeTruthy(); + flushMicrotasks(); + expect(hasStyle(element, 'color', 'red')).toBeTruthy(); - cmp.exp = '1'; - cmp.color = 'blue'; - fixture.detectChanges(); - resetLog(); + cmp.exp = '1'; + cmp.color = 'blue'; + fixture.detectChanges(); + resetLog(); - flushMicrotasks(); - expect(hasStyle(element, 'color', 'blue')).toBeTruthy(); + flushMicrotasks(); + expect(hasStyle(element, 'color', 'blue')).toBeTruthy(); - cmp.exp = '1'; - cmp.color = null; - fixture.detectChanges(); - resetLog(); + cmp.exp = '1'; + cmp.color = null; + fixture.detectChanges(); + resetLog(); - flushMicrotasks(); - expect(hasStyle(element, 'color', 'black')).toBeTruthy(); - })); + flushMicrotasks(); + expect(hasStyle(element, 'color', 'black')).toBeTruthy(); + })); - it('should substitute in values if the provided state match is an object with values', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should substitute in values if the provided state match is an object with values', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [trigger( - 'myAnimation', - [transition( - 'a => b', - [style({opacity: '{{ start }}'}), animate(1000, style({opacity: '{{ end }}'}))], - buildParams({start: '0', end: '1'}))])] - }) - class Cmp { - public exp: any; - } + animations: [trigger( + 'myAnimation', + [transition( + 'a => b', + [style({opacity: '{{ start }}'}), animate(1000, style({opacity: '{{ end }}'}))], + buildParams({start: '0', end: '1'}))])] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = {value: 'a'}; - fixture.detectChanges(); - engine.flush(); - resetLog(); + cmp.exp = {value: 'a'}; + fixture.detectChanges(); + engine.flush(); + resetLog(); - cmp.exp = {value: 'b', params: {start: .3, end: .6}}; - fixture.detectChanges(); - engine.flush(); - const player = getLog().pop() !; - expect(player.keyframes).toEqual([ - {opacity: '0.3', offset: 0}, {opacity: '0.6', offset: 1} - ]); - }); + cmp.exp = {value: 'b', params: {start: .3, end: .6}}; + fixture.detectChanges(); + engine.flush(); + const player = getLog().pop()!; + expect(player.keyframes).toEqual([{opacity: '0.3', offset: 0}, {opacity: '0.6', offset: 1}]); + }); - it('should retain substituted styles on the element once the animation is complete if referenced in the final state', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should retain substituted styles on the element once the animation is complete if referenced in the final state', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="{value:exp, params: { color: color }}"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state( - 'start', style({ - color: '{{ color }}', - fontSize: '{{ fontSize }}px', - width: '{{ width }}' - }), - {params: {color: 'red', fontSize: '200', width: '10px'}}), - - state( - 'final', - style( - {color: '{{ color }}', fontSize: '{{ fontSize }}px', width: '888px'}), - {params: {color: 'green', fontSize: '50', width: '100px'}}), - - transition('start => final', animate(500)), - ]), - ] - }) - class Cmp { - public exp: any; - public color: any; - } + animations: [ + trigger( + 'myAnimation', + [ + state( + 'start', style({ + color: '{{ color }}', + fontSize: '{{ fontSize }}px', + width: '{{ width }}' + }), + {params: {color: 'red', fontSize: '200', width: '10px'}}), + + state( + 'final', + style({color: '{{ color }}', fontSize: '{{ fontSize }}px', width: '888px'}), + {params: {color: 'green', fontSize: '50', width: '100px'}}), + + transition('start => final', animate(500)), + ]), + ] + }) + class Cmp { + public exp: any; + public color: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'start'; - cmp.color = 'red'; - fixture.detectChanges(); - resetLog(); + cmp.exp = 'start'; + cmp.color = 'red'; + fixture.detectChanges(); + resetLog(); - cmp.exp = 'final'; - cmp.color = 'blue'; - fixture.detectChanges(); + cmp.exp = 'final'; + cmp.color = 'blue'; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(1); - const [p1] = players; + const players = getLog(); + expect(players.length).toEqual(1); + const [p1] = players; - expect(p1.keyframes).toEqual([ - {color: 'red', fontSize: '200px', width: '10px', offset: 0}, - {color: 'blue', fontSize: '50px', width: '888px', offset: 1} - ]); + expect(p1.keyframes).toEqual([ + {color: 'red', fontSize: '200px', width: '10px', offset: 0}, + {color: 'blue', fontSize: '50px', width: '888px', offset: 1} + ]); - const element = p1.element; - p1.finish(); - flushMicrotasks(); + const element = p1.element; + p1.finish(); + flushMicrotasks(); - expect(hasStyle(element, 'color', 'blue')).toBeTruthy(); - expect(hasStyle(element, 'fontSize', '50px')).toBeTruthy(); - expect(hasStyle(element, 'width', '888px')).toBeTruthy(); - })); + expect(hasStyle(element, 'color', 'blue')).toBeTruthy(); + expect(hasStyle(element, 'fontSize', '50px')).toBeTruthy(); + expect(hasStyle(element, 'width', '888px')).toBeTruthy(); + })); - it('should only evaluate final state param substitutions from the expression and state values and not from the transition options ', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - template: ` - <div [@myAnimation]="exp"></div> + it('should only evaluate final state param substitutions from the expression and state values and not from the transition options ', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + template: ` + <div [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state( - 'start', style({ - width: '{{ width }}', - height: '{{ height }}', - }), - {params: {width: '0px', height: '0px'}}), - - state( - 'final', style({ - width: '{{ width }}', - height: '{{ height }}', - }), - {params: {width: '100px', height: '100px'}}), + animations: [ + trigger( + 'myAnimation', + [ + state( + 'start', style({ + width: '{{ width }}', + height: '{{ height }}', + }), + {params: {width: '0px', height: '0px'}}), + + state( + 'final', style({ + width: '{{ width }}', + height: '{{ height }}', + }), + {params: {width: '100px', height: '100px'}}), - transition( - 'start => final', [animate(500)], - {params: {width: '333px', height: '666px'}}), - ]), - ] - }) - class Cmp { - public exp: any; - } + transition( + 'start => final', [animate(500)], + {params: {width: '333px', height: '666px'}}), + ]), + ] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'start'; - fixture.detectChanges(); - resetLog(); + cmp.exp = 'start'; + fixture.detectChanges(); + resetLog(); - cmp.exp = 'final'; - fixture.detectChanges(); + cmp.exp = 'final'; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(1); - const [p1] = players; + const players = getLog(); + expect(players.length).toEqual(1); + const [p1] = players; - expect(p1.keyframes).toEqual([ - {width: '0px', height: '0px', offset: 0}, - {width: '100px', height: '100px', offset: 1}, - ]); + expect(p1.keyframes).toEqual([ + {width: '0px', height: '0px', offset: 0}, + {width: '100px', height: '100px', offset: 1}, + ]); - const element = p1.element; - p1.finish(); - flushMicrotasks(); + const element = p1.element; + p1.finish(); + flushMicrotasks(); - expect(hasStyle(element, 'width', '100px')).toBeTruthy(); - expect(hasStyle(element, 'height', '100px')).toBeTruthy(); - })); + expect(hasStyle(element, 'width', '100px')).toBeTruthy(); + expect(hasStyle(element, 'height', '100px')).toBeTruthy(); + })); - it('should not flush animations twice when an inner component runs change detection', () => { - @Component({ - selector: 'outer-cmp', - template: ` + it('should not flush animations twice when an inner component runs change detection', () => { + @Component({ + selector: 'outer-cmp', + template: ` <div *ngIf="exp" @outer></div> <inner-cmp #inner></inner-cmp> `, - animations: [trigger( - 'outer', - [transition(':enter', [style({opacity: 0}), animate('1s', style({opacity: 1}))])])] - }) - class OuterCmp { - @ViewChild('inner') public inner: any; - public exp: any = null; + animations: [trigger( + 'outer', + [transition(':enter', [style({opacity: 0}), animate('1s', style({opacity: 1}))])])] + }) + class OuterCmp { + @ViewChild('inner') public inner: any; + public exp: any = null; - update() { this.exp = 'go'; } + update() { + this.exp = 'go'; + } - ngDoCheck() { - if (this.exp == 'go') { - this.inner.update(); - } + ngDoCheck() { + if (this.exp == 'go') { + this.inner.update(); } } + } - @Component({ - selector: 'inner-cmp', - template: ` + @Component({ + selector: 'inner-cmp', + template: ` <div *ngIf="exp" @inner></div> `, - animations: [trigger('inner', [transition( - ':enter', - [ - style({opacity: 0}), - animate('1s', style({opacity: 1})), - ])])] - }) - class InnerCmp { - public exp: any; - constructor(private _ref: ChangeDetectorRef) {} - update() { - this.exp = 'go'; - this._ref.detectChanges(); - } + animations: [trigger('inner', [transition( + ':enter', + [ + style({opacity: 0}), + animate('1s', style({opacity: 1})), + ])])] + }) + class InnerCmp { + public exp: any; + constructor(private _ref: ChangeDetectorRef) {} + update() { + this.exp = 'go'; + this._ref.detectChanges(); } + } - TestBed.configureTestingModule({declarations: [OuterCmp, InnerCmp]}); + TestBed.configureTestingModule({declarations: [OuterCmp, InnerCmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(OuterCmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - expect(getLog()).toEqual([]); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(OuterCmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + expect(getLog()).toEqual([]); - cmp.update(); - fixture.detectChanges(); + cmp.update(); + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); - }); + const players = getLog(); + expect(players.length).toEqual(2); + }); - describe('transition aliases', () => { - describe(':increment', () => { - it('should detect when a value has incremented', () => { - @Component({ - selector: 'if-cmp', - template: ` + describe('transition aliases', () => { + describe(':increment', () => { + it('should detect when a value has incremented', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - ':increment', - [ - animate(1234, style({background: 'red'})), - ]), - ]), - ] - }) - class Cmp { - exp: number = 0; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + ':increment', + [ + animate(1234, style({background: 'red'})), + ]), + ]), + ] + }) + class Cmp { + exp: number = 0; + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(0); - - cmp.exp++; - fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - resetLog(); - - cmp.exp = 5; - fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - }); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + let players = getLog(); + expect(players.length).toEqual(0); + + cmp.exp++; + fixture.detectChanges(); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); + resetLog(); + + cmp.exp = 5; + fixture.detectChanges(); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); }); + }); - describe(':decrement', () => { - it('should detect when a value has decremented', () => { - @Component({ - selector: 'if-cmp', - template: ` + describe(':decrement', () => { + it('should detect when a value has decremented', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - ':decrement', - [ - animate(1234, style({background: 'red'})), - ]), - ]), - ] - }) - class Cmp { - exp: number = 5; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + ':decrement', + [ + animate(1234, style({background: 'red'})), + ]), + ]), + ] + }) + class Cmp { + exp: number = 5; + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(0); - - cmp.exp--; - fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - resetLog(); - - cmp.exp = 0; - fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].duration).toEqual(1234); - }); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + let players = getLog(); + expect(players.length).toEqual(0); + + cmp.exp--; + fixture.detectChanges(); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); + resetLog(); + + cmp.exp = 0; + fixture.detectChanges(); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].duration).toEqual(1234); }); }); + }); - it('should animate nodes properly when they have been re-ordered', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should animate nodes properly when they have been re-ordered', () => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngFor="let item of items" [class]="'class-' + item.value"> <div [@myAnimation]="item.count"> {{ item.value }} </div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('0', style({opacity: 0})), state('1', style({opacity: 0.4})), - state('2', style({opacity: 0.8})), transition('* => 1, * => 2', [animate(1000)]) - ]), - ] - }) - class Cmp { - items = [ - {value: '1', count: 0}, - {value: '2', count: 0}, - {value: '3', count: 0}, - {value: '4', count: 0}, - {value: '5', count: 0}, + animations: [ + trigger( + 'myAnimation', + [ + state('0', style({opacity: 0})), state('1', style({opacity: 0.4})), + state('2', style({opacity: 0.8})), transition('* => 1, * => 2', [animate(1000)]) + ]), + ] + }) + class Cmp { + items = [ + {value: '1', count: 0}, + {value: '2', count: 0}, + {value: '3', count: 0}, + {value: '4', count: 0}, + {value: '5', count: 0}, + ]; + + reOrder() { + this.items = [ + this.items[4], + this.items[1], + this.items[3], + this.items[0], + this.items[2], ]; - - reOrder() { - this.items = [ - this.items[4], - this.items[1], - this.items[3], - this.items[0], - this.items[2], - ]; - } } + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - const one = cmp.items[0]; - const two = cmp.items[1]; - one.count++; - fixture.detectChanges(); - - cmp.reOrder(); - fixture.detectChanges(); - resetLog(); + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + const one = cmp.items[0]; + const two = cmp.items[1]; + one.count++; + fixture.detectChanges(); + + cmp.reOrder(); + fixture.detectChanges(); + resetLog(); - one.count++; - two.count++; - fixture.detectChanges(); + one.count++; + two.count++; + fixture.detectChanges(); - const players = getLog(); - expect(players.length).toEqual(2); - }); + const players = getLog(); + expect(players.length).toEqual(2); }); + }); - describe('animation listeners', () => { - it('should trigger a `start` state change listener for when the animation changes state from void => state', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + describe('animation listeners', () => { + it('should trigger a `start` state change listener for when the animation changes state from void => state', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngIf="exp" [@myAnimation]="exp" (@myAnimation.start)="callback($event)"></div> `, - animations: [trigger( - 'myAnimation', - [transition( - 'void => *', - [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + animations: [trigger( + 'myAnimation', + [transition( + 'void => *', + [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + // TODO(issue/24571): remove '!'. + event!: AnimationEvent; - callback = (event: any) => { this.event = event; }; + callback = (event: any) => { + this.event = event; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'true'; - fixture.detectChanges(); - flushMicrotasks(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'true'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation'); - expect(cmp.event.phaseName).toEqual('start'); - expect(cmp.event.totalTime).toEqual(500); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('true'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation'); + expect(cmp.event.phaseName).toEqual('start'); + expect(cmp.event.totalTime).toEqual(500); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('true'); + })); - it('should trigger a `done` state change listener for when the animation changes state from a => b', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should trigger a `done` state change listener for when the animation changes state from a => b', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngIf="exp" [@myAnimation123]="exp" (@myAnimation123.done)="callback($event)"></div> `, - animations: [trigger( - 'myAnimation123', - [transition( - '* => b', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any = false; - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + animations: [trigger( + 'myAnimation123', + [transition( + '* => b', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any = false; + // TODO(issue/24571): remove '!'. + event!: AnimationEvent; - callback = (event: any) => { this.event = event; }; + callback = (event: any) => { + this.event = event; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp = 'b'; + fixture.detectChanges(); + engine.flush(); - expect(cmp.event).toBeFalsy(); + expect(cmp.event).toBeFalsy(); - const player = engine.players.pop() !; - player.finish(); - flushMicrotasks(); + const player = engine.players.pop()!; + player.finish(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation123'); - expect(cmp.event.phaseName).toEqual('done'); - expect(cmp.event.totalTime).toEqual(999); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('b'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation123'); + expect(cmp.event.phaseName).toEqual('done'); + expect(cmp.event.totalTime).toEqual(999); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('b'); + })); - it('should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div [@ani1]="exp1" (@ani1.done)="callback1($event)"></div> <div [@ani2]="exp2" (@ani2.done)="callback2($event)"></div> `, - animations: [ - trigger( - 'ani1', - [ - transition( - '* => a', - [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]), - ]), - trigger( - 'ani2', - [ - transition( - '* => b', - [style({'width': '0px'}), animate(999, style({'width': '100px'}))]), - ]) - ], - }) - class Cmp { - exp1: any = false; - exp2: any = false; - // TODO(issue/24571): remove '!'. - event1 !: AnimationEvent; - // TODO(issue/24571): remove '!'. - event2 !: AnimationEvent; - // tslint:disable:semicolon - callback1 = (event: any) => { this.event1 = event; }; - // tslint:disable:semicolon - callback2 = (event: any) => { this.event2 = event; }; - } + animations: [ + trigger( + 'ani1', + [ + transition( + '* => a', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]), + ]), + trigger( + 'ani2', + [ + transition( + '* => b', + [style({'width': '0px'}), animate(999, style({'width': '100px'}))]), + ]) + ], + }) + class Cmp { + exp1: any = false; + exp2: any = false; + // TODO(issue/24571): remove '!'. + event1!: AnimationEvent; + // TODO(issue/24571): remove '!'. + event2!: AnimationEvent; + // tslint:disable:semicolon + callback1 = (event: any) => { + this.event1 = event; + }; + // tslint:disable:semicolon + callback2 = (event: any) => { + this.event2 = event; + }; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = 'a'; - cmp.exp2 = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = 'a'; + cmp.exp2 = 'b'; + fixture.detectChanges(); + engine.flush(); - expect(cmp.event1).toBeFalsy(); - expect(cmp.event2).toBeFalsy(); + expect(cmp.event1).toBeFalsy(); + expect(cmp.event2).toBeFalsy(); - const player1 = engine.players[0]; - const player2 = engine.players[1]; + const player1 = engine.players[0]; + const player2 = engine.players[1]; - player1.finish(); - player2.finish(); - expect(cmp.event1).toBeFalsy(); - expect(cmp.event2).toBeFalsy(); + player1.finish(); + player2.finish(); + expect(cmp.event1).toBeFalsy(); + expect(cmp.event2).toBeFalsy(); - flushMicrotasks(); - expect(cmp.event1.triggerName).toBeTruthy('ani1'); - expect(cmp.event2.triggerName).toBeTruthy('ani2'); - })); + flushMicrotasks(); + expect(cmp.event1.triggerName).toBeTruthy('ani1'); + expect(cmp.event2.triggerName).toBeTruthy('ani2'); + })); - it('should handle callbacks for multiple triggers running simultaneously on the same element', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should handle callbacks for multiple triggers running simultaneously on the same element', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div [@ani1]="exp1" (@ani1.done)="callback1($event)" [@ani2]="exp2" (@ani2.done)="callback2($event)"></div> `, - animations: [ - trigger( - 'ani1', - [ - transition( - '* => a', - [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]), - ]), - trigger( - 'ani2', - [ - transition( - '* => b', - [style({'width': '0px'}), animate(999, style({'width': '100px'}))]), - ]) - ], - }) - class Cmp { - exp1: any = false; - exp2: any = false; - // TODO(issue/24571): remove '!'. - event1 !: AnimationEvent; - // TODO(issue/24571): remove '!'. - event2 !: AnimationEvent; - callback1 = (event: any) => { this.event1 = event; }; - callback2 = (event: any) => { this.event2 = event; }; - } + animations: [ + trigger( + 'ani1', + [ + transition( + '* => a', [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]), + ]), + trigger( + 'ani2', + [ + transition( + '* => b', + [style({'width': '0px'}), animate(999, style({'width': '100px'}))]), + ]) + ], + }) + class Cmp { + exp1: any = false; + exp2: any = false; + // TODO(issue/24571): remove '!'. + event1!: AnimationEvent; + // TODO(issue/24571): remove '!'. + event2!: AnimationEvent; + callback1 = (event: any) => { + this.event1 = event; + }; + callback2 = (event: any) => { + this.event2 = event; + }; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp1 = 'a'; - cmp.exp2 = 'b'; - fixture.detectChanges(); - engine.flush(); + cmp.exp1 = 'a'; + cmp.exp2 = 'b'; + fixture.detectChanges(); + engine.flush(); - expect(cmp.event1).toBeFalsy(); - expect(cmp.event2).toBeFalsy(); + expect(cmp.event1).toBeFalsy(); + expect(cmp.event2).toBeFalsy(); - const player1 = engine.players[0]; - const player2 = engine.players[1]; + const player1 = engine.players[0]; + const player2 = engine.players[1]; - player1.finish(); - player2.finish(); - expect(cmp.event1).toBeFalsy(); - expect(cmp.event2).toBeFalsy(); + player1.finish(); + player2.finish(); + expect(cmp.event1).toBeFalsy(); + expect(cmp.event2).toBeFalsy(); - flushMicrotasks(); - expect(cmp.event1.triggerName).toBeTruthy('ani1'); - expect(cmp.event2.triggerName).toBeTruthy('ani2'); - })); + flushMicrotasks(); + expect(cmp.event1.triggerName).toBeTruthy('ani1'); + expect(cmp.event2.triggerName).toBeTruthy('ani2'); + })); - it('should handle a leave animation for multiple triggers even if not all triggers have their own leave transition specified', - fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` + it('should handle a leave animation for multiple triggers even if not all triggers have their own leave transition specified', + fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` <div *ngIf="exp" @foo @bar>123</div> `, - animations: [ - trigger( - 'foo', - [ - transition( - ':enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - trigger( - 'bar', - [ - transition( - ':leave', - [ - animate(1000, style({opacity: 0})), - ]), - ]) - ], - }) - class Cmp { - exp: boolean = false; - } + animations: [ + trigger( + 'foo', + [ + transition( + ':enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + trigger( + 'bar', + [ + transition( + ':leave', + [ + animate(1000, style({opacity: 0})), + ]), + ]) + ], + }) + class Cmp { + exp: boolean = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const elm = fixture.elementRef.nativeElement; - const cmp = fixture.componentInstance; + TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); + const elm = fixture.elementRef.nativeElement; + const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); + cmp.exp = true; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(1); - let [p1] = players; - p1.finish(); - flushMicrotasks(); - expect(elm.innerText.trim()).toEqual('123'); + let players = getLog(); + expect(players.length).toEqual(1); + let [p1] = players; + p1.finish(); + flushMicrotasks(); + expect(elm.innerText.trim()).toEqual('123'); - resetLog(); - cmp.exp = false; - fixture.detectChanges(); + resetLog(); + cmp.exp = false; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - [p1] = players; - p1.finish(); - flushMicrotasks(); - expect(elm.innerText.trim()).toEqual(''); - })); + players = getLog(); + expect(players.length).toEqual(1); + [p1] = players; + p1.finish(); + flushMicrotasks(); + expect(elm.innerText.trim()).toEqual(''); + })); - it('should trigger a state change listener for when the animation changes state from void => state on the host element', - fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: `...`, - animations: [trigger( - 'myAnimation2', - [transition( - 'void => *', - [style({'opacity': '0'}), animate(1000, style({'opacity': '1'}))])])], - }) - class Cmp { - // TODO(issue/24571): remove '!'. - event !: AnimationEvent; + it('should trigger a state change listener for when the animation changes state from void => state on the host element', + fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: `...`, + animations: [trigger( + 'myAnimation2', + [transition( + 'void => *', + [style({'opacity': '0'}), animate(1000, style({'opacity': '1'}))])])], + }) + class Cmp { + // TODO(issue/24571): remove '!'. + event!: AnimationEvent; - @HostBinding('@myAnimation2') - exp: any = false; + @HostBinding('@myAnimation2') exp: any = false; - @HostListener('@myAnimation2.start', ['$event']) - callback = (event: any) => { this.event = event; } + @HostListener('@myAnimation2.start', ['$event']) + callback = (event: any) => { + this.event = event; } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'TRUE'; - fixture.detectChanges(); - flushMicrotasks(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'TRUE'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.event.triggerName).toEqual('myAnimation2'); - expect(cmp.event.phaseName).toEqual('start'); - expect(cmp.event.totalTime).toEqual(1000); - expect(cmp.event.fromState).toEqual('void'); - expect(cmp.event.toState).toEqual('TRUE'); - })); + expect(cmp.event.triggerName).toEqual('myAnimation2'); + expect(cmp.event.phaseName).toEqual('start'); + expect(cmp.event.totalTime).toEqual(1000); + expect(cmp.event.fromState).toEqual('void'); + expect(cmp.event.toState).toEqual('TRUE'); + })); - it('should always fire callbacks even when a transition is not detected', fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should always fire callbacks even when a transition is not detected', fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: ` <div [@myAnimation]="exp" (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div> `, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - exp !: string; - log: any[] = []; - callback = (event: any) => this.log.push(`${event.phaseName} => ${event.toState}`); - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + exp!: string; + log: any[] = []; + callback = (event: any) => this.log.push(`${event.phaseName} => ${event.toState}`); + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], + declarations: [Cmp] + }); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = 'a'; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.log).toEqual(['start => a', 'done => a']); + cmp.exp = 'a'; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.log).toEqual(['start => a', 'done => a']); - cmp.log = []; - cmp.exp = 'b'; - fixture.detectChanges(); - flushMicrotasks(); + cmp.log = []; + cmp.exp = 'b'; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual(['start => b', 'done => b']); - })); + expect(cmp.log).toEqual(['start => b', 'done => b']); + })); - it('should fire callback events for leave animations even if there is no leave transition', - fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should fire callback events for leave animations even if there is no leave transition', + fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: ` <div *ngIf="exp" @myAnimation (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div> `, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - exp: boolean = false; - log: any[] = []; - callback = (event: any) => { - const state = event.toState || '_default_'; - this.log.push(`${event.phaseName} => ${state}`); - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + exp: boolean = false; + log: any[] = []; + callback = (event: any) => { + const state = event.toState || '_default_'; + this.log.push(`${event.phaseName} => ${state}`); } + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], + declarations: [Cmp] + }); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - cmp.exp = true; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.log).toEqual(['start => _default_', 'done => _default_']); + cmp.exp = true; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.log).toEqual(['start => _default_', 'done => _default_']); - cmp.log = []; + cmp.log = []; - cmp.exp = false; - fixture.detectChanges(); - flushMicrotasks(); + cmp.exp = false; + fixture.detectChanges(); + flushMicrotasks(); - expect(cmp.log).toEqual(['start => void', 'done => void']); - })); + expect(cmp.log).toEqual(['start => void', 'done => void']); + })); - it('should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { - @Component({ - selector: 'my-cmp', - template: ` + it('should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: ` <div class="parent" [@parent]="exp1" (@parent.start)="cb('parent-start',$event)" @@ -2911,82 +2916,83 @@ const DEFAULT_COMPONENT_ID = '1'; (@child.done)="cb('child-done', $event)"></div> </div> `, - animations: [ - trigger( - 'parent', - [ - transition( - '* => go', - [ - style({width: '0px'}), - animate(1000, style({width: '100px'})), - query( - '.child', - [ - animateChild({duration: '1s'}), - ]), - animate(1000, style({width: '0px'})), - ]), - ]), - trigger( - 'child', - [ - transition( - '* => go', - [ - style({height: '0px'}), - animate(1000, style({height: '100px'})), - ]), - ]) - ] - }) - class Cmp { - log: string[] = []; - // TODO(issue/24571): remove '!'. - exp1 !: string; - // TODO(issue/24571): remove '!'. - exp2 !: string; - - cb(name: string, event: AnimationEvent) { this.log.push(name); } + animations: [ + trigger( + 'parent', + [ + transition( + '* => go', + [ + style({width: '0px'}), + animate(1000, style({width: '100px'})), + query( + '.child', + [ + animateChild({duration: '1s'}), + ]), + animate(1000, style({width: '0px'})), + ]), + ]), + trigger( + 'child', + [ + transition( + '* => go', + [ + style({height: '0px'}), + animate(1000, style({height: '100px'})), + ]), + ]) + ] + }) + class Cmp { + log: string[] = []; + // TODO(issue/24571): remove '!'. + exp1!: string; + // TODO(issue/24571): remove '!'. + exp2!: string; + + cb(name: string, event: AnimationEvent) { + this.log.push(name); } + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp1 = 'go'; - cmp.exp2 = 'go'; - fixture.detectChanges(); - engine.flush(); - flushMicrotasks(); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp1 = 'go'; + cmp.exp2 = 'go'; + fixture.detectChanges(); + engine.flush(); + flushMicrotasks(); - expect(cmp.log).toEqual(['parent-start', 'child-start']); - cmp.log = []; + expect(cmp.log).toEqual(['parent-start', 'child-start']); + cmp.log = []; - const players = getLog(); - expect(players.length).toEqual(3); - const [p1, p2, p3] = players; + const players = getLog(); + expect(players.length).toEqual(3); + const [p1, p2, p3] = players; - p1.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual([]); + p1.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual([]); - p2.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual([]); + p2.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual([]); - p3.finish(); - flushMicrotasks(); - expect(cmp.log).toEqual(['parent-done', 'child-done']); - })); + p3.finish(); + flushMicrotasks(); + expect(cmp.log).toEqual(['parent-done', 'child-done']); + })); - it('should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', - fakeAsync( - () => { - @Component({ - selector: 'my-cmp', - template: ` + it('should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', + fakeAsync(() => { + @Component({ + selector: 'my-cmp', + template: ` <div class="parent" [@parent]="exp" (@parent.done)="cb('all','done', $event)"> <div *ngFor="let item of items" class="item item-{{ item }}" @@ -2997,563 +3003,441 @@ const DEFAULT_COMPONENT_ID = '1'; </div> </div> `, - animations: [ - trigger('parent', [ - transition('* => go', [ - style({ opacity: 0 }), - animate('1s', style({ opacity: 1 })), - query('.item', [ - style({ opacity: 0 }), - animate(1000, style({ opacity: 1 })) - ]), - query('.item', [ - animateChild({ duration: '1.8s', delay: '300ms' }) - ]) - ]) - ]), - trigger('child', [ - transition(':enter', [ - style({ opacity: 0 }), - animate(1500, style({ opacity: 1 })) - ]) - ]) - ] - }) - class Cmp { - log: string[] = []; - events: {[name: string]: any} = {}; - // TODO(issue/24571): remove '!'. - exp !: string; - items: any = [0, 1, 2, 3]; - - cb(name: string, phase: string, event: AnimationEvent) { - this.log.push(name + '-' + phase); - this.events[name] = event; - } - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'go'; - fixture.detectChanges(); - engine.flush(); - flushMicrotasks(); - - expect(cmp.log).toEqual(['c-0-start', 'c-1-start', 'c-2-start', 'c-3-start']); - cmp.log = []; - - const players = getLog(); - // 1 + 4 + 4 = 9 players - expect(players.length).toEqual(9); - - const [pA, pq1a, pq1b, pq1c, pq1d, pq2a, pq2b, pq2c, pq2d] = getLog(); - pA.finish(); - pq1a.finish(); - pq1b.finish(); - pq1c.finish(); - pq1d.finish(); - flushMicrotasks(); - - expect(cmp.log).toEqual([]); - pq2a.finish(); - pq2b.finish(); - pq2c.finish(); - pq2d.finish(); - flushMicrotasks(); - - expect(cmp.log).toEqual( - ['all-done', 'c-0-done', 'c-1-done', 'c-2-done', 'c-3-done']); - - expect(cmp.events['c-0'].totalTime).toEqual(4100); // 1000 + 1000 + 1800 + 300 - expect(cmp.events['c-0'].element.innerText.trim()).toEqual('0'); - expect(cmp.events['c-1'].totalTime).toEqual(4100); - expect(cmp.events['c-1'].element.innerText.trim()).toEqual('1'); - expect(cmp.events['c-2'].totalTime).toEqual(4100); - expect(cmp.events['c-2'].element.innerText.trim()).toEqual('2'); - expect(cmp.events['c-3'].totalTime).toEqual(4100); - expect(cmp.events['c-3'].element.innerText.trim()).toEqual('3'); - })); - }); + animations: [ + trigger( + 'parent', + [transition( + '* => go', + [ + style({opacity: 0}), animate('1s', style({opacity: 1})), + query('.item', [style({opacity: 0}), animate(1000, style({opacity: 1}))]), + query('.item', [animateChild({duration: '1.8s', delay: '300ms'})]) + ])]), + trigger( + 'child', + [transition(':enter', [style({opacity: 0}), animate(1500, style({opacity: 1}))])]) + ] + }) + class Cmp { + log: string[] = []; + events: {[name: string]: any} = {}; + // TODO(issue/24571): remove '!'. + exp!: string; + items: any = [0, 1, 2, 3]; + + cb(name: string, phase: string, event: AnimationEvent) { + this.log.push(name + '-' + phase); + this.events[name] = event; + } + } - describe('animation control flags', () => { - describe('[@.disabled]', () => { - it('should disable child animations when set to true', () => { - @Component({ - selector: 'if-cmp', - template: ` + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + engine.flush(); + flushMicrotasks(); + + expect(cmp.log).toEqual(['c-0-start', 'c-1-start', 'c-2-start', 'c-3-start']); + cmp.log = []; + + const players = getLog(); + // 1 + 4 + 4 = 9 players + expect(players.length).toEqual(9); + + const [pA, pq1a, pq1b, pq1c, pq1d, pq2a, pq2b, pq2c, pq2d] = getLog(); + pA.finish(); + pq1a.finish(); + pq1b.finish(); + pq1c.finish(); + pq1d.finish(); + flushMicrotasks(); + + expect(cmp.log).toEqual([]); + pq2a.finish(); + pq2b.finish(); + pq2c.finish(); + pq2d.finish(); + flushMicrotasks(); + + expect(cmp.log).toEqual(['all-done', 'c-0-done', 'c-1-done', 'c-2-done', 'c-3-done']); + + expect(cmp.events['c-0'].totalTime).toEqual(4100); // 1000 + 1000 + 1800 + 300 + expect(cmp.events['c-0'].element.innerText.trim()).toEqual('0'); + expect(cmp.events['c-1'].totalTime).toEqual(4100); + expect(cmp.events['c-1'].element.innerText.trim()).toEqual('1'); + expect(cmp.events['c-2'].totalTime).toEqual(4100); + expect(cmp.events['c-2'].element.innerText.trim()).toEqual('2'); + expect(cmp.events['c-3'].totalTime).toEqual(4100); + expect(cmp.events['c-3'].element.innerText.trim()).toEqual('3'); + })); + }); + + describe('animation control flags', () => { + describe('[@.disabled]', () => { + it('should disable child animations when set to true', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@.disabled]="disableExp"> <div [@myAnimation]="exp"></div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => 1, * => 2', - [ - animate(1234, style({width: '100px'})), - ]), - ]), - ] - }) - class Cmp { - exp: any = false; - disableExp = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => 1, * => 2', + [ + animate(1234, style({width: '100px'})), + ]), + ]), + ] + }) + class Cmp { + exp: any = false; + disableExp = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + resetLog(); - cmp.disableExp = true; - cmp.exp = '1'; - fixture.detectChanges(); + cmp.disableExp = true; + cmp.exp = '1'; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(0); + let players = getLog(); + expect(players.length).toEqual(0); - cmp.disableExp = false; - cmp.exp = '2'; - fixture.detectChanges(); + cmp.disableExp = false; + cmp.exp = '2'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].totalTime).toEqual(1234); - }); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].totalTime).toEqual(1234); + }); - it('should ensure state() values are applied when an animation is disabled', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should ensure state() values are applied when an animation is disabled', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@.disabled]="disableExp"> <div [@myAnimation]="exp" #elm></div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('1', style({height: '100px'})), state('2', style({height: '200px'})), - state('3', style({height: '300px'})), transition('* => *', animate(500)) - ]), - ] - }) - class Cmp { - exp: any = false; - disableExp = false; + animations: [ + trigger( + 'myAnimation', + [ + state('1', style({height: '100px'})), state('2', style({height: '200px'})), + state('3', style({height: '300px'})), transition('* => *', animate(500)) + ]), + ] + }) + class Cmp { + exp: any = false; + disableExp = false; - @ViewChild('elm', {static: true}) public element: any; - } + @ViewChild('elm', {static: true}) public element: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const engine = TestBed.inject(ɵAnimationEngine); - function assertHeight(element: any, height: string) { - expect(element.style['height']).toEqual(height); - } + function assertHeight(element: any, height: string) { + expect(element.style['height']).toEqual(height); + } - // In Ivy, change detection needs to run before the ViewQuery for cmp.element will - // resolve. Keeping this test enabled since we still want to test the animation logic. - if (ivyEnabled) fixture.detectChanges(); + // In Ivy, change detection needs to run before the ViewQuery for cmp.element will + // resolve. Keeping this test enabled since we still want to test the animation logic. + if (ivyEnabled) fixture.detectChanges(); - const cmp = fixture.componentInstance; - const element = cmp.element.nativeElement; - fixture.detectChanges(); + const cmp = fixture.componentInstance; + const element = cmp.element.nativeElement; + fixture.detectChanges(); - cmp.disableExp = true; - cmp.exp = '1'; - fixture.detectChanges(); - assertHeight(element, '100px'); + cmp.disableExp = true; + cmp.exp = '1'; + fixture.detectChanges(); + assertHeight(element, '100px'); - cmp.exp = '2'; - fixture.detectChanges(); - assertHeight(element, '200px'); + cmp.exp = '2'; + fixture.detectChanges(); + assertHeight(element, '200px'); - cmp.exp = '3'; - fixture.detectChanges(); - assertHeight(element, '300px'); - }); + cmp.exp = '3'; + fixture.detectChanges(); + assertHeight(element, '300px'); + }); - it('should disable animations for the element that they are disabled on', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should disable animations for the element that they are disabled on', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@.disabled]="disableExp" [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => 1, * => 2', - [ - animate(1234, style({width: '100px'})), - ]), - ]), - ] - }) - class Cmp { - exp: any = false; - disableExp = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => 1, * => 2', + [ + animate(1234, style({width: '100px'})), + ]), + ]), + ] + }) + class Cmp { + exp: any = false; + disableExp = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + resetLog(); - cmp.disableExp = true; - cmp.exp = '1'; - fixture.detectChanges(); + cmp.disableExp = true; + cmp.exp = '1'; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(0); - resetLog(); + let players = getLog(); + expect(players.length).toEqual(0); + resetLog(); - cmp.disableExp = false; - cmp.exp = '2'; - fixture.detectChanges(); + cmp.disableExp = false; + cmp.exp = '2'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].totalTime).toEqual(1234); - }); + players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].totalTime).toEqual(1234); + }); - it('should respect inner disabled nodes once a parent becomes enabled', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should respect inner disabled nodes once a parent becomes enabled', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@.disabled]="disableParentExp"> <div [@.disabled]="disableChildExp"> <div [@myAnimation]="exp"></div> </div> </div> `, - animations: [trigger( - 'myAnimation', - [transition('* => 1, * => 2, * => 3', [animate(1234, style({width: '100px'}))])])] - }) - class Cmp { - disableParentExp = false; - disableChildExp = false; - exp = ''; - } + animations: [trigger( + 'myAnimation', + [transition('* => 1, * => 2, * => 3', [animate(1234, style({width: '100px'}))])])] + }) + class Cmp { + disableParentExp = false; + disableChildExp = false; + exp = ''; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + resetLog(); - cmp.disableParentExp = true; - cmp.disableChildExp = true; - cmp.exp = '1'; - fixture.detectChanges(); + cmp.disableParentExp = true; + cmp.disableChildExp = true; + cmp.exp = '1'; + fixture.detectChanges(); - let players = getLog(); - expect(players.length).toEqual(0); + let players = getLog(); + expect(players.length).toEqual(0); - cmp.disableParentExp = false; - cmp.exp = '2'; - fixture.detectChanges(); + cmp.disableParentExp = false; + cmp.exp = '2'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(0); + players = getLog(); + expect(players.length).toEqual(0); - cmp.disableChildExp = false; - cmp.exp = '3'; - fixture.detectChanges(); + cmp.disableChildExp = false; + cmp.exp = '3'; + fixture.detectChanges(); - players = getLog(); - expect(players.length).toEqual(1); - }); + players = getLog(); + expect(players.length).toEqual(1); + }); - it('should properly handle dom operations when disabled', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should properly handle dom operations when disabled', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@.disabled]="disableExp" #parent> <div *ngIf="exp" @myAnimation></div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - ':enter', - [ - style({opacity: 0}), - animate(1234, style({opacity: 1})), - ]), - transition( - ':leave', - [ - animate(1234, style({opacity: 0})), - ]), - ]), - ] - }) - class Cmp { - @ViewChild('parent') public parentElm: any; - disableExp = false; - exp = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + ':enter', + [ + style({opacity: 0}), + animate(1234, style({opacity: 1})), + ]), + transition( + ':leave', + [ + animate(1234, style({opacity: 0})), + ]), + ]), + ] + }) + class Cmp { + @ViewChild('parent') public parentElm: any; + disableExp = false; + exp = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.disableExp = true; - fixture.detectChanges(); - resetLog(); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.disableExp = true; + fixture.detectChanges(); + resetLog(); - const parent = cmp.parentElm !.nativeElement; + const parent = cmp.parentElm!.nativeElement; - cmp.exp = true; - fixture.detectChanges(); - expect(getLog().length).toEqual(0); - expect(parent.childElementCount).toEqual(1); + cmp.exp = true; + fixture.detectChanges(); + expect(getLog().length).toEqual(0); + expect(parent.childElementCount).toEqual(1); - cmp.exp = false; - fixture.detectChanges(); - expect(getLog().length).toEqual(0); - expect(parent.childElementCount).toEqual(0); - }); + cmp.exp = false; + fixture.detectChanges(); + expect(getLog().length).toEqual(0); + expect(parent.childElementCount).toEqual(0); + }); + + it('should properly resolve animation event listeners when disabled', fakeAsync(() => { + @Component({ + selector: 'if-cmp', + template: ` + <div [@.disabled]="disableExp"> + <div [@myAnimation]="exp" (@myAnimation.start)="startEvent=$event" (@myAnimation.done)="doneEvent=$event"></div> + </div> + `, + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => 1, * => 2', + [style({opacity: 0}), animate(9876, style({opacity: 1}))]), + ]), + ] + }) + class Cmp { + disableExp = false; + exp = ''; + // TODO(issue/24571): remove '!'. + startEvent!: AnimationEvent; + // TODO(issue/24571): remove '!'. + doneEvent!: AnimationEvent; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.disableExp = true; + fixture.detectChanges(); + resetLog(); + expect(cmp.startEvent).toBeFalsy(); + expect(cmp.doneEvent).toBeFalsy(); + + cmp.exp = '1'; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.startEvent.totalTime).toEqual(9876); + expect(cmp.startEvent.disabled).toBeTruthy(); + expect(cmp.doneEvent.totalTime).toEqual(9876); + expect(cmp.doneEvent.disabled).toBeTruthy(); - it('should properly resolve animation event listeners when disabled', fakeAsync(() => { - @Component({ - selector: 'if-cmp', - template: ` - <div [@.disabled]="disableExp"> - <div [@myAnimation]="exp" (@myAnimation.start)="startEvent=$event" (@myAnimation.done)="doneEvent=$event"></div> - </div> - `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => 1, * => 2', - [style({opacity: 0}), animate(9876, style({opacity: 1}))]), - ]), - ] - }) - class Cmp { - disableExp = false; - exp = ''; - // TODO(issue/24571): remove '!'. - startEvent !: AnimationEvent; - // TODO(issue/24571): remove '!'. - doneEvent !: AnimationEvent; - } + cmp.exp = '2'; + cmp.disableExp = false; + fixture.detectChanges(); + flushMicrotasks(); + expect(cmp.startEvent.totalTime).toEqual(9876); + expect(cmp.startEvent.disabled).toBeFalsy(); + // the done event isn't fired because it's an actual animation + })); - TestBed.configureTestingModule({declarations: [Cmp]}); - - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.disableExp = true; - fixture.detectChanges(); - resetLog(); - expect(cmp.startEvent).toBeFalsy(); - expect(cmp.doneEvent).toBeFalsy(); - - cmp.exp = '1'; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.startEvent.totalTime).toEqual(9876); - expect(cmp.startEvent.disabled).toBeTruthy(); - expect(cmp.doneEvent.totalTime).toEqual(9876); - expect(cmp.doneEvent.disabled).toBeTruthy(); - - cmp.exp = '2'; - cmp.disableExp = false; - fixture.detectChanges(); - flushMicrotasks(); - expect(cmp.startEvent.totalTime).toEqual(9876); - expect(cmp.startEvent.disabled).toBeFalsy(); - // the done event isn't fired because it's an actual animation - })); - - it('should work when there are no animations on the component handling the disable/enable flag', - () => { - @Component({ - selector: 'parent-cmp', - template: ` + it('should work when there are no animations on the component handling the disable/enable flag', + () => { + @Component({ + selector: 'parent-cmp', + template: ` <div [@.disabled]="disableExp"> <child-cmp #child></child-cmp> </div> ` - }) - class ParentCmp { - @ViewChild('child') public child: ChildCmp|null = null; - disableExp = false; - } + }) + class ParentCmp { + @ViewChild('child') public child: ChildCmp|null = null; + disableExp = false; + } - @Component({ - selector: 'child-cmp', - template: ` + @Component({ + selector: 'child-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [trigger( - 'myAnimation', - [transition( - '* => go, * => goAgain', - [style({opacity: 0}), animate('1s', style({opacity: 1}))])])] - }) - class ChildCmp { - public exp = ''; - } - - TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - - const fixture = TestBed.createComponent(ParentCmp); - const cmp = fixture.componentInstance; - cmp.disableExp = true; - fixture.detectChanges(); - resetLog(); - - const child = cmp.child !; - child.exp = 'go'; - fixture.detectChanges(); - - expect(getLog().length).toEqual(0); - resetLog(); - - cmp.disableExp = false; - child.exp = 'goAgain'; - fixture.detectChanges(); - expect(getLog().length).toEqual(1); - }); - - it('should treat the property as true when the expression is missing', () => { - @Component({ - selector: 'parent-cmp', - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - style({opacity: 0}), - animate(500, style({opacity: 1})), - ]), - ]), - ], - template: ` - <div @.disabled> - <div [@myAnimation]="exp"></div> - </div> - ` - }) - class Cmp { - exp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - fixture.detectChanges(); - resetLog(); + animations: [trigger( + 'myAnimation', [transition( + '* => go, * => goAgain', + [style({opacity: 0}), animate('1s', style({opacity: 1}))])])] + }) + class ChildCmp { + public exp = ''; + } - cmp.exp = 'go'; - fixture.detectChanges(); - expect(getLog().length).toEqual(0); - }); + TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); - it('should respect parent/sub animations when the respective area in the DOM is disabled', - fakeAsync(() => { - @Component({ - selector: 'parent-cmp', - animations: [ - trigger( - 'parent', - [ - transition( - '* => empty', - [ - style({opacity: 0}), - query( - '@child', - [ - animateChild(), - ]), - animate('1s', style({opacity: 1})), - ]), - ]), - trigger( - 'child', - [ - transition( - ':leave', - [ - animate('1s', style({opacity: 0})), - ]), - ]), - ], - template: ` - <div [@.disabled]="disableExp" #container> - <div [@parent]="exp" (@parent.done)="onDone($event)"> - <div class="item" *ngFor="let item of items" @child (@child.done)="onDone($event)"></div> - </div> - </div> - ` - }) - class Cmp { - @ViewChild('container') public container: any; + const fixture = TestBed.createComponent(ParentCmp); + const cmp = fixture.componentInstance; + cmp.disableExp = true; + fixture.detectChanges(); + resetLog(); - disableExp = false; - exp = ''; - items: any[] = []; - doneLog: any[] = []; + const child = cmp.child!; + child.exp = 'go'; + fixture.detectChanges(); - onDone(event: any) { this.doneLog.push(event); } - } + expect(getLog().length).toEqual(0); + resetLog(); - TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.disableExp = true; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - flushMicrotasks(); - - cmp.exp = 'empty'; - cmp.items = []; - cmp.doneLog = []; - fixture.detectChanges(); - flushMicrotasks(); - - const elms = cmp.container.nativeElement.querySelectorAll('.item'); - expect(elms.length).toEqual(0); - - expect(cmp.doneLog.length).toEqual(6); - })); - }); - }); + cmp.disableExp = false; + child.exp = 'goAgain'; + fixture.detectChanges(); + expect(getLog().length).toEqual(1); + }); - describe('animation normalization', () => { - it('should convert hyphenated properties to camelcase by default', () => { + it('should treat the property as true when the expression is missing', () => { @Component({ - selector: 'cmp', - template: ` - <div [@myAnimation]="exp"></div> - `, + selector: 'parent-cmp', animations: [ trigger( 'myAnimation', @@ -3561,194 +3445,311 @@ const DEFAULT_COMPONENT_ID = '1'; transition( '* => go', [ - style({'background-color': 'red', height: '100px', fontSize: '100px'}), - animate( - '1s', - style( - {'background-color': 'blue', height: '200px', fontSize: '200px'})), + style({opacity: 0}), + animate(500, style({opacity: 1})), ]), ]), - ] + ], + template: ` + <div @.disabled> + <div [@myAnimation]="exp"></div> + </div> + ` }) class Cmp { - exp: any = false; + exp = ''; } TestBed.configureTestingModule({declarations: [Cmp]}); + const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; - cmp.exp = 'go'; fixture.detectChanges(); + resetLog(); - const players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].keyframes).toEqual([ - {backgroundColor: 'red', height: '100px', fontSize: '100px', offset: 0}, - {backgroundColor: 'blue', height: '200px', fontSize: '200px', offset: 1}, - ]); + cmp.exp = 'go'; + fixture.detectChanges(); + expect(getLog().length).toEqual(0); }); - it('should convert hyphenated properties to camelcase by default that are auto/pre style properties', - () => { + it('should respect parent/sub animations when the respective area in the DOM is disabled', + fakeAsync(() => { @Component({ - selector: 'cmp', - template: ` - <div [@myAnimation]="exp"></div> - `, + selector: 'parent-cmp', animations: [ trigger( - 'myAnimation', + 'parent', [ transition( - '* => go', + '* => empty', [ - style({'background-color': AUTO_STYLE, 'font-size': '100px'}), - animate( - '1s', style({'background-color': 'blue', 'font-size': PRE_STYLE})), + style({opacity: 0}), + query( + '@child', + [ + animateChild(), + ]), + animate('1s', style({opacity: 1})), ]), ]), - ] + trigger( + 'child', + [ + transition( + ':leave', + [ + animate('1s', style({opacity: 0})), + ]), + ]), + ], + template: ` + <div [@.disabled]="disableExp" #container> + <div [@parent]="exp" (@parent.done)="onDone($event)"> + <div class="item" *ngFor="let item of items" @child (@child.done)="onDone($event)"></div> + </div> + </div> + ` }) class Cmp { - exp: any = false; + @ViewChild('container') public container: any; + + disableExp = false; + exp = ''; + items: any[] = []; + doneLog: any[] = []; + + onDone(event: any) { + this.doneLog.push(event); + } } TestBed.configureTestingModule({declarations: [Cmp]}); + const engine = TestBed.inject(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; - cmp.exp = 'go'; + cmp.disableExp = true; + cmp.items = [0, 1, 2, 3, 4]; fixture.detectChanges(); + flushMicrotasks(); - const players = getLog(); - expect(players.length).toEqual(1); - expect(players[0].keyframes).toEqual([ - {backgroundColor: AUTO_STYLE, fontSize: '100px', offset: 0}, - {backgroundColor: 'blue', fontSize: PRE_STYLE, offset: 1}, - ]); - }); + cmp.exp = 'empty'; + cmp.items = []; + cmp.doneLog = []; + fixture.detectChanges(); + flushMicrotasks(); + + const elms = cmp.container.nativeElement.querySelectorAll('.item'); + expect(elms.length).toEqual(0); + + expect(cmp.doneLog.length).toEqual(6); + })); }); + }); - it('should throw neither state() or transition() are used inside of trigger()', () => { + describe('animation normalization', () => { + it('should convert hyphenated properties to camelcase by default', () => { @Component({ - selector: 'if-cmp', + selector: 'cmp', template: ` - <div [@myAnimation]="exp"></div> - `, - animations: [trigger('myAnimation', [animate(1000, style({width: '100px'}))])] + <div [@myAnimation]="exp"></div> + `, + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + style({'background-color': 'red', height: '100px', fontSize: '100px'}), + animate( + '1s', + style({'background-color': 'blue', height: '200px', fontSize: '200px'})), + ]), + ]), + ] }) class Cmp { exp: any = false; } TestBed.configureTestingModule({declarations: [Cmp]}); - - expect(() => { TestBed.createComponent(Cmp); }) - .toThrowError( - /only state\(\) and transition\(\) definitions can sit inside of a trigger\(\)/); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'go'; + fixture.detectChanges(); + + const players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].keyframes).toEqual([ + {backgroundColor: 'red', height: '100px', fontSize: '100px', offset: 0}, + {backgroundColor: 'blue', height: '200px', fontSize: '200px', offset: 1}, + ]); }); - it('should combine multiple errors together into one exception when an animation fails to be built', + it('should convert hyphenated properties to camelcase by default that are auto/pre style properties', () => { @Component({ - selector: 'if-cmp', + selector: 'cmp', template: ` - <div [@foo]="fooExp" [@bar]="barExp"></div> - `, + <div [@myAnimation]="exp"></div> + `, animations: [ trigger( - 'foo', - [ - transition(':enter', []), - transition( - '* => *', - [ - query('foo', animate(1000, style({background: 'red'}))), - ]), - ]), - trigger( - 'bar', + 'myAnimation', [ - transition(':enter', []), transition( - '* => *', + '* => go', [ - query('bar', animate(1000, style({background: 'blue'}))), + style({'background-color': AUTO_STYLE, 'font-size': '100px'}), + animate('1s', style({'background-color': 'blue', 'font-size': PRE_STYLE})), ]), ]), ] }) class Cmp { - fooExp: any = false; - barExp: any = false; + exp: any = false; } TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); const fixture = TestBed.createComponent(Cmp); const cmp = fixture.componentInstance; + cmp.exp = 'go'; fixture.detectChanges(); - cmp.fooExp = 'go'; - cmp.barExp = 'go'; + const players = getLog(); + expect(players.length).toEqual(1); + expect(players[0].keyframes).toEqual([ + {backgroundColor: AUTO_STYLE, fontSize: '100px', offset: 0}, + {backgroundColor: 'blue', fontSize: PRE_STYLE, offset: 1}, + ]); + }); + }); + + it('should throw neither state() or transition() are used inside of trigger()', () => { + @Component({ + selector: 'if-cmp', + template: ` + <div [@myAnimation]="exp"></div> + `, + animations: [trigger('myAnimation', [animate(1000, style({width: '100px'}))])] + }) + class Cmp { + exp: any = false; + } - let errorMsg: string = ''; - try { - fixture.detectChanges(); - } catch (e) { - errorMsg = e.message; - } + TestBed.configureTestingModule({declarations: [Cmp]}); - expect(errorMsg).toMatch(/@foo has failed due to:/); - expect(errorMsg).toMatch(/`query\("foo"\)` returned zero elements/); - expect(errorMsg).toMatch(/@bar has failed due to:/); - expect(errorMsg).toMatch(/`query\("bar"\)` returned zero elements/); - }); + expect(() => { + TestBed.createComponent(Cmp); + }) + .toThrowError( + /only state\(\) and transition\(\) definitions can sit inside of a trigger\(\)/); + }); - it('should not throw an error if styles overlap in separate transitions', () => { - @Component({ - selector: 'if-cmp', - template: ` + it('should combine multiple errors together into one exception when an animation fails to be built', + () => { + @Component({ + selector: 'if-cmp', + template: ` + <div [@foo]="fooExp" [@bar]="barExp"></div> + `, + animations: [ + trigger( + 'foo', + [ + transition(':enter', []), + transition( + '* => *', + [ + query('foo', animate(1000, style({background: 'red'}))), + ]), + ]), + trigger( + 'bar', + [ + transition(':enter', []), + transition( + '* => *', + [ + query('bar', animate(1000, style({background: 'blue'}))), + ]), + ]), + ] + }) + class Cmp { + fooExp: any = false; + barExp: any = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + fixture.detectChanges(); + + cmp.fooExp = 'go'; + cmp.barExp = 'go'; + + let errorMsg: string = ''; + try { + fixture.detectChanges(); + } catch (e) { + errorMsg = e.message; + } + + expect(errorMsg).toMatch(/@foo has failed due to:/); + expect(errorMsg).toMatch(/`query\("foo"\)` returned zero elements/); + expect(errorMsg).toMatch(/@bar has failed due to:/); + expect(errorMsg).toMatch(/`query\("bar"\)` returned zero elements/); + }); + + it('should not throw an error if styles overlap in separate transitions', () => { + @Component({ + selector: 'if-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - 'void => *', - [ - style({opacity: 0}), - animate('0.5s 1s', style({opacity: 1})), - ]), - transition( - '* => void', - [animate(1000, style({height: 0})), animate(1000, style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - exp: any = false; - } + animations: [ + trigger( + 'myAnimation', + [ + transition( + 'void => *', + [ + style({opacity: 0}), + animate('0.5s 1s', style({opacity: 1})), + ]), + transition( + '* => void', + [animate(1000, style({height: 0})), animate(1000, style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + exp: any = false; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - expect(() => { TestBed.createComponent(Cmp); }).not.toThrowError(); - }); + expect(() => { + TestBed.createComponent(Cmp); + }).not.toThrowError(); + }); - modifiedInIvy('FW-952 - Error recovery is handled differently in Ivy than VE') - .it('should continue to clean up DOM-related animation artifacts even if a compiler-level error is thrown midway', - () => { - @Component({ - selector: 'if-cmp', - animations: [ - trigger( - 'foo', - [ - transition('* => something', []), - ]), - ], - template: ` + modifiedInIvy('FW-952 - Error recovery is handled differently in Ivy than VE') + .it('should continue to clean up DOM-related animation artifacts even if a compiler-level error is thrown midway', + () => { + @Component({ + selector: 'if-cmp', + animations: [ + trigger( + 'foo', + [ + transition('* => something', []), + ]), + ], + template: ` value = {{ foo[bar] }} <div #contents> <div *ngIf="exp">1</div> @@ -3756,67 +3757,66 @@ const DEFAULT_COMPONENT_ID = '1'; <div *ngIf="exp" [@foo]="'123'">3</div> </div> `, - }) - class Cmp { - exp: any = false; + }) + class Cmp { + exp: any = false; - @ViewChild('contents', {static: true}) public contents: any; - } + @ViewChild('contents', {static: true}) public contents: any; + } - TestBed.configureTestingModule({declarations: [Cmp]}); + TestBed.configureTestingModule({declarations: [Cmp]}); - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); - const runCD = () => fixture.detectChanges(); - const cmp = fixture.componentInstance; + const runCD = () => fixture.detectChanges(); + const cmp = fixture.componentInstance; - cmp.exp = true; - expect(runCD).toThrow(); + cmp.exp = true; + expect(runCD).toThrow(); - const contents = cmp.contents.nativeElement; - expect(contents.innerText.replace(/\s+/gm, '')).toEqual('123'); + const contents = cmp.contents.nativeElement; + expect(contents.innerText.replace(/\s+/gm, '')).toEqual('123'); - cmp.exp = false; - expect(runCD).toThrow(); + cmp.exp = false; + expect(runCD).toThrow(); - expect(contents.innerText.trim()).toEqual(''); - }); + expect(contents.innerText.trim()).toEqual(''); + }); - describe('errors for not using the animation module', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{provide: RendererFactory2, useExisting: ɵDomRendererFactory2}], - }); + describe('errors for not using the animation module', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [{provide: RendererFactory2, useExisting: ɵDomRendererFactory2}], }); + }); - it('should throw when using an @prop binding without the animation module', () => { - @Component({template: `<div [@myAnimation]="true"></div>`}) - class Cmp { - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - const comp = TestBed.createComponent(Cmp); - expect(() => comp.detectChanges()) - .toThrowError( - 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); - }); + it('should throw when using an @prop binding without the animation module', () => { + @Component({template: `<div [@myAnimation]="true"></div>`}) + class Cmp { + } - it('should throw when using an @prop listener without the animation module', () => { - @Component({template: `<div (@myAnimation.start)="a = true"></div>`}) - class Cmp { - a: any; - } + TestBed.configureTestingModule({declarations: [Cmp]}); + const comp = TestBed.createComponent(Cmp); + expect(() => comp.detectChanges()) + .toThrowError( + 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); + }); - TestBed.configureTestingModule({declarations: [Cmp]}); + it('should throw when using an @prop listener without the animation module', () => { + @Component({template: `<div (@myAnimation.start)="a = true"></div>`}) + class Cmp { + a: any; + } - expect(() => TestBed.createComponent(Cmp)) - .toThrowError( - 'Found the synthetic listener @myAnimation.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); + TestBed.configureTestingModule({declarations: [Cmp]}); - }); + expect(() => TestBed.createComponent(Cmp)) + .toThrowError( + 'Found the synthetic listener @myAnimation.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); }); }); +}); })(); function assertHasParent(element: any, yes: boolean) { diff --git a/packages/core/test/animation/animation_router_integration_spec.ts b/packages/core/test/animation/animation_router_integration_spec.ts index 9a33ef40bbe37..033a8a3eebdb9 100644 --- a/packages/core/test/animation/animation_router_integration_spec.ts +++ b/packages/core/test/animation/animation_router_integration_spec.ts @@ -10,376 +10,377 @@ import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser'; import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine'; import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing'; import {Component, HostBinding} from '@angular/core'; -import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {ActivatedRoute, Router, RouterOutlet} from '@angular/router'; import {RouterTestingModule} from '@angular/router/testing'; (function() { - // these tests are only mean't to be run within the DOM (for now) - if (isNode) return; - - describe('Animation Router Tests', function() { - function getLog(): MockAnimationPlayer[] { - return MockAnimationDriver.log as MockAnimationPlayer[]; - } - - function resetLog() { MockAnimationDriver.log = []; } - - beforeEach(() => { - resetLog(); - TestBed.configureTestingModule({ - imports: [RouterTestingModule, BrowserAnimationsModule], - providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}] - }); +// these tests are only mean't to be run within the DOM (for now) +if (isNode) return; + +describe('Animation Router Tests', function() { + function getLog(): MockAnimationPlayer[] { + return MockAnimationDriver.log as MockAnimationPlayer[]; + } + + function resetLog() { + MockAnimationDriver.log = []; + } + + beforeEach(() => { + resetLog(); + TestBed.configureTestingModule({ + imports: [RouterTestingModule, BrowserAnimationsModule], + providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}] }); + }); - it('should query the old and new routes via :leave and :enter', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':leave', animateChild()), - query(':enter', animateChild()), - ]), - ]), - ], - template: ` + it('should query the old and new routes via :leave and :enter', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':leave', animateChild()), + query(':enter', animateChild()), + ]), + ]), + ], + template: ` <div [@routerAnimations]="prepareRouteAnimation(r)"> <router-outlet #r="outlet"></router-outlet> </div> ` - }) - class ContainerCmp { - constructor(public router: Router) {} - - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } - } - - @Component({ - selector: 'page1', - template: `page1`, - animations: [ - trigger( - 'page1Animation', - [ - transition( - ':leave', - [ - style({width: '200px'}), - animate(1000, style({width: '0px'})), - ]), - ]), - ] - }) - class Page1Cmp { - @HostBinding('@page1Animation') public doAnimate = true; - } - - @Component({ - selector: 'page2', - template: `page2`, - animations: [ - trigger( - 'page2Animation', - [ - transition( - ':enter', - [ - style({opacity: 0}), - animate(1000, style({opacity: 1})), - ]), - ]), - ] - }) - class Page2Cmp { - @HostBinding('@page2Animation') public doAnimate = true; + }) + class ContainerCmp { + constructor(public router: Router) {} + + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; } - - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); - - const player = engine.players[0] !; - const groupPlayer = - (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; - - expect(players.length).toEqual(2); - const [p1, p2] = players; - - expect(p1.duration).toEqual(1000); - expect(p1.keyframes).toEqual([ - {offset: 0, width: '200px'}, - {offset: 1, width: '0px'}, - ]); - - expect(p2.duration).toEqual(2000); - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: .5, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - })); - - it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':enter', animateChild()), - ]), - ]), - ], - template: ` + } + + @Component({ + selector: 'page1', + template: `page1`, + animations: [ + trigger( + 'page1Animation', + [ + transition( + ':leave', + [ + style({width: '200px'}), + animate(1000, style({width: '0px'})), + ]), + ]), + ] + }) + class Page1Cmp { + @HostBinding('@page1Animation') public doAnimate = true; + } + + @Component({ + selector: 'page2', + template: `page2`, + animations: [ + trigger( + 'page2Animation', + [ + transition( + ':enter', + [ + style({opacity: 0}), + animate(1000, style({opacity: 1})), + ]), + ]), + ] + }) + class Page2Cmp { + @HostBinding('@page2Animation') public doAnimate = true; + } + + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); + + const player = engine.players[0]!; + const groupPlayer = + (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; + + expect(players.length).toEqual(2); + const [p1, p2] = players; + + expect(p1.duration).toEqual(1000); + expect(p1.keyframes).toEqual([ + {offset: 0, width: '200px'}, + {offset: 1, width: '0px'}, + ]); + + expect(p2.duration).toEqual(2000); + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: .5, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + })); + + it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':enter', animateChild()), + ]), + ]), + ], + template: ` <div [@routerAnimations]="prepareRouteAnimation(r)"> <router-outlet #r="outlet"></router-outlet> </div> ` - }) - class ContainerCmp { - constructor(public router: Router) {} - - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } + }) + class ContainerCmp { + constructor(public router: Router) {} + + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; } + } - @Component({selector: 'page1', template: `page1`, animations: []}) - class Page1Cmp { - } + @Component({selector: 'page1', template: `page1`, animations: []}) + class Page1Cmp { + } - @Component({ - selector: 'page2', - template: ` + @Component({ + selector: 'page2', + template: ` <h1>Page 2</h1> <div *ngIf="exp" class="if-one" @ifAnimation></div> <div *ngIf="exp" class="if-two" @ifAnimation></div> `, - animations: [ - trigger( - 'page2Animation', - [ - transition( - ':enter', - [query('.if-one', animateChild()), query('.if-two', animateChild())]), - ]), - trigger( - 'ifAnimation', - [transition( - ':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) - ] - }) - class Page2Cmp { - @HostBinding('@page2Animation') public doAnimate = true; - - public exp = true; - } - - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); - - const player = engine.players[0] !; - const groupPlayer = - (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; - - expect(players.length).toEqual(2); - const [p1, p2] = players; - - expect(p1.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '0'}, - {offset: .5, opacity: '0'}, - {offset: 1, opacity: '1'}, - ]); - })); - - it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { - @Component({ - animations: [ - trigger( - 'routerAnimations', - [ - transition( - 'page1 => page2', - [ - query(':leave', animateChild()), - ]), - ]), - ], - template: ` + animations: [ + trigger( + 'page2Animation', + [ + transition( + ':enter', + [query('.if-one', animateChild()), query('.if-two', animateChild())]), + ]), + trigger( + 'ifAnimation', + [transition(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])]) + ] + }) + class Page2Cmp { + @HostBinding('@page2Animation') public doAnimate = true; + + public exp = true; + } + + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); + + const player = engine.players[0]!; + const groupPlayer = + (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; + + expect(players.length).toEqual(2); + const [p1, p2] = players; + + expect(p1.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '0'}, + {offset: .5, opacity: '0'}, + {offset: 1, opacity: '1'}, + ]); + })); + + it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => { + @Component({ + animations: [ + trigger( + 'routerAnimations', + [ + transition( + 'page1 => page2', + [ + query(':leave', animateChild()), + ]), + ]), + ], + template: ` <div [@routerAnimations]="prepareRouteAnimation(r)"> <router-outlet #r="outlet"></router-outlet> </div> ` - }) - class ContainerCmp { - constructor(public router: Router) {} - - prepareRouteAnimation(r: RouterOutlet) { - const animation = r.activatedRouteData['animation']; - const value = animation ? animation['value'] : null; - return value; - } + }) + class ContainerCmp { + constructor(public router: Router) {} + + prepareRouteAnimation(r: RouterOutlet) { + const animation = r.activatedRouteData['animation']; + const value = animation ? animation['value'] : null; + return value; } + } - @Component({ - selector: 'page1', - template: ` + @Component({ + selector: 'page1', + template: ` <h1>Page 1</h1> <div *ngIf="exp" class="if-one" @ifAnimation></div> <div *ngIf="exp" class="if-two" @ifAnimation></div> `, - animations: [ - trigger( - 'page1Animation', - [ - transition( - ':leave', - [query('.if-one', animateChild()), query('.if-two', animateChild())]), - ]), - trigger( - 'ifAnimation', - [transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]), - ] - }) - class Page1Cmp { - @HostBinding('@page1Animation') public doAnimate = true; - - public exp = true; - } - - @Component({selector: 'page2', template: `page2`, animations: []}) - class Page2Cmp { - } - - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page1'); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page2'); - tick(); - fixture.detectChanges(); - engine.flush(); - - const player = engine.players[0] !; - const groupPlayer = - (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; - const players = groupPlayer.players as MockAnimationPlayer[]; - - expect(players.length).toEqual(2); - const [p1, p2] = players; - - expect(p1.keyframes).toEqual([ - {offset: 0, opacity: '1'}, - {offset: 1, opacity: '0'}, - ]); - - expect(p2.keyframes).toEqual([ - {offset: 0, opacity: '1'}, - {offset: .5, opacity: '1'}, - {offset: 1, opacity: '0'}, - ]); - })); - - it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', - fakeAsync(() => { - @Component({ - selector: 'ani-cmp', - animations: [ - trigger( - 'pageAnimation', - [ - transition( - 'page1 => page2', - [ - query('.router-container :leave', animate('1s', style({opacity: 0}))), - query('.router-container :enter', animate('1s', style({opacity: 1}))), - ]), - ]), - ], - template: ` + animations: [ + trigger( + 'page1Animation', + [ + transition( + ':leave', + [query('.if-one', animateChild()), query('.if-two', animateChild())]), + ]), + trigger( + 'ifAnimation', + [transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]), + ] + }) + class Page1Cmp { + @HostBinding('@page1Animation') public doAnimate = true; + + public exp = true; + } + + @Component({selector: 'page2', template: `page2`, animations: []}) + class Page2Cmp { + } + + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page1'); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page2'); + tick(); + fixture.detectChanges(); + engine.flush(); + + const player = engine.players[0]!; + const groupPlayer = + (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; + const players = groupPlayer.players as MockAnimationPlayer[]; + + expect(players.length).toEqual(2); + const [p1, p2] = players; + + expect(p1.keyframes).toEqual([ + {offset: 0, opacity: '1'}, + {offset: 1, opacity: '0'}, + ]); + + expect(p2.keyframes).toEqual([ + {offset: 0, opacity: '1'}, + {offset: .5, opacity: '1'}, + {offset: 1, opacity: '0'}, + ]); + })); + + it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries', + fakeAsync(() => { + @Component({ + selector: 'ani-cmp', + animations: [ + trigger( + 'pageAnimation', + [ + transition( + 'page1 => page2', + [ + query('.router-container :leave', animate('1s', style({opacity: 0}))), + query('.router-container :enter', animate('1s', style({opacity: 1}))), + ]), + ]), + ], + template: ` <div [@pageAnimation]="prepRoute(outlet)"> <header> <div class="inner"> @@ -392,138 +393,144 @@ import {RouterTestingModule} from '@angular/router/testing'; </section> </div> ` - }) - class ContainerCmp { - loading = false; + }) + class ContainerCmp { + loading = false; - constructor(public router: Router) {} - - prepRoute(outlet: any) { return outlet.activatedRouteData['animation']; } - } + constructor(public router: Router) {} - @Component({selector: 'page1', template: `page1`}) - class Page1Cmp { + prepRoute(outlet: any) { + return outlet.activatedRouteData['animation']; } - - @Component({selector: 'page2', template: `page2`}) - class Page2Cmp { + } + + @Component({selector: 'page1', template: `page1`}) + class Page1Cmp { + } + + @Component({selector: 'page2', template: `page2`}) + class Page2Cmp { + } + + TestBed.configureTestingModule({ + declarations: [Page1Cmp, Page2Cmp, ContainerCmp], + imports: [RouterTestingModule.withRoutes([ + {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, + {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} + ])] + }); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.router.initialNavigation(); + tick(); + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page1'); + tick(); + cmp.loading = true; + fixture.detectChanges(); + engine.flush(); + + cmp.router.navigateByUrl('/page2'); + tick(); + cmp.loading = false; + fixture.detectChanges(); + engine.flush(); + + const players = engine.players; + expect(players.length).toEqual(1); + const [p1] = players; + + const innerPlayers = + ((p1 as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players; + expect(innerPlayers.length).toEqual(2); + + const [ip1, ip2] = innerPlayers as any; + expect(ip1.element.innerText).toEqual('page1'); + expect(ip2.element.innerText).toEqual('page2'); + })); + + it('should allow a recursive set of :leave animations to occur for nested routes', + fakeAsync(() => { + @Component({selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'}) + class ContainerCmp { + constructor(private _router: Router) {} + log: string[] = []; + + enter() { + this._router.navigateByUrl('/(recur:recur/nested)'); } - TestBed.configureTestingModule({ - declarations: [Page1Cmp, Page2Cmp, ContainerCmp], - imports: [RouterTestingModule.withRoutes([ - {path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')}, - {path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')} - ])] - }); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.router.initialNavigation(); - tick(); - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page1'); - tick(); - cmp.loading = true; - fixture.detectChanges(); - engine.flush(); - - cmp.router.navigateByUrl('/page2'); - tick(); - cmp.loading = false; - fixture.detectChanges(); - engine.flush(); - - const players = engine.players; - expect(players.length).toEqual(1); - const [p1] = players; - - const innerPlayers = - ((p1 as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players; - expect(innerPlayers.length).toEqual(2); - - const [ip1, ip2] = innerPlayers as any; - expect(ip1.element.innerText).toEqual('page1'); - expect(ip2.element.innerText).toEqual('page2'); - })); - - it('should allow a recursive set of :leave animations to occur for nested routes', - fakeAsync(() => { - @Component({selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'}) - class ContainerCmp { - constructor(private _router: Router) {} - log: string[] = []; - - enter() { this._router.navigateByUrl('/(recur:recur/nested)'); } - - leave() { this._router.navigateByUrl('/'); } + leave() { + this._router.navigateByUrl('/'); } - - @Component({ - selector: 'recur-page', - template: 'Depth: {{ depth }} \n <router-outlet></router-outlet>', - animations: [ - trigger( - 'pageAnimations', - [ - transition(':leave', [group([ - sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), - query('@*', animateChild(), {optional: true}) - ])]), - ]), - ] - }) - class RecurPageCmp { - @HostBinding('@pageAnimations') public animatePage = true; - - @HostBinding('attr.data-depth') public depth = 0; - - constructor(private container: ContainerCmp, private route: ActivatedRoute) { - this.route.data.subscribe(data => { - this.container.log.push(`DEPTH ${data.depth}`); - this.depth = data.depth; - }); - } + } + + @Component({ + selector: 'recur-page', + template: 'Depth: {{ depth }} \n <router-outlet></router-outlet>', + animations: [ + trigger( + 'pageAnimations', + [ + transition(':leave', [group([ + sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]), + query('@*', animateChild(), {optional: true}) + ])]), + ]), + ] + }) + class RecurPageCmp { + @HostBinding('@pageAnimations') public animatePage = true; + + @HostBinding('attr.data-depth') public depth = 0; + + constructor(private container: ContainerCmp, private route: ActivatedRoute) { + this.route.data.subscribe(data => { + this.container.log.push(`DEPTH ${data.depth}`); + this.depth = data.depth; + }); } - - TestBed.configureTestingModule({ - declarations: [ContainerCmp, RecurPageCmp], - imports: [RouterTestingModule.withRoutes([{ - path: 'recur', - component: RecurPageCmp, - outlet: 'recur', - data: {depth: 0}, - children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}] - }])] - }); - - const fixture = TestBed.createComponent(ContainerCmp); - const cmp = fixture.componentInstance; - cmp.enter(); - tick(); - fixture.detectChanges(); - flushMicrotasks(); - - expect(cmp.log).toEqual([ - 'DEPTH 0', - 'DEPTH 1', - ]); - - cmp.leave(); - tick(); - fixture.detectChanges(); - - const players = getLog(); - expect(players.length).toEqual(2); - - const [p1, p2] = players; - expect(p1.element.getAttribute('data-depth')).toEqual('0'); - expect(p2.element.getAttribute('data-depth')).toEqual('1'); - })); - }); + } + + TestBed.configureTestingModule({ + declarations: [ContainerCmp, RecurPageCmp], + imports: [RouterTestingModule.withRoutes([{ + path: 'recur', + component: RecurPageCmp, + outlet: 'recur', + data: {depth: 0}, + children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}] + }])] + }); + + const fixture = TestBed.createComponent(ContainerCmp); + const cmp = fixture.componentInstance; + cmp.enter(); + tick(); + fixture.detectChanges(); + flushMicrotasks(); + + expect(cmp.log).toEqual([ + 'DEPTH 0', + 'DEPTH 1', + ]); + + cmp.leave(); + tick(); + fixture.detectChanges(); + + const players = getLog(); + expect(players.length).toEqual(2); + + const [p1, p2] = players; + expect(p1.element.getAttribute('data-depth')).toEqual('0'); + expect(p2.element.getAttribute('data-depth')).toEqual('1'); + })); +}); }); function makeAnimationData(value: string, params: {[key: string]: any} = {}): {[key: string]: any} { diff --git a/packages/core/test/animation/animations_with_css_keyframes_animations_integration_spec.ts b/packages/core/test/animation/animations_with_css_keyframes_animations_integration_spec.ts index 9590b533449ac..5bb6822b049e0 100644 --- a/packages/core/test/animation/animations_with_css_keyframes_animations_integration_spec.ts +++ b/packages/core/test/animation/animations_with_css_keyframes_animations_integration_spec.ts @@ -15,23 +15,22 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut import {TestBed} from '../../testing'; (function() { - // these tests are only mean't to be run within the DOM (for now) - // Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793 - if (isNode) return; - - describe('animation integration tests using css keyframe animations', function() { - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: CssKeyframesDriver}], - imports: [BrowserAnimationsModule] - }); +// these tests are only mean't to be run within the DOM (for now) +// Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793 +if (isNode) return; + +describe('animation integration tests using css keyframe animations', function() { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: CssKeyframesDriver}], + imports: [BrowserAnimationsModule] }); + }); - it('should compute (*) animation styles for a container that is being removed', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should compute (*) animation styles for a container that is being removed', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @auto *ngIf="exp"> <div style="line-height:20px;">1</div> <div style="line-height:20px;">2</div> @@ -40,46 +39,46 @@ import {TestBed} from '../../testing'; <div style="line-height:20px;">5</div> </div> `, - animations: [trigger( - 'auto', - [ - state('void', style({height: '0px'})), - state('*', style({height: '*'})), - transition('* => *', animate(1000)), - ])] - }) - class Cmp { - public exp: boolean = false; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = true; - fixture.detectChanges(); - - expect(engine.players.length).toEqual(1); - let player = getPlayer(engine) as CssKeyframesPlayer; - expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]); - - player.finish(); - if (browserDetection.isOldChrome) return; - - cmp.exp = false; - fixture.detectChanges(); - - player = getPlayer(engine) as CssKeyframesPlayer; - expect(player.keyframes).toEqual([{height: '100px', offset: 0}, {height: '0px', offset: 1}]); - }); + animations: [trigger( + 'auto', + [ + state('void', style({height: '0px'})), + state('*', style({height: '*'})), + transition('* => *', animate(1000)), + ])] + }) + class Cmp { + public exp: boolean = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); + + expect(engine.players.length).toEqual(1); + let player = getPlayer(engine) as CssKeyframesPlayer; + expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]); + + player.finish(); + if (browserDetection.isOldChrome) return; + + cmp.exp = false; + fixture.detectChanges(); + + player = getPlayer(engine) as CssKeyframesPlayer; + expect(player.keyframes).toEqual([{height: '100px', offset: 0}, {height: '0px', offset: 1}]); + }); - it('should cleanup all existing @keyframe <style> objects after the animation has finished', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should cleanup all existing @keyframe <style> objects after the animation has finished', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="myAnimationExp"> <div>1</div> <div>2</div> @@ -88,278 +87,278 @@ import {TestBed} from '../../testing'; <div>5</div> </div> `, - animations: [trigger( - 'myAnimation', - [ - transition( - '* => go', - [ - query( - 'div', - [ - style({opacity: 0}), - animate('1s', style({opacity: 0})), - ]), - ]), - ])] - }) - class Cmp { - public myAnimationExp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.myAnimationExp = 'go'; - fixture.detectChanges(); - - const webPlayer = <AnimationGroupPlayer>getPlayer(engine); - const players = webPlayer.players as CssKeyframesPlayer[]; - expect(players.length).toEqual(5); - - const head = document.querySelector('head') !; - const sheets: any[] = []; - for (let i = 0; i < 5; i++) { - const sheet = findStyleObjectWithKeyframes(i); - expect(head.contains(sheet)).toBeTruthy(); - sheets.push(sheet); - } - - cmp.myAnimationExp = 'go-back'; - fixture.detectChanges(); - - for (let i = 0; i < 5; i++) { - expect(head.contains(sheets[i])).toBeFalsy(); - } - }); - - it('should properly handle easing values that are apart of the sequence', () => { - @Component({ - selector: 'ani-cmp', - template: ` + animations: [trigger( + 'myAnimation', + [ + transition( + '* => go', + [ + query( + 'div', + [ + style({opacity: 0}), + animate('1s', style({opacity: 0})), + ]), + ]), + ])] + }) + class Cmp { + public myAnimationExp = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.myAnimationExp = 'go'; + fixture.detectChanges(); + + const webPlayer = <AnimationGroupPlayer>getPlayer(engine); + const players = webPlayer.players as CssKeyframesPlayer[]; + expect(players.length).toEqual(5); + + const head = document.querySelector('head')!; + const sheets: any[] = []; + for (let i = 0; i < 5; i++) { + const sheet = findStyleObjectWithKeyframes(i); + expect(head.contains(sheet)).toBeTruthy(); + sheets.push(sheet); + } + + cmp.myAnimationExp = 'go-back'; + fixture.detectChanges(); + + for (let i = 0; i < 5; i++) { + expect(head.contains(sheets[i])).toBeFalsy(); + } + }); + + it('should properly handle easing values that are apart of the sequence', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #elm [@myAnimation]="myAnimationExp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => goSteps', - [ - style({opacity: 0}), - animate('1s ease-out', style({opacity: 1})), - ]), - transition( - '* => goKeyframes', - [ - animate('1s cubic-bezier(0.5, 1, 0.5, 1)', keyframes([ - style({opacity: 0}), - style({opacity: 0.5}), - style({opacity: 1}), - ])), - ]), - ]), - ] - }) - class Cmp { - @ViewChild('elm') public element: any; - - public myAnimationExp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.myAnimationExp = 'goSteps'; - fixture.detectChanges(); - - let kfElm = findStyleObjectWithKeyframes(); - const [r1, r2] = kfElm.sheet.cssRules[0].cssRules; - assertEasing(r1, 'ease-out'); - assertEasing(r2, ''); - - const element = cmp.element.nativeElement; - - const webPlayer = getPlayer(engine); - cmp.myAnimationExp = 'goKeyframes'; - fixture.detectChanges(); - - assertEasing(element, 'cubic-bezier(0.5,1,0.5,1)'); - }); + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => goSteps', + [ + style({opacity: 0}), + animate('1s ease-out', style({opacity: 1})), + ]), + transition( + '* => goKeyframes', + [ + animate('1s cubic-bezier(0.5, 1, 0.5, 1)', keyframes([ + style({opacity: 0}), + style({opacity: 0.5}), + style({opacity: 1}), + ])), + ]), + ]), + ] + }) + class Cmp { + @ViewChild('elm') public element: any; + + public myAnimationExp = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.myAnimationExp = 'goSteps'; + fixture.detectChanges(); + + let kfElm = findStyleObjectWithKeyframes(); + const [r1, r2] = kfElm.sheet.cssRules[0].cssRules; + assertEasing(r1, 'ease-out'); + assertEasing(r2, ''); + + const element = cmp.element.nativeElement; + + const webPlayer = getPlayer(engine); + cmp.myAnimationExp = 'goKeyframes'; + fixture.detectChanges(); + + assertEasing(element, 'cubic-bezier(0.5,1,0.5,1)'); + }); - it('should restore existing style values once the animation completes', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should restore existing style values once the animation completes', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #elm [@myAnimation]="myAnimationExp"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('go', style({width: '200px'})), - transition( - '* => go', - [ - style({height: '100px', width: '100px'}), group([ - animate('1s', style({height: '200px'})), - animate('1s', style({width: '200px'})) - ]) - ]), - ]), - ] - }) - class Cmp { - @ViewChild('elm') public element: any; - - public myAnimationExp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - fixture.detectChanges(); - const element = cmp.element.nativeElement; - element.style['width'] = '50px'; - element.style['height'] = '50px'; - - assertStyle(element, 'width', '50px'); - assertStyle(element, 'height', '50px'); - - cmp.myAnimationExp = 'go'; - fixture.detectChanges(); - - const player = getPlayer(engine); - - assertStyle(element, 'width', '100px'); - assertStyle(element, 'height', '100px'); - - player.finish(); - - assertStyle(element, 'width', '200px'); - assertStyle(element, 'height', '50px'); - }); + animations: [ + trigger( + 'myAnimation', + [ + state('go', style({width: '200px'})), + transition( + '* => go', + [ + style({height: '100px', width: '100px'}), group([ + animate('1s', style({height: '200px'})), + animate('1s', style({width: '200px'})) + ]) + ]), + ]), + ] + }) + class Cmp { + @ViewChild('elm') public element: any; + + public myAnimationExp = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + fixture.detectChanges(); + const element = cmp.element.nativeElement; + element.style['width'] = '50px'; + element.style['height'] = '50px'; + + assertStyle(element, 'width', '50px'); + assertStyle(element, 'height', '50px'); + + cmp.myAnimationExp = 'go'; + fixture.detectChanges(); + + const player = getPlayer(engine); + + assertStyle(element, 'width', '100px'); + assertStyle(element, 'height', '100px'); + + player.finish(); + + assertStyle(element, 'width', '200px'); + assertStyle(element, 'height', '50px'); + }); - it('should clean up 0 second animation styles (queried styles) that contain camel casing when complete', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should clean up 0 second animation styles (queried styles) that contain camel casing when complete', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #elm [@myAnimation]="myAnimationExp"> <div class="foo"></div> <div class="bar"></div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('go', style({width: '200px'})), - transition( - '* => go', - [ - query('.foo', [style({maxHeight: '0px'})]), - query( - '.bar', - [ - style({width: '0px'}), - animate('1s', style({width: '100px'})), - ]), - ]), - ]), - ] - }) - class Cmp { - @ViewChild('elm', {static: true}) public element: any; - - public myAnimationExp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - const elm = cmp.element.nativeElement; - const foo = elm.querySelector('.foo') as HTMLElement; - - cmp.myAnimationExp = 'go'; - fixture.detectChanges(); - - expect(foo.style.getPropertyValue('max-height')).toEqual('0px'); - - const player = engine.players.pop() !; - player.finish(); - - expect(foo.style.getPropertyValue('max-height')).toBeFalsy(); - }); - - it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + animations: [ + trigger( + 'myAnimation', + [ + state('go', style({width: '200px'})), + transition( + '* => go', + [ + query('.foo', [style({maxHeight: '0px'})]), + query( + '.bar', + [ + style({width: '0px'}), + animate('1s', style({width: '100px'})), + ]), + ]), + ]), + ] + }) + class Cmp { + @ViewChild('elm', {static: true}) public element: any; + + public myAnimationExp = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + const elm = cmp.element.nativeElement; + const foo = elm.querySelector('.foo') as HTMLElement; + + cmp.myAnimationExp = 'go'; + fixture.detectChanges(); + + expect(foo.style.getPropertyValue('max-height')).toEqual('0px'); + + const player = engine.players.pop()!; + player.finish(); + + expect(foo.style.getPropertyValue('max-height')).toBeFalsy(); + }); + + it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #elm [@myAnimation]="myAnimationExp" style="display:table; position:fixed"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('go', style({display: 'inline-block'})), - transition( - '* => go', - [ - style({display: 'inline', position: 'absolute', opacity: 0}), - animate('1s', style({display: 'inline', opacity: 1, position: 'static'})), - animate('1s', style({display: 'flexbox', opacity: 0})), - ]) - ]), - ] - }) - class Cmp { - @ViewChild('elm', {static: true}) public element: any; - - public myAnimationExp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - const elm = cmp.element.nativeElement; - expect(elm.style.getPropertyValue('display')).toEqual('table'); - expect(elm.style.getPropertyValue('position')).toEqual('fixed'); - - cmp.myAnimationExp = 'go'; - fixture.detectChanges(); - - expect(elm.style.getPropertyValue('display')).toEqual('inline'); - expect(elm.style.getPropertyValue('position')).toEqual('absolute'); - - const player = engine.players.pop() !; - player.finish(); - player.destroy(); - - expect(elm.style.getPropertyValue('display')).toEqual('inline-block'); - expect(elm.style.getPropertyValue('position')).toEqual('fixed'); - }); - }); + animations: [ + trigger( + 'myAnimation', + [ + state('go', style({display: 'inline-block'})), + transition( + '* => go', + [ + style({display: 'inline', position: 'absolute', opacity: 0}), + animate('1s', style({display: 'inline', opacity: 1, position: 'static'})), + animate('1s', style({display: 'flexbox', opacity: 0})), + ]) + ]), + ] + }) + class Cmp { + @ViewChild('elm', {static: true}) public element: any; + + public myAnimationExp = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + const elm = cmp.element.nativeElement; + expect(elm.style.getPropertyValue('display')).toEqual('table'); + expect(elm.style.getPropertyValue('position')).toEqual('fixed'); + + cmp.myAnimationExp = 'go'; + fixture.detectChanges(); + + expect(elm.style.getPropertyValue('display')).toEqual('inline'); + expect(elm.style.getPropertyValue('position')).toEqual('absolute'); + + const player = engine.players.pop()!; + player.finish(); + player.destroy(); + + expect(elm.style.getPropertyValue('display')).toEqual('inline-block'); + expect(elm.style.getPropertyValue('position')).toEqual('fixed'); + }); +}); })(); function getPlayer(engine: AnimationEngine, index = 0) { - return (engine.players[index] as any) !.getRealPlayer(); + return (engine.players[index] as any)!.getRealPlayer(); } function findStyleObjectWithKeyframes(index?: number): any|null { diff --git a/packages/core/test/animation/animations_with_web_animations_integration_spec.ts b/packages/core/test/animation/animations_with_web_animations_integration_spec.ts index eee0c9307b2a7..dbda33c59e6e9 100644 --- a/packages/core/test/animation/animations_with_web_animations_integration_spec.ts +++ b/packages/core/test/animation/animations_with_web_animations_integration_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {animate, query, state, style, transition, trigger} from '@angular/animations'; -import {AnimationDriver, ɵAnimationEngine, ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser'; +import {AnimationDriver, ɵAnimationEngine, ɵsupportsWebAnimations, ɵWebAnimationsDriver, ɵWebAnimationsPlayer} from '@angular/animations/browser'; import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine'; import {AnimationGroupPlayer} from '@angular/animations/src/players/animation_group_player'; import {Component, ViewChild} from '@angular/core'; @@ -15,23 +15,22 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; (function() { - // these tests are only mean't to be run within the DOM (for now) - // Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793 - if (isNode || !ɵsupportsWebAnimations()) return; - - describe('animation integration tests using web animations', function() { - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{provide: AnimationDriver, useClass: ɵWebAnimationsDriver}], - imports: [BrowserAnimationsModule] - }); +// these tests are only mean't to be run within the DOM (for now) +// Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793 +if (isNode || !ɵsupportsWebAnimations()) return; + +describe('animation integration tests using web animations', function() { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [{provide: AnimationDriver, useClass: ɵWebAnimationsDriver}], + imports: [BrowserAnimationsModule] }); + }); - it('should compute (*) animation styles for a container that is being removed', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should compute (*) animation styles for a container that is being removed', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @auto *ngIf="exp"> <div style="line-height:20px;">1</div> <div style="line-height:20px;">2</div> @@ -40,55 +39,53 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut <div style="line-height:20px;">5</div> </div> `, - animations: [trigger( - 'auto', - [ - state('void', style({height: '0px'})), state('*', style({height: '*'})), - transition('* => *', animate(1000)) - ])] - }) - class Cmp { - public exp: boolean = false; - } + animations: [trigger( + 'auto', + [ + state('void', style({height: '0px'})), state('*', style({height: '*'})), + transition('* => *', animate(1000)) + ])] + }) + class Cmp { + public exp: boolean = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); - TestBed.configureTestingModule({declarations: [Cmp]}); + expect(engine.players.length).toEqual(1); + let webPlayer = + (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + expect(webPlayer.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]); - cmp.exp = true; + webPlayer.finish(); + + if (!browserDetection.isOldChrome) { + cmp.exp = false; fixture.detectChanges(); + engine.flush(); expect(engine.players.length).toEqual(1); - let webPlayer = + webPlayer = (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; expect(webPlayer.keyframes).toEqual([ - {height: '0px', offset: 0}, {height: '100px', offset: 1} + {height: '100px', offset: 0}, {height: '0px', offset: 1} ]); + } + }); - webPlayer.finish(); - - if (!browserDetection.isOldChrome) { - cmp.exp = false; - fixture.detectChanges(); - engine.flush(); - - expect(engine.players.length).toEqual(1); - webPlayer = (engine.players[0] as TransitionAnimationPlayer) - .getRealPlayer() as ɵWebAnimationsPlayer; - - expect(webPlayer.keyframes).toEqual([ - {height: '100px', offset: 0}, {height: '0px', offset: 1} - ]); - } - }); - - it('should compute (!) animation styles for a container that is being inserted', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should compute (!) animation styles for a container that is being inserted', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div @auto *ngIf="exp"> <div style="line-height:20px;">1</div> <div style="line-height:20px;">2</div> @@ -97,95 +94,92 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut <div style="line-height:20px;">5</div> </div> `, - animations: [trigger( - 'auto', - [transition( - ':enter', [style({height: '!'}), animate(1000, style({height: '120px'}))])])] - }) - class Cmp { - public exp: boolean = false; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = true; - fixture.detectChanges(); - engine.flush(); - - expect(engine.players.length).toEqual(1); - let webPlayer = - (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - - expect(webPlayer.keyframes).toEqual([ - {height: '100px', offset: 0}, {height: '120px', offset: 1} - ]); - }); + animations: [trigger( + 'auto', + [transition(':enter', [style({height: '!'}), animate(1000, style({height: '120px'}))])])] + }) + class Cmp { + public exp: boolean = false; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); + engine.flush(); + + expect(engine.players.length).toEqual(1); + let webPlayer = + (engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + + expect(webPlayer.keyframes).toEqual([ + {height: '100px', offset: 0}, {height: '120px', offset: 1} + ]); + }); - it('should compute pre (!) and post (*) animation styles with different dom states', () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should compute pre (!) and post (*) animation styles with different dom states', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp" #parent> <div *ngFor="let item of items" class="child" style="line-height:20px"> - {{ item }} </div> </div> `, - animations: [trigger( - 'myAnimation', - [transition('* => *', [style({height: '!'}), animate(1000, style({height: '*'}))])])] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: number; - public items = [0, 1, 2, 3, 4]; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 1; - fixture.detectChanges(); - engine.flush(); - - expect(engine.players.length).toEqual(1); - let player = engine.players[0]; - let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - - expect(webPlayer.keyframes).toEqual([ - {height: '0px', offset: 0}, {height: '100px', offset: 1} - ]); - - // we destroy the player because since it has started and is - // at 0ms duration a height value of `0px` will be extracted - // from the element and passed into the follow-up animation. - player.destroy(); - - cmp.exp = 2; - cmp.items = [0, 1, 2, 6]; - fixture.detectChanges(); - engine.flush(); - - expect(engine.players.length).toEqual(1); - player = engine.players[0]; - webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - - expect(webPlayer.keyframes).toEqual([ - {height: '100px', offset: 0}, {height: '80px', offset: 1} - ]); - }); + animations: [trigger( + 'myAnimation', + [transition('* => *', [style({height: '!'}), animate(1000, style({height: '*'}))])])] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp!: number; + public items = [0, 1, 2, 3, 4]; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 1; + fixture.detectChanges(); + engine.flush(); + + expect(engine.players.length).toEqual(1); + let player = engine.players[0]; + let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + + expect(webPlayer.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]); + + // we destroy the player because since it has started and is + // at 0ms duration a height value of `0px` will be extracted + // from the element and passed into the follow-up animation. + player.destroy(); + + cmp.exp = 2; + cmp.items = [0, 1, 2, 6]; + fixture.detectChanges(); + engine.flush(); + + expect(engine.players.length).toEqual(1); + player = engine.players[0]; + webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + + expect(webPlayer.keyframes).toEqual([ + {height: '100px', offset: 0}, {height: '80px', offset: 1} + ]); + }); - it('should treat * styles as ! when a removal animation is being rendered', () => { - @Component({ - selector: 'ani-cmp', - styles: [` + it('should treat * styles as ! when a removal animation is being rendered', () => { + @Component({ + selector: 'ani-cmp', + styles: [` .box { width: 500px; overflow:hidden; @@ -195,58 +189,60 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut text-align:center; } `], - template: ` + template: ` <button (click)="toggle()">Open / Close</button> <hr /> <div *ngIf="exp" @slide class="box"> ... </div> `, - animations: [trigger( - 'slide', - [ - state('void', style({height: '0px'})), - state('*', style({height: '*'})), - transition('* => *', animate('500ms')), - ])] - }) - class Cmp { - exp = false; - - toggle() { this.exp = !this.exp; } + animations: [trigger( + 'slide', + [ + state('void', style({height: '0px'})), + state('*', style({height: '*'})), + transition('* => *', animate('500ms')), + ])] + }) + class Cmp { + exp = false; + + toggle() { + this.exp = !this.exp; } + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = true; + fixture.detectChanges(); + + let player = engine.players[0]!; + let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + expect(webPlayer.keyframes).toEqual([ + {height: '0px', offset: 0}, + {height: '300px', offset: 1}, + ]); + player.finish(); + + cmp.exp = false; + fixture.detectChanges(); + + player = engine.players[0]!; + webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + expect(webPlayer.keyframes).toEqual([ + {height: '300px', offset: 0}, + {height: '0px', offset: 1}, + ]); + }); - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = true; - fixture.detectChanges(); - - let player = engine.players[0] !; - let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - expect(webPlayer.keyframes).toEqual([ - {height: '0px', offset: 0}, - {height: '300px', offset: 1}, - ]); - player.finish(); - - cmp.exp = false; - fixture.detectChanges(); - - player = engine.players[0] !; - webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - expect(webPlayer.keyframes).toEqual([ - {height: '300px', offset: 0}, - {height: '0px', offset: 1}, - ]); - }); - - it('should treat * styles as ! for queried items that are collected in a container that is being removed', - () => { - @Component({ + it('should treat * styles as ! for queried items that are collected in a container that is being removed', + () => { + @Component({ selector: 'my-app', styles: [` .list .outer { @@ -287,235 +283,236 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut ] }) class Cmp { - items: any[] = []; + items: any[] = []; - get exp() { return this.items.length ? 'full' : 'empty'; } - - empty() { this.items = []; } - - full() { this.items = [0, 1, 2, 3, 4]; } + get exp() { + return this.items.length ? 'full' : 'empty'; } - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.empty(); - fixture.detectChanges(); - let player = engine.players[0] !as TransitionAnimationPlayer; - player.finish(); - - cmp.full(); - fixture.detectChanges(); - - player = engine.players[0] !as TransitionAnimationPlayer; - let queriedPlayers = - ((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer) - .players; - expect(queriedPlayers.length).toEqual(5); - - let i = 0; - for (i = 0; i < queriedPlayers.length; i++) { - let player = queriedPlayers[i] as ɵWebAnimationsPlayer; - expect(player.keyframes).toEqual([ - {height: '0px', offset: 0}, - {height: '50px', offset: 1}, - ]); - player.finish(); + empty() { + this.items = []; } - cmp.empty(); - fixture.detectChanges(); - - player = engine.players[0] !as TransitionAnimationPlayer; - queriedPlayers = - ((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer) - .players; - expect(queriedPlayers.length).toEqual(5); - - for (i = 0; i < queriedPlayers.length; i++) { - let player = queriedPlayers[i] as ɵWebAnimationsPlayer; - expect(player.keyframes).toEqual([ - {height: '50px', offset: 0}, - {height: '0px', offset: 1}, - ]); + full() { + this.items = [0, 1, 2, 3, 4]; } - }); - - it('should compute intermediate styles properly when an animation is cancelled', () => { - @Component({ - selector: 'ani-cmp', - template: ` + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.empty(); + fixture.detectChanges(); + let player = engine.players[0]! as TransitionAnimationPlayer; + player.finish(); + + cmp.full(); + fixture.detectChanges(); + + player = engine.players[0]! as TransitionAnimationPlayer; + let queriedPlayers = + ((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players; + expect(queriedPlayers.length).toEqual(5); + + let i = 0; + for (i = 0; i < queriedPlayers.length; i++) { + let player = queriedPlayers[i] as ɵWebAnimationsPlayer; + expect(player.keyframes).toEqual([ + {height: '0px', offset: 0}, + {height: '50px', offset: 1}, + ]); + player.finish(); + } + + cmp.empty(); + fixture.detectChanges(); + + player = engine.players[0]! as TransitionAnimationPlayer; + queriedPlayers = + ((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players; + expect(queriedPlayers.length).toEqual(5); + + for (i = 0; i < queriedPlayers.length; i++) { + let player = queriedPlayers[i] as ɵWebAnimationsPlayer; + expect(player.keyframes).toEqual([ + {height: '50px', offset: 0}, + {height: '0px', offset: 1}, + ]); + } + }); + + it('should compute intermediate styles properly when an animation is cancelled', () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp">...</div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => a', - [ - style({width: 0, height: 0}), - animate('1s', style({width: '300px', height: '600px'})), - ]), - transition('* => b', [animate('1s', style({opacity: 0}))]), - ]), - ] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: string; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'a'; - fixture.detectChanges(); - - let player = engine.players[0] !; - let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - webPlayer.setPosition(0.5); - - cmp.exp = 'b'; - fixture.detectChanges(); - - player = engine.players[0] !; - webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; - expect(approximate(parseFloat(webPlayer.keyframes[0]['width'] as string), 150)) - .toBeLessThan(0.05); - expect(approximate(parseFloat(webPlayer.keyframes[0]['height'] as string), 300)) - .toBeLessThan(0.05); - }); + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => a', + [ + style({width: 0, height: 0}), + animate('1s', style({width: '300px', height: '600px'})), + ]), + transition('* => b', [animate('1s', style({opacity: 0}))]), + ]), + ] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp!: string; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'a'; + fixture.detectChanges(); + + let player = engine.players[0]!; + let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + webPlayer.setPosition(0.5); + + cmp.exp = 'b'; + fixture.detectChanges(); + + player = engine.players[0]!; + webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer; + expect(approximate(parseFloat(webPlayer.keyframes[0]['width'] as string), 150)) + .toBeLessThan(0.05); + expect(approximate(parseFloat(webPlayer.keyframes[0]['height'] as string), 300)) + .toBeLessThan(0.05); + }); - it('should compute intermediate styles properly for multiple queried elements when an animation is cancelled', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + it('should compute intermediate styles properly for multiple queried elements when an animation is cancelled', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div [@myAnimation]="exp"> <div *ngFor="let item of items" class="target"></div> </div> `, - animations: [ - trigger( - 'myAnimation', - [ - transition( - '* => full', [query( - '.target', - [ - style({width: 0, height: 0}), - animate('1s', style({width: '500px', height: '1000px'})), - ])]), - transition( - '* => empty', [query('.target', [animate('1s', style({opacity: 0}))])]), - ]), - ] - }) - class Cmp { - // TODO(issue/24571): remove '!'. - public exp !: string; - public items: any[] = []; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - cmp.exp = 'full'; - cmp.items = [0, 1, 2, 3, 4]; - fixture.detectChanges(); - - let player = engine.players[0] !; - let groupPlayer = - (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; - let players = groupPlayer.players; - expect(players.length).toEqual(5); - - for (let i = 0; i < players.length; i++) { - const p = players[i] as ɵWebAnimationsPlayer; - p.setPosition(0.5); - } - - cmp.exp = 'empty'; - cmp.items = []; - fixture.detectChanges(); - - player = engine.players[0]; - groupPlayer = - (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; - players = groupPlayer.players; - - expect(players.length).toEqual(5); - for (let i = 0; i < players.length; i++) { - const p = players[i] as ɵWebAnimationsPlayer; - expect(approximate(parseFloat(p.keyframes[0]['width'] as string), 250)) - .toBeLessThan(0.05); - expect(approximate(parseFloat(p.keyframes[0]['height'] as string), 500)) - .toBeLessThan(0.05); - } - }); - - it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation', - () => { - @Component({ - selector: 'ani-cmp', - template: ` + animations: [ + trigger( + 'myAnimation', + [ + transition( + '* => full', [query( + '.target', + [ + style({width: 0, height: 0}), + animate('1s', style({width: '500px', height: '1000px'})), + ])]), + transition('* => empty', [query('.target', [animate('1s', style({opacity: 0}))])]), + ]), + ] + }) + class Cmp { + // TODO(issue/24571): remove '!'. + public exp!: string; + public items: any[] = []; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + cmp.exp = 'full'; + cmp.items = [0, 1, 2, 3, 4]; + fixture.detectChanges(); + + let player = engine.players[0]!; + let groupPlayer = + (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; + let players = groupPlayer.players; + expect(players.length).toEqual(5); + + for (let i = 0; i < players.length; i++) { + const p = players[i] as ɵWebAnimationsPlayer; + p.setPosition(0.5); + } + + cmp.exp = 'empty'; + cmp.items = []; + fixture.detectChanges(); + + player = engine.players[0]; + groupPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer; + players = groupPlayer.players; + + expect(players.length).toEqual(5); + for (let i = 0; i < players.length; i++) { + const p = players[i] as ɵWebAnimationsPlayer; + expect(approximate(parseFloat(p.keyframes[0]['width'] as string), 250)).toBeLessThan(0.05); + expect(approximate(parseFloat(p.keyframes[0]['height'] as string), 500)) + .toBeLessThan(0.05); + } + }); + + it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation', + () => { + @Component({ + selector: 'ani-cmp', + template: ` <div #elm [@myAnimation]="myAnimationExp" style="display:table; position:fixed"></div> `, - animations: [ - trigger( - 'myAnimation', - [ - state('go', style({display: 'inline-block'})), - transition( - '* => go', - [ - style({display: 'inline', position: 'absolute', opacity: 0}), - animate('1s', style({display: 'inline', opacity: 1, position: 'static'})), - animate('1s', style({display: 'flexbox', opacity: 0})), - ]) - ]), - ] - }) - class Cmp { - @ViewChild('elm', {static: true}) public element: any; - - public myAnimationExp = ''; - } - - TestBed.configureTestingModule({declarations: [Cmp]}); - - const engine = TestBed.inject(ɵAnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - const elm = cmp.element.nativeElement; - expect(elm.style.getPropertyValue('display')).toEqual('table'); - expect(elm.style.getPropertyValue('position')).toEqual('fixed'); - - cmp.myAnimationExp = 'go'; - fixture.detectChanges(); - - expect(elm.style.getPropertyValue('display')).toEqual('inline'); - expect(elm.style.getPropertyValue('position')).toEqual('absolute'); - - const player = engine.players.pop() !; - player.finish(); - player.destroy(); - - expect(elm.style.getPropertyValue('display')).toEqual('inline-block'); - expect(elm.style.getPropertyValue('position')).toEqual('fixed'); - }); - }); + animations: [ + trigger( + 'myAnimation', + [ + state('go', style({display: 'inline-block'})), + transition( + '* => go', + [ + style({display: 'inline', position: 'absolute', opacity: 0}), + animate('1s', style({display: 'inline', opacity: 1, position: 'static'})), + animate('1s', style({display: 'flexbox', opacity: 0})), + ]) + ]), + ] + }) + class Cmp { + @ViewChild('elm', {static: true}) public element: any; + + public myAnimationExp = ''; + } + + TestBed.configureTestingModule({declarations: [Cmp]}); + + const engine = TestBed.inject(ɵAnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + const elm = cmp.element.nativeElement; + expect(elm.style.getPropertyValue('display')).toEqual('table'); + expect(elm.style.getPropertyValue('position')).toEqual('fixed'); + + cmp.myAnimationExp = 'go'; + fixture.detectChanges(); + + expect(elm.style.getPropertyValue('display')).toEqual('inline'); + expect(elm.style.getPropertyValue('position')).toEqual('absolute'); + + const player = engine.players.pop()!; + player.finish(); + player.destroy(); + + expect(elm.style.getPropertyValue('display')).toEqual('inline-block'); + expect(elm.style.getPropertyValue('position')).toEqual('fixed'); + }); +}); })(); function approximate(value: number, target: number) { diff --git a/packages/core/test/application_init_spec.ts b/packages/core/test/application_init_spec.ts index 05069e561a37d..2d5ec25db079b 100644 --- a/packages/core/test/application_init_spec.ts +++ b/packages/core/test/application_init_spec.ts @@ -7,12 +7,12 @@ */ import {Injector} from '@angular/core'; import {APP_INITIALIZER, ApplicationInitStatus} from '@angular/core/src/application_init'; -import {TestBed, async, inject} from '../testing'; + +import {async, inject, TestBed} from '../testing'; { describe('ApplicationInitStatus', () => { describe('no initializers', () => { - it('should return true for `done`', async(inject([ApplicationInitStatus], (status: ApplicationInitStatus) => { (status as any).runInitializers(); @@ -22,7 +22,9 @@ import {TestBed, async, inject} from '../testing'; it('should return a promise that resolves immediately for `donePromise`', async(inject([ApplicationInitStatus], (status: ApplicationInitStatus) => { (status as any).runInitializers(); - status.donePromise.then(() => { expect(status.done).toBe(true); }); + status.donePromise.then(() => { + expect(status.done).toBe(true); + }); }))); }); @@ -34,10 +36,14 @@ import {TestBed, async, inject} from '../testing'; let initializerFactory = (injector: Injector) => { return () => { const initStatus = injector.get(ApplicationInitStatus); - initStatus.donePromise.then(() => { expect(completerResolver).toBe(true); }); + initStatus.donePromise.then(() => { + expect(completerResolver).toBe(true); + }); }; }; - promise = new Promise((res) => { resolve = res; }); + promise = new Promise((res) => { + resolve = res; + }); TestBed.configureTestingModule({ providers: [ {provide: APP_INITIALIZER, multi: true, useValue: () => promise}, diff --git a/packages/core/test/application_module_spec.ts b/packages/core/test/application_module_spec.ts index 2cb36d26b5c0e..c730302934539 100644 --- a/packages/core/test/application_module_spec.ts +++ b/packages/core/test/application_module_spec.ts @@ -16,8 +16,9 @@ import {describe, expect, inject, it} from '../testing/src/testing_internal'; { describe('Application module', () => { - it('should set the default locale to "en-US"', - inject([LOCALE_ID], (defaultLocale: string) => { expect(defaultLocale).toEqual('en-US'); })); + it('should set the default locale to "en-US"', inject([LOCALE_ID], (defaultLocale: string) => { + expect(defaultLocale).toEqual('en-US'); + })); it('should set the default currency code to "USD"', inject([DEFAULT_CURRENCY_CODE], (defaultCurrencyCode: string) => { diff --git a/packages/core/test/application_ref_integration_spec.ts b/packages/core/test/application_ref_integration_spec.ts index 10cbee4ce2bfb..7395ccdff2aaf 100644 --- a/packages/core/test/application_ref_integration_spec.ts +++ b/packages/core/test/application_ref_integration_spec.ts @@ -17,13 +17,16 @@ ivyEnabled && describe('ApplicationRef bootstrap', () => { selector: 'hello-world', template: '<div>Hello {{ name }}</div>', }) - class HelloWorldComponent implements OnInit, - DoCheck { + class HelloWorldComponent implements OnInit, DoCheck { log: string[] = []; name = 'World'; - ngOnInit(): void { this.log.push('OnInit'); } - ngDoCheck(): void { this.log.push('DoCheck'); } + ngOnInit(): void { + this.log.push('OnInit'); + } + ngDoCheck(): void { + this.log.push('DoCheck'); + } } @NgModule({ @@ -34,7 +37,7 @@ ivyEnabled && describe('ApplicationRef bootstrap', () => { class MyAppModule { } - it('should bootstrap hello world', withBody('<hello-world></hello-world>', async() => { + it('should bootstrap hello world', withBody('<hello-world></hello-world>', async () => { const MyAppModuleFactory = new NgModuleFactory(MyAppModule); const moduleRef = await getTestBed().platform.bootstrapModuleFactory(MyAppModuleFactory, {ngZone: 'noop'}); @@ -58,7 +61,7 @@ ivyEnabled && describe('ApplicationRef bootstrap', () => { })); it('should expose the `window.ng` global utilities', - withBody('<hello-world></hello-world>', async() => { + withBody('<hello-world></hello-world>', async () => { const MyAppModuleFactory = new NgModuleFactory(MyAppModule); const moduleRef = await getTestBed().platform.bootstrapModuleFactory(MyAppModuleFactory, {ngZone: 'noop'}); diff --git a/packages/core/test/application_ref_spec.ts b/packages/core/test/application_ref_spec.ts index 8639cbe0db02a..da2ddb7e6de56 100644 --- a/packages/core/test/application_ref_spec.ts +++ b/packages/core/test/application_ref_spec.ts @@ -19,7 +19,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; import {onlyInIvy} from '@angular/private/testing'; import {NoopNgZone} from '../src/zone/ng_zone'; -import {ComponentFixtureNoNgZone, TestBed, async, inject, withModule} from '../testing'; +import {async, ComponentFixtureNoNgZone, inject, TestBed, withModule} from '../testing'; @Component({selector: 'bootstrap-app', template: 'hello'}) class SomeComponent { @@ -29,7 +29,9 @@ class SomeComponent { describe('bootstrap', () => { let mockConsole: MockConsole; - beforeEach(() => { mockConsole = new MockConsole(); }); + beforeEach(() => { + mockConsole = new MockConsole(); + }); function createRootEl(selector = 'bootstrap-app') { const doc = TestBed.inject(DOCUMENT); @@ -47,7 +49,7 @@ class SomeComponent { function createModule(providers?: any[]): Type<any>; function createModule(options: CreateModuleOptions): Type<any>; - function createModule(providersOrOptions: any[] | CreateModuleOptions | undefined): Type<any> { + function createModule(providersOrOptions: any[]|CreateModuleOptions|undefined): Type<any> { let options: CreateModuleOptions = {}; if (Array.isArray(providersOrOptions)) { options = {providers: providersOrOptions}; @@ -98,8 +100,7 @@ class SomeComponent { createRootEl(); const modFactory = compiler.compileModuleSync(SomeModule); const module = modFactory.create(TestBed); - const cmpFactory = - module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !; + const cmpFactory = module.componentFactoryResolver.resolveComponentFactory(SomeComponent)!; const component = app.bootstrap(cmpFactory); // The component should see the child module providers @@ -128,8 +129,7 @@ class SomeComponent { createRootEl('custom-selector'); const modFactory = compiler.compileModuleSync(SomeModule); const module = modFactory.create(TestBed); - const cmpFactory = - module.componentFactoryResolver.resolveComponentFactory(SomeComponent) !; + const cmpFactory = module.componentFactoryResolver.resolveComponentFactory(SomeComponent)!; const component = app.bootstrap(cmpFactory, 'custom-selector'); // The component should see the child module providers @@ -137,7 +137,9 @@ class SomeComponent { }))); describe('ApplicationRef', () => { - beforeEach(() => { TestBed.configureTestingModule({imports: [createModule()]}); }); + beforeEach(() => { + TestBed.configureTestingModule({imports: [createModule()]}); + }); it('should throw when reentering tick', () => { @Component({template: '{{reenter()}}'}) @@ -175,7 +177,9 @@ class SomeComponent { providers: [{ provide: APP_BOOTSTRAP_LISTENER, multi: true, - useValue: (compRef: any) => { capturedCompRefs.push(compRef); } + useValue: (compRef: any) => { + capturedCompRefs.push(compRef); + } }] }); }); @@ -214,7 +218,9 @@ class SomeComponent { it('should wait for asynchronous app initializers', async(() => { let resolve: (result: any) => void; - const promise: Promise<any> = new Promise((res) => { resolve = res; }); + const promise: Promise<any> = new Promise((res) => { + resolve = res; + }); let initializerDone = false; setTimeout(() => { resolve(true); @@ -224,13 +230,20 @@ class SomeComponent { defaultPlatform .bootstrapModule( createModule([{provide: APP_INITIALIZER, useValue: () => promise, multi: true}])) - .then(_ => { expect(initializerDone).toBe(true); }); + .then(_ => { + expect(initializerDone).toBe(true); + }); })); it('should rethrow sync errors even if the exceptionHandler is not rethrowing', async(() => { defaultPlatform - .bootstrapModule(createModule( - [{provide: APP_INITIALIZER, useValue: () => { throw 'Test'; }, multi: true}])) + .bootstrapModule(createModule([{ + provide: APP_INITIALIZER, + useValue: () => { + throw 'Test'; + }, + multi: true + }])) .then(() => expect(false).toBe(true), (e) => { expect(e).toBe('Test'); // Error rethrown will be seen by the exception handler since it's after @@ -306,7 +319,7 @@ class SomeComponent { }); })); - it('should resolve component resources when creating module factory', async() => { + it('should resolve component resources when creating module factory', async () => { @Component({ selector: 'with-templates-app', templateUrl: '/test-template.html', @@ -328,7 +341,7 @@ class SomeComponent { }); onlyInIvy('We only need to define `LOCALE_ID` for runtime i18n') - .it('should define `LOCALE_ID`', async() => { + .it('should define `LOCALE_ID`', async () => { @Component({ selector: 'i18n-app', templateUrl: '', @@ -343,7 +356,7 @@ class SomeComponent { expect(getLocaleId()).toEqual('ro'); }); - it('should wait for APP_INITIALIZER to set providers for `LOCALE_ID`', async() => { + it('should wait for APP_INITIALIZER to set providers for `LOCALE_ID`', async () => { let locale: string = ''; const testModule = createModule({ @@ -365,7 +378,9 @@ class SomeComponent { })); it('should wait for asynchronous app initializers', async(() => { let resolve: (result: any) => void; - const promise: Promise<any> = new Promise((res) => { resolve = res; }); + const promise: Promise<any> = new Promise((res) => { + resolve = res; + }); let initializerDone = false; setTimeout(() => { resolve(true); @@ -373,7 +388,7 @@ class SomeComponent { }, 1); const compilerFactory: CompilerFactory = - defaultPlatform.injector.get(CompilerFactory, null) !; + defaultPlatform.injector.get(CompilerFactory, null)!; const moduleFactory = compilerFactory.createCompiler().compileModuleSync( createModule([{provide: APP_INITIALIZER, useValue: () => promise, multi: true}])); defaultPlatform.bootstrapModuleFactory(moduleFactory).then(_ => { @@ -383,9 +398,14 @@ class SomeComponent { it('should rethrow sync errors even if the exceptionHandler is not rethrowing', async(() => { const compilerFactory: CompilerFactory = - defaultPlatform.injector.get(CompilerFactory, null) !; - const moduleFactory = compilerFactory.createCompiler().compileModuleSync(createModule( - [{provide: APP_INITIALIZER, useValue: () => { throw 'Test'; }, multi: true}])); + defaultPlatform.injector.get(CompilerFactory, null)!; + const moduleFactory = compilerFactory.createCompiler().compileModuleSync(createModule([{ + provide: APP_INITIALIZER, + useValue: () => { + throw 'Test'; + }, + multi: true + }])); expect(() => defaultPlatform.bootstrapModuleFactory(moduleFactory)).toThrow('Test'); // Error rethrown will be seen by the exception handler since it's after // construction. @@ -395,7 +415,7 @@ class SomeComponent { it('should rethrow promise errors even if the exceptionHandler is not rethrowing', async(() => { const compilerFactory: CompilerFactory = - defaultPlatform.injector.get(CompilerFactory, null) !; + defaultPlatform.injector.get(CompilerFactory, null)!; const moduleFactory = compilerFactory.createCompiler().compileModuleSync(createModule( [{provide: APP_INITIALIZER, useValue: () => Promise.reject('Test'), multi: true}])); defaultPlatform.bootstrapModuleFactory(moduleFactory) @@ -415,15 +435,13 @@ class SomeComponent { @Component({template: '<ng-container #vc></ng-container>'}) class ContainerComp { // TODO(issue/24571): remove '!'. - @ViewChild('vc', {read: ViewContainerRef}) - vc !: ViewContainerRef; + @ViewChild('vc', {read: ViewContainerRef}) vc!: ViewContainerRef; } @Component({template: '<ng-template #t>Dynamic content</ng-template>'}) class EmbeddedViewComp { // TODO(issue/24571): remove '!'. - @ViewChild(TemplateRef, {static: true}) - tplRef !: TemplateRef<Object>; + @ViewChild(TemplateRef, {static: true}) tplRef!: TemplateRef<Object>; } beforeEach(() => { @@ -497,7 +515,7 @@ class SomeComponent { vc.insert(hostView); expect(() => appRef.attachView(hostView)) .toThrowError('This view is already attached to a ViewContainer!'); - hostView = vc.detach(0) !; + hostView = vc.detach(0)!; appRef.attachView(hostView); expect(() => vc.insert(hostView)) @@ -516,7 +534,9 @@ class SomeComponent { class ClickComp { text: string = '1'; - onClick() { this.text += '1'; } + onClick() { + this.text += '1'; + } } @Component({selector: 'micro-task-comp', template: `<span>{{text}}</span>`}) @@ -524,7 +544,9 @@ class SomeComponent { text: string = '1'; ngOnInit() { - Promise.resolve(null).then((_) => { this.text += '1'; }); + Promise.resolve(null).then((_) => { + this.text += '1'; + }); } } @@ -533,7 +555,9 @@ class SomeComponent { text: string = '1'; ngOnInit() { - setTimeout(() => { this.text += '1'; }, 10); + setTimeout(() => { + this.text += '1'; + }, 10); } } @@ -544,7 +568,9 @@ class SomeComponent { ngOnInit() { Promise.resolve(null).then((_) => { this.text += '1'; - setTimeout(() => { this.text += '1'; }, 10); + setTimeout(() => { + this.text += '1'; + }, 10); }); } } @@ -556,7 +582,9 @@ class SomeComponent { ngOnInit() { setTimeout(() => { this.text += '1'; - Promise.resolve(null).then((_: any) => { this.text += '1'; }); + Promise.resolve(null).then((_: any) => { + this.text += '1'; + }); }, 10); } } @@ -572,7 +600,9 @@ class SomeComponent { }); }); - afterEach(() => { expect(stableCalled).toBe(true, 'isStable did not emit true on stable'); }); + afterEach(() => { + expect(stableCalled).toBe(true, 'isStable did not emit true on stable'); + }); function expectStableTexts(component: Type<any>, expected: string[]) { const fixture = TestBed.createComponent(component); @@ -593,26 +623,34 @@ class SomeComponent { }); } - it('isStable should fire on synchronous component loading', - async(() => { expectStableTexts(SyncComp, ['1']); })); + it('isStable should fire on synchronous component loading', async(() => { + expectStableTexts(SyncComp, ['1']); + })); - it('isStable should fire after a microtask on init is completed', - async(() => { expectStableTexts(MicroTaskComp, ['11']); })); + it('isStable should fire after a microtask on init is completed', async(() => { + expectStableTexts(MicroTaskComp, ['11']); + })); - it('isStable should fire after a macrotask on init is completed', - async(() => { expectStableTexts(MacroTaskComp, ['11']); })); + it('isStable should fire after a macrotask on init is completed', async(() => { + expectStableTexts(MacroTaskComp, ['11']); + })); it('isStable should fire only after chain of micro and macrotasks on init are completed', - async(() => { expectStableTexts(MicroMacroTaskComp, ['111']); })); + async(() => { + expectStableTexts(MicroMacroTaskComp, ['111']); + })); it('isStable should fire only after chain of macro and microtasks on init are completed', - async(() => { expectStableTexts(MacroMicroTaskComp, ['111']); })); + async(() => { + expectStableTexts(MacroMicroTaskComp, ['111']); + })); describe('unstable', () => { let unstableCalled = false; - afterEach( - () => { expect(unstableCalled).toBe(true, 'isStable did not emit false on unstable'); }); + afterEach(() => { + expect(unstableCalled).toBe(true, 'isStable did not emit false on unstable'); + }); function expectUnstable(appRef: ApplicationRef) { appRef.isStable.subscribe({ diff --git a/packages/core/test/bundling/animation_world/index.ts b/packages/core/test/bundling/animation_world/index.ts index 6c68aa888b50d..224eb1fe9e68b 100644 --- a/packages/core/test/bundling/animation_world/index.ts +++ b/packages/core/test/bundling/animation_world/index.ts @@ -30,17 +30,20 @@ class MakeColorGreyDirective { this._textColor = null; } - toggle() { this._backgroundColor ? this.off() : this.on(); } + toggle() { + this._backgroundColor ? this.off() : this.on(); + } } @Component({selector: 'box-with-overridden-styles', template: '...'}) class BoxWithOverriddenStylesComponent { public active = false; - @HostBinding('style') - styles = {}; + @HostBinding('style') styles = {}; - constructor() { this.onInActive(); } + constructor() { + this.onInActive(); + } @HostListener('click', ['$event']) toggle() { @@ -102,9 +105,13 @@ class AnimationWorldComponent { private _hostElement: HTMLElement; public styles: {[key: string]: any}|null = null; - constructor(element: ElementRef) { this._hostElement = element.nativeElement; } + constructor(element: ElementRef) { + this._hostElement = element.nativeElement; + } - makeClass(item: any) { return `record-${item.value}`; } + makeClass(item: any) { + return `record-${item.value}`; + } toggleActive(item: any, makeColorGrey: MakeColorGreyDirective) { item.active = !item.active; diff --git a/packages/core/test/bundling/cyclic_import/integration_spec.ts b/packages/core/test/bundling/cyclic_import/integration_spec.ts index e1a2d4f3181e3..26b9a61d038db 100644 --- a/packages/core/test/bundling/cyclic_import/integration_spec.ts +++ b/packages/core/test/bundling/cyclic_import/integration_spec.ts @@ -17,10 +17,11 @@ const UTF8 = { const PACKAGE = 'angular/packages/core/test/bundling/cyclic_import'; describe('treeshaking with uglify', () => { - let content: string; const contentPath = require.resolve(path.join(PACKAGE, 'bundle.min_debug.js')); - beforeAll(() => { content = fs.readFileSync(contentPath, UTF8); }); + beforeAll(() => { + content = fs.readFileSync(contentPath, UTF8); + }); describe('functional test in domino', () => { it('should render hello world when not minified', withBody('<trigger></trigger>', () => { diff --git a/packages/core/test/bundling/hello_world/treeshaking_spec.ts b/packages/core/test/bundling/hello_world/treeshaking_spec.ts index f4a76c7dc693b..e6646baff5306 100644 --- a/packages/core/test/bundling/hello_world/treeshaking_spec.ts +++ b/packages/core/test/bundling/hello_world/treeshaking_spec.ts @@ -17,21 +17,24 @@ const UTF8 = { const PACKAGE = 'angular/packages/core/test/bundling/hello_world'; describe('treeshaking with uglify', () => { - let content: string; const contentPath = require.resolve(path.join(PACKAGE, 'bundle.min_debug.js')); - beforeAll(() => { content = fs.readFileSync(contentPath, UTF8); }); + beforeAll(() => { + content = fs.readFileSync(contentPath, UTF8); + }); - it('should drop unused TypeScript helpers', - () => { expect(content).not.toContain('__asyncGenerator'); }); + it('should drop unused TypeScript helpers', () => { + expect(content).not.toContain('__asyncGenerator'); + }); it('should not contain rxjs from commonjs distro', () => { expect(content).not.toContain('commonjsGlobal'); expect(content).not.toContain('createCommonjsModule'); }); - it('should not contain zone.js', - () => { expect(content).not.toContain('global[\'Zone\'] = Zone'); }); + it('should not contain zone.js', () => { + expect(content).not.toContain('global[\'Zone\'] = Zone'); + }); describe('functional test in domino', () => { it('should render hello world when not minified', diff --git a/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts b/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts index 9f9eedd37508c..55309b5965980 100644 --- a/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts +++ b/packages/core/test/bundling/hello_world_r2/treeshaking_spec.ts @@ -16,13 +16,15 @@ const UTF8 = { const PACKAGE = 'angular/packages/core/test/bundling/hello_world_r2'; describe('treeshaking with uglify', () => { - let content: string; const contentPath = require.resolve(path.join(PACKAGE, 'bundle.min_debug.js')); - beforeAll(() => { content = fs.readFileSync(contentPath, UTF8); }); + beforeAll(() => { + content = fs.readFileSync(contentPath, UTF8); + }); - it('should drop unused TypeScript helpers', - () => { expect(content).not.toContain('__asyncGenerator'); }); + it('should drop unused TypeScript helpers', () => { + expect(content).not.toContain('__asyncGenerator'); + }); it('should not contain rxjs from commonjs distro', () => { expect(content).not.toContain('commonjsGlobal'); diff --git a/packages/core/test/bundling/injection/treeshaking_spec.ts b/packages/core/test/bundling/injection/treeshaking_spec.ts index 03a82172d0965..7c5529f74b440 100644 --- a/packages/core/test/bundling/injection/treeshaking_spec.ts +++ b/packages/core/test/bundling/injection/treeshaking_spec.ts @@ -11,6 +11,7 @@ import {INJECTOR, ScopedService} from './usage'; describe('functional test for injection system bundling', () => { - it('should be able to inject the scoped service', - () => { expect(INJECTOR.get(ScopedService) instanceof ScopedService).toBe(true); }); + it('should be able to inject the scoped service', () => { + expect(INJECTOR.get(ScopedService) instanceof ScopedService).toBe(true); + }); }); diff --git a/packages/core/test/bundling/todo/index.ts b/packages/core/test/bundling/todo/index.ts index 532f3077c5a59..4c9b3da2c4ff9 100644 --- a/packages/core/test/bundling/todo/index.ts +++ b/packages/core/test/bundling/todo/index.ts @@ -15,9 +15,13 @@ class Todo { editing: boolean; // TODO(issue/24571): remove '!'. - private _title !: string; - get title() { return this._title; } - set title(value: string) { this._title = value.trim(); } + private _title!: string; + get title() { + return this._title; + } + set title(value: string) { + this._title = value.trim(); + } constructor(title: string, public completed: boolean = false) { this.editing = false; @@ -39,21 +43,37 @@ class TodoStore { return this.todos.filter((todo: Todo) => todo.completed === completed); } - allCompleted() { return this.todos.length === this.getCompleted().length; } + allCompleted() { + return this.todos.length === this.getCompleted().length; + } - setAllTo(completed: boolean) { this.todos.forEach((t: Todo) => t.completed = completed); } + setAllTo(completed: boolean) { + this.todos.forEach((t: Todo) => t.completed = completed); + } - removeCompleted() { this.todos = this.getWithCompleted(false); } + removeCompleted() { + this.todos = this.getWithCompleted(false); + } - getRemaining() { return this.getWithCompleted(false); } + getRemaining() { + return this.getWithCompleted(false); + } - getCompleted() { return this.getWithCompleted(true); } + getCompleted() { + return this.getWithCompleted(true); + } - toggleCompletion(todo: Todo) { todo.completed = !todo.completed; } + toggleCompletion(todo: Todo) { + todo.completed = !todo.completed; + } - remove(todo: Todo) { this.todos.splice(this.todos.indexOf(todo), 1); } + remove(todo: Todo) { + this.todos.splice(this.todos.indexOf(todo), 1); + } - add(title: string) { this.todos.push(new Todo(title)); } + add(title: string) { + this.todos.push(new Todo(title)); + } } @Component({ diff --git a/packages/core/test/bundling/todo/todo_e2e_spec.ts b/packages/core/test/bundling/todo/todo_e2e_spec.ts index 2beca5a55e51b..cb2b461912e00 100644 --- a/packages/core/test/bundling/todo/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo/todo_e2e_spec.ts @@ -21,13 +21,13 @@ const BUNDLES = ['bundle.js', 'bundle.min_debug.js', 'bundle.min.js']; describe('functional test for todo', () => { BUNDLES.forEach(bundle => { describe(bundle, () => { - it('should render todo', withBody('<todo-app></todo-app>', async() => { + it('should render todo', withBody('<todo-app></todo-app>', async () => { require(path.join(PACKAGE, bundle)); - const toDoAppComponent = getComponent(document.querySelector('todo-app') !); + const toDoAppComponent = getComponent(document.querySelector('todo-app')!); expect(document.body.textContent).toContain('todos'); expect(document.body.textContent).toContain('Demonstrate Components'); expect(document.body.textContent).toContain('4 items left'); - document.querySelector('button') !.click(); + document.querySelector('button')!.click(); await whenRendered(toDoAppComponent); expect(document.body.textContent).toContain('3 items left'); })); diff --git a/packages/core/test/bundling/todo_i18n/index.ts b/packages/core/test/bundling/todo_i18n/index.ts index d57b51649b9fb..3613fefcff0fc 100644 --- a/packages/core/test/bundling/todo_i18n/index.ts +++ b/packages/core/test/bundling/todo_i18n/index.ts @@ -13,42 +13,64 @@ import {Component, Injectable, NgModule, ViewEncapsulation, ɵmarkDirty as markD class Todo { editing: boolean; - get title() { return this._title; } - set title(value: string) { this._title = value.trim(); } + get title() { + return this._title; + } + set title(value: string) { + this._title = value.trim(); + } - constructor(private _title: string, public completed: boolean = false) { this.editing = false; } + constructor(private _title: string, public completed: boolean = false) { + this.editing = false; + } } @Injectable({providedIn: 'root'}) class TodoStore { todos: Array<Todo> = [ - new Todo($localize `Demonstrate Components`), - new Todo($localize `Demonstrate Structural Directives`, true), + new Todo($localize`Demonstrate Components`), + new Todo($localize`Demonstrate Structural Directives`, true), // Using a placeholder - new Todo($localize `Demonstrate ${'NgModules'}:value:`), - new Todo($localize `Demonstrate zoneless change detection`), - new Todo($localize `Demonstrate internationalization`), + new Todo($localize`Demonstrate ${'NgModules'}:value:`), + new Todo($localize`Demonstrate zoneless change detection`), + new Todo($localize`Demonstrate internationalization`), ]; private getWithCompleted(completed: boolean) { return this.todos.filter((todo: Todo) => todo.completed === completed); } - allCompleted() { return this.todos.length === this.getCompleted().length; } + allCompleted() { + return this.todos.length === this.getCompleted().length; + } - setAllTo(completed: boolean) { this.todos.forEach((t: Todo) => t.completed = completed); } + setAllTo(completed: boolean) { + this.todos.forEach((t: Todo) => t.completed = completed); + } - removeCompleted() { this.todos = this.getWithCompleted(false); } + removeCompleted() { + this.todos = this.getWithCompleted(false); + } - getRemaining() { return this.getWithCompleted(false); } + getRemaining() { + return this.getWithCompleted(false); + } - getCompleted() { return this.getWithCompleted(true); } + getCompleted() { + return this.getWithCompleted(true); + } - toggleCompletion(todo: Todo) { todo.completed = !todo.completed; } + toggleCompletion(todo: Todo) { + todo.completed = !todo.completed; + } - remove(todo: Todo) { this.todos.splice(this.todos.indexOf(todo), 1); } + remove(todo: Todo) { + this.todos.splice(this.todos.indexOf(todo), 1); + } - add(title: string) { this.todos.push(new Todo(title)); } + add(title: string) { + this.todos.push(new Todo(title)); + } } @Component({ diff --git a/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts b/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts index 74d560ab0e97b..dbe8737749bdc 100644 --- a/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo_i18n/todo_e2e_spec.ts @@ -20,17 +20,17 @@ const BUNDLES = ['bundle.js', 'bundle.min_debug.js', 'bundle.min.js']; describe('functional test for todo i18n', () => { BUNDLES.forEach(bundle => { describe(bundle, () => { - it('should render todo i18n', withBody('<todo-app></todo-app>', async() => { + it('should render todo i18n', withBody('<todo-app></todo-app>', async () => { clearTranslations(); require(path.join(PACKAGE, bundle)); - const toDoAppComponent = getComponent(document.querySelector('todo-app') !); + const toDoAppComponent = getComponent(document.querySelector('todo-app')!); expect(document.body.textContent).toContain('liste de tâches'); expect(document.body.textContent).toContain('Démontrer les components'); expect(document.body.textContent).toContain('Démontrer NgModules'); expect(document.body.textContent).toContain('4 tâches restantes'); - expect(document.querySelector('.new-todo') !.getAttribute('placeholder')) + expect(document.querySelector('.new-todo')!.getAttribute('placeholder')) .toEqual(`Qu'y a-t-il à faire ?`); - document.querySelector('button') !.click(); + document.querySelector('button')!.click(); await whenRendered(toDoAppComponent); expect(document.body.textContent).toContain('3 tâches restantes'); })); diff --git a/packages/core/test/bundling/todo_r2/index.ts b/packages/core/test/bundling/todo_r2/index.ts index 16b2404c30058..2db25ed4c1bac 100644 --- a/packages/core/test/bundling/todo_r2/index.ts +++ b/packages/core/test/bundling/todo_r2/index.ts @@ -16,9 +16,13 @@ class Todo { editing: boolean; // TODO(issue/24571): remove '!'. - private _title !: string; - get title() { return this._title; } - set title(value: string) { this._title = value.trim(); } + private _title!: string; + get title() { + return this._title; + } + set title(value: string) { + this._title = value.trim(); + } constructor(title: string, public completed: boolean = false) { this.editing = false; @@ -40,21 +44,37 @@ class TodoStore { return this.todos.filter((todo: Todo) => todo.completed === completed); } - allCompleted() { return this.todos.length === this.getCompleted().length; } + allCompleted() { + return this.todos.length === this.getCompleted().length; + } - setAllTo(completed: boolean) { this.todos.forEach((t: Todo) => t.completed = completed); } + setAllTo(completed: boolean) { + this.todos.forEach((t: Todo) => t.completed = completed); + } - removeCompleted() { this.todos = this.getWithCompleted(false); } + removeCompleted() { + this.todos = this.getWithCompleted(false); + } - getRemaining() { return this.getWithCompleted(false); } + getRemaining() { + return this.getWithCompleted(false); + } - getCompleted() { return this.getWithCompleted(true); } + getCompleted() { + return this.getWithCompleted(true); + } - toggleCompletion(todo: Todo) { todo.completed = !todo.completed; } + toggleCompletion(todo: Todo) { + todo.completed = !todo.completed; + } - remove(todo: Todo) { this.todos.splice(this.todos.indexOf(todo), 1); } + remove(todo: Todo) { + this.todos.splice(this.todos.indexOf(todo), 1); + } - add(title: string) { this.todos.push(new Todo(title)); } + add(title: string) { + this.todos.push(new Todo(title)); + } } @Component({ @@ -120,14 +140,18 @@ class TodoStore { class ToDoAppComponent { newTodoText = ''; - constructor(public todoStore: TodoStore) { (window as any).toDoAppComponent = this; } + constructor(public todoStore: TodoStore) { + (window as any).toDoAppComponent = this; + } stopEditing(todo: Todo, editedTitle: string) { todo.title = editedTitle; todo.editing = false; } - cancelEditingTodo(todo: Todo) { todo.editing = false; } + cancelEditingTodo(todo: Todo) { + todo.editing = false; + } updateEditingTodo(todo: Todo, editedTitle: string) { editedTitle = editedTitle.trim(); @@ -140,13 +164,21 @@ class ToDoAppComponent { todo.title = editedTitle; } - editTodo(todo: Todo) { todo.editing = true; } + editTodo(todo: Todo) { + todo.editing = true; + } - removeCompleted() { this.todoStore.removeCompleted(); } + removeCompleted() { + this.todoStore.removeCompleted(); + } - toggleCompletion(todo: Todo) { this.todoStore.toggleCompletion(todo); } + toggleCompletion(todo: Todo) { + this.todoStore.toggleCompletion(todo); + } - remove(todo: Todo) { this.todoStore.remove(todo); } + remove(todo: Todo) { + this.todoStore.remove(todo); + } addTodo() { if (this.newTodoText.trim().length) { @@ -158,7 +190,9 @@ class ToDoAppComponent { @NgModule({declarations: [ToDoAppComponent], imports: [CommonModule, BrowserModule]}) class ToDoAppModule { - ngDoBootstrap(app: any) { app.bootstrap(ToDoAppComponent); } + ngDoBootstrap(app: any) { + app.bootstrap(ToDoAppComponent); + } } (window as any).waitForApp = diff --git a/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts b/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts index 1037bec8f2ff3..48bb04f4d752d 100644 --- a/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts +++ b/packages/core/test/bundling/todo_r2/todo_e2e_spec.ts @@ -21,9 +21,9 @@ describe('functional test for todo', () => { BUNDLES.forEach(bundle => { describe(bundle, () => { it('should place styles on the elements within the component', - withBody('<todo-app></todo-app>', async() => { + withBody('<todo-app></todo-app>', async () => { require(path.join(PACKAGE, bundle)); - await(window as any).waitForApp; + await (window as any).waitForApp; const toDoAppComponent = (window as any).toDoAppComponent; await whenRendered(toDoAppComponent); diff --git a/packages/core/test/change_detection/change_detector_util_spec.ts b/packages/core/test/change_detection/change_detector_util_spec.ts index f6a58a17976f0..74636f090e823 100644 --- a/packages/core/test/change_detection/change_detector_util_spec.ts +++ b/packages/core/test/change_detection/change_detector_util_spec.ts @@ -49,8 +49,9 @@ import {devModeEqual} from '@angular/core/src/change_detection/change_detection_ expect(devModeEqual(null, {})).toBe(false); }); - it('should return true for other objects', - () => { expect(devModeEqual({}, {})).toBe(true); }); + it('should return true for other objects', () => { + expect(devModeEqual({}, {})).toBe(true); + }); }); }); } diff --git a/packages/core/test/change_detection/differs/default_iterable_differ_spec.ts b/packages/core/test/change_detection/differs/default_iterable_differ_spec.ts index 8a9bf2a845908..dcdf0f94fe3a3 100644 --- a/packages/core/test/change_detection/differs/default_iterable_differ_spec.ts +++ b/packages/core/test/change_detection/differs/default_iterable_differ_spec.ts @@ -14,13 +14,17 @@ import {iterableChangesAsString, iterableDifferToString} from '../../change_dete class ItemWithId { constructor(private id: string) {} - toString() { return `{id: ${this.id}}`; } + toString() { + return `{id: ${this.id}}`; + } } class ComplexItem { constructor(private id: string, private color: string) {} - toString() { return `{id: ${this.id}, color: ${this.color}}`; } + toString() { + return `{id: ${this.id}, color: ${this.color}}`; + } } // TODO(vicb): UnmodifiableListView / frozen object when implemented @@ -29,7 +33,9 @@ class ComplexItem { describe('DefaultIterableDiffer', function() { let differ: DefaultIterableDiffer<any>; - beforeEach(() => { differ = new DefaultIterableDiffer(); }); + beforeEach(() => { + differ = new DefaultIterableDiffer(); + }); it('should support list and iterables', () => { const f = new DefaultIterableDifferFactory(); @@ -47,10 +53,9 @@ class ComplexItem { l.list = [1]; differ.check(l); - expect(iterableDifferToString(differ)).toEqual(iterableChangesAsString({ - collection: ['1[null->0]'], - additions: ['1[null->0]'] - })); + expect(iterableDifferToString(differ)) + .toEqual( + iterableChangesAsString({collection: ['1[null->0]'], additions: ['1[null->0]']})); l.list = [2, 1]; differ.check(l); @@ -69,10 +74,9 @@ class ComplexItem { l.push('a'); differ.check(l); - expect(iterableDifferToString(differ)).toEqual(iterableChangesAsString({ - collection: ['a[null->0]'], - additions: ['a[null->0]'] - })); + expect(iterableDifferToString(differ)) + .toEqual( + iterableChangesAsString({collection: ['a[null->0]'], additions: ['a[null->0]']})); l.push('b'); differ.check(l); @@ -148,10 +152,9 @@ class ComplexItem { l.push('a'); differ.check(l); - expect(iterableDifferToString(differ)).toEqual(iterableChangesAsString({ - collection: ['a[null->0]'], - additions: ['a[null->0]'] - })); + expect(iterableDifferToString(differ)) + .toEqual( + iterableChangesAsString({collection: ['a[null->0]'], additions: ['a[null->0]']})); l.push('b'); differ.check(l); @@ -299,7 +302,7 @@ class ComplexItem { describe('forEachOperation', () => { function stringifyItemChange( - record: any, p: number | null, c: number | null, originalIndex: number) { + record: any, p: number|null, c: number|null, originalIndex: number) { const suffix = originalIndex == null ? '' : ' [o=' + originalIndex + ']'; const value = record.item; if (record.currentIndex == null) { @@ -312,13 +315,13 @@ class ComplexItem { } function modifyArrayUsingOperation( - arr: number[], endData: any[], prev: number | null, next: number | null) { - let value: number = null !; + arr: number[], endData: any[], prev: number|null, next: number|null) { + let value: number = null!; if (prev == null) { // "next" index is guaranteed to be set since the previous index is // not defined and therefore a new entry is added. - value = endData[next !]; - arr.splice(next !, 0, value); + value = endData[next!]; + arr.splice(next!, 0, value); } else if (next == null) { value = arr[prev]; arr.splice(prev, 1); @@ -335,11 +338,11 @@ class ComplexItem { const startData = [0, 1, 2, 3, 4, 5]; const endData = [6, 2, 7, 0, 4, 8]; - differ = differ.diff(startData) !; - differ = differ.diff(endData) !; + differ = differ.diff(startData)!; + differ = differ.diff(endData)!; const operations: string[] = []; - differ.forEachOperation((item: any, prev: number | null, next: number | null) => { + differ.forEachOperation((item: any, prev: number|null, next: number|null) => { const value = modifyArrayUsingOperation(startData, endData, prev, next); operations.push(stringifyItemChange(item, prev, next, item.previousIndex)); }); @@ -358,11 +361,11 @@ class ComplexItem { const startData = [0, 1, 2, 3]; const endData = [2, 1]; - differ = differ.diff(startData) !; - differ = differ.diff(endData) !; + differ = differ.diff(startData)!; + differ = differ.diff(endData)!; const operations: string[] = []; - differ.forEachOperation((item: any, prev: number | null, next: number | null) => { + differ.forEachOperation((item: any, prev: number|null, next: number|null) => { modifyArrayUsingOperation(startData, endData, prev, next); operations.push(stringifyItemChange(item, prev, next, item.previousIndex)); }); @@ -378,11 +381,11 @@ class ComplexItem { const startData = [1, 2, 3, 4, 5, 6]; const endData = [3, 6, 4, 9, 1, 2]; - differ = differ.diff(startData) !; - differ = differ.diff(endData) !; + differ = differ.diff(startData)!; + differ = differ.diff(endData)!; const operations: string[] = []; - differ.forEachOperation((item: any, prev: number | null, next: number | null) => { + differ.forEachOperation((item: any, prev: number|null, next: number|null) => { modifyArrayUsingOperation(startData, endData, prev, next); operations.push(stringifyItemChange(item, prev, next, item.previousIndex)); }); @@ -399,11 +402,11 @@ class ComplexItem { const startData = [0, 1, 2, 3, 4]; const endData = [4, 1, 2, 3, 0, 5]; - differ = differ.diff(startData) !; - differ = differ.diff(endData) !; + differ = differ.diff(startData)!; + differ = differ.diff(endData)!; const operations: string[] = []; - differ.forEachOperation((item: any, prev: number | null, next: number | null) => { + differ.forEachOperation((item: any, prev: number|null, next: number|null) => { modifyArrayUsingOperation(startData, endData, prev, next); operations.push(stringifyItemChange(item, prev, next, item.previousIndex)); }); @@ -420,11 +423,11 @@ class ComplexItem { const startData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; const endData = [10, 11, 1, 5, 7, 8, 0, 5, 3, 6]; - differ = differ.diff(startData) !; - differ = differ.diff(endData) !; + differ = differ.diff(startData)!; + differ = differ.diff(endData)!; const operations: string[] = []; - differ.forEachOperation((item: any, prev: number | null, next: number | null) => { + differ.forEachOperation((item: any, prev: number|null, next: number|null) => { modifyArrayUsingOperation(startData, endData, prev, next); operations.push(stringifyItemChange(item, prev, next, item.previousIndex)); }); @@ -446,11 +449,11 @@ class ComplexItem { const startData = [1, 2, 3, 4]; const endData = [5, 6, 7, 8]; - differ = differ.diff(startData) !; - differ = differ.diff(endData) !; + differ = differ.diff(startData)!; + differ = differ.diff(endData)!; const operations: string[] = []; - differ.forEachOperation((item: any, prev: number | null, next: number | null) => { + differ.forEachOperation((item: any, prev: number|null, next: number|null) => { const value = modifyArrayUsingOperation(startData, endData, prev, next); operations.push(stringifyItemChange(item, prev, next, item.previousIndex)); }); @@ -471,7 +474,7 @@ class ComplexItem { it('should treat null as an empty list', () => { differ.diff(['a', 'b']); - expect(iterableDifferToString(differ.diff(null !) !)).toEqual(iterableChangesAsString({ + expect(iterableDifferToString(differ.diff(null!)!)).toEqual(iterableChangesAsString({ previous: ['a[0->null]', 'b[1->null]'], removals: ['a[0->null]', 'b[1->null]'] })); @@ -490,7 +493,9 @@ class ComplexItem { const buildItemList = (list: string[]) => list.map((val) => new ItemWithId(val)); - beforeEach(() => { differ = new DefaultIterableDiffer(trackByItemId); }); + beforeEach(() => { + differ = new DefaultIterableDiffer(trackByItemId); + }); it('should treat the collection as dirty if identity changes', () => { differ.diff(buildItemList(['a'])); @@ -539,7 +544,6 @@ class ComplexItem { previous: ['{id: a}[0->1]', '{id: b}[1->0]', '{id: c}'], moves: ['{id: b}[1->0]', '{id: a}[0->1]'] })); - }); it('should track duplicate reinsertion normally', () => { @@ -555,7 +559,6 @@ class ComplexItem { moves: ['{id: a}[0->1]', '{id: a}[1->2]'], additions: ['{id: b}[null->0]'] })); - }); it('should track removals normally', () => { @@ -577,7 +580,9 @@ class ComplexItem { const trackByIndex = (index: number, item: any): number => index; - beforeEach(() => { differ = new DefaultIterableDiffer(trackByIndex); }); + beforeEach(() => { + differ = new DefaultIterableDiffer(trackByIndex); + }); it('should track removals normally', () => { differ.check(['a', 'b', 'c', 'd']); diff --git a/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts b/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts index bba585f5b069e..86435ed8e2843 100644 --- a/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts +++ b/packages/core/test/change_detection/differs/default_keyvalue_differ_spec.ts @@ -23,7 +23,9 @@ import {kvChangesAsString, testChangesAsString} from '../../change_detection/uti m = new Map(); }); - afterEach(() => { differ = null !; }); + afterEach(() => { + differ = null!; + }); it('should detect additions', () => { differ.check(m); @@ -66,7 +68,6 @@ import {kvChangesAsString, testChangesAsString} from '../../change_detection/uti expect(record.previousValue).toEqual(10); expect(record.currentValue).toEqual(20); }); - }); it('should do basic map watching', () => { @@ -183,7 +184,6 @@ import {kvChangesAsString, testChangesAsString} from '../../change_detection/uti previous: ['a[A->null]', 'd[D->null]'], removals: ['a[A->null]', 'd[D->null]'] })); - }); it('should work regardless key order', () => { @@ -221,7 +221,6 @@ import {kvChangesAsString, testChangesAsString} from '../../change_detection/uti removals: ['b[b->null]'] })); }); - }); describe('diff', () => { diff --git a/packages/core/test/change_detection/iterable.ts b/packages/core/test/change_detection/iterable.ts index 97e2401bcd4af..528dca0524ce0 100644 --- a/packages/core/test/change_detection/iterable.ts +++ b/packages/core/test/change_detection/iterable.ts @@ -10,7 +10,11 @@ import {getSymbolIterator} from '@angular/core/src/util/symbol'; export class TestIterable { list: number[]; - constructor() { this.list = []; } + constructor() { + this.list = []; + } - [getSymbolIterator()]() { return (this.list as any)[getSymbolIterator()](); } + [getSymbolIterator()]() { + return (this.list as any)[getSymbolIterator()](); + } } diff --git a/packages/core/test/change_detection/util.ts b/packages/core/test/change_detection/util.ts index 97d68f52dca92..a29a188453533 100644 --- a/packages/core/test/change_detection/util.ts +++ b/packages/core/test/change_detection/util.ts @@ -47,9 +47,14 @@ function icrAsString<V>(icr: IterableChangeRecord<V>): string { stringify(icr.previousIndex) + '->' + stringify(icr.currentIndex) + ']'; } -export function iterableChangesAsString( - {collection = [] as any, previous = [] as any, additions = [] as any, moves = [] as any, - removals = [] as any, identityChanges = [] as any}): string { +export function iterableChangesAsString({ + collection = [] as any, + previous = [] as any, + additions = [] as any, + moves = [] as any, + removals = [] as any, + identityChanges = [] as any +}): string { return 'collection: ' + collection.join(', ') + '\n' + 'previous: ' + previous.join(', ') + '\n' + 'additions: ' + additions.join(', ') + '\n' + diff --git a/packages/core/test/component_fixture_spec.ts b/packages/core/test/component_fixture_spec.ts index 882bf548cb0a7..b40a78b06a401 100644 --- a/packages/core/test/component_fixture_spec.ts +++ b/packages/core/test/component_fixture_spec.ts @@ -7,7 +7,7 @@ */ import {Component, Injectable, Input} from '@angular/core'; -import {ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, TestBed, async, withModule} from '@angular/core/testing'; +import {async, ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, TestBed, withModule} from '@angular/core/testing'; import {dispatchEvent} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -15,7 +15,9 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; @Injectable() class SimpleComp { simpleBinding: string; - constructor() { this.simpleBinding = 'Simple'; } + constructor() { + this.simpleBinding = 'Simple'; + } } @Component({ @@ -31,7 +33,9 @@ class MyIfComp { class AutoDetectComp { text: string = '1'; - click() { this.text += '1'; } + click() { + this.text += '1'; + } } @Component({selector: 'async-comp', template: `<span (click)='click()'>{{text}}</span>`}) @@ -39,7 +43,9 @@ class AsyncComp { text: string = '1'; click() { - Promise.resolve(null).then((_) => { this.text += '1'; }); + Promise.resolve(null).then((_) => { + this.text += '1'; + }); } } @@ -49,7 +55,9 @@ class AsyncChildComp { @Input() set text(value: string) { - Promise.resolve(null).then((_) => { this.localText = value; }); + Promise.resolve(null).then((_) => { + this.localText = value; + }); } } @@ -60,7 +68,9 @@ class AsyncChildComp { class AsyncChangeComp { text: string = '1'; - click() { this.text += '1'; } + click() { + this.text += '1'; + } } @Component({selector: 'async-timeout-comp', template: `<span (click)='click()'>{{text}}</span>`}) @@ -68,7 +78,9 @@ class AsyncTimeoutComp { text: string = '1'; click() { - setTimeout(() => { this.text += '1'; }, 10); + setTimeout(() => { + this.text += '1'; + }, 10); } } @@ -78,7 +90,11 @@ class NestedAsyncTimeoutComp { text: string = '1'; click() { - setTimeout(() => { setTimeout(() => { this.text += '1'; }, 10); }, 10); + setTimeout(() => { + setTimeout(() => { + this.text += '1'; + }, 10); + }, 10); } } @@ -94,7 +110,6 @@ class NestedAsyncTimeoutComp { })); it('should auto detect changes if autoDetectChanges is called', () => { - const componentFixture = TestBed.createComponent(AutoDetectComp); expect(componentFixture.ngZone).not.toBeNull(); componentFixture.autoDetectChanges(); @@ -109,7 +124,6 @@ class NestedAsyncTimeoutComp { it('should auto detect changes if ComponentFixtureAutoDetect is provided as true', withModule({providers: [{provide: ComponentFixtureAutoDetect, useValue: true}]}, () => { - const componentFixture = TestBed.createComponent(AutoDetectComp); expect(componentFixture.nativeElement).toHaveText('1'); @@ -181,7 +195,6 @@ class NestedAsyncTimeoutComp { it('should wait for macroTask(setTimeout) while checking for whenStable ' + '(no autoDetectChanges)', async(() => { - const componentFixture = TestBed.createComponent(AsyncTimeoutComp); componentFixture.detectChanges(); expect(componentFixture.nativeElement).toHaveText('1'); @@ -203,7 +216,6 @@ class NestedAsyncTimeoutComp { it('should wait for nested macroTasks(setTimeout) while checking for whenStable ' + '(autoDetectChanges)', async(() => { - const componentFixture = TestBed.createComponent(NestedAsyncTimeoutComp); componentFixture.autoDetectChanges(); @@ -225,7 +237,6 @@ class NestedAsyncTimeoutComp { it('should wait for nested macroTasks(setTimeout) while checking for whenStable ' + '(no autoDetectChanges)', async(() => { - const componentFixture = TestBed.createComponent(NestedAsyncTimeoutComp); componentFixture.detectChanges(); expect(componentFixture.nativeElement).toHaveText('1'); @@ -245,7 +256,6 @@ class NestedAsyncTimeoutComp { })); it('should stabilize after async task in change detection (autoDetectChanges)', async(() => { - const componentFixture = TestBed.createComponent(AsyncChangeComp); componentFixture.autoDetectChanges(); @@ -255,13 +265,13 @@ class NestedAsyncTimeoutComp { const element = componentFixture.debugElement.children[0]; dispatchEvent(element.nativeElement, 'click'); - componentFixture.whenStable().then( - (_) => { expect(componentFixture.nativeElement).toHaveText('11'); }); + componentFixture.whenStable().then((_) => { + expect(componentFixture.nativeElement).toHaveText('11'); + }); }); })); it('should stabilize after async task in change detection(no autoDetectChanges)', async(() => { - const componentFixture = TestBed.createComponent(AsyncChangeComp); componentFixture.detectChanges(); componentFixture.whenStable().then((_) => { @@ -290,7 +300,6 @@ class NestedAsyncTimeoutComp { }); it('calling autoDetectChanges raises an error', () => { - const componentFixture = TestBed.createComponent(SimpleComp); expect(() => { componentFixture.autoDetectChanges(); @@ -298,7 +307,6 @@ class NestedAsyncTimeoutComp { }); it('should instantiate a component with valid DOM', async(() => { - const componentFixture = TestBed.createComponent(SimpleComp); expect(componentFixture.ngZone).toBeNull(); @@ -307,7 +315,6 @@ class NestedAsyncTimeoutComp { })); it('should allow changing members of the component', async(() => { - const componentFixture = TestBed.createComponent(MyIfComp); componentFixture.detectChanges(); @@ -316,9 +323,7 @@ class NestedAsyncTimeoutComp { componentFixture.componentInstance.showMore = true; componentFixture.detectChanges(); expect(componentFixture.nativeElement).toHaveText('MyIf(More)'); - })); }); - }); } diff --git a/packages/core/test/debug/debug_node_spec.ts b/packages/core/test/debug/debug_node_spec.ts index 255a8057ddbd4..0ebe8c3e60191 100644 --- a/packages/core/test/debug/debug_node_spec.ts +++ b/packages/core/test/debug/debug_node_spec.ts @@ -10,7 +10,7 @@ import {CommonModule, NgIfContext, ɵgetDOM as getDOM} from '@angular/common'; import {Component, DebugElement, DebugNode, Directive, ElementRef, EmbeddedViewRef, EventEmitter, HostBinding, Injectable, Input, NO_ERRORS_SCHEMA, OnInit, Output, Renderer2, TemplateRef, ViewChild, ViewContainerRef} from '@angular/core'; import {NgZone} from '@angular/core/src/zone'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {createMouseEvent, hasClass} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -20,18 +20,26 @@ import {ivyEnabled, onlyInIvy} from '@angular/private/testing'; class Logger { logs: string[]; - constructor() { this.logs = []; } + constructor() { + this.logs = []; + } - add(thing: string) { this.logs.push(thing); } + add(thing: string) { + this.logs.push(thing); + } } @Directive({selector: '[message]', inputs: ['message']}) class MessageDir { logger: Logger; - constructor(logger: Logger) { this.logger = logger; } + constructor(logger: Logger) { + this.logger = logger; + } - set message(newMessage: string) { this.logger.add(newMessage); } + set message(newMessage: string) { + this.logger.add(newMessage); + } } @Directive({selector: '[with-title]', inputs: ['title']}) @@ -49,7 +57,9 @@ class WithTitleDir { class ChildComp { childBinding: string; - constructor() { this.childBinding = 'Original'; } + constructor() { + this.childBinding = 'Original'; + } } @Component({ @@ -63,14 +73,18 @@ class ChildComp { }) class ParentComp { parentBinding: string; - constructor() { this.parentBinding = 'OriginalParent'; } + constructor() { + this.parentBinding = 'OriginalParent'; + } } @Directive({selector: 'custom-emitter', outputs: ['myevent']}) class CustomEmitter { myevent: EventEmitter<any>; - constructor() { this.myevent = new EventEmitter(); } + constructor() { + this.myevent = new EventEmitter(); + } } @Component({ @@ -87,9 +101,13 @@ class EventsComp { this.customed = false; } - handleClick() { this.clicked = true; } + handleClick() { + this.clicked = true; + } - handleCustom() { this.customed = true; } + handleCustom() { + this.customed = true; + } } @Component({ @@ -111,7 +129,9 @@ class ConditionalContentComp { }) class ConditionalParentComp { parentBinding: string; - constructor() { this.parentBinding = 'OriginalParent'; } + constructor() { + this.parentBinding = 'OriginalParent'; + } } @Component({ @@ -124,7 +144,9 @@ class ConditionalParentComp { }) class UsingFor { stuff: string[]; - constructor() { this.stuff = ['one', 'two', 'three']; } + constructor() { + this.stuff = ['one', 'two', 'three']; + } } @Directive({selector: '[mydir]', exportAs: 'mydir'}) @@ -154,12 +176,12 @@ class LocalsComp { }) class BankAccount { // TODO(issue/24571): remove '!'. - @Input() bank !: string; + @Input() bank!: string; // TODO(issue/24571): remove '!'. - @Input('account') id !: string; + @Input('account') id!: string; // TODO(issue/24571): remove '!'. - normalizedBankName !: string; + normalizedBankName!: string; } @Component({ @@ -168,7 +190,7 @@ class BankAccount { ` }) class SimpleContentComp { - @ViewChild('content') content !: ElementRef; + @ViewChild('content') content!: ElementRef; } @Component({ @@ -199,8 +221,7 @@ class TestCmptWithRenderer { @Component({selector: 'host-class-binding', template: ''}) class HostClassBindingCmp { - @HostBinding('class') - hostClasses = 'class-one class-two'; + @HostBinding('class') hostClasses = 'class-one class-two'; } @Component({selector: 'test-cmpt-vcref', template: `<div></div>`}) @@ -525,11 +546,15 @@ class TestCmptWithPropInterpolation { class ViewManipulatingDirective { constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<any>) {} - insert() { this._vcRef.createEmbeddedView(this._tplRef); } + insert() { + this._vcRef.createEmbeddedView(this._tplRef); + } removeFromTheDom() { const viewRef = this._vcRef.get(0) as EmbeddedViewRef<any>; - viewRef.rootNodes.forEach(rootNode => { getDOM().remove(rootNode); }); + viewRef.rootNodes.forEach(rootNode => { + getDOM().remove(rootNode); + }); } } @@ -596,7 +621,6 @@ class TestCmptWithPropInterpolation { describe('DebugElement.query with dynamically created descendant elements', () => { let fixture: ComponentFixture<{}>; beforeEach(() => { - @Directive({ selector: '[dir]', }) @@ -627,11 +651,11 @@ class TestCmptWithPropInterpolation { TestBed.configureTestingModule({declarations: [MyComponent, MyDir]}); fixture = TestBed.createComponent(MyComponent); fixture.detectChanges(); - }); - it('should find the dynamic elements from fixture root', - () => { expect(fixture.debugElement.query(By.css('.myclass'))).toBeTruthy(); }); + it('should find the dynamic elements from fixture root', () => { + expect(fixture.debugElement.query(By.css('.myclass'))).toBeTruthy(); + }); it('can use a dynamic element as root for another query', () => { const inner = fixture.debugElement.query(By.css('.inner')); @@ -660,15 +684,17 @@ class TestCmptWithPropInterpolation { el = fixture.debugElement; }); - it('when searching for elements by name', - () => { expect(() => el.query(e => e.name === 'any search text')).not.toThrow(); }); + it('when searching for elements by name', () => { + expect(() => el.query(e => e.name === 'any search text')).not.toThrow(); + }); it('when searching for elements by their attributes', () => { - expect(() => el.query(e => e.attributes !['name'] === 'any attribute')).not.toThrow(); + expect(() => el.query(e => e.attributes!['name'] === 'any attribute')).not.toThrow(); }); - it('when searching for elements by their classes', - () => { expect(() => el.query(e => e.classes['any class'] === true)).not.toThrow(); }); + it('when searching for elements by their classes', () => { + expect(() => el.query(e => e.classes['any class'] === true)).not.toThrow(); + }); it('when searching for elements by their styles', () => { expect(() => el.query(e => e.styles['any style'] === 'any value')).not.toThrow(); @@ -678,23 +704,29 @@ class TestCmptWithPropInterpolation { expect(() => el.query(e => e.properties['any prop'] === 'any value')).not.toThrow(); }); - it('when searching by componentInstance', - () => { expect(() => el.query(e => e.componentInstance === null)).not.toThrow(); }); + it('when searching by componentInstance', () => { + expect(() => el.query(e => e.componentInstance === null)).not.toThrow(); + }); - it('when searching by context', - () => { expect(() => el.query(e => e.context === null)).not.toThrow(); }); + it('when searching by context', () => { + expect(() => el.query(e => e.context === null)).not.toThrow(); + }); - it('when searching by listeners', - () => { expect(() => el.query(e => e.listeners.length === 0)).not.toThrow(); }); + it('when searching by listeners', () => { + expect(() => el.query(e => e.listeners.length === 0)).not.toThrow(); + }); - it('when searching by references', - () => { expect(() => el.query(e => e.references === null)).not.toThrow(); }); + it('when searching by references', () => { + expect(() => el.query(e => e.references === null)).not.toThrow(); + }); - it('when searching by providerTokens', - () => { expect(() => el.query(e => e.providerTokens.length === 0)).not.toThrow(); }); + it('when searching by providerTokens', () => { + expect(() => el.query(e => e.providerTokens.length === 0)).not.toThrow(); + }); - it('when searching by injector', - () => { expect(() => el.query(e => e.injector === null)).not.toThrow(); }); + it('when searching by injector', () => { + expect(() => el.query(e => e.injector === null)).not.toThrow(); + }); onlyInIvy('VE does not match elements created outside Angular context') .it('when using the out-of-context element as the DebugElement query root', () => { @@ -746,7 +778,7 @@ class TestCmptWithPropInterpolation { fixture = TestBed.createComponent(LocalsComp); fixture.detectChanges(); - expect(fixture.debugElement.children[0].references !['alice']).toBeAnInstanceOf(MyDir); + expect(fixture.debugElement.children[0].references!['alice']).toBeAnInstanceOf(MyDir); }); it('should allow injecting from the element injector', () => { @@ -941,7 +973,6 @@ class TestCmptWithPropInterpolation { }); describe('componentInstance on DebugNode', () => { - it('should return component associated with a node if a node is a component host', () => { TestBed.overrideTemplate(TestCmpt, `<parent-comp></parent-comp>`); fixture = TestBed.createComponent(TestCmpt); @@ -1199,7 +1230,9 @@ class TestCmptWithPropInterpolation { }) class App { visible = true; - cancel() { calls++; } + cancel() { + calls++; + } } TestBed.configureTestingModule({declarations: [App, CancelButton]}); @@ -1218,7 +1251,6 @@ class TestCmptWithPropInterpolation { expect(calls).toBe(1, 'Expected calls to stay 1 after destroying the node.'); }); - }); it('should not error when accessing node name', () => { @@ -1234,7 +1266,7 @@ class TestCmptWithPropInterpolation { // Node.ELEMENT_NODE while (node) { superParentName = node.name; - node = node.parent !; + node = node.parent!; } expect(superParentName).not.toEqual(''); }); @@ -1257,13 +1289,16 @@ class TestCmptWithPropInterpolation { it('does not call event listeners added outside angular context', () => { let listenerCalled = false; const eventToTrigger = createMouseEvent('mouseenter'); - function listener() { listenerCalled = true; } + function listener() { + listenerCalled = true; + } @Component({template: ''}) class MyComp { constructor(private readonly zone: NgZone, private readonly element: ElementRef) {} ngOnInit() { - this.zone.runOutsideAngular( - () => { this.element.nativeElement.addEventListener('mouseenter', listener); }); + this.zone.runOutsideAngular(() => { + this.element.nativeElement.addEventListener('mouseenter', listener); + }); } } const fixture = diff --git a/packages/core/test/dev_mode_spec.ts b/packages/core/test/dev_mode_spec.ts index 926bfd86d39b5..d64f0cdd9dec9 100644 --- a/packages/core/test/dev_mode_spec.ts +++ b/packages/core/test/dev_mode_spec.ts @@ -10,6 +10,8 @@ import {isDevMode} from '@angular/core'; { describe('dev mode', () => { - it('is enabled in our tests by default', () => { expect(isDevMode()).toBe(true); }); + it('is enabled in our tests by default', () => { + expect(isDevMode()).toBe(true); + }); }); } diff --git a/packages/core/test/di/injector_spec.ts b/packages/core/test/di/injector_spec.ts index aef7d802f3926..7db573fbadc9a 100644 --- a/packages/core/test/di/injector_spec.ts +++ b/packages/core/test/di/injector_spec.ts @@ -22,7 +22,8 @@ import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; .toThrowError('NullInjectorError: No provider for someToken!'); }); - it('should return the default value', - () => { expect(Injector.NULL.get('someToken', 'notFound')).toEqual('notFound'); }); + it('should return the default value', () => { + expect(Injector.NULL.get('someToken', 'notFound')).toEqual('notFound'); + }); }); } diff --git a/packages/core/test/di/r3_injector_spec.ts b/packages/core/test/di/r3_injector_spec.ts index fb48a634b8d4e..680c2c9ff3017 100644 --- a/packages/core/test/di/r3_injector_spec.ts +++ b/packages/core/test/di/r3_injector_spec.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {INJECTOR, InjectFlags, InjectionToken, Injector, Optional, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵinject} from '@angular/core'; -import {R3Injector, createInjector} from '@angular/core/src/di/r3_injector'; +import {InjectFlags, InjectionToken, INJECTOR, Injector, Optional, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵinject} from '@angular/core'; +import {createInjector, R3Injector} from '@angular/core/src/di/r3_injector'; import {expect} from '@angular/platform-browser/testing/src/matchers'; describe('InjectorDef-based createInjector()', () => { @@ -64,7 +64,7 @@ describe('InjectorDef-based createInjector()', () => { providedIn: null, // ChildService is derived from ServiceWithDep, so the factory function here must do the right // thing and create an instance of the requested type if one is given. - factory: (t?: typeof ServiceWithDep) => new (t || ServiceWithDep)(ɵɵinject(Service)), + factory: (t?: typeof ServiceWithDep) => new(t || ServiceWithDep)(ɵɵinject(Service)), }); } @@ -114,7 +114,9 @@ describe('InjectorDef-based createInjector()', () => { factory: () => new DeepService(), }); - ngOnDestroy(): void { deepServiceDestroyed = true; } + ngOnDestroy(): void { + deepServiceDestroyed = true; + } } let eagerServiceCreated: boolean = false; @@ -125,20 +127,31 @@ describe('InjectorDef-based createInjector()', () => { factory: () => new EagerService(), }); - constructor() { eagerServiceCreated = true; } + constructor() { + eagerServiceCreated = true; + } } let deepModuleCreated: boolean = false; class DeepModule { - constructor(eagerService: EagerService) { deepModuleCreated = true; } + constructor(eagerService: EagerService) { + deepModuleCreated = true; + } static ɵinj = ɵɵdefineInjector({ factory: () => new DeepModule(ɵɵinject(EagerService)), imports: undefined, - providers: [ - EagerService, - {provide: DeepService, useFactory: () => { throw new Error('Not overridden!'); }}, - ], + providers: + [ + EagerService, + { + provide: DeepService, + useFactory: + () => { + throw new Error('Not overridden!'); + } + }, + ], }); static safe() { @@ -171,22 +184,23 @@ describe('InjectorDef-based createInjector()', () => { static ɵinj = ɵɵdefineInjector({ factory: () => new Module(), imports: [IntermediateModule], - providers: [ - ChildService, - ServiceWithDep, - ServiceWithOptionalDep, - ServiceWithMultiDep, - {provide: LOCALE, multi: true, useValue: 'en'}, - {provide: LOCALE, multi: true, useValue: 'es'}, - {provide: PRIMITIVE_VALUE, useValue: 'foo'}, - {provide: UNDEFINED_VALUE, useValue: undefined}, - Service, - {provide: SERVICE_TOKEN, useExisting: Service}, - CircularA, - CircularB, - {provide: STATIC_TOKEN, useClass: StaticService, deps: [Service]}, - InjectorWithDep, - ], + providers: + [ + ChildService, + ServiceWithDep, + ServiceWithOptionalDep, + ServiceWithMultiDep, + {provide: LOCALE, multi: true, useValue: 'en'}, + {provide: LOCALE, multi: true, useValue: 'es'}, + {provide: PRIMITIVE_VALUE, useValue: 'foo'}, + {provide: UNDEFINED_VALUE, useValue: undefined}, + Service, + {provide: SERVICE_TOKEN, useExisting: Service}, + CircularA, + CircularB, + {provide: STATIC_TOKEN, useClass: StaticService, deps: [Service]}, + InjectorWithDep, + ], }); } @@ -224,7 +238,9 @@ describe('InjectorDef-based createInjector()', () => { factory: () => new ScopedService(), }); - ngOnDestroy(): void { scopedServiceDestroyed = true; } + ngOnDestroy(): void { + scopedServiceDestroyed = true; + } } class WrongScopeService { @@ -252,10 +268,11 @@ describe('InjectorDef-based createInjector()', () => { class WithProvidersTest { static ɵinj = ɵɵdefineInjector({ factory: () => new WithProvidersTest(), - imports: [ - {ngModule: MultiProviderA, providers: [{provide: LOCALE, multi: true, useValue: 'C'}]}, - MultiProviderB - ], + imports: + [ + {ngModule: MultiProviderA, providers: [{provide: LOCALE, multi: true, useValue: 'C'}]}, + MultiProviderB + ], providers: [], }); } @@ -276,7 +293,9 @@ describe('InjectorDef-based createInjector()', () => { imports: undefined, providers: [], }); - constructor() { moduleRegistrations.push('ChildModule'); } + constructor() { + moduleRegistrations.push('ChildModule'); + } } class RootModule { @@ -285,7 +304,9 @@ describe('InjectorDef-based createInjector()', () => { imports: [ChildModule], providers: [], }); - constructor() { moduleRegistrations.push('RootModule'); } + constructor() { + moduleRegistrations.push('RootModule'); + } } createInjector(RootModule); expect(moduleRegistrations).toEqual(['ChildModule', 'RootModule']); @@ -297,8 +318,9 @@ describe('InjectorDef-based createInjector()', () => { expect(injector.get(Service)).toBe(instance); }); - it('returns the default value if a provider isn\'t present', - () => { expect(injector.get(ServiceTwo, null)).toBeNull(); }); + it('returns the default value if a provider isn\'t present', () => { + expect(injector.get(ServiceTwo, null)).toBeNull(); + }); it('should throw when no provider defined', () => { expect(() => injector.get(ServiceTwo)) @@ -373,14 +395,17 @@ describe('InjectorDef-based createInjector()', () => { expect(instance.dep).toBe(injector.get(Service)); }); - it('allows injecting itself via INJECTOR', - () => { expect(injector.get(INJECTOR)).toBe(injector); }); + it('allows injecting itself via INJECTOR', () => { + expect(injector.get(INJECTOR)).toBe(injector); + }); - it('allows injecting itself via Injector', - () => { expect(injector.get(Injector)).toBe(injector); }); + it('allows injecting itself via Injector', () => { + expect(injector.get(Injector)).toBe(injector); + }); - it('allows injecting a deeply imported service', - () => { expect(injector.get(DeepService) instanceof DeepService).toBeTruthy(); }); + it('allows injecting a deeply imported service', () => { + expect(injector.get(DeepService) instanceof DeepService).toBeTruthy(); + }); it('allows injecting a scoped service', () => { const instance = injector.get(ScopedService); @@ -393,8 +418,9 @@ describe('InjectorDef-based createInjector()', () => { expect(instance instanceof ChildService).toBe(true); }); - it('does not create instances of a service not in scope', - () => { expect(injector.get(WrongScopeService, null)).toBeNull(); }); + it('does not create instances of a service not in scope', () => { + expect(injector.get(WrongScopeService, null)).toBeNull(); + }); it('eagerly instantiates the injectordef types', () => { expect(deepModuleCreated).toBe(true, 'DeepModule not instantiated'); @@ -432,11 +458,13 @@ describe('InjectorDef-based createInjector()', () => { }); describe('error handling', () => { - it('throws an error when a token is not found', - () => { expect(() => injector.get(ServiceTwo)).toThrow(); }); + it('throws an error when a token is not found', () => { + expect(() => injector.get(ServiceTwo)).toThrow(); + }); - it('throws an error on circular deps', - () => { expect(() => injector.get(CircularA)).toThrow(); }); + it('throws an error on circular deps', () => { + expect(() => injector.get(CircularA)).toThrow(); + }); it('should throw when it can\'t resolve all arguments', () => { class MissingArgumentType { diff --git a/packages/core/test/di/reflective_injector_spec.ts b/packages/core/test/di/reflective_injector_spec.ts index 139f8d1eab64a..38bb93b0a4a81 100644 --- a/packages/core/test/di/reflective_injector_spec.ts +++ b/packages/core/test/di/reflective_injector_spec.ts @@ -6,17 +6,20 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, Injectable, InjectionToken, Injector, Optional, Provider, ReflectiveInjector, ReflectiveKey, Self, forwardRef} from '@angular/core'; +import {forwardRef, Inject, Injectable, InjectionToken, Injector, Optional, Provider, ReflectiveInjector, ReflectiveKey, Self} from '@angular/core'; import {ReflectiveInjector_} from '@angular/core/src/di/reflective_injector'; import {ResolvedReflectiveProvider_} from '@angular/core/src/di/reflective_provider'; import {getOriginalError} from '@angular/core/src/errors'; import {expect} from '@angular/platform-browser/testing/src/matchers'; + import {stringify} from '../../src/util/stringify'; class Engine {} class BrokenEngine { - constructor() { throw new Error('Broken Engine'); } + constructor() { + throw new Error('Broken Engine'); + } } class DashboardSoftware {} @@ -66,464 +69,456 @@ class NoAnnotations { constructor(secretDependency: any) {} } -function factoryFn(a: any){} +function factoryFn(a: any) {} (function() { - const dynamicProviders = [ - {provide: 'provider0', useValue: 1}, {provide: 'provider1', useValue: 1}, - {provide: 'provider2', useValue: 1}, {provide: 'provider3', useValue: 1}, - {provide: 'provider4', useValue: 1}, {provide: 'provider5', useValue: 1}, - {provide: 'provider6', useValue: 1}, {provide: 'provider7', useValue: 1}, - {provide: 'provider8', useValue: 1}, {provide: 'provider9', useValue: 1}, - {provide: 'provider10', useValue: 1} - ]; - - function createInjector( - providers: Provider[], parent?: ReflectiveInjector | null): ReflectiveInjector_ { - const resolvedProviders = ReflectiveInjector.resolve(providers.concat(dynamicProviders)); - if (parent != null) { - return <ReflectiveInjector_>parent.createChildFromResolved(resolvedProviders); - } else { - return <ReflectiveInjector_>ReflectiveInjector.fromResolvedProviders(resolvedProviders); - } +const dynamicProviders = [ + {provide: 'provider0', useValue: 1}, {provide: 'provider1', useValue: 1}, + {provide: 'provider2', useValue: 1}, {provide: 'provider3', useValue: 1}, + {provide: 'provider4', useValue: 1}, {provide: 'provider5', useValue: 1}, + {provide: 'provider6', useValue: 1}, {provide: 'provider7', useValue: 1}, + {provide: 'provider8', useValue: 1}, {provide: 'provider9', useValue: 1}, + {provide: 'provider10', useValue: 1} +]; + +function createInjector( + providers: Provider[], parent?: ReflectiveInjector|null): ReflectiveInjector_ { + const resolvedProviders = ReflectiveInjector.resolve(providers.concat(dynamicProviders)); + if (parent != null) { + return <ReflectiveInjector_>parent.createChildFromResolved(resolvedProviders); + } else { + return <ReflectiveInjector_>ReflectiveInjector.fromResolvedProviders(resolvedProviders); } +} - describe(`injector`, () => { - - it('should instantiate a class without dependencies', () => { - const injector = createInjector([Engine]); - const engine = injector.get(Engine); - - expect(engine).toBeAnInstanceOf(Engine); - }); - - it('should resolve dependencies based on type information', () => { - const injector = createInjector([Engine, Car]); - const car = injector.get(Car); +describe(`injector`, () => { + it('should instantiate a class without dependencies', () => { + const injector = createInjector([Engine]); + const engine = injector.get(Engine); - expect(car).toBeAnInstanceOf(Car); - expect(car.engine).toBeAnInstanceOf(Engine); - }); + expect(engine).toBeAnInstanceOf(Engine); + }); - it('should resolve dependencies based on @Inject annotation', () => { - const injector = createInjector([TurboEngine, Engine, CarWithInject]); - const car = injector.get(CarWithInject); + it('should resolve dependencies based on type information', () => { + const injector = createInjector([Engine, Car]); + const car = injector.get(Car); - expect(car).toBeAnInstanceOf(CarWithInject); - expect(car.engine).toBeAnInstanceOf(TurboEngine); - }); + expect(car).toBeAnInstanceOf(Car); + expect(car.engine).toBeAnInstanceOf(Engine); + }); - it('should throw when no type and not @Inject (class case)', () => { - expect(() => createInjector([NoAnnotations])) - .toThrowError( - 'Cannot resolve all parameters for \'NoAnnotations\'(?). ' + - 'Make sure that all the parameters are decorated with Inject or have valid type annotations ' + - 'and that \'NoAnnotations\' is decorated with Injectable.'); - }); + it('should resolve dependencies based on @Inject annotation', () => { + const injector = createInjector([TurboEngine, Engine, CarWithInject]); + const car = injector.get(CarWithInject); - it('should throw when no type and not @Inject (factory case)', () => { - expect(() => createInjector([{provide: 'someToken', useFactory: factoryFn}])) - .toThrowError( - 'Cannot resolve all parameters for \'factoryFn\'(?). ' + - 'Make sure that all the parameters are decorated with Inject or have valid type annotations ' + - 'and that \'factoryFn\' is decorated with Injectable.'); - }); + expect(car).toBeAnInstanceOf(CarWithInject); + expect(car.engine).toBeAnInstanceOf(TurboEngine); + }); - it('should cache instances', () => { - const injector = createInjector([Engine]); + it('should throw when no type and not @Inject (class case)', () => { + expect(() => createInjector([NoAnnotations])) + .toThrowError( + 'Cannot resolve all parameters for \'NoAnnotations\'(?). ' + + 'Make sure that all the parameters are decorated with Inject or have valid type annotations ' + + 'and that \'NoAnnotations\' is decorated with Injectable.'); + }); - const e1 = injector.get(Engine); - const e2 = injector.get(Engine); + it('should throw when no type and not @Inject (factory case)', () => { + expect(() => createInjector([{provide: 'someToken', useFactory: factoryFn}])) + .toThrowError( + 'Cannot resolve all parameters for \'factoryFn\'(?). ' + + 'Make sure that all the parameters are decorated with Inject or have valid type annotations ' + + 'and that \'factoryFn\' is decorated with Injectable.'); + }); - expect(e1).toBe(e2); - }); + it('should cache instances', () => { + const injector = createInjector([Engine]); - it('should provide to a value', () => { - const injector = createInjector([{provide: Engine, useValue: 'fake engine'}]); + const e1 = injector.get(Engine); + const e2 = injector.get(Engine); - const engine = injector.get(Engine); - expect(engine).toEqual('fake engine'); - }); + expect(e1).toBe(e2); + }); - it('should inject dependencies instance of InjectionToken', () => { - const TOKEN = new InjectionToken<string>('token'); + it('should provide to a value', () => { + const injector = createInjector([{provide: Engine, useValue: 'fake engine'}]); - const injector = createInjector([ - {provide: TOKEN, useValue: 'by token'}, - {provide: Engine, useFactory: (v: string) => v, deps: [[TOKEN]]}, - ]); + const engine = injector.get(Engine); + expect(engine).toEqual('fake engine'); + }); - const engine = injector.get(Engine); - expect(engine).toEqual('by token'); - }); + it('should inject dependencies instance of InjectionToken', () => { + const TOKEN = new InjectionToken<string>('token'); - it('should provide to a factory', () => { - function sportsCarFactory(e: any) { return new SportsCar(e); } + const injector = createInjector([ + {provide: TOKEN, useValue: 'by token'}, + {provide: Engine, useFactory: (v: string) => v, deps: [[TOKEN]]}, + ]); - const injector = - createInjector([Engine, {provide: Car, useFactory: sportsCarFactory, deps: [Engine]}]); + const engine = injector.get(Engine); + expect(engine).toEqual('by token'); + }); - const car = injector.get(Car); - expect(car).toBeAnInstanceOf(SportsCar); - expect(car.engine).toBeAnInstanceOf(Engine); - }); + it('should provide to a factory', () => { + function sportsCarFactory(e: any) { + return new SportsCar(e); + } - it('should supporting provider to null', () => { - const injector = createInjector([{provide: Engine, useValue: null}]); - const engine = injector.get(Engine); - expect(engine).toBeNull(); - }); + const injector = + createInjector([Engine, {provide: Car, useFactory: sportsCarFactory, deps: [Engine]}]); - it('should provide to an alias', () => { - const injector = createInjector([ - Engine, {provide: SportsCar, useClass: SportsCar}, {provide: Car, useExisting: SportsCar} - ]); + const car = injector.get(Car); + expect(car).toBeAnInstanceOf(SportsCar); + expect(car.engine).toBeAnInstanceOf(Engine); + }); - const car = injector.get(Car); - const sportsCar = injector.get(SportsCar); - expect(car).toBeAnInstanceOf(SportsCar); - expect(car).toBe(sportsCar); - }); + it('should supporting provider to null', () => { + const injector = createInjector([{provide: Engine, useValue: null}]); + const engine = injector.get(Engine); + expect(engine).toBeNull(); + }); - it('should support multiProviders', () => { - const injector = createInjector([ - Engine, {provide: Car, useClass: SportsCar, multi: true}, - {provide: Car, useClass: CarWithOptionalEngine, multi: true} - ]); + it('should provide to an alias', () => { + const injector = createInjector([ + Engine, {provide: SportsCar, useClass: SportsCar}, {provide: Car, useExisting: SportsCar} + ]); - const cars = injector.get(Car); - expect(cars.length).toEqual(2); - expect(cars[0]).toBeAnInstanceOf(SportsCar); - expect(cars[1]).toBeAnInstanceOf(CarWithOptionalEngine); - }); + const car = injector.get(Car); + const sportsCar = injector.get(SportsCar); + expect(car).toBeAnInstanceOf(SportsCar); + expect(car).toBe(sportsCar); + }); - it('should support multiProviders that are created using useExisting', () => { - const injector = - createInjector([Engine, SportsCar, {provide: Car, useExisting: SportsCar, multi: true}]); + it('should support multiProviders', () => { + const injector = createInjector([ + Engine, {provide: Car, useClass: SportsCar, multi: true}, + {provide: Car, useClass: CarWithOptionalEngine, multi: true} + ]); - const cars = injector.get(Car); - expect(cars.length).toEqual(1); - expect(cars[0]).toBe(injector.get(SportsCar)); - }); + const cars = injector.get(Car); + expect(cars.length).toEqual(2); + expect(cars[0]).toBeAnInstanceOf(SportsCar); + expect(cars[1]).toBeAnInstanceOf(CarWithOptionalEngine); + }); - it('should throw when the aliased provider does not exist', () => { - const injector = createInjector([{provide: 'car', useExisting: SportsCar}]); - const e = `No provider for ${stringify(SportsCar)}! (car -> ${stringify(SportsCar)})`; - expect(() => injector.get('car')).toThrowError(e); - }); + it('should support multiProviders that are created using useExisting', () => { + const injector = + createInjector([Engine, SportsCar, {provide: Car, useExisting: SportsCar, multi: true}]); - it('should handle forwardRef in useExisting', () => { - const injector = createInjector([ - {provide: 'originalEngine', useClass: forwardRef(() => Engine)}, - {provide: 'aliasedEngine', useExisting: <any>forwardRef(() => 'originalEngine')} - ]); - expect(injector.get('aliasedEngine')).toBeAnInstanceOf(Engine); - }); + const cars = injector.get(Car); + expect(cars.length).toEqual(1); + expect(cars[0]).toBe(injector.get(SportsCar)); + }); - it('should support overriding factory dependencies', () => { - const injector = createInjector( - [Engine, {provide: Car, useFactory: (e: Engine) => new SportsCar(e), deps: [Engine]}]); + it('should throw when the aliased provider does not exist', () => { + const injector = createInjector([{provide: 'car', useExisting: SportsCar}]); + const e = `No provider for ${stringify(SportsCar)}! (car -> ${stringify(SportsCar)})`; + expect(() => injector.get('car')).toThrowError(e); + }); - const car = injector.get(Car); - expect(car).toBeAnInstanceOf(SportsCar); - expect(car.engine).toBeAnInstanceOf(Engine); - }); + it('should handle forwardRef in useExisting', () => { + const injector = createInjector([ + {provide: 'originalEngine', useClass: forwardRef(() => Engine)}, + {provide: 'aliasedEngine', useExisting: <any>forwardRef(() => 'originalEngine')} + ]); + expect(injector.get('aliasedEngine')).toBeAnInstanceOf(Engine); + }); - it('should support optional dependencies', () => { - const injector = createInjector([CarWithOptionalEngine]); + it('should support overriding factory dependencies', () => { + const injector = createInjector( + [Engine, {provide: Car, useFactory: (e: Engine) => new SportsCar(e), deps: [Engine]}]); - const car = injector.get(CarWithOptionalEngine); - expect(car.engine).toEqual(null); - }); + const car = injector.get(Car); + expect(car).toBeAnInstanceOf(SportsCar); + expect(car.engine).toBeAnInstanceOf(Engine); + }); - it('should flatten passed-in providers', () => { - const injector = createInjector([[[Engine, Car]]]); + it('should support optional dependencies', () => { + const injector = createInjector([CarWithOptionalEngine]); - const car = injector.get(Car); - expect(car).toBeAnInstanceOf(Car); - }); + const car = injector.get(CarWithOptionalEngine); + expect(car.engine).toEqual(null); + }); - it('should use the last provider when there are multiple providers for same token', () => { - const injector = createInjector( - [{provide: Engine, useClass: Engine}, {provide: Engine, useClass: TurboEngine}]); + it('should flatten passed-in providers', () => { + const injector = createInjector([[[Engine, Car]]]); - expect(injector.get(Engine)).toBeAnInstanceOf(TurboEngine); - }); + const car = injector.get(Car); + expect(car).toBeAnInstanceOf(Car); + }); - it('should use non-type tokens', () => { - const injector = createInjector([{provide: 'token', useValue: 'value'}]); + it('should use the last provider when there are multiple providers for same token', () => { + const injector = createInjector( + [{provide: Engine, useClass: Engine}, {provide: Engine, useClass: TurboEngine}]); - expect(injector.get('token')).toEqual('value'); - }); + expect(injector.get(Engine)).toBeAnInstanceOf(TurboEngine); + }); - it('should throw when given invalid providers', () => { - expect(() => createInjector(<any>['blah'])) - .toThrowError( - 'Invalid provider - only instances of Provider and Type are allowed, got: blah'); - }); + it('should use non-type tokens', () => { + const injector = createInjector([{provide: 'token', useValue: 'value'}]); - it('should provide itself', () => { - const parent = createInjector([]); - const child = parent.resolveAndCreateChild([]); + expect(injector.get('token')).toEqual('value'); + }); - expect(child.get(Injector)).toBe(child); - }); + it('should throw when given invalid providers', () => { + expect(() => createInjector(<any>['blah'])) + .toThrowError( + 'Invalid provider - only instances of Provider and Type are allowed, got: blah'); + }); - it('should throw when no provider defined', () => { - const injector = createInjector([]); - expect(() => injector.get('NonExisting')).toThrowError('No provider for NonExisting!'); - }); + it('should provide itself', () => { + const parent = createInjector([]); + const child = parent.resolveAndCreateChild([]); - it('should show the full path when no provider', () => { - const injector = createInjector([CarWithDashboard, Engine, Dashboard]); - expect(() => injector.get(CarWithDashboard)) - .toThrowError( - `No provider for DashboardSoftware! (${stringify(CarWithDashboard)} -> ${stringify(Dashboard)} -> DashboardSoftware)`); - }); + expect(child.get(Injector)).toBe(child); + }); - it('should throw when trying to instantiate a cyclic dependency', () => { - const injector = createInjector([Car, {provide: Engine, useClass: CyclicEngine}]); + it('should throw when no provider defined', () => { + const injector = createInjector([]); + expect(() => injector.get('NonExisting')).toThrowError('No provider for NonExisting!'); + }); - expect(() => injector.get(Car)) - .toThrowError( - `Cannot instantiate cyclic dependency! (${stringify(Car)} -> ${stringify(Engine)} -> ${stringify(Car)})`); - }); + it('should show the full path when no provider', () => { + const injector = createInjector([CarWithDashboard, Engine, Dashboard]); + expect(() => injector.get(CarWithDashboard)) + .toThrowError(`No provider for DashboardSoftware! (${stringify(CarWithDashboard)} -> ${ + stringify(Dashboard)} -> DashboardSoftware)`); + }); - it('should show the full path when error happens in a constructor', () => { - const providers = - ReflectiveInjector.resolve([Car, {provide: Engine, useClass: BrokenEngine}]); - const injector = new ReflectiveInjector_(providers); - - try { - injector.get(Car); - throw 'Must throw'; - } catch (e) { - expect(e.message).toContain( - `Error during instantiation of Engine! (${stringify(Car)} -> Engine)`); - expect(getOriginalError(e) instanceof Error).toBeTruthy(); - expect(e.keys[0].token).toEqual(Engine); - } - }); + it('should throw when trying to instantiate a cyclic dependency', () => { + const injector = createInjector([Car, {provide: Engine, useClass: CyclicEngine}]); - it('should instantiate an object after a failed attempt', () => { - let isBroken = true; + expect(() => injector.get(Car)) + .toThrowError(`Cannot instantiate cyclic dependency! (${stringify(Car)} -> ${ + stringify(Engine)} -> ${stringify(Car)})`); + }); - const injector = createInjector([ - Car, {provide: Engine, useFactory: (() => isBroken ? new BrokenEngine() : new Engine())} - ]); + it('should show the full path when error happens in a constructor', () => { + const providers = ReflectiveInjector.resolve([Car, {provide: Engine, useClass: BrokenEngine}]); + const injector = new ReflectiveInjector_(providers); + + try { + injector.get(Car); + throw 'Must throw'; + } catch (e) { + expect(e.message).toContain( + `Error during instantiation of Engine! (${stringify(Car)} -> Engine)`); + expect(getOriginalError(e) instanceof Error).toBeTruthy(); + expect(e.keys[0].token).toEqual(Engine); + } + }); - expect(() => injector.get(Car)) - .toThrowError('Broken Engine: Error during instantiation of Engine! (Car -> Engine).'); + it('should instantiate an object after a failed attempt', () => { + let isBroken = true; - isBroken = false; + const injector = createInjector( + [Car, {provide: Engine, useFactory: (() => isBroken ? new BrokenEngine() : new Engine())}]); - expect(injector.get(Car)).toBeAnInstanceOf(Car); - }); + expect(() => injector.get(Car)) + .toThrowError('Broken Engine: Error during instantiation of Engine! (Car -> Engine).'); - it('should support null values', () => { - const injector = createInjector([{provide: 'null', useValue: null}]); - expect(injector.get('null')).toBe(null); - }); + isBroken = false; + expect(injector.get(Car)).toBeAnInstanceOf(Car); }); + it('should support null values', () => { + const injector = createInjector([{provide: 'null', useValue: null}]); + expect(injector.get('null')).toBe(null); + }); +}); - describe('child', () => { - it('should load instances from parent injector', () => { - const parent = ReflectiveInjector.resolveAndCreate([Engine]); - const child = parent.resolveAndCreateChild([]); - const engineFromParent = parent.get(Engine); - const engineFromChild = child.get(Engine); +describe('child', () => { + it('should load instances from parent injector', () => { + const parent = ReflectiveInjector.resolveAndCreate([Engine]); + const child = parent.resolveAndCreateChild([]); - expect(engineFromChild).toBe(engineFromParent); - }); + const engineFromParent = parent.get(Engine); + const engineFromChild = child.get(Engine); - it('should not use the child providers when resolving the dependencies of a parent provider', - () => { - const parent = ReflectiveInjector.resolveAndCreate([Car, Engine]); - const child = parent.resolveAndCreateChild([{provide: Engine, useClass: TurboEngine}]); + expect(engineFromChild).toBe(engineFromParent); + }); - const carFromChild = child.get(Car); - expect(carFromChild.engine).toBeAnInstanceOf(Engine); - }); + it('should not use the child providers when resolving the dependencies of a parent provider', + () => { + const parent = ReflectiveInjector.resolveAndCreate([Car, Engine]); + const child = parent.resolveAndCreateChild([{provide: Engine, useClass: TurboEngine}]); - it('should create new instance in a child injector', () => { - const parent = ReflectiveInjector.resolveAndCreate([Engine]); - const child = parent.resolveAndCreateChild([{provide: Engine, useClass: TurboEngine}]); + const carFromChild = child.get(Car); + expect(carFromChild.engine).toBeAnInstanceOf(Engine); + }); - const engineFromParent = parent.get(Engine); - const engineFromChild = child.get(Engine); + it('should create new instance in a child injector', () => { + const parent = ReflectiveInjector.resolveAndCreate([Engine]); + const child = parent.resolveAndCreateChild([{provide: Engine, useClass: TurboEngine}]); - expect(engineFromParent).not.toBe(engineFromChild); - expect(engineFromChild).toBeAnInstanceOf(TurboEngine); - }); + const engineFromParent = parent.get(Engine); + const engineFromChild = child.get(Engine); - it('should give access to parent', () => { - const parent = ReflectiveInjector.resolveAndCreate([]); - const child = parent.resolveAndCreateChild([]); - expect(child.parent).toBe(parent); - }); + expect(engineFromParent).not.toBe(engineFromChild); + expect(engineFromChild).toBeAnInstanceOf(TurboEngine); }); - describe('resolveAndInstantiate', () => { - it('should instantiate an object in the context of the injector', () => { - const inj = ReflectiveInjector.resolveAndCreate([Engine]); - const car = inj.resolveAndInstantiate(Car); - expect(car).toBeAnInstanceOf(Car); - expect(car.engine).toBe(inj.get(Engine)); - }); - - it('should not store the instantiated object in the injector', () => { - const inj = ReflectiveInjector.resolveAndCreate([Engine]); - inj.resolveAndInstantiate(Car); - expect(() => inj.get(Car)).toThrowError(); - }); + it('should give access to parent', () => { + const parent = ReflectiveInjector.resolveAndCreate([]); + const child = parent.resolveAndCreateChild([]); + expect(child.parent).toBe(parent); }); - - describe('instantiate', () => { - it('should instantiate an object in the context of the injector', () => { - const inj = ReflectiveInjector.resolveAndCreate([Engine]); - const car = inj.instantiateResolved(ReflectiveInjector.resolve([Car])[0]); - expect(car).toBeAnInstanceOf(Car); - expect(car.engine).toBe(inj.get(Engine)); - }); +}); + +describe('resolveAndInstantiate', () => { + it('should instantiate an object in the context of the injector', () => { + const inj = ReflectiveInjector.resolveAndCreate([Engine]); + const car = inj.resolveAndInstantiate(Car); + expect(car).toBeAnInstanceOf(Car); + expect(car.engine).toBe(inj.get(Engine)); }); - describe('depedency resolution', () => { - describe('@Self()', () => { - it('should return a dependency from self', () => { - const inj = ReflectiveInjector.resolveAndCreate([ - Engine, - {provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]} - ]); - - expect(inj.get(Car)).toBeAnInstanceOf(Car); - }); + it('should not store the instantiated object in the injector', () => { + const inj = ReflectiveInjector.resolveAndCreate([Engine]); + inj.resolveAndInstantiate(Car); + expect(() => inj.get(Car)).toThrowError(); + }); +}); + +describe('instantiate', () => { + it('should instantiate an object in the context of the injector', () => { + const inj = ReflectiveInjector.resolveAndCreate([Engine]); + const car = inj.instantiateResolved(ReflectiveInjector.resolve([Car])[0]); + expect(car).toBeAnInstanceOf(Car); + expect(car.engine).toBe(inj.get(Engine)); + }); +}); - it('should throw when not requested provider on self', () => { - const parent = ReflectiveInjector.resolveAndCreate([Engine]); - const child = parent.resolveAndCreateChild( - [{provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]}]); +describe('depedency resolution', () => { + describe('@Self()', () => { + it('should return a dependency from self', () => { + const inj = ReflectiveInjector.resolveAndCreate([ + Engine, {provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]} + ]); - expect(() => child.get(Car)) - .toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`); - }); + expect(inj.get(Car)).toBeAnInstanceOf(Car); }); - describe('default', () => { - it('should not skip self', () => { - const parent = ReflectiveInjector.resolveAndCreate([Engine]); - const child = parent.resolveAndCreateChild([ - {provide: Engine, useClass: TurboEngine}, - {provide: Car, useFactory: (e: Engine) => new Car(e), deps: [Engine]} - ]); + it('should throw when not requested provider on self', () => { + const parent = ReflectiveInjector.resolveAndCreate([Engine]); + const child = parent.resolveAndCreateChild( + [{provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]}]); - expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine); - }); + expect(() => child.get(Car)) + .toThrowError(`No provider for Engine! (${stringify(Car)} -> ${stringify(Engine)})`); }); }); - describe('resolve', () => { - it('should resolve and flatten', () => { - const providers = ReflectiveInjector.resolve([Engine, [BrokenEngine]]); - providers.forEach(function(b) { - if (!b) return; // the result is a sparse array - expect(b instanceof ResolvedReflectiveProvider_).toBe(true); - }); - }); + describe('default', () => { + it('should not skip self', () => { + const parent = ReflectiveInjector.resolveAndCreate([Engine]); + const child = parent.resolveAndCreateChild([ + {provide: Engine, useClass: TurboEngine}, + {provide: Car, useFactory: (e: Engine) => new Car(e), deps: [Engine]} + ]); - it('should support multi providers', () => { - const provider = ReflectiveInjector.resolve([ - {provide: Engine, useClass: BrokenEngine, multi: true}, - {provide: Engine, useClass: TurboEngine, multi: true} - ])[0]; + expect(child.get(Car).engine).toBeAnInstanceOf(TurboEngine); + }); + }); +}); - expect(provider.key.token).toBe(Engine); - expect(provider.multiProvider).toEqual(true); - expect(provider.resolvedFactories.length).toEqual(2); +describe('resolve', () => { + it('should resolve and flatten', () => { + const providers = ReflectiveInjector.resolve([Engine, [BrokenEngine]]); + providers.forEach(function(b) { + if (!b) return; // the result is a sparse array + expect(b instanceof ResolvedReflectiveProvider_).toBe(true); }); + }); + it('should support multi providers', () => { + const provider = ReflectiveInjector.resolve([ + {provide: Engine, useClass: BrokenEngine, multi: true}, + {provide: Engine, useClass: TurboEngine, multi: true} + ])[0]; - it('should support providers as hash', () => { - const provider = ReflectiveInjector.resolve([ - {provide: Engine, useClass: BrokenEngine, multi: true}, - {provide: Engine, useClass: TurboEngine, multi: true} - ])[0]; + expect(provider.key.token).toBe(Engine); + expect(provider.multiProvider).toEqual(true); + expect(provider.resolvedFactories.length).toEqual(2); + }); - expect(provider.key.token).toBe(Engine); - expect(provider.multiProvider).toEqual(true); - expect(provider.resolvedFactories.length).toEqual(2); - }); - it('should support multi providers with only one provider', () => { - const provider = - ReflectiveInjector.resolve([{provide: Engine, useClass: BrokenEngine, multi: true}])[0]; + it('should support providers as hash', () => { + const provider = ReflectiveInjector.resolve([ + {provide: Engine, useClass: BrokenEngine, multi: true}, + {provide: Engine, useClass: TurboEngine, multi: true} + ])[0]; - expect(provider.key.token).toBe(Engine); - expect(provider.multiProvider).toEqual(true); - expect(provider.resolvedFactories.length).toEqual(1); - }); + expect(provider.key.token).toBe(Engine); + expect(provider.multiProvider).toEqual(true); + expect(provider.resolvedFactories.length).toEqual(2); + }); - it('should throw when mixing multi providers with regular providers', () => { - expect(() => { - ReflectiveInjector.resolve( - [{provide: Engine, useClass: BrokenEngine, multi: true}, Engine]); - }).toThrowError(/Cannot mix multi providers and regular providers/); + it('should support multi providers with only one provider', () => { + const provider = + ReflectiveInjector.resolve([{provide: Engine, useClass: BrokenEngine, multi: true}])[0]; - expect(() => { - ReflectiveInjector.resolve( - [Engine, {provide: Engine, useClass: BrokenEngine, multi: true}]); - }).toThrowError(/Cannot mix multi providers and regular providers/); - }); + expect(provider.key.token).toBe(Engine); + expect(provider.multiProvider).toEqual(true); + expect(provider.resolvedFactories.length).toEqual(1); + }); - it('should resolve forward references', () => { - const providers = ReflectiveInjector.resolve([ - forwardRef(() => Engine), - [{provide: forwardRef(() => BrokenEngine), useClass: forwardRef(() => Engine)}], { - provide: forwardRef(() => String), - useFactory: () => 'OK', - deps: [forwardRef(() => Engine)] - } - ]); + it('should throw when mixing multi providers with regular providers', () => { + expect(() => { + ReflectiveInjector.resolve([{provide: Engine, useClass: BrokenEngine, multi: true}, Engine]); + }).toThrowError(/Cannot mix multi providers and regular providers/); - const engineProvider = providers[0]; - const brokenEngineProvider = providers[1]; - const stringProvider = providers[2]; + expect(() => { + ReflectiveInjector.resolve([Engine, {provide: Engine, useClass: BrokenEngine, multi: true}]); + }).toThrowError(/Cannot mix multi providers and regular providers/); + }); - expect(engineProvider.resolvedFactories[0].factory() instanceof Engine).toBe(true); - expect(brokenEngineProvider.resolvedFactories[0].factory() instanceof Engine).toBe(true); - expect(stringProvider.resolvedFactories[0].dependencies[0].key) - .toEqual(ReflectiveKey.get(Engine)); - }); + it('should resolve forward references', () => { + const providers = ReflectiveInjector.resolve([ + forwardRef(() => Engine), + [{provide: forwardRef(() => BrokenEngine), useClass: forwardRef(() => Engine)}], + {provide: forwardRef(() => String), useFactory: () => 'OK', deps: [forwardRef(() => Engine)]} + ]); + + const engineProvider = providers[0]; + const brokenEngineProvider = providers[1]; + const stringProvider = providers[2]; + + expect(engineProvider.resolvedFactories[0].factory() instanceof Engine).toBe(true); + expect(brokenEngineProvider.resolvedFactories[0].factory() instanceof Engine).toBe(true); + expect(stringProvider.resolvedFactories[0].dependencies[0].key) + .toEqual(ReflectiveKey.get(Engine)); + }); - it('should support overriding factory dependencies with dependency annotations', () => { - const providers = ReflectiveInjector.resolve([{ - provide: 'token', - useFactory: (e: any /** TODO #9100 */) => 'result', - deps: [[new Inject('dep')]] - }]); + it('should support overriding factory dependencies with dependency annotations', () => { + const providers = ReflectiveInjector.resolve([{ + provide: 'token', + useFactory: (e: any /** TODO #9100 */) => 'result', + deps: [[new Inject('dep')]] + }]); - const provider = providers[0]; + const provider = providers[0]; - expect(provider.resolvedFactories[0].dependencies[0].key.token).toEqual('dep'); - }); + expect(provider.resolvedFactories[0].dependencies[0].key.token).toEqual('dep'); + }); - it('should allow declaring dependencies with flat arrays', () => { - const resolved = ReflectiveInjector.resolve( - [{provide: 'token', useFactory: (e: any) => e, deps: [new Inject('dep')]}]); - const nestedResolved = ReflectiveInjector.resolve( - [{provide: 'token', useFactory: (e: any) => e, deps: [[new Inject('dep')]]}]); - expect(resolved[0].resolvedFactories[0].dependencies[0].key.token) - .toEqual(nestedResolved[0].resolvedFactories[0].dependencies[0].key.token); - }); + it('should allow declaring dependencies with flat arrays', () => { + const resolved = ReflectiveInjector.resolve( + [{provide: 'token', useFactory: (e: any) => e, deps: [new Inject('dep')]}]); + const nestedResolved = ReflectiveInjector.resolve( + [{provide: 'token', useFactory: (e: any) => e, deps: [[new Inject('dep')]]}]); + expect(resolved[0].resolvedFactories[0].dependencies[0].key.token) + .toEqual(nestedResolved[0].resolvedFactories[0].dependencies[0].key.token); }); +}); - describe('displayName', () => { - it('should work', () => { - expect((<ReflectiveInjector_>ReflectiveInjector.resolveAndCreate([Engine, BrokenEngine])) - .displayName) - .toEqual('ReflectiveInjector(providers: [ "Engine" , "BrokenEngine" ])'); - }); +describe('displayName', () => { + it('should work', () => { + expect((<ReflectiveInjector_>ReflectiveInjector.resolveAndCreate([Engine, BrokenEngine])) + .displayName) + .toEqual('ReflectiveInjector(providers: [ "Engine" , "BrokenEngine" ])'); }); +}); })(); diff --git a/packages/core/test/di/reflective_key_spec.ts b/packages/core/test/di/reflective_key_spec.ts index fe82a254a14d1..1b9e3588a1934 100644 --- a/packages/core/test/di/reflective_key_spec.ts +++ b/packages/core/test/di/reflective_key_spec.ts @@ -12,16 +12,20 @@ import {KeyRegistry} from '@angular/core/src/di/reflective_key'; describe('key', function() { let registry: KeyRegistry; - beforeEach(function() { registry = new KeyRegistry(); }); + beforeEach(function() { + registry = new KeyRegistry(); + }); - it('should be equal to another key if type is the same', - function() { expect(registry.get('car')).toBe(registry.get('car')); }); + it('should be equal to another key if type is the same', function() { + expect(registry.get('car')).toBe(registry.get('car')); + }); - it('should not be equal to another key if types are different', - function() { expect(registry.get('car')).not.toBe(registry.get('porsche')); }); - - it('should return the passed in key', - function() { expect(registry.get(registry.get('car'))).toBe(registry.get('car')); }); + it('should not be equal to another key if types are different', function() { + expect(registry.get('car')).not.toBe(registry.get('porsche')); + }); + it('should return the passed in key', function() { + expect(registry.get(registry.get('car'))).toBe(registry.get('car')); + }); }); } diff --git a/packages/core/test/di/static_injector_spec.ts b/packages/core/test/di/static_injector_spec.ts index 007f9f7b4ed79..59386386200da 100644 --- a/packages/core/test/di/static_injector_spec.ts +++ b/packages/core/test/di/static_injector_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Inject, InjectFlags, InjectionToken, Injector, Optional, Self, SkipSelf, forwardRef} from '@angular/core'; +import {forwardRef, Inject, InjectFlags, InjectionToken, Injector, Optional, Self, SkipSelf} from '@angular/core'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, modifiedInIvy} from '@angular/private/testing'; @@ -18,7 +18,9 @@ class Engine { class BrokenEngine { static PROVIDER = {provide: Engine, useClass: BrokenEngine, deps: []}; - constructor() { throw new Error('Broken Engine'); } + constructor() { + throw new Error('Broken Engine'); + } } class DashboardSoftware { @@ -75,7 +77,7 @@ class NoAnnotations { constructor(secretDependency: any) {} } -function factoryFn(a: any){} +function factoryFn(a: any) {} { const dynamicProviders = [ @@ -88,7 +90,6 @@ function factoryFn(a: any){} ]; modifiedInIvy('Ivy uses R3Injector').describe(`StaticInjector`, () => { - it('should instantiate a class without dependencies', () => { const injector = Injector.create([Engine.PROVIDER]); const engine = injector.get(Engine); @@ -133,7 +134,9 @@ function factoryFn(a: any){} }); it('should provide to a factory', () => { - function sportsCarFactory(e: any) { return new SportsCar(e); } + function sportsCarFactory(e: any) { + return new SportsCar(e); + } const injector = Injector.create( [Engine.PROVIDER, {provide: Car, useFactory: sportsCarFactory, deps: [Engine]}]); @@ -187,26 +190,22 @@ function factoryFn(a: any){} it('should throw when the aliased provider does not exist', () => { const injector = Injector.create([{provide: 'car', useExisting: SportsCar}]); - const e = - `StaticInjectorError[car -> ${stringify(SportsCar)}]: \n NullInjectorError: No provider for ${stringify(SportsCar)}!`; + const e = `StaticInjectorError[car -> ${ + stringify(SportsCar)}]: \n NullInjectorError: No provider for ${stringify(SportsCar)}!`; expect(() => injector.get('car')).toThrowError(e); }); it('should handle forwardRef in useExisting', () => { const injector = Injector.create([ - {provide: 'originalEngine', useClass: forwardRef(() => Engine), deps: []}, { - provide: 'aliasedEngine', - useExisting: <any>forwardRef(() => 'originalEngine'), - deps: [] - } + {provide: 'originalEngine', useClass: forwardRef(() => Engine), deps: []}, + {provide: 'aliasedEngine', useExisting: <any>forwardRef(() => 'originalEngine'), deps: []} ]); expect(injector.get('aliasedEngine')).toBeAnInstanceOf(Engine); }); it('should support overriding factory dependencies', () => { const injector = Injector.create([ - Engine.PROVIDER, - {provide: Car, useFactory: (e: Engine) => new SportsCar(e), deps: [Engine]} + Engine.PROVIDER, {provide: Car, useFactory: (e: Engine) => new SportsCar(e), deps: [Engine]} ]); const car = injector.get<Car>(Car); @@ -249,9 +248,9 @@ function factoryFn(a: any){} }); it('should throw when missing deps', () => { - expect(() => Injector.create(<any>[{provide: Engine, useClass: Engine}])) - .toThrowError( - 'StaticInjectorError[{provide:Engine, useClass:Engine}]: \'deps\' required'); + expect(() => Injector.create(<any>[ + {provide: Engine, useClass: Engine} + ])).toThrowError('StaticInjectorError[{provide:Engine, useClass:Engine}]: \'deps\' required'); }); it('should throw when using reflective API', () => { @@ -289,7 +288,8 @@ function factoryFn(a: any){} Injector.create([CarWithDashboard.PROVIDER, Engine.PROVIDER, Dashboard.PROVIDER]); expect(() => injector.get(CarWithDashboard)) .toThrowError( - `StaticInjectorError[${stringify(CarWithDashboard)} -> ${stringify(Dashboard)} -> DashboardSoftware]: \n` + + `StaticInjectorError[${stringify(CarWithDashboard)} -> ${ + stringify(Dashboard)} -> DashboardSoftware]: \n` + ' NullInjectorError: No provider for DashboardSoftware!'); }); @@ -297,14 +297,21 @@ function factoryFn(a: any){} const injector = Injector.create([Car.PROVIDER, CyclicEngine.PROVIDER]); expect(() => injector.get(Car)) - .toThrowError( - `StaticInjectorError[${stringify(Car)} -> ${stringify(Engine)} -> ${stringify(Car)}]: Circular dependency`); + .toThrowError(`StaticInjectorError[${stringify(Car)} -> ${stringify(Engine)} -> ${ + stringify(Car)}]: Circular dependency`); }); it('should show the full path when error happens in a constructor', () => { const error = new Error('MyError'); - const injector = Injector.create( - [Car.PROVIDER, {provide: Engine, useFactory: () => { throw error; }, deps: []}]); + const injector = Injector.create([ + Car.PROVIDER, { + provide: Engine, + useFactory: () => { + throw error; + }, + deps: [] + } + ]); try { injector.get(Car); @@ -345,7 +352,6 @@ function factoryFn(a: any){} expect(injector.get('null')).toBe(null); expect(injector.get('undefined')).toBe(undefined); }); - }); @@ -495,8 +501,7 @@ function factoryFn(a: any){} it('should support overriding factory dependencies with dependency annotations', () => { const injector = Injector.create([ - Engine.PROVIDER, - {provide: 'token', useFactory: (e: any) => e, deps: [[new Inject(Engine)]]} + Engine.PROVIDER, {provide: 'token', useFactory: (e: any) => e, deps: [[new Inject(Engine)]]} ]); expect(injector.get('token')).toBeAnInstanceOf(Engine); diff --git a/packages/core/test/directive_lifecycle_integration_spec.ts b/packages/core/test/directive_lifecycle_integration_spec.ts index 84e944188a377..ab4e5e9e61d90 100644 --- a/packages/core/test/directive_lifecycle_integration_spec.ts +++ b/packages/core/test/directive_lifecycle_integration_spec.ts @@ -8,7 +8,7 @@ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, DoCheck, OnChanges, OnInit} from '@angular/core'; import {Component, Directive} from '@angular/core/src/metadata'; -import {TestBed, inject} from '@angular/core/testing'; +import {inject, TestBed} from '@angular/core/testing'; import {Log} from '@angular/core/testing/src/testing_internal'; describe('directive lifecycle integration spec', () => { @@ -27,7 +27,9 @@ describe('directive lifecycle integration spec', () => { .overrideComponent(MyComp5, {set: {template: '<div [field]="123" lifecycle></div>'}}); }); - beforeEach(inject([Log], (_log: any) => { log = _log; })); + beforeEach(inject([Log], (_log: any) => { + log = _log; + })); it('should invoke lifecycle methods ngOnChanges > ngOnInit > ngDoCheck > ngAfterContentChecked', () => { @@ -51,7 +53,9 @@ describe('directive lifecycle integration spec', () => { @Directive({selector: '[lifecycle-dir]'}) class LifecycleDir implements DoCheck { constructor(private _log: Log) {} - ngDoCheck() { this._log.add('child_ngDoCheck'); } + ngDoCheck() { + this._log.add('child_ngDoCheck'); + } } @Component({ @@ -59,24 +63,38 @@ class LifecycleDir implements DoCheck { inputs: ['field'], template: `<div lifecycle-dir></div>`, }) -class LifecycleCmp implements OnChanges, - OnInit, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked { +class LifecycleCmp implements OnChanges, OnInit, DoCheck, AfterContentInit, AfterContentChecked, + AfterViewInit, AfterViewChecked { field: any /** TODO #9100 */; constructor(private _log: Log) {} - ngOnChanges(_: any /** TODO #9100 */) { this._log.add('ngOnChanges'); } + ngOnChanges(_: any /** TODO #9100 */) { + this._log.add('ngOnChanges'); + } - ngOnInit() { this._log.add('ngOnInit'); } + ngOnInit() { + this._log.add('ngOnInit'); + } - ngDoCheck() { this._log.add('ngDoCheck'); } + ngDoCheck() { + this._log.add('ngDoCheck'); + } - ngAfterContentInit() { this._log.add('ngAfterContentInit'); } + ngAfterContentInit() { + this._log.add('ngAfterContentInit'); + } - ngAfterContentChecked() { this._log.add('ngAfterContentChecked'); } + ngAfterContentChecked() { + this._log.add('ngAfterContentChecked'); + } - ngAfterViewInit() { this._log.add('ngAfterViewInit'); } + ngAfterViewInit() { + this._log.add('ngAfterViewInit'); + } - ngAfterViewChecked() { this._log.add('ngAfterViewChecked'); } + ngAfterViewChecked() { + this._log.add('ngAfterViewChecked'); + } } @Component({selector: 'my-comp'}) diff --git a/packages/core/test/dom/dom_adapter_spec.ts b/packages/core/test/dom/dom_adapter_spec.ts index fc4c540e3a791..d858eac3c2061 100644 --- a/packages/core/test/dom/dom_adapter_spec.ts +++ b/packages/core/test/dom/dom_adapter_spec.ts @@ -40,8 +40,9 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; describe('getBaseHref', () => { beforeEach(() => getDOM().resetBaseElement()); - it('should return null if base element is absent', - () => { expect(getDOM().getBaseHref(defaultDoc)).toBeNull(); }); + it('should return null if base element is absent', () => { + expect(getDOM().getBaseHref(defaultDoc)).toBeNull(); + }); it('should return the value of the base element', () => { const baseEl = getDOM().createElement('base'); @@ -62,7 +63,7 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; const headEl = defaultDoc.head; headEl.appendChild(baseEl); - const baseHref = getDOM().getBaseHref(defaultDoc) !; + const baseHref = getDOM().getBaseHref(defaultDoc)!; headEl.removeChild(baseEl); getDOM().resetBaseElement(); @@ -70,7 +71,5 @@ import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; }); }); } - - }); } diff --git a/packages/core/test/dom/shim_spec.ts b/packages/core/test/dom/shim_spec.ts index 07b2bd1738dfd..3d09e8d7d7c11 100644 --- a/packages/core/test/dom/shim_spec.ts +++ b/packages/core/test/dom/shim_spec.ts @@ -10,7 +10,6 @@ import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; { describe('Shim', () => { - it('should provide correct function.name ', () => { const functionWithoutName = identity(() => function(_: any /** TODO #9100 */) {}); function foo(_: any /** TODO #9100 */) {} @@ -18,7 +17,6 @@ import {describe, expect, it} from '@angular/core/testing/src/testing_internal'; expect((<any>functionWithoutName).name).toBeFalsy(); expect((<any>foo).name).toEqual('foo'); }); - }); } diff --git a/packages/core/test/error_handler_spec.ts b/packages/core/test/error_handler_spec.ts index e52fd36ebad1e..d566d61233f26 100644 --- a/packages/core/test/error_handler_spec.ts +++ b/packages/core/test/error_handler_spec.ts @@ -12,66 +12,73 @@ import {ErrorHandler} from '../src/error_handler'; class MockConsole { res: any[][] = []; - error(...s: any[]): void { this.res.push(s); } + error(...s: any[]): void { + this.res.push(s); + } } (function() { - function errorToString(error: any) { - const logger = new MockConsole(); - const errorHandler = new ErrorHandler(); - (errorHandler as any)._console = logger as any; - errorHandler.handleError(error); - return logger.res.map(line => line.join('#')).join('\n'); - } +function errorToString(error: any) { + const logger = new MockConsole(); + const errorHandler = new ErrorHandler(); + (errorHandler as any)._console = logger as any; + errorHandler.handleError(error); + return logger.res.map(line => line.join('#')).join('\n'); +} - describe('ErrorHandler', () => { - it('should output exception', () => { - const e = errorToString(new Error('message!')); - expect(e).toContain('message!'); - }); +describe('ErrorHandler', () => { + it('should output exception', () => { + const e = errorToString(new Error('message!')); + expect(e).toContain('message!'); + }); - describe('context', () => { - it('should print nested context', () => { - const cause = new Error('message!'); - const context = { source: 'context!', toString() { return 'Context'; } } as any; - const original = debugError(cause, context); - const e = errorToString(wrappedError('message', original)); - expect(e).toEqual(`ERROR#Error: message caused by: Error in context! caused by: message! + describe('context', () => { + it('should print nested context', () => { + const cause = new Error('message!'); + const context = { + source: 'context!', + toString() { + return 'Context'; + } + } as any; + const original = debugError(cause, context); + const e = errorToString(wrappedError('message', original)); + expect(e).toEqual(`ERROR#Error: message caused by: Error in context! caused by: message! ORIGINAL ERROR#Error: message! ERROR CONTEXT#Context`); - }); }); + }); - describe('original exception', () => { - it('should print original exception message if available (original is Error)', () => { - const realOriginal = new Error('inner'); - const original = wrappedError('wrapped', realOriginal); - const e = errorToString(wrappedError('wrappedwrapped', original)); - expect(e).toContain('inner'); - }); + describe('original exception', () => { + it('should print original exception message if available (original is Error)', () => { + const realOriginal = new Error('inner'); + const original = wrappedError('wrapped', realOriginal); + const e = errorToString(wrappedError('wrappedwrapped', original)); + expect(e).toContain('inner'); + }); - it('should print original exception message if available (original is not Error)', () => { - const realOriginal = new Error('custom'); - const original = wrappedError('wrapped', realOriginal); - const e = errorToString(wrappedError('wrappedwrapped', original)); - expect(e).toContain('custom'); - }); + it('should print original exception message if available (original is not Error)', () => { + const realOriginal = new Error('custom'); + const original = wrappedError('wrapped', realOriginal); + const e = errorToString(wrappedError('wrappedwrapped', original)); + expect(e).toContain('custom'); }); + }); - it('should use the error logger on the error', () => { - const err = new Error('test'); - const console = new MockConsole(); - const errorHandler = new ErrorHandler(); - (errorHandler as any)._console = console as any; - const logger = jasmine.createSpy('logger'); - (err as any)[ERROR_LOGGER] = logger; + it('should use the error logger on the error', () => { + const err = new Error('test'); + const console = new MockConsole(); + const errorHandler = new ErrorHandler(); + (errorHandler as any)._console = console as any; + const logger = jasmine.createSpy('logger'); + (err as any)[ERROR_LOGGER] = logger; - errorHandler.handleError(err); + errorHandler.handleError(err); - expect(console.res).toEqual([]); - expect(logger).toHaveBeenCalledWith(console, 'ERROR', err); - }); + expect(console.res).toEqual([]); + expect(logger).toHaveBeenCalledWith(console, 'ERROR', err); }); +}); })(); function debugError(originalError: any, context: any): Error { diff --git a/packages/core/test/event_emitter_spec.ts b/packages/core/test/event_emitter_spec.ts index 0b46ecc4eca4f..2edecec58d5c9 100644 --- a/packages/core/test/event_emitter_spec.ts +++ b/packages/core/test/event_emitter_spec.ts @@ -15,7 +15,9 @@ import {EventEmitter} from '../src/event_emitter'; describe('EventEmitter', () => { let emitter: EventEmitter<any>; - beforeEach(() => { emitter = new EventEmitter(); }); + beforeEach(() => { + emitter = new EventEmitter(); + }); it('should call the next callback', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { @@ -42,20 +44,34 @@ import {EventEmitter} from '../src/event_emitter'; it('should work when no throw callback is provided', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - emitter.subscribe({next: () => {}, error: (_: any) => { async.done(); }}); + emitter.subscribe({ + next: () => {}, + error: (_: any) => { + async.done(); + } + }); emitter.error('Boom'); })); it('should call the return callback', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - emitter.subscribe( - {next: () => {}, error: (_: any) => {}, complete: () => { async.done(); }}); + emitter.subscribe({ + next: () => {}, + error: (_: any) => {}, + complete: () => { + async.done(); + } + }); emitter.complete(); })); it('should subscribe to the wrapper synchronously', () => { let called = false; - emitter.subscribe({next: (value: any) => { called = true; }}); + emitter.subscribe({ + next: (value: any) => { + called = true; + } + }); emitter.emit(99); expect(called).toBe(true); @@ -117,7 +133,6 @@ import {EventEmitter} from '../src/event_emitter'; log.push(1); e.emit(2); log.push(3); - })); it('reports whether it has subscribers', () => { @@ -161,8 +176,16 @@ import {EventEmitter} from '../src/event_emitter'; it('error thrown inside an Rx chain propagates to the error handler and disposes the chain', () => { let errorPropagated = false; - emitter.pipe(filter(() => { throw new Error(); }), ) - .subscribe(() => {}, err => errorPropagated = true, ); + emitter + .pipe( + filter(() => { + throw new Error(); + }), + ) + .subscribe( + () => {}, + err => errorPropagated = true, + ); emitter.next(1); @@ -172,7 +195,11 @@ import {EventEmitter} from '../src/event_emitter'; it('error sent by EventEmitter should dispose the Rx chain and remove subscribers', () => { let errorPropagated = false; - emitter.pipe(filter(() => true)).subscribe(() => {}, err => errorPropagated = true, ); + emitter.pipe(filter(() => true)) + .subscribe( + () => {}, + err => errorPropagated = true, + ); emitter.error(1); diff --git a/packages/core/test/fake_async_spec.ts b/packages/core/test/fake_async_spec.ts index ddf44dfa29b49..30c7bed06db3c 100644 --- a/packages/core/test/fake_async_spec.ts +++ b/packages/core/test/fake_async_spec.ts @@ -7,7 +7,7 @@ */ import {discardPeriodicTasks, fakeAsync, flush, flushMicrotasks, tick} from '@angular/core/testing'; -import {Log, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; +import {beforeEach, describe, inject, it, Log} from '@angular/core/testing/src/testing_internal'; import {EventManager} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -18,7 +18,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' describe('fake async', () => { it('should run synchronous code', () => { let ran = false; - fakeAsync(() => { ran = true; })(); + fakeAsync(() => { + ran = true; + })(); expect(ran).toEqual(true); }); @@ -37,26 +39,35 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should throw on nested calls', () => { expect(() => { - fakeAsync(() => { fakeAsync((): any /** TODO #9100 */ => null)(); })(); + fakeAsync(() => { + fakeAsync((): any /** TODO #9100 */ => null)(); + })(); }).toThrowError('fakeAsync() calls can not be nested'); }); it('should flush microtasks before returning', () => { let thenRan = false; - fakeAsync(() => { resolvedPromise.then(_ => { thenRan = true; }); })(); + fakeAsync(() => { + resolvedPromise.then(_ => { + thenRan = true; + }); + })(); expect(thenRan).toEqual(true); }); - it('should propagate the return value', - () => { expect(fakeAsync(() => 'foo')()).toEqual('foo'); }); + it('should propagate the return value', () => { + expect(fakeAsync(() => 'foo')()).toEqual('foo'); + }); describe('Promise', () => { it('should run asynchronous code', fakeAsync(() => { let thenRan = false; - resolvedPromise.then((_) => { thenRan = true; }); + resolvedPromise.then((_) => { + thenRan = true; + }); expect(thenRan).toEqual(false); @@ -92,22 +103,29 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should complain if the test throws an exception during async calls', () => { expect(() => { fakeAsync(() => { - resolvedPromise.then((_) => { throw new Error('async'); }); + resolvedPromise.then((_) => { + throw new Error('async'); + }); flushMicrotasks(); })(); }).toThrow(); }); it('should complain if a test throws an exception', () => { - expect(() => { fakeAsync(() => { throw new Error('sync'); })(); }).toThrowError('sync'); + expect(() => { + fakeAsync(() => { + throw new Error('sync'); + })(); + }).toThrowError('sync'); }); - }); describe('timers', () => { it('should run queued zero duration timer on zero tick', fakeAsync(() => { let ran = false; - setTimeout(() => { ran = true; }, 0); + setTimeout(() => { + ran = true; + }, 0); expect(ran).toEqual(false); @@ -118,7 +136,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should run queued timer after sufficient clock ticks', fakeAsync(() => { let ran = false; - setTimeout(() => { ran = true; }, 10); + setTimeout(() => { + ran = true; + }, 10); tick(6); expect(ran).toEqual(false); @@ -154,7 +174,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should run queued timer only once', fakeAsync(() => { let cycles = 0; - setTimeout(() => { cycles++; }, 10); + setTimeout(() => { + cycles++; + }, 10); tick(10); expect(cycles).toEqual(1); @@ -168,7 +190,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should not run cancelled timer', fakeAsync(() => { let ran = false; - const id = setTimeout(() => { ran = true; }, 10); + const id = setTimeout(() => { + ran = true; + }, 10); clearTimeout(id); tick(10); @@ -177,19 +201,25 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should throw an error on dangling timers', () => { expect(() => { - fakeAsync(() => { setTimeout(() => {}, 10); })(); + fakeAsync(() => { + setTimeout(() => {}, 10); + })(); }).toThrowError('1 timer(s) still in the queue.'); }); it('should throw an error on dangling periodic timers', () => { expect(() => { - fakeAsync(() => { setInterval(() => {}, 10); })(); + fakeAsync(() => { + setInterval(() => {}, 10); + })(); }).toThrowError('1 periodic timer(s) still in the queue.'); }); it('should run periodic timers', fakeAsync(() => { let cycles = 0; - const id = setInterval(() => { cycles++; }, 10); + const id = setInterval(() => { + cycles++; + }, 10); tick(10); expect(cycles).toEqual(1); @@ -204,7 +234,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should not run cancelled periodic timer', fakeAsync(() => { let ran = false; - const id = setInterval(() => { ran = true; }, 10); + const id = setInterval(() => { + ran = true; + }, 10); clearInterval(id); tick(10); @@ -229,7 +261,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should clear periodic timers', fakeAsync(() => { let cycles = 0; - const id = setInterval(() => { cycles++; }, 10); + const id = setInterval(() => { + cycles++; + }, 10); tick(10); expect(cycles).toEqual(1); @@ -289,7 +323,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should flush tasks', fakeAsync(() => { let ran = false; - setTimeout(() => { ran = true; }, 10); + setTimeout(() => { + ran = true; + }, 10); flush(); expect(ran).toEqual(true); @@ -298,8 +334,12 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should flush multiple tasks', fakeAsync(() => { let ran = false; let ran2 = false; - setTimeout(() => { ran = true; }, 10); - setTimeout(() => { ran2 = true; }, 30); + setTimeout(() => { + ran = true; + }, 10); + setTimeout(() => { + ran2 = true; + }, 30); let elapsed = flush(); @@ -311,8 +351,12 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' it('should move periodic tasks', fakeAsync(() => { let ran = false; let count = 0; - setInterval(() => { count++; }, 10); - setTimeout(() => { ran = true; }, 35); + setInterval(() => { + count++; + }, 10); + setTimeout(() => { + ran = true; + }, 35); let elapsed = flush(); @@ -353,7 +397,9 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' describe('only one `fakeAsync` zone per test', () => { let zoneInBeforeEach: Zone; let zoneInTest1: Zone; - beforeEach(fakeAsync(() => { zoneInBeforeEach = Zone.current; })); + beforeEach(fakeAsync(() => { + zoneInBeforeEach = Zone.current; + })); it('should use the same zone as in beforeEach', fakeAsync(() => { zoneInTest1 = Zone.current; @@ -363,9 +409,13 @@ const ProxyZoneSpec: {assertPresent: () => void} = (Zone as any)['ProxyZoneSpec' }); describe('ProxyZone', () => { - beforeEach(() => { ProxyZoneSpec.assertPresent(); }); + beforeEach(() => { + ProxyZoneSpec.assertPresent(); + }); - afterEach(() => { ProxyZoneSpec.assertPresent(); }); + afterEach(() => { + ProxyZoneSpec.assertPresent(); + }); it('should allow fakeAsync zone to retroactively set a zoneSpec outside of fakeAsync', () => { ProxyZoneSpec.assertPresent(); diff --git a/packages/core/test/forward_ref_integration_spec.ts b/packages/core/test/forward_ref_integration_spec.ts index 856ab52ee455a..034dde7b87810 100644 --- a/packages/core/test/forward_ref_integration_spec.ts +++ b/packages/core/test/forward_ref_integration_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {Component, ContentChildren, Directive, Inject, NO_ERRORS_SCHEMA, NgModule, QueryList, asNativeElements, forwardRef} from '@angular/core'; +import {asNativeElements, Component, ContentChildren, Directive, forwardRef, Inject, NgModule, NO_ERRORS_SCHEMA, QueryList} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -20,7 +20,9 @@ class ModuleFrame { } describe('forwardRef integration', function() { - beforeEach(() => { TestBed.configureTestingModule({imports: [Module], declarations: [App]}); }); + beforeEach(() => { + TestBed.configureTestingModule({imports: [Module], declarations: [App]}); + }); it('should instantiate components which are declared using forwardRef', () => { const a = TestBed.configureTestingModule({schemas: [NO_ERRORS_SCHEMA]}).createComponent(App); @@ -53,10 +55,12 @@ class App { }) class Door { // TODO(issue/24571): remove '!'. - @ContentChildren(forwardRef(() => Lock)) locks !: QueryList<Lock>; + @ContentChildren(forwardRef(() => Lock)) locks!: QueryList<Lock>; frame: Frame; - constructor(@Inject(forwardRef(() => Frame)) frame: Frame) { this.frame = frame; } + constructor(@Inject(forwardRef(() => Frame)) frame: Frame) { + this.frame = frame; + } } @Directive({selector: 'lock'}) diff --git a/packages/core/test/i18n/locale_data_api_spec.ts b/packages/core/test/i18n/locale_data_api_spec.ts index 3c995a61d3e46..13ecb23774c08 100644 --- a/packages/core/test/i18n/locale_data_api_spec.ts +++ b/packages/core/test/i18n/locale_data_api_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {LocaleDataIndex, findLocaleData, getLocaleCurrencyCode, registerLocaleData, unregisterAllLocaleData} from '../../src/i18n/locale_data_api'; +import {findLocaleData, getLocaleCurrencyCode, LocaleDataIndex, registerLocaleData, unregisterAllLocaleData} from '../../src/i18n/locale_data_api'; import {global} from '../../src/util/global'; { @@ -53,14 +53,18 @@ import {global} from '../../src/util/global'; .toThrowError(/Missing locale data for the locale "pt-AO"/); }); - it('should return english data if the locale is en-US', - () => { expect(findLocaleData('en-US')).toEqual(localeEn); }); + it('should return english data if the locale is en-US', () => { + expect(findLocaleData('en-US')).toEqual(localeEn); + }); - it('should return the exact LOCALE_DATA if it is available', - () => { expect(findLocaleData('fr-CA')).toEqual(localeFrCA); }); + it('should return the exact LOCALE_DATA if it is available', () => { + expect(findLocaleData('fr-CA')).toEqual(localeFrCA); + }); it('should return the parent LOCALE_DATA if it exists and exact locale is not available', - () => { expect(findLocaleData('fr-BE')).toEqual(localeFr); }); + () => { + expect(findLocaleData('fr-BE')).toEqual(localeFr); + }); it(`should find the LOCALE_DATA even if the locale id is badly formatted`, () => { expect(findLocaleData('ca-ES-VALENCIA')).toEqual(localeCaESVALENCIA); @@ -73,22 +77,30 @@ import {global} from '../../src/util/global'; expect(findLocaleData('fake-id2')).toEqual(localeFrCA); }); - it('should find the exact LOCALE_DATA if the locale is on the global object', - () => { expect(findLocaleData('de-CH')).toEqual(localeDeCH); }); + it('should find the exact LOCALE_DATA if the locale is on the global object', () => { + expect(findLocaleData('de-CH')).toEqual(localeDeCH); + }); it('should find the parent LOCALE_DATA if the exact locale is not available and the parent locale is on the global object', - () => { expect(findLocaleData('de-BE')).toEqual(localeDe); }); + () => { + expect(findLocaleData('de-BE')).toEqual(localeDe); + }); it('should find the registered LOCALE_DATA even if the same locale is on the global object', - () => { expect(findLocaleData('fr')).not.toBe(fakeGlobalFr); }); + () => { + expect(findLocaleData('fr')).not.toBe(fakeGlobalFr); + }); }); describe('getLocaleCurrencyCode()', () => { - it('should return `null` if the given locale does not provide a currency code', - () => { expect(getLocaleCurrencyCode('de')).toBe(null); }); + it('should return `null` if the given locale does not provide a currency code', () => { + expect(getLocaleCurrencyCode('de')).toBe(null); + }); it('should return the code at the `LocaleDataIndex.CurrencyCode` of the given locale`s data', - () => { expect(getLocaleCurrencyCode('fr')).toEqual('EUR'); }); + () => { + expect(getLocaleCurrencyCode('fr')).toEqual('EUR'); + }); }); }); } diff --git a/packages/core/test/linker/entry_components_integration_spec.ts b/packages/core/test/linker/entry_components_integration_spec.ts index 7c0adff4aa1a5..e924bd05ab348 100644 --- a/packages/core/test/linker/entry_components_integration_spec.ts +++ b/packages/core/test/linker/entry_components_integration_spec.ts @@ -14,17 +14,25 @@ import {obsoleteInIvy} from '@angular/private/testing'; if (ivyEnabled) { - describe('ivy', () => { declareTests(); }); + describe('ivy', () => { + declareTests(); + }); } else { - describe('jit', () => { declareTests({useJit: true}); }); - describe('no jit', () => { declareTests({useJit: false}); }); + describe('jit', () => { + declareTests({useJit: true}); + }); + describe('no jit', () => { + declareTests({useJit: false}); + }); } class DummyConsole implements Console { public warnings: string[] = []; log(message: string) {} - warn(message: string) { this.warnings.push(message); } + warn(message: string) { + this.warnings.push(message); + } } function declareTests(config?: {useJit: boolean}) { @@ -40,7 +48,7 @@ function declareTests(config?: {useJit: boolean}) { const compFixture = TestBed.createComponent(MainComp); const mainComp: MainComp = compFixture.componentInstance; expect(compFixture.componentRef.injector.get(ComponentFactoryResolver)).toBe(mainComp.cfr); - const cf = mainComp.cfr.resolveComponentFactory(ChildComp) !; + const cf = mainComp.cfr.resolveComponentFactory(ChildComp)!; expect(cf.componentType).toBe(ChildComp); }); @@ -52,8 +60,8 @@ function declareTests(config?: {useJit: boolean}) { const mainComp: CompWithAnalyzeEntryComponentsProvider = compFixture.componentInstance; const cfr: ComponentFactoryResolver = compFixture.componentRef.injector.get(ComponentFactoryResolver); - expect(cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp); - expect(cfr.resolveComponentFactory(NestedChildComp) !.componentType).toBe(NestedChildComp); + expect(cfr.resolveComponentFactory(ChildComp)!.componentType).toBe(ChildComp); + expect(cfr.resolveComponentFactory(NestedChildComp)!.componentType).toBe(NestedChildComp); }); it('should be able to get a component form a parent component (view hierarchy)', () => { @@ -63,10 +71,10 @@ function declareTests(config?: {useJit: boolean}) { const childCompEl = compFixture.debugElement.children[0]; const childComp: ChildComp = childCompEl.componentInstance; // declared on ChildComp directly - expect(childComp.cfr.resolveComponentFactory(NestedChildComp) !.componentType) + expect(childComp.cfr.resolveComponentFactory(NestedChildComp)!.componentType) .toBe(NestedChildComp); // inherited from MainComp - expect(childComp.cfr.resolveComponentFactory(ChildComp) !.componentType).toBe(ChildComp); + expect(childComp.cfr.resolveComponentFactory(ChildComp)!.componentType).toBe(ChildComp); }); obsoleteInIvy('In Ivy, the ComponentFactoryResolver can resolve any component factory') @@ -79,12 +87,11 @@ function declareTests(config?: {useJit: boolean}) { const compFixture = TestBed.createComponent(MainComp); const nestedChildCompEl = compFixture.debugElement.children[0].children[0]; const nestedChildComp: NestedChildComp = nestedChildCompEl.componentInstance; - expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp) !.componentType) + expect(nestedChildComp.cfr.resolveComponentFactory(ChildComp)!.componentType) .toBe(ChildComp); expect(() => nestedChildComp.cfr.resolveComponentFactory(NestedChildComp)) .toThrow(noComponentFactoryError(NestedChildComp)); }); - }); } diff --git a/packages/core/test/linker/inheritance_integration_spec.ts b/packages/core/test/linker/inheritance_integration_spec.ts index 24f7129079c61..6da392f4968e8 100644 --- a/packages/core/test/linker/inheritance_integration_spec.ts +++ b/packages/core/test/linker/inheritance_integration_spec.ts @@ -17,8 +17,7 @@ class DirectiveA { @Directive({selector: '[directiveB]'}) class DirectiveB { - @HostBinding('title') - title = 'DirectiveB Title'; + @HostBinding('title') title = 'DirectiveB Title'; } @Component({selector: 'component-a', template: 'ComponentA Template'}) @@ -34,8 +33,7 @@ class ComponentWithNoAnnotation extends ComponentA {} @Directive({selector: '[directiveExtendsComponent]'}) class DirectiveExtendsComponent extends ComponentA { - @HostBinding('title') - title = 'DirectiveExtendsComponent Title'; + @HostBinding('title') title = 'DirectiveExtendsComponent Title'; } class DirectiveWithNoAnnotation extends DirectiveB {} diff --git a/packages/core/test/linker/integration_spec.ts b/packages/core/test/linker/integration_spec.ts index 35228190217b8..679795b62970d 100644 --- a/packages/core/test/linker/integration_spec.ts +++ b/packages/core/test/linker/integration_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule, DOCUMENT, ɵgetDOM as getDOM} from '@angular/common'; -import {Compiler, ComponentFactory, ComponentRef, ErrorHandler, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NO_ERRORS_SCHEMA, NgModule, NgModuleRef, OnDestroy, SkipSelf, ViewRef, ɵivyEnabled as ivyEnabled} from '@angular/core'; +import {Compiler, ComponentFactory, ComponentRef, ErrorHandler, EventEmitter, Host, Inject, Injectable, InjectionToken, Injector, NgModule, NgModuleRef, NO_ERRORS_SCHEMA, OnDestroy, SkipSelf, ViewRef, ɵivyEnabled as ivyEnabled} from '@angular/core'; import {ChangeDetectionStrategy, ChangeDetectorRef, PipeTransform} from '@angular/core/src/change_detection/change_detection'; import {getDebugContext} from '@angular/core/src/errors'; import {ComponentFactoryResolver} from '@angular/core/src/linker/component_factory_resolver'; @@ -17,7 +17,7 @@ import {TemplateRef} from '@angular/core/src/linker/template_ref'; import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref'; import {EmbeddedViewRef} from '@angular/core/src/linker/view_ref'; import {Attribute, Component, ContentChildren, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata'; -import {TestBed, async, fakeAsync, getTestBed, tick} from '@angular/core/testing'; +import {async, fakeAsync, getTestBed, TestBed, tick} from '@angular/core/testing'; import {createMouseEvent, dispatchEvent, el, isCommentNode} from '@angular/platform-browser/testing/src/browser_util'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; @@ -27,16 +27,23 @@ import {stringify} from '../../src/util/stringify'; const ANCHOR_ELEMENT = new InjectionToken('AnchorElement'); if (ivyEnabled) { - describe('ivy', () => { declareTests(); }); + describe('ivy', () => { + declareTests(); + }); } else { - describe('jit', () => { declareTests({useJit: true}); }); - describe('no jit', () => { declareTests({useJit: false}); }); + describe('jit', () => { + declareTests({useJit: true}); + }); + describe('no jit', () => { + declareTests({useJit: false}); + }); } function declareTests(config?: {useJit: boolean}) { describe('integration tests', function() { - - beforeEach(() => { TestBed.configureCompiler({...config}); }); + beforeEach(() => { + TestBed.configureCompiler({...config}); + }); describe('react to record changes', function() { it('should consume text node changes', () => { @@ -55,7 +62,7 @@ function declareTests(config?: {useJit: boolean}) { const template = '<div>{{null}}{{ctxProp}}</div>'; TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - fixture.componentInstance.ctxProp = null !; + fixture.componentInstance.ctxProp = null!; fixture.detectChanges(); expect(fixture.nativeElement).toHaveText(''); @@ -133,7 +140,7 @@ function declareTests(config?: {useJit: boolean}) { fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.getAttribute('foo')).toEqual('bar'); - fixture.componentInstance.ctxProp = null !; + fixture.componentInstance.ctxProp = null!; fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.hasAttribute('foo')).toBeFalsy(); }); @@ -148,7 +155,7 @@ function declareTests(config?: {useJit: boolean}) { fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual('10px'); - fixture.componentInstance.ctxProp = null !; + fixture.componentInstance.ctxProp = null!; fixture.detectChanges(); expect(fixture.debugElement.children[0].nativeElement.style['height']).toEqual(''); }); @@ -265,7 +272,7 @@ function declareTests(config?: {useJit: boolean}) { fixture.componentInstance.ctxProp = 'a'; fixture.detectChanges(); - const dir = fixture.debugElement.children[0].references !['dir']; + const dir = fixture.debugElement.children[0].references!['dir']; expect(dir.dirProp).toEqual('aa'); }); }); @@ -344,7 +351,7 @@ function declareTests(config?: {useJit: boolean}) { it('should display correct error message for uninitialized @Output', () => { @Component({selector: 'my-uninitialized-output', template: '<p>It works!</p>'}) class UninitializedOutputComp { - @Output() customEvent !: EventEmitter<any>; + @Output() customEvent!: EventEmitter<any>; } const template = @@ -406,7 +413,7 @@ function declareTests(config?: {useJit: boolean}) { ngIfEl.childNodes .find( debugElement => debugElement.nativeNode.nodeType === - Node.COMMENT_NODE) !.injector.get(SomeViewport); + Node.COMMENT_NODE)!.injector.get(SomeViewport); expect(someViewport.container.length).toBe(2); expect(ngIfEl.children.length).toBe(2); @@ -455,7 +462,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - expect(fixture.debugElement.children[0].children[0].references !['alice']) + expect(fixture.debugElement.children[0].children[0].references!['alice']) .toBeAnInstanceOf(ChildComp); }); @@ -465,7 +472,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - expect(fixture.debugElement.children[0].children[0].references !['localdir']) + expect(fixture.debugElement.children[0].children[0].references!['localdir']) .toBeAnInstanceOf(ExportDir); }); @@ -477,9 +484,9 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - expect(fixture.debugElement.children[0].references !['x']) + expect(fixture.debugElement.children[0].references!['x']) .toBeAnInstanceOf(DirectiveWithMultipleExportAsNames); - expect(fixture.debugElement.children[0].references !['y']) + expect(fixture.debugElement.children[0].references!['y']) .toBeAnInstanceOf(DirectiveWithMultipleExportAsNames); }); @@ -505,8 +512,8 @@ function declareTests(config?: {useJit: boolean}) { const pEl = fixture.debugElement.children[0]; - const alice = pEl.children[0].references !['alice']; - const bob = pEl.children[1].references !['bob']; + const alice = pEl.children[0].references!['alice']; + const bob = pEl.children[1].references!['bob']; expect(alice).toBeAnInstanceOf(ChildComp); expect(bob).toBeAnInstanceOf(ChildComp); expect(alice).not.toBe(bob); @@ -518,8 +525,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - expect(fixture.debugElement.children[0].references !['alice']) - .toBeAnInstanceOf(ChildComp); + expect(fixture.debugElement.children[0].references!['alice']).toBeAnInstanceOf(ChildComp); }); it('should assign the element instance to a user-defined variable', () => { @@ -528,7 +534,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - const value = fixture.debugElement.children[0].children[0].references !['alice']; + const value = fixture.debugElement.children[0].children[0].references!['alice']; expect(value).not.toBe(null); expect(value.tagName.toLowerCase()).toEqual('div'); }); @@ -540,7 +546,7 @@ function declareTests(config?: {useJit: boolean}) { MyComp, {set: {template: '<ng-template ref-alice></ng-template>'}}) .createComponent(MyComp); - const value = fixture.debugElement.childNodes[0].references !['alice']; + const value = fixture.debugElement.childNodes[0].references!['alice']; expect(value.createEmbeddedView).toBeTruthy(); }); @@ -550,7 +556,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - expect(fixture.debugElement.children[0].children[0].references !['superAlice']) + expect(fixture.debugElement.children[0].children[0].references!['superAlice']) .toBeAnInstanceOf(ChildComp); }); }); @@ -573,14 +579,13 @@ function declareTests(config?: {useJit: boolean}) { }); describe('OnPush components', () => { - it('should use ChangeDetectorRef to manually request a check', () => { TestBed.configureTestingModule({declarations: [MyComp, [[PushCmpWithRef]]]}); const template = '<push-cmp-with-ref #cmp></push-cmp-with-ref>'; TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - const cmp = fixture.debugElement.children[0].references !['cmp']; + const cmp = fixture.debugElement.children[0].references!['cmp']; fixture.detectChanges(); expect(cmp.numberOfChecks).toEqual(1); @@ -601,7 +606,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - const cmp = fixture.debugElement.children[0].references !['cmp']; + const cmp = fixture.debugElement.children[0].references!['cmp']; fixture.componentInstance.ctxProp = 'one'; fixture.detectChanges(); @@ -675,7 +680,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - const cmp = fixture.debugElement.children[0].references !['cmp']; + const cmp = fixture.debugElement.children[0].references!['cmp']; fixture.componentInstance.ctxProp = 'one'; fixture.detectChanges(); @@ -695,7 +700,7 @@ function declareTests(config?: {useJit: boolean}) { tick(); - const cmp: PushCmpWithAsyncPipe = fixture.debugElement.children[0].references !['cmp']; + const cmp: PushCmpWithAsyncPipe = fixture.debugElement.children[0].references!['cmp']; fixture.detectChanges(); expect(cmp.numberOfChecks).toEqual(1); @@ -726,7 +731,7 @@ function declareTests(config?: {useJit: boolean}) { const fixture = TestBed.createComponent(MyComp); const childComponent = - fixture.debugElement.children[0].children[0].children[0].references !['child']; + fixture.debugElement.children[0].children[0].children[0].references!['child']; expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective); }); @@ -748,7 +753,7 @@ function declareTests(config?: {useJit: boolean}) { const tc = fixture.debugElement.children[0].children[0].children[0]; - const childComponent = tc.references !['child']; + const childComponent = tc.references!['child']; expect(childComponent.myHost).toBeAnInstanceOf(SomeDirective); }); @@ -795,7 +800,7 @@ function declareTests(config?: {useJit: boolean}) { }) .createComponent(MyComp); const tc = fixture.debugElement.childNodes.find( - debugElement => debugElement.nativeNode.nodeType === Node.COMMENT_NODE) !; + debugElement => debugElement.nativeNode.nodeType === Node.COMMENT_NODE)!; const emitter = tc.injector.get(DirectiveEmittingEvent); const myComp = fixture.debugElement.injector.get(MyComp); @@ -827,8 +832,11 @@ function declareTests(config?: {useJit: boolean}) { expect(dir.control).toEqual('one'); - dir.controlChange.subscribe( - {next: () => { expect(fixture.componentInstance.ctxProp).toEqual('two'); }}); + dir.controlChange.subscribe({ + next: () => { + expect(fixture.componentInstance.ctxProp).toEqual('two'); + } + }); dir.triggerChange('two'); })); @@ -954,9 +962,11 @@ function declareTests(config?: {useJit: boolean}) { class DirectiveWithHostListener { id = 'one'; // TODO(issue/24571): remove '!'. - receivedArgs !: any[]; + receivedArgs!: any[]; - doIt(...args: any[]) { this.receivedArgs = args; } + doIt(...args: any[]) { + this.receivedArgs = args; + } } const fixture = @@ -1239,7 +1249,6 @@ function declareTests(config?: {useJit: boolean}) { }).toThrowError('Cannot move a destroyed View in a ViewContainer!'); })); }); - }); it('should support static attributes', () => { @@ -1292,7 +1301,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - const comp = fixture.debugElement.children[0].children[0].references !['consuming']; + const comp = fixture.debugElement.children[0].children[0].references!['consuming']; expect(comp.injectable).toBeAnInstanceOf(InjectableService); }); @@ -1308,7 +1317,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(DirectiveProvidingInjectableInView, {set: {template}}); const fixture = TestBed.createComponent(DirectiveProvidingInjectableInView); - const comp = fixture.debugElement.children[0].references !['consuming']; + const comp = fixture.debugElement.children[0].references!['consuming']; expect(comp.injectable).toBeAnInstanceOf(InjectableService); }); @@ -1336,7 +1345,7 @@ function declareTests(config?: {useJit: boolean}) { }); const fixture = TestBed.createComponent(MyComp); - const comp = fixture.debugElement.children[0].children[0].references !['dir']; + const comp = fixture.debugElement.children[0].children[0].references!['dir']; expect(comp.directive.injectable).toBeAnInstanceOf(InjectableService); }); @@ -1386,7 +1395,7 @@ function declareTests(config?: {useJit: boolean}) { TestBed.overrideComponent(MyComp, {set: {template}}); const fixture = TestBed.createComponent(MyComp); - const providing = fixture.debugElement.children[0].references !['providing']; + const providing = fixture.debugElement.children[0].references!['providing']; expect(providing.created).toBe(false); fixture.componentInstance.ctxBoolProp = true; @@ -1469,7 +1478,7 @@ function declareTests(config?: {useJit: boolean}) { }); it('should use a default element name for components without selectors', () => { - let noSelectorComponentFactory: ComponentFactory<SomeComponent> = undefined !; + let noSelectorComponentFactory: ComponentFactory<SomeComponent> = undefined!; @Component({template: '----'}) class NoSelectorComponent { @@ -1480,7 +1489,7 @@ function declareTests(config?: {useJit: boolean}) { constructor(componentFactoryResolver: ComponentFactoryResolver) { // grab its own component factory noSelectorComponentFactory = - componentFactoryResolver.resolveComponentFactory(NoSelectorComponent) !; + componentFactoryResolver.resolveComponentFactory(NoSelectorComponent)!; } } @@ -1502,8 +1511,9 @@ function declareTests(config?: {useJit: boolean}) { TestBed.configureTestingModule({declarations: [MyComp, SomeDirectiveMissingAnnotation]}); expect(() => TestBed.createComponent(MyComp)) - .toThrowError( - `Unexpected value '${stringify(SomeDirectiveMissingAnnotation)}' declared by the module 'DynamicTestModule'. Please add a @Pipe/@Directive/@Component annotation.`); + .toThrowError(`Unexpected value '${ + stringify( + SomeDirectiveMissingAnnotation)}' declared by the module 'DynamicTestModule'. Please add a @Pipe/@Directive/@Component annotation.`); }); it('should report a meaningful error when a component is missing view annotation', () => { @@ -1822,7 +1832,7 @@ function declareTests(config?: {useJit: boolean}) { expect(fixture.nativeElement.innerHTML).toContain('ng-reflect-dir-prop="hello"'); - fixture.componentInstance.ctxProp = undefined !; + fixture.componentInstance.ctxProp = undefined!; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML).not.toContain('ng-reflect-'); @@ -1839,7 +1849,7 @@ function declareTests(config?: {useJit: boolean}) { expect(fixture.nativeElement.innerHTML).toContain('ng-reflect-dir-prop="hello"'); - fixture.componentInstance.ctxProp = null !; + fixture.componentInstance.ctxProp = null!; fixture.detectChanges(); expect(fixture.nativeElement.innerHTML).not.toContain('ng-reflect-'); @@ -1871,7 +1881,7 @@ function declareTests(config?: {useJit: boolean}) { expect(html).toContain('bindings={'); expect(html).toContain('"ng-reflect-ng-if": "true"'); - fixture.componentInstance.ctxBoolProp = undefined !; + fixture.componentInstance.ctxBoolProp = undefined!; fixture.detectChanges(); html = fixture.nativeElement.innerHTML; @@ -1893,14 +1903,13 @@ function declareTests(config?: {useJit: boolean}) { expect(html).toContain('bindings={'); expect(html).toContain('"ng-reflect-ng-if": "true"'); - fixture.componentInstance.ctxBoolProp = null !; + fixture.componentInstance.ctxBoolProp = null!; fixture.detectChanges(); html = fixture.nativeElement.innerHTML; expect(html).toContain('bindings={'); expect(html).toContain('"ng-reflect-ng-if": null'); }); - }); describe('property decorators', () => { @@ -2079,7 +2088,6 @@ function declareTests(config?: {useJit: boolean}) { }); describe('attributes', () => { - it('should support attributes with namespace', () => { TestBed.configureTestingModule({declarations: [MyComp, SomeCmp]}); const template = '<svg:use xlink:href="#id" />'; @@ -2142,7 +2150,9 @@ class ComponentWithCustomInterpolationB { @Injectable() class MyService { greeting: string; - constructor() { this.greeting = 'hello'; } + constructor() { + this.greeting = 'hello'; + } } @Component({selector: 'simple-imp-cmp', template: ''}) @@ -2165,14 +2175,16 @@ class DynamicViewport { this.injector = Injector.create([{provide: MyService, useValue: myService}], vc.injector); this.componentFactory = - componentFactoryResolver.resolveComponentFactory(ChildCompUsingService) !; + componentFactoryResolver.resolveComponentFactory(ChildCompUsingService)!; } create(): ComponentRef<ChildCompUsingService> { return this.vc.createComponent(this.componentFactory, this.vc.length, this.injector); } - insert(viewRef: ViewRef, index?: number): ViewRef { return this.vc.insert(viewRef, index); } + insert(viewRef: ViewRef, index?: number): ViewRef { + return this.vc.insert(viewRef, index); + } move(viewRef: ViewRef, currentIndex: number): ViewRef { return this.vc.move(viewRef, currentIndex); @@ -2182,25 +2194,29 @@ class DynamicViewport { @Directive({selector: '[my-dir]', inputs: ['dirProp: elprop'], exportAs: 'mydir'}) class MyDir { dirProp: string; - constructor() { this.dirProp = ''; } + constructor() { + this.dirProp = ''; + } } @Directive({selector: '[my-dir2]', inputs: ['dirProp2: elprop'], exportAs: 'mydir2'}) class MyDir2 { dirProp2: string; - constructor() { this.dirProp2 = ''; } + constructor() { + this.dirProp2 = ''; + } } @Directive({selector: '[title]', inputs: ['title']}) class DirectiveWithTitle { // TODO(issue/24571): remove '!'. - title !: string; + title!: string; } @Directive({selector: '[title]', inputs: ['title'], host: {'[title]': 'title'}}) class DirectiveWithTitleAndHostProperty { // TODO(issue/24571): remove '!'. - title !: string; + title!: string; } @Component({selector: 'event-cmp', template: '<div (click)="noop()"></div>'}) @@ -2220,7 +2236,9 @@ class PushCmp { numberOfChecks: number; prop: any; - constructor() { this.numberOfChecks = 0; } + constructor() { + this.numberOfChecks = 0; + } noop() {} @@ -2251,7 +2269,9 @@ class PushCmpWithRef { return 'fixed'; } - propagate() { this.ref.markForCheck(); } + propagate() { + this.ref.markForCheck(); + } } @Component({ @@ -2272,11 +2292,13 @@ class PushCmpWithHostEvent { class PushCmpWithAsyncPipe { numberOfChecks: number = 0; // TODO(issue/24571): remove '!'. - resolve !: (result: any) => void; + resolve!: (result: any) => void; promise: Promise<any>; constructor() { - this.promise = new Promise((resolve) => { this.resolve = resolve; }); + this.promise = new Promise((resolve) => { + this.resolve = resolve; + }); } get field() { @@ -2291,7 +2313,11 @@ class MyComp { ctxNumProp: number; ctxBoolProp: boolean; ctxArrProp: number[]; - toStringThrow = {toString: function() { throw 'boom'; }}; + toStringThrow = { + toString: function() { + throw 'boom'; + } + }; constructor() { this.ctxProp = 'initial value'; @@ -2300,7 +2326,9 @@ class MyComp { this.ctxArrProp = [0, 1, 2]; } - throwError() { throw 'boom'; } + throwError() { + throw 'boom'; + } } @Component({ @@ -2326,7 +2354,9 @@ class ChildCompNoTemplate { @Component({selector: 'child-cmp-svc', template: '{{ctxProp}}'}) class ChildCompUsingService { ctxProp: string; - constructor(service: MyService) { this.ctxProp = service.greeting; } + constructor(service: MyService) { + this.ctxProp = service.greeting; + } } @Directive({selector: 'some-directive'}) @@ -2341,7 +2371,9 @@ class SomeDirectiveMissingAnnotation {} }) class CompWithHost { myHost: SomeDirective; - constructor(@Host() someComp: SomeDirective) { this.myHost = someComp; } + constructor(@Host() someComp: SomeDirective) { + this.myHost = someComp; + } } @Component({selector: '[child-cmp2]', viewProviders: [MyService]}) @@ -2384,7 +2416,9 @@ class NoContext { @Pipe({name: 'double'}) class DoublePipe implements PipeTransform, OnDestroy { ngOnDestroy() {} - transform(value: any) { return `${value}${value}`; } + transform(value: any) { + return `${value}${value}`; + } } @Directive({selector: '[emitter]', outputs: ['event']}) @@ -2397,7 +2431,9 @@ class DirectiveEmittingEvent { this.event = new EventEmitter(); } - fireEvent(msg: string) { this.event.emit(msg); } + fireEvent(msg: string) { + this.event.emit(msg); + } } @Directive({selector: '[update-host-attributes]', host: {'role': 'button'}}) @@ -2408,16 +2444,22 @@ class DirectiveUpdatingHostAttributes { class DirectiveUpdatingHostProperties { id: string; - constructor() { this.id = 'one'; } + constructor() { + this.id = 'one'; + } } @Directive({selector: '[listener]', host: {'(event)': 'onEvent($event)'}}) class DirectiveListeningEvent { msg: string; - constructor() { this.msg = ''; } + constructor() { + this.msg = ''; + } - onEvent(msg: string) { this.msg = msg; } + onEvent(msg: string) { + this.msg = msg; + } } @Directive({ @@ -2431,17 +2473,27 @@ class DirectiveListeningEvent { }) class DirectiveListeningDomEvent { eventTypes: string[] = []; - onEvent(eventType: string) { this.eventTypes.push(eventType); } - onWindowEvent(eventType: string) { this.eventTypes.push('window_' + eventType); } - onDocumentEvent(eventType: string) { this.eventTypes.push('document_' + eventType); } - onBodyEvent(eventType: string) { this.eventTypes.push('body_' + eventType); } + onEvent(eventType: string) { + this.eventTypes.push(eventType); + } + onWindowEvent(eventType: string) { + this.eventTypes.push('window_' + eventType); + } + onDocumentEvent(eventType: string) { + this.eventTypes.push('document_' + eventType); + } + onBodyEvent(eventType: string) { + this.eventTypes.push('body_' + eventType); + } } let globalCounter = 0; @Directive({selector: '[listenerother]', host: {'(window:domEvent)': 'onEvent($event.type)'}}) class DirectiveListeningDomEventOther { eventType: string; - constructor() { this.eventType = ''; } + constructor() { + this.eventType = ''; + } onEvent(eventType: string) { globalCounter++; this.eventType = 'other_' + eventType; @@ -2450,18 +2502,22 @@ class DirectiveListeningDomEventOther { @Directive({selector: '[listenerprevent]', host: {'(click)': 'onEvent($event)'}}) class DirectiveListeningDomEventPrevent { - onEvent(event: any) { return false; } + onEvent(event: any) { + return false; + } } @Directive({selector: '[listenernoprevent]', host: {'(click)': 'onEvent($event)'}}) class DirectiveListeningDomEventNoPrevent { - onEvent(event: any) { return true; } + onEvent(event: any) { + return true; + } } @Directive({selector: '[id]', inputs: ['id']}) class IdDir { // TODO(issue/24571): remove '!'. - id !: string; + id!: string; } @Directive({selector: '[customEvent]'}) @@ -2497,7 +2553,9 @@ class PrivateImpl extends PublicApi { @Directive({selector: '[needs-public-api]'}) class NeedsPublicApi { - constructor(@Host() api: PublicApi) { expect(api instanceof PrivateImpl).toBe(true); } + constructor(@Host() api: PublicApi) { + expect(api instanceof PrivateImpl).toBe(true); + } } class ToolbarContext { @@ -2507,7 +2565,9 @@ class ToolbarContext { @Directive({selector: '[toolbarpart]'}) class ToolbarPart { templateRef: TemplateRef<ToolbarContext>; - constructor(templateRef: TemplateRef<ToolbarContext>) { this.templateRef = templateRef; } + constructor(templateRef: TemplateRef<ToolbarContext>) { + this.templateRef = templateRef; + } } @Directive({selector: '[toolbarVc]', inputs: ['toolbarVc']}) @@ -2525,7 +2585,7 @@ class ToolbarViewContainer { }) class ToolbarComponent { // TODO(issue/24571): remove '!'. - @ContentChildren(ToolbarPart) query !: QueryList<ToolbarPart>; + @ContentChildren(ToolbarPart) query!: QueryList<ToolbarPart>; ctxProp: string = 'hello world'; constructor() {} @@ -2536,7 +2596,9 @@ class DirectiveWithTwoWayBinding { controlChange = new EventEmitter(); control: any = null; - triggerChange(value: any) { this.controlChange.emit(value); } + triggerChange(value: any) { + this.controlChange.emit(value); + } } @Injectable() @@ -2585,7 +2647,9 @@ class DirectiveProvidingInjectableInHostAndView { class DirectiveConsumingInjectable { injectable: any; - constructor(@Host() @Inject(InjectableService) injectable: any) { this.injectable = injectable; } + constructor(@Host() @Inject(InjectableService) injectable: any) { + this.injectable = injectable; + } } @@ -2620,12 +2684,14 @@ class EventBus { @Directive({ selector: 'grand-parent-providing-event-bus', - providers: [{provide: EventBus, useValue: new EventBus(null !, 'grandparent')}] + providers: [{provide: EventBus, useValue: new EventBus(null!, 'grandparent')}] }) class GrandParentProvidingEventBus { bus: EventBus; - constructor(bus: EventBus) { this.bus = bus; } + constructor(bus: EventBus) { + this.bus = bus; + } } function createParentBus(peb: EventBus) { @@ -2651,7 +2717,9 @@ class ParentProvidingEventBus { class ChildConsumingEventBus { bus: EventBus; - constructor(@SkipSelf() bus: EventBus) { this.bus = bus; } + constructor(@SkipSelf() bus: EventBus) { + this.bus = bus; + } } @Directive({selector: '[someImpvp]', inputs: ['someImpvp']}) @@ -2695,17 +2763,23 @@ class ComponentWithoutView { @Directive({selector: '[no-duplicate]'}) class DuplicateDir { - constructor(elRef: ElementRef) { elRef.nativeElement.textContent += 'noduplicate'; } + constructor(elRef: ElementRef) { + elRef.nativeElement.textContent += 'noduplicate'; + } } @Directive({selector: '[no-duplicate]'}) class OtherDuplicateDir { - constructor(elRef: ElementRef) { elRef.nativeElement.textContent += 'othernoduplicate'; } + constructor(elRef: ElementRef) { + elRef.nativeElement.textContent += 'othernoduplicate'; + } } @Directive({selector: 'directive-throwing-error'}) class DirectiveThrowingAnError { - constructor() { throw new Error('BOOM'); } + constructor() { + throw new Error('BOOM'); + } } @Component({ @@ -2721,15 +2795,19 @@ class DirectiveWithPropDecorators { target: any; // TODO(issue/24571): remove '!'. - @Input('elProp') dirProp !: string; + @Input('elProp') dirProp!: string; @Output('elEvent') event = new EventEmitter(); // TODO(issue/24571): remove '!'. - @HostBinding('attr.my-attr') myAttr !: string; + @HostBinding('attr.my-attr') myAttr!: string; @HostListener('click', ['$event.target']) - onClick(target: any) { this.target = target; } + onClick(target: any) { + this.target = target; + } - fireEvent(msg: any) { this.event.emit(msg); } + fireEvent(msg: any) { + this.event.emit(msg); + } } @Component({selector: 'some-cmp'}) diff --git a/packages/core/test/linker/jit_summaries_integration_spec.ts b/packages/core/test/linker/jit_summaries_integration_spec.ts index 20dfd201b0198..3c7b28aad9674 100644 --- a/packages/core/test/linker/jit_summaries_integration_spec.ts +++ b/packages/core/test/linker/jit_summaries_integration_spec.ts @@ -10,7 +10,7 @@ import {ResourceLoader} from '@angular/compiler'; import {CompileMetadataResolver} from '@angular/compiler/src/metadata_resolver'; import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_mock'; import {Component, Directive, Injectable, NgModule, OnDestroy, Pipe} from '@angular/core'; -import {TestBed, async, getTestBed} from '@angular/core/testing'; +import {async, getTestBed, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {obsoleteInIvy} from '@angular/private/testing'; @@ -32,7 +32,7 @@ import {obsoleteInIvy} from '@angular/private/testing'; } function expectInstanceCreated(type: any) { - const instance = instances.get(type) !; + const instance = instances.get(type)!; expect(instance).toBeDefined(); expect(instance.dep instanceof SomeDep).toBe(true); } @@ -46,7 +46,9 @@ import {obsoleteInIvy} from '@angular/private/testing'; class SomeDirective extends Base {} class SomePipe extends Base { - transform(value: any) { return value; } + transform(value: any) { + return value; + } } class SomeService extends Base {} @@ -138,7 +140,9 @@ import {obsoleteInIvy} from '@angular/private/testing'; createSummaries().then(s => summaries = s); })); - afterEach(() => { resetTestEnvironmentWithSummaries(); }); + afterEach(() => { + resetTestEnvironmentWithSummaries(); + }); it('should use directive metadata from summaries', () => { resetTestEnvironmentWithSummaries(summaries); diff --git a/packages/core/test/linker/ng_container_integration_spec.ts b/packages/core/test/linker/ng_container_integration_spec.ts index 6f7fca54a268c..d0f737d6e9fa6 100644 --- a/packages/core/test/linker/ng_container_integration_spec.ts +++ b/packages/core/test/linker/ng_container_integration_spec.ts @@ -15,15 +15,20 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; import {modifiedInIvy} from '@angular/private/testing'; if (ivyEnabled) { - describe('ivy', () => { declareTests(); }); + describe('ivy', () => { + declareTests(); + }); } else { - describe('jit', () => { declareTests({useJit: true}); }); - describe('no jit', () => { declareTests({useJit: false}); }); + describe('jit', () => { + declareTests({useJit: true}); + }); + describe('no jit', () => { + declareTests({useJit: false}); + }); } function declareTests(config?: {useJit: boolean}) { describe('<ng-container>', function() { - beforeEach(() => { TestBed.configureCompiler({...config}); TestBed.configureTestingModule({ @@ -140,7 +145,7 @@ function declareTests(config?: {useJit: boolean}) { const fixture = TestBed.createComponent(MyComp); fixture.detectChanges(); - const q = fixture.debugElement.children[0].references !['q']; + const q = fixture.debugElement.children[0].references!['q']; fixture.detectChanges(); expect(q.textDirChildren.length).toEqual(1); @@ -153,7 +158,7 @@ function declareTests(config?: {useJit: boolean}) { const fixture = TestBed.createComponent(MyComp); fixture.detectChanges(); - const q = fixture.debugElement.children[0].references !['q']; + const q = fixture.debugElement.children[0].references!['q']; fixture.detectChanges(); expect(q.textDirChildren.length).toEqual(1); @@ -170,21 +175,25 @@ class TextDirective { @Component({selector: 'needs-content-children', template: ''}) class NeedsContentChildren implements AfterContentInit { // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective) textDirChildren !: QueryList<TextDirective>; + @ContentChildren(TextDirective) textDirChildren!: QueryList<TextDirective>; // TODO(issue/24571): remove '!'. - numberOfChildrenAfterContentInit !: number; + numberOfChildrenAfterContentInit!: number; - ngAfterContentInit() { this.numberOfChildrenAfterContentInit = this.textDirChildren.length; } + ngAfterContentInit() { + this.numberOfChildrenAfterContentInit = this.textDirChildren.length; + } } @Component({selector: 'needs-view-children', template: '<div text></div>'}) class NeedsViewChildren implements AfterViewInit { // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) textDirChildren !: QueryList<TextDirective>; + @ViewChildren(TextDirective) textDirChildren!: QueryList<TextDirective>; // TODO(issue/24571): remove '!'. - numberOfChildrenAfterViewInit !: number; + numberOfChildrenAfterViewInit!: number; - ngAfterViewInit() { this.numberOfChildrenAfterViewInit = this.textDirChildren.length; } + ngAfterViewInit() { + this.numberOfChildrenAfterViewInit = this.textDirChildren.length; + } } @Component({selector: 'simple', template: 'SIMPLE(<ng-content></ng-content>)'}) diff --git a/packages/core/test/linker/ng_module_integration_spec.ts b/packages/core/test/linker/ng_module_integration_spec.ts index 08acb83c10d55..e6f2bf694b4aa 100644 --- a/packages/core/test/linker/ng_module_integration_spec.ts +++ b/packages/core/test/linker/ng_module_integration_spec.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {ANALYZE_FOR_ENTRY_COMPONENTS, CUSTOM_ELEMENTS_SCHEMA, ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, Directive, HostBinding, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, Provider, Self, Type, forwardRef, getModuleFactory, ɵivyEnabled as ivyEnabled, ɵɵdefineNgModule as defineNgModule} from '@angular/core'; +import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectorRef, Compiler, Component, ComponentFactoryResolver, CUSTOM_ELEMENTS_SCHEMA, Directive, forwardRef, getModuleFactory, HostBinding, Inject, Injectable, InjectionToken, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, Provider, Self, Type, ɵivyEnabled as ivyEnabled, ɵɵdefineNgModule as defineNgModule} from '@angular/core'; import {Console} from '@angular/core/src/console'; -import {ɵɵInjectableDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs'; +import {ɵɵdefineInjectable, ɵɵInjectableDef} from '@angular/core/src/di/interface/defs'; import {getNgModuleDef} from '@angular/core/src/render3/definition'; import {NgModuleData} from '@angular/core/src/view/types'; import {tokenKey} from '@angular/core/src/view/util'; -import {ComponentFixture, TestBed, inject} from '@angular/core/testing'; +import {ComponentFixture, inject, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; @@ -23,7 +23,9 @@ import {stringify} from '../../src/util/stringify'; class Engine {} class BrokenEngine { - constructor() { throw new Error('Broken Engine'); } + constructor() { + throw new Error('Broken Engine'); + } } class DashboardSoftware {} @@ -53,7 +55,9 @@ class CarWithDashboard { @Injectable() class SportsCar extends Car { - constructor(engine: Engine) { super(engine); } + constructor(engine: Engine) { + super(engine); + } } @Injectable() @@ -79,13 +83,14 @@ class SomeComp { @Directive({selector: '[someDir]'}) class SomeDirective { // TODO(issue/24571): remove '!'. - @HostBinding('title') @Input() - someDir !: string; + @HostBinding('title') @Input() someDir!: string; } @Pipe({name: 'somePipe'}) class SomePipe { - transform(value: string): any { return `transformed ${value}`; } + transform(value: string): any { + return `transformed ${value}`; + } } @Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`}) @@ -94,10 +99,16 @@ class CompUsingModuleDirectiveAndPipe { { if (ivyEnabled) { - describe('ivy', () => { declareTests(); }); + describe('ivy', () => { + declareTests(); + }); } else { - describe('jit', () => { declareTests({useJit: true}); }); - describe('no jit', () => { declareTests({useJit: false}); }); + describe('jit', () => { + declareTests({useJit: true}); + }); + describe('no jit', () => { + declareTests({useJit: false}); + }); } } @@ -106,7 +117,9 @@ function declareTests(config?: {useJit: boolean}) { let compiler: Compiler; let injector: Injector; - beforeEach(() => { TestBed.configureCompiler(config || {}); }); + beforeEach(() => { + TestBed.configureCompiler(config || {}); + }); beforeEach(inject([Compiler, Injector], (_compiler: Compiler, _injector: Injector) => { compiler = _compiler; @@ -117,8 +130,7 @@ function declareTests(config?: {useJit: boolean}) { return compiler.compileModuleSync(moduleType); } - function createModule<T>( - moduleType: Type<T>, parentInjector?: Injector | null): NgModuleRef<T> { + function createModule<T>(moduleType: Type<T>, parentInjector?: Injector|null): NgModuleRef<T> { // Read the `ngModuleDef` to cause it to be compiled and any errors thrown. getNgModuleDef(moduleType); return createModuleFactory(moduleType).create(parentInjector || null); @@ -136,11 +148,11 @@ function declareTests(config?: {useJit: boolean}) { const ngModule = createModule(moduleType, injector); - const cf = ngModule.componentFactoryResolver.resolveComponentFactory(compType) !; + const cf = ngModule.componentFactoryResolver.resolveComponentFactory(compType)!; const comp = cf.create(Injector.NULL); - return new ComponentFixture(comp, null !, false); + return new ComponentFixture(comp, null!, false); } describe('errors', () => { @@ -150,8 +162,8 @@ function declareTests(config?: {useJit: boolean}) { } expect(() => createModule(SomeModule)) - .toThrowError( - `Can't export directive ${stringify(SomeDirective)} from ${stringify(SomeModule)} as it was neither declared nor imported!`); + .toThrowError(`Can't export directive ${stringify(SomeDirective)} from ${ + stringify(SomeModule)} as it was neither declared nor imported!`); }); it('should error when exporting a pipe that was neither declared nor imported', () => { @@ -160,8 +172,8 @@ function declareTests(config?: {useJit: boolean}) { } expect(() => createModule(SomeModule)) - .toThrowError( - `Can't export pipe ${stringify(SomePipe)} from ${stringify(SomeModule)} as it was neither declared nor imported!`); + .toThrowError(`Can't export pipe ${stringify(SomePipe)} from ${ + stringify(SomeModule)} as it was neither declared nor imported!`); }); it('should error if a directive is declared in more than 1 module', () => { @@ -177,9 +189,14 @@ function declareTests(config?: {useJit: boolean}) { expect(() => createModule(Module2)) .toThrowError( - `Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` + - `Please consider moving ${stringify(SomeDirective)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` + - `You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); + `Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${ + stringify(Module1)} and ${stringify(Module2)}! ` + + `Please consider moving ${ + stringify(SomeDirective)} to a higher module that imports ${ + stringify(Module1)} and ${stringify(Module2)}. ` + + `You can also create a new NgModule that exports and includes ${ + stringify(SomeDirective)} then import that NgModule in ${ + stringify(Module1)} and ${stringify(Module2)}.`); }); it('should error if a directive is declared in more than 1 module also if the module declaring it is imported', @@ -194,9 +211,14 @@ function declareTests(config?: {useJit: boolean}) { expect(() => createModule(Module2)) .toThrowError( - `Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` + - `Please consider moving ${stringify(SomeDirective)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` + - `You can also create a new NgModule that exports and includes ${stringify(SomeDirective)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); + `Type ${stringify(SomeDirective)} is part of the declarations of 2 modules: ${ + stringify(Module1)} and ${stringify(Module2)}! ` + + `Please consider moving ${ + stringify(SomeDirective)} to a higher module that imports ${ + stringify(Module1)} and ${stringify(Module2)}. ` + + `You can also create a new NgModule that exports and includes ${ + stringify(SomeDirective)} then import that NgModule in ${ + stringify(Module1)} and ${stringify(Module2)}.`); }); it('should error if a pipe is declared in more than 1 module', () => { @@ -212,9 +234,13 @@ function declareTests(config?: {useJit: boolean}) { expect(() => createModule(Module2)) .toThrowError( - `Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` + - `Please consider moving ${stringify(SomePipe)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` + - `You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); + `Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${ + stringify(Module1)} and ${stringify(Module2)}! ` + + `Please consider moving ${stringify(SomePipe)} to a higher module that imports ${ + stringify(Module1)} and ${stringify(Module2)}. ` + + `You can also create a new NgModule that exports and includes ${ + stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${ + stringify(Module2)}.`); }); it('should error if a pipe is declared in more than 1 module also if the module declaring it is imported', @@ -229,11 +255,14 @@ function declareTests(config?: {useJit: boolean}) { expect(() => createModule(Module2)) .toThrowError( - `Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${stringify(Module1)} and ${stringify(Module2)}! ` + - `Please consider moving ${stringify(SomePipe)} to a higher module that imports ${stringify(Module1)} and ${stringify(Module2)}. ` + - `You can also create a new NgModule that exports and includes ${stringify(SomePipe)} then import that NgModule in ${stringify(Module1)} and ${stringify(Module2)}.`); + `Type ${stringify(SomePipe)} is part of the declarations of 2 modules: ${ + stringify(Module1)} and ${stringify(Module2)}! ` + + `Please consider moving ${stringify(SomePipe)} to a higher module that imports ${ + stringify(Module1)} and ${stringify(Module2)}. ` + + `You can also create a new NgModule that exports and includes ${ + stringify(SomePipe)} then import that NgModule in ${ + stringify(Module1)} and ${stringify(Module2)}.`); }); - }); describe('schemas', () => { @@ -361,7 +390,7 @@ function declareTests(config?: {useJit: boolean}) { } const ngModule = createModule(SomeModule); - expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType) + expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType) .toBe(SomeComp); expect(ngModule.injector.get(ComponentFactoryResolver) .resolveComponentFactory(SomeComp) @@ -411,7 +440,7 @@ function declareTests(config?: {useJit: boolean}) { } const ngModule = createModule(SomeModule); - expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType) + expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType) .toBe(SomeComp); expect(ngModule.injector.get(ComponentFactoryResolver) .resolveComponentFactory(SomeComp) @@ -429,7 +458,7 @@ function declareTests(config?: {useJit: boolean}) { } const ngModule = createModule(SomeModule); - expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType) + expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType) .toBe(SomeComp); expect(ngModule.injector.get(ComponentFactoryResolver) .resolveComponentFactory(SomeComp) @@ -447,14 +476,13 @@ function declareTests(config?: {useJit: boolean}) { } const ngModule = createModule(SomeModule); - expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType) + expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType) .toBe(SomeComp); expect(ngModule.injector.get(ComponentFactoryResolver) .resolveComponentFactory(SomeComp) .componentType) .toBe(SomeComp); }); - }); describe('bootstrap components', () => { @@ -464,7 +492,7 @@ function declareTests(config?: {useJit: boolean}) { } const ngModule = createModule(SomeModule); - expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp) !.componentType) + expect(ngModule.componentFactoryResolver.resolveComponentFactory(SomeComp)!.componentType) .toBe(SomeComp); }); @@ -477,7 +505,6 @@ function declareTests(config?: {useJit: boolean}) { expect(ngModule._bootstrapComponents.length).toBe(1); expect(ngModule._bootstrapComponents[0]).toBe(SomeComp); }); - }); describe('directives and pipes', () => { @@ -542,7 +569,6 @@ function declareTests(config?: {useJit: boolean}) { }); describe('import/export', () => { - it('should support exported directives and pipes', () => { @NgModule({declarations: [SomeDirective, SomePipe], exports: [SomeDirective, SomePipe]}) class SomeImportedModule { @@ -677,7 +703,7 @@ function declareTests(config?: {useJit: boolean}) { let moduleType: any = null; - function createInjector(providers: Provider[], parent?: Injector | null): Injector { + function createInjector(providers: Provider[], parent?: Injector|null): Injector { @NgModule({providers: providers}) class SomeModule { } @@ -687,8 +713,9 @@ function declareTests(config?: {useJit: boolean}) { return createModule(SomeModule, parent).injector; } - it('should provide the module', - () => { expect(createInjector([]).get(moduleType)).toBeAnInstanceOf(moduleType); }); + it('should provide the module', () => { + expect(createInjector([]).get(moduleType)).toBeAnInstanceOf(moduleType); + }); it('should instantiate a class without dependencies', () => { const injector = createInjector([Engine]); @@ -741,7 +768,9 @@ function declareTests(config?: {useJit: boolean}) { }); it('should provide to a factory', () => { - function sportsCarFactory(e: Engine) { return new SportsCar(e); } + function sportsCarFactory(e: Engine) { + return new SportsCar(e); + } const injector = createInjector([Engine, {provide: Car, useFactory: sportsCarFactory, deps: [Engine]}]); @@ -759,8 +788,7 @@ function declareTests(config?: {useJit: boolean}) { it('should provide to an alias', () => { const injector = createInjector([ - Engine, {provide: SportsCar, useClass: SportsCar}, - {provide: Car, useExisting: SportsCar} + Engine, {provide: SportsCar, useClass: SportsCar}, {provide: Car, useExisting: SportsCar} ]); const car = injector.get(Car); @@ -879,7 +907,6 @@ function declareTests(config?: {useJit: boolean}) { }); describe('injecting lazy providers into an eager provider via Injector.get', () => { - it('should inject providers that were declared before it', () => { @NgModule({ providers: [ @@ -920,7 +947,6 @@ function declareTests(config?: {useJit: boolean}) { }); describe('injecting eager providers into an eager provider via Injector.get', () => { - it('should inject providers that were declared before it', () => { @NgModule({ providers: [ @@ -1039,7 +1065,6 @@ function declareTests(config?: {useJit: boolean}) { expect(engineFromParent).not.toBe(engineFromChild); expect(engineFromChild).toBeAnInstanceOf(TurboEngine); }); - }); describe('depedency resolution', () => { @@ -1075,7 +1100,9 @@ function declareTests(config?: {useJit: boolean}) { @NgModule() class ImportedModule { - constructor() { created = true; } + constructor() { + created = true; + } } @NgModule({imports: [ImportedModule]}) @@ -1105,7 +1132,9 @@ function declareTests(config?: {useJit: boolean}) { let destroyed = false; class SomeInjectable { - ngOnDestroy() { destroyed = true; } + ngOnDestroy() { + destroyed = true; + } } @NgModule({providers: [SomeInjectable]}) @@ -1125,8 +1154,12 @@ function declareTests(config?: {useJit: boolean}) { let destroyed = false; class SomeInjectable { - constructor() { created = true; } - ngOnDestroy() { destroyed = true; } + constructor() { + created = true; + } + ngOnDestroy() { + destroyed = true; + } } @NgModule({providers: [SomeInjectable]}) @@ -1174,9 +1207,8 @@ function declareTests(config?: {useJit: boolean}) { } @NgModule({ - imports: [ - {ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]} - ] + imports: + [{ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]}] }) class SomeModule { } @@ -1210,9 +1242,8 @@ function declareTests(config?: {useJit: boolean}) { @NgModule({ providers: [{provide: 'token1', useValue: 'direct'}], - imports: [ - {ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]} - ] + imports: + [{ngModule: ImportedModule, providers: [{provide: 'token1', useValue: 'imported'}]}] }) class SomeModule { } diff --git a/packages/core/test/linker/projection_integration_spec.ts b/packages/core/test/linker/projection_integration_spec.ts index 96590a54369d9..814739e9b6377 100644 --- a/packages/core/test/linker/projection_integration_spec.ts +++ b/packages/core/test/linker/projection_integration_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule, ɵgetDOM as getDOM} from '@angular/common'; -import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, Injector, Input, NO_ERRORS_SCHEMA, NgModule, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation} from '@angular/core'; +import {Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, Injector, Input, NgModule, NO_ERRORS_SCHEMA, OnInit, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser/src/dom/debug/by'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -50,9 +50,7 @@ describe('projection', () => { it('should support projecting text interpolation to a non bound element with other bound elements after it', () => { TestBed.overrideComponent(Simple, { - set: { - template: 'SIMPLE(<div><ng-content></ng-content></div><div [tabIndex]="0">EL</div>)' - } + set: {template: 'SIMPLE(<div><ng-content></ng-content></div><div [tabIndex]="0">EL</div>)'} }); TestBed.overrideComponent(MainComp, {set: {template: '<simple>{{text}}</simple>'}}); const main = TestBed.createComponent(MainComp); @@ -244,8 +242,7 @@ describe('projection', () => { it('should support nesting with content being direct child of a nested component', () => { TestBed.configureTestingModule({ - declarations: - [InnerComponent, InnerInnerComponent, OuterComponent, ManualViewportDirective] + declarations: [InnerComponent, InnerInnerComponent, OuterComponent, ManualViewportDirective] }); TestBed.overrideComponent(MainComp, { set: { @@ -304,7 +301,7 @@ describe('projection', () => { `<ng-content></ng-content>(<ng-template [ngIf]="showing"><ng-content select="div"></ng-content></ng-template>)` }) class Child { - @Input() showing !: boolean; + @Input() showing!: boolean; } @Component({ @@ -361,11 +358,13 @@ describe('projection', () => { }); it('should support moving non projected light dom around', () => { - let sourceDirective: ManualViewportDirective = undefined !; + let sourceDirective: ManualViewportDirective = undefined!; @Directive({selector: '[manual]'}) class ManualViewportDirective { - constructor(public templateRef: TemplateRef<Object>) { sourceDirective = this; } + constructor(public templateRef: TemplateRef<Object>) { + sourceDirective = this; + } } TestBed.configureTestingModule( @@ -594,7 +593,6 @@ describe('projection', () => { it('should project nodes into nested templates when the main template doesn\'t have <ng-content>', () => { - @Component({ selector: 'content-in-template', template: @@ -622,7 +620,6 @@ describe('projection', () => { }); it('should project nodes into nested templates and the main template', () => { - @Component({ selector: 'content-in-main-and-template', template: @@ -720,7 +717,6 @@ describe('projection', () => { }); describe('projectable nodes', () => { - @Component({selector: 'test', template: ''}) class TestComponent { constructor(public cfr: ComponentFactoryResolver) {} @@ -739,14 +735,20 @@ describe('projection', () => { class InsertTplRef implements OnInit { constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {} - ngOnInit() { this._vcRef.createEmbeddedView(this._tplRef); } + ngOnInit() { + this._vcRef.createEmbeddedView(this._tplRef); + } } @Directive({selector: '[delayedInsert]', exportAs: 'delayedInsert'}) class DelayedInsertTplRef { constructor(public vc: ViewContainerRef, public templateRef: TemplateRef<Object>) {} - show() { this.vc.createEmbeddedView(this.templateRef); } - hide() { this.vc.clear(); } + show() { + this.vc.createEmbeddedView(this.templateRef); + } + hide() { + this.vc.clear(); + } } @NgModule({ @@ -893,15 +895,23 @@ class SingleContentTagComponent { @Directive({selector: '[manual]'}) class ManualViewportDirective { constructor(public vc: ViewContainerRef, public templateRef: TemplateRef<Object>) {} - show() { this.vc.createEmbeddedView(this.templateRef); } - hide() { this.vc.clear(); } + show() { + this.vc.createEmbeddedView(this.templateRef); + } + hide() { + this.vc.clear(); + } } @Directive({selector: '[project]'}) class ProjectDirective { constructor(public vc: ViewContainerRef) {} - show(templateRef: TemplateRef<Object>) { this.vc.createEmbeddedView(templateRef); } - hide() { this.vc.clear(); } + show(templateRef: TemplateRef<Object>) { + this.vc.createEmbeddedView(templateRef); + } + hide() { + this.vc.clear(); + } } @Component({ @@ -1034,5 +1044,5 @@ class CmpA2 { } function supportsNativeShadowDOM(): boolean { - return typeof(<any>document.body).createShadowRoot === 'function'; + return typeof (<any>document.body).createShadowRoot === 'function'; } diff --git a/packages/core/test/linker/query_integration_spec.ts b/packages/core/test/linker/query_integration_spec.ts index 4339e63e0683c..bbcfad6ed0240 100644 --- a/packages/core/test/linker/query_integration_spec.ts +++ b/packages/core/test/linker/query_integration_spec.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.io/license */ -import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core'; +import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, asNativeElements, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core'; import {ElementRef} from '@angular/core/src/core'; -import {ComponentFixture, TestBed, async} from '@angular/core/testing'; +import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing'; import {Subject} from 'rxjs'; @@ -16,7 +16,6 @@ import {Subject} from 'rxjs'; import {stringify} from '../../src/util/stringify'; describe('Query API', () => { - beforeEach(() => TestBed.configureTestingModule({ declarations: [ MyComp0, @@ -76,7 +75,7 @@ describe('Query API', () => { const template = '<needs-content-children #q><div text="foo"></div></needs-content-children>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; view.detectChanges(); expect(q.textDirChildren.length).toEqual(1); expect(q.numberOfChildrenAfterContentInit).toEqual(1); @@ -88,7 +87,7 @@ describe('Query API', () => { const view = createTestCmp(MyComp0, template); view.componentInstance.shouldShow = true; view.detectChanges(); - const q: NeedsContentChild = view.debugElement.children[0].references !['q']; + const q: NeedsContentChild = view.debugElement.children[0].references!['q']; expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]); view.componentInstance.shouldShow = false; @@ -114,7 +113,7 @@ describe('Query API', () => { `; const view = createTestCmp(MyComp0, template); view.detectChanges(); - const q: NeedsContentChild = view.debugElement.children[1].references !['q']; + const q: NeedsContentChild = view.debugElement.children[1].references!['q']; expect(q.child.text).toEqual('foo'); const directive: DirectiveNeedsContentChild = view.debugElement.children[0].injector.get(DirectiveNeedsContentChild); @@ -125,7 +124,7 @@ describe('Query API', () => { const template = '<needs-view-child #q></needs-view-child>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewChild = view.debugElement.children[0].references !['q']; + const q: NeedsViewChild = view.debugElement.children[0].references!['q']; expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]); q.shouldShow = false; @@ -140,7 +139,7 @@ describe('Query API', () => { const template = '<needs-static-content-view-child #q><div text="contentFoo"></div></needs-static-content-view-child>'; const view = createTestCmp(MyComp0, template); - const q: NeedsStaticContentAndViewChild = view.debugElement.children[0].references !['q']; + const q: NeedsStaticContentAndViewChild = view.debugElement.children[0].references!['q']; expect(q.contentChild.text).toBeFalsy(); expect(q.viewChild.text).toBeFalsy(); @@ -161,7 +160,7 @@ describe('Query API', () => { const view = TestBed.createComponent(MyComp0); view.detectChanges(); - const q: NeedsViewChild = view.debugElement.children[0].references !['q']; + const q: NeedsViewChild = view.debugElement.children[0].references!['q']; expect(q.logs).toEqual([['setter', 'foo'], ['init', 'foo'], ['check', 'foo']]); q.shouldShow = false; @@ -252,8 +251,8 @@ describe('Query API', () => { const template = '<has-null-query-condition></has-null-query-condition>'; TestBed.overrideComponent(MyCompBroken0, {set: {template}}); expect(() => TestBed.createComponent(MyCompBroken0)) - .toThrowError( - `Can't construct a query for the property "errorTrigger" of "${stringify(HasNullQueryCondition)}" since the query selector wasn't defined.`); + .toThrowError(`Can't construct a query for the property "errorTrigger" of "${ + stringify(HasNullQueryCondition)}" since the query selector wasn't defined.`); }); }); @@ -422,7 +421,7 @@ describe('Query API', () => { '</needs-query>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; q.query.changes.subscribe({ next: () => { @@ -444,11 +443,13 @@ describe('Query API', () => { let isQueryListCompleted = false; - const q: NeedsQuery = view.debugElement.children[0].references !['q']; + const q: NeedsQuery = view.debugElement.children[0].references!['q']; const changes = <Subject<any>>q.query.changes; expect(q.query.length).toEqual(1); expect(changes.closed).toBeFalsy(); - changes.subscribe(() => {}, () => {}, () => { isQueryListCompleted = true; }); + changes.subscribe(() => {}, () => {}, () => { + isQueryListCompleted = true; + }); view.componentInstance.shouldShow = false; view.detectChanges(); @@ -457,7 +458,7 @@ describe('Query API', () => { view.componentInstance.shouldShow = true; view.detectChanges(); - const q2: NeedsQuery = view.debugElement.children[0].references !['q']; + const q2: NeedsQuery = view.debugElement.children[0].references!['q']; expect(q2.query.length).toEqual(1); expect(changes.closed).toBeTruthy(); @@ -472,7 +473,7 @@ describe('Query API', () => { '<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' + '</needs-query-by-ref-binding>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; view.componentInstance.list = ['1d', '2d']; view.detectChanges(); @@ -486,7 +487,7 @@ describe('Query API', () => { '<div text="two" #textLabel2="textDir"></div>' + '</needs-query-by-ref-bindings>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; expect(q.query.first.text).toEqual('one'); expect(q.query.last.text).toEqual('two'); @@ -497,7 +498,7 @@ describe('Query API', () => { '<div *ngFor="let item of list" [text]="item" #textLabel="textDir"></div>' + '</needs-query-by-ref-binding>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; view.componentInstance.list = ['1d', '2d']; view.detectChanges(); @@ -513,7 +514,7 @@ describe('Query API', () => { '</div>' + '</needs-query-by-ref-binding>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; view.componentInstance.list = ['1d', '2d']; view.detectChanges(); @@ -534,14 +535,14 @@ describe('Query API', () => { const template = '<needs-view-query-by-ref-binding #q></needs-view-query-by-ref-binding>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQueryByLabel = view.debugElement.children[0].references !['q']; + const q: NeedsViewQueryByLabel = view.debugElement.children[0].references!['q']; expect(q.query.first.nativeElement).toHaveText('text'); }); it('should contain all child directives in the view dom', () => { const template = '<needs-view-children #q></needs-view-children>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; expect(q.textDirChildren.length).toEqual(1); expect(q.numberOfChildrenAfterViewInit).toEqual(1); }); @@ -551,21 +552,21 @@ describe('Query API', () => { it('should contain all the elements in the view with that have the given directive', () => { const template = '<needs-view-query #q><div text="ignoreme"></div></needs-view-query>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQuery = view.debugElement.children[0].references !['q']; + const q: NeedsViewQuery = view.debugElement.children[0].references!['q']; expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); }); it('should not include directive present on the host element', () => { const template = '<needs-view-query #q text="self"></needs-view-query>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQuery = view.debugElement.children[0].references !['q']; + const q: NeedsViewQuery = view.debugElement.children[0].references!['q']; expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); }); it('should reflect changes in the component', () => { const template = '<needs-view-query-if #q></needs-view-query-if>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQueryIf = view.debugElement.children[0].references !['q']; + const q: NeedsViewQueryIf = view.debugElement.children[0].references!['q']; expect(q.query.length).toBe(0); q.show = true; @@ -577,7 +578,7 @@ describe('Query API', () => { it('should not be affected by other changes in the component', () => { const template = '<needs-view-query-nested-if #q></needs-view-query-nested-if>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQueryNestedIf = view.debugElement.children[0].references !['q']; + const q: NeedsViewQueryNestedIf = view.debugElement.children[0].references!['q']; expect(q.query.length).toEqual(1); expect(q.query.first.text).toEqual('1'); @@ -592,7 +593,7 @@ describe('Query API', () => { () => { const template = '<needs-view-query-order #q></needs-view-query-order>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQueryOrder = view.debugElement.children[0].references !['q']; + const q: NeedsViewQueryOrder = view.debugElement.children[0].references!['q']; expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); @@ -605,7 +606,7 @@ describe('Query API', () => { () => { const template = '<needs-view-query-order-with-p #q></needs-view-query-order-with-p>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQueryOrderWithParent = view.debugElement.children[0].references !['q']; + const q: NeedsViewQueryOrderWithParent = view.debugElement.children[0].references!['q']; expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2', '3', '4']); q.list = ['-3', '2']; @@ -616,7 +617,7 @@ describe('Query API', () => { it('should handle long ngFor cycles', () => { const template = '<needs-view-query-order #q></needs-view-query-order>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q: NeedsViewQueryOrder = view.debugElement.children[0].references !['q']; + const q: NeedsViewQueryOrder = view.debugElement.children[0].references!['q']; // no significance to 50, just a reasonably large cycle. for (let i = 0; i < 50; i++) { @@ -630,7 +631,7 @@ describe('Query API', () => { it('should support more than three queries', () => { const template = '<needs-four-queries #q><div text="1"></div></needs-four-queries>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; expect(q.query1).toBeDefined(); expect(q.query2).toBeDefined(); expect(q.query3).toBeDefined(); @@ -643,7 +644,7 @@ describe('Query API', () => { const template = '<manual-projecting #q><ng-template><div text="1"></div></ng-template></manual-projecting>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; expect(q.query.length).toBe(0); q.create(); @@ -665,7 +666,7 @@ describe('Query API', () => { </ng-template> </manual-projecting>`; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q'] as ManualProjecting; + const q = view.debugElement.children[0].references!['q'] as ManualProjecting; expect(q.query.length).toBe(0); const view1 = q.vc.createEmbeddedView(q.template, {'x': '1'}); @@ -694,7 +695,7 @@ describe('Query API', () => { </ng-template> </manual-projecting>`; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q'] as ManualProjecting; + const q = view.debugElement.children[0].references!['q'] as ManualProjecting; expect(q.query.length).toBe(0); const view1 = q.vc.createEmbeddedView(q.template, {'x': '1'}); @@ -729,7 +730,7 @@ describe('Query API', () => { </div> `; const view = createTestCmp(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; view.componentInstance.shouldShow = true; view.detectChanges(); @@ -751,13 +752,11 @@ describe('Query API', () => { class AutoProjecting { // TODO(issue/24571): // remove '!'. - @ContentChild(TemplateRef) - content !: TemplateRef<any>; + @ContentChild(TemplateRef) content!: TemplateRef<any>; // TODO(issue/24571): // remove '!'. - @ContentChildren(TextDirective) - query !: QueryList<TextDirective>; + @ContentChildren(TextDirective) query!: QueryList<TextDirective>; } TestBed.configureTestingModule({declarations: [AutoProjecting]}); @@ -765,7 +764,7 @@ describe('Query API', () => { '<auto-projecting #q><ng-template><div text="1"></div></ng-template></auto-projecting>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; // This should be 1, but due to // https://github.com/angular/angular/issues/15117 // this is 0. @@ -783,13 +782,11 @@ describe('Query API', () => { class AutoProjecting { // TODO(issue/24571): // remove '!'. - @ContentChild(TemplateRef) - content !: TemplateRef<any>; + @ContentChild(TemplateRef) content!: TemplateRef<any>; // TODO(issue/24571): // remove '!'. - @ContentChildren(TextDirective) - query !: QueryList<TextDirective>; + @ContentChildren(TextDirective) query!: QueryList<TextDirective>; } TestBed.configureTestingModule({declarations: [AutoProjecting]}); @@ -797,7 +794,7 @@ describe('Query API', () => { '<auto-projecting #q><ng-template><div text="1"></div></ng-template></auto-projecting>'; const view = createTestCmpAndDetectChanges(MyComp0, template); - const q = view.debugElement.children[0].references !['q']; + const q = view.debugElement.children[0].references!['q']; expect(q.query.length).toBe(1); }); } @@ -808,35 +805,39 @@ describe('Query API', () => { @Directive({selector: '[text]', inputs: ['text'], exportAs: 'textDir'}) class TextDirective { // TODO(issue/24571): remove '!'. - text !: string; + text!: string; constructor() {} } @Component({selector: 'needs-content-children', template: ''}) class NeedsContentChildren implements AfterContentInit { // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective) textDirChildren !: QueryList<TextDirective>; + @ContentChildren(TextDirective) textDirChildren!: QueryList<TextDirective>; // TODO(issue/24571): remove '!'. - numberOfChildrenAfterContentInit !: number; + numberOfChildrenAfterContentInit!: number; - ngAfterContentInit() { this.numberOfChildrenAfterContentInit = this.textDirChildren.length; } + ngAfterContentInit() { + this.numberOfChildrenAfterContentInit = this.textDirChildren.length; + } } @Component({selector: 'needs-view-children', template: '<div text></div>'}) class NeedsViewChildren implements AfterViewInit { // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) textDirChildren !: QueryList<TextDirective>; + @ViewChildren(TextDirective) textDirChildren!: QueryList<TextDirective>; // TODO(issue/24571): remove '!'. - numberOfChildrenAfterViewInit !: number; + numberOfChildrenAfterViewInit!: number; - ngAfterViewInit() { this.numberOfChildrenAfterViewInit = this.textDirChildren.length; } + ngAfterViewInit() { + this.numberOfChildrenAfterViewInit = this.textDirChildren.length; + } } @Component({selector: 'needs-content-child', template: ''}) class NeedsContentChild implements AfterContentInit, AfterContentChecked { /** @internal */ // TODO(issue/24571): remove '!'. - _child !: TextDirective; + _child!: TextDirective; @ContentChild(TextDirective) set child(value) { @@ -844,18 +845,24 @@ class NeedsContentChild implements AfterContentInit, AfterContentChecked { this.logs.push(['setter', value ? value.text : null]); } - get child() { return this._child; } + get child() { + return this._child; + } logs: any[] /** TODO #9100 */ = []; - ngAfterContentInit() { this.logs.push(['init', this.child ? this.child.text : null]); } + ngAfterContentInit() { + this.logs.push(['init', this.child ? this.child.text : null]); + } - ngAfterContentChecked() { this.logs.push(['check', this.child ? this.child.text : null]); } + ngAfterContentChecked() { + this.logs.push(['check', this.child ? this.child.text : null]); + } } @Directive({selector: '[directive-needs-content-child]'}) class DirectiveNeedsContentChild { // TODO(issue/24571): remove '!'. - @ContentChild(TextDirective) child !: TextDirective; + @ContentChild(TextDirective) child!: TextDirective; } @Component({selector: 'needs-view-child', template: `<div *ngIf="shouldShow" text="foo"></div>`}) @@ -864,7 +871,7 @@ class NeedsViewChild implements AfterViewInit, AfterViewChecked { shouldShow2: boolean = false; /** @internal */ // TODO(issue/24571): remove '!'. - _child !: TextDirective; + _child!: TextDirective; @ViewChild(TextDirective) set child(value) { @@ -872,12 +879,18 @@ class NeedsViewChild implements AfterViewInit, AfterViewChecked { this.logs.push(['setter', value ? value.text : null]); } - get child() { return this._child; } + get child() { + return this._child; + } logs: any[] /** TODO #9100 */ = []; - ngAfterViewInit() { this.logs.push(['init', this.child ? this.child.text : null]); } + ngAfterViewInit() { + this.logs.push(['init', this.child ? this.child.text : null]); + } - ngAfterViewChecked() { this.logs.push(['check', this.child ? this.child.text : null]); } + ngAfterViewChecked() { + this.logs.push(['check', this.child ? this.child.text : null]); + } } function createTestCmp<T>(type: Type<T>, template: string): ComponentFixture<T> { @@ -895,9 +908,9 @@ function createTestCmpAndDetectChanges<T>(type: Type<T>, template: string): Comp @Component({selector: 'needs-static-content-view-child', template: `<div text="viewFoo"></div>`}) class NeedsStaticContentAndViewChild { // TODO(issue/24571): remove '!'. - @ContentChild(TextDirective, {static: true}) contentChild !: TextDirective; + @ContentChild(TextDirective, {static: true}) contentChild!: TextDirective; // TODO(issue/24571): remove '!'. - @ViewChild(TextDirective, {static: true}) viewChild !: TextDirective; + @ViewChild(TextDirective, {static: true}) viewChild!: TextDirective; } @Directive({selector: '[dir]'}) @@ -910,19 +923,19 @@ class InertDirective { }) class NeedsQuery { // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective) query !: QueryList<TextDirective>; + @ContentChildren(TextDirective) query!: QueryList<TextDirective>; } @Component({selector: 'needs-four-queries', template: ''}) class NeedsFourQueries { // TODO(issue/24571): remove '!'. - @ContentChild(TextDirective) query1 !: TextDirective; + @ContentChild(TextDirective) query1!: TextDirective; // TODO(issue/24571): remove '!'. - @ContentChild(TextDirective) query2 !: TextDirective; + @ContentChild(TextDirective) query2!: TextDirective; // TODO(issue/24571): remove '!'. - @ContentChild(TextDirective) query3 !: TextDirective; + @ContentChild(TextDirective) query3!: TextDirective; // TODO(issue/24571): remove '!'. - @ContentChild(TextDirective) query4 !: TextDirective; + @ContentChild(TextDirective) query4!: TextDirective; } @Component({ @@ -931,25 +944,25 @@ class NeedsFourQueries { }) class NeedsQueryDesc { // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective, {descendants: true}) query !: QueryList<TextDirective>; + @ContentChildren(TextDirective, {descendants: true}) query!: QueryList<TextDirective>; } @Component({selector: 'needs-query-by-ref-binding', template: '<ng-content>'}) class NeedsQueryByLabel { // TODO(issue/24571): remove '!'. - @ContentChildren('textLabel', {descendants: true}) query !: QueryList<any>; + @ContentChildren('textLabel', {descendants: true}) query!: QueryList<any>; } @Component({selector: 'needs-view-query-by-ref-binding', template: '<div #textLabel>text</div>'}) class NeedsViewQueryByLabel { // TODO(issue/24571): remove '!'. - @ViewChildren('textLabel') query !: QueryList<any>; + @ViewChildren('textLabel') query!: QueryList<any>; } @Component({selector: 'needs-query-by-ref-bindings', template: '<ng-content>'}) class NeedsQueryByTwoLabels { // TODO(issue/24571): remove '!'. - @ContentChildren('textLabel1,textLabel2', {descendants: true}) query !: QueryList<any>; + @ContentChildren('textLabel1,textLabel2', {descendants: true}) query!: QueryList<any>; } @Component({ @@ -958,7 +971,7 @@ class NeedsQueryByTwoLabels { }) class NeedsQueryAndProject { // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective) query !: QueryList<TextDirective>; + @ContentChildren(TextDirective) query!: QueryList<TextDirective>; } @Component({ @@ -967,14 +980,14 @@ class NeedsQueryAndProject { }) class NeedsViewQuery { // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) query !: QueryList<TextDirective>; + @ViewChildren(TextDirective) query!: QueryList<TextDirective>; } @Component({selector: 'needs-view-query-if', template: '<div *ngIf="show" text="1"></div>'}) class NeedsViewQueryIf { show: boolean = false; // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) query !: QueryList<TextDirective>; + @ViewChildren(TextDirective) query!: QueryList<TextDirective>; } @Component({ @@ -984,7 +997,7 @@ class NeedsViewQueryIf { class NeedsViewQueryNestedIf { show: boolean = true; // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) query !: QueryList<TextDirective>; + @ViewChildren(TextDirective) query!: QueryList<TextDirective>; } @Component({ @@ -995,7 +1008,7 @@ class NeedsViewQueryNestedIf { }) class NeedsViewQueryOrder { // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) query !: QueryList<TextDirective>; + @ViewChildren(TextDirective) query!: QueryList<TextDirective>; list: string[] = ['2', '3']; } @@ -1007,16 +1020,16 @@ class NeedsViewQueryOrder { }) class NeedsViewQueryOrderWithParent { // TODO(issue/24571): remove '!'. - @ViewChildren(TextDirective) query !: QueryList<TextDirective>; + @ViewChildren(TextDirective) query!: QueryList<TextDirective>; list: string[] = ['2', '3']; } @Component({selector: 'needs-tpl', template: '<ng-template><div>shadow</div></ng-template>'}) class NeedsTpl { // TODO(issue/24571): remove '!'. - @ViewChildren(TemplateRef) viewQuery !: QueryList<TemplateRef<Object>>; + @ViewChildren(TemplateRef) viewQuery!: QueryList<TemplateRef<Object>>; // TODO(issue/24571): remove '!'. - @ContentChildren(TemplateRef) query !: QueryList<TemplateRef<Object>>; + @ContentChildren(TemplateRef) query!: QueryList<TemplateRef<Object>>; constructor(public vc: ViewContainerRef) {} } @@ -1024,33 +1037,31 @@ class NeedsTpl { {selector: 'needs-named-tpl', template: '<ng-template #tpl><div>shadow</div></ng-template>'}) class NeedsNamedTpl { // TODO(issue/24571): remove '!'. - @ViewChild('tpl', {static: true}) viewTpl !: TemplateRef<Object>; + @ViewChild('tpl', {static: true}) viewTpl!: TemplateRef<Object>; // TODO(issue/24571): remove '!'. - @ContentChild('tpl', {static: true}) contentTpl !: TemplateRef<Object>; + @ContentChild('tpl', {static: true}) contentTpl!: TemplateRef<Object>; constructor(public vc: ViewContainerRef) {} } @Component({selector: 'needs-content-children-read', template: ''}) class NeedsContentChildrenWithRead { // TODO(issue/24571): remove '!'. - @ContentChildren('q', {read: TextDirective}) textDirChildren !: QueryList<TextDirective>; + @ContentChildren('q', {read: TextDirective}) textDirChildren!: QueryList<TextDirective>; // TODO(issue/24571): remove '!'. - @ContentChildren('nonExisting', {read: TextDirective}) nonExistingVar !: QueryList<TextDirective>; + @ContentChildren('nonExisting', {read: TextDirective}) nonExistingVar!: QueryList<TextDirective>; } @Component({selector: 'needs-content-child-read', template: ''}) class NeedsContentChildWithRead { // TODO(issue/24571): remove '!'. - @ContentChild('q', {read: TextDirective}) textDirChild !: TextDirective; + @ContentChild('q', {read: TextDirective}) textDirChild!: TextDirective; // TODO(issue/24571): remove '!'. - @ContentChild('nonExisting', {read: TextDirective}) - nonExistingVar !: TextDirective; + @ContentChild('nonExisting', {read: TextDirective}) nonExistingVar!: TextDirective; } @Component({selector: 'needs-content-children-shallow', template: ''}) class NeedsContentChildrenShallow { - @ContentChildren('q', {descendants: false}) - children !: QueryList<ElementRef>; + @ContentChildren('q', {descendants: false}) children!: QueryList<ElementRef>; } @Component({ @@ -1059,7 +1070,7 @@ class NeedsContentChildrenShallow { }) class NeedsContentChildTemplateRef { // TODO(issue/24571): remove '!'. - @ContentChild(TemplateRef, {static: true}) templateRef !: TemplateRef<any>; + @ContentChild(TemplateRef, {static: true}) templateRef!: TemplateRef<any>; } @Component({ @@ -1077,9 +1088,9 @@ class NeedsContentChildTemplateRefApp { }) class NeedsViewChildrenWithRead { // TODO(issue/24571): remove '!'. - @ViewChildren('q,w', {read: TextDirective}) textDirChildren !: QueryList<TextDirective>; + @ViewChildren('q,w', {read: TextDirective}) textDirChildren!: QueryList<TextDirective>; // TODO(issue/24571): remove '!'. - @ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar !: QueryList<TextDirective>; + @ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar!: QueryList<TextDirective>; } @Component({ @@ -1088,27 +1099,28 @@ class NeedsViewChildrenWithRead { }) class NeedsViewChildWithRead { // TODO(issue/24571): remove '!'. - @ViewChild('q', {read: TextDirective}) textDirChild !: TextDirective; + @ViewChild('q', {read: TextDirective}) textDirChild!: TextDirective; // TODO(issue/24571): remove '!'. - @ViewChild('nonExisting', {read: TextDirective}) nonExistingVar !: TextDirective; + @ViewChild('nonExisting', {read: TextDirective}) nonExistingVar!: TextDirective; } @Component({selector: 'needs-viewcontainer-read', template: '<div #q></div>'}) class NeedsViewContainerWithRead { // TODO(issue/24571): remove '!'. - @ViewChild('q', {read: ViewContainerRef}) vc !: ViewContainerRef; + @ViewChild('q', {read: ViewContainerRef}) vc!: ViewContainerRef; // TODO(issue/24571): remove '!'. - @ViewChild('nonExisting', {read: ViewContainerRef}) - nonExistingVar !: ViewContainerRef; + @ViewChild('nonExisting', {read: ViewContainerRef}) nonExistingVar!: ViewContainerRef; // TODO(issue/24571): remove '!'. @ContentChild(TemplateRef, {static: true}) template !: TemplateRef<Object>; - createView() { this.vc.createEmbeddedView(this.template); } + createView() { + this.vc.createEmbeddedView(this.template); + } } @Component({selector: 'has-null-query-condition', template: '<div></div>'}) class HasNullQueryCondition { - @ContentChildren(null !) errorTrigger: any; + @ContentChildren(null!) errorTrigger: any; } @Component({selector: 'my-comp', template: ''}) @@ -1127,14 +1139,16 @@ class ManualProjecting { @ContentChild(TemplateRef, {static: true}) template !: TemplateRef<any>; // TODO(issue/24571): remove '!'. - @ViewChild('vc', {read: ViewContainerRef}) - vc !: ViewContainerRef; + @ViewChild('vc', {read: ViewContainerRef}) vc!: ViewContainerRef; // TODO(issue/24571): remove '!'. - @ContentChildren(TextDirective) - query !: QueryList<TextDirective>; + @ContentChildren(TextDirective) query!: QueryList<TextDirective>; - create() { this.vc.createEmbeddedView(this.template); } + create() { + this.vc.createEmbeddedView(this.template); + } - destroy() { this.vc.clear(); } + destroy() { + this.vc.clear(); + } } diff --git a/packages/core/test/linker/query_list_spec.ts b/packages/core/test/linker/query_list_spec.ts index b53827183956d..fa9bf5f9e965d 100644 --- a/packages/core/test/linker/query_list_spec.ts +++ b/packages/core/test/linker/query_list_spec.ts @@ -21,10 +21,11 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin log = ''; }); - function logAppend(item: any /** TODO #9100 */) { log += (log.length == 0 ? '' : ', ') + item; } + function logAppend(item: any /** TODO #9100 */) { + log += (log.length == 0 ? '' : ', ') + item; + } describe('dirty and reset', () => { - it('should initially be dirty and empty', () => { expect(queryList.dirty).toBeTruthy(); expect(queryList.length).toBe(0); @@ -36,7 +37,6 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin expect(queryList.dirty).toBeFalsy(); expect(queryList.length).toBe(2); }); - }); it('should support resetting and iterating over the new objects', () => { @@ -146,7 +146,7 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin // For loops use the iteration protocol. for (const value of queryListAsIterable) { - expect(value).toBe(data.shift() !); + expect(value).toBe(data.shift()!); } expect(data.length).toBe(0); }); @@ -155,7 +155,11 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin describe('simple observable interface', () => { it('should fire callbacks on change', fakeAsync(() => { let fires = 0; - queryList.changes.subscribe({next: (_) => { fires += 1; }}); + queryList.changes.subscribe({ + next: (_) => { + fires += 1; + } + }); queryList.notifyOnChanges(); tick(); @@ -170,7 +174,11 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/src/testin it('should provides query list as an argument', fakeAsync(() => { let recorded: any /** TODO #9100 */; - queryList.changes.subscribe({next: (v: any) => { recorded = v; }}); + queryList.changes.subscribe({ + next: (v: any) => { + recorded = v; + } + }); queryList.reset(['one']); queryList.notifyOnChanges(); diff --git a/packages/core/test/linker/regression_integration_spec.ts b/packages/core/test/linker/regression_integration_spec.ts index 4666970a22424..15239a6277558 100644 --- a/packages/core/test/linker/regression_integration_spec.ts +++ b/packages/core/test/linker/regression_integration_spec.ts @@ -7,18 +7,24 @@ */ import {DOCUMENT, ɵgetDOM as getDOM} from '@angular/common'; -import {ANALYZE_FOR_ENTRY_COMPONENTS, ApplicationRef, Component, ComponentRef, ContentChild, Directive, ErrorHandler, EventEmitter, HostListener, InjectionToken, Injector, Input, NgModule, NgModuleRef, NgZone, Output, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, destroyPlatform, ɵivyEnabled as ivyEnabled} from '@angular/core'; -import {TestBed, fakeAsync, inject, tick} from '@angular/core/testing'; +import {ANALYZE_FOR_ENTRY_COMPONENTS, ApplicationRef, Component, ComponentRef, ContentChild, destroyPlatform, Directive, ErrorHandler, EventEmitter, HostListener, InjectionToken, Injector, Input, NgModule, NgModuleRef, NgZone, Output, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, ɵivyEnabled as ivyEnabled} from '@angular/core'; +import {fakeAsync, inject, TestBed, tick} from '@angular/core/testing'; import {BrowserModule, By} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; if (ivyEnabled) { - describe('ivy', () => { declareTests(); }); + describe('ivy', () => { + declareTests(); + }); } else { - describe('jit', () => { declareTests({useJit: true}); }); - describe('no jit', () => { declareTests({useJit: false}); }); + describe('jit', () => { + declareTests({useJit: true}); + }); + describe('no jit', () => { + declareTests({useJit: false}); + }); } declareTestsUsingBootstrap(); @@ -26,11 +32,14 @@ declareTestsUsingBootstrap(); function declareTests(config?: {useJit: boolean}) { // Place to put reproductions for regressions describe('regressions', () => { - - beforeEach(() => { TestBed.configureTestingModule({declarations: [MyComp1, PlatformPipe]}); }); + beforeEach(() => { + TestBed.configureTestingModule({declarations: [MyComp1, PlatformPipe]}); + }); describe('platform pipes', () => { - beforeEach(() => { TestBed.configureCompiler({...config}); }); + beforeEach(() => { + TestBed.configureCompiler({...config}); + }); it('should overwrite them by custom pipes', () => { TestBed.configureTestingModule({declarations: [CustomPipe]}); @@ -84,14 +93,20 @@ function declareTests(config?: {useJit: boolean}) { class MyDir { setterCalls: {[key: string]: any} = {}; // TODO(issue/24571): remove '!'. - changes !: SimpleChanges; + changes!: SimpleChanges; @Input() - set a(v: number) { this.setterCalls['a'] = v; } + set a(v: number) { + this.setterCalls['a'] = v; + } @Input() - set b(v: number) { this.setterCalls['b'] = v; } + set b(v: number) { + this.setterCalls['b'] = v; + } - ngOnChanges(changes: SimpleChanges) { this.changes = changes; } + ngOnChanges(changes: SimpleChanges) { + this.changes = changes; + } } TestBed.configureTestingModule({declarations: [MyDir, MyComp]}); @@ -128,7 +143,7 @@ function declareTests(config?: {useJit: boolean}) { @Component({selector: 'some-comp', template: '<p (click)="nullValue?.click()"></p>'}) class SomeComponent { // TODO(issue/24571): remove '!'. - nullValue !: SomeReferencedClass; + nullValue!: SomeReferencedClass; } class SomeReferencedClass { @@ -195,20 +210,17 @@ function declareTests(config?: {useJit: boolean}) { }); describe('ANALYZE_FOR_ENTRY_COMPONENTS providers', () => { - it('should support class instances', () => { class SomeObject { someMethod() {} } - expect( - () => createInjector([ - {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: new SomeObject(), multi: true} - ])) + expect(() => createInjector([ + {provide: ANALYZE_FOR_ENTRY_COMPONENTS, useValue: new SomeObject(), multi: true} + ])) .not.toThrow(); }); }); - }); it('should allow logging a previous elements class binding via interpolation', () => { @@ -298,8 +310,7 @@ function declareTests(config?: {useJit: boolean}) { @Component({template: '<div #vc></div><div *ngIf="show" #vc></div>'}) class MyComp { // TODO(issue/24571): remove '!'. - @ViewChildren('vc', {read: ViewContainerRef}) - viewContainers !: QueryList<ViewContainerRef>; + @ViewChildren('vc', {read: ViewContainerRef}) viewContainers!: QueryList<ViewContainerRef>; show = true; } @@ -361,7 +372,7 @@ function declareTests(config?: {useJit: boolean}) { @Directive({selector: 'test'}) class Test { // TODO(issue/24571): remove '!'. - @Input() @ContentChild(TemplateRef, {static: true}) tpl !: TemplateRef<any>; + @Input() @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>; } @Component({ @@ -391,7 +402,7 @@ function declareTests(config?: {useJit: boolean}) { .it('should throw if @ContentChild and @Input are on the same property', () => { @Directive({selector: 'test'}) class Test { - @Input() @ContentChild(TemplateRef, {static: true}) tpl !: TemplateRef<any>; + @Input() @ContentChild(TemplateRef, {static: true}) tpl!: TemplateRef<any>; } @Component({selector: 'my-app', template: `<test></test>`}) @@ -412,8 +423,8 @@ function declareTests(config?: {useJit: boolean}) { class MyModule { } - const modRef = TestBed.configureTestingModule({imports: [MyModule]}) - .get(NgModuleRef) as NgModuleRef<MyModule>; + const modRef = TestBed.configureTestingModule({imports: [MyModule]}).get(NgModuleRef) as + NgModuleRef<MyModule>; const compRef = modRef.componentFactoryResolver.resolveComponentFactory(App).create(Injector.NULL); @@ -429,7 +440,9 @@ function declareTestsUsingBootstrap() { class MockConsole { errors: any[][] = []; - error(...s: any[]): void { this.errors.push(s); } + error(...s: any[]): void { + this.errors.push(s); + } } let logger: MockConsole; @@ -445,7 +458,9 @@ function declareTestsUsingBootstrap() { (errorHandler as any)._console = logger as any; })); - afterEach(() => { destroyPlatform(); }); + afterEach(() => { + destroyPlatform(); + }); if (getDOM().supportsDOMEvents()) { // This test needs a real DOM.... @@ -459,7 +474,9 @@ function declareTestsUsingBootstrap() { class ErrorComp { value = 0; thrownValue = 0; - next() { this.value++; } + next() { + this.value++; + } nextAndThrow() { this.value++; this.throwIfNeeded(); @@ -475,11 +492,12 @@ function declareTestsUsingBootstrap() { @Directive({selector: '[dirClick]'}) class EventDir { - @Output() - dirClick = new EventEmitter(); + @Output() dirClick = new EventEmitter(); @HostListener('click', ['$event']) - onClick(event: any) { this.dirClick.next(event); } + onClick(event: any) { + this.dirClick.next(event); + } } @NgModule({ @@ -552,12 +570,16 @@ class MyComp1 { @Pipe({name: 'somePipe', pure: true}) class PlatformPipe implements PipeTransform { - transform(value: any): any { return 'somePlatformPipe'; } + transform(value: any): any { + return 'somePlatformPipe'; + } } @Pipe({name: 'somePipe', pure: true}) class CustomPipe implements PipeTransform { - transform(value: any): any { return 'someCustomPipe'; } + transform(value: any): any { + return 'someCustomPipe'; + } } @Component({selector: 'cmp-content', template: `<ng-content></ng-content>`}) @@ -571,7 +593,9 @@ class MyCountingComp { return {value: 'counting method value'}; } - static reset() { MyCountingComp.calls = 0; } + static reset() { + MyCountingComp.calls = 0; + } static calls = 0; } @@ -581,7 +605,9 @@ class CountingPipe implements PipeTransform { CountingPipe.calls++; return {value: 'counting pipe value'}; } - static reset() { CountingPipe.calls = 0; } + static reset() { + CountingPipe.calls = 0; + } static calls = 0; } diff --git a/packages/core/test/linker/security_integration_spec.ts b/packages/core/test/linker/security_integration_spec.ts index fb077acac786e..ce8b5c5216dd4 100644 --- a/packages/core/test/linker/security_integration_spec.ts +++ b/packages/core/test/linker/security_integration_spec.ts @@ -8,16 +8,22 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {Component, Directive, HostBinding, Input, NO_ERRORS_SCHEMA, ɵivyEnabled as ivyEnabled} from '@angular/core'; -import {ComponentFixture, TestBed, getTestBed} from '@angular/core/testing'; +import {ComponentFixture, getTestBed, TestBed} from '@angular/core/testing'; import {DomSanitizer} from '@angular/platform-browser/src/security/dom_sanitization_service'; import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; { if (ivyEnabled) { - describe('ivy', () => { declareTests(); }); + describe('ivy', () => { + declareTests(); + }); } else { - describe('jit', () => { declareTests({useJit: true}); }); - describe('no jit', () => { declareTests({useJit: false}); }); + describe('jit', () => { + declareTests({useJit: true}); + }); + describe('no jit', () => { + declareTests({useJit: false}); + }); } } @@ -34,7 +40,6 @@ class OnPrefixDir { function declareTests(config?: {useJit: boolean}) { describe('security integration tests', function() { - beforeEach(() => { TestBed.configureCompiler({...config}).configureTestingModule({ declarations: [ @@ -49,7 +54,9 @@ function declareTests(config?: {useJit: boolean}) { originalLog = getDOM().log; getDOM().log = (msg) => { /* disable logging */ }; }); - afterEach(() => { getDOM().log = originalLog; }); + afterEach(() => { + getDOM().log = originalLog; + }); describe('events', () => { modifiedInIvy('on-prefixed attributes validation happens at runtime in Ivy') @@ -113,7 +120,7 @@ function declareTests(config?: {useJit: boolean}) { }); // should not throw for inputs starting with "on" - let cmp: ComponentFixture<SecuredComponent> = undefined !; + let cmp: ComponentFixture<SecuredComponent> = undefined!; expect(() => cmp = TestBed.createComponent(SecuredComponent)).not.toThrow(); // must bind to the directive not to the property of the div @@ -124,7 +131,6 @@ function declareTests(config?: {useJit: boolean}) { expect(getDOM().getProperty(div.nativeElement, 'onclick')).not.toBe(value); expect(div.nativeElement.hasAttribute('onclick')).toEqual(false); }); - }); describe('safe HTML values', function() { @@ -206,8 +212,7 @@ function declareTests(config?: {useJit: boolean}) { @Directive({selector: '[dirHref]'}) class HrefDirective { // TODO(issue/24571): remove '!'. - @HostBinding('href') @Input() - dirHref !: string; + @HostBinding('href') @Input() dirHref!: string; } const template = `<a [dirHref]="ctxProp">Link Title</a>`; @@ -222,8 +227,7 @@ function declareTests(config?: {useJit: boolean}) { @Directive({selector: '[dirHref]'}) class HrefDirective { // TODO(issue/24571): remove '!'. - @HostBinding('attr.href') @Input() - dirHref !: string; + @HostBinding('attr.href') @Input() dirHref!: string; } const template = `<a [dirHref]="ctxProp">Link Title</a>`; diff --git a/packages/core/test/linker/source_map_integration_node_only_spec.ts b/packages/core/test/linker/source_map_integration_node_only_spec.ts index 581fc63dc4c6d..221a7c630925b 100644 --- a/packages/core/test/linker/source_map_integration_node_only_spec.ts +++ b/packages/core/test/linker/source_map_integration_node_only_spec.ts @@ -16,7 +16,7 @@ import {Attribute, Component, Directive, ErrorHandler, ɵglobal} from '@angular/ import {CompilerFacade, ExportedCompilerFacade} from '@angular/core/src/compiler/compiler_facade'; import {getErrorLogger} from '@angular/core/src/errors'; import {resolveComponentResources} from '@angular/core/src/metadata/resource_loading'; -import {TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {fakeAsync, TestBed, tick} from '@angular/core/testing'; import {modifiedInIvy, onlyInIvy} from '@angular/private/testing'; describe('jit source mapping', () => { @@ -44,7 +44,9 @@ describe('jit source mapping', () => { .describe('(View Engine)', () => { describe('inline templates', () => { const ngUrl = 'ng:///DynamicTestModule/MyComp.html'; - function templateDecorator(template: string) { return {template}; } + function templateDecorator(template: string) { + return {template}; + } declareTests({ngUrl, templateDecorator}); }); @@ -66,7 +68,9 @@ describe('jit source mapping', () => { class MyComp { } - expect(() => { compileAndCreateComponent(MyComp); }) + expect(() => { + compileAndCreateComponent(MyComp); + }) .toThrowError( new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:2`)); })); @@ -76,7 +80,9 @@ describe('jit source mapping', () => { class MyComp { } - expect(() => { compileAndCreateComponent(MyComp); }) + expect(() => { + compileAndCreateComponent(MyComp); + }) .toThrowError( new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:7`)); })); @@ -105,7 +111,9 @@ describe('jit source mapping', () => { @Directive({selector: '[someDir]'}) class SomeDir { - constructor() { throw new Error('Test'); } + constructor() { + throw new Error('Test'); + } } TestBed.configureTestingModule({declarations: [SomeDir]}); @@ -163,7 +171,9 @@ describe('jit source mapping', () => { @Component({...templateDecorator(template)}) class MyComp { - createError() { throw new Error('Test'); } + createError() { + throw new Error('Test'); + } } const comp = compileAndCreateComponent(MyComp); @@ -195,7 +205,9 @@ describe('jit source mapping', () => { @Component({...templateDecorator(template)}) class MyComp { - createError() { throw new Error('Test'); } + createError() { + throw new Error('Test'); + } } const comp = compileAndCreateComponent(MyComp); @@ -219,19 +231,19 @@ describe('jit source mapping', () => { column: 4, source: ngUrl, }); - })); } }); onlyInIvy('Generated filenames and stack traces have changed in ivy').describe('(Ivy)', () => { - beforeEach(() => overrideCompilerFacade()); afterEach(() => restoreCompilerFacade()); describe('inline templates', () => { const ngUrl = 'ng:///MyComp/template.html'; - function templateDecorator(template: string) { return {template}; } + function templateDecorator(template: string) { + return {template}; + } declareTests({ngUrl, templateDecorator}); }); @@ -268,7 +280,9 @@ describe('jit source mapping', () => { class MyComp { } - expect(() => { resolveCompileAndCreateComponent(MyComp, template); }) + expect(() => { + resolveCompileAndCreateComponent(MyComp, template); + }) .toThrowError( new RegExp(`Template parse errors[\\s\\S]*${escapeRegExp(ngUrl)}@1:7`)); })); @@ -297,7 +311,9 @@ describe('jit source mapping', () => { @Directive({selector: '[someDir]'}) class SomeDir { - constructor() { throw new Error('Test'); } + constructor() { + throw new Error('Test'); + } } TestBed.configureTestingModule({declarations: [SomeDir]}); @@ -351,7 +367,9 @@ describe('jit source mapping', () => { @Component({...templateDecorator(template)}) class MyComp { - createError() { throw new Error('Test'); } + createError() { + throw new Error('Test'); + } } const comp = resolveCompileAndCreateComponent(MyComp, template); @@ -375,7 +393,9 @@ describe('jit source mapping', () => { @Component({...templateDecorator(template)}) class MyComp { - createError() { throw new Error('Test'); } + createError() { + throw new Error('Test'); + } } const comp = resolveCompileAndCreateComponent(MyComp, template); @@ -414,7 +434,9 @@ describe('jit source mapping', () => { return TestBed.createComponent(comType); } - function createResolver(contents: string) { return (_url: string) => Promise.resolve(contents); } + function createResolver(contents: string) { + return (_url: string) => Promise.resolve(contents); + } function resolveCompileAndCreateComponent(comType: any, template: string) { resolveComponentResources(createResolver(template)); @@ -438,7 +460,9 @@ describe('jit source mapping', () => { interface TestConfig { ngUrl: string; - templateDecorator: (template: string) => { [key: string]: any }; + templateDecorator: (template: string) => { + [key: string]: any + }; } interface SourcePos { @@ -448,8 +472,8 @@ describe('jit source mapping', () => { } /** - * A helper class that captures the sources that have been JIT compiled. - */ + * A helper class that captures the sources that have been JIT compiled. + */ class MockJitEvaluator extends JitEvaluator { sources: string[] = []; @@ -466,7 +490,7 @@ describe('jit source mapping', () => { */ getSourceMap(genFile: string): SourceMap { return this.sources.map(source => extractSourceMap(source)) - .find(map => !!(map && map.file === genFile)) !; + .find(map => !!(map && map.file === genFile))!; } getSourcePositionForStack(stack: string, genFile: string): SourcePos { @@ -475,9 +499,9 @@ describe('jit source mapping', () => { .map(line => urlRegexp.exec(line)) .filter(match => !!match) .map(match => ({ - file: match ![1], - line: parseInt(match ![2], 10), - column: parseInt(match ![3], 10) + file: match![1], + line: parseInt(match![2], 10), + column: parseInt(match![3], 10) })) .shift(); if (!pos) { @@ -489,8 +513,8 @@ describe('jit source mapping', () => { } function getErrorLoggerStack(e: Error): string { - let logStack: string = undefined !; - getErrorLogger(e)(<any>{error: () => logStack = new Error().stack !}, e.message); + let logStack: string = undefined!; + getErrorLogger(e)(<any>{error: () => logStack = new Error().stack!}, e.message); return logStack; } }); diff --git a/packages/core/test/linker/system_ng_module_factory_loader_spec.ts b/packages/core/test/linker/system_ng_module_factory_loader_spec.ts index b4baf714f93dd..357b738b73577 100644 --- a/packages/core/test/linker/system_ng_module_factory_loader_spec.ts +++ b/packages/core/test/linker/system_ng_module_factory_loader_spec.ts @@ -32,12 +32,15 @@ describe('SystemJsNgModuleLoader', () => { 'prefixed/test/suffixed': {'NamedNgFactory': 'test module factory'} }); }); - afterEach(() => { global['System'] = oldSystem; }); + afterEach(() => { + global['System'] = oldSystem; + }); it('loads a default factory by appending the factory suffix', async(() => { const loader = new SystemJsNgModuleLoader(new Compiler()); - loader.load('test').then( - contents => { expect(contents).toBe('test module factory' as any); }); + loader.load('test').then(contents => { + expect(contents).toBe('test module factory' as any); + }); })); it('loads a named factory by appending the factory suffix', async(() => { const loader = new SystemJsNgModuleLoader(new Compiler()); @@ -63,12 +66,15 @@ describe('SystemJsNgModuleLoader', () => { 'test': {'default': 'test module', 'NamedModule': 'test NamedModule'}, }); }); - afterEach(() => { global['System'] = oldSystem; }); + afterEach(() => { + global['System'] = oldSystem; + }); it('loads a default module', async(() => { const loader = new SystemJsNgModuleLoader(new Compiler()); - loader.load('test').then( - contents => { expect(contents.moduleType).toBe('test module' as any); }); + loader.load('test').then(contents => { + expect(contents.moduleType).toBe('test module' as any); + }); })); it('loads a named module', async(() => { const loader = new SystemJsNgModuleLoader(new Compiler()); diff --git a/packages/core/test/linker/view_injector_integration_spec.ts b/packages/core/test/linker/view_injector_integration_spec.ts index f6604d552b2f9..008f9f5c37f1f 100644 --- a/packages/core/test/linker/view_injector_integration_spec.ts +++ b/packages/core/test/linker/view_injector_integration_spec.ts @@ -7,7 +7,7 @@ */ import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, DebugElement, Directive, ElementRef, EmbeddedViewRef, Host, Inject, InjectionToken, Injector, Input, NgModule, Optional, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewContainerRef} from '@angular/core'; -import {ComponentFixture, TestBed, fakeAsync} from '@angular/core/testing'; +import {ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; @@ -32,61 +32,81 @@ class CycleDirective { @Directive({selector: '[needsDirectiveFromSelf]'}) class NeedsDirectiveFromSelf { dependency: SimpleDirective; - constructor(@Self() dependency: SimpleDirective) { this.dependency = dependency; } + constructor(@Self() dependency: SimpleDirective) { + this.dependency = dependency; + } } @Directive({selector: '[optionallyNeedsDirective]'}) class OptionallyNeedsDirective { dependency: SimpleDirective; - constructor(@Self() @Optional() dependency: SimpleDirective) { this.dependency = dependency; } + constructor(@Self() @Optional() dependency: SimpleDirective) { + this.dependency = dependency; + } } @Directive({selector: '[needsComponentFromHost]'}) class NeedsComponentFromHost { dependency: SimpleComponent; - constructor(@Host() dependency: SimpleComponent) { this.dependency = dependency; } + constructor(@Host() dependency: SimpleComponent) { + this.dependency = dependency; + } } @Directive({selector: '[needsDirectiveFromHost]'}) class NeedsDirectiveFromHost { dependency: SimpleDirective; - constructor(@Host() dependency: SimpleDirective) { this.dependency = dependency; } + constructor(@Host() dependency: SimpleDirective) { + this.dependency = dependency; + } } @Directive({selector: '[needsDirective]'}) class NeedsDirective { dependency: SimpleDirective; - constructor(dependency: SimpleDirective) { this.dependency = dependency; } + constructor(dependency: SimpleDirective) { + this.dependency = dependency; + } } @Directive({selector: '[needsService]'}) class NeedsService { service: any; - constructor(@Inject('service') service: any) { this.service = service; } + constructor(@Inject('service') service: any) { + this.service = service; + } } @Directive({selector: '[needsAppService]'}) class NeedsAppService { service: any; - constructor(@Inject('appService') service: any) { this.service = service; } + constructor(@Inject('appService') service: any) { + this.service = service; + } } @Component({selector: '[needsHostAppService]', template: ''}) class NeedsHostAppService { service: any; - constructor(@Host() @Inject('appService') service: any) { this.service = service; } + constructor(@Host() @Inject('appService') service: any) { + this.service = service; + } } @Component({selector: '[needsServiceComponent]', template: ''}) class NeedsServiceComponent { service: any; - constructor(@Inject('service') service: any) { this.service = service; } + constructor(@Inject('service') service: any) { + this.service = service; + } } @Directive({selector: '[needsServiceFromHost]'}) class NeedsServiceFromHost { service: any; - constructor(@Host() @Inject('service') service: any) { this.service = service; } + constructor(@Host() @Inject('service') service: any) { + this.service = service; + } } @Directive({selector: '[needsAttribute]'}) @@ -146,36 +166,50 @@ class PushComponentNeedsChangeDetectorRef { @Pipe({name: 'purePipe', pure: true}) class PurePipe implements PipeTransform { constructor() {} - transform(value: any): any { return this; } + transform(value: any): any { + return this; + } } @Pipe({name: 'impurePipe', pure: false}) class ImpurePipe implements PipeTransform { constructor() {} - transform(value: any): any { return this; } + transform(value: any): any { + return this; + } } @Pipe({name: 'pipeNeedsChangeDetectorRef'}) class PipeNeedsChangeDetectorRef { constructor(public changeDetectorRef: ChangeDetectorRef) {} - transform(value: any): any { return this; } + transform(value: any): any { + return this; + } } @Pipe({name: 'pipeNeedsService'}) export class PipeNeedsService implements PipeTransform { service: any; - constructor(@Inject('service') service: any) { this.service = service; } - transform(value: any): any { return this; } + constructor(@Inject('service') service: any) { + this.service = service; + } + transform(value: any): any { + return this; + } } @Pipe({name: 'duplicatePipe'}) export class DuplicatePipe1 implements PipeTransform { - transform(value: any): any { return this; } + transform(value: any): any { + return this; + } } @Pipe({name: 'duplicatePipe'}) export class DuplicatePipe2 implements PipeTransform { - transform(value: any): any { return this; } + transform(value: any): any { + return this; + } } @Component({selector: 'root', template: ''}) @@ -183,15 +217,15 @@ class TestComp { } function createComponentFixture<T>( - template: string, providers?: Provider[] | null, comp?: Type<T>): ComponentFixture<T> { + template: string, providers?: Provider[]|null, comp?: Type<T>): ComponentFixture<T> { if (!comp) { comp = <any>TestComp; } - TestBed.overrideComponent(comp !, {set: {template}}); + TestBed.overrideComponent(comp!, {set: {template}}); if (providers && providers.length) { - TestBed.overrideComponent(comp !, {add: {providers: providers}}); + TestBed.overrideComponent(comp!, {add: {providers: providers}}); } - return TestBed.createComponent(comp !); + return TestBed.createComponent(comp!); } function createComponent(template: string, providers?: Provider[], comp?: Type<any>): DebugElement { @@ -351,7 +385,6 @@ describe('View injector', () => { }); describe('injecting lazy providers into an eager provider via Injector.get', () => { - it('should inject providers that were declared before it', () => { @Component({ template: '', @@ -448,7 +481,9 @@ describe('View injector', () => { @Component({providers: [{provide: 'a', useFactory: () => 'aValue'}], template: ''}) class SomeComponent { public a: string; - constructor(injector: Injector) { this.a = injector.get('a'); } + constructor(injector: Injector) { + this.a = injector.get('a'); + } } const comp = TestBed.configureTestingModule({declarations: [SomeComponent]}) @@ -461,8 +496,12 @@ describe('View injector', () => { let destroyed = false; class SomeInjectable { - constructor() { created = true; } - ngOnDestroy() { destroyed = true; } + constructor() { + created = true; + } + ngOnDestroy() { + destroyed = true; + } } @Component({providers: [SomeInjectable], template: ''}) @@ -910,7 +949,7 @@ describe('View injector', () => { const testInjector = <Injector>{ get: (token: any, notFoundValue: any) => - token === 'someToken' ? 'someNewValue' : notFoundValue + token === 'someToken' ? 'someNewValue' : notFoundValue }; const compFactory = TestBed.configureTestingModule({imports: [TestModule]}) @@ -961,8 +1000,7 @@ describe('View injector', () => { it('should inject ChangeDetectorRef into pipes', () => { TestBed.configureTestingModule({ - declarations: - [SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] + declarations: [SimpleDirective, PipeNeedsChangeDetectorRef, DirectiveNeedsChangeDetectorRef] }); const el = createComponent( '<div [simpleDirective]="true | pipeNeedsChangeDetectorRef" directiveNeedsChangeDetectorRef></div>'); diff --git a/packages/core/test/metadata/di_spec.ts b/packages/core/test/metadata/di_spec.ts index 733328e53c540..13421776d5fec 100644 --- a/packages/core/test/metadata/di_spec.ts +++ b/packages/core/test/metadata/di_spec.ts @@ -68,7 +68,6 @@ import {TestBed} from '@angular/core/testing'; view.detectChanges(); expect(view.componentInstance.children).toBeDefined(); expect(view.componentInstance.children.length).toBe(2); - }); }); } @@ -77,30 +76,30 @@ import {TestBed} from '@angular/core/testing'; @Directive({selector: 'simple'}) class Simple { // TODO(issue/24571): remove '!'. - @Input() marker !: string; + @Input() marker!: string; } @Component({selector: 'view-child-type-selector', template: ''}) class ViewChildTypeSelectorComponent { // TODO(issue/24571): remove '!'. - @ViewChild(Simple) child !: Simple; + @ViewChild(Simple) child!: Simple; } @Component({selector: 'view-child-string-selector', template: ''}) class ViewChildStringSelectorComponent { // TODO(issue/24571): remove '!'. - @ViewChild('child') child !: ElementRef; + @ViewChild('child') child!: ElementRef; } @Component({selector: 'view-children-type-selector', template: ''}) class ViewChildrenTypeSelectorComponent { // TODO(issue/24571): remove '!'. - @ViewChildren(Simple) children !: QueryList<Simple>; + @ViewChildren(Simple) children!: QueryList<Simple>; } @Component({selector: 'view-child-string-selector', template: ''}) class ViewChildrenStringSelectorComponent { // Allow comma separated selector (with spaces). // TODO(issue/24571): remove '!'. - @ViewChildren('child1 , child2') children !: QueryList<ElementRef>; + @ViewChildren('child1 , child2') children!: QueryList<ElementRef>; } diff --git a/packages/core/test/metadata/resource_loading_spec.ts b/packages/core/test/metadata/resource_loading_spec.ts index c27f8a5f3e4a2..2fb11b3f1127a 100644 --- a/packages/core/test/metadata/resource_loading_spec.ts +++ b/packages/core/test/metadata/resource_loading_spec.ts @@ -16,7 +16,7 @@ describe('resource_loading', () => { describe('error handling', () => { it('should throw an error when compiling component that has unresolved templateUrl', () => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; compileComponent(MyComponent, {templateUrl: 'someUrl'}); expect(() => MyComponent.ɵcmp).toThrowError(` Component 'MyComponent' is not resolved: @@ -25,7 +25,7 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); }); it('should throw an error when compiling component that has unresolved styleUrls', () => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; compileComponent(MyComponent, {styleUrls: ['someUrl1', 'someUrl2']}); expect(() => MyComponent.ɵcmp).toThrowError(` Component 'MyComponent' is not resolved: @@ -35,7 +35,7 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); it('should throw an error when compiling component that has unresolved templateUrl and styleUrls', () => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; compileComponent( MyComponent, {templateUrl: 'someUrl', styleUrls: ['someUrl1', 'someUrl2']}); expect(() => MyComponent.ɵcmp).toThrowError(` @@ -59,8 +59,8 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); } beforeEach(() => resourceFetchCount = 0); - it('should resolve template', async() => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + it('should resolve template', async () => { + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; const metadata: Component = {templateUrl: 'test://content'}; compileComponent(MyComponent, metadata); await resolveComponentResources(testResolver); @@ -69,8 +69,8 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); expect(resourceFetchCount).toBe(1); }); - it('should resolve styleUrls', async() => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + it('should resolve styleUrls', async () => { + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; const metadata: Component = {template: '', styleUrls: ['test://style1', 'test://style2']}; compileComponent(MyComponent, metadata); await resolveComponentResources(testResolver); @@ -80,8 +80,8 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); expect(resourceFetchCount).toBe(2); }); - it('should cache multiple resolution to same URL', async() => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + it('should cache multiple resolution to same URL', async () => { + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; const metadata: Component = {template: '', styleUrls: ['test://style1', 'test://style1']}; compileComponent(MyComponent, metadata); await resolveComponentResources(testResolver); @@ -91,8 +91,8 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); expect(resourceFetchCount).toBe(1); }); - it('should keep order even if the resolution is out of order', async() => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + it('should keep order even if the resolution is out of order', async () => { + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; const metadata: Component = { template: '', styles: ['existing'], @@ -113,8 +113,8 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); }); it('should not add components without external resources to resolution queue', () => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; - const MyComponent2: ComponentType<any> = (class MyComponent{}) as any; + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; + const MyComponent2: ComponentType<any> = (class MyComponent {}) as any; compileComponent(MyComponent, {template: ''}); expect(isComponentResourceResolutionQueueEmpty()).toBe(true); @@ -127,12 +127,14 @@ Did you run and wait for 'resolveComponentResources()'?`.trim()); describe('fetch', () => { function fetch(url: string): Promise<Response> { return Promise.resolve({ - text() { return 'response for ' + url; } + text() { + return 'response for ' + url; + } } as any as Response); } - it('should work with fetch', async() => { - const MyComponent: ComponentType<any> = (class MyComponent{}) as any; + it('should work with fetch', async () => { + const MyComponent: ComponentType<any> = (class MyComponent {}) as any; const metadata: Component = {templateUrl: 'test://content'}; compileComponent(MyComponent, metadata); await resolveComponentResources(fetch); diff --git a/packages/core/test/reflection/reflector_spec.ts b/packages/core/test/reflection/reflector_spec.ts index ff07f8b1f66b1..90a008238fd9f 100644 --- a/packages/core/test/reflection/reflector_spec.ts +++ b/packages/core/test/reflection/reflector_spec.ts @@ -7,13 +7,13 @@ */ import {Reflector} from '@angular/core/src/reflection/reflection'; -import {ReflectionCapabilities, isDelegateCtor} from '@angular/core/src/reflection/reflection_capabilities'; +import {isDelegateCtor, ReflectionCapabilities} from '@angular/core/src/reflection/reflection_capabilities'; import {makeDecorator, makeParamDecorator, makePropDecorator} from '@angular/core/src/util/decorators'; import {global} from '@angular/core/src/util/global'; interface ClassDecoratorFactory { (data: ClassDecorator): any; - new (data: ClassDecorator): ClassDecorator; + new(data: ClassDecorator): ClassDecorator; } interface ClassDecorator { @@ -46,10 +46,12 @@ class ClassWithDecorators { b: AType; @PropDecorator('p3') - set c(value: any) {} + set c(value: any) { + } @PropDecorator('p4') - someMethod() {} + someMethod() { + } constructor(@ParamDecorator('a') a: AType, @ParamDecorator('b') b: AType) { this.a = a; @@ -64,14 +66,18 @@ class ClassWithoutDecorators { class TestObj { constructor(public a: any, public b: any) {} - identity(arg: any) { return arg; } + identity(arg: any) { + return arg; + } } { describe('Reflector', () => { let reflector: Reflector; - beforeEach(() => { reflector = new Reflector(new ReflectionCapabilities()); }); + beforeEach(() => { + reflector = new Reflector(new ReflectionCapabilities()); + }); describe('factory', () => { it('should create a factory for the given type', () => { @@ -131,8 +137,7 @@ class TestObj { it('should also return metadata if the class has no decorator', () => { class Test { - @PropDecorator('test') - prop: any; + @PropDecorator('test') prop: any; } expect(reflector.propMetadata(Test)).toEqual({'prop': [new PropDecorator('test')]}); @@ -183,7 +188,9 @@ class TestObj { class ChildNoCtor extends Parent {} class ChildWithCtor extends Parent { - constructor() { super(); } + constructor() { + super(); + } } class ChildNoCtorPrivateProps extends Parent { private x = 10; @@ -242,12 +249,10 @@ class TestObj { noCtor(`class $Bar1_ extends $Fo0_ {}`); noCtor(`class Bar extends Foo { other(){} }`); }); - }); describe('inheritance with decorators', () => { it('should inherit annotations', () => { - @ClassDecorator({value: 'parent'}) class Parent { } @@ -273,7 +278,7 @@ class TestObj { expect(reflector.annotations(NoDecorators)).toEqual([]); expect(reflector.annotations(<any>{})).toEqual([]); expect(reflector.annotations(<any>1)).toEqual([]); - expect(reflector.annotations(null !)).toEqual([]); + expect(reflector.annotations(null!)).toEqual([]); }); it('should inherit parameters', () => { @@ -303,11 +308,15 @@ class TestObj { // as otherwise TS won't capture the ctor arguments! @ClassDecorator({value: 'child'}) class ChildWithCtor extends Parent { - constructor(@ParamDecorator('c') c: C) { super(null !, null !); } + constructor(@ParamDecorator('c') c: C) { + super(null!, null!); + } } class ChildWithCtorNoDecorator extends Parent { - constructor(a: any, b: any, c: any) { super(null !, null !); } + constructor(a: any, b: any, c: any) { + super(null!, null!); + } } class NoDecorators {} @@ -340,7 +349,7 @@ class TestObj { expect(reflector.parameters(NoDecorators)).toEqual([]); expect(reflector.parameters(<any>{})).toEqual([]); expect(reflector.parameters(<any>1)).toEqual([]); - expect(reflector.parameters(null !)).toEqual([]); + expect(reflector.parameters(null!)).toEqual([]); }); it('should inherit property metadata', () => { @@ -350,20 +359,16 @@ class TestObj { class Parent { // TODO(issue/24571): remove '!'. - @PropDecorator('a') - a !: A; + @PropDecorator('a') a!: A; // TODO(issue/24571): remove '!'. - @PropDecorator('b1') - b !: B; + @PropDecorator('b1') b!: B; } class Child extends Parent { // TODO(issue/24571): remove '!'. - @PropDecorator('b2') - b !: B; + @PropDecorator('b2') b!: B; // TODO(issue/24571): remove '!'. - @PropDecorator('c') - c !: C; + @PropDecorator('c') c!: C; } class NoDecorators {} @@ -383,7 +388,7 @@ class TestObj { expect(reflector.propMetadata(NoDecorators)).toEqual({}); expect(reflector.propMetadata(<any>{})).toEqual({}); expect(reflector.propMetadata(<any>1)).toEqual({}); - expect(reflector.propMetadata(null !)).toEqual({}); + expect(reflector.propMetadata(null!)).toEqual({}); }); it('should inherit lifecycle hooks', () => { @@ -406,12 +411,10 @@ class TestObj { expect(hooks(Child, ['hook1', 'hook2', 'hook3'])).toEqual([true, true, true]); }); - }); describe('inheritance with tsickle', () => { it('should inherit annotations', () => { - class Parent { static decorators = [{type: ClassDecorator, args: [{value: 'parent'}]}]; } @@ -448,9 +451,12 @@ class TestObj { class Child extends Parent {} class ChildWithCtor extends Parent { - static ctorParameters = - () => [{type: C, decorators: [{type: ParamDecorator, args: ['c']}]}, ] - constructor() { super(); } + static ctorParameters = () => + [{type: C, decorators: [{type: ParamDecorator, args: ['c']}]}, + ] + constructor() { + super(); + } } // Check that metadata for Parent was not changed! @@ -496,12 +502,10 @@ class TestObj { 'c': [new PropDecorator('c')] }); }); - }); describe('inheritance with es5 API', () => { it('should inherit annotations', () => { - class Parent { static annotations = [new ClassDecorator({value: 'parent'})]; } @@ -541,7 +545,9 @@ class TestObj { static parameters = [ [C, new ParamDecorator('c')], ]; - constructor() { super(); } + constructor() { + super(); + } } // Check that metadata for Parent was not changed! diff --git a/packages/core/test/render3/basic_perf.ts b/packages/core/test/render3/basic_perf.ts index f719d1c0d1f9b..27e562f64e4ca 100644 --- a/packages/core/test/render3/basic_perf.ts +++ b/packages/core/test/render3/basic_perf.ts @@ -13,7 +13,6 @@ import {RenderFlags} from '../../src/render3/interfaces/definition'; import {document, renderComponent} from './render_util'; describe('iv perf test', () => { - const count = 100000; const noOfIterations = 10; @@ -39,28 +38,29 @@ describe('iv perf test', () => { selectors: [['div']], decls: 1, vars: 0, - template: function Template(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵcontainer(0); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(0); - { - for (let i = 0; i < count; i++) { - let rf0 = ɵɵembeddedViewStart(0, 2, 0); + template: + function Template(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵcontainer(0); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(0); { - if (rf0 & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - ɵɵtext(1, '-'); - ɵɵelementEnd(); + for (let i = 0; i < count; i++) { + let rf0 = ɵɵembeddedViewStart(0, 2, 0); + { + if (rf0 & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + ɵɵtext(1, '-'); + ɵɵelementEnd(); + } + } + ɵɵembeddedViewEnd(); } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } } - ɵɵcontainerRefreshEnd(); - } - } }); } diff --git a/packages/core/test/render3/change_detection_spec.ts b/packages/core/test/render3/change_detection_spec.ts index cc46bf864e7f9..b6844608b0fd5 100644 --- a/packages/core/test/render3/change_detection_spec.ts +++ b/packages/core/test/render3/change_detection_spec.ts @@ -10,7 +10,7 @@ import {withBody} from '@angular/private/testing'; import {ChangeDetectionStrategy, DoCheck} from '../../src/core'; import {whenRendered} from '../../src/render3/component'; -import {LifecycleHooksFeature, getRenderedText, ɵɵadvance, ɵɵdefineComponent, ɵɵgetCurrentView, ɵɵproperty, ɵɵtextInterpolate1, ɵɵtextInterpolate2} from '../../src/render3/index'; +import {getRenderedText, LifecycleHooksFeature, ɵɵadvance, ɵɵdefineComponent, ɵɵgetCurrentView, ɵɵproperty, ɵɵtextInterpolate1, ɵɵtextInterpolate2} from '../../src/render3/index'; import {detectChanges, markDirty, tick, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵlistener, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer'; @@ -23,7 +23,9 @@ describe('change detection', () => { class MyComponent implements DoCheck { value: string = 'works'; doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + ngDoCheck(): void { + this.doCheckCount++; + } static ɵfac = () => new MyComponent(); static ɵcmp = ɵɵdefineComponent({ @@ -31,17 +33,18 @@ describe('change detection', () => { selectors: [['my-comp']], decls: 2, vars: 1, - template: (rf: RenderFlags, ctx: MyComponent) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'span'); - ɵɵtext(1); - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵadvance(1); - ɵɵtextInterpolate(ctx.value); - } - } + template: + (rf: RenderFlags, ctx: MyComponent) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'span'); + ɵɵtext(1); + ɵɵelementEnd(); + } + if (rf & RenderFlags.Update) { + ɵɵadvance(1); + ɵɵtextInterpolate(ctx.value); + } + } }); } @@ -78,7 +81,7 @@ describe('change detection', () => { expect(myComp.doCheckCount).toBe(2); })); - it('should notify whenRendered', withBody('my-comp', async() => { + it('should notify whenRendered', withBody('my-comp', async () => { const myComp = renderComponent(MyComponent, {hostFeatures: [LifecycleHooksFeature]}); await whenRendered(myComp); myComp.value = 'updated'; @@ -97,7 +100,9 @@ describe('change detection', () => { name = 'Nancy'; doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + ngDoCheck(): void { + this.doCheckCount++; + } onClick() {} @@ -111,19 +116,22 @@ describe('change detection', () => { * {{ doCheckCount }} - {{ name }} * <button (click)="onClick()"></button> */ - template: (rf: RenderFlags, ctx: MyComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - ɵɵelementStart(1, 'button'); - { - ɵɵlistener('click', () => { ctx.onClick(); }); - } - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate2('', ctx.doCheckCount, ' - ', ctx.name, ''); - } - }, + template: + (rf: RenderFlags, ctx: MyComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + ɵɵelementStart(1, 'button'); + { + ɵɵlistener('click', () => { + ctx.onClick(); + }); + } + ɵɵelementEnd(); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate2('', ctx.doCheckCount, ' - ', ctx.name, ''); + } + }, changeDetection: ChangeDetectionStrategy.OnPush, inputs: {name: 'name'} }); @@ -135,7 +143,9 @@ describe('change detection', () => { name = 'Nancy'; doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + ngDoCheck(): void { + this.doCheckCount++; + } onClick() {} @@ -149,24 +159,27 @@ describe('change detection', () => { * {{ doCheckCount }} - {{ name }} * <button (click)="onClick()"></button> */ - template: (rf: RenderFlags, ctx: ManualComponent) => { - if (rf & RenderFlags.Create) { - // This is temporarily the only way to turn on manual change detection - // because public API has not yet been added. - const view = ɵɵgetCurrentView() as any; - view[FLAGS] |= LViewFlags.ManualOnPush; - - ɵɵtext(0); - ɵɵelementStart(1, 'button'); - { - ɵɵlistener('click', () => { ctx.onClick(); }); - } - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate2('', ctx.doCheckCount, ' - ', ctx.name, ''); - } - }, + template: + (rf: RenderFlags, ctx: ManualComponent) => { + if (rf & RenderFlags.Create) { + // This is temporarily the only way to turn on manual change detection + // because public API has not yet been added. + const view = ɵɵgetCurrentView() as any; + view[FLAGS] |= LViewFlags.ManualOnPush; + + ɵɵtext(0); + ɵɵelementStart(1, 'button'); + { + ɵɵlistener('click', () => { + ctx.onClick(); + }); + } + ɵɵelementEnd(); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate2('', ctx.doCheckCount, ' - ', ctx.name, ''); + } + }, changeDetection: ChangeDetectionStrategy.OnPush, inputs: {name: 'name'} }); @@ -182,15 +195,15 @@ describe('change detection', () => { decls: 1, vars: 1, /** <manual-comp [name]="name"></manual-comp> */ - template: (rf: RenderFlags, ctx: ManualApp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'manual-comp'); - } - if (rf & RenderFlags.Update) { - ɵɵproperty('name', ctx.name); - } - - }, + template: + (rf: RenderFlags, ctx: ManualApp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'manual-comp'); + } + if (rf & RenderFlags.Update) { + ɵɵproperty('name', ctx.name); + } + }, directives: () => [ManualComponent] }); } @@ -202,7 +215,7 @@ describe('change detection', () => { expect(comp.doCheckCount).toEqual(1); expect(getRenderedText(myApp)).toEqual('1 - Nancy'); - const button = containerEl.querySelector('button') !; + const button = containerEl.querySelector('button')!; button.click(); requestAnimationFrame.flush(); // No ticks should have been scheduled. @@ -228,7 +241,9 @@ describe('change detection', () => { class ButtonParent implements DoCheck { doCheckCount = 0; - ngDoCheck(): void { this.doCheckCount++; } + ngDoCheck(): void { + this.doCheckCount++; + } static ɵfac = () => parent = new ButtonParent(); static ɵcmp = ɵɵdefineComponent({ @@ -237,15 +252,16 @@ describe('change detection', () => { decls: 2, vars: 1, /** {{ doCheckCount }} - <manual-comp></manual-comp> */ - template: (rf: RenderFlags, ctx: ButtonParent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - ɵɵelement(1, 'manual-comp'); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate1('', ctx.doCheckCount, ' - '); - } - }, + template: + (rf: RenderFlags, ctx: ButtonParent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + ɵɵelement(1, 'manual-comp'); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate1('', ctx.doCheckCount, ' - '); + } + }, directives: () => [ManualComponent], changeDetection: ChangeDetectionStrategy.OnPush }); @@ -258,35 +274,35 @@ describe('change detection', () => { }, 1, 0, [ButtonParent]); const myButtonApp = renderComponent(MyButtonApp); - expect(parent !.doCheckCount).toEqual(1); - expect(comp !.doCheckCount).toEqual(1); + expect(parent!.doCheckCount).toEqual(1); + expect(comp!.doCheckCount).toEqual(1); expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); tick(myButtonApp); - expect(parent !.doCheckCount).toEqual(2); + expect(parent!.doCheckCount).toEqual(2); // parent isn't checked, so child doCheck won't run - expect(comp !.doCheckCount).toEqual(1); + expect(comp!.doCheckCount).toEqual(1); expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); const button = containerEl.querySelector('button'); - button !.click(); + button!.click(); requestAnimationFrame.flush(); // No ticks should have been scheduled. - expect(parent !.doCheckCount).toEqual(2); - expect(comp !.doCheckCount).toEqual(1); + expect(parent!.doCheckCount).toEqual(2); + expect(comp!.doCheckCount).toEqual(1); tick(myButtonApp); - expect(parent !.doCheckCount).toEqual(3); + expect(parent!.doCheckCount).toEqual(3); // parent isn't checked, so child doCheck won't run - expect(comp !.doCheckCount).toEqual(1); + expect(comp!.doCheckCount).toEqual(1); expect(getRenderedText(myButtonApp)).toEqual('1 - 1 - Nancy'); markDirty(comp); requestAnimationFrame.flush(); // Now that markDirty has been manually called, both views should be dirty and a tick // should be scheduled to check the view. - expect(parent !.doCheckCount).toEqual(4); - expect(comp !.doCheckCount).toEqual(2); + expect(parent!.doCheckCount).toEqual(4); + expect(comp!.doCheckCount).toEqual(2); expect(getRenderedText(myButtonApp)).toEqual('4 - 2 - Nancy'); }); }); @@ -296,7 +312,9 @@ describe('change detection', () => { const log: string[] = []; const testRendererFactory: RendererFactory3 = { - createRenderer: (): Renderer3 => { return document; }, + createRenderer: (): Renderer3 => { + return document; + }, begin: () => log.push('begin'), end: () => log.push('end'), }; @@ -313,14 +331,15 @@ describe('change detection', () => { selectors: [['my-comp']], decls: 1, vars: 1, - template: (rf: RenderFlags, ctx: MyComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.value); - } - } + template: + (rf: RenderFlags, ctx: MyComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.value); + } + } }); } @@ -328,5 +347,4 @@ describe('change detection', () => { expect(getRenderedText(myComp)).toEqual('works'); expect(log).toEqual(['begin', 'detect changes', 'end']); }); - }); diff --git a/packages/core/test/render3/common_with_def.ts b/packages/core/test/render3/common_with_def.ts index 96904c1b8e5cc..4a36243bb4527 100644 --- a/packages/core/test/render3/common_with_def.ts +++ b/packages/core/test/render3/common_with_def.ts @@ -9,7 +9,7 @@ import {NgForOf as NgForOfDef, NgIf as NgIfDef, NgTemplateOutlet as NgTemplateOutletDef} from '@angular/common'; import {IterableDiffers, NgIterable, TemplateRef, ViewContainerRef} from '@angular/core'; -import {DirectiveType, ɵɵNgOnChangesFeature, ɵɵdefineDirective, ɵɵdirectiveInject} from '../../src/render3/index'; +import {DirectiveType, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵNgOnChangesFeature} from '../../src/render3/index'; export const NgForOf: DirectiveType<NgForOfDef<any, NgIterable<any>>> = NgForOfDef as any; export const NgIf: DirectiveType<NgIfDef<any>> = NgIfDef as any; @@ -42,8 +42,7 @@ NgTemplateOutlet.ɵdir = ɵɵdefineDirective({ type: NgTemplateOutletDef, selectors: [['', 'ngTemplateOutlet', '']], features: [ɵɵNgOnChangesFeature], - inputs: - {ngTemplateOutlet: 'ngTemplateOutlet', ngTemplateOutletContext: 'ngTemplateOutletContext'} + inputs: {ngTemplateOutlet: 'ngTemplateOutlet', ngTemplateOutletContext: 'ngTemplateOutletContext'} }); NgTemplateOutlet.ɵfac = () => new NgTemplateOutletDef(ɵɵdirectiveInject(ViewContainerRef as any)); diff --git a/packages/core/test/render3/component_ref_spec.ts b/packages/core/test/render3/component_ref_spec.ts index 6d5b4375ab96b..4c06136361dc5 100644 --- a/packages/core/test/render3/component_ref_spec.ts +++ b/packages/core/test/render3/component_ref_spec.ts @@ -11,7 +11,7 @@ import {ComponentFactory} from '../../src/linker/component_factory'; import {RendererFactory2, RendererType2} from '../../src/render/api'; import {injectComponentFactoryResolver} from '../../src/render3/component_ref'; import {AttributeMarker, ɵɵdefineComponent} from '../../src/render3/index'; -import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; +import {domRendererFactory3, RElement, Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer'; import {Sanitizer} from '../../src/sanitization/sanitizer'; describe('ComponentFactory', () => { @@ -146,7 +146,7 @@ describe('ComponentFactory', () => { {provide: RendererFactory2, useValue: {createRenderer: createRenderer3Spy}}, ]); - cf.create(injector, undefined, undefined, { injector: mInjector } as NgModuleRef<any>); + cf.create(injector, undefined, undefined, {injector: mInjector} as NgModuleRef<any>); expect(createRenderer2Spy).toHaveBeenCalled(); expect(createRenderer3Spy).not.toHaveBeenCalled(); @@ -159,7 +159,7 @@ describe('ComponentFactory', () => { {provide: RendererFactory2, useValue: {createRenderer: createRenderer2Spy}}, ]); - cf.create(injector, undefined, undefined, { injector: mInjector } as NgModuleRef<any>); + cf.create(injector, undefined, undefined, {injector: mInjector} as NgModuleRef<any>); expect(createRenderer2Spy).toHaveBeenCalled(); expect(createRenderer3Spy).not.toHaveBeenCalled(); @@ -169,7 +169,7 @@ describe('ComponentFactory', () => { const injector = Injector.create([]); const mInjector = Injector.create([]); - cf.create(injector, undefined, undefined, { injector: mInjector } as NgModuleRef<any>); + cf.create(injector, undefined, undefined, {injector: mInjector} as NgModuleRef<any>); expect(createRenderer2Spy).not.toHaveBeenCalled(); expect(createRenderer3Spy).toHaveBeenCalled(); @@ -188,7 +188,7 @@ describe('ComponentFactory', () => { {provide: Sanitizer, useFactory: mSanitizerFactorySpy, deps: []}, ]); - cf.create(injector, undefined, undefined, { injector: mInjector } as NgModuleRef<any>); + cf.create(injector, undefined, undefined, {injector: mInjector} as NgModuleRef<any>); expect(iSanitizerFactorySpy).toHaveBeenCalled(); expect(mSanitizerFactorySpy).not.toHaveBeenCalled(); @@ -205,7 +205,7 @@ describe('ComponentFactory', () => { ]); - cf.create(injector, undefined, undefined, { injector: mInjector } as NgModuleRef<any>); + cf.create(injector, undefined, undefined, {injector: mInjector} as NgModuleRef<any>); expect(mSanitizerFactorySpy).toHaveBeenCalled(); }); diff --git a/packages/core/test/render3/component_spec.ts b/packages/core/test/render3/component_spec.ts index ded79d0183e3e..b15319cc0be77 100644 --- a/packages/core/test/render3/component_spec.ts +++ b/packages/core/test/render3/component_spec.ts @@ -8,18 +8,20 @@ import {ViewEncapsulation, ɵɵdefineInjectable, ɵɵdefineInjector} from '../../src/core'; import {createInjector} from '../../src/di/r3_injector'; -import {AttributeMarker, ComponentFactory, LifecycleHooksFeature, getRenderedText, markDirty, ɵɵadvance, ɵɵdefineComponent, ɵɵdirectiveInject, ɵɵproperty, ɵɵselect, ɵɵtemplate} from '../../src/render3/index'; +import {AttributeMarker, ComponentFactory, getRenderedText, LifecycleHooksFeature, markDirty, ɵɵadvance, ɵɵdefineComponent, ɵɵdirectiveInject, ɵɵproperty, ɵɵselect, ɵɵtemplate} from '../../src/render3/index'; import {tick, ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵnextContext, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; import {ComponentDef, RenderFlags} from '../../src/render3/interfaces/definition'; import {NgIf} from './common_with_def'; -import {ComponentFixture, MockRendererFactory, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame, toHtml} from './render_util'; +import {ComponentFixture, containerEl, createComponent, MockRendererFactory, renderComponent, renderToHtml, requestAnimationFrame, toHtml} from './render_util'; describe('component', () => { class CounterComponent { count = 0; - increment() { this.count++; } + increment() { + this.count++; + } static ɵfac = () => new CounterComponent; static ɵcmp = ɵɵdefineComponent({ @@ -28,14 +30,15 @@ describe('component', () => { selectors: [['counter']], decls: 1, vars: 1, - template: function(rf: RenderFlags, ctx: CounterComponent) { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.count); - } - }, + template: + function(rf: RenderFlags, ctx: CounterComponent) { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.count); + } + }, inputs: {count: 'count'}, }); } @@ -78,14 +81,15 @@ describe('component', () => { selectors: [['my-component']], decls: 1, vars: 1, - template: function(fs: RenderFlags, ctx: MyComponent) { - if (fs & RenderFlags.Create) { - ɵɵtext(0); - } - if (fs & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.myService.value); - } - } + template: + function(fs: RenderFlags, ctx: MyComponent) { + if (fs & RenderFlags.Create) { + ɵɵtext(0); + } + if (fs & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.myService.value); + } + } }); } @@ -105,11 +109,9 @@ describe('component', () => { const fixture = new ComponentFixture(MyComponent, {injector: createInjector(MyModule)}); expect(fixture.html).toEqual('injector'); }); - }); it('should instantiate components at high indices', () => { - // {{ name }} class Comp { // @Input @@ -121,14 +123,15 @@ describe('component', () => { selectors: [['comp']], decls: 1, vars: 1, - template: (rf: RenderFlags, ctx: Comp) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.name); - } - }, + template: + (rf: RenderFlags, ctx: Comp) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.name); + } + }, inputs: {name: 'name'} }); } @@ -152,7 +155,6 @@ describe('component', () => { fixture.update(); expect(fixture.html).toEqual('<comp>some name</comp>'); }); - }); it('should not invoke renderer destroy method for embedded views', () => { @@ -186,31 +188,32 @@ it('should not invoke renderer destroy method for embedded views', () => { * <div>Root view</div> * <div *ngIf="visible">Child view</div> */ - template: function(rf: RenderFlags, ctx: Comp) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - ɵɵtext(1, 'Root view'); - ɵɵelementEnd(); - ɵɵtemplate(2, MyComponent_div_Template_2, 2, 0, 'div', 0); - } - if (rf & RenderFlags.Update) { - ɵɵadvance(2); - ɵɵproperty('ngIf', ctx.visible); - } - } + template: + function(rf: RenderFlags, ctx: Comp) { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + ɵɵtext(1, 'Root view'); + ɵɵelementEnd(); + ɵɵtemplate(2, MyComponent_div_Template_2, 2, 0, 'div', 0); + } + if (rf & RenderFlags.Update) { + ɵɵadvance(2); + ɵɵproperty('ngIf', ctx.visible); + } + } }); } const rendererFactory = new MockRendererFactory(['destroy']); const fixture = new ComponentFixture(Comp, {rendererFactory}); - comp !.visible = false; + comp!.visible = false; fixture.update(); - comp !.visible = true; + comp!.visible = true; fixture.update(); - const renderer = rendererFactory.lastRenderer !; + const renderer = rendererFactory.lastRenderer!; const destroySpy = renderer.spies['destroy']; // we should never see `destroy` method being called @@ -246,7 +249,7 @@ describe('component with a container', () => { class WrapperComponent { // TODO(issue/24571): remove '!'. - items !: string[]; + items!: string[]; static ɵfac = () => new WrapperComponent; static ɵcmp = ɵɵdefineComponent({ type: WrapperComponent, @@ -254,20 +257,21 @@ describe('component with a container', () => { selectors: [['wrapper']], decls: 1, vars: 0, - template: function ChildComponentTemplate(rf: RenderFlags, ctx: {items: string[]}) { - if (rf & RenderFlags.Create) { - ɵɵcontainer(0); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(0); - { - const rf0 = ɵɵembeddedViewStart(0, 1, 0); - { showItems(rf0, {items: ctx.items}); } - ɵɵembeddedViewEnd(); - } - ɵɵcontainerRefreshEnd(); - } - }, + template: + function ChildComponentTemplate(rf: RenderFlags, ctx: {items: string[]}) { + if (rf & RenderFlags.Create) { + ɵɵcontainer(0); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(0); + { + const rf0 = ɵɵembeddedViewStart(0, 1, 0); + { showItems(rf0, {items: ctx.items}); } + ɵɵembeddedViewEnd(); + } + ɵɵcontainerRefreshEnd(); + } + }, inputs: {items: 'items'} }); } @@ -320,9 +324,13 @@ describe('recursive components', () => { class TreeComponent { data: TreeNode = _buildTree(0); - ngDoCheck() { events.push('check' + this.data.value); } + ngDoCheck() { + events.push('check' + this.data.value); + } - ngOnDestroy() { events.push('destroy' + this.data.value); } + ngOnDestroy() { + events.push('destroy' + this.data.value); + } static ɵfac = () => new TreeComponent(); static ɵcmp = ɵɵdefineComponent({ @@ -331,46 +339,47 @@ describe('recursive components', () => { selectors: [['tree-comp']], decls: 3, vars: 1, - template: (rf: RenderFlags, ctx: TreeComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - ɵɵcontainer(1); - ɵɵcontainer(2); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.data.value); - ɵɵcontainerRefreshStart(1); - { - if (ctx.data.left != null) { - let rf0 = ɵɵembeddedViewStart(0, 1, 1); - if (rf0 & RenderFlags.Create) { - ɵɵelement(0, 'tree-comp'); - } - if (rf0 & RenderFlags.Update) { - ɵɵselect(0); - ɵɵproperty('data', ctx.data.left); - } - ɵɵembeddedViewEnd(); + template: + (rf: RenderFlags, ctx: TreeComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + ɵɵcontainer(1); + ɵɵcontainer(2); } - } - ɵɵcontainerRefreshEnd(); - ɵɵcontainerRefreshStart(2); - { - if (ctx.data.right != null) { - let rf0 = ɵɵembeddedViewStart(0, 1, 1); - if (rf0 & RenderFlags.Create) { - ɵɵelement(0, 'tree-comp'); + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.data.value); + ɵɵcontainerRefreshStart(1); + { + if (ctx.data.left != null) { + let rf0 = ɵɵembeddedViewStart(0, 1, 1); + if (rf0 & RenderFlags.Create) { + ɵɵelement(0, 'tree-comp'); + } + if (rf0 & RenderFlags.Update) { + ɵɵselect(0); + ɵɵproperty('data', ctx.data.left); + } + ɵɵembeddedViewEnd(); + } } - if (rf0 & RenderFlags.Update) { - ɵɵselect(0); - ɵɵproperty('data', ctx.data.right); + ɵɵcontainerRefreshEnd(); + ɵɵcontainerRefreshStart(2); + { + if (ctx.data.right != null) { + let rf0 = ɵɵembeddedViewStart(0, 1, 1); + if (rf0 & RenderFlags.Create) { + ɵɵelement(0, 'tree-comp'); + } + if (rf0 & RenderFlags.Update) { + ɵɵselect(0); + ɵɵproperty('data', ctx.data.right); + } + ɵɵembeddedViewEnd(); + } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, + }, inputs: {data: 'data'} }); } @@ -385,9 +394,13 @@ describe('recursive components', () => { class NgIfTree { data: TreeNode = _buildTree(0); - ngDoCheck() { events.push('check' + this.data.value); } + ngDoCheck() { + events.push('check' + this.data.value); + } - ngOnDestroy() { events.push('destroy' + this.data.value); } + ngOnDestroy() { + events.push('destroy' + this.data.value); + } static ɵfac = () => new NgIfTree(); static ɵcmp = ɵɵdefineComponent({ @@ -397,20 +410,21 @@ describe('recursive components', () => { decls: 3, vars: 3, consts: [[AttributeMarker.Bindings, 'data', AttributeMarker.Template, 'ngIf']], - template: (rf: RenderFlags, ctx: NgIfTree) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - ɵɵtemplate(1, IfTemplate, 1, 1, 'ng-if-tree', 0); - ɵɵtemplate(2, IfTemplate2, 1, 1, 'ng-if-tree', 0); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.data.value); - ɵɵadvance(1); - ɵɵproperty('ngIf', ctx.data.left); - ɵɵadvance(1); - ɵɵproperty('ngIf', ctx.data.right); - } - }, + template: + (rf: RenderFlags, ctx: NgIfTree) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + ɵɵtemplate(1, IfTemplate, 1, 1, 'ng-if-tree', 0); + ɵɵtemplate(2, IfTemplate2, 1, 1, 'ng-if-tree', 0); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.data.value); + ɵɵadvance(1); + ɵɵproperty('ngIf', ctx.data.left); + ɵɵadvance(1); + ɵɵproperty('ngIf', ctx.data.right); + } + }, inputs: {data: 'data'}, }); } @@ -457,7 +471,6 @@ describe('recursive components', () => { // This tests that the view tree is set up properly for recursive components it('should call onDestroys properly', () => { - /** * % if (!skipContent) { * <tree-comp></tree-comp> @@ -526,10 +539,10 @@ describe('recursive components', () => { ['destroy0', 'destroy1', 'destroy2', 'destroy3', 'destroy4', 'destroy5', 'destroy6']); }); - it('should map inputs minified & unminified names', async() => { + it('should map inputs minified & unminified names', async () => { class TestInputsComponent { // TODO(issue/24571): remove '!'. - minifiedName !: string; + minifiedName!: string; static ɵfac = () => new TestInputsComponent(); static ɵcmp = ɵɵdefineComponent({ type: TestInputsComponent, @@ -538,9 +551,10 @@ describe('recursive components', () => { inputs: {minifiedName: 'unminifiedName'}, decls: 0, vars: 0, - template: function(rf: RenderFlags, ctx: TestInputsComponent): void { - // Template not needed for this test - } + template: function(rf: RenderFlags, ctx: TestInputsComponent): + void { + // Template not needed for this test + } }); } @@ -549,7 +563,5 @@ describe('recursive components', () => { expect([ {propName: 'minifiedName', templateName: 'unminifiedName'} ]).toEqual(testInputsComponentFactory.inputs); - }); - }); diff --git a/packages/core/test/render3/control_flow_spec.ts b/packages/core/test/render3/control_flow_spec.ts index c401d42c9bccb..524d6a184ca48 100644 --- a/packages/core/test/render3/control_flow_spec.ts +++ b/packages/core/test/render3/control_flow_spec.ts @@ -10,7 +10,7 @@ import {ɵɵdefineComponent} from '../../src/render3/definition'; import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵselect, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; -import {ComponentFixture, TemplateFixture, createComponent} from './render_util'; +import {ComponentFixture, createComponent, TemplateFixture} from './render_util'; describe('JS control flow', () => { it('should work with if block', () => { @@ -151,9 +151,10 @@ describe('JS control flow', () => { }); it('should work with nested adjacent if blocks', () => { - const ctx: {condition: boolean, - condition2: boolean, - condition3: boolean} = {condition: true, condition2: false, condition3: true}; + const ctx: + {condition: boolean, + condition2: boolean, + condition3: boolean} = {condition: true, condition2: false, condition3: true}; /** * % if(ctx.condition) { @@ -165,7 +166,9 @@ describe('JS control flow', () => { * % } * % } */ - function createTemplate() { ɵɵcontainer(0); } + function createTemplate() { + ɵɵcontainer(0); + } function updateTemplate() { ɵɵcontainerRefreshStart(0); @@ -174,7 +177,9 @@ describe('JS control flow', () => { let rf1 = ɵɵembeddedViewStart(1, 2, 0); { if (rf1 & RenderFlags.Create) { - { ɵɵcontainer(0); } + { + ɵɵcontainer(0); + } { ɵɵcontainer(1); } } if (rf1 & RenderFlags.Update) { @@ -222,14 +227,14 @@ describe('JS control flow', () => { it('should work with adjacent if blocks managing views in the same container', () => { /** - * % if(ctx.condition1) { - * 1 - * % }; if(ctx.condition2) { - * 2 - * % }; if(ctx.condition3) { - * 3 - * % } - */ + * % if(ctx.condition1) { + * 1 + * % }; if(ctx.condition2) { + * 2 + * % }; if(ctx.condition3) { + * 3 + * % } + */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵcontainer(0); @@ -539,15 +544,15 @@ describe('JS control flow', () => { * <div> * Before * % for (let i = 0; i < cafes.length; i++) { - * <h2> {{ cafes[i].name }} </h2> - * % for (let j = 0; j < cafes[i].entrees.length; j++) { - * <h3> {{ cafes[i].entrees[j].name }} </h3> - * % for (let k = 0; k < cafes[i].entrees[j].foods.length; k++) { - * {{ cafes[i].entrees[j].foods[k] }} - * % } - * % } - * - - * % } + * <h2> {{ cafes[i].name }} </h2> + * % for (let j = 0; j < cafes[i].entrees.length; j++) { + * <h3> {{ cafes[i].entrees[j].name }} </h3> + * % for (let k = 0; k < cafes[i].entrees[j].foods.length; k++) { + * {{ cafes[i].entrees[j].foods[k] }} + * % } + * % } + * - + * % } * After * <div> */ @@ -718,37 +723,38 @@ describe('JS control flow', () => { selectors: [['app']], decls: 3, vars: 0, - template: function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div'); - ɵɵcontainer(1); - ɵɵcontainer(2); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(1); - { - if (ctx.condition) { - let rf1 = ɵɵembeddedViewStart(0, 1, 0); - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'comp'); - } - ɵɵembeddedViewEnd(); + template: + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div'); + ɵɵcontainer(1); + ɵɵcontainer(2); } - } - ɵɵcontainerRefreshEnd(); - ɵɵcontainerRefreshStart(2); - { - if (ctx.condition2) { - let rf1 = ɵɵembeddedViewStart(0, 1, 0); - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'comp'); + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(1); + { + if (ctx.condition) { + let rf1 = ɵɵembeddedViewStart(0, 1, 0); + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'comp'); + } + ɵɵembeddedViewEnd(); + } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); + ɵɵcontainerRefreshStart(2); + { + if (ctx.condition2) { + let rf1 = ɵɵembeddedViewStart(0, 1, 0); + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'comp'); + } + ɵɵembeddedViewEnd(); + } + } + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, + }, directives: () => [Comp] }); } @@ -788,37 +794,38 @@ describe('JS control flow', () => { selectors: [['app']], decls: 3, vars: 0, - template: function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div'); - ɵɵcontainer(1); - ɵɵcontainer(2); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(1); - { - if (ctx.condition) { - let rf1 = ɵɵembeddedViewStart(0, 1, 0); - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'comp'); - } - ɵɵembeddedViewEnd(); + template: + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div'); + ɵɵcontainer(1); + ɵɵcontainer(2); } - } - ɵɵcontainerRefreshEnd(); - ɵɵcontainerRefreshStart(2); - { - if (ctx.condition2) { - let rf1 = ɵɵembeddedViewStart(0, 1, 0); - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'comp'); + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(1); + { + if (ctx.condition) { + let rf1 = ɵɵembeddedViewStart(0, 1, 0); + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'comp'); + } + ɵɵembeddedViewEnd(); + } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); + ɵɵcontainerRefreshStart(2); + { + if (ctx.condition2) { + let rf1 = ɵɵembeddedViewStart(0, 1, 0); + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'comp'); + } + ɵɵembeddedViewEnd(); + } + } + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, + }, directives: () => [Comp] }); } @@ -902,7 +909,7 @@ describe('function calls', () => { it('should work', () => { let data: string[] = ['foo', 'bar']; - function spanify(rf: RenderFlags, ctx: {message: string | null}) { + function spanify(rf: RenderFlags, ctx: {message: string|null}) { const message = ctx.message; if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'span'); @@ -950,6 +957,5 @@ describe('function calls', () => { data = []; fixture.update(); expect(fixture.html).toEqual('<div>Before<span></span><span></span>After</div>'); - }); }); diff --git a/packages/core/test/render3/di_spec.ts b/packages/core/test/render3/di_spec.ts index 1bcd79c5a193d..8a6857622887a 100644 --- a/packages/core/test/render3/di_spec.ts +++ b/packages/core/test/render3/di_spec.ts @@ -11,7 +11,7 @@ import {createLView, createTView, getOrCreateTNode} from '@angular/core/src/rend import {RenderFlags} from '@angular/core/src/render3/interfaces/definition'; import {ɵɵdefineComponent} from '../../src/render3/definition'; -import {bloomAdd, bloomHasToken, bloomHashBitOrFactory as bloomHash, getOrCreateNodeInjectorForNode} from '../../src/render3/di'; +import {bloomAdd, bloomHashBitOrFactory as bloomHash, bloomHasToken, getOrCreateNodeInjectorForNode} from '../../src/render3/di'; import {ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵtext} from '../../src/render3/index'; import {TNODE} from '../../src/render3/interfaces/injector'; import {TNodeType} from '../../src/render3/interfaces/node'; @@ -24,7 +24,6 @@ import {ComponentFixture, createComponent, createDirective} from './render_util' describe('di', () => { describe('directive injection', () => { - class DirB { value = 'DirB'; @@ -34,10 +33,9 @@ describe('di', () => { } describe('flags', () => { - class DirB { // TODO(issue/24571): remove '!'. - value !: string; + value!: string; static ɵfac = () => new DirB(); static ɵdir = @@ -62,7 +60,6 @@ describe('di', () => { beforeEach(() => dirA = null); it('should not throw if dependency is @Optional (limp mode)', () => { - /** <div dirA></div> */ const App = createComponent('app', function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -70,8 +67,10 @@ describe('di', () => { } }, 1, 0, [DirA, DirB], [], undefined, [], [], undefined, [['dirA', '']]); - expect(() => { new ComponentFixture(App); }).not.toThrow(); - expect(dirA !.dirB).toEqual(null); + expect(() => { + new ComponentFixture(App); + }).not.toThrow(); + expect(dirA!.dirB).toEqual(null); }); }); @@ -123,11 +122,12 @@ describe('di', () => { selectors: [['my-comp']], decls: 1, vars: 0, - template: function(rf: RenderFlags, ctx: MyComp) { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'Foo'); - } - } + template: + function(rf: RenderFlags, ctx: MyComp) { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'Foo'); + } + } }); } @@ -137,8 +137,9 @@ describe('di', () => { expect(isProceduralRenderer(fixture.component.renderer)).toBeTruthy(); }); - it('should throw when injecting Renderer2 but the application is using Renderer3', - () => { expect(() => new ComponentFixture(MyComp)).toThrow(); }); + it('should throw when injecting Renderer2 but the application is using Renderer3', () => { + expect(() => new ComponentFixture(MyComp)).toThrow(); + }); }); describe('ɵɵinject', () => { @@ -148,7 +149,9 @@ describe('di', () => { mockTView = {data: [0, 0, 0, 0, 0, 0, 0, 0, null], firstCreatePass: true}; }); - function bloomState() { return mockTView.data.slice(0, TNODE).reverse(); } + function bloomState() { + return mockTView.data.slice(0, TNODE).reverse(); + } class Dir0 { /** @internal */ static __NG_ELEMENT_ID__ = 0; @@ -232,7 +235,7 @@ describe('di', () => { // Simulate the situation where the previous parent is not initialized. // This happens on first bootstrap because we don't init existing values // so that we have smaller HelloWorld. - (parentTNode as{parent: any}).parent = undefined; + (parentTNode as {parent: any}).parent = undefined; const injector = getOrCreateNodeInjectorForNode(parentTNode, contentView); expect(injector).not.toEqual(-1); @@ -241,5 +244,4 @@ describe('di', () => { } }); }); - }); diff --git a/packages/core/test/render3/i18n_spec.ts b/packages/core/test/render3/i18n_spec.ts index 0535ce454bec5..1a2cb3d2eda51 100644 --- a/packages/core/test/render3/i18n_spec.ts +++ b/packages/core/test/render3/i18n_spec.ts @@ -15,7 +15,9 @@ import {getNativeByIndex} from '../../src/render3/util/view_utils'; import {TemplateFixture} from './render_util'; describe('Runtime i18n', () => { - afterEach(() => { setDelayProjection(false); }); + afterEach(() => { + setDelayProjection(false); + }); describe('getTranslationForTemplate', () => { it('should crop messages for the selected template', () => { let message = `simple text`; @@ -69,10 +71,12 @@ describe('Runtime i18n', () => { const MSG_DIV = `simple text`; const nbConsts = 1; const index = 0; - const opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); // Check debug - const debugOps = (opCodes as any).create.debug !.operations; + const debugOps = (opCodes as any).create.debug!.operations; expect(debugOps[0].__raw_opCode).toBe('simple text'); expect(debugOps[0].type).toBe('Create Text Node'); expect(debugOps[0].nodeIndex).toBe(1); @@ -100,7 +104,9 @@ describe('Runtime i18n', () => { const index = 1; const elementIndex = 2; const elementIndex2 = 3; - const opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); expect(opCodes).toEqual({ vars: 5, @@ -136,7 +142,9 @@ describe('Runtime i18n', () => { const MSG_DIV = `Hello �0�!`; const nbConsts = 2; const index = 1; - const opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); expect((opCodes as any).update.debug.operations).toEqual([ {__raw_opCode: 8, checkBit: 1, type: 'Text', nodeIndex: 2, text: 'Hello �0�!'} @@ -161,7 +169,9 @@ describe('Runtime i18n', () => { const MSG_DIV = `Hello �0� and �1�, again �0�!`; const nbConsts = 2; const index = 1; - const opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); expect(opCodes).toEqual({ vars: 1, @@ -195,7 +205,9 @@ describe('Runtime i18n', () => { let index = 1; const firstTextNode = 3; const rootTemplate = 2; - let opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + let opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); expect(opCodes).toEqual({ vars: 2, @@ -225,7 +237,9 @@ describe('Runtime i18n', () => { index = 0; const spanElement = 1; const bElementSubTemplate = 2; - opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV, 1); }, null, nbConsts, index); + opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV, 1); + }, null, nbConsts, index); expect(opCodes).toEqual({ vars: 2, @@ -252,7 +266,9 @@ describe('Runtime i18n', () => { nbConsts = 2; index = 0; const bElement = 1; - opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV, 2); }, null, nbConsts, index); + opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV, 2); + }, null, nbConsts, index); expect(opCodes).toEqual({ vars: 1, @@ -277,7 +293,9 @@ describe('Runtime i18n', () => { }`; const nbConsts = 1; const index = 0; - const opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); const tIcuIndex = 0; const icuCommentNodeIndex = index + 1; const firstTextNodeIndex = index + 2; @@ -465,7 +483,9 @@ describe('Runtime i18n', () => { }`; const nbConsts = 1; const index = 0; - const opCodes = getOpCodes(() => { ɵɵi18nStart(index, MSG_DIV); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nStart(index, MSG_DIV); + }, null, nbConsts, index); const icuCommentNodeIndex = index + 1; const firstTextNodeIndex = index + 2; const nestedIcuCommentNodeIndex = index + 3; @@ -497,18 +517,18 @@ describe('Runtime i18n', () => { cases: ['cat', 'dog', 'other'], create: [ [ - 'cats', nestedTextNodeIndex, nestedIcuCommentNodeIndex - << I18nMutateOpCode.SHIFT_PARENT | + 'cats', nestedTextNodeIndex, + nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], [ - 'dogs', nestedTextNodeIndex, nestedIcuCommentNodeIndex - << I18nMutateOpCode.SHIFT_PARENT | + 'dogs', nestedTextNodeIndex, + nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ], [ - 'animals', nestedTextNodeIndex, nestedIcuCommentNodeIndex - << I18nMutateOpCode.SHIFT_PARENT | + 'animals', nestedTextNodeIndex, + nestedIcuCommentNodeIndex << I18nMutateOpCode.SHIFT_PARENT | I18nMutateOpCode.AppendChild ] ], @@ -599,8 +619,9 @@ describe('Runtime i18n', () => { const MSG_div_attr = ['title', MSG_title]; const nbConsts = 2; const index = 1; - const opCodes = - getOpCodes(() => { ɵɵi18nAttributes(index, MSG_div_attr); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nAttributes(index, MSG_div_attr); + }, null, nbConsts, index); expect(opCodes).toEqual([ 0b1, // bindings mask @@ -616,8 +637,9 @@ describe('Runtime i18n', () => { const MSG_div_attr = ['title', MSG_title]; const nbConsts = 2; const index = 1; - const opCodes = - getOpCodes(() => { ɵɵi18nAttributes(index, MSG_div_attr); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nAttributes(index, MSG_div_attr); + }, null, nbConsts, index); expect(opCodes).toEqual([ 0b11, // bindings mask @@ -632,8 +654,9 @@ describe('Runtime i18n', () => { const MSG_div_attr = ['title', MSG_title, 'aria-label', MSG_title]; const nbConsts = 2; const index = 1; - const opCodes = - getOpCodes(() => { ɵɵi18nAttributes(index, MSG_div_attr); }, null, nbConsts, index); + const opCodes = getOpCodes(() => { + ɵɵi18nAttributes(index, MSG_div_attr); + }, null, nbConsts, index); expect(opCodes).toEqual([ 0b1, // bindings mask diff --git a/packages/core/test/render3/imported_renderer2.ts b/packages/core/test/render3/imported_renderer2.ts index 07978d744629a..88d224e9deac4 100644 --- a/packages/core/test/render3/imported_renderer2.ts +++ b/packages/core/test/render3/imported_renderer2.ts @@ -17,9 +17,13 @@ import {EventManagerPlugin} from '@angular/platform-browser/src/dom/events/event import {isTextNode} from '@angular/platform-browser/testing/src/browser_util'; export class SimpleDomEventsPlugin extends EventManagerPlugin { - constructor(doc: any) { super(doc); } + constructor(doc: any) { + super(doc); + } - supports(eventName: string): boolean { return true; } + supports(eventName: string): boolean { + return true; + } addEventListener(element: HTMLElement, eventName: string, handler: Function): Function { let callback: EventListener = handler as EventListener; diff --git a/packages/core/test/render3/instructions/lview_debug_spec.ts b/packages/core/test/render3/instructions/lview_debug_spec.ts index 28d51c3002516..55f9d63a45ea6 100644 --- a/packages/core/test/render3/instructions/lview_debug_spec.ts +++ b/packages/core/test/render3/instructions/lview_debug_spec.ts @@ -21,13 +21,13 @@ describe('lView_debug', () => { afterEach(() => leaveView()); describe('TNode', () => { - let tNode !: TNodeDebug; - let tView !: TView; + let tNode!: TNodeDebug; + let tView!: TView; beforeEach(() => { tView = createTView(TViewType.Component, 0, null, 0, 0, null, null, null, null, null); - tNode = createTNode(tView, null !, TNodeType.Element, 0, '', null) as TNodeDebug; + tNode = createTNode(tView, null!, TNodeType.Element, 0, '', null) as TNodeDebug; }); - afterEach(() => tNode = tView = null !); + afterEach(() => tNode = tView = null!); describe('styling', () => { it('should decode no styling', () => { diff --git a/packages/core/test/render3/instructions/shared_spec.ts b/packages/core/test/render3/instructions/shared_spec.ts index 1649d8dfe8c6f..73c1e61e321d5 100644 --- a/packages/core/test/render3/instructions/shared_spec.ts +++ b/packages/core/test/render3/instructions/shared_spec.ts @@ -39,7 +39,7 @@ export function enterViewWithOneDiv() { TViewType.Component, -1, emptyTemplate, consts, vars, null, null, null, null, null); // Just assume that the expando starts after 10 initial bindings. tView.expandoStartIndex = HEADER_OFFSET + 10; - const tNode = tView.firstChild = createTNode(tView, null !, TNodeType.Element, 0, 'div', null); + const tNode = tView.firstChild = createTNode(tView, null!, TNodeType.Element, 0, 'div', null); const lView = createLView( null, tView, null, LViewFlags.CheckAlways, null, null, domRendererFactory3, renderer, null, null); diff --git a/packages/core/test/render3/instructions/styling_spec.ts b/packages/core/test/render3/instructions/styling_spec.ts index 22a09c4e68163..8751b15bff1d1 100644 --- a/packages/core/test/render3/instructions/styling_spec.ts +++ b/packages/core/test/render3/instructions/styling_spec.ts @@ -1,16 +1,16 @@ /** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {DirectiveDef} from '@angular/core/src/render3'; import {ɵɵdefineDirective} from '@angular/core/src/render3/definition'; import {classStringParser, styleStringParser, toStylingKeyValueArray, ɵɵclassProp, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer} from '@angular/core/src/render3/instructions/styling'; import {AttributeMarker, TAttributes} from '@angular/core/src/render3/interfaces/node'; -import {StylingRange, TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, setTStylingRangeNext, setTStylingRangePrev, toTStylingRange} from '@angular/core/src/render3/interfaces/styling'; +import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, setTStylingRangeNext, setTStylingRangePrev, StylingRange, toTStylingRange, TStylingKey, TStylingRange} from '@angular/core/src/render3/interfaces/styling'; import {HEADER_OFFSET, TVIEW} from '@angular/core/src/render3/interfaces/view'; import {getLView, leaveView, setBindingRootForHostBindings} from '@angular/core/src/render3/state'; import {getNativeByIndex} from '@angular/core/src/render3/util/view_utils'; @@ -27,7 +27,7 @@ describe('styling', () => { beforeEach(enterViewWithOneDiv); afterEach(leaveView); - let div !: HTMLElement; + let div!: HTMLElement; beforeEach(() => div = getNativeByIndex(0, getLView()) as HTMLElement); it('should do set basic style', () => { @@ -68,7 +68,7 @@ describe('styling', () => { ɵɵstyleProp('color', 'blue'); // Higher priority, should win. expectStyle(div).toEqual({color: 'blue'}); // The intermediate value has to set since it does not know if it is last one. - expect(ngDevMode !.rendererSetStyle).toEqual(2); + expect(ngDevMode!.rendererSetStyle).toEqual(2); ngDevModeResetPerfCounters(); clearFirstUpdatePass(); @@ -76,34 +76,34 @@ describe('styling', () => { ɵɵstyleProp('color', 'red'); // no change ɵɵstyleProp('color', 'green'); // change to green expectStyle(div).toEqual({color: 'green'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererSetStyle).toEqual(1); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleProp('color', 'black'); // First binding update expectStyle(div).toEqual({color: 'green'}); // Green still has priority. - expect(ngDevMode !.rendererSetStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(0); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleProp('color', 'black'); // no change ɵɵstyleProp('color', undefined); // Clear second binding expectStyle(div).toEqual({color: 'black'}); // default to first binding - expect(ngDevMode !.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererSetStyle).toEqual(1); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleProp('color', null); expectStyle(div).toEqual({}); // default to first binding - expect(ngDevMode !.rendererSetStyle).toEqual(0); - expect(ngDevMode !.rendererRemoveStyle).toEqual(1); + expect(ngDevMode!.rendererSetStyle).toEqual(0); + expect(ngDevMode!.rendererRemoveStyle).toEqual(1); }); it('should set class based on priority', () => { ɵɵclassProp('foo', false); ɵɵclassProp('foo', true); // Higher priority, should win. expectClass(div).toEqual({foo: true}); - expect(ngDevMode !.rendererAddClass).toEqual(1); + expect(ngDevMode!.rendererAddClass).toEqual(1); ngDevModeResetPerfCounters(); clearFirstUpdatePass(); @@ -111,8 +111,8 @@ describe('styling', () => { ɵɵclassProp('foo', false); // no change ɵɵclassProp('foo', undefined); // change (have no opinion) expectClass(div).toEqual({}); - expect(ngDevMode !.rendererAddClass).toEqual(0); - expect(ngDevMode !.rendererRemoveClass).toEqual(1); + expect(ngDevMode!.rendererAddClass).toEqual(0); + expect(ngDevMode!.rendererRemoveClass).toEqual(1); ngDevModeResetPerfCounters(); rewindBindingIndex(); @@ -130,8 +130,8 @@ describe('styling', () => { it('should work with maps', () => { ɵɵstyleMap({}); expectStyle(div).toEqual({}); - expect(ngDevMode !.rendererSetStyle).toEqual(0); - expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(0); + expect(ngDevMode!.rendererRemoveStyle).toEqual(0); ngDevModeResetPerfCounters(); clearFirstUpdatePass(); @@ -139,30 +139,30 @@ describe('styling', () => { rewindBindingIndex(); ɵɵstyleMap({color: 'blue'}); expectStyle(div).toEqual({color: 'blue'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); - expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererRemoveStyle).toEqual(0); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleMap({color: 'red'}); expectStyle(div).toEqual({color: 'red'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); - expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererRemoveStyle).toEqual(0); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleMap({color: null, width: '100px'}); expectStyle(div).toEqual({width: '100px'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); - expect(ngDevMode !.rendererRemoveStyle).toEqual(1); + expect(ngDevMode!.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererRemoveStyle).toEqual(1); ngDevModeResetPerfCounters(); }); it('should work with object literal and strings', () => { ɵɵstyleMap(''); expectStyle(div).toEqual({}); - expect(ngDevMode !.rendererSetStyle).toEqual(0); - expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(0); + expect(ngDevMode!.rendererRemoveStyle).toEqual(0); ngDevModeResetPerfCounters(); clearFirstUpdatePass(); @@ -170,22 +170,22 @@ describe('styling', () => { rewindBindingIndex(); ɵɵstyleMap('color: blue'); expectStyle(div).toEqual({color: 'blue'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); - expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererRemoveStyle).toEqual(0); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleMap('color: red'); expectStyle(div).toEqual({color: 'red'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); - expect(ngDevMode !.rendererRemoveStyle).toEqual(0); + expect(ngDevMode!.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererRemoveStyle).toEqual(0); ngDevModeResetPerfCounters(); rewindBindingIndex(); ɵɵstyleMap('width: 100px'); expectStyle(div).toEqual({width: '100px'}); - expect(ngDevMode !.rendererSetStyle).toEqual(1); - expect(ngDevMode !.rendererRemoveStyle).toEqual(1); + expect(ngDevMode!.rendererSetStyle).toEqual(1); + expect(ngDevMode!.rendererRemoveStyle).toEqual(1); ngDevModeResetPerfCounters(); }); @@ -395,7 +395,6 @@ describe('styling', () => { ['color', 'red', 'content', '"TEMPLATE"'] ]); expectStyle(div).toEqual({content: '"TEMPLATE"', color: 'red', width: '100px'}); - }); }); }); @@ -404,23 +403,23 @@ describe('styling', () => { describe('toStylingArray', () => { describe('falsy', () => { it('should return empty KeyValueArray', () => { - expect(toStylingKeyValueArray(keyValueArraySet, null !, '')).toEqual([] as any); - expect(toStylingKeyValueArray(keyValueArraySet, null !, null)).toEqual([] as any); - expect(toStylingKeyValueArray(keyValueArraySet, null !, undefined)).toEqual([] as any); - expect(toStylingKeyValueArray(keyValueArraySet, null !, [])).toEqual([] as any); - expect(toStylingKeyValueArray(keyValueArraySet, null !, {})).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null!, '')).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null!, null)).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null!, undefined)).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null!, [])).toEqual([] as any); + expect(toStylingKeyValueArray(keyValueArraySet, null!, {})).toEqual([] as any); }); describe('string', () => { it('should parse classes', () => { - expect(toStylingKeyValueArray(keyValueArraySet, classStringParser, ' ')).toEqual([ - ] as any); + expect(toStylingKeyValueArray(keyValueArraySet, classStringParser, ' ')) + .toEqual([] as any); expect(toStylingKeyValueArray(keyValueArraySet, classStringParser, ' X A ')).toEqual([ 'A', true, 'X', true ] as any); }); it('should parse styles', () => { - expect(toStylingKeyValueArray(keyValueArraySet, styleStringParser, ' ')).toEqual([ - ] as any); + expect(toStylingKeyValueArray(keyValueArraySet, styleStringParser, ' ')) + .toEqual([] as any); expect(toStylingKeyValueArray(keyValueArraySet, styleStringParser, 'B:b;A:a')).toEqual([ 'A', 'a', 'B', 'b' ] as any); @@ -428,14 +427,14 @@ describe('styling', () => { }); describe('array', () => { it('should parse', () => { - expect(toStylingKeyValueArray(keyValueArraySet, null !, ['X', 'A'])).toEqual([ + expect(toStylingKeyValueArray(keyValueArraySet, null!, ['X', 'A'])).toEqual([ 'A', true, 'X', true ] as any); }); }); describe('object', () => { it('should parse', () => { - expect(toStylingKeyValueArray(keyValueArraySet, null !, {X: 'x', A: 'a'})).toEqual([ + expect(toStylingKeyValueArray(keyValueArraySet, null!, {X: 'x', A: 'a'})).toEqual([ 'A', 'a', 'X', 'x' ] as any); }); @@ -495,7 +494,7 @@ function givenTemplateAttrs(tAttrs: TAttributes) { } function getTNode() { - return getLView()[TVIEW].firstChild !; + return getLView()[TVIEW].firstChild!; } function getTData() { @@ -517,7 +516,7 @@ function givenDirectiveAttrs(tAttrs: TAttributes[]) { } } -function applyTAttributes(attrs: TAttributes | null) { +function applyTAttributes(attrs: TAttributes|null) { if (attrs === null) return; const div: HTMLElement = getLView()[HEADER_OFFSET]; let mode: AttributeMarker = AttributeMarker.ImplicitAttributes; @@ -553,12 +552,12 @@ function getTDataIndexFromDirectiveIndex(index: number) { return HEADER_OFFSET + index + 10; // offset to give template bindings space. } -function expectTStylingKeys(styling: 'style' | 'class') { +function expectTStylingKeys(styling: 'style'|'class') { const tNode = getTNode(); const tData = getTData(); const isClassBased = styling === 'class'; const headIndex = getTStylingRangePrev(isClassBased ? tNode.classBindings : tNode.styleBindings); - const tStylingKeys: (string | (null | string)[] | null)[] = []; + const tStylingKeys: (string|(null | string)[]|null)[] = []; let index = headIndex; let prevIndex = index; // rewind to beginning of list. diff --git a/packages/core/test/render3/instructions_spec.ts b/packages/core/test/render3/instructions_spec.ts index 09139881ad48c..3f90a06cda9e9 100644 --- a/packages/core/test/render3/instructions_spec.ts +++ b/packages/core/test/render3/instructions_spec.ts @@ -12,7 +12,7 @@ import {getSortedClassName} from '@angular/core/testing/src/styling'; import {ɵɵdefineComponent} from '../../src/render3/definition'; import {RenderFlags, ɵɵattribute, ɵɵclassMap, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵproperty, ɵɵselect, ɵɵstyleMap, ɵɵstyleProp, ɵɵstyleSanitizer, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate1} from '../../src/render3/index'; import {AttributeMarker} from '../../src/render3/interfaces/node'; -import {SafeValue, bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, unwrapSafeValue} from '../../src/sanitization/bypass'; +import {bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, getSanitizationBypassType, SafeValue, unwrapSafeValue} from '../../src/sanitization/bypass'; import {ɵɵdefaultStyleSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl} from '../../src/sanitization/sanitization'; import {Sanitizer} from '../../src/sanitization/sanitizer'; import {SecurityContext} from '../../src/sanitization/security'; @@ -21,18 +21,32 @@ import {NgForOf} from './common_with_def'; import {ComponentFixture, TemplateFixture} from './render_util'; describe('instructions', () => { - function createAnchor() { ɵɵelement(0, 'a'); } + function createAnchor() { + ɵɵelement(0, 'a'); + } - function createDiv() { ɵɵelement(0, 'div', 0); } + function createDiv() { + ɵɵelement(0, 'div', 0); + } - function createScript() { ɵɵelement(0, 'script'); } + function createScript() { + ɵɵelement(0, 'script'); + } describe('ɵɵselect', () => { it('should error in DevMode if index is out of range', () => { // Only one constant added, meaning only index `0` is valid. const t = new TemplateFixture(createDiv, () => {}, 1, 0); - expect(() => { t.update(() => { ɵɵselect(-1); }); }).toThrow(); - expect(() => { t.update(() => { ɵɵselect(1); }); }).toThrow(); + expect(() => { + t.update(() => { + ɵɵselect(-1); + }); + }).toThrow(); + expect(() => { + t.update(() => { + ɵɵselect(1); + }); + }).toThrow(); }); }); @@ -40,10 +54,14 @@ describe('instructions', () => { it('should update bindings when value changes with the correct perf counters', () => { const t = new TemplateFixture(createAnchor, () => {}, 1, 1); - t.update(() => { ɵɵproperty('title', 'Hello'); }); + t.update(() => { + ɵɵproperty('title', 'Hello'); + }); expect(t.html).toEqual('<a title="Hello"></a>'); - t.update(() => { ɵɵproperty('title', 'World'); }); + t.update(() => { + ɵɵproperty('title', 'World'); + }); expect(t.html).toEqual('<a title="World"></a>'); expect(ngDevMode).toHaveProperties({ firstCreatePass: 1, @@ -56,7 +74,9 @@ describe('instructions', () => { it('should not update bindings when value does not change, with the correct perf counters', () => { - const idempotentUpdate = () => { ɵɵproperty('title', 'Hello'); }; + const idempotentUpdate = () => { + ɵɵproperty('title', 'Hello'); + }; const t = new TemplateFixture(createAnchor, idempotentUpdate, 1, 1); t.update(); @@ -80,7 +100,7 @@ describe('instructions', () => { ɵɵelement(0, 'div', 0); }, () => {}, 1, 0, null, null, null, undefined, [['id', 'test', 'title', 'Hello']]); - const div = (t.hostElement as HTMLElement).querySelector('div') !; + const div = (t.hostElement as HTMLElement).querySelector('div')!; expect(div.id).toEqual('test'); expect(div.title).toEqual('Hello'); expect(ngDevMode).toHaveProperties({ @@ -96,7 +116,9 @@ describe('instructions', () => { it('should use sanitizer function', () => { const t = new TemplateFixture(createDiv, () => {}, 1, 1); - t.update(() => { ɵɵattribute('title', 'javascript:true', ɵɵsanitizeUrl); }); + t.update(() => { + ɵɵattribute('title', 'javascript:true', ɵɵsanitizeUrl); + }); expect(t.html).toEqual('<div title="unsafe:javascript:true"></div>'); t.update(() => { @@ -122,9 +144,13 @@ describe('instructions', () => { it('should chain', () => { // <div [title]="title" [accesskey]="key"></div> const t = new TemplateFixture(createDiv, () => {}, 1, 2); - t.update(() => { ɵɵproperty('title', 'one')('accessKey', 'A'); }); + t.update(() => { + ɵɵproperty('title', 'one')('accessKey', 'A'); + }); expect(t.html).toEqual('<div accesskey="A" title="one"></div>'); - t.update(() => { ɵɵproperty('title', 'two')('accessKey', 'B'); }); + t.update(() => { + ɵɵproperty('title', 'two')('accessKey', 'B'); + }); expect(t.html).toEqual('<div accesskey="B" title="two"></div>'); expect(ngDevMode).toHaveProperties({ firstCreatePass: 1, @@ -140,7 +166,9 @@ describe('instructions', () => { it('should automatically sanitize unless a bypass operation is applied', () => { let backgroundImage: string|SafeValue = 'url("http://server")'; const t = new TemplateFixture( - () => { return createDiv(); }, + () => { + return createDiv(); + }, () => { ɵɵstyleSanitizer(ɵɵdefaultStyleSanitizer); ɵɵstyleProp('background-image', backgroundImage); @@ -160,7 +188,9 @@ describe('instructions', () => { describe('styleMap', () => { const attrs = [[AttributeMarker.Styles, 'height', '10px']]; - function createDivWithStyle() { ɵɵelement(0, 'div', 0); } + function createDivWithStyle() { + ɵɵelement(0, 'div', 0); + } it('should add style', () => { const fixture = new TemplateFixture(createDivWithStyle, () => { @@ -172,10 +202,13 @@ describe('instructions', () => { it('should sanitize new styles that may contain `url` properties', () => { const detectedValues: string[] = []; - const sanitizerInterceptor = - new MockSanitizerInterceptor(value => { detectedValues.push(value); }); + const sanitizerInterceptor = new MockSanitizerInterceptor(value => { + detectedValues.push(value); + }); const fixture = new TemplateFixture( - () => { return createDiv(); }, // + () => { + return createDiv(); + }, // () => { ɵɵstyleSanitizer(sanitizerInterceptor.getStyleSanitizer()); ɵɵstyleMap({ @@ -198,12 +231,15 @@ describe('instructions', () => { }); describe('elementClass', () => { - function createDivWithStyling() { ɵɵelement(0, 'div'); } + function createDivWithStyling() { + ɵɵelement(0, 'div'); + } it('should add class', () => { - const fixture = new TemplateFixture( - createDivWithStyling, () => { ɵɵclassMap('multiple classes'); }, 1, 2); - const div = fixture.containerElement.querySelector('div.multiple') !; + const fixture = new TemplateFixture(createDivWithStyling, () => { + ɵɵclassMap('multiple classes'); + }, 1, 2); + const div = fixture.containerElement.querySelector('div.multiple')!; expect(getSortedClassName(div)).toEqual('classes multiple'); }); }); @@ -246,21 +282,24 @@ describe('instructions', () => { class NestedLoops { rows = [['a', 'b'], ['A', 'B'], ['a', 'b'], ['A', 'B']]; - static ɵfac = function ToDoAppComponent_Factory() { return new NestedLoops(); }; + static ɵfac = function ToDoAppComponent_Factory() { + return new NestedLoops(); + }; static ɵcmp = ɵɵdefineComponent({ type: NestedLoops, selectors: [['nested-loops']], decls: 1, vars: 1, consts: [[AttributeMarker.Template, 'ngFor', 'ngForOf']], - template: function ToDoAppComponent_Template(rf: RenderFlags, ctx: NestedLoops) { - if (rf & RenderFlags.Create) { - ɵɵtemplate(0, ToDoAppComponent_NgForOf_Template_0, 2, 1, 'ul', 0); - } - if (rf & RenderFlags.Update) { - ɵɵproperty('ngForOf', ctx.rows); - } - }, + template: + function ToDoAppComponent_Template(rf: RenderFlags, ctx: NestedLoops) { + if (rf & RenderFlags.Create) { + ɵɵtemplate(0, ToDoAppComponent_NgForOf_Template_0, 2, 1, 'ul', 0); + } + if (rf & RenderFlags.Update) { + ɵɵproperty('ngForOf', ctx.rows); + } + }, directives: [NgForOf] }); } @@ -269,7 +308,6 @@ describe('instructions', () => { // Expect: fixture view/Host view + component + ngForRow + ngForCol tView: 4, // should be: 4, }); - }); }); @@ -280,7 +318,9 @@ describe('instructions', () => { const inputValue = 'http://foo'; const outputValue = 'http://foo-sanitized'; - t.update(() => { ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); }); + t.update(() => { + ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); + }); expect(t.html).toEqual(`<a href="${outputValue}"></a>`); expect(s.lastSanitizedValue).toEqual(outputValue); }); @@ -291,7 +331,9 @@ describe('instructions', () => { const inputValue = s.bypassSecurityTrustUrl('http://foo'); const outputValue = 'http://foo'; - t.update(() => { ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); }); + t.update(() => { + ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); + }); expect(t.html).toEqual(`<a href="${outputValue}"></a>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -302,7 +344,9 @@ describe('instructions', () => { const inputValue = bypassSanitizationTrustUrl('http://foo'); const outputValue = 'http://foo-ivy'; - t.update(() => { ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); }); + t.update(() => { + ɵɵattribute('href', inputValue, ɵɵsanitizeUrl); + }); expect(t.html).toEqual(`<a href="${outputValue}"></a>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -313,7 +357,9 @@ describe('instructions', () => { const inputValue = 'color:red'; const outputValue = 'color:blue'; - t.update(() => { ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); }); + t.update(() => { + ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); + }); expect(stripStyleWsCharacters(t.html)).toEqual(`<div style="${outputValue}"></div>`); expect(s.lastSanitizedValue).toEqual(outputValue); }); @@ -324,7 +370,9 @@ describe('instructions', () => { const inputValue = s.bypassSecurityTrustStyle('color:maroon'); const outputValue = 'color:maroon'; - t.update(() => { ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); }); + t.update(() => { + ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); + }); expect(stripStyleWsCharacters(t.html)).toEqual(`<div style="${outputValue}"></div>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -335,7 +383,9 @@ describe('instructions', () => { const inputValue = bypassSanitizationTrustStyle('font-family:foo'); const outputValue = 'font-family:foo-ivy'; - t.update(() => { ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); }); + t.update(() => { + ɵɵattribute('style', inputValue, ɵɵsanitizeStyle); + }); expect(stripStyleWsCharacters(t.html)).toEqual(`<div style="${outputValue}"></div>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -346,7 +396,9 @@ describe('instructions', () => { const inputValue = 'http://resource'; const outputValue = 'http://resource-sanitized'; - t.update(() => { ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); }); + t.update(() => { + ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); + }); expect(t.html).toEqual(`<script src="${outputValue}"></script>`); expect(s.lastSanitizedValue).toEqual(outputValue); }); @@ -357,7 +409,9 @@ describe('instructions', () => { const inputValue = s.bypassSecurityTrustResourceUrl('file://all-my-secrets.pdf'); const outputValue = 'file://all-my-secrets.pdf'; - t.update(() => { ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); }); + t.update(() => { + ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); + }); expect(t.html).toEqual(`<script src="${outputValue}"></script>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -368,7 +422,9 @@ describe('instructions', () => { const inputValue = bypassSanitizationTrustResourceUrl('file://all-my-secrets.pdf'); const outputValue = 'file://all-my-secrets.pdf-ivy'; - t.update(() => { ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); }); + t.update(() => { + ɵɵattribute('src', inputValue, ɵɵsanitizeResourceUrl); + }); expect(t.html).toEqual(`<script src="${outputValue}"></script>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -379,7 +435,9 @@ describe('instructions', () => { const inputValue = 'fn();'; const outputValue = 'fn(); //sanitized'; - t.update(() => { ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript); }); + t.update(() => { + ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript); + }); expect(t.html).toEqual(`<script>${outputValue}</script>`); expect(s.lastSanitizedValue).toEqual(outputValue); }); @@ -390,7 +448,9 @@ describe('instructions', () => { const inputValue = s.bypassSecurityTrustScript('alert("bar")'); const outputValue = 'alert("bar")'; - t.update(() => { ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript); }); + t.update(() => { + ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript); + }); expect(t.html).toEqual(`<script>${outputValue}</script>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -401,7 +461,9 @@ describe('instructions', () => { const inputValue = bypassSanitizationTrustScript('alert("bar")'); const outputValue = 'alert("bar")-ivy'; - t.update(() => { ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript); }); + t.update(() => { + ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeScript); + }); expect(t.html).toEqual(`<script>${outputValue}</script>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -412,7 +474,9 @@ describe('instructions', () => { const inputValue = '<header></header>'; const outputValue = '<header></header> <!--sanitized-->'; - t.update(() => { ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml); }); + t.update(() => { + ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml); + }); expect(t.html).toEqual(`<div>${outputValue}</div>`); expect(s.lastSanitizedValue).toEqual(outputValue); }); @@ -423,7 +487,9 @@ describe('instructions', () => { const inputValue = s.bypassSecurityTrustHtml('<div onclick="alert(123)"></div>'); const outputValue = '<div onclick="alert(123)"></div>'; - t.update(() => { ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml); }); + t.update(() => { + ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml); + }); expect(t.html).toEqual(`<div>${outputValue}</div>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -434,7 +500,9 @@ describe('instructions', () => { const inputValue = bypassSanitizationTrustHtml('<div onclick="alert(123)"></div>'); const outputValue = '<div onclick="alert(123)"></div>-ivy'; - t.update(() => { ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml); }); + t.update(() => { + ɵɵproperty('innerHTML', inputValue, ɵɵsanitizeHtml); + }); expect(t.html).toEqual(`<div>${outputValue}</div>`); expect(s.lastSanitizedValue).toBeFalsy(); }); @@ -444,12 +512,14 @@ describe('instructions', () => { class LocalSanitizedValue { constructor(public value: any) {} - toString() { return this.value; } + toString() { + return this.value; + } } class LocalMockSanitizer implements Sanitizer { // TODO(issue/24571): remove '!'. - public lastSanitizedValue !: string | null; + public lastSanitizedValue!: string|null; constructor(private _interceptor: (value: string|null|any) => string) {} @@ -465,21 +535,33 @@ class LocalMockSanitizer implements Sanitizer { return this.lastSanitizedValue = this._interceptor(value); } - bypassSecurityTrustHtml(value: string) { return new LocalSanitizedValue(value); } + bypassSecurityTrustHtml(value: string) { + return new LocalSanitizedValue(value); + } - bypassSecurityTrustStyle(value: string) { return new LocalSanitizedValue(value); } + bypassSecurityTrustStyle(value: string) { + return new LocalSanitizedValue(value); + } - bypassSecurityTrustScript(value: string) { return new LocalSanitizedValue(value); } + bypassSecurityTrustScript(value: string) { + return new LocalSanitizedValue(value); + } - bypassSecurityTrustUrl(value: string) { return new LocalSanitizedValue(value); } + bypassSecurityTrustUrl(value: string) { + return new LocalSanitizedValue(value); + } - bypassSecurityTrustResourceUrl(value: string) { return new LocalSanitizedValue(value); } + bypassSecurityTrustResourceUrl(value: string) { + return new LocalSanitizedValue(value); + } } class MockSanitizerInterceptor { public lastValue: string|null = null; constructor(private _interceptorFn?: ((value: any) => any)|null) {} - getStyleSanitizer() { return ɵɵdefaultStyleSanitizer; } + getStyleSanitizer() { + return ɵɵdefaultStyleSanitizer; + } sanitize(context: SecurityContext, value: LocalSanitizedValue|string|null|any): string|null { if (this._interceptorFn) { this._interceptorFn(value); diff --git a/packages/core/test/render3/integration_spec.ts b/packages/core/test/render3/integration_spec.ts index cba57eb192ab1..055c91a2496cd 100644 --- a/packages/core/test/render3/integration_spec.ts +++ b/packages/core/test/render3/integration_spec.ts @@ -12,7 +12,7 @@ import {AttributeMarker, ɵɵadvance, ɵɵattribute, ɵɵdefineComponent, ɵɵde import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵprojection, ɵɵprojectionDef, ɵɵtemplate, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; import {MONKEY_PATCH_KEY_NAME} from '../../src/render3/interfaces/context'; import {RenderFlags} from '../../src/render3/interfaces/definition'; -import {RElement, Renderer3, RendererFactory3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; +import {domRendererFactory3, RElement, Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer'; import {CONTEXT, HEADER_OFFSET} from '../../src/render3/interfaces/view'; import {ɵɵsanitizeUrl} from '../../src/sanitization/sanitization'; import {Sanitizer} from '../../src/sanitization/sanitizer'; @@ -22,7 +22,6 @@ import {NgIf} from './common_with_def'; import {ComponentFixture, MockRendererFactory, renderToHtml} from './render_util'; describe('render3 integration test', () => { - describe('render', () => { describe('text bindings', () => { it('should support creation-time values in text nodes', () => { @@ -56,7 +55,7 @@ describe('render3 integration test', () => { afterTree: Tree; } - function showLabel(rf: RenderFlags, ctx: {label: string | undefined}) { + function showLabel(rf: RenderFlags, ctx: {label: string|undefined}) { if (rf & RenderFlags.Create) { ɵɵcontainer(0); } @@ -113,9 +112,9 @@ describe('render3 integration test', () => { class ChildComponent { // TODO(issue/24571): remove '!'. - beforeTree !: Tree; + beforeTree!: Tree; // TODO(issue/24571): remove '!'. - afterTree !: Tree; + afterTree!: Tree; static ɵfac = () => new ChildComponent; static ɵcmp = ɵɵdefineComponent({ @@ -123,31 +122,32 @@ describe('render3 integration test', () => { type: ChildComponent, decls: 3, vars: 0, - template: function ChildComponentTemplate( - rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵcontainer(0); - ɵɵprojection(1); - ɵɵcontainer(2); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(0); - { - const rf0 = ɵɵembeddedViewStart(0, 3, 0); - { showTree(rf0, {tree: ctx.beforeTree}); } - ɵɵembeddedViewEnd(); - } - ɵɵcontainerRefreshEnd(); - ɵɵcontainerRefreshStart(2); - { - const rf0 = ɵɵembeddedViewStart(0, 3, 0); - { showTree(rf0, {tree: ctx.afterTree}); } - ɵɵembeddedViewEnd(); - } - ɵɵcontainerRefreshEnd(); - } - }, + template: + function ChildComponentTemplate( + rf: RenderFlags, ctx: {beforeTree: Tree, afterTree: Tree}) { + if (rf & RenderFlags.Create) { + ɵɵprojectionDef(); + ɵɵcontainer(0); + ɵɵprojection(1); + ɵɵcontainer(2); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(0); + { + const rf0 = ɵɵembeddedViewStart(0, 3, 0); + { showTree(rf0, {tree: ctx.beforeTree}); } + ɵɵembeddedViewEnd(); + } + ɵɵcontainerRefreshEnd(); + ɵɵcontainerRefreshStart(2); + { + const rf0 = ɵɵembeddedViewStart(0, 3, 0); + { showTree(rf0, {tree: ctx.afterTree}); } + ɵɵembeddedViewEnd(); + } + ɵɵcontainerRefreshEnd(); + } + }, inputs: {beforeTree: 'beforeTree', afterTree: 'afterTree'} }); } @@ -172,7 +172,6 @@ describe('render3 integration test', () => { } it('should work with a tree', () => { - const ctx: ParentCtx = { beforeTree: {subTrees: [{beforeLabel: 'a'}]}, projectedTree: {beforeLabel: 'p'}, @@ -181,19 +180,17 @@ describe('render3 integration test', () => { const defs = [ChildComponent]; expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>apz</child>'); ctx.projectedTree = {subTrees: [{}, {}, {subTrees: [{}, {}]}, {}]}; - ctx.beforeTree.subTrees !.push({afterLabel: 'b'}); + ctx.beforeTree.subTrees!.push({afterLabel: 'b'}); expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>abz</child>'); - ctx.projectedTree.subTrees ![1].afterLabel = 'h'; + ctx.projectedTree.subTrees![1].afterLabel = 'h'; expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>abhz</child>'); - ctx.beforeTree.subTrees !.push({beforeLabel: 'c'}); + ctx.beforeTree.subTrees!.push({beforeLabel: 'c'}); expect(renderToHtml(parentTemplate, ctx, 2, 2, defs)).toEqual('<child>abchz</child>'); // To check the context easily: // console.log(JSON.stringify(ctx)); }); - }); - }); describe('component styles', () => { @@ -207,17 +204,18 @@ describe('component styles', () => { vars: 0, encapsulation: 100, selectors: [['foo']], - template: (rf: RenderFlags, ctx: StyledComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div'); - } - } + template: + (rf: RenderFlags, ctx: StyledComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div'); + } + } }); } const rendererFactory = new ProxyRenderer3Factory(); new ComponentFixture(StyledComp, {rendererFactory}); - expect(rendererFactory.lastCapturedType !.styles).toEqual(['div { color: red; }']); - expect(rendererFactory.lastCapturedType !.encapsulation).toEqual(100); + expect(rendererFactory.lastCapturedType!.styles).toEqual(['div { color: red; }']); + expect(rendererFactory.lastCapturedType!.encapsulation).toEqual(100); }); }); @@ -233,10 +231,11 @@ describe('component animations', () => { decls: 0, vars: 0, data: { - animation: [ - animA, - animB, - ], + animation: + [ + animA, + animB, + ], }, selectors: [['foo']], template: (rf: RenderFlags, ctx: AnimComp) => {} @@ -245,7 +244,7 @@ describe('component animations', () => { const rendererFactory = new ProxyRenderer3Factory(); new ComponentFixture(AnimComp, {rendererFactory}); - const capturedAnimations = rendererFactory.lastCapturedType !.data !['animation']; + const capturedAnimations = rendererFactory.lastCapturedType!.data!['animation']; expect(Array.isArray(capturedAnimations)).toBeTruthy(); expect(capturedAnimations.length).toEqual(2); expect(capturedAnimations).toContain(animA); @@ -268,7 +267,7 @@ describe('component animations', () => { } const rendererFactory = new ProxyRenderer3Factory(); new ComponentFixture(AnimComp, {rendererFactory}); - const data = rendererFactory.lastCapturedType !.data; + const data = rendererFactory.lastCapturedType!.data; expect(data.animation).toEqual([]); }); @@ -281,14 +280,15 @@ describe('component animations', () => { vars: 1, selectors: [['foo']], consts: [[AttributeMarker.Bindings, '@fooAnimation']], - template: (rf: RenderFlags, ctx: AnimComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0); - } - if (rf & RenderFlags.Update) { - ɵɵattribute('@fooAnimation', ctx.animationValue); - } - } + template: + (rf: RenderFlags, ctx: AnimComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 0); + } + if (rf & RenderFlags.Update) { + ɵɵattribute('@fooAnimation', ctx.animationValue); + } + } }); animationValue = '123'; @@ -297,7 +297,7 @@ describe('component animations', () => { const rendererFactory = new MockRendererFactory(['setAttribute']); const fixture = new ComponentFixture(AnimComp, {rendererFactory}); - const renderer = rendererFactory.lastRenderer !; + const renderer = rendererFactory.lastRenderer!; fixture.component.animationValue = '456'; fixture.update(); @@ -318,18 +318,19 @@ describe('component animations', () => { vars: 1, selectors: [['foo']], consts: [['@fooAnimation', '']], - template: (rf: RenderFlags, ctx: AnimComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0); - } - } + template: + (rf: RenderFlags, ctx: AnimComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 0); + } + } }); } const rendererFactory = new MockRendererFactory(['setProperty']); const fixture = new ComponentFixture(AnimComp, {rendererFactory}); - const renderer = rendererFactory.lastRenderer !; + const renderer = rendererFactory.lastRenderer!; fixture.update(); const spy = renderer.spies['setProperty']; @@ -396,16 +397,17 @@ describe('element discovery', () => { selectors: [['structured-comp']], decls: 2, vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - ɵɵelementStart(1, 'p'); - ɵɵelementEnd(); - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + ɵɵelementStart(1, 'p'); + ɵɵelementEnd(); + ɵɵelementEnd(); + } + if (rf & RenderFlags.Update) { + } + } }); } @@ -428,13 +430,14 @@ describe('element discovery', () => { selectors: [['child-comp']], decls: 3, vars: 0, - template: (rf: RenderFlags, ctx: ChildComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div'); - ɵɵelement(1, 'div'); - ɵɵelement(2, 'div'); - } - } + template: + (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div'); + ɵɵelement(1, 'div'); + ɵɵelement(2, 'div'); + } + } }); } @@ -446,14 +449,15 @@ describe('element discovery', () => { directives: [ChildComp], decls: 2, vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'section'); - ɵɵelementStart(1, 'child-comp'); - ɵɵelementEnd(); - ɵɵelementEnd(); - } - } + template: + (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'section'); + ɵɵelementStart(1, 'child-comp'); + ɵɵelementEnd(); + ɵɵelementEnd(); + } + } }); } @@ -480,24 +484,25 @@ describe('element discovery', () => { decls: 2, vars: 1, consts: [['ngIf', '']], - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'section'); - ɵɵtemplate(1, (rf, ctx) => { + template: + (rf: RenderFlags, ctx: StructuredComp) => { if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - ɵɵelement(1, 'p'); + ɵɵelementStart(0, 'section'); + ɵɵtemplate(1, (rf, ctx) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + ɵɵelement(1, 'p'); + ɵɵelementEnd(); + ɵɵelement(2, 'div'); + } + }, 3, 0, 'ng-template', 0); ɵɵelementEnd(); - ɵɵelement(2, 'div'); } - }, 3, 0, 'ng-template', 0); - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵadvance(1); - ɵɵproperty('ngIf', true); - } - } + if (rf & RenderFlags.Update) { + ɵɵadvance(1); + ɵɵproperty('ngIf', true); + } + } }); } @@ -529,28 +534,29 @@ describe('element discovery', () => { directives: [NgIf], decls: 2, vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'section'); - ɵɵelement(1, 'div'); - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'section'); + ɵɵelement(1, 'div'); + } + } }); } const fixture = new ComponentFixture(StructuredComp); fixture.update(); - const section = fixture.hostElement.querySelector('section') !; - const sectionContext = getLContext(section) !; - const sectionLView = sectionContext.lView !; + const section = fixture.hostElement.querySelector('section')!; + const sectionContext = getLContext(section)!; + const sectionLView = sectionContext.lView!; expect(sectionContext.nodeIndex).toEqual(HEADER_OFFSET); expect(sectionLView.length).toBeGreaterThan(HEADER_OFFSET); expect(sectionContext.native).toBe(section); - const div = fixture.hostElement.querySelector('div') !; - const divContext = getLContext(div) !; - const divLView = divContext.lView !; + const div = fixture.hostElement.querySelector('div')!; + const divContext = getLContext(div)!; + const divLView = divContext.lView!; expect(divContext.nodeIndex).toEqual(HEADER_OFFSET + 1); expect(divLView.length).toBeGreaterThan(HEADER_OFFSET); expect(divContext.native).toBe(div); @@ -566,22 +572,23 @@ describe('element discovery', () => { selectors: [['structured-comp']], decls: 1, vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'section'); - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'section'); + } + } }); } const fixture = new ComponentFixture(StructuredComp); fixture.update(); - const section = fixture.hostElement.querySelector('section') !as any; + const section = fixture.hostElement.querySelector('section')! as any; const result1 = section[MONKEY_PATCH_KEY_NAME]; expect(Array.isArray(result1)).toBeTruthy(); - const context = getLContext(section) !; + const context = getLContext(section)!; const result2 = section[MONKEY_PATCH_KEY_NAME]; expect(Array.isArray(result2)).toBeFalsy(); @@ -598,26 +605,27 @@ describe('element discovery', () => { selectors: [['structured-comp']], decls: 2, vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'section'); - ɵɵelement(1, 'p'); - ɵɵelementEnd(); - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'section'); + ɵɵelement(1, 'p'); + ɵɵelementEnd(); + } + } }); } const fixture = new ComponentFixture(StructuredComp); fixture.update(); - const section = fixture.hostElement.querySelector('section') !as any; + const section = fixture.hostElement.querySelector('section')! as any; expect(section[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - const p = fixture.hostElement.querySelector('p') !as any; + const p = fixture.hostElement.querySelector('p')! as any; expect(p[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); - const pContext = getLContext(p) !; + const pContext = getLContext(p)!; expect(pContext.native).toBe(p); expect(p[MONKEY_PATCH_KEY_NAME]).toBe(pContext); }); @@ -631,25 +639,26 @@ describe('element discovery', () => { selectors: [['structured-comp']], decls: 1, vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'section'); - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'section'); + } + } }); } const fixture = new ComponentFixture(StructuredComp); fixture.update(); - const section = fixture.hostElement.querySelector('section') !as any; + const section = fixture.hostElement.querySelector('section')! as any; const result1 = section[MONKEY_PATCH_KEY_NAME]; expect(Array.isArray(result1)).toBeTruthy(); const elementResult = result1[HEADER_OFFSET]; // first element expect(elementResult).toBe(section); - const context = getLContext(section) !; + const context = getLContext(section)!; const result2 = section[MONKEY_PATCH_KEY_NAME]; expect(Array.isArray(result2)).toBeFalsy(); @@ -679,19 +688,20 @@ describe('element discovery', () => { selectors: [['projector-comp']], decls: 4, vars: 0, - template: (rf: RenderFlags, ctx: ProjectorComp) => { - if (rf & RenderFlags.Create) { - ɵɵprojectionDef(); - ɵɵtext(0, 'welcome'); - ɵɵelementStart(1, 'header'); - ɵɵelementStart(2, 'h1'); - ɵɵprojection(3); - ɵɵelementEnd(); - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - } - } + template: + (rf: RenderFlags, ctx: ProjectorComp) => { + if (rf & RenderFlags.Create) { + ɵɵprojectionDef(); + ɵɵtext(0, 'welcome'); + ɵɵelementStart(1, 'header'); + ɵɵelementStart(2, 'h1'); + ɵɵprojection(3); + ɵɵelementEnd(); + ɵɵelementEnd(); + } + if (rf & RenderFlags.Update) { + } + } }); } @@ -703,18 +713,19 @@ describe('element discovery', () => { directives: [ProjectorComp], decls: 5, vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'section'); - ɵɵelementStart(1, 'projector-comp'); - ɵɵelementStart(2, 'p'); - ɵɵtext(3, 'this content is projected'); - ɵɵelementEnd(); - ɵɵtext(4, 'this content is projected also'); - ɵɵelementEnd(); - ɵɵelementEnd(); - } - } + template: + (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'section'); + ɵɵelementStart(1, 'projector-comp'); + ɵɵelementStart(2, 'p'); + ɵɵtext(3, 'this content is projected'); + ɵɵelementEnd(); + ɵɵtext(4, 'this content is projected also'); + ɵɵelementEnd(); + ɵɵelementEnd(); + } + } }); } @@ -723,11 +734,11 @@ describe('element discovery', () => { const host = fixture.hostElement; const textNode = host.firstChild as any; - const section = host.querySelector('section') !as any; - const projectorComp = host.querySelector('projector-comp') !as any; - const header = host.querySelector('header') !as any; - const h1 = host.querySelector('h1') !as any; - const p = host.querySelector('p') !as any; + const section = host.querySelector('section')! as any; + const projectorComp = host.querySelector('projector-comp')! as any; + const header = host.querySelector('header')! as any; + const h1 = host.querySelector('h1')! as any; + const p = host.querySelector('p')! as any; const pText = p.firstChild as any; const projectedTextNode = p.nextSibling; @@ -743,9 +754,9 @@ describe('element discovery', () => { expect(pText[MONKEY_PATCH_KEY_NAME]).toBeFalsy(); expect(projectedTextNode[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - const parentContext = getLContext(section) !; - const shadowContext = getLContext(header) !; - const projectedContext = getLContext(p) !; + const parentContext = getLContext(section)!; + const shadowContext = getLContext(header)!; + const projectedContext = getLContext(p)!; const parentComponentData = parentContext.lView; const shadowComponentData = shadowContext.lView; @@ -776,18 +787,19 @@ describe('element discovery', () => { selectors: [['structured-comp']], decls: 1, vars: 0, - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'section'); - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'section'); + } + } }); } const fixture = new ComponentFixture(StructuredComp); fixture.update(); - const section = fixture.hostElement.querySelector('section') !as any; + const section = fixture.hostElement.querySelector('section')! as any; const manuallyCreatedElement = document.createElement('div'); section.appendChild(manuallyCreatedElement); @@ -819,11 +831,11 @@ describe('element discovery', () => { const hostLView = (hostElm as any)[MONKEY_PATCH_KEY_NAME]; expect(hostLView).toBe(componentLView); - const context1 = getLContext(hostElm) !; + const context1 = getLContext(hostElm)!; expect(context1.lView).toBe(hostLView); expect(context1.native).toEqual(hostElm); - const context2 = getLContext(component) !; + const context2 = getLContext(component)!; expect(context2).toBe(context1); expect(context2.lView).toBe(hostLView); expect(context2.native).toEqual(hostElm); @@ -859,12 +871,13 @@ describe('element discovery', () => { decls: 2, vars: 0, consts: [['my-dir-1', '', 'my-dir-2', ''], ['my-dir-3']], - template: (rf: RenderFlags, ctx: StructuredComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0); - ɵɵelement(1, 'div', 1); - } - } + template: + (rf: RenderFlags, ctx: StructuredComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 0); + ɵɵelement(1, 'div', 1); + } + } }); } @@ -872,9 +885,9 @@ describe('element discovery', () => { fixture.update(); const hostElm = fixture.hostElement; - const div1 = hostElm.querySelector('div:first-child') !as any; - const div2 = hostElm.querySelector('div:last-child') !as any; - const context = getLContext(hostElm) !; + const div1 = hostElm.querySelector('div:first-child')! as any; + const div2 = hostElm.querySelector('div:last-child')! as any; + const context = getLContext(hostElm)!; const componentView = context.lView[context.nodeIndex]; expect(componentView).toContain(myDir1Instance); @@ -885,9 +898,9 @@ describe('element discovery', () => { expect(Array.isArray((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); expect(Array.isArray((myDir3Instance as any)[MONKEY_PATCH_KEY_NAME])).toBeTruthy(); - const d1Context = getLContext(myDir1Instance) !; - const d2Context = getLContext(myDir2Instance) !; - const d3Context = getLContext(myDir3Instance) !; + const d1Context = getLContext(myDir1Instance)!; + const d2Context = getLContext(myDir2Instance)!; + const d3Context = getLContext(myDir3Instance)!; expect(d1Context.lView).toEqual(componentView); expect(d2Context.lView).toEqual(componentView); @@ -933,11 +946,12 @@ describe('element discovery', () => { selectors: [['child-comp']], decls: 1, vars: 0, - template: (rf: RenderFlags, ctx: ChildComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div'); - } - } + template: + (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div'); + } + } }); } @@ -950,18 +964,19 @@ describe('element discovery', () => { decls: 1, vars: 0, consts: [['my-dir-1', '', 'my-dir-2', '']], - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'child-comp', 0); - } - } + template: + (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'child-comp', 0); + } + } }); } const fixture = new ComponentFixture(ParentComp); fixture.update(); - const childCompHostElm = fixture.hostElement.querySelector('child-comp') !as any; + const childCompHostElm = fixture.hostElement.querySelector('child-comp')! as any; const lView = childCompHostElm[MONKEY_PATCH_KEY_NAME]; expect(Array.isArray(lView)).toBeTruthy(); @@ -969,7 +984,7 @@ describe('element discovery', () => { expect((myDir2Instance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); expect((childComponentInstance as any)[MONKEY_PATCH_KEY_NAME]).toBe(lView); - const childNodeContext = getLContext(childCompHostElm) !; + const childNodeContext = getLContext(childCompHostElm)!; expect(childNodeContext.component).toBeFalsy(); expect(childNodeContext.directives).toBeFalsy(); assertMonkeyPatchValueIsLView(myDir1Instance); @@ -978,21 +993,21 @@ describe('element discovery', () => { expect(getLContext(myDir1Instance)).toBe(childNodeContext); expect(childNodeContext.component).toBeFalsy(); - expect(childNodeContext.directives !.length).toEqual(2); + expect(childNodeContext.directives!.length).toEqual(2); assertMonkeyPatchValueIsLView(myDir1Instance, false); assertMonkeyPatchValueIsLView(myDir2Instance, false); assertMonkeyPatchValueIsLView(childComponentInstance); expect(getLContext(myDir2Instance)).toBe(childNodeContext); expect(childNodeContext.component).toBeFalsy(); - expect(childNodeContext.directives !.length).toEqual(2); + expect(childNodeContext.directives!.length).toEqual(2); assertMonkeyPatchValueIsLView(myDir1Instance, false); assertMonkeyPatchValueIsLView(myDir2Instance, false); assertMonkeyPatchValueIsLView(childComponentInstance); expect(getLContext(childComponentInstance)).toBe(childNodeContext); expect(childNodeContext.component).toBeTruthy(); - expect(childNodeContext.directives !.length).toEqual(2); + expect(childNodeContext.directives!.length).toEqual(2); assertMonkeyPatchValueIsLView(myDir1Instance, false); assertMonkeyPatchValueIsLView(myDir2Instance, false); assertMonkeyPatchValueIsLView(childComponentInstance, false); @@ -1011,13 +1026,14 @@ describe('element discovery', () => { selectors: [['child-comp']], decls: 3, vars: 0, - template: (rf: RenderFlags, ctx: ChildComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div'); - ɵɵelement(1, 'div'); - ɵɵelement(2, 'div'); - } - } + template: + (rf: RenderFlags, ctx: ChildComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div'); + ɵɵelement(1, 'div'); + ɵɵelement(2, 'div'); + } + } }); } @@ -1029,14 +1045,15 @@ describe('element discovery', () => { directives: [ChildComp], decls: 2, vars: 0, - template: (rf: RenderFlags, ctx: ParentComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'section'); - ɵɵelementStart(1, 'child-comp'); - ɵɵelementEnd(); - ɵɵelementEnd(); - } - } + template: + (rf: RenderFlags, ctx: ParentComp) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'section'); + ɵɵelementStart(1, 'child-comp'); + ɵɵelementEnd(); + ɵɵelementEnd(); + } + } }); } @@ -1047,7 +1064,7 @@ describe('element discovery', () => { const child = host.querySelector('child-comp') as any; expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); - const context = getLContext(child) !; + const context = getLContext(child)!; expect(child[MONKEY_PATCH_KEY_NAME]).toBeTruthy(); const componentData = context.lView[context.nodeIndex]; @@ -1055,7 +1072,7 @@ describe('element discovery', () => { expect(component instanceof ChildComp).toBeTruthy(); expect(component[MONKEY_PATCH_KEY_NAME]).toBe(context.lView); - const componentContext = getLContext(component) !; + const componentContext = getLContext(component)!; expect(component[MONKEY_PATCH_KEY_NAME]).toBe(componentContext); expect(componentContext.nodeIndex).toEqual(context.nodeIndex); expect(componentContext.native).toEqual(context.native); @@ -1072,28 +1089,33 @@ describe('sanitization', () => { selectors: [['sanitize-this']], decls: 1, vars: 1, - template: (rf: RenderFlags, ctx: SanitizationComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'a'); - } - if (rf & RenderFlags.Update) { - ɵɵproperty('href', ctx.href, ɵɵsanitizeUrl); - } - } + template: + (rf: RenderFlags, ctx: SanitizationComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'a'); + } + if (rf & RenderFlags.Update) { + ɵɵproperty('href', ctx.href, ɵɵsanitizeUrl); + } + } }); private href = ''; - updateLink(href: any) { this.href = href; } + updateLink(href: any) { + this.href = href; + } } - const sanitizer = new LocalSanitizer((value) => { return 'http://bar'; }); + const sanitizer = new LocalSanitizer((value) => { + return 'http://bar'; + }); const fixture = new ComponentFixture(SanitizationComp, {sanitizer}); fixture.component.updateLink('http://foo'); fixture.update(); - const anchor = fixture.hostElement.querySelector('a') !; + const anchor = fixture.hostElement.querySelector('a')!; expect(anchor.getAttribute('href')).toEqual('http://bar'); fixture.component.updateLink(sanitizer.bypassSecurityTrustUrl('http://foo')); @@ -1113,11 +1135,12 @@ describe('sanitization', () => { type: UnsafeUrlHostBindingDir, selectors: [['', 'unsafeUrlHostBindingDir', '']], hostVars: 1, - hostBindings: (rf: RenderFlags, ctx: any) => { - if (rf & RenderFlags.Update) { - ɵɵhostProperty('cite', ctx.cite, ɵɵsanitizeUrl); - } - } + hostBindings: + (rf: RenderFlags, ctx: any) => { + if (rf & RenderFlags.Update) { + ɵɵhostProperty('cite', ctx.cite, ɵɵsanitizeUrl); + } + } }); } @@ -1129,11 +1152,12 @@ describe('sanitization', () => { decls: 1, vars: 0, consts: [['unsafeUrlHostBindingDir', '']], - template: (rf: RenderFlags, ctx: SimpleComp) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'blockquote', 0); - } - }, + template: + (rf: RenderFlags, ctx: SimpleComp) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'blockquote', 0); + } + }, directives: [UnsafeUrlHostBindingDir] }); } @@ -1141,13 +1165,13 @@ describe('sanitization', () => { const sanitizer = new LocalSanitizer((value) => 'http://bar'); const fixture = new ComponentFixture(SimpleComp, {sanitizer}); - hostBindingDir !.cite = 'http://foo'; + hostBindingDir!.cite = 'http://foo'; fixture.update(); - const anchor = fixture.hostElement.querySelector('blockquote') !; + const anchor = fixture.hostElement.querySelector('blockquote')!; expect(anchor.getAttribute('cite')).toEqual('http://bar'); - hostBindingDir !.cite = sanitizer.bypassSecurityTrustUrl('http://foo'); + hostBindingDir!.cite = sanitizer.bypassSecurityTrustUrl('http://foo'); fixture.update(); expect(anchor.getAttribute('cite')).toEqual('http://foo'); @@ -1156,7 +1180,9 @@ describe('sanitization', () => { class LocalSanitizedValue { constructor(public value: any) {} - toString() { return this.value; } + toString() { + return this.value; + } } class LocalSanitizer implements Sanitizer { @@ -1174,7 +1200,9 @@ class LocalSanitizer implements Sanitizer { bypassSecurityTrustScript(value: string) {} bypassSecurityTrustResourceUrl(value: string) {} - bypassSecurityTrustUrl(value: string) { return new LocalSanitizedValue(value); } + bypassSecurityTrustUrl(value: string) { + return new LocalSanitizedValue(value); + } } class ProxyRenderer3Factory implements RendererFactory3 { diff --git a/packages/core/test/render3/ivy/jit_spec.ts b/packages/core/test/render3/ivy/jit_spec.ts index 6b14b3fe8b55c..9aad29f7ac67d 100644 --- a/packages/core/test/render3/ivy/jit_spec.ts +++ b/packages/core/test/render3/ivy/jit_spec.ts @@ -10,7 +10,7 @@ import 'reflect-metadata'; import {ElementRef, QueryList, ɵɵsetComponentScope as setComponentScope} from '@angular/core'; import {Injectable} from '@angular/core/src/di/injectable'; import {setCurrentInjector, ɵɵinject} from '@angular/core/src/di/injector_compatibility'; -import {ɵɵInjectorDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs'; +import {ɵɵdefineInjectable, ɵɵInjectorDef} from '@angular/core/src/di/interface/defs'; import {ivyEnabled} from '@angular/core/src/ivy_switch'; import {ContentChild, ContentChildren, ViewChild, ViewChildren} from '@angular/core/src/metadata/di'; import {Component, Directive, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata/directives'; @@ -20,9 +20,13 @@ import {ComponentDef, FactoryFn, PipeDef} from '@angular/core/src/render3/interf ivyEnabled && describe('render3 jit', () => { let injector: any; - beforeAll(() => { injector = setCurrentInjector(null); }); + beforeAll(() => { + injector = setCurrentInjector(null); + }); - afterAll(() => { setCurrentInjector(injector); }); + afterAll(() => { + setCurrentInjector(injector); + }); it('compiles a component', () => { @Component({ @@ -69,7 +73,6 @@ ivyEnabled && describe('render3 jit', () => { }); it('compiles an injectable with a useFactory provider, without deps', () => { - @Injectable({providedIn: 'root', useFactory: () => 'test'}) class Service { } @@ -100,7 +103,9 @@ ivyEnabled && describe('render3 jit', () => { @Injectable({providedIn: 'root', useClass: Other, deps: [Existing]}) class Service { - get value(): any { return null; } + get value(): any { + return null; + } } const ServiceAny = Service as any; @@ -116,7 +121,9 @@ ivyEnabled && describe('render3 jit', () => { @Injectable({providedIn: 'root', useClass: Existing}) class Service { - get value(): number { return 0; } + get value(): number { + return 0; + } } expect(ɵɵinject(Existing).value).toBe(1); @@ -223,17 +230,17 @@ ivyEnabled && describe('render3 jit', () => { }, }) class Cmp { - @HostBinding('class.green') - green: boolean = false; + @HostBinding('class.green') green: boolean = false; @HostListener('change', ['$event']) - onChange(event: any): void {} + onChange(event: any): void { + } } const cmpDef = (Cmp as any).ɵcmp as ComponentDef<Cmp>; expect(cmpDef.hostBindings).toBeDefined(); - expect(cmpDef.hostBindings !.length).toBe(2); + expect(cmpDef.hostBindings!.length).toBe(2); }); it('should compile @Pipes without errors', () => { diff --git a/packages/core/test/render3/jit/directive_spec.ts b/packages/core/test/render3/jit/directive_spec.ts index 3013e05a80d1e..8b94dadb5e406 100644 --- a/packages/core/test/render3/jit/directive_spec.ts +++ b/packages/core/test/render3/jit/directive_spec.ts @@ -12,16 +12,14 @@ import {setClassMetadata} from '@angular/core/src/render3/metadata'; import {convertToR3QueryMetadata, directiveMetadata, extendsDirectlyFromObject} from '../../../src/render3/jit/directive'; describe('jit directive helper functions', () => { - describe('extendsDirectlyFromObject', () => { - // Inheritance Example using Classes class Parent {} class Child extends Parent {} // Inheritance Example using Function - const Parent5 = function Parent5() {} as any as{new (): {}}; - const Child5 = function Child5() {} as any as{new (): {}}; + const Parent5 = function Parent5() {} as any as {new (): {}}; + const Child5 = function Child5() {} as any as {new (): {}}; Child5.prototype = new Parent5; Child5.prototype.constructor = Child5; @@ -45,7 +43,6 @@ describe('jit directive helper functions', () => { }); describe('convertToR3QueryMetadata', () => { - it('should convert decorator with a single string selector', () => { expect(convertToR3QueryMetadata('propName', { selector: 'localRef', @@ -83,7 +80,6 @@ describe('jit directive helper functions', () => { }); it('should convert decorator with type selector and read option', () => { - class Directive {} const converted = convertToR3QueryMetadata('propName', { @@ -98,7 +94,6 @@ describe('jit directive helper functions', () => { expect(converted.predicate).toEqual(Directive); expect(converted.read).toEqual(Directive); }); - }); describe('directiveMetadata', () => { @@ -155,6 +150,5 @@ describe('jit directive helper functions', () => { expect(subPropMetadata.someInput).toBeFalsy(); expect(subPropMetadata.someOtherInput).toBeTruthy(); }); - }); }); diff --git a/packages/core/test/render3/jit_environment_spec.ts b/packages/core/test/render3/jit_environment_spec.ts index c7e5b4640e0de..18d26e2599d4a 100644 --- a/packages/core/test/render3/jit_environment_spec.ts +++ b/packages/core/test/render3/jit_environment_spec.ts @@ -29,7 +29,7 @@ describe('r3 jit environment', () => { Object // Map over the static properties of Identifiers. .keys(Identifiers) - .map(key => (Identifiers as any as{[key: string]: string | ExternalReference})[key]) + .map(key => (Identifiers as any as {[key: string]: string | ExternalReference})[key]) // A few such properties are string constants. Ignore them, and focus on ExternalReferences. .filter(isExternalReference) // Some references are to interface types. Only take properties which have runtime values. @@ -42,7 +42,7 @@ describe('r3 jit environment', () => { }); }); -function isExternalReference(sym: ExternalReference | string): sym is ExternalReference& +function isExternalReference(sym: ExternalReference|string): sym is ExternalReference& {name: string} { return typeof sym === 'object' && sym.name !== null && sym.moduleName !== null; } diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index 87271664d965e..b8abf18072f19 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -13,7 +13,6 @@ import {NgIf} from './common_with_def'; import {ComponentFixture, createComponent} from './render_util'; describe('lifecycles', () => { - function getParentTemplate(name: string) { return (rf: RenderFlags, ctx: any) => { if (rf & RenderFlags.Create) { @@ -28,7 +27,9 @@ describe('lifecycles', () => { describe('onInit', () => { let events: string[]; - beforeEach(() => { events = []; }); + beforeEach(() => { + events = []; + }); let Comp = createOnInitComponent('comp', (rf: RenderFlags) => { if (rf & RenderFlags.Create) { @@ -61,14 +62,17 @@ describe('lifecycles', () => { selectors: [[name]], decls: decls, vars: vars, - inputs: {val: 'val'}, template, + inputs: {val: 'val'}, + template, directives: directives }); }; } class Directive { - ngOnInit() { events.push('dir'); } + ngOnInit() { + events.push('dir'); + } static ɵfac = () => new Directive(); static ɵdir = ɵɵdefineDirective({type: Directive, selectors: [['', 'dir', '']]}); diff --git a/packages/core/test/render3/listeners_spec.ts b/packages/core/test/render3/listeners_spec.ts index 27455f683628a..67fe696feb32f 100644 --- a/packages/core/test/render3/listeners_spec.ts +++ b/packages/core/test/render3/listeners_spec.ts @@ -13,8 +13,9 @@ import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵe import {RenderFlags} from '../../src/render3/interfaces/definition'; import {GlobalTargetResolver} from '../../src/render3/interfaces/renderer'; import {ɵɵrestoreView} from '../../src/render3/state'; + import {getRendererFactory2} from './imported_renderer2'; -import {ComponentFixture, TemplateFixture, containerEl, createComponent, getDirectiveOnNode, renderToHtml, requestAnimationFrame} from './render_util'; +import {ComponentFixture, containerEl, createComponent, getDirectiveOnNode, renderToHtml, requestAnimationFrame, TemplateFixture} from './render_util'; describe('event listeners', () => { @@ -25,7 +26,9 @@ describe('event listeners', () => { showing = true; counter = 0; - onClick() { this.counter++; } + onClick() { + this.counter++; + } static ɵfac = () => { @@ -40,25 +43,32 @@ describe('event listeners', () => { decls: 2, vars: 0, /** <button (click)="onClick()"> Click me </button> */ - template: function CompTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(); }); - ɵɵtext(1, 'Click me'); + template: + function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { + return ctx.onClick(); + }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + } } - ɵɵelementEnd(); - } - } }); } class MyCompWithGlobalListeners { /* @HostListener('document:custom') */ - onDocumentCustomEvent() { events.push('component - document:custom'); } + onDocumentCustomEvent() { + events.push('component - document:custom'); + } /* @HostListener('body:click') */ - onBodyClick() { events.push('component - body:click'); } + onBodyClick() { + events.push('component - body:click'); + } static ɵfac = () => { @@ -72,51 +82,60 @@ describe('event listeners', () => { selectors: [['comp']], decls: 1, vars: 0, - template: function CompTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'Some text'); - } - }, - hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵlistener('custom', function() { - return ctx.onDocumentCustomEvent(); - }, false, ɵɵresolveDocument as GlobalTargetResolver); - ɵɵlistener('click', function() { - return ctx.onBodyClick(); - }, false, ɵɵresolveBody as GlobalTargetResolver); - } - } + template: + function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'Some text'); + } + }, + hostBindings: + function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵlistener('custom', function() { + return ctx.onDocumentCustomEvent(); + }, false, ɵɵresolveDocument as GlobalTargetResolver); + ɵɵlistener('click', function() { + return ctx.onBodyClick(); + }, false, ɵɵresolveBody as GlobalTargetResolver); + } + } }); } class GlobalHostListenerDir { /* @HostListener('document:custom') */ - onDocumentCustomEvent() { events.push('directive - document:custom'); } + onDocumentCustomEvent() { + events.push('directive - document:custom'); + } /* @HostListener('body:click') */ - onBodyClick() { events.push('directive - body:click'); } + onBodyClick() { + events.push('directive - body:click'); + } - static ɵfac = function HostListenerDir_Factory() { return new GlobalHostListenerDir(); }; + static ɵfac = function HostListenerDir_Factory() { + return new GlobalHostListenerDir(); + }; static ɵdir = ɵɵdefineDirective({ type: GlobalHostListenerDir, selectors: [['', 'hostListenerDir', '']], - hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵlistener('custom', function() { - return ctx.onDocumentCustomEvent(); - }, false, ɵɵresolveDocument as GlobalTargetResolver)('click', function() { - return ctx.onBodyClick(); - }, false, ɵɵresolveBody as GlobalTargetResolver); - } - } + hostBindings: + function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵlistener('custom', function() { + return ctx.onDocumentCustomEvent(); + }, false, ɵɵresolveDocument as GlobalTargetResolver)('click', function() { + return ctx.onBodyClick(); + }, false, ɵɵresolveBody as GlobalTargetResolver); + } + } }); } class PreventDefaultComp { handlerReturnValue: any = true; // TODO(issue/24571): remove '!'. - event !: Event; + event!: Event; onClick(e: any) { this.event = e; @@ -136,16 +155,19 @@ describe('event listeners', () => { decls: 2, vars: 0, /** <button (click)="onClick($event)">Click</button> */ - template: (rf: RenderFlags, ctx: PreventDefaultComp) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function($event: any) { return ctx.onClick($event); }); - ɵɵtext(1, 'Click'); + template: + (rf: RenderFlags, ctx: PreventDefaultComp) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function($event: any) { + return ctx.onClick($event); + }); + ɵɵtext(1, 'Click'); + } + ɵɵelementEnd(); + } } - ɵɵelementEnd(); - } - } }); } @@ -157,7 +179,7 @@ describe('event listeners', () => { it('should call function on event emit', () => { const fixture = new ComponentFixture(MyComp); const comp = fixture.component; - const button = fixture.hostElement.querySelector('button') !; + const button = fixture.hostElement.querySelector('button')!; button.click(); expect(comp.counter).toEqual(1); @@ -169,36 +191,36 @@ describe('event listeners', () => { it('should retain event handler return values using document', () => { const fixture = new ComponentFixture(PreventDefaultComp); const preventDefaultComp = fixture.component; - const button = fixture.hostElement.querySelector('button') !; + const button = fixture.hostElement.querySelector('button')!; button.click(); - expect(preventDefaultComp.event !.preventDefault).not.toHaveBeenCalled(); + expect(preventDefaultComp.event!.preventDefault).not.toHaveBeenCalled(); preventDefaultComp.handlerReturnValue = undefined; button.click(); - expect(preventDefaultComp.event !.preventDefault).not.toHaveBeenCalled(); + expect(preventDefaultComp.event!.preventDefault).not.toHaveBeenCalled(); preventDefaultComp.handlerReturnValue = false; button.click(); - expect(preventDefaultComp.event !.preventDefault).toHaveBeenCalled(); + expect(preventDefaultComp.event!.preventDefault).toHaveBeenCalled(); }); it('should retain event handler return values with renderer2', () => { const fixture = new ComponentFixture(PreventDefaultComp, {rendererFactory: getRendererFactory2(document)}); const preventDefaultComp = fixture.component; - const button = fixture.hostElement.querySelector('button') !; + const button = fixture.hostElement.querySelector('button')!; button.click(); - expect(preventDefaultComp.event !.preventDefault).not.toHaveBeenCalled(); + expect(preventDefaultComp.event!.preventDefault).not.toHaveBeenCalled(); preventDefaultComp.handlerReturnValue = undefined; button.click(); - expect(preventDefaultComp.event !.preventDefault).not.toHaveBeenCalled(); + expect(preventDefaultComp.event!.preventDefault).not.toHaveBeenCalled(); preventDefaultComp.handlerReturnValue = false; button.click(); - expect(preventDefaultComp.event !.preventDefault).toHaveBeenCalled(); + expect(preventDefaultComp.event!.preventDefault).toHaveBeenCalled(); }); it('should call function chain on event emit', () => { @@ -220,11 +242,15 @@ describe('event listeners', () => { const ctx = { counter: 0, counter2: 0, - onClick: function() { this.counter++; }, - onClick2: function() { this.counter2++; } + onClick: function() { + this.counter++; + }, + onClick2: function() { + this.counter2++; + } }; renderToHtml(Template, ctx, 2); - const button = containerEl.querySelector('button') !; + const button = containerEl.querySelector('button')!; button.click(); expect(ctx.counter).toBe(1); @@ -236,13 +262,14 @@ describe('event listeners', () => { }); it('should evaluate expression on event emit', () => { - /** <button (click)="showing=!showing"> Click me </button> */ function Template(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'button'); { - ɵɵlistener('click', function() { return ctx.showing = !ctx.showing; }); + ɵɵlistener('click', function() { + return ctx.showing = !ctx.showing; + }); ɵɵtext(1, 'Click me'); } ɵɵelementEnd(); @@ -251,7 +278,7 @@ describe('event listeners', () => { const ctx = {showing: false}; renderToHtml(Template, ctx, 2); - const button = containerEl.querySelector('button') !; + const button = containerEl.querySelector('button')!; button.click(); expect(ctx.showing).toBe(true); @@ -261,11 +288,10 @@ describe('event listeners', () => { }); it('should support listeners in views', () => { - /** * % if (ctx.showing) { - * <button (click)="onClick()"> Click me </button> - * % } + * <button (click)="onClick()"> Click me </button> + * % } */ function Template(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -278,7 +304,9 @@ describe('event listeners', () => { if (ɵɵembeddedViewStart(1, 2, 0)) { ɵɵelementStart(0, 'button'); { - ɵɵlistener('click', function() { return ctx.onClick(); }); + ɵɵlistener('click', function() { + return ctx.onClick(); + }); ɵɵtext(1, 'Click me'); } ɵɵelementEnd(); @@ -292,7 +320,7 @@ describe('event listeners', () => { let comp = new MyComp(); renderToHtml(Template, comp, 1); - const button = containerEl.querySelector('button') !; + const button = containerEl.querySelector('button')!; button.click(); expect(comp.counter).toEqual(1); @@ -308,17 +336,18 @@ describe('event listeners', () => { }); it('should destroy listeners in views with renderer2', () => { - /** - * % if (ctx.showing) { - * <button (click)="onClick()"> Click me </button> - * % } + * % if (ctx.showing) { + * <button (click)="onClick()"> Click me </button> + * % } */ class AppComp { counter = 0; showing = true; - onClick() { this.counter++; } + onClick() { + this.counter++; + } static ɵfac = () => new AppComp(); static ɵcmp = ɵɵdefineComponent({ @@ -326,34 +355,37 @@ describe('event listeners', () => { selectors: [['app-comp']], decls: 1, vars: 0, - template: function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵcontainer(0); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(0); - { - if (ctx.showing) { - if (ɵɵembeddedViewStart(0, 2, 0)) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(); }); - ɵɵtext(1, 'Click me'); + template: + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵcontainer(0); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(0); + { + if (ctx.showing) { + if (ɵɵembeddedViewStart(0, 2, 0)) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { + return ctx.onClick(); + }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + } + ɵɵembeddedViewEnd(); } - ɵɵelementEnd(); } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } } - ɵɵcontainerRefreshEnd(); - } - } }); } const fixture = new ComponentFixture(AppComp, {rendererFactory: getRendererFactory2(document)}); const comp = fixture.component; - const button = fixture.hostElement.querySelector('button') !; + const button = fixture.hostElement.querySelector('button')!; button.click(); expect(comp.counter).toEqual(1); @@ -369,17 +401,18 @@ describe('event listeners', () => { }); it('should destroy listeners in for loops', () => { - /** - * % for (let i = 0; i < ctx.buttons; i++) { - * <button (click)="onClick(i)"> Click me </button> - * % } + * % for (let i = 0; i < ctx.buttons; i++) { + * <button (click)="onClick(i)"> Click me </button> + * % } */ class AppComp { buttons = 2; counters = [0, 0]; - onClick(index: number) { this.counters[index]++; } + onClick(index: number) { + this.counters[index]++; + } static ɵfac = () => new AppComp(); static ɵcmp = ɵɵdefineComponent({ @@ -387,34 +420,37 @@ describe('event listeners', () => { selectors: [['app-comp']], decls: 1, vars: 0, - template: function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵcontainer(0); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(0); - { - for (let i = 0; i < ctx.buttons; i++) { - if (ɵɵembeddedViewStart(0, 2, 0)) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(i); }); - ɵɵtext(1, 'Click me'); + template: + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵcontainer(0); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(0); + { + for (let i = 0; i < ctx.buttons; i++) { + if (ɵɵembeddedViewStart(0, 2, 0)) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { + return ctx.onClick(i); + }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + } + ɵɵembeddedViewEnd(); } - ɵɵelementEnd(); } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } } - ɵɵcontainerRefreshEnd(); - } - } }); } const fixture = new ComponentFixture(AppComp); const comp = fixture.component; - const buttons = fixture.hostElement.querySelectorAll('button') !; + const buttons = fixture.hostElement.querySelectorAll('button')!; buttons[0].click(); expect(comp.counters).toEqual([1, 0]); @@ -432,18 +468,19 @@ describe('event listeners', () => { }); it('should destroy listeners in for loops with renderer2', () => { - /** - * % for (let i = 0; i < ctx.buttons; i++) { - * <button (click)="onClick(i)"> Click me </button> - * {{ counters[i] }} - * % } + * % for (let i = 0; i < ctx.buttons; i++) { + * <button (click)="onClick(i)"> Click me </button> + * {{ counters[i] }} + * % } */ class AppComp { buttons = 2; counters = [0, 0]; - onClick(index: number) { this.counters[index]++; } + onClick(index: number) { + this.counters[index]++; + } static ɵfac = () => new AppComp(); static ɵcmp = ɵɵdefineComponent({ @@ -451,42 +488,45 @@ describe('event listeners', () => { selectors: [['app-comp']], decls: 1, vars: 0, - template: function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵcontainer(0); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(0); - { - for (let i = 0; i < ctx.buttons; i++) { - const rf1 = ɵɵembeddedViewStart(1, 4, 1); - if (rf1 & RenderFlags.Create) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(i); }); - ɵɵtext(1, 'Click me'); + template: + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵcontainer(0); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(0); + { + for (let i = 0; i < ctx.buttons; i++) { + const rf1 = ɵɵembeddedViewStart(1, 4, 1); + if (rf1 & RenderFlags.Create) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { + return ctx.onClick(i); + }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + ɵɵelementStart(2, 'div'); + { ɵɵtext(3); } + ɵɵelementEnd(); + } + if (rf1 & RenderFlags.Update) { + ɵɵselect(3); + ɵɵtextInterpolate(ctx.counters[i]); + } + ɵɵembeddedViewEnd(); } - ɵɵelementEnd(); - ɵɵelementStart(2, 'div'); - { ɵɵtext(3); } - ɵɵelementEnd(); - } - if (rf1 & RenderFlags.Update) { - ɵɵselect(3); - ɵɵtextInterpolate(ctx.counters[i]); } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } } - ɵɵcontainerRefreshEnd(); - } - } }); } const fixture = new ComponentFixture(AppComp, {rendererFactory: getRendererFactory2(document)}); const comp = fixture.component; - const buttons = fixture.hostElement.querySelectorAll('button') !; + const buttons = fixture.hostElement.querySelectorAll('button')!; const divs = fixture.hostElement.querySelectorAll('div'); buttons[0].click(); @@ -522,24 +562,34 @@ describe('event listeners', () => { let events: string[] = []; class MyComp { /* @HostListener('click') */ - onClick() { events.push('click!'); } + onClick() { + events.push('click!'); + } + + static ɵfac = + () => { + return new MyComp(); + } - static ɵfac = () => { return new MyComp(); }; static ɵcmp = ɵɵdefineComponent({ type: MyComp, selectors: [['comp']], decls: 1, vars: 0, - template: function CompTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'Some text'); - } - }, - hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵlistener('click', function() { return ctx.onClick(); }); - } - } + template: + function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'Some text'); + } + }, + hostBindings: + function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵlistener('click', function() { + return ctx.onClick(); + }); + } + } }); } @@ -555,7 +605,7 @@ describe('event listeners', () => { it('should support global host listeners on components', () => { const fixture = new ComponentFixture(MyCompWithGlobalListeners); - const doc = fixture.hostElement.ownerDocument !; + const doc = fixture.hostElement.ownerDocument!; dispatchEvent(doc, 'custom'); expect(events).toEqual(['component - document:custom']); @@ -572,17 +622,24 @@ describe('event listeners', () => { class HostListenerDir { /* @HostListener('click') */ - onClick() { events.push('click!'); } + onClick() { + events.push('click!'); + } - static ɵfac = function HostListenerDir_Factory() { return new HostListenerDir(); }; + static ɵfac = function HostListenerDir_Factory() { + return new HostListenerDir(); + }; static ɵdir = ɵɵdefineDirective({ type: HostListenerDir, selectors: [['', 'hostListenerDir', '']], - hostBindings: function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵlistener('click', function() { return ctx.onClick(); }); - } - } + hostBindings: + function HostListenerDir_HostBindings(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵlistener('click', function() { + return ctx.onClick(); + }); + } + } }); } @@ -592,7 +649,7 @@ describe('event listeners', () => { ɵɵelementEnd(); }, () => {}, 2, 0, [HostListenerDir], null, null, undefined, [['hostListenerDir', '']]); - const button = fixture.hostElement.querySelector('button') !; + const button = fixture.hostElement.querySelector('button')!; button.click(); expect(events).toEqual(['click!']); @@ -606,7 +663,7 @@ describe('event listeners', () => { ɵɵelement(0, 'div', 0); }, () => {}, 1, 0, [GlobalHostListenerDir], null, null, undefined, [['hostListenerDir', '']]); - const doc = fixture.hostElement.ownerDocument !; + const doc = fixture.hostElement.ownerDocument!; dispatchEvent(doc, 'custom'); expect(events).toEqual(['directive - document:custom']); @@ -623,7 +680,9 @@ describe('event listeners', () => { counter = 0; data = {a: 1, b: 2}; - onClick(a: any, b: any) { this.counter += a + b; } + onClick(a: any, b: any) { + this.counter += a + b; + } static ɵfac = () => new MyComp(); static ɵcmp = ɵɵdefineComponent({ @@ -632,22 +691,25 @@ describe('event listeners', () => { decls: 2, vars: 0, /** <button (click)="onClick(data.a, data.b)"> Click me </button> */ - template: function CompTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(ctx.data.a, ctx.data.b); }); - ɵɵtext(1, 'Click me'); + template: + function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { + return ctx.onClick(ctx.data.a, ctx.data.b); + }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + } } - ɵɵelementEnd(); - } - } }); } const fixture = new ComponentFixture(MyComp); const comp = fixture.component; - const button = fixture.hostElement.querySelector('button') !; + const button = fixture.hostElement.querySelector('button')!; button.click(); expect(comp.counter).toEqual(3); @@ -657,14 +719,13 @@ describe('event listeners', () => { }); it('should destroy listeners in nested views', () => { - /** - * % if (showing) { - * Hello - * % if (button) { - * <button (click)="onClick()"> Click </button> - * % } - * % } + * % if (showing) { + * Hello + * % if (button) { + * <button (click)="onClick()"> Click </button> + * % } + * % } */ function Template(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { @@ -687,7 +748,9 @@ describe('event listeners', () => { if (rf1 & RenderFlags.Create) { ɵɵelementStart(0, 'button'); { - ɵɵlistener('click', function() { return ctx.onClick(); }); + ɵɵlistener('click', function() { + return ctx.onClick(); + }); ɵɵtext(1, 'Click'); } ɵɵelementEnd(); @@ -704,9 +767,16 @@ describe('event listeners', () => { } } - const comp = {showing: true, counter: 0, button: true, onClick: function() { this.counter++; }}; + const comp = { + showing: true, + counter: 0, + button: true, + onClick: function() { + this.counter++; + } + }; renderToHtml(Template, comp, 1); - const button = containerEl.querySelector('button') !; + const button = containerEl.querySelector('button')!; button.click(); expect(comp.counter).toEqual(1); @@ -719,13 +789,12 @@ describe('event listeners', () => { }); it('should destroy listeners in component views', () => { - /** - * % if (showing) { - * Hello - * <comp></comp> - * <comp></comp> - * % } + * % if (showing) { + * Hello + * <comp></comp> + * <comp></comp> + * % } * * comp: * <button (click)="onClick()"> Click </button> @@ -753,28 +822,30 @@ describe('event listeners', () => { const ctx = {showing: true}; renderToHtml(Template, ctx, 1, 0, [MyComp]); - const buttons = containerEl.querySelectorAll('button') !; + const buttons = containerEl.querySelectorAll('button')!; buttons[0].click(); - expect(comps[0] !.counter).toEqual(1); + expect(comps[0]!.counter).toEqual(1); buttons[1].click(); - expect(comps[1] !.counter).toEqual(1); + expect(comps[1]!.counter).toEqual(1); // the child view listener should be removed when the parent view is removed ctx.showing = false; renderToHtml(Template, ctx, 1, 0, [MyComp]); buttons[0].click(); buttons[1].click(); - expect(comps[0] !.counter).toEqual(1); - expect(comps[1] !.counter).toEqual(1); + expect(comps[0]!.counter).toEqual(1); + expect(comps[1]!.counter).toEqual(1); }); it('should destroy global listeners in component views', () => { const ctx = {showing: true}; const fixture = new TemplateFixture( - () => { ɵɵcontainer(0); }, + () => { + ɵɵcontainer(0); + }, () => { ɵɵcontainerRefreshStart(0); { @@ -790,7 +861,7 @@ describe('event listeners', () => { }, 1, 0, [MyCompWithGlobalListeners]); - const body = fixture.hostElement.ownerDocument !.body; + const body = fixture.hostElement.ownerDocument!.body; body.click(); expect(events).toEqual(['component - body:click']); @@ -839,7 +910,9 @@ describe('event listeners', () => { if (rf1 & RenderFlags.Create) { ɵɵelementStart(0, 'button'); { - ɵɵlistener('click', function() { return ctx.counter1++; }); + ɵɵlistener('click', function() { + return ctx.counter1++; + }); ɵɵtext(1, 'Click'); } ɵɵelementEnd(); @@ -855,7 +928,9 @@ describe('event listeners', () => { if (rf1 & RenderFlags.Create) { ɵɵelementStart(0, 'button'); { - ɵɵlistener('click', function() { return ctx.counter2++; }); + ɵɵlistener('click', function() { + return ctx.counter2++; + }); ɵɵtext(1, 'Click'); } ɵɵelementEnd(); @@ -874,7 +949,7 @@ describe('event listeners', () => { const ctx = {condition: true, counter1: 0, counter2: 0, sub1: true, sub2: true}; renderToHtml(Template, ctx, 1); - const buttons = containerEl.querySelectorAll('button') !; + const buttons = containerEl.querySelectorAll('button')!; buttons[0].click(); expect(ctx.counter1).toEqual(1); @@ -889,7 +964,6 @@ describe('event listeners', () => { buttons[1].click(); expect(ctx.counter1).toEqual(1); expect(ctx.counter2).toEqual(1); - }); it('should support local refs in listeners', () => { @@ -904,7 +978,9 @@ describe('event listeners', () => { class App { comp: any = null; - onClick(comp: any) { this.comp = comp; } + onClick(comp: any) { + this.comp = comp; + } static ɵfac = () => new App(); static ɵcmp = ɵɵdefineComponent({ @@ -913,24 +989,25 @@ describe('event listeners', () => { decls: 3, vars: 0, consts: [['comp', '']], - template: (rf: RenderFlags, ctx: App) => { - if (rf & RenderFlags.Create) { - const state = ɵɵgetCurrentView(); - ɵɵelement(0, 'comp', null, 0); - ɵɵelementStart(2, 'button'); - { - ɵɵlistener('click', function() { - ɵɵrestoreView(state); - const comp = ɵɵreference(1); - return ctx.onClick(comp); - }); - } - ɵɵelementEnd(); - } + template: + (rf: RenderFlags, ctx: App) => { + if (rf & RenderFlags.Create) { + const state = ɵɵgetCurrentView(); + ɵɵelement(0, 'comp', null, 0); + ɵɵelementStart(2, 'button'); + { + ɵɵlistener('click', function() { + ɵɵrestoreView(state); + const comp = ɵɵreference(1); + return ctx.onClick(comp); + }); + } + ɵɵelementEnd(); + } - // testing only - compInstance = getDirectiveOnNode(0); - }, + // testing only + compInstance = getDirectiveOnNode(0); + }, directives: [Comp] }); } @@ -942,5 +1019,4 @@ describe('event listeners', () => { button.click(); expect(fixture.component.comp).toEqual(compInstance); }); - }); diff --git a/packages/core/test/render3/metadata_spec.ts b/packages/core/test/render3/metadata_spec.ts index 7a124d9ee160d..0f9a7d4f132a1 100644 --- a/packages/core/test/render3/metadata_spec.ts +++ b/packages/core/test/render3/metadata_spec.ts @@ -31,33 +31,33 @@ function metadataOf(value: Type<any>): HasMetadata { describe('render3 setClassMetadata()', () => { it('should set decorator metadata on a type', () => { - const Foo = metadataOf(class Foo{}); + const Foo = metadataOf(class Foo {}); setClassMetadata(Foo, [{type: 'test', args: ['arg']}], null, null); expect(Foo.decorators).toEqual([{type: 'test', args: ['arg']}]); }); it('should merge decorator metadata on a type', () => { - const Foo = metadataOf(class Foo{}); + const Foo = metadataOf(class Foo {}); Foo.decorators = [{type: 'first'}]; setClassMetadata(Foo, [{type: 'test', args: ['arg']}], null, null); expect(Foo.decorators).toEqual([{type: 'first'}, {type: 'test', args: ['arg']}]); }); it('should set ctor parameter metadata on a type', () => { - const Foo = metadataOf(class Foo{}); + const Foo = metadataOf(class Foo {}); Foo.ctorParameters = () => [{type: 'initial'}]; setClassMetadata(Foo, null, () => [{type: 'test'}], null); expect(Foo.ctorParameters()).toEqual([{type: 'test'}]); }); it('should set parameter decorator metadata on a type', () => { - const Foo = metadataOf(class Foo{}); + const Foo = metadataOf(class Foo {}); setClassMetadata(Foo, null, null, {field: [{type: 'test', args: ['arg']}]}); expect(Foo.propDecorators).toEqual({field: [{type: 'test', args: ['arg']}]}); }); it('should merge parameter decorator metadata on a type', () => { - const Foo = metadataOf(class Foo{}); + const Foo = metadataOf(class Foo {}); Foo.propDecorators = {initial: [{type: 'first'}]}; setClassMetadata(Foo, null, null, {field: [{type: 'test', args: ['arg']}]}); expect(Foo.propDecorators) diff --git a/packages/core/test/render3/outputs_spec.ts b/packages/core/test/render3/outputs_spec.ts index 9e5f95f4c0d65..fd009950bd698 100644 --- a/packages/core/test/render3/outputs_spec.ts +++ b/packages/core/test/render3/outputs_spec.ts @@ -59,7 +59,9 @@ describe('outputs', () => { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'button'); { - ɵɵlistener('click', function() { return ctx.onClick(); }); + ɵɵlistener('click', function() { + return ctx.onClick(); + }); ɵɵtext(1, 'Click me'); } ɵɵelementEnd(); @@ -73,7 +75,9 @@ describe('outputs', () => { if (rf1 & RenderFlags.Create) { ɵɵelementStart(0, 'button-toggle'); { - ɵɵlistener('change', function() { return ctx.onChange(); }); + ɵɵlistener('change', function() { + return ctx.onChange(); + }); } ɵɵelementEnd(); } @@ -82,7 +86,9 @@ describe('outputs', () => { if (ɵɵembeddedViewStart(1, 1, 0)) { ɵɵelementStart(0, 'div', 0); { - ɵɵlistener('change', function() { return ctx.onChange(); }); + ɵɵlistener('change', function() { + return ctx.onChange(); + }); } ɵɵelementEnd(); } @@ -98,15 +104,14 @@ describe('outputs', () => { const attrs = [['otherDir', '']]; renderToHtml(Template, ctx, 3, 0, deps, null, null, false, attrs); - buttonToggle !.change.next(); + buttonToggle!.change.next(); expect(counter).toEqual(1); ctx.condition = false; renderToHtml(Template, ctx, 3, 0, deps, null, null, false, attrs); expect(counter).toEqual(1); - otherDir !.changeStream.next(); + otherDir!.changeStream.next(); expect(counter).toEqual(2); }); - }); diff --git a/packages/core/test/render3/perf/directive_instantiate/index.ts b/packages/core/test/render3/perf/directive_instantiate/index.ts index ea3d5263c512b..c5d6a47cd4a6a 100644 --- a/packages/core/test/render3/perf/directive_instantiate/index.ts +++ b/packages/core/test/render3/perf/directive_instantiate/index.ts @@ -78,7 +78,7 @@ const rootLView = createLView( null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {}, LViewFlags.IsRoot, null, null); -const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode; +const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode; const embeddedTView = createTView( TViewType.Embedded, -1, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null, [['position', 'top', 3, 'tooltip']]); diff --git a/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts b/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts index b8d3a02b31aa5..0d234a1205116 100644 --- a/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts +++ b/packages/core/test/render3/perf/duplicate_map_based_style_and_class_bindings/index.ts @@ -1,10 +1,10 @@ /** -* @license -* Copyright Google Inc. All Rights Reserved. -* -* Use of this source code is governed by an MIT-style license that can be -* found in the LICENSE file at https://angular.io/license -*/ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {ɵɵadvance} from '../../../../src/render3/instructions/advance'; import {ɵɵelement, ɵɵelementEnd, ɵɵelementStart} from '../../../../src/render3/instructions/element'; import {refreshView} from '../../../../src/render3/instructions/shared'; diff --git a/packages/core/test/render3/perf/element_text_create/index.ts b/packages/core/test/render3/perf/element_text_create/index.ts index 65cc7ec7ba3a3..2851c278fd4dd 100644 --- a/packages/core/test/render3/perf/element_text_create/index.ts +++ b/packages/core/test/render3/perf/element_text_create/index.ts @@ -67,7 +67,7 @@ const rootLView = createLView( null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {}, LViewFlags.IsRoot, null, null); -const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode; +const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode; const embeddedTView = createTView( TViewType.Embedded, -1, testTemplate, 21, 0, null, null, null, null, [[ 'name1', 'value1', 'name2', 'value2', 'name3', 'value3', 'name4', 'value4', 'name5', 'value5' diff --git a/packages/core/test/render3/perf/host_binding/index.ts b/packages/core/test/render3/perf/host_binding/index.ts index e42e9a627a60a..ec41b9d83e2a6 100644 --- a/packages/core/test/render3/perf/host_binding/index.ts +++ b/packages/core/test/render3/perf/host_binding/index.ts @@ -31,19 +31,24 @@ function generateHostBindingDirDef() { } `; class HostBindingDir { - static ɵfac() { return new HostBindingDir(); } + static ɵfac() { + return new HostBindingDir(); + } static ɵdir = ɵɵdefineDirective({ type: HostBindingDir, selectors: [['', 'hostBindingDir', '']], hostVars: 2, - hostBindings: function(rf: RenderFlags, ctx: any) { - if (rf & 1) { - ɵɵlistener('click', function() { return ctx.onClick(); }); - } - if (rf & 2) { - ɵɵhostProperty('data-a', ctx.exp); - } - } + hostBindings: + function(rf: RenderFlags, ctx: any) { + if (rf & 1) { + ɵɵlistener('click', function() { + return ctx.onClick(); + }); + } + if (rf & 2) { + ɵɵhostProperty('data-a', ctx.exp); + } + } }); exp = 'string-exp'; diff --git a/packages/core/test/render3/perf/listeners/index.ts b/packages/core/test/render3/perf/listeners/index.ts index 0c6f228f49061..f11e6d3910bda 100644 --- a/packages/core/test/render3/perf/listeners/index.ts +++ b/packages/core/test/render3/perf/listeners/index.ts @@ -69,7 +69,7 @@ const rootLView = createLView( null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {}, LViewFlags.IsRoot, null, null); -const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode; +const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode; const embeddedTView = createTView( TViewType.Embedded, -1, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]); diff --git a/packages/core/test/render3/perf/micro_bench.ts b/packages/core/test/render3/perf/micro_bench.ts index 2f7e714fc0679..b9c12454fcb45 100644 --- a/packages/core/test/render3/perf/micro_bench.ts +++ b/packages/core/test/render3/perf/micro_bench.ts @@ -64,8 +64,8 @@ export function createBenchmark(benchmarkName: string): Benchmark { } if (!runAgain) { // tslint:disable-next-line:no-console - console.log( - ` ${formatTime(profile.bestTime)} (count: ${profile.sampleCount}, iterations: ${profile.iterationCount})`); + console.log(` ${formatTime(profile.bestTime)} (count: ${ + profile.sampleCount}, iterations: ${profile.iterationCount})`); } } iterationCounter = profile.iterationCount; @@ -91,11 +91,14 @@ export function createBenchmark(benchmarkName: string): Benchmark { return (previous.bestTime < current.bestTime) ? previous : current; }); const unitOffset = findUnit(fastest.bestTime); - (fn || console.info)(`\nBenchmark: ${benchmarkName}\n${profiles.map((profile: Profile) => { - const time = formatTime(profile.bestTime, unitOffset); - const percent = formatPercent(1 - profile.bestTime / fastest.bestTime); - return ` ${profile.profileName}: ${time}(${percent}) `; - }).join('\n')}`); + (fn || console.info)(`\nBenchmark: ${benchmarkName}\n${ + profiles + .map((profile: Profile) => { + const time = formatTime(profile.bestTime, unitOffset); + const percent = formatPercent(1 - profile.bestTime / fastest.bestTime); + return ` ${profile.profileName}: ${time}(${percent}) `; + }) + .join('\n')}`); }; return benchmark; } diff --git a/packages/core/test/render3/perf/ng_template/index.ts b/packages/core/test/render3/perf/ng_template/index.ts index 324bd65849d86..8c9754ed3aa0f 100644 --- a/packages/core/test/render3/perf/ng_template/index.ts +++ b/packages/core/test/render3/perf/ng_template/index.ts @@ -62,7 +62,7 @@ const rootLView = createLView( null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {}, LViewFlags.IsRoot, null, null); -const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode; +const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode; const embeddedTView = createTView( TViewType.Root, -1, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null, [['viewManipulation', '']]); diff --git a/packages/core/test/render3/perf/noop_renderer.ts b/packages/core/test/render3/perf/noop_renderer.ts index ef93923c16e71..1401df52ea683 100644 --- a/packages/core/test/render3/perf/noop_renderer.ts +++ b/packages/core/test/render3/perf/noop_renderer.ts @@ -5,33 +5,49 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3} from '../../../src/render3/interfaces/renderer'; +import {ProceduralRenderer3, RComment, RElement, Renderer3, RendererFactory3, RendererStyleFlags3, RNode, RText} from '../../../src/render3/interfaces/renderer'; export class MicroBenchmarkRenderNode implements RNode, RComment, RText { textContent: string|null = null; parentNode: RNode|null = null; parentElement: RElement|null = null; nextSibling: RNode|null = null; - removeChild(oldChild: RNode): RNode { return oldChild; } + removeChild(oldChild: RNode): RNode { + return oldChild; + } insertBefore(newChild: RNode, refChild: RNode|null, isViewRoot: boolean): void {} - appendChild(newChild: RNode): RNode { return newChild; } + appendChild(newChild: RNode): RNode { + return newChild; + } className: string = ''; } export class MicroBenchmarkRenderer implements ProceduralRenderer3 { - destroy(): void { throw new Error('Method not implemented.'); } - createComment(value: string): RComment { return new MicroBenchmarkRenderNode(); } + destroy(): void { + throw new Error('Method not implemented.'); + } + createComment(value: string): RComment { + return new MicroBenchmarkRenderNode(); + } createElement(name: string, namespace?: string|null|undefined): RElement { return new MicroBenchmarkRenderNode() as any as RElement; } - createText(value: string): RText { return new MicroBenchmarkRenderNode(); } + createText(value: string): RText { + return new MicroBenchmarkRenderNode(); + } destroyNode?: ((node: RNode) => void)|null|undefined; appendChild(parent: RElement, newChild: RNode): void {} insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void {} removeChild(parent: RElement, oldChild: RNode, isHostElement?: boolean|undefined): void {} - selectRootElement(selectorOrNode: any): RElement { throw new Error('Method not implemented.'); } - parentNode(node: RNode): RElement|null { throw new Error('Method not implemented.'); } - nextSibling(node: RNode): RNode|null { throw new Error('Method not implemented.'); } + selectRootElement(selectorOrNode: any): RElement { + throw new Error('Method not implemented.'); + } + parentNode(node: RNode): RElement|null { + throw new Error('Method not implemented.'); + } + nextSibling(node: RNode): RNode|null { + throw new Error('Method not implemented.'); + } setAttribute(el: RElement, name: string, value: string, namespace?: string|null|undefined): void { if (name === 'class' && isOurNode(el)) { el.className = value; @@ -51,7 +67,9 @@ export class MicroBenchmarkRenderer implements ProceduralRenderer3 { setStyle(el: RElement, style: string, value: any, flags?: RendererStyleFlags3|undefined): void {} removeStyle(el: RElement, style: string, flags?: RendererStyleFlags3|undefined): void {} setProperty(el: RElement, name: string, value: any): void {} - setValue(node: RComment|RText, value: string): void { node.textContent = value; } + setValue(node: RComment|RText, value: string): void { + node.textContent = value; + } listen( target: RNode|'document'|'window'|'body', eventName: string, callback: (event: any) => boolean | void): () => void { diff --git a/packages/core/test/render3/perf/noop_renderer_spec.ts b/packages/core/test/render3/perf/noop_renderer_spec.ts index 63cd2f1a7c90f..d569096d7441c 100644 --- a/packages/core/test/render3/perf/noop_renderer_spec.ts +++ b/packages/core/test/render3/perf/noop_renderer_spec.ts @@ -8,7 +8,7 @@ import {ProceduralRenderer3} from '@angular/core/src/render3/interfaces/renderer'; -import {MicroBenchmarkRenderNode, MicroBenchmarkRendererFactory} from './noop_renderer'; +import {MicroBenchmarkRendererFactory, MicroBenchmarkRenderNode} from './noop_renderer'; describe('MicroBenchmarkRenderNode', () => { const renderer = diff --git a/packages/core/test/render3/perf/setup.ts b/packages/core/test/render3/perf/setup.ts index 51b2579428f2c..cd90954f73f3c 100644 --- a/packages/core/test/render3/perf/setup.ts +++ b/packages/core/test/render3/perf/setup.ts @@ -8,7 +8,7 @@ import {addToViewTree, createLContainer, createLView, createTNode, createTView, getOrCreateTNode, refreshView, renderView} from '../../../src/render3/instructions/shared'; import {ComponentTemplate, DirectiveDefList} from '../../../src/render3/interfaces/definition'; import {TAttributes, TNodeType, TViewNode} from '../../../src/render3/interfaces/node'; -import {RendererFactory3, domRendererFactory3} from '../../../src/render3/interfaces/renderer'; +import {domRendererFactory3, RendererFactory3} from '../../../src/render3/interfaces/renderer'; import {LView, LViewFlags, TVIEW, TView, TViewType} from '../../../src/render3/interfaces/view'; import {insertView} from '../../../src/render3/node_manipulation'; @@ -28,9 +28,9 @@ export function createAndRenderLView( } export function setupRootViewWithEmbeddedViews( - templateFn: ComponentTemplate<any>| null, decls: number, vars: number, noOfViews: number, - embeddedViewContext: any = {}, consts: TAttributes[] | null = null, - directiveRegistry: DirectiveDefList | null = null): LView { + templateFn: ComponentTemplate<any>|null, decls: number, vars: number, noOfViews: number, + embeddedViewContext: any = {}, consts: TAttributes[]|null = null, + directiveRegistry: DirectiveDefList|null = null): LView { return setupTestHarness( templateFn, decls, vars, noOfViews, embeddedViewContext, consts, directiveRegistry) .hostLView; @@ -45,9 +45,9 @@ export interface TestHarness { } export function setupTestHarness( - templateFn: ComponentTemplate<any>| null, decls: number, vars: number, noOfViews: number, - embeddedViewContext: any = {}, consts: TAttributes[] | null = null, - directiveRegistry: DirectiveDefList | null = null): TestHarness { + templateFn: ComponentTemplate<any>|null, decls: number, vars: number, noOfViews: number, + embeddedViewContext: any = {}, consts: TAttributes[]|null = null, + directiveRegistry: DirectiveDefList|null = null): TestHarness { // Create a root view with a container const hostTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, consts); const tContainerNode = getOrCreateTNode(hostTView, null, 0, TNodeType.Container, null, null); diff --git a/packages/core/test/render3/perf/shared.ts b/packages/core/test/render3/perf/shared.ts index 353a03046eacf..55038df751b60 100644 --- a/packages/core/test/render3/perf/shared.ts +++ b/packages/core/test/render3/perf/shared.ts @@ -19,5 +19,7 @@ export function defineBenchmarkTestDirective( } class FakeDirectiveType { - static ɵfac = () => { return {}; }; + static ɵfac = () => { + return {}; + } } diff --git a/packages/core/test/render3/perf/view_destroy_hook/index.ts b/packages/core/test/render3/perf/view_destroy_hook/index.ts index 67f61095603c6..98aa6de0b97b5 100644 --- a/packages/core/test/render3/perf/view_destroy_hook/index.ts +++ b/packages/core/test/render3/perf/view_destroy_hook/index.ts @@ -55,7 +55,7 @@ const rootLView = createLView( null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {}, LViewFlags.IsRoot, null, null); -const viewTNode = createTNode(null !, null, TNodeType.View, -1, null, null) as TViewNode; +const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode; const embeddedTView = createTView( TViewType.Embedded, -1, testTemplate, 21, 10, [ToDestroy.ɵdir], null, null, null, [['to-destroy']]); diff --git a/packages/core/test/render3/pipe_spec.ts b/packages/core/test/render3/pipe_spec.ts index 06584ce27fdd6..81312294362ff 100644 --- a/packages/core/test/render3/pipe_spec.ts +++ b/packages/core/test/render3/pipe_spec.ts @@ -32,9 +32,13 @@ describe('pipe', () => { describe('WrappedValue', () => { @Pipe({name: 'wrappingPipe'}) class WrappingPipe implements PipeTransform { - transform(value: any) { return new WrappedValue('Bar'); } + transform(value: any) { + return new WrappedValue('Bar'); + } - static ɵfac = function WrappingPipe_Factory() { return new WrappingPipe(); }; + static ɵfac = function WrappingPipe_Factory() { + return new WrappingPipe(); + }; static ɵpipe = ɵɵdefinePipe({name: 'wrappingPipe', type: WrappingPipe, pure: false}); } @@ -43,7 +47,9 @@ describe('pipe', () => { ɵɵpipe(1, 'wrappingPipe'); } - function updateTemplate() { ɵɵtextInterpolate1('', ɵɵpipeBind1(1, 1, null), ''); } + function updateTemplate() { + ɵɵtextInterpolate1('', ɵɵpipeBind1(1, 1, null), ''); + } it('should unwrap', () => { const fixture = @@ -56,7 +62,7 @@ describe('pipe', () => { new TemplateFixture(createTemplate, updateTemplate, 2, 3, undefined, [WrappingPipe]); expect(fixture.html).toEqual('Bar'); - fixture.hostElement.childNodes[0] !.textContent = 'Foo'; + fixture.hostElement.childNodes[0]!.textContent = 'Foo'; expect(fixture.html).toEqual('Foo'); fixture.update(); @@ -71,7 +77,9 @@ describe('pipe', () => { it('should be able to use DI in a Pipe that extends an Injectable', () => { @Injectable({providedIn: 'root'}) class SayHelloService { - getHello() { return 'Hello there'; } + getHello() { + return 'Hello there'; + } static ɵfac = () => new SayHelloService(); static ɵprov = ɵɵdefineInjectable( {token: SayHelloService, factory: SayHelloService.ɵfac, providedIn: 'root'}); @@ -80,13 +88,15 @@ describe('pipe', () => { @Injectable() class ParentPipe { constructor(protected sayHelloService: SayHelloService) {} - static ɵfac = (t?: any) => new (t || ParentPipe)(ɵɵinject(SayHelloService)); + static ɵfac = (t?: any) => new(t || ParentPipe)(ɵɵinject(SayHelloService)); static ɵprov = ɵɵdefineInjectable({token: ParentPipe, factory: ParentPipe.ɵfac}); } @Pipe({name: 'sayHello', pure: true}) class SayHelloPipe extends ParentPipe implements PipeTransform { - transform() { return this.sayHelloService.getHello(); } + transform() { + return this.sayHelloService.getHello(); + } static ɵfac = (t?: any) => ɵɵgetInheritedFactory(t || SayHelloPipe)(SayHelloPipe); static ɵpipe = ɵɵdefinePipe({name: 'sayHello', type: SayHelloPipe, pure: true}); } @@ -96,10 +106,11 @@ describe('pipe', () => { ɵɵtext(0); ɵɵpipe(1, 'sayHello'); }, - () => { ɵɵtextInterpolate1('', ɵɵpipeBind1(1, 1, null), ''); }, 2, 3, undefined, - [SayHelloPipe]); + () => { + ɵɵtextInterpolate1('', ɵɵpipeBind1(1, 1, null), ''); + }, + 2, 3, undefined, [SayHelloPipe]); expect(fixture.html).toBe('Hello there'); }); - }); diff --git a/packages/core/test/render3/providers_spec.ts b/packages/core/test/render3/providers_spec.ts index 566bcd8538983..6f3e25d003404 100644 --- a/packages/core/test/render3/providers_spec.ts +++ b/packages/core/test/render3/providers_spec.ts @@ -6,10 +6,10 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component as _Component, ComponentFactoryResolver, ElementRef, InjectFlags, Injectable as _Injectable, InjectionToken, InjectorType, Provider, RendererFactory2, ViewContainerRef, ɵNgModuleDef as NgModuleDef, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵinject} from '../../src/core'; +import {Component as _Component, ComponentFactoryResolver, ElementRef, Injectable as _Injectable, InjectFlags, InjectionToken, InjectorType, Provider, RendererFactory2, ViewContainerRef, ɵNgModuleDef as NgModuleDef, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵinject} from '../../src/core'; import {forwardRef} from '../../src/di/forward_ref'; import {createInjector} from '../../src/di/r3_injector'; -import {injectComponentFactoryResolver, ɵɵProvidersFeature, ɵɵadvance, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵtextInterpolate1} from '../../src/render3/index'; +import {injectComponentFactoryResolver, ɵɵadvance, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵProvidersFeature, ɵɵtextInterpolate1} from '../../src/render3/index'; import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵtext, ɵɵtextInterpolate} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {NgModuleFactory} from '../../src/render3/ng_module_ref'; @@ -30,7 +30,9 @@ const Injectable: typeof _Injectable = function(...args: any[]): any { describe('providers', () => { describe('should support all types of Provider:', () => { - abstract class Greeter { abstract greet: string; } + abstract class Greeter { + abstract greet: string; + } const GREETER = new InjectionToken<Greeter>('greeter'); @@ -50,13 +52,17 @@ describe('providers', () => { } class GreeterProvider { - provide() { return 'Provided'; } + provide() { + return 'Provided'; + } } @Injectable() class GreeterInj implements Greeter { public greet: string; - constructor(private provider: GreeterProvider) { this.greet = this.provider.provide(); } + constructor(private provider: GreeterProvider) { + this.greet = this.provider.provide(); + } static ɵprov = ɵɵdefineInjectable({ token: GreeterInj, @@ -68,8 +74,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [GreeterClass], - componentAssertion: - () => { expect(ɵɵdirectiveInject(GreeterClass).greet).toEqual('Class'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GreeterClass).greet).toEqual('Class'); + } } }); }); @@ -78,7 +85,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [{provide: GREETER, useValue: {greet: 'Value'}}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Value'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Value'); + } } }); }); @@ -87,7 +96,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [{provide: GREETER, useClass: GreeterClass}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); + } } }); }); @@ -96,7 +107,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [GreeterClass, {provide: GREETER, useExisting: GreeterClass}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); + } } }); }); @@ -105,7 +118,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [GreeterClass, {provide: GREETER, useFactory: () => new GreeterClass()}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); + } } }); }); @@ -119,7 +134,9 @@ describe('providers', () => { {provide: MESSAGE, useValue: 'Message'}, {provide: GREETER, useClass: GreeterDeps, deps: [MESSAGE]} ], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message'); + } } }); }); @@ -131,8 +148,9 @@ describe('providers', () => { {provide: MESSAGE, useValue: 'Message'}, {provide: GREETER, useClass: GreeterBuiltInDeps, deps: [MESSAGE, ElementRef]} ], - componentAssertion: - () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message from PARENT'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message from PARENT'); + } } }); }); @@ -144,7 +162,9 @@ describe('providers', () => { {provide: MESSAGE, useValue: 'Message'}, {provide: GREETER, useFactory: (msg: string) => new GreeterDeps(msg), deps: [MESSAGE]} ], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message'); + } } }); }); @@ -156,12 +176,13 @@ describe('providers', () => { {provide: MESSAGE, useValue: 'Message'}, { provide: GREETER, useFactory: (msg: string, elementRef: ElementRef) => - new GreeterBuiltInDeps(msg, elementRef), + new GreeterBuiltInDeps(msg, elementRef), deps: [MESSAGE, ElementRef] } ], - componentAssertion: - () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message from PARENT'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Message from PARENT'); + } } }); }); @@ -170,8 +191,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [GreeterProvider, {provide: GREETER, useClass: GreeterInj}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Provided'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Provided'); + } } }); }); @@ -182,8 +204,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [forwardRef(() => ForLater)], - componentAssertion: - () => { expect(ɵɵdirectiveInject(ForLater) instanceof ForLater).toBeTruthy(); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(ForLater) instanceof ForLater).toBeTruthy(); + } } }); done(); @@ -196,9 +219,15 @@ describe('providers', () => { it('ValueProvider wrapped in forwardRef', () => { expectProvidersScenario({ parent: { - providers: - [{provide: GREETER, useValue: forwardRef(() => { return {greet: 'Value'}; })}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Value'); } + providers: [{ + provide: GREETER, + useValue: forwardRef(() => { + return {greet: 'Value'}; + }) + }], + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Value'); + } } }); }); @@ -207,7 +236,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [{provide: GREETER, useClass: forwardRef(() => GreeterClass)}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); + } } }); }); @@ -217,7 +248,9 @@ describe('providers', () => { parent: { providers: [GreeterClass, {provide: GREETER, useExisting: forwardRef(() => GreeterClass)}], - componentAssertion: () => { expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(GREETER).greet).toEqual('Class'); + } } }); }); @@ -233,9 +266,7 @@ describe('providers', () => { } }); }); - }); - }); /* @@ -258,7 +289,9 @@ describe('providers', () => { parent: { providers: [{provide: String, useValue: 'Message 1'}], directiveProviders: [{provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -268,7 +301,9 @@ describe('providers', () => { parent: { providers: [{provide: String, useValue: 'Message 1'}], viewProviders: [{provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -278,7 +313,9 @@ describe('providers', () => { parent: { directiveProviders: [{provide: String, useValue: 'Message 1'}], viewProviders: [{provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -288,7 +325,9 @@ describe('providers', () => { parent: { directive2Providers: [{provide: String, useValue: 'Message 1'}], directiveProviders: [{provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -298,7 +337,9 @@ describe('providers', () => { parent: { providers: [{provide: String, useValue: 'Message 1'}, {provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -308,7 +349,9 @@ describe('providers', () => { parent: { viewProviders: [{provide: String, useValue: 'Message 1'}, {provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -318,7 +361,9 @@ describe('providers', () => { parent: { directiveProviders: [{provide: String, useValue: 'Message 1'}, {provide: String, useValue: 'Message 2'}], - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('Message 2'); + } } }); }); @@ -334,16 +379,28 @@ describe('providers', () => { it('should work without providers nor viewProviders in component', () => { expectProvidersScenario({ parent: { - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); }, - directiveAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + } }, viewChild: { - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); }, - directiveAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + } }, contentChild: { - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); }, - directiveAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + } }, ngModule: MyModule }); @@ -353,22 +410,28 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [{provide: String, useValue: 'From providers'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + } }, ngModule: MyModule }); @@ -378,19 +441,28 @@ describe('providers', () => { expectProvidersScenario({ parent: { viewProviders: [{provide: String, useValue: 'From viewProviders'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + } }, contentChild: { - componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); }, - directiveAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual('From module'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From module'); + } }, ngModule: MyModule }); @@ -401,22 +473,28 @@ describe('providers', () => { parent: { providers: [{provide: String, useValue: 'From providers'}], viewProviders: [{provide: String, useValue: 'From viewProviders'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From providers'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From providers'); + } }, ngModule: MyModule }); @@ -429,22 +507,28 @@ describe('providers', () => { parent: { directiveProviders: [{provide: String, useValue: 'From directive'}], directive2Providers: [{provide: String, useValue: 'Never'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, ngModule: MyModule }); @@ -456,22 +540,28 @@ describe('providers', () => { providers: [{provide: String, useValue: 'From providers'}], directiveProviders: [{provide: String, useValue: 'From directive'}], directive2Providers: [{provide: String, useValue: 'Never'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, ngModule: MyModule }); @@ -483,22 +573,28 @@ describe('providers', () => { viewProviders: [{provide: String, useValue: 'From viewProviders'}], directiveProviders: [{provide: String, useValue: 'From directive'}], directive2Providers: [{provide: String, useValue: 'Never'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, ngModule: MyModule }); @@ -511,22 +607,28 @@ describe('providers', () => { viewProviders: [{provide: String, useValue: 'From viewProviders'}], directiveProviders: [{provide: String, useValue: 'From directive'}], directive2Providers: [{provide: String, useValue: 'Never'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From viewProviders'); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual('From directive'); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual('From directive'); + } }, ngModule: MyModule }); @@ -546,22 +648,28 @@ describe('providers', () => { it('should work without providers nor viewProviders in component', () => { expectProvidersScenario({ parent: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + } }, ngModule: MyModule }); @@ -571,22 +679,28 @@ describe('providers', () => { expectProvidersScenario({ parent: { providers: [{provide: String, useValue: 'From providers', multi: true}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + } }, ngModule: MyModule }); @@ -596,22 +710,28 @@ describe('providers', () => { expectProvidersScenario({ parent: { viewProviders: [{provide: String, useValue: 'From viewProviders', multi: true}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From viewProviders']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From viewProviders']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + } }, viewChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From viewProviders']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From viewProviders']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From viewProviders']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From viewProviders']); + } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From module']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From module']); + } }, ngModule: MyModule }); @@ -625,8 +745,9 @@ describe('providers', () => { componentAssertion: () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers', 'From viewProviders']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); } + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + } }, viewChild: { componentAssertion: () => { @@ -637,10 +758,12 @@ describe('providers', () => { } }, contentChild: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); }, - directiveAssertion: - () => { expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + }, + directiveAssertion: () => { + expect(ɵɵdirectiveInject(String)).toEqual(['From providers']); + } }, ngModule: MyModule }); @@ -825,8 +948,9 @@ describe('providers', () => { expectProvidersScenario({ parent: { - componentAssertion: - () => { expect(ɵɵdirectiveInject(FooForRoot) instanceof FooForRoot).toBeTruthy(); } + componentAssertion: () => { + expect(ɵɵdirectiveInject(FooForRoot) instanceof FooForRoot).toBeTruthy(); + } } }); }); @@ -868,24 +992,27 @@ describe('providers', () => { constructor(private s: String, private n: Number) {} static ɵfac = - () => { return new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)); } + () => { + return new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)); + } static ɵcmp = ɵɵdefineComponent({ type: Repeated, selectors: [['repeated']], decls: 2, vars: 2, - template: function(fs: RenderFlags, ctx: Repeated) { - if (fs & RenderFlags.Create) { - ɵɵtext(0); - ɵɵtext(1); - } - if (fs & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.s); - ɵɵadvance(1); - ɵɵtextInterpolate(ctx.n); - } - } + template: + function(fs: RenderFlags, ctx: Repeated) { + if (fs & RenderFlags.Create) { + ɵɵtext(0); + ɵɵtext(1); + } + if (fs & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.s); + ɵɵadvance(1); + ɵɵtextInterpolate(ctx.n); + } + } }); } @@ -906,33 +1033,38 @@ describe('providers', () => { selectors: [['component-with-providers']], decls: 2, vars: 0, - template: function(fs: RenderFlags, ctx: ComponentWithProviders) { - if (fs & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - { ɵɵcontainer(1); } - ɵɵelementEnd(); - } - if (fs & RenderFlags.Update) { - ɵɵcontainerRefreshStart(1); - { - for (let i = 0; i < 3; i++) { - let rf1 = ɵɵembeddedViewStart(1, 1, 0); + template: + function(fs: RenderFlags, ctx: ComponentWithProviders) { + if (fs & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + { ɵɵcontainer(1); } + ɵɵelementEnd(); + } + if (fs & RenderFlags.Update) { + ɵɵcontainerRefreshStart(1); { - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'repeated'); + for (let i = 0; i < 3; i++) { + let rf1 = ɵɵembeddedViewStart(1, 1, 0); + { + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'repeated'); + } + } + ɵɵembeddedViewEnd(); } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, - features: [ - ɵɵProvidersFeature( - [{provide: Number, useValue: 1, multi: true}], - [{provide: String, useValue: 'foo'}, {provide: Number, useValue: 2, multi: true}]), - ], + }, + features: + [ + ɵɵProvidersFeature( + [{provide: Number, useValue: 1, multi: true}], + [ + {provide: String, useValue: 'foo'}, + {provide: Number, useValue: 2, multi: true} + ]), + ], directives: [Repeated] }); } @@ -954,29 +1086,36 @@ describe('providers', () => { constructor(private s: String, private n: Number) {} static ɵfac = - () => { return new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)); } + () => { + return new Repeated(ɵɵdirectiveInject(String), ɵɵdirectiveInject(Number)); + } static ɵcmp = ɵɵdefineComponent({ type: Repeated, selectors: [['repeated']], decls: 2, vars: 2, - template: function(fs: RenderFlags, ctx: Repeated) { - if (fs & RenderFlags.Create) { - ɵɵtext(0); - ɵɵtext(1); - } - if (fs & RenderFlags.Update) { - ɵɵtextInterpolate(ctx.s); - ɵɵadvance(1); - ɵɵtextInterpolate(ctx.n); - } - }, - features: [ - ɵɵProvidersFeature( - [{provide: Number, useValue: 1, multi: true}], - [{provide: String, useValue: 'bar'}, {provide: Number, useValue: 2, multi: true}]), - ], + template: + function(fs: RenderFlags, ctx: Repeated) { + if (fs & RenderFlags.Create) { + ɵɵtext(0); + ɵɵtext(1); + } + if (fs & RenderFlags.Update) { + ɵɵtextInterpolate(ctx.s); + ɵɵadvance(1); + ɵɵtextInterpolate(ctx.n); + } + }, + features: + [ + ɵɵProvidersFeature( + [{provide: Number, useValue: 1, multi: true}], + [ + {provide: String, useValue: 'bar'}, + {provide: Number, useValue: 2, multi: true} + ]), + ], }); } @@ -995,28 +1134,29 @@ describe('providers', () => { selectors: [['component-with-providers']], decls: 2, vars: 0, - template: function(fs: RenderFlags, ctx: ComponentWithProviders) { - if (fs & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - { ɵɵcontainer(1); } - ɵɵelementEnd(); - } - if (fs & RenderFlags.Update) { - ɵɵcontainerRefreshStart(1); - { - for (let i = 0; i < 3; i++) { - let rf1 = ɵɵembeddedViewStart(1, 1, 0); + template: + function(fs: RenderFlags, ctx: ComponentWithProviders) { + if (fs & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + { ɵɵcontainer(1); } + ɵɵelementEnd(); + } + if (fs & RenderFlags.Update) { + ɵɵcontainerRefreshStart(1); { - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'repeated'); + for (let i = 0; i < 3; i++) { + let rf1 = ɵɵembeddedViewStart(1, 1, 0); + { + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'repeated'); + } + } + ɵɵembeddedViewEnd(); } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, + }, features: [ɵɵProvidersFeature([], [{provide: String, useValue: 'foo'}])], directives: [Repeated] }); @@ -1044,14 +1184,15 @@ describe('providers', () => { selectors: [['embedded-cmp']], decls: 1, vars: 1, - template: (rf: RenderFlags, cmp: EmbeddedComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0); - } - if (rf & RenderFlags.Update) { - ɵɵtextInterpolate1('', cmp.s, ''); - } - } + template: + (rf: RenderFlags, cmp: EmbeddedComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0); + } + if (rf & RenderFlags.Update) { + ɵɵtextInterpolate1('', cmp.s, ''); + } + } }); } @@ -1067,14 +1208,16 @@ describe('providers', () => { selectors: [['host-cmp']], decls: 1, vars: 0, - template: (rf: RenderFlags, cmp: HostComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'foo'); - } - }, - features: [ - ɵɵProvidersFeature([{provide: String, useValue: 'From host component'}]), - ], + template: + (rf: RenderFlags, cmp: HostComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'foo'); + } + }, + features: + [ + ɵɵProvidersFeature([{provide: String, useValue: 'From host component'}]), + ], }); } @@ -1091,14 +1234,16 @@ describe('providers', () => { selectors: [['app-cmp']], decls: 1, vars: 0, - template: (rf: RenderFlags, cmp: AppComponent) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'host-cmp'); - } - }, - features: [ - ɵɵProvidersFeature([{provide: String, useValue: 'From app component'}]), - ], + template: + (rf: RenderFlags, cmp: AppComponent) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'host-cmp'); + } + }, + features: + [ + ɵɵProvidersFeature([{provide: String, useValue: 'From app component'}]), + ], directives: [HostComponent] }); } @@ -1107,8 +1252,8 @@ describe('providers', () => { const fixture = new ComponentFixture(AppComponent); expect(fixture.html).toEqual('<host-cmp>foo</host-cmp>'); - hostComponent !.vcref.createComponent( - hostComponent !.cfr.resolveComponentFactory(EmbeddedComponent), undefined, { + hostComponent!.vcref.createComponent( + hostComponent!.cfr.resolveComponentFactory(EmbeddedComponent), undefined, { get: (token: any, notFoundValue?: any) => { return token === String ? 'From custom root view injector' : notFoundValue; } @@ -1121,7 +1266,6 @@ describe('providers', () => { it('should not cross the root view boundary, and use the module injector if no root view injector', () => { - const fixture = new ComponentFixture(AppComponent); expect(fixture.html).toEqual('<host-cmp>foo</host-cmp>'); @@ -1129,18 +1273,19 @@ describe('providers', () => { static ɵinj = ɵɵdefineInjector({ factory: () => new MyAppModule(), imports: [], - providers: [ - {provide: RendererFactory2, useValue: getRendererFactory2(document)}, - {provide: String, useValue: 'From module injector'} - ] + providers: + [ + {provide: RendererFactory2, useValue: getRendererFactory2(document)}, + {provide: String, useValue: 'From module injector'} + ] }); - static ɵmod: NgModuleDef<any> = { bootstrap: [] } as any; + static ɵmod: NgModuleDef<any> = {bootstrap: []} as any; } const myAppModuleFactory = new NgModuleFactory(MyAppModule); const ngModuleRef = myAppModuleFactory.create(null); - hostComponent !.vcref.createComponent( - hostComponent !.cfr.resolveComponentFactory(EmbeddedComponent), undefined, + hostComponent!.vcref.createComponent( + hostComponent!.cfr.resolveComponentFactory(EmbeddedComponent), undefined, {get: (token: any, notFoundValue?: any) => notFoundValue}, undefined, ngModuleRef); fixture.update(); expect(fixture.html) @@ -1153,8 +1298,8 @@ describe('providers', () => { const fixture = new ComponentFixture(AppComponent); expect(fixture.html).toEqual('<host-cmp>foo</host-cmp>'); - hostComponent !.vcref.createComponent( - hostComponent !.cfr.resolveComponentFactory(EmbeddedComponent)); + hostComponent!.vcref.createComponent( + hostComponent!.cfr.resolveComponentFactory(EmbeddedComponent)); fixture.update(); expect(fixture.html) .toEqual('<host-cmp>foo</host-cmp><embedded-cmp>From app component</embedded-cmp>'); @@ -1201,8 +1346,9 @@ describe('providers', () => { }, viewChild: { providers: [{provide: String, useValue: 'view'}], - componentAssertion: - () => { expect(ɵɵdirectiveInject(Greeter).greeting).toEqual('parent'); }, + componentAssertion: () => { + expect(ɵɵdirectiveInject(Greeter).greeting).toEqual('parent'); + }, }, }); }); @@ -1228,7 +1374,9 @@ describe('providers', () => { }); describe('from a node without injector', () => { - abstract class Some { abstract location: String; } + abstract class Some { + abstract location: String; + } class SomeInj implements Some { constructor(public location: String) {} @@ -1253,16 +1401,18 @@ describe('providers', () => { selectors: [['my-cmp']], decls: 1, vars: 0, - template: (rf: RenderFlags, cmp: MyComponent) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'p'); - } - }, - features: [ - ɵɵProvidersFeature( - [{provide: String, useValue: 'From my component'}], - [{provide: Number, useValue: 123}]), - ], + template: + (rf: RenderFlags, cmp: MyComponent) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'p'); + } + }, + features: + [ + ɵɵProvidersFeature( + [{provide: String, useValue: 'From my component'}], + [{provide: Number, useValue: 123}]), + ], }); } @@ -1280,16 +1430,19 @@ describe('providers', () => { selectors: [['app-cmp']], decls: 1, vars: 0, - template: (rf: RenderFlags, cmp: AppComponent) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'my-cmp'); - } - }, - features: [ - ɵɵProvidersFeature([ - {provide: String, useValue: 'From app component'}, {provide: Some, useClass: SomeInj} - ]), - ], + template: + (rf: RenderFlags, cmp: AppComponent) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'my-cmp'); + } + }, + features: + [ + ɵɵProvidersFeature([ + {provide: String, useValue: 'From app component'}, + {provide: Some, useClass: SomeInj} + ]), + ], directives: [MyComponent] }); } @@ -1323,14 +1476,30 @@ describe('providers', () => { @Injectable() class InjectableWithLifeCycleHooks { - ngOnChanges() { logs.push('Injectable OnChanges'); } - ngOnInit() { logs.push('Injectable OnInit'); } - ngDoCheck() { logs.push('Injectable DoCheck'); } - ngAfterContentInit() { logs.push('Injectable AfterContentInit'); } - ngAfterContentChecked() { logs.push('Injectable AfterContentChecked'); } - ngAfterViewInit() { logs.push('Injectable AfterViewInit'); } - ngAfterViewChecked() { logs.push('Injectable gAfterViewChecked'); } - ngOnDestroy() { logs.push('Injectable OnDestroy'); } + ngOnChanges() { + logs.push('Injectable OnChanges'); + } + ngOnInit() { + logs.push('Injectable OnInit'); + } + ngDoCheck() { + logs.push('Injectable DoCheck'); + } + ngAfterContentInit() { + logs.push('Injectable AfterContentInit'); + } + ngAfterContentChecked() { + logs.push('Injectable AfterContentChecked'); + } + ngAfterViewInit() { + logs.push('Injectable AfterViewInit'); + } + ngAfterViewChecked() { + logs.push('Injectable gAfterViewChecked'); + } + ngOnDestroy() { + logs.push('Injectable OnDestroy'); + } } @Component({template: `<span></span>`, providers: [InjectableWithLifeCycleHooks]}) @@ -1338,18 +1507,21 @@ describe('providers', () => { constructor(foo: InjectableWithLifeCycleHooks) {} static ɵfac = - () => { return new MyComponent(ɵɵdirectiveInject(InjectableWithLifeCycleHooks)); } + () => { + return new MyComponent(ɵɵdirectiveInject(InjectableWithLifeCycleHooks)); + } static ɵcmp = ɵɵdefineComponent({ type: MyComponent, selectors: [['my-comp']], decls: 1, vars: 0, - template: (rf: RenderFlags, ctx: MyComponent) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'span'); - } - }, + template: + (rf: RenderFlags, ctx: MyComponent) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'span'); + } + }, features: [ɵɵProvidersFeature([InjectableWithLifeCycleHooks])] }); } @@ -1372,28 +1544,29 @@ describe('providers', () => { selectors: [['app-cmp']], decls: 2, vars: 0, - template: (rf: RenderFlags, ctx: App) => { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'div'); - { ɵɵcontainer(1); } - ɵɵelementEnd(); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(1); - { - if (ctx.condition) { - let rf1 = ɵɵembeddedViewStart(1, 2, 1); + template: + (rf: RenderFlags, ctx: App) => { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'div'); + { ɵɵcontainer(1); } + ɵɵelementEnd(); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(1); { - if (rf1 & RenderFlags.Create) { - ɵɵelement(0, 'my-comp'); + if (ctx.condition) { + let rf1 = ɵɵembeddedViewStart(1, 2, 1); + { + if (rf1 & RenderFlags.Create) { + ɵɵelement(0, 'my-comp'); + } + } + ɵɵembeddedViewEnd(); } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, + }, directives: [MyComponent] }); } @@ -1407,7 +1580,6 @@ describe('providers', () => { expect(fixture.html).toEqual('<div></div>'); expect(logs).toEqual(['Injectable OnDestroy']); }); - }); }); interface ComponentTest { @@ -1426,14 +1598,14 @@ function expectProvidersScenario(defs: { contentChild?: ComponentTest, ngModule?: InjectorType<any>, }): void { - function testComponentInjection<T>(def: ComponentTest | undefined, instance: T): T { + function testComponentInjection<T>(def: ComponentTest|undefined, instance: T): T { if (def) { def.componentAssertion && def.componentAssertion(); } return instance; } - function testDirectiveInjection<T>(def: ComponentTest | undefined, instance: T): T { + function testDirectiveInjection<T>(def: ComponentTest|undefined, instance: T): T { if (def) { def.directiveAssertion && def.directiveAssertion(); } @@ -1447,11 +1619,12 @@ function expectProvidersScenario(defs: { selectors: [['view-child']], decls: 1, vars: 0, - template: function(fs: RenderFlags, ctx: ViewChildComponent) { - if (fs & RenderFlags.Create) { - ɵɵtext(0, 'view-child'); - } - }, + template: + function(fs: RenderFlags, ctx: ViewChildComponent) { + if (fs & RenderFlags.Create) { + ɵɵtext(0, 'view-child'); + } + }, features: defs.viewChild && [ɵɵProvidersFeature(defs.viewChild.providers || [], defs.viewChild.viewProviders || [])] }); @@ -1468,18 +1641,21 @@ function expectProvidersScenario(defs: { class ContentChildComponent { static ɵfac = - () => { return testComponentInjection(defs.contentChild, new ContentChildComponent()); } + () => { + return testComponentInjection(defs.contentChild, new ContentChildComponent()); + } static ɵcmp = ɵɵdefineComponent({ type: ContentChildComponent, selectors: [['content-child']], decls: 1, vars: 0, - template: function(fs: RenderFlags, ctx: ParentComponent) { - if (fs & RenderFlags.Create) { - ɵɵtext(0, 'content-child'); - } - }, + template: + function(fs: RenderFlags, ctx: ParentComponent) { + if (fs & RenderFlags.Create) { + ɵɵtext(0, 'content-child'); + } + }, features: defs.contentChild && [ɵɵProvidersFeature( defs.contentChild.providers || [], defs.contentChild.viewProviders || [])], @@ -1488,13 +1664,15 @@ function expectProvidersScenario(defs: { class ContentChildDirective { static ɵfac = - () => { return testDirectiveInjection(defs.contentChild, new ContentChildDirective()); } + () => { + return testDirectiveInjection(defs.contentChild, new ContentChildDirective()); + } static ɵdir = ɵɵdefineDirective({ type: ContentChildDirective, selectors: [['content-child']], - features: - defs.contentChild && [ɵɵProvidersFeature(defs.contentChild.directiveProviders || [])], + features: defs.contentChild && + [ɵɵProvidersFeature(defs.contentChild.directiveProviders || [])], }); } @@ -1506,11 +1684,12 @@ function expectProvidersScenario(defs: { selectors: [['parent']], decls: 1, vars: 0, - template: function(fs: RenderFlags, ctx: ParentComponent) { - if (fs & RenderFlags.Create) { - ɵɵelement(0, 'view-child'); - } - }, + template: + function(fs: RenderFlags, ctx: ParentComponent) { + if (fs & RenderFlags.Create) { + ɵɵelement(0, 'view-child'); + } + }, features: defs.parent && [ɵɵProvidersFeature(defs.parent.providers || [], defs.parent.viewProviders || [])], directives: [ViewChildComponent, ViewChildDirective] @@ -1543,19 +1722,21 @@ function expectProvidersScenario(defs: { selectors: [['app']], decls: 2, vars: 0, - template: function(fs: RenderFlags, ctx: App) { - if (fs & RenderFlags.Create) { - ɵɵelementStart(0, 'parent'); - ɵɵelement(1, 'content-child'); - ɵɵelementEnd(); - } - }, - features: - defs.app && [ɵɵProvidersFeature(defs.app.providers || [], defs.app.viewProviders || [])], - directives: [ - ParentComponent, ParentDirective2, ParentDirective, ContentChildComponent, - ContentChildDirective - ] + template: + function(fs: RenderFlags, ctx: App) { + if (fs & RenderFlags.Create) { + ɵɵelementStart(0, 'parent'); + ɵɵelement(1, 'content-child'); + ɵɵelementEnd(); + } + }, + features: defs.app && + [ɵɵProvidersFeature(defs.app.providers || [], defs.app.viewProviders || [])], + directives: + [ + ParentComponent, ParentDirective2, ParentDirective, ContentChildComponent, + ContentChildDirective + ] }); } diff --git a/packages/core/test/render3/pure_function_spec.ts b/packages/core/test/render3/pure_function_spec.ts index be5837e3a4a7a..940b8f2a2db6a 100644 --- a/packages/core/test/render3/pure_function_spec.ts +++ b/packages/core/test/render3/pure_function_spec.ts @@ -17,9 +17,11 @@ describe('object literals', () => { class ObjectComp { // TODO(issue/24571): remove '!'. - config !: {[key: string]: any}; + config!: {[key: string]: any}; - static ɵfac = function ObjectComp_Factory() { return objectComp = new ObjectComp(); }; + static ɵfac = function ObjectComp_Factory() { + return objectComp = new ObjectComp(); + }; static ɵcmp = ɵɵdefineComponent({ type: ObjectComp, selectors: [['object-comp']], @@ -70,7 +72,9 @@ describe('object literals', () => { } } - const e0_ff = (v1: any, v2: any) => { return {opacity: v1, duration: v2}; }; + const e0_ff = (v1: any, v2: any) => { + return {opacity: v1, duration: v2}; + }; const configs = [{opacity: 0, duration: 500}, {opacity: 1, duration: 600}]; renderToHtml(Template, {configs}, 1, 0, defs); @@ -82,5 +86,4 @@ describe('object literals', () => { expect(objectComps[0].config).toEqual({opacity: 0, duration: 1000}); expect(objectComps[1].config).toEqual({opacity: 1, duration: 600}); }); - }); diff --git a/packages/core/test/render3/query_spec.ts b/packages/core/test/render3/query_spec.ts index bf4f79d5a7d7f..9a688ecec0e56 100644 --- a/packages/core/test/render3/query_spec.ts +++ b/packages/core/test/render3/query_spec.ts @@ -9,7 +9,7 @@ import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core'; import {EventEmitter} from '../..'; -import {AttributeMarker, ɵɵProvidersFeature, ɵɵdefineComponent, ɵɵdefineDirective} from '../../src/render3/index'; +import {AttributeMarker, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵProvidersFeature} from '../../src/render3/index'; import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵdirectiveInject, ɵɵelement, ɵɵelementContainerEnd, ɵɵelementContainerStart, ɵɵelementEnd, ɵɵelementStart, ɵɵembeddedViewEnd, ɵɵembeddedViewStart, ɵɵtemplate, ɵɵtext} from '../../src/render3/instructions/all'; import {RenderFlags} from '../../src/render3/interfaces/definition'; import {ɵɵcontentQuery, ɵɵloadQuery, ɵɵqueryRefresh, ɵɵviewQuery} from '../../src/render3/query'; @@ -17,7 +17,7 @@ import {getLView} from '../../src/render3/state'; import {getNativeByIndex, load} from '../../src/render3/util/view_utils'; import {ɵɵtemplateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound'; -import {ComponentFixture, TemplateFixture, createComponent, createDirective, getDirectiveOnNode, renderComponent} from './render_util'; +import {ComponentFixture, createComponent, createDirective, getDirectiveOnNode, renderComponent, TemplateFixture} from './render_util'; @@ -99,7 +99,6 @@ describe('query', () => { describe('predicate', () => { describe('types', () => { - it('should query using type predicate and read a specified token', () => { const Child = createDirective('child'); let elToQuery; @@ -211,7 +210,6 @@ describe('query', () => { }); describe('providers', () => { - class Service {} class Alias {} @@ -234,7 +232,6 @@ describe('query', () => { // https://stackblitz.com/edit/ng-viewengine-viewchild-providers?file=src%2Fapp%2Fapp.component.ts it('should query for providers that are present on a directive', () => { - /** * <div myDir></div> * class App { @@ -248,43 +245,48 @@ describe('query', () => { service?: Service; alias?: Alias; - static ɵfac = function App_Factory() { return new App(); }; + static ɵfac = function App_Factory() { + return new App(); + }; static ɵcmp = ɵɵdefineComponent({ type: App, selectors: [['app']], decls: 1, vars: 0, consts: [['myDir']], - template: function App_Template(rf: RenderFlags, ctx: App) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0); - } - }, - viewQuery: function(rf: RenderFlags, ctx: App) { - if (rf & RenderFlags.Create) { - ɵɵviewQuery(MyDirective, false); - ɵɵviewQuery(Service, false); - ɵɵviewQuery(Alias, false); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && (ctx.directive = tmp.first); - ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && (ctx.service = tmp.first); - ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && (ctx.alias = tmp.first); - } - }, + template: + function App_Template(rf: RenderFlags, ctx: App) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 0); + } + }, + viewQuery: + function(rf: RenderFlags, ctx: App) { + if (rf & RenderFlags.Create) { + ɵɵviewQuery(MyDirective, false); + ɵɵviewQuery(Service, false); + ɵɵviewQuery(Alias, false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && + (ctx.directive = tmp.first); + ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && + (ctx.service = tmp.first); + ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && (ctx.alias = tmp.first); + } + }, directives: [MyDirective] }); } const componentFixture = new ComponentFixture(App); - expect(componentFixture.component.directive).toBe(directive !); - expect(componentFixture.component.service).toBe(directive !.service); - expect(componentFixture.component.alias).toBe(directive !.service); + expect(componentFixture.component.directive).toBe(directive!); + expect(componentFixture.component.service).toBe(directive!.service); + expect(componentFixture.component.alias).toBe(directive!.service); }); it('should resolve a provider if given as read token', () => { - /** * <div myDir></div> * class App { @@ -294,41 +296,43 @@ describe('query', () => { class App { service?: Service; - static ɵfac = function App_Factory() { return new App(); }; + static ɵfac = function App_Factory() { + return new App(); + }; static ɵcmp = ɵɵdefineComponent({ type: App, selectors: [['app']], decls: 1, vars: 0, consts: [['myDir']], - template: function App_Template(rf: RenderFlags, ctx: App) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 0); - } - }, - viewQuery: function(rf: RenderFlags, ctx: App) { - let tmp: any; - if (rf & RenderFlags.Create) { - ɵɵviewQuery(MyDirective, false, Alias); - } - if (rf & RenderFlags.Update) { - ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && (ctx.service = tmp.first); - } - }, + template: + function App_Template(rf: RenderFlags, ctx: App) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 0); + } + }, + viewQuery: + function(rf: RenderFlags, ctx: App) { + let tmp: any; + if (rf & RenderFlags.Create) { + ɵɵviewQuery(MyDirective, false, Alias); + } + if (rf & RenderFlags.Update) { + ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && + (ctx.service = tmp.first); + } + }, directives: [MyDirective] }); } const componentFixture = new ComponentFixture(App); - expect(componentFixture.component.service).toBe(directive !.service); + expect(componentFixture.component.service).toBe(directive!.service); }); - }); describe('local names', () => { - it('should query for a single element and read ElementRef by default', () => { - let elToQuery; /** * <div #foo></div> @@ -413,7 +417,6 @@ describe('query', () => { }); it('should query for multiple elements and read ElementRef by default', () => { - let el1ToQuery; let el2ToQuery; /** @@ -456,7 +459,6 @@ describe('query', () => { }); it('should read ElementRef from an element when explicitly asked for', () => { - let elToQuery; /** * <div #foo></div> @@ -652,7 +654,6 @@ describe('query', () => { }, 2, 0, [], [], function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { ɵɵviewQuery(['foo'], false, ElementRef); } @@ -822,7 +823,7 @@ describe('query', () => { const cmptInstance = renderComponent(Cmpt); const qList = (cmptInstance.query as QueryList<any>); expect(qList.length).toBe(1); - expect(qList.first).toBe(childInstance !); + expect(qList.first).toBe(childInstance!); }); it('should read directive instance if element queried for has an exported directive with a matching name', @@ -1294,7 +1295,6 @@ describe('query', () => { expect(elemQList.length).toBe(3); expect(isElementRef(elemQList.first)).toBeTruthy(); }); - }); }); @@ -1322,7 +1322,9 @@ describe('query', () => { }, [], [], undefined, [['foo', '']]); - function createTemplate() { ɵɵcontainer(0); } + function createTemplate() { + ɵɵcontainer(0); + } function updateTemplate() { ɵɵcontainerRefreshStart(0); @@ -1349,12 +1351,12 @@ describe('query', () => { const t = new TemplateFixture(createTemplate, updateTemplate, 1, 0, [SimpleComponentWithQuery]); expect(t.html).toEqual('<some-component-with-query><div></div></some-component-with-query>'); - expect((queryInstance !.changes as EventEmitter<any>).closed).toBeFalsy(); + expect((queryInstance!.changes as EventEmitter<any>).closed).toBeFalsy(); condition = false; t.update(); expect(t.html).toEqual(''); - expect((queryInstance !.changes as EventEmitter<any>).closed).toBeTruthy(); + expect((queryInstance!.changes as EventEmitter<any>).closed).toBeTruthy(); }); }); @@ -1411,15 +1413,19 @@ describe('query', () => { describe('content', () => { let withContentInstance: WithContentDirective|null; - beforeEach(() => { withContentInstance = null; }); + beforeEach(() => { + withContentInstance = null; + }); class WithContentDirective { // @ContentChildren('foo') - foos !: QueryList<ElementRef>; + foos!: QueryList<ElementRef>; contentInitQuerySnapshot = 0; contentCheckedQuerySnapshot = 0; - ngAfterContentInit() { this.contentInitQuerySnapshot = this.foos ? this.foos.length : 0; } + ngAfterContentInit() { + this.contentInitQuerySnapshot = this.foos ? this.foos.length : 0; + } ngAfterContentChecked() { this.contentCheckedQuerySnapshot = this.foos ? this.foos.length : 0; @@ -1429,15 +1435,16 @@ describe('query', () => { static ɵdir = ɵɵdefineDirective({ type: WithContentDirective, selectors: [['', 'with-content', '']], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, ['foo'], true); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.foos = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, ['foo'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.foos = tmp); + } + } }); } @@ -1460,15 +1467,15 @@ describe('query', () => { [[AttributeMarker.Bindings, 'with-content'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); - expect(withContentInstance !.foos.length) + expect(withContentInstance!.foos.length) .toBe(1, `Expected content query to match <span #foo>.`); - expect(withContentInstance !.contentInitQuerySnapshot) + expect(withContentInstance!.contentInitQuerySnapshot) .toBe( 1, `Expected content query results to be available when ngAfterContentInit was called.`); - expect(withContentInstance !.contentCheckedQuerySnapshot) + expect(withContentInstance!.contentCheckedQuerySnapshot) .toBe( 1, `Expected content query results to be available when ngAfterContentChecked was called.`); @@ -1509,15 +1516,15 @@ describe('query', () => { [[AttributeMarker.Bindings, 'with-content'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); - expect(withContentInstance !.foos.length) + expect(withContentInstance!.foos.length) .toBe(1, `Expected content query to match <span #foo>.`); - expect(withContentInstance !.contentInitQuerySnapshot) + expect(withContentInstance!.contentInitQuerySnapshot) .toBe( 1, `Expected content query results to be available when ngAfterContentInit was called.`); - expect(withContentInstance !.contentCheckedQuerySnapshot) + expect(withContentInstance!.contentCheckedQuerySnapshot) .toBe( 1, `Expected content query results to be available when ngAfterContentChecked was called.`); @@ -1539,7 +1546,7 @@ describe('query', () => { [['with-content', ''], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); - expect(withContentInstance !.foos.length) + expect(withContentInstance!.foos.length) .toBe(0, `Expected content query not to match <div with-content #foo>.`); }); @@ -1581,8 +1588,8 @@ describe('query', () => { const viewQList = fixture.component.foos; expect(viewQList.length).toBe(2); - expect(withContentInstance !.foos.length).toBe(1); - expect(viewQList.first.nativeElement).toBe(withContentInstance !.foos.first.nativeElement); + expect(withContentInstance!.foos.length).toBe(1); + expect(viewQList.first.nativeElement).toBe(withContentInstance!.foos.first.nativeElement); expect(viewQList.last.nativeElement.id).toBe('after'); }); @@ -1620,8 +1627,8 @@ describe('query', () => { [], [], undefined, [['with-content', ''], ['id', 'yes'], ['foo', '']]); const fixture = new ComponentFixture(AppComponent); - expect(withContentInstance !.foos.length).toBe(1); - expect(withContentInstance !.foos.first.nativeElement.id).toEqual('yes'); + expect(withContentInstance!.foos.length).toBe(1); + expect(withContentInstance!.foos.first.nativeElement.id).toEqual('yes'); }); it('should report results to appropriate queries where deep content queries are nested', () => { @@ -1632,17 +1639,18 @@ describe('query', () => { type: QueryDirective, selectors: [['', 'query', '']], exportAs: ['query'], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - // @ContentChildren('foo, bar, baz', {descendants: true}) - // fooBars: QueryList<ElementRef>; - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, ['foo', 'bar', 'baz'], true); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.fooBars = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo, bar, baz', {descendants: true}) + // fooBars: QueryList<ElementRef>; + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, ['foo', 'bar', 'baz'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.fooBars = tmp); + } + } }); } @@ -1684,8 +1692,8 @@ describe('query', () => { ]); const fixture = new ComponentFixture(AppComponent); - expect(outInstance !.fooBars.length).toBe(3); - expect(inInstance !.fooBars.length).toBe(1); + expect(outInstance!.fooBars.length).toBe(3); + expect(inInstance!.fooBars.length).toBe(1); }); @@ -1700,17 +1708,18 @@ describe('query', () => { type: QueryDirective, selectors: [['', 'query', '']], exportAs: ['query'], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - // @ContentChildren('foo', {descendants: true}) - // fooBars: QueryList<ElementRef>; - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, ['foo'], false); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.fooBars = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: true}) + // fooBars: QueryList<ElementRef>; + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.fooBars = tmp); + } + } }); } @@ -1740,13 +1749,12 @@ describe('query', () => { } }, 7, 0, [QueryDirective], [], null, [], [], undefined, [ - ['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], - ['foo', ''] + ['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], ['foo', ''] ]); const fixture = new ComponentFixture(AppComponent); - expect(outInstance !.fooBars.length).toBe(1); - expect(inInstance !.fooBars.length).toBe(1); + expect(outInstance!.fooBars.length).toBe(1); + expect(inInstance!.fooBars.length).toBe(1); }); it('should support nested shallow content queries across multiple component instances', () => { @@ -1760,17 +1768,18 @@ describe('query', () => { type: QueryDirective, selectors: [['', 'query', '']], exportAs: ['query'], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - // @ContentChildren('foo', {descendants: true}) - // fooBars: QueryList<ElementRef>; - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, ['foo'], false); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.fooBars = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: true}) + // fooBars: QueryList<ElementRef>; + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.fooBars = tmp); + } + } }); } @@ -1800,19 +1809,18 @@ describe('query', () => { } }, 7, 0, [QueryDirective], [], null, [], [], undefined, [ - ['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], - ['foo', ''] + ['query', ''], ['id', 'bar'], ['out', 'query'], ['in', 'query', 'foo', ''], ['foo', ''] ]); const fixture1 = new ComponentFixture(AppComponent); - expect(outInstance !.fooBars.length).toBe(1); - expect(inInstance !.fooBars.length).toBe(1); + expect(outInstance!.fooBars.length).toBe(1); + expect(inInstance!.fooBars.length).toBe(1); - outInstance = inInstance = null !; + outInstance = inInstance = null!; const fixture2 = new ComponentFixture(AppComponent); - expect(outInstance !.fooBars.length).toBe(1); - expect(inInstance !.fooBars.length).toBe(1); + expect(outInstance!.fooBars.length).toBe(1); + expect(inInstance!.fooBars.length).toBe(1); }); it('should respect shallow flag on content queries when mixing deep and shallow queries', @@ -1824,17 +1832,18 @@ describe('query', () => { type: ShallowQueryDirective, selectors: [['', 'shallow-query', '']], exportAs: ['shallow-query'], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - // @ContentChildren('foo', {descendants: false}) - // foos: QueryList<ElementRef>; - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, ['foo'], false); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.foos = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: false}) + // foos: QueryList<ElementRef>; + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, ['foo'], false); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.foos = tmp); + } + } }); } @@ -1845,17 +1854,18 @@ describe('query', () => { type: DeepQueryDirective, selectors: [['', 'deep-query', '']], exportAs: ['deep-query'], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - // @ContentChildren('foo', {descendants: true}) - // foos: QueryList<ElementRef>; - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, ['foo'], true); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.foos = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren('foo', {descendants: true}) + // foos: QueryList<ElementRef>; + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, ['foo'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<ElementRef>()) && (ctx.foos = tmp); + } + } }); } @@ -1866,7 +1876,7 @@ describe('query', () => { 'app-component', /** * <div shallow-query #shallow="shallow-query" deep-query #deep="deep-query"> - * <span #foo></span> + * <span #foo></span> * <div> * <span #foo></span> * </div> @@ -1895,14 +1905,14 @@ describe('query', () => { ]); const fixture = new ComponentFixture(AppComponent); - expect(shallowInstance !.foos.length).toBe(1); - expect(deepInstance !.foos.length).toBe(2); + expect(shallowInstance!.foos.length).toBe(1); + expect(deepInstance!.foos.length).toBe(2); }); }); describe('order', () => { class TextDirective { - value !: string; + value!: string; static ɵfac = () => new TextDirective(); static ɵdir = ɵɵdefineDirective( @@ -1914,39 +1924,40 @@ describe('query', () => { class ContentQueryDirective { // @ContentChildren(TextDirective) - texts !: QueryList<TextDirective>; + texts!: QueryList<TextDirective>; static ɵfac = () => contentQueryDirective = new ContentQueryDirective(); static ɵcmp = ɵɵdefineDirective({ type: ContentQueryDirective, selectors: [['', 'content-query', '']], - contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => { - // @ContentChildren(TextDirective, {descendants: true}) - // texts: QueryList<TextDirective>; - if (rf & RenderFlags.Create) { - ɵɵcontentQuery(dirIndex, TextDirective, true); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<TextDirective>()) && (ctx.texts = tmp); - } - } + contentQueries: + (rf: RenderFlags, ctx: any, dirIndex: number) => { + // @ContentChildren(TextDirective, {descendants: true}) + // texts: QueryList<TextDirective>; + if (rf & RenderFlags.Create) { + ɵɵcontentQuery(dirIndex, TextDirective, true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<TextDirective>()) && (ctx.texts = tmp); + } + } }); } const AppComponent = createComponent( 'app-component', /** - * <div content-query> - * <span text="A"></span> - * <div text="B"> - * <span text="C"> - * <span text="D"></span> - * </span> - * </div> - * <span text="E"></span> - * </div> - */ + * <div content-query> + * <span text="A"></span> + * <div text="B"> + * <span text="C"> + * <span text="D"></span> + * </span> + * </div> + * <span text="E"></span> + * </div> + */ function(rf: RenderFlags, ctx: any) { if (rf & RenderFlags.Create) { ɵɵelementStart(0, 'div', 0); @@ -1968,53 +1979,55 @@ describe('query', () => { ]); new ComponentFixture(AppComponent); - expect(contentQueryDirective !.texts.map(item => item.value)).toEqual([ + expect(contentQueryDirective!.texts.map(item => item.value)).toEqual([ 'A', 'B', 'C', 'D', 'E' ]); }); it('should register view matches from top to bottom', () => { /** - * <span text="A"></span> - * <div text="B"> - * <span text="C"> - * <span text="D"></span> - * </span> - * </div> - * <span text="E"></span> - */ + * <span text="A"></span> + * <div text="B"> + * <span text="C"> + * <span text="D"></span> + * </span> + * </div> + * <span text="E"></span> + */ class ViewQueryComponent { // @ViewChildren(TextDirective) - texts !: QueryList<TextDirective>; + texts!: QueryList<TextDirective>; static ɵfac = () => new ViewQueryComponent(); static ɵcmp = ɵɵdefineComponent({ type: ViewQueryComponent, selectors: [['view-query']], consts: [['text', 'A'], ['text', 'B'], ['text', 'C'], ['text', 'D'], ['text', 'E']], - template: function(rf: RenderFlags, ctx: ViewQueryComponent) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'span', 0); - ɵɵelementStart(1, 'div', 1); - ɵɵelementStart(2, 'span', 2); - { ɵɵelement(3, 'span', 3); } - ɵɵelementEnd(); - ɵɵelementEnd(); - ɵɵelement(4, 'span', 4); - } - }, + template: + function(rf: RenderFlags, ctx: ViewQueryComponent) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'span', 0); + ɵɵelementStart(1, 'div', 1); + ɵɵelementStart(2, 'span', 2); + { ɵɵelement(3, 'span', 3); } + ɵɵelementEnd(); + ɵɵelementEnd(); + ɵɵelement(4, 'span', 4); + } + }, decls: 5, vars: 0, - viewQuery: function(rf: RenderFlags, ctx: ViewQueryComponent) { - let tmp: any; - if (rf & RenderFlags.Create) { - ɵɵviewQuery(TextDirective, true); - } - if (rf & RenderFlags.Update) { - ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<TextDirective>>()) && - (ctx.texts = tmp as QueryList<TextDirective>); - } - }, + viewQuery: + function(rf: RenderFlags, ctx: ViewQueryComponent) { + let tmp: any; + if (rf & RenderFlags.Create) { + ɵɵviewQuery(TextDirective, true); + } + if (rf & RenderFlags.Update) { + ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<TextDirective>>()) && + (ctx.texts = tmp as QueryList<TextDirective>); + } + }, directives: [TextDirective] }); } diff --git a/packages/core/test/render3/render_util.ts b/packages/core/test/render3/render_util.ts index d4c84c4a0acfa..0dfd00ef6b16d 100644 --- a/packages/core/test/render3/render_util.ts +++ b/packages/core/test/render3/render_util.ts @@ -28,11 +28,11 @@ import {CreateComponentOptions} from '../../src/render3/component'; import {getDirectivesAtNodeIndex, getLContext, isComponentInstance} from '../../src/render3/context_discovery'; import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition'; import {NG_ELEMENT_ID} from '../../src/render3/fields'; -import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, RenderFlags, renderComponent as _renderComponent, tick, ɵɵProvidersFeature, ɵɵdefineComponent, ɵɵdefineDirective} from '../../src/render3/index'; +import {ComponentDef, ComponentTemplate, ComponentType, DirectiveDef, DirectiveType, renderComponent as _renderComponent, RenderFlags, tick, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵProvidersFeature} from '../../src/render3/index'; import {DirectiveDefList, DirectiveDefListOrFactory, DirectiveTypesOrFactory, HostBindingsFunction, PipeDef, PipeDefList, PipeDefListOrFactory, PipeTypesOrFactory} from '../../src/render3/interfaces/definition'; import {PlayerHandler} from '../../src/render3/interfaces/player'; -import {ProceduralRenderer3, RComment, RElement, RNode, RText, Renderer3, RendererFactory3, RendererStyleFlags3, domRendererFactory3} from '../../src/render3/interfaces/renderer'; -import {HEADER_OFFSET, LView, LViewFlags, TVIEW, TViewType, T_HOST} from '../../src/render3/interfaces/view'; +import {domRendererFactory3, ProceduralRenderer3, RComment, RElement, Renderer3, RendererFactory3, RendererStyleFlags3, RNode, RText} from '../../src/render3/interfaces/renderer'; +import {HEADER_OFFSET, LView, LViewFlags, T_HOST, TVIEW, TViewType} from '../../src/render3/interfaces/view'; import {destroyLView} from '../../src/render3/node_manipulation'; import {getRootView} from '../../src/render3/util/view_traversal_utils'; import {Sanitizer} from '../../src/sanitization/sanitizer'; @@ -69,13 +69,17 @@ export abstract class BaseFixture { /** * Current state of HTML rendered by the bootstrapped component. */ - get html(): string { return toHtml(this.hostElement as any as Element); } + get html(): string { + return toHtml(this.hostElement as any as Element); + } /** * Current state of HTML rendered by the fixture (will include HTML rendered by the bootstrapped * component as well as any elements outside of the component's host). */ - get outerHtml(): string { return toHtml(this.containerElement as any as Element); } + get outerHtml(): string { + return toHtml(this.containerElement as any as Element); + } } function noop() {} @@ -121,7 +125,7 @@ export class TemplateFixture extends BaseFixture { this.updateBlock(); } }, - decls, vars, null !, this._rendererFactory, null, this._directiveDefs, this._pipeDefs, + decls, vars, null!, this._rendererFactory, null, this._directiveDefs, this._pipeDefs, sanitizer, this._consts); } @@ -132,7 +136,7 @@ export class TemplateFixture extends BaseFixture { */ update(updateBlock?: () => void): void { renderTemplate( - this.hostElement, updateBlock || this.updateBlock, 0, this.vars, null !, + this.hostElement, updateBlock || this.updateBlock, 0, this.vars, null!, this._rendererFactory, this.hostView, this._directiveDefs, this._pipeDefs, this._sanitizer, this._consts); } @@ -164,7 +168,7 @@ export class ComponentFixture<T> extends BaseFixture { this.requestAnimationFrame.queue = []; this.requestAnimationFrame.flush = function() { while (requestAnimationFrame.queue.length) { - requestAnimationFrame.queue.shift() !(); + requestAnimationFrame.queue.shift()!(); } }; @@ -201,7 +205,7 @@ export class ComponentFixture<T> extends BaseFixture { /////////////////////////////////////////////////////////////////////////////////// export const document = ((typeof global == 'object' && global || window) as any).document; -export let containerEl: HTMLElement = null !; +export let containerEl: HTMLElement = null!; let hostView: LView|null; const isRenderer2 = typeof process == 'object' && process.argv[3] && process.argv[3] === '--r=renderer2'; @@ -216,7 +220,7 @@ export const requestAnimationFrame: } as any; requestAnimationFrame.flush = function() { while (requestAnimationFrame.queue.length) { - requestAnimationFrame.queue.shift() !(); + requestAnimationFrame.queue.shift()!(); } }; @@ -250,9 +254,9 @@ export function resetDOM() { */ export function renderTemplate<T>( hostNode: RElement, templateFn: ComponentTemplate<T>, decls: number, vars: number, context: T, - providedRendererFactory: RendererFactory3, componentView: LView | null, - directives?: DirectiveDefListOrFactory | null, pipes?: PipeDefListOrFactory | null, - sanitizer?: Sanitizer | null, consts?: TConstants): LView { + providedRendererFactory: RendererFactory3, componentView: LView|null, + directives?: DirectiveDefListOrFactory|null, pipes?: PipeDefListOrFactory|null, + sanitizer?: Sanitizer|null, consts?: TConstants): LView { if (componentView === null) { const renderer = providedRendererFactory.createRenderer(null, null); @@ -290,8 +294,8 @@ export function renderTemplate<T>( */ export function renderToHtml( template: ComponentTemplate<any>, ctx: any, decls: number = 0, vars: number = 0, - directives?: DirectiveTypesOrFactory | null, pipes?: PipeTypesOrFactory | null, - providedRendererFactory?: RendererFactory3 | null, keepNgReflect = false, consts?: TConstants) { + directives?: DirectiveTypesOrFactory|null, pipes?: PipeTypesOrFactory|null, + providedRendererFactory?: RendererFactory3|null, keepNgReflect = false, consts?: TConstants) { hostView = renderTemplate( containerEl, template, decls, vars, ctx, providedRendererFactory || testRendererFactory, hostView, toDefs(directives, extractDirectiveDef), toDefs(pipes, extractPipeDef), null, @@ -300,13 +304,12 @@ export function renderToHtml( } function toDefs( - types: DirectiveTypesOrFactory | undefined | null, + types: DirectiveTypesOrFactory|undefined|null, mapFn: (type: Type<any>) => DirectiveDef<any>): DirectiveDefList|null; +function toDefs(types: PipeTypesOrFactory|undefined|null, mapFn: (type: Type<any>) => PipeDef<any>): + PipeDefList|null; function toDefs( - types: PipeTypesOrFactory | undefined | null, - mapFn: (type: Type<any>) => PipeDef<any>): PipeDefList|null; -function toDefs( - types: Type<any>[] | (() => Type<any>[]) | undefined | null, + types: Type<any>[]|(() => Type<any>[])|undefined|null, mapFn: (type: Type<any>) => PipeDef<any>| DirectiveDef<any>): any { if (!types) return null; if (typeof types == 'function') { @@ -337,7 +340,7 @@ export function renderComponent<T>(type: ComponentType<T>, opts?: CreateComponen /** * @deprecated use `TemplateFixture` or `ComponentFixture` */ -export function toHtml<T>(componentOrElement: T | RElement, keepNgReflect = false): string { +export function toHtml<T>(componentOrElement: T|RElement, keepNgReflect = false): string { let element: any; if (isComponentInstance(componentOrElement)) { const context = getLContext(componentOrElement); @@ -369,7 +372,7 @@ export function toHtml<T>(componentOrElement: T | RElement, keepNgReflect = fals export function createComponent( name: string, template: ComponentTemplate<any>, decls: number = 0, vars: number = 0, directives: DirectiveTypesOrFactory = [], pipes: PipeTypesOrFactory = [], - viewQuery: ComponentTemplate<any>| null = null, providers: Provider[] = [], + viewQuery: ComponentTemplate<any>|null = null, providers: Provider[] = [], viewProviders: Provider[] = [], hostBindings?: HostBindingsFunction<any>, consts: TConstants = []): ComponentType<any> { return class Component { @@ -382,7 +385,8 @@ export function createComponent( vars: vars, template: template, viewQuery: viewQuery, - directives: directives, hostBindings, + directives: directives, + hostBindings, pipes: pipes, features: (providers.length > 0 || viewProviders.length > 0)? [ɵɵProvidersFeature(providers || [], viewProviders || [])]: [], @@ -437,7 +441,9 @@ export class MockRendererFactory implements RendererFactory3 { lastRenderer: any; private _spyOnMethods: string[]; - constructor(spyOnMethods?: string[]) { this._spyOnMethods = spyOnMethods || []; } + constructor(spyOnMethods?: string[]) { + this._spyOnMethods = spyOnMethods || []; + } createRenderer(hostElement: RElement|null, rendererType: RendererType2|null): Renderer3 { const renderer = this.lastRenderer = new MockRenderer(this._spyOnMethods); @@ -455,22 +461,34 @@ class MockRenderer implements ProceduralRenderer3 { } destroy(): void {} - createComment(value: string): RComment { return document.createComment(value); } + createComment(value: string): RComment { + return document.createComment(value); + } createElement(name: string, namespace?: string|null): RElement { return namespace ? document.createElementNS(namespace, name) : document.createElement(name); } - createText(value: string): RText { return document.createTextNode(value); } - appendChild(parent: RElement, newChild: RNode): void { parent.appendChild(newChild); } + createText(value: string): RText { + return document.createTextNode(value); + } + appendChild(parent: RElement, newChild: RNode): void { + parent.appendChild(newChild); + } insertBefore(parent: RNode, newChild: RNode, refChild: RNode|null): void { parent.insertBefore(newChild, refChild, false); } - removeChild(parent: RElement, oldChild: RNode): void { parent.removeChild(oldChild); } + removeChild(parent: RElement, oldChild: RNode): void { + parent.removeChild(oldChild); + } selectRootElement(selectorOrNode: string|any): RElement { return typeof selectorOrNode === 'string' ? document.querySelector(selectorOrNode) : selectorOrNode; } - parentNode(node: RNode): RElement|null { return node.parentNode as RElement; } - nextSibling(node: RNode): RNode|null { return node.nextSibling; } + parentNode(node: RNode): RElement|null { + return node.parentNode as RElement; + } + nextSibling(node: RNode): RNode|null { + return node.nextSibling; + } setAttribute(el: RElement, name: string, value: string, namespace?: string|null): void { // set all synthetic attributes as properties if (name[0] === '@') { @@ -486,8 +504,12 @@ class MockRenderer implements ProceduralRenderer3 { el: RElement, style: string, value: any, flags?: RendererStyleFlags2|RendererStyleFlags3): void {} removeStyle(el: RElement, style: string, flags?: RendererStyleFlags2|RendererStyleFlags3): void {} - setProperty(el: RElement, name: string, value: any): void { (el as any)[name] = value; } - setValue(node: RText, value: string): void { node.textContent = value; } + setProperty(el: RElement, name: string, value: any): void { + (el as any)[name] = value; + } + setValue(node: RText, value: string): void { + node.textContent = value; + } // TODO(misko): Deprecate in favor of addEventListener/removeEventListener listen(target: RNode, eventName: string, callback: (event: any) => boolean | void): () => void { diff --git a/packages/core/test/render3/renderer_factory_spec.ts b/packages/core/test/render3/renderer_factory_spec.ts index 7b3990a7afe1d..829fa1c15ffad 100644 --- a/packages/core/test/render3/renderer_factory_spec.ts +++ b/packages/core/test/render3/renderer_factory_spec.ts @@ -12,13 +12,13 @@ import {ɵɵcontainer, ɵɵcontainerRefreshEnd, ɵɵcontainerRefreshStart, ɵɵe import {RenderFlags} from '../../src/render3/interfaces/definition'; import {getRendererFactory2} from './imported_renderer2'; -import {TemplateFixture, document, renderToHtml} from './render_util'; +import {document, renderToHtml, TemplateFixture} from './render_util'; describe('renderer factory lifecycle', () => { let logs: string[] = []; let rendererFactory = getRendererFactory2(document); const createRender = rendererFactory.createRenderer; - rendererFactory.createRenderer = (hostElement: any, type: RendererType2 | null) => { + rendererFactory.createRenderer = (hostElement: any, type: RendererType2|null) => { logs.push('create'); return createRender.apply(rendererFactory, [hostElement, type]); }; @@ -33,15 +33,16 @@ describe('renderer factory lifecycle', () => { selectors: [['some-component']], decls: 1, vars: 0, - template: function(rf: RenderFlags, ctx: SomeComponent) { - if (rf & RenderFlags.Create) { - logs.push('component create'); - ɵɵtext(0, 'foo'); - } - if (rf & RenderFlags.Update) { - logs.push('component update'); - } - } + template: + function(rf: RenderFlags, ctx: SomeComponent) { + if (rf & RenderFlags.Create) { + logs.push('component create'); + ɵɵtext(0, 'foo'); + } + if (rf & RenderFlags.Update) { + logs.push('component update'); + } + } }); } @@ -53,9 +54,10 @@ describe('renderer factory lifecycle', () => { selectors: [['some-component-with-Error']], decls: 0, vars: 0, - template: function(rf: RenderFlags, ctx: SomeComponentWhichThrows) { - throw(new Error('SomeComponentWhichThrows threw')); - } + template: + function(rf: RenderFlags, ctx: SomeComponentWhichThrows) { + throw (new Error('SomeComponentWhichThrows threw')); + } }); } @@ -82,7 +84,9 @@ describe('renderer factory lifecycle', () => { } } - beforeEach(() => { logs = []; }); + beforeEach(() => { + logs = []; + }); it('should work with a template', () => { renderToHtml(Template, {}, 1, 0, null, null, rendererFactory); @@ -104,7 +108,6 @@ describe('renderer factory lifecycle', () => { renderToHtml(TemplateWithComponent, {}, 2, 0, directives); expect(logs).toEqual(['begin', 'function_with_component update', 'component update', 'end']); }); - }); describe('Renderer2 destruction hooks', () => { @@ -157,11 +160,12 @@ describe('Renderer2 destruction hooks', () => { selectors: [['simple']], decls: 1, vars: 0, - template: function(rf: RenderFlags, ctx: SimpleComponent) { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'span'); - } - }, + template: + function(rf: RenderFlags, ctx: SimpleComponent) { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'span'); + } + }, }); } diff --git a/packages/core/test/render3/styling_next/static_styling_spec.ts b/packages/core/test/render3/styling_next/static_styling_spec.ts index d9e5d8f2fae9c..5df0dc2bae1db 100644 --- a/packages/core/test/render3/styling_next/static_styling_spec.ts +++ b/packages/core/test/render3/styling_next/static_styling_spec.ts @@ -14,10 +14,10 @@ import {computeStaticStyling} from '@angular/core/src/render3/styling/static_sty describe('static styling', () => { const mockFirstCreatePassLView: LView = [null, {firstCreatePass: true}] as any; - let tNode !: TNode; + let tNode!: TNode; beforeEach(() => { enterView(mockFirstCreatePassLView, null); - tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); }); it('should initialize when no attrs', () => { computeStaticStyling(tNode, []); diff --git a/packages/core/test/render3/styling_next/style_binding_list_spec.ts b/packages/core/test/render3/styling_next/style_binding_list_spec.ts index d5e66cc0a5ec7..e42a2f50bfd86 100644 --- a/packages/core/test/render3/styling_next/style_binding_list_spec.ts +++ b/packages/core/test/render3/styling_next/style_binding_list_spec.ts @@ -8,7 +8,7 @@ import {createTNode} from '@angular/core/src/render3/instructions/shared'; import {TNode, TNodeType} from '@angular/core/src/render3/interfaces/node'; -import {TStylingKey, TStylingRange, getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate} from '@angular/core/src/render3/interfaces/styling'; +import {getTStylingRangeNext, getTStylingRangeNextDuplicate, getTStylingRangePrev, getTStylingRangePrevDuplicate, TStylingKey, TStylingRange} from '@angular/core/src/render3/interfaces/styling'; import {LView, TData} from '@angular/core/src/render3/interfaces/view'; import {enterView, leaveView} from '@angular/core/src/render3/state'; import {insertTStylingBinding} from '@angular/core/src/render3/styling/style_binding_list'; @@ -20,7 +20,7 @@ describe('TNode styling linked list', () => { afterEach(() => leaveView()); describe('insertTStylingBinding', () => { it('should append template only', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'tmpl1', 2, false, true); @@ -60,7 +60,7 @@ describe('TNode styling linked list', () => { it('should append host only', () => { const tData: TData = [null, null]; - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); insertTStylingBinding(tData, tNode, 'host1', 2, true, true); expectRange(tNode.classBindings).toEqual([2, 0 /* no template binding */]); @@ -79,7 +79,7 @@ describe('TNode styling linked list', () => { }); it('should append template and host', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'tmpl1', 2, false, true); @@ -113,7 +113,7 @@ describe('TNode styling linked list', () => { // ɵɵstyleMap({color: '#007'}); // Binding index: 28 // ɵɵstyleProp('color', '#008'); // Binding index: 30 - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); tNode.styles = ''; const tData: TData = newArray(32, null); @@ -291,12 +291,11 @@ describe('TNode styling linked list', () => { [12, 'color', true, false], // 12 - Template: ɵɵstyleProp('color', '#002'}); ]); }); - }); describe('markDuplicates', () => { it('should not mark items as duplicate if names don\'t match', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'color', 2, false, false); expectPriorityOrder(tData, tNode, false).toEqual([ @@ -321,7 +320,7 @@ describe('TNode styling linked list', () => { }); it('should mark items as duplicate if names match', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'color', 2, false, false); expectPriorityOrder(tData, tNode, false).toEqual([ @@ -345,7 +344,7 @@ describe('TNode styling linked list', () => { }); it('should treat maps as matching all', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'color', 2, false, false); insertTStylingBinding(tData, tNode, 'height', 4, true, false); @@ -365,7 +364,7 @@ describe('TNode styling linked list', () => { }); it('should mark all things after map as duplicate', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, null, 2, false, false); insertTStylingBinding(tData, tNode, 'height', 4, false, false); @@ -379,7 +378,7 @@ describe('TNode styling linked list', () => { }); it('should mark duplicate on complex objects like width.px', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'width', 2, false, false); insertTStylingBinding(tData, tNode, 'height', 4, false, false); @@ -406,7 +405,7 @@ describe('TNode styling linked list', () => { }); it('should mark duplicate on static fields', () => { - const tNode = createTNode(null !, null !, TNodeType.Element, 0, '', null); + const tNode = createTNode(null!, null!, TNodeType.Element, 0, '', null); tNode.residualStyles = ['color', 'blue'] as any; const tData: TData = [null, null]; insertTStylingBinding(tData, tNode, 'width', 2, false, false); @@ -431,7 +430,6 @@ describe('TNode styling linked list', () => { ]); }); }); - }); const empty_0_through_9 = [null, null, null, null, null, null, null, null, null, null]; @@ -460,7 +458,7 @@ function expectTData(tData: TData) { function expectPriorityOrder(tData: TData, tNode: TNode, isClassBinding: boolean) { // first find head. let index = getStylingBindingHead(tData, tNode, isClassBinding); - const indexes: [number, string | null, boolean, boolean][] = []; + const indexes: [number, string|null, boolean, boolean][] = []; while (index !== 0) { let key = tData[index] as TStylingKey | null; const tStylingRange = tData[index + 1] as TStylingRange; diff --git a/packages/core/test/render3/testing_spec.ts b/packages/core/test/render3/testing_spec.ts index 850534020345f..cd1e2844d7d87 100644 --- a/packages/core/test/render3/testing_spec.ts +++ b/packages/core/test/render3/testing_spec.ts @@ -24,7 +24,7 @@ describe('testing', () => { return Promise.resolve(true).then(() => passed = true); })); - it('should support async and await', withBody('<span>works!</span>', async() => { + it('should support async and await', withBody('<span>works!</span>', async () => { await Promise.resolve(true); passed = true; })); diff --git a/packages/core/test/render3/view_container_ref_spec.ts b/packages/core/test/render3/view_container_ref_spec.ts index 27ab15e59ab66..5195c67e5ed49 100644 --- a/packages/core/test/render3/view_container_ref_spec.ts +++ b/packages/core/test/render3/view_container_ref_spec.ts @@ -39,7 +39,7 @@ describe('ViewContainerRef', () => { }); // TODO(issue/24571): remove '!'. - tplRef !: TemplateRef<{}>; + tplRef!: TemplateRef<{}>; name: string = ''; @@ -49,9 +49,7 @@ describe('ViewContainerRef', () => { } describe('API', () => { - describe('createEmbeddedView (incl. insert)', () => { - it('should add embedded views at the right position in the DOM tree (ng-template next to other ng-template)', () => { let directiveInstances: TestDirective[] = []; @@ -75,9 +73,13 @@ describe('ViewContainerRef', () => { constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {} - insertTpl(ctx: {}) { this._vcRef.createEmbeddedView(this._tplRef, ctx); } + insertTpl(ctx: {}) { + this._vcRef.createEmbeddedView(this._tplRef, ctx); + } - remove(index?: number) { this._vcRef.remove(index); } + remove(index?: number) { + this._vcRef.remove(index); + } } function EmbeddedTemplateA(rf: RenderFlags, ctx: any) { @@ -100,7 +102,7 @@ describe('ViewContainerRef', () => { */ class TestComponent { // TODO(issue/24571): remove '!'. - testDir !: TestDirective; + testDir!: TestDirective; static ɵfac = () => new TestComponent(); static ɵcmp = ɵɵdefineComponent({ type: TestComponent, @@ -109,14 +111,15 @@ describe('ViewContainerRef', () => { decls: 4, vars: 0, consts: [['testdir', '']], - template: (rf: RenderFlags, cmp: TestComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'before|'); - ɵɵtemplate(1, EmbeddedTemplateA, 1, 0, 'ng-template', 0); - ɵɵtemplate(2, EmbeddedTemplateB, 1, 0, 'ng-template', 0); - ɵɵtext(3, '|after'); - } - }, + template: + (rf: RenderFlags, cmp: TestComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'before|'); + ɵɵtemplate(1, EmbeddedTemplateA, 1, 0, 'ng-template', 0); + ɵɵtemplate(2, EmbeddedTemplateB, 1, 0, 'ng-template', 0); + ɵɵtext(3, '|after'); + } + }, directives: [TestDirective] }); } @@ -124,10 +127,10 @@ describe('ViewContainerRef', () => { const fixture = new ComponentFixture(TestComponent); expect(fixture.html).toEqual('before||after'); - directiveInstances ![1].insertTpl({}); + directiveInstances![1].insertTpl({}); expect(fixture.html).toEqual('before|B|after'); - directiveInstances ![0].insertTpl({}); + directiveInstances![0].insertTpl({}); expect(fixture.html).toEqual('before|AB|after'); }); @@ -145,14 +148,18 @@ describe('ViewContainerRef', () => { constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {} - insertTpl(ctx: {}) { this._vcRef.createEmbeddedView(this._tplRef, ctx); } + insertTpl(ctx: {}) { + this._vcRef.createEmbeddedView(this._tplRef, ctx); + } insertTpl2(ctx: {}) { const viewRef = this._tplRef.createEmbeddedView(ctx); this._vcRef.insert(viewRef); } - remove(index?: number) { this._vcRef.remove(index); } + remove(index?: number) { + this._vcRef.remove(index); + } } function EmbeddedTemplateA(rf: RenderFlags, ctx: any) { @@ -172,7 +179,7 @@ describe('ViewContainerRef', () => { class TestComponent { condition = false; // TODO(issue/24571): remove '!'. - testDir !: TestDirective; + testDir!: TestDirective; static ɵfac = () => new TestComponent(); static ɵcmp = ɵɵdefineComponent({ type: TestComponent, @@ -181,29 +188,30 @@ describe('ViewContainerRef', () => { decls: 4, vars: 0, consts: [['testdir', '']], - template: (rf: RenderFlags, cmp: TestComponent) => { - if (rf & RenderFlags.Create) { - ɵɵtext(0, 'before|'); - ɵɵtemplate(1, EmbeddedTemplateA, 1, 0, 'ng-template', 0); - ɵɵcontainer(2); - ɵɵtext(3, '|after'); - } - if (rf & RenderFlags.Update) { - ɵɵcontainerRefreshStart(2); - { - if (cmp.condition) { - let rf1 = ɵɵembeddedViewStart(0, 1, 0); + template: + (rf: RenderFlags, cmp: TestComponent) => { + if (rf & RenderFlags.Create) { + ɵɵtext(0, 'before|'); + ɵɵtemplate(1, EmbeddedTemplateA, 1, 0, 'ng-template', 0); + ɵɵcontainer(2); + ɵɵtext(3, '|after'); + } + if (rf & RenderFlags.Update) { + ɵɵcontainerRefreshStart(2); { - if (rf1 & RenderFlags.Create) { - ɵɵtext(0, 'B'); + if (cmp.condition) { + let rf1 = ɵɵembeddedViewStart(0, 1, 0); + { + if (rf1 & RenderFlags.Create) { + ɵɵtext(0, 'B'); + } + } + ɵɵembeddedViewEnd(); } } - ɵɵembeddedViewEnd(); + ɵɵcontainerRefreshEnd(); } - } - ɵɵcontainerRefreshEnd(); - } - }, + }, directives: [TestDirective] }); } @@ -215,28 +223,27 @@ describe('ViewContainerRef', () => { fixture.update(); expect(fixture.html).toEqual('before|B|after'); - directiveInstance !.insertTpl({}); + directiveInstance!.insertTpl({}); expect(fixture.html).toEqual('before|AB|after'); fixture.component.condition = false; fixture.update(); expect(fixture.html).toEqual('before|A|after'); - directiveInstance !.insertTpl2({}); + directiveInstance!.insertTpl2({}); expect(fixture.html).toEqual('before|AA|after'); fixture.component.condition = true; fixture.update(); expect(fixture.html).toEqual('before|AAB|after'); }); - }); describe('createComponent', () => { let templateExecutionCounter = 0; describe('ComponentRef', () => { - let dynamicComp !: DynamicComp; + let dynamicComp!: DynamicComp; class AppComp { constructor(public vcr: ViewContainerRef, public cfr: ComponentFactoryResolver) {} @@ -259,7 +266,9 @@ describe('ViewContainerRef', () => { class DynamicComp { doCheckCount = 0; - ngDoCheck() { this.doCheckCount++; } + ngDoCheck() { + this.doCheckCount++; + } static ɵfac = () => dynamicComp = new DynamicComp(); @@ -313,8 +322,9 @@ describe('ViewContainerRef', () => { fixture.component.vcr.detach(fixture.component.vcr.indexOf(ref.hostView)); - expect(() => { ref.destroy(); }).not.toThrow(); - + expect(() => { + ref.destroy(); + }).not.toThrow(); }); }); }); @@ -330,12 +340,12 @@ describe('ViewContainerRef', () => { createTemplate, undefined, 2, 0, [DirectiveWithVCRef], null, null, undefined, [['vcref', '']]); - expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase()) + expect(directiveInstance!.vcref.element.nativeElement.tagName.toLowerCase()) .toEqual('header'); expect( - directiveInstance !.vcref.injector.get(ElementRef).nativeElement.tagName.toLowerCase()) + directiveInstance!.vcref.injector.get(ElementRef).nativeElement.tagName.toLowerCase()) .toEqual('header'); - expect(() => directiveInstance !.vcref.parentInjector.get(ElementRef)).toThrow(); + expect(() => directiveInstance!.vcref.parentInjector.get(ElementRef)).toThrow(); }); it('should work on components', () => { @@ -351,18 +361,17 @@ describe('ViewContainerRef', () => { createTemplate, undefined, 2, 0, [HeaderComponent, DirectiveWithVCRef], null, null, undefined, [['vcref', '']]); - expect(directiveInstance !.vcref.element.nativeElement.tagName.toLowerCase()) + expect(directiveInstance!.vcref.element.nativeElement.tagName.toLowerCase()) .toEqual('header-cmp'); expect( - directiveInstance !.vcref.injector.get(ElementRef).nativeElement.tagName.toLowerCase()) + directiveInstance!.vcref.injector.get(ElementRef).nativeElement.tagName.toLowerCase()) .toEqual('header-cmp'); - expect(() => directiveInstance !.vcref.parentInjector.get(ElementRef)).toThrow(); + expect(() => directiveInstance!.vcref.parentInjector.get(ElementRef)).toThrow(); }); }); }); describe('view engine compatibility', () => { - @Component({selector: 'app', template: ''}) class AppCmpt { static ɵfac = () => @@ -383,14 +392,17 @@ describe('ViewContainerRef', () => { this._vcRef.createComponent(this._cfResolver.resolveComponentFactory(comp)); } - clear() { this._vcRef.clear(); } + clear() { + this._vcRef.clear(); + } - getVCRefParentInjector() { return this._vcRef.parentInjector; } + getVCRefParentInjector() { + return this._vcRef.parentInjector; + } } // https://stackblitz.com/edit/angular-xxpffd?file=src%2Findex.html it('should allow injecting VCRef into the root (bootstrapped) component', () => { - const DynamicComponent = createComponent('dynamic-cmpt', function(rf: RenderFlags, parent: any) { if (rf & RenderFlags.Create) { @@ -428,12 +440,12 @@ describe('ViewContainerRef', () => { }); it('should support view queries for dynamically created components', () => { - let dynamicComp !: DynamicCompWithViewQueries; - let fooEl !: RElement; + let dynamicComp!: DynamicCompWithViewQueries; + let fooEl!: RElement; class DynamicCompWithViewQueries { // @ViewChildren('foo') - foo !: QueryList<any>; + foo!: QueryList<any>; static ɵfac = () => dynamicComp = new DynamicCompWithViewQueries(); static ɵcmp = ɵɵdefineComponent({ @@ -442,23 +454,25 @@ describe('ViewContainerRef', () => { decls: 2, vars: 0, consts: [['foo', ''], ['bar', '']], - template: (rf: RenderFlags, ctx: DynamicCompWithViewQueries) => { - if (rf & RenderFlags.Create) { - ɵɵelement(0, 'div', 1, 0); - } - // testing only - fooEl = getNativeByIndex(0, getLView()) as RElement; - }, - viewQuery: function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵviewQuery(['foo'], true); - } - if (rf & RenderFlags.Update) { - let tmp: any; - ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && - (ctx.foo = tmp as QueryList<any>); - } - } + template: + (rf: RenderFlags, ctx: DynamicCompWithViewQueries) => { + if (rf & RenderFlags.Create) { + ɵɵelement(0, 'div', 1, 0); + } + // testing only + fooEl = getNativeByIndex(0, getLView()) as RElement; + }, + viewQuery: + function(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵviewQuery(['foo'], true); + } + if (rf & RenderFlags.Update) { + let tmp: any; + ɵɵqueryRefresh(tmp = ɵɵloadQuery<QueryList<any>>()) && + (ctx.foo = tmp as QueryList<any>); + } + } }); } @@ -469,7 +483,6 @@ describe('ViewContainerRef', () => { expect(dynamicComp.foo.first.nativeElement).toEqual(fooEl as any); }); - }); describe('view destruction', () => { @@ -478,7 +491,9 @@ describe('ViewContainerRef', () => { onClick() {} - ngOnDestroy() { this.viewRef.destroy(); } + ngOnDestroy() { + this.viewRef.destroy(); + } // We want the ViewRef, so we rely on the knowledge that `ViewRef` is actually given // when injecting `ChangeDetectorRef`. @@ -491,16 +506,19 @@ describe('ViewContainerRef', () => { decls: 2, vars: 0, /** <button (click)="onClick()"> Click me </button> */ - template: function CompTemplate(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - ɵɵelementStart(0, 'button'); - { - ɵɵlistener('click', function() { return ctx.onClick(); }); - ɵɵtext(1, 'Click me'); - } - ɵɵelementEnd(); - } - }, + template: + function CompTemplate(rf: RenderFlags, ctx: any) { + if (rf & RenderFlags.Create) { + ɵɵelementStart(0, 'button'); + { + ɵɵlistener('click', function() { + return ctx.onClick(); + }); + ɵɵtext(1, 'Click me'); + } + ɵɵelementEnd(); + } + }, }); } diff --git a/packages/core/test/render3/view_utils_spec.ts b/packages/core/test/render3/view_utils_spec.ts index caedd809674c1..944921fcfacf1 100644 --- a/packages/core/test/render3/view_utils_spec.ts +++ b/packages/core/test/render3/view_utils_spec.ts @@ -15,7 +15,7 @@ describe('view_utils', () => { const div = document.createElement('div'); const tView = createTView(TViewType.Root, 0, null, 0, 0, null, null, null, null, null); const lView = createLView(null, tView, {}, 0, div, null, {} as any, {} as any, null, null); - const tNode = createTNode(null !, null, 3, 0, 'div', []); + const tNode = createTNode(null!, null, 3, 0, 'div', []); const lContainer = createLContainer(lView, lView, div, tNode); expect(isLView(lView)).toBe(true); diff --git a/packages/core/test/sanitization/html_sanitizer_spec.ts b/packages/core/test/sanitization/html_sanitizer_spec.ts index df917b55df3fa..8e99a670e45d9 100644 --- a/packages/core/test/sanitization/html_sanitizer_spec.ts +++ b/packages/core/test/sanitization/html_sanitizer_spec.ts @@ -13,7 +13,7 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer'; { describe('HTML sanitizer', () => { let defaultDoc: any; - let originalLog: (msg: any) => any = null !; + let originalLog: (msg: any) => any = null!; let logMsgs: string[]; beforeEach(() => { @@ -23,7 +23,9 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer'; console.warn = (msg: any) => logMsgs.push(msg); }); - afterEach(() => { console.warn = originalLog; }); + afterEach(() => { + console.warn = originalLog; + }); it('serializes nested structures', () => { expect(_sanitizeHtml(defaultDoc, '<div alt="x"><p>a</p>b<b>c<a alt="more">d</a></b>e</div>')) @@ -36,8 +38,9 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer'; .toEqual('<p>Hello <br> World</p>'); }); - it('supports namespaced elements', - () => { expect(_sanitizeHtml(defaultDoc, 'a<my:hr/><my:div>b</my:div>c')).toEqual('abc'); }); + it('supports namespaced elements', () => { + expect(_sanitizeHtml(defaultDoc, 'a<my:hr/><my:div>b</my:div>c')).toEqual('abc'); + }); it('supports namespaced attributes', () => { expect(_sanitizeHtml(defaultDoc, '<a xlink:href="something">t</a>')) @@ -66,8 +69,9 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer'; .toEqual('<img srcset="/foo.png 400px, unsafe:javascript:evil() 23px">'); }); - it('supports sanitizing plain text', - () => { expect(_sanitizeHtml(defaultDoc, 'Hello, World')).toEqual('Hello, World'); }); + it('supports sanitizing plain text', () => { + expect(_sanitizeHtml(defaultDoc, 'Hello, World')).toEqual('Hello, World'); + }); it('ignores non-element, non-attribute nodes', () => { expect(_sanitizeHtml(defaultDoc, '<!-- comments? -->no.')).toEqual('no.'); @@ -104,8 +108,9 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer'; 'select', ]; for (const tag of dangerousTags) { - it(tag, - () => { expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual('evil!'); }); + it(tag, () => { + expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual('evil!'); + }); } const dangerousSelfClosingTags = [ @@ -129,7 +134,9 @@ import {_sanitizeHtml} from '../../src/sanitization/html_sanitizer'; 'template', ]; for (const tag of dangerousSkipContentTags) { - it(tag, () => { expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual(''); }); + it(tag, () => { + expect(_sanitizeHtml(defaultDoc, `<${tag}>evil!</${tag}>`)).toEqual(''); + }); } it(`frame`, () => { diff --git a/packages/core/test/sanitization/sanitization_spec.ts b/packages/core/test/sanitization/sanitization_spec.ts index 2c7a8d2650c61..d9dcc1bae16ae 100644 --- a/packages/core/test/sanitization/sanitization_spec.ts +++ b/packages/core/test/sanitization/sanitization_spec.ts @@ -24,7 +24,9 @@ describe('sanitization', () => { afterEach(() => leaveView()); class Wrap { constructor(private value: string) {} - toString() { return this.value; } + toString() { + return this.value; + } } it('should sanitize html', () => { expect(ɵɵsanitizeHtml('<div></div>')).toEqual('<div></div>'); @@ -96,7 +98,7 @@ describe('sanitization', () => { contextsByProp.set(prop, contexts); // check only in case a prop can be a part of both URL contexts if (contexts.size === 2) { - expect(getUrlSanitizer(tag, prop)).toEqual(sanitizerNameByContext.get(context) !); + expect(getUrlSanitizer(tag, prop)).toEqual(sanitizerNameByContext.get(context)!); } } }); diff --git a/packages/core/test/sanitization/style_sanitizer_spec.ts b/packages/core/test/sanitization/style_sanitizer_spec.ts index d96251b482bed..0a776483f9bb9 100644 --- a/packages/core/test/sanitization/style_sanitizer_spec.ts +++ b/packages/core/test/sanitization/style_sanitizer_spec.ts @@ -19,9 +19,13 @@ describe('Style sanitizer', () => { console.warn = (msg: any) => logMsgs.push(msg); }); - afterEach(() => { console.warn = originalLog; }); + afterEach(() => { + console.warn = originalLog; + }); - function expectSanitize(v: string) { return expect(_sanitizeStyle(v)); } + function expectSanitize(v: string) { + return expect(_sanitizeStyle(v)); + } it('sanitizes values', () => { expectSanitize('').toEqual(''); @@ -31,7 +35,9 @@ describe('Style sanitizer', () => { expectSanitize('expression(haha)').toEqual('unsafe'); }); - it('rejects unblanaced quotes', () => { expectSanitize('"value" "').toEqual('unsafe'); }); + it('rejects unblanaced quotes', () => { + expectSanitize('"value" "').toEqual('unsafe'); + }); it('accepts transform functions', () => { expectSanitize('rotate(90deg)').toEqual('rotate(90deg)'); @@ -47,12 +53,17 @@ describe('Style sanitizer', () => { .toEqual('repeating-radial-gradient(ellipse cover, black, red, black, red)'); }); - it('accepts attr', () => { expectSanitize('attr(value string)').toEqual('attr(value string)'); }); + it('accepts attr', () => { + expectSanitize('attr(value string)').toEqual('attr(value string)'); + }); - it('accepts calc', () => { expectSanitize('calc(90%-123px)').toEqual('calc(90%-123px)'); }); + it('accepts calc', () => { + expectSanitize('calc(90%-123px)').toEqual('calc(90%-123px)'); + }); - it('accepts var', - () => { expectSanitize('var(--my-custom-var)').toEqual('var(--my-custom-var)'); }); + it('accepts var', () => { + expectSanitize('var(--my-custom-var)').toEqual('var(--my-custom-var)'); + }); it('sanitizes URLs', () => { expectSanitize('url(foo/bar.png)').toEqual('url(foo/bar.png)'); diff --git a/packages/core/test/sanitization/url_sanitizer_spec.ts b/packages/core/test/sanitization/url_sanitizer_spec.ts index 69c1f705a483a..6c53c9328adbe 100644 --- a/packages/core/test/sanitization/url_sanitizer_spec.ts +++ b/packages/core/test/sanitization/url_sanitizer_spec.ts @@ -21,7 +21,9 @@ import {_sanitizeUrl, sanitizeSrcset} from '../../src/sanitization/url_sanitizer console.warn = (msg: any) => logMsgs.push(msg); }); - afterEach(() => { console.warn = originalLog; }); + afterEach(() => { + console.warn = originalLog; + }); t.it('reports unsafe URLs', () => { t.expect(_sanitizeUrl('javascript:evil()')).toBe('unsafe:javascript:evil()'); @@ -113,6 +115,5 @@ import {_sanitizeUrl, sanitizeSrcset} from '../../src/sanitization/url_sanitizer t.it(`valid ${srcset}`, () => t.expect(sanitizeSrcset(srcset)).toMatch(/unsafe:/)); } }); - }); } diff --git a/packages/core/test/spies.ts b/packages/core/test/spies.ts index 08acdd7c9601e..ff2638cbe4c59 100644 --- a/packages/core/test/spies.ts +++ b/packages/core/test/spies.ts @@ -22,5 +22,7 @@ export class SpyChangeDetectorRef extends SpyObject { export class SpyIterableDifferFactory extends SpyObject {} export class SpyElementRef extends SpyObject { - constructor() { super(ElementRef); } + constructor() { + super(ElementRef); + } } diff --git a/packages/core/test/strict_types/inheritance_spec.ts b/packages/core/test/strict_types/inheritance_spec.ts index c49fc0a9ed695..28e6b3aa66247 100644 --- a/packages/core/test/strict_types/inheritance_spec.ts +++ b/packages/core/test/strict_types/inheritance_spec.ts @@ -21,7 +21,9 @@ declare class SubComponent extends SuperComponent { static ɵcmp: ɵɵComponentDefWithMeta<SubComponent, '[sub]', never, {}, {}, never, never>; } -declare class SuperPipe { static ɵpipe: PipeDefWithMeta<SuperPipe, 'super'>; } +declare class SuperPipe { + static ɵpipe: PipeDefWithMeta<SuperPipe, 'super'>; +} declare class SubPipe extends SuperPipe { onlyInSubtype: string; diff --git a/packages/core/test/test_bed_async_spec.ts b/packages/core/test/test_bed_async_spec.ts index 56c3ed092bb78..4f158c5e8bd4f 100644 --- a/packages/core/test/test_bed_async_spec.ts +++ b/packages/core/test/test_bed_async_spec.ts @@ -10,9 +10,12 @@ import {TestBed} from '@angular/core/testing/src/test_bed'; import {AsyncTestCompleter, ddescribe, describe, inject, it} from '@angular/core/testing/src/testing_internal'; describe('TestBed with async processing', () => { - - beforeEach(() => { TestBed.resetTestingModule(); }); + beforeEach(() => { + TestBed.resetTestingModule(); + }); it('should allow injecting AsyncTestCompleter', - inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { async.done(); })); + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + async.done(); + })); }); diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 6a3eecf9271e7..6049dc3a9d854 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -7,7 +7,7 @@ */ import {APP_INITIALIZER, ChangeDetectorRef, Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core'; -import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed'; +import {getTestBed, TestBed} from '@angular/core/testing/src/test_bed'; import {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {onlyInIvy} from '@angular/private/testing'; @@ -18,7 +18,9 @@ const NAME = new InjectionToken<string>('name'); class SimpleService { static ngOnDestroyCalls: number = 0; id: number = 1; - ngOnDestroy() { SimpleService.ngOnDestroyCalls++; } + ngOnDestroy() { + SimpleService.ngOnDestroyCalls++; + } } // -- module: HWModule @@ -325,7 +327,7 @@ describe('TestBed', () => { template: `<test-cmp #testCmpCtrl></test-cmp>`, }) class AppComponent { - @ViewChild('testCmpCtrl', {static: true}) testCmpCtrl !: TestComponent; + @ViewChild('testCmpCtrl', {static: true}) testCmpCtrl!: TestComponent; } @NgModule({ @@ -403,7 +405,7 @@ describe('TestBed', () => { it('overridden with an array', () => { const overrideValue = ['override']; - TestBed.overrideProvider(multiToken, { useValue: overrideValue, multi: true } as any); + TestBed.overrideProvider(multiToken, {useValue: overrideValue, multi: true} as any); const value = TestBed.inject(multiToken); expect(value.length).toEqual(overrideValue.length); @@ -414,7 +416,7 @@ describe('TestBed', () => { // This is actually invalid because multi providers return arrays. We have this here so we can // ensure Ivy behaves the same as VE does currently. const overrideValue = 'override'; - TestBed.overrideProvider(multiToken, { useValue: overrideValue, multi: true } as any); + TestBed.overrideProvider(multiToken, {useValue: overrideValue, multi: true} as any); const value = TestBed.inject(multiToken); expect(value.length).toEqual(overrideValue.length); @@ -474,12 +476,16 @@ describe('TestBed', () => { it('should allow overriding a provider defined via ModuleWithProviders (using TestBed.overrideProvider)', () => { const serviceOverride = { - get() { return 'override'; }, + get() { + return 'override'; + }, }; @Injectable({providedIn: 'root'}) class MyService { - get() { return 'original'; } + get() { + return 'original'; + } } @NgModule({}) @@ -523,12 +529,16 @@ describe('TestBed', () => { it('should allow overriding a provider defined via ModuleWithProviders (using TestBed.configureTestingModule)', () => { const serviceOverride = { - get() { return 'override'; }, + get() { + return 'override'; + }, }; @Injectable({providedIn: 'root'}) class MyService { - get() { return 'original'; } + get() { + return 'original'; + } } @NgModule({}) @@ -604,7 +614,9 @@ describe('TestBed', () => { }) class CompA { @Input() inputA: string = ''; - ngOnInit() { log.push('CompA:ngOnInit', this.inputA); } + ngOnInit() { + log.push('CompA:ngOnInit', this.inputA); + } } @Component({ @@ -613,7 +625,9 @@ describe('TestBed', () => { }) class CompB { @Input() inputB: string = ''; - ngOnInit() { log.push('CompB:ngOnInit', this.inputB); } + ngOnInit() { + log.push('CompB:ngOnInit', this.inputB); + } } TestBed.configureTestingModule({declarations: [CompA, CompB]}); @@ -662,13 +676,12 @@ describe('TestBed', () => { TestBed.configureTestingModule({imports: [ProvidesErrorHandler, HelloWorldModule]}); expect(TestBed.inject(ErrorHandler)).toEqual(jasmine.any(CustomErrorHandler)); - }); it('should throw errors in CD', () => { @Component({selector: 'my-comp', template: ''}) class MyComp { - name !: {hello: string}; + name!: {hello: string}; ngOnInit() { // this should throw because this.name is undefined @@ -688,10 +701,9 @@ describe('TestBed', () => { // tests to fail. This is an issue in both View Engine and Ivy, and may require a breaking // change to completely fix (since simple re-throwing breaks handlers in ngrx, etc). xit('should throw errors in listeners', () => { - @Component({selector: 'my-comp', template: '<button (click)="onClick()">Click me</button>'}) class MyComp { - name !: {hello: string}; + name!: {hello: string}; onClick() { // this should throw because this.name is undefined @@ -819,11 +831,12 @@ describe('TestBed', () => { selectors: [['comp']], decls: 1, vars: 0, - template: (rf: any, ctx: any) => { - if (rf & 1) { - text(0, 'Some template'); - } - }, + template: + (rf: any, ctx: any) => { + if (rf & 1) { + text(0, 'Some template'); + } + }, styles: ['body { margin: 0; }'] }); } @@ -898,7 +911,9 @@ describe('TestBed', () => { it('should restore ng defs to their initial states', () => { @Pipe({name: 'somePipe', pure: true}) class SomePipe { - transform(value: string): string { return `transformed ${value}`; } + transform(value: string): string { + return `transformed ${value}`; + } } @Directive({selector: 'someDirective'}) @@ -964,9 +979,8 @@ describe('TestBed', () => { class PipeWithNoAnnotations extends SomePipe {} TestBed.configureTestingModule({ - declarations: [ - ComponentWithNoAnnotations, DirectiveWithNoAnnotations, PipeWithNoAnnotations - ] + declarations: + [ComponentWithNoAnnotations, DirectiveWithNoAnnotations, PipeWithNoAnnotations] }); TestBed.createComponent(ComponentWithNoAnnotations); @@ -994,7 +1008,6 @@ describe('TestBed', () => { it('should clean up overridden providers for modules that are imported more than once', () => { - @Injectable() class Token { name: string = 'real'; @@ -1019,7 +1032,7 @@ describe('TestBed', () => { }); it('should clean up overridden providers on components whose modules are compiled more than once', - async() => { + async () => { @Injectable() class SomeInjectable { id: string|undefined; @@ -1098,6 +1111,6 @@ describe('TestBed', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); - expect(fixture !.nativeElement.textContent).toContain('changed'); + expect(fixture!.nativeElement.textContent).toContain('changed'); }); }); diff --git a/packages/core/test/testability/testability_spec.ts b/packages/core/test/testability/testability_spec.ts index ad604b8cf1ee7..bdca80a38c984 100644 --- a/packages/core/test/testability/testability_spec.ts +++ b/packages/core/test/testability/testability_spec.ts @@ -11,7 +11,7 @@ import {Injectable} from '@angular/core/src/di'; import {PendingMacrotask, Testability, TestabilityRegistry} from '@angular/core/src/testability/testability'; import {NgZone} from '@angular/core/src/zone/ng_zone'; import {async, fakeAsync, flush, tick} from '@angular/core/testing'; -import {SpyObject, beforeEach, describe, expect, it} from '@angular/core/testing/src/testing_internal'; +import {beforeEach, describe, expect, it, SpyObject} from '@angular/core/testing/src/testing_internal'; import {scheduleMicroTask} from '../../src/util/microtask'; @@ -38,9 +38,13 @@ class MockNgZone extends NgZone { this.onStable = new EventEmitter(false); } - unstable(): void { this.onUnstable.emit(null); } + unstable(): void { + this.onUnstable.emit(null); + } - stable(): void { this.onStable.emit(null); } + stable(): void { + this.onStable.emit(null); + } } { @@ -60,13 +64,16 @@ class MockNgZone extends NgZone { })); describe('Pending count logic', () => { - it('should start with a pending count of 0', - () => { expect(testability.getPendingRequestCount()).toEqual(0); }); + it('should start with a pending count of 0', () => { + expect(testability.getPendingRequestCount()).toEqual(0); + }); it('should fire whenstable callbacks if pending count is 0', async(() => { testability.whenStable(execute); - microTask(() => { expect(execute).toHaveBeenCalled(); }); + microTask(() => { + expect(execute).toHaveBeenCalled(); + }); })); it('should not fire whenstable callbacks synchronously if pending count is 0', () => { @@ -83,7 +90,9 @@ class MockNgZone extends NgZone { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - microTask(() => { expect(execute).not.toHaveBeenCalled(); }); + microTask(() => { + expect(execute).not.toHaveBeenCalled(); + }); }); })); @@ -95,7 +104,9 @@ class MockNgZone extends NgZone { expect(execute).not.toHaveBeenCalled(); testability.decreasePendingRequestCount(); - microTask(() => { expect(execute).toHaveBeenCalled(); }); + microTask(() => { + expect(execute).toHaveBeenCalled(); + }); }); })); @@ -111,7 +122,9 @@ class MockNgZone extends NgZone { microTask(() => { testability.whenStable(execute); - microTask(() => { expect(execute).toHaveBeenCalledWith(false); }); + microTask(() => { + expect(execute).toHaveBeenCalledWith(false); + }); }); })); @@ -125,10 +138,11 @@ class MockNgZone extends NgZone { expect(execute).toHaveBeenCalledWith(true); testability.whenStable(execute2); - microTask(() => { expect(execute2).toHaveBeenCalledWith(false); }); + microTask(() => { + expect(execute2).toHaveBeenCalledWith(false); + }); }); })); - }); describe('NgZone callback logic', () => { @@ -144,9 +158,9 @@ class MockNgZone extends NgZone { expect(tasks.length).toEqual(1); expect(tasks[0].data).toBeTruthy(); - expect(tasks[0].data !.delay).toEqual(1000); + expect(tasks[0].data!.delay).toEqual(1000); expect(tasks[0].source).toEqual('setTimeout'); - expect(tasks[0].data !.isPeriodic).toEqual(false); + expect(tasks[0].data!.isPeriodic).toEqual(false); clearTimeout(id); })); @@ -154,7 +168,9 @@ class MockNgZone extends NgZone { it('should fire if Angular is already stable', async(() => { testability.whenStable(execute, 200); - microTask(() => { expect(execute).toHaveBeenCalled(); }); + microTask(() => { + expect(execute).toHaveBeenCalled(); + }); })); it('should fire when macroTasks are cancelled', fakeAsync(() => { @@ -208,11 +224,11 @@ class MockNgZone extends NgZone { expect(execute).toHaveBeenCalled(); const update1 = updateCallback.calls.all()[0].args[0] as PendingMacrotask[]; - expect(update1[0].data !.delay).toEqual(500); + expect(update1[0].data!.delay).toEqual(500); const update2 = updateCallback.calls.all()[1].args[0] as PendingMacrotask[]; - expect(update2[0].data !.delay).toEqual(500); - expect(update2[1].data !.delay).toEqual(300); + expect(update2[0].data!.delay).toEqual(500); + expect(update2[1].data!.delay).toEqual(300); })); it('cancels the done callback if the update callback returns true', fakeAsync(() => { diff --git a/packages/core/test/testing_internal_spec.ts b/packages/core/test/testing_internal_spec.ts index fc29424e97e01..584e93ebf9a0f 100644 --- a/packages/core/test/testing_internal_spec.ts +++ b/packages/core/test/testing_internal_spec.ts @@ -10,23 +10,34 @@ import {SpyObject} from '@angular/core/testing/src/testing_internal'; class TestObj { prop: any; - constructor(prop: any) { this.prop = prop; } - someFunc(): number { return -1; } - someComplexFunc(a: any) { return a; } + constructor(prop: any) { + this.prop = prop; + } + someFunc(): number { + return -1; + } + someComplexFunc(a: any) { + return a; + } } { describe('testing', () => { describe('should respect custom equality tester', () => { beforeEach(() => { - const equalIfMarried = - (first: any, second: any) => { return first === 'kevin' && second === 'patricia'; }; + const equalIfMarried = (first: any, second: any) => { + return first === 'kevin' && second === 'patricia'; + }; jasmine.addCustomEqualityTester(equalIfMarried); }); - it('for positive test', () => { expect('kevin').toEqual('patricia'); }); + it('for positive test', () => { + expect('kevin').toEqual('patricia'); + }); - it('for negative test', () => { expect('kevin').not.toEqual('kevin'); }); + it('for negative test', () => { + expect('kevin').not.toEqual('kevin'); + }); }); describe('equality', () => { @@ -83,10 +94,13 @@ class TestObj { describe('spy objects', () => { let spyObj: any; - beforeEach(() => { spyObj = new SpyObject(TestObj); }); + beforeEach(() => { + spyObj = new SpyObject(TestObj); + }); - it('should return a new spy func with no calls', - () => { expect(spyObj.spy('someFunc')).not.toHaveBeenCalled(); }); + it('should return a new spy func with no calls', () => { + expect(spyObj.spy('someFunc')).not.toHaveBeenCalled(); + }); it('should record function calls', () => { spyObj.spy('someFunc').and.callFake((a: any, b: any) => a + b); diff --git a/packages/core/test/util/array_utils_spec.ts b/packages/core/test/util/array_utils_spec.ts index 5d2fdd6cef815..48ef711673ff6 100644 --- a/packages/core/test/util/array_utils_spec.ts +++ b/packages/core/test/util/array_utils_spec.ts @@ -6,15 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -import {KeyValueArray, arrayIndexOfSorted, arrayInsert, arrayInsert2, arrayInsertSorted, arrayRemoveSorted, arraySplice, flatten, keyValueArrayDelete, keyValueArrayGet, keyValueArrayIndexOf, keyValueArraySet} from '../../src/util/array_utils'; +import {arrayIndexOfSorted, arrayInsert, arrayInsert2, arrayInsertSorted, arrayRemoveSorted, arraySplice, flatten, KeyValueArray, keyValueArrayDelete, keyValueArrayGet, keyValueArrayIndexOf, keyValueArraySet} from '../../src/util/array_utils'; describe('array_utils', () => { - describe('flatten', () => { + it('should flatten an empty array', () => { + expect(flatten([])).toEqual([]); + }); - it('should flatten an empty array', () => { expect(flatten([])).toEqual([]); }); - - it('should flatten a flat array', () => { expect(flatten([1, 2, 3])).toEqual([1, 2, 3]); }); + it('should flatten a flat array', () => { + expect(flatten([1, 2, 3])).toEqual([1, 2, 3]); + }); it('should flatten a nested array depth-first', () => { expect(flatten([1, [2], 3])).toEqual([1, 2, 3]); @@ -75,7 +77,6 @@ describe('array_utils', () => { }); describe('arrayInsertSorted', () => { - it('should insert items don\'t allow duplicates', () => { let a; a = ['a', 'c', 'e', 'g', 'i']; @@ -103,7 +104,6 @@ describe('array_utils', () => { describe('arrayRemoveSorted', () => { - it('should remove items', () => { let a; a = ['a', 'b', 'c', 'd', 'e']; diff --git a/packages/core/test/util/decorators_spec.ts b/packages/core/test/util/decorators_spec.ts index f657f96f254e8..d418f01a6309f 100644 --- a/packages/core/test/util/decorators_spec.ts +++ b/packages/core/test/util/decorators_spec.ts @@ -24,8 +24,7 @@ class DecoratedChild extends DecoratedParent {} const Prop = makePropDecorator('Prop', (value: any) => ({value})); class TestClass { - @Prop('firefox!') - watch: any; + @Prop('firefox!') watch: any; } const p = reflector.propMetadata(TestClass); diff --git a/packages/core/test/util/global_spec.ts b/packages/core/test/util/global_spec.ts index c74e33ea69ca6..7aff2fcd21627 100644 --- a/packages/core/test/util/global_spec.ts +++ b/packages/core/test/util/global_spec.ts @@ -19,7 +19,9 @@ declare var globalThis: any /** TODO #9100 */; }); if (typeof globalThis !== 'undefined') { - it('should use globalThis as global reference', () => { expect(global).toBe(globalThis); }); + it('should use globalThis as global reference', () => { + expect(global).toBe(globalThis); + }); } }); } diff --git a/packages/core/test/util/lang_spec.ts b/packages/core/test/util/lang_spec.ts index 73086b09cf494..d734463171e4c 100644 --- a/packages/core/test/util/lang_spec.ts +++ b/packages/core/test/util/lang_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {isObservable, isPromise} from '@angular/core/src/util/lang'; -import {of } from 'rxjs'; +import {of} from 'rxjs'; { describe('isPromise', () => { @@ -28,7 +28,7 @@ import {of } from 'rxjs'; }); describe('isObservable', () => { - it('should be true for an Observable', () => expect(isObservable(of (true))).toEqual(true)); + it('should be true for an Observable', () => expect(isObservable(of(true))).toEqual(true)); it('should be true if the argument is the object with subscribe function', () => expect(isObservable({subscribe: () => {}})).toEqual(true)); diff --git a/packages/core/test/util/stringify_spec.ts b/packages/core/test/util/stringify_spec.ts index e5ce710f6c0ec..d2e15e2f049d5 100644 --- a/packages/core/test/util/stringify_spec.ts +++ b/packages/core/test/util/stringify_spec.ts @@ -21,7 +21,8 @@ describe('stringify', () => { expect(concatStringsWithSpace('', 'b')).toEqual('b'); }); - it('should concat when not empty', - () => { expect(concatStringsWithSpace('before', 'after')).toEqual('before after'); }); + it('should concat when not empty', () => { + expect(concatStringsWithSpace('before', 'after')).toEqual('before after'); + }); }); }); diff --git a/packages/core/test/view/anchor_spec.ts b/packages/core/test/view/anchor_spec.ts index d19a5a3d3f411..d5e5e9535acf6 100644 --- a/packages/core/test/view/anchor_spec.ts +++ b/packages/core/test/view/anchor_spec.ts @@ -8,13 +8,12 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {getDebugNode} from '@angular/core'; -import {NodeFlags, anchorDef, asElementData, elementDef} from '@angular/core/src/view/index'; +import {anchorDef, asElementData, elementDef, NodeFlags} from '@angular/core/src/view/index'; import {compViewDef, createAndGetRootNodes} from './helper'; { describe(`View Anchor`, () => { - describe('create', () => { it('should create anchor nodes without parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ @@ -43,7 +42,7 @@ import {compViewDef, createAndGetRootNodes} from './helper'; const someContext = {}; const {view, rootNodes} = createAndGetRootNodes( compViewDef([anchorDef(NodeFlags.None, null, null, 0)]), someContext); - expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement); + expect(getDebugNode(rootNodes[0])!.nativeNode).toBe(asElementData(view, 0).renderElement); }); }); }); diff --git a/packages/core/test/view/component_view_spec.ts b/packages/core/test/view/component_view_spec.ts index 1588cd750604e..cb53b9791b82c 100644 --- a/packages/core/test/view/component_view_spec.ts +++ b/packages/core/test/view/component_view_spec.ts @@ -8,7 +8,7 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {SecurityContext} from '@angular/core'; -import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, ViewFlags, ViewState, asElementData, directiveDef, elementDef, rootRenderNodes} from '@angular/core/src/view/index'; +import {ArgumentType, asElementData, BindingFlags, directiveDef, elementDef, NodeCheckFn, NodeFlags, rootRenderNodes, Services, ViewData, ViewFlags, ViewState} from '@angular/core/src/view/index'; import {callMostRecentEventListenerHandler, compViewDef, createAndGetRootNodes, createRootView, isBrowser, recordNodeToRemove} from './helper'; @@ -23,9 +23,11 @@ const addEventListener = 'addEventListener'; { describe(`Component Views`, () => { it('should create and attach component views', () => { - let instance: AComp = undefined !; + let instance: AComp = undefined!; class AComp { - constructor() { instance = this; } + constructor() { + instance = this; + } } const {view, rootNodes} = createAndGetRootNodes(compViewDef([ @@ -108,15 +110,18 @@ const addEventListener = 'addEventListener'; check(view, 0, ArgumentType.Inline, value); }); - const {view, rootNodes} = createAndGetRootNodes( - compViewDef([ - elementDef(0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, () => compViewDef( - [ - elementDef(0, NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]), - ], null, update - )), - directiveDef(1, NodeFlags.Component, null, 0, AComp, []), - ])); + const {view, rootNodes} = createAndGetRootNodes(compViewDef([ + elementDef( + 0, NodeFlags.None, null, null, 1, 'div', null, null, null, null, + () => compViewDef( + [ + elementDef( + 0, NodeFlags.None, null, null, 0, 'span', null, + [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]]), + ], + null, update)), + directiveDef(1, NodeFlags.Component, null, 0, AComp, []), + ])); const compView = asElementData(view, 0).componentView; value = 'v1'; @@ -218,13 +223,15 @@ const addEventListener = 'addEventListener'; [ elementDef( 0, NodeFlags.None, null, null, 0, 'span', null, null, - [[null !, 'click']]), + [[null!, 'click']]), ], update, null, ViewFlags.OnPush); }), directiveDef(1, NodeFlags.Component, null, 0, AComp, [], {a: [0, 'a']}), ], - (check, view) => { check(view, 1, ArgumentType.Inline, compInputValue); })); + (check, view) => { + check(view, 1, ArgumentType.Inline, compInputValue); + })); Services.checkAndUpdateView(view); @@ -272,10 +279,21 @@ const addEventListener = 'addEventListener'; 0, NodeFlags.None, null, null, 0, 'span', null, [[BindingFlags.TypeElementAttribute, 'a', SecurityContext.NONE]])], null, update)), - directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ), + directiveDef( + 1, + NodeFlags.Component, + null, + 0, + AComp, + [], + null, + null, + ), ])); - update.and.callFake((check: NodeCheckFn, view: ViewData) => { throw new Error('Test'); }); + update.and.callFake((check: NodeCheckFn, view: ViewData) => { + throw new Error('Test'); + }); expect(() => Services.checkAndUpdateView(view)).toThrowError('Test'); expect(update).toHaveBeenCalled(); @@ -283,7 +301,6 @@ const addEventListener = 'addEventListener'; expect(() => Services.checkAndUpdateView(view)).toThrowError('Test'); expect(update).toHaveBeenCalled(); }); - }); describe('destroy', () => { @@ -293,7 +310,9 @@ const addEventListener = 'addEventListener'; class AComp {} class ChildProvider { - ngOnDestroy() { log.push('ngOnDestroy'); } + ngOnDestroy() { + log.push('ngOnDestroy'); + } } const {view, rootNodes} = createAndGetRootNodes(compViewDef([ @@ -303,7 +322,16 @@ const addEventListener = 'addEventListener'; elementDef(0, NodeFlags.None, null, null, 1, 'span'), directiveDef(1, NodeFlags.OnDestroy, null, 0, ChildProvider, []) ])), - directiveDef(1, NodeFlags.Component, null, 0, AComp, [], null, null, ), + directiveDef( + 1, + NodeFlags.Component, + null, + 0, + AComp, + [], + null, + null, + ), ])); Services.destroyView(view); @@ -321,6 +349,5 @@ const addEventListener = 'addEventListener'; .toThrowError('ViewDestroyedError: Attempt to use a destroyed view: detectChanges'); }); }); - }); } diff --git a/packages/core/test/view/element_spec.ts b/packages/core/test/view/element_spec.ts index 967cf83884137..551a533adaddb 100644 --- a/packages/core/test/view/element_spec.ts +++ b/packages/core/test/view/element_spec.ts @@ -7,9 +7,9 @@ */ import {ɵgetDOM as getDOM} from '@angular/common'; -import {ErrorHandler, SecurityContext, getDebugNode} from '@angular/core'; +import {ErrorHandler, getDebugNode, SecurityContext} from '@angular/core'; import {getDebugContext} from '@angular/core/src/errors'; -import {BindingFlags, NodeFlags, Services, ViewData, ViewDefinition, asElementData, elementDef} from '@angular/core/src/view/index'; +import {asElementData, BindingFlags, elementDef, NodeFlags, Services, ViewData, ViewDefinition} from '@angular/core/src/view/index'; import {TestBed} from '@angular/core/testing'; import {ARG_TYPE_VALUES, callMostRecentEventListenerHandler, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes, isBrowser, recordNodeToRemove} from './helper'; @@ -25,7 +25,6 @@ const removeEventListener = 'removeEventListener'; { describe(`View Elements`, () => { - describe('create', () => { it('should create elements without parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([ @@ -65,14 +64,13 @@ const removeEventListener = 'removeEventListener'; const someContext = {}; const {view, rootNodes} = createAndGetRootNodes( compViewDef([elementDef(0, NodeFlags.None, null, null, 0, 'div')]), someContext); - expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asElementData(view, 0).renderElement); + expect(getDebugNode(rootNodes[0])!.nativeNode).toBe(asElementData(view, 0).renderElement); }); }); describe('change properties', () => { ARG_TYPE_VALUES.forEach((inlineDynamic) => { it(`should update via strategy ${inlineDynamic}`, () => { - const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ elementDef( @@ -189,7 +187,7 @@ const removeEventListener = 'removeEventListener'; const removeListenerSpy = spyOn(HTMLElement.prototype, removeEventListener).and.callThrough(); const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']], + 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null!, 'click']], handleEventSpy)])); rootNodes[0].click(); @@ -253,10 +251,10 @@ const removeEventListener = 'removeEventListener'; it('should preventDefault only if the handler returns false', () => { let eventHandlerResult: any; - let preventDefaultSpy: jasmine.Spy = undefined !; + let preventDefaultSpy: jasmine.Spy = undefined!; const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']], + 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null!, 'click']], (view, eventName, event) => { preventDefaultSpy = spyOn(event, 'preventDefault').and.callThrough(); return eventHandlerResult; @@ -283,8 +281,9 @@ const removeEventListener = 'removeEventListener'; const handleErrorSpy = spyOn(TestBed.inject(ErrorHandler), 'handleError'); const addListenerSpy = spyOn(HTMLElement.prototype, addEventListener).and.callThrough(); const {view, rootNodes} = createAndAttachAndGetRootNodes(compViewDef([elementDef( - 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null !, 'click']], - () => { throw new Error('Test'); })])); + 0, NodeFlags.None, null, null, 0, 'button', null, null, [[null!, 'click']], () => { + throw new Error('Test'); + })])); callMostRecentEventListenerHandler(addListenerSpy, 'SomeEvent'); const err = handleErrorSpy.calls.mostRecent().args[0]; diff --git a/packages/core/test/view/embedded_view_spec.ts b/packages/core/test/view/embedded_view_spec.ts index f327981582346..d1c3d5f0b2a50 100644 --- a/packages/core/test/view/embedded_view_spec.ts +++ b/packages/core/test/view/embedded_view_spec.ts @@ -8,13 +8,12 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {SecurityContext} from '@angular/core'; -import {ArgumentType, BindingFlags, NodeCheckFn, NodeFlags, Services, ViewData, anchorDef, asElementData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, rootRenderNodes} from '@angular/core/src/view/index'; +import {anchorDef, ArgumentType, asElementData, attachEmbeddedView, BindingFlags, detachEmbeddedView, directiveDef, elementDef, moveEmbeddedView, NodeCheckFn, NodeFlags, rootRenderNodes, Services, ViewData} from '@angular/core/src/view/index'; import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper'; { describe(`Embedded Views`, () => { - it('should create embedded views with the right context', () => { const parentContext = {}; const childContext = {}; @@ -39,9 +38,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']]) ])), - anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef( - 0, NodeFlags.None, null, null, 0, 'span', - [['name', 'child1']])])) + anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child1']]) + ])) ])); const viewContainerData = asElementData(parentView, 1); const rf = parentView.root.rendererFactory; @@ -58,10 +57,10 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi expect(rootChildren[1].getAttribute('name')).toBe('child0'); expect(rootChildren[2].getAttribute('name')).toBe('child1'); - rf.begin !(); + rf.begin!(); detachEmbeddedView(viewContainerData, 1); detachEmbeddedView(viewContainerData, 0); - rf.end !(); + rf.end!(); expect(rootNodes[0].childNodes.length).toBe(2); }); @@ -72,9 +71,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi anchorDef(NodeFlags.EmbeddedViews, null, null, 0, null, compViewDefFactory([ elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child0']]) ])), - anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([elementDef( - 0, NodeFlags.None, null, null, 0, 'span', - [['name', 'child1']])])) + anchorDef(NodeFlags.None, null, null, 0, null, compViewDefFactory([ + elementDef(0, NodeFlags.None, null, null, 0, 'span', [['name', 'child1']]) + ])) ])); const viewContainerData = asElementData(parentView, 1); @@ -86,7 +85,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi moveEmbeddedView(viewContainerData, 0, 1); - expect(viewContainerData.viewContainer !._embeddedViews).toEqual([childView1, childView0]); + expect(viewContainerData.viewContainer!._embeddedViews).toEqual([childView1, childView0]); // 2 anchors + 2 elements const rootChildren = rootNodes[0].childNodes; expect(rootChildren.length).toBe(4); @@ -152,7 +151,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi const log: string[] = []; class ChildProvider { - ngOnDestroy() { log.push('ngOnDestroy'); } + ngOnDestroy() { + log.push('ngOnDestroy'); + } } const {view: parentView} = createAndGetRootNodes(compViewDef([ diff --git a/packages/core/test/view/helper.ts b/packages/core/test/view/helper.ts index 537355d7a0a09..3efd574c40ee1 100644 --- a/packages/core/test/view/helper.ts +++ b/packages/core/test/view/helper.ts @@ -8,7 +8,7 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {Injector, NgModuleRef} from '@angular/core'; -import {ArgumentType, NodeCheckFn, NodeDef, Services, ViewData, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewUpdateFn, initServicesIfNeeded, rootRenderNodes, viewDef} from '@angular/core/src/view/index'; +import {ArgumentType, initServicesIfNeeded, NodeCheckFn, NodeDef, rootRenderNodes, Services, ViewData, viewDef, ViewDefinition, ViewDefinitionFactory, ViewFlags, ViewUpdateFn} from '@angular/core/src/view/index'; import {TestBed} from '@angular/core/testing'; export function isBrowser() { @@ -38,11 +38,11 @@ export function createRootView( } export function createEmbeddedView(parent: ViewData, anchorDef: NodeDef, context?: any): ViewData { - return Services.createEmbeddedView(parent, anchorDef, anchorDef.element !.template !, context); + return Services.createEmbeddedView(parent, anchorDef, anchorDef.element!.template !, context); } export function compViewDef( - nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn, + nodes: NodeDef[], updateDirectives?: null|ViewUpdateFn, updateRenderer?: null|ViewUpdateFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinition { const def = viewDef(viewFlags, nodes, updateDirectives, updateRenderer); @@ -53,8 +53,8 @@ export function compViewDef( // This check should be removed when we start reordering nodes at runtime if (node.checkIndex > -1 && node.checkIndex !== node.nodeIndex) { - throw new Error( - `nodeIndex and checkIndex should be the same, got ${node.nodeIndex} !== ${node.checkIndex}`); + throw new Error(`nodeIndex and checkIndex should be the same, got ${node.nodeIndex} !== ${ + node.checkIndex}`); } }); @@ -62,7 +62,7 @@ export function compViewDef( } export function compViewDefFactory( - nodes: NodeDef[], updateDirectives?: null | ViewUpdateFn, updateRenderer?: null | ViewUpdateFn, + nodes: NodeDef[], updateDirectives?: null|ViewUpdateFn, updateRenderer?: null|ViewUpdateFn, viewFlags: ViewFlags = ViewFlags.None): ViewDefinitionFactory { return () => compViewDef(nodes, updateDirectives, updateRenderer, viewFlags); } @@ -76,8 +76,12 @@ export function createAndGetRootNodes( let removeNodes: Node[]; -beforeEach(() => { removeNodes = []; }); -afterEach(() => { removeNodes.forEach((node) => getDOM().remove(node)); }); +beforeEach(() => { + removeNodes = []; +}); +afterEach(() => { + removeNodes.forEach((node) => getDOM().remove(node)); +}); export function recordNodeToRemove(node: Node) { removeNodes.push(node); diff --git a/packages/core/test/view/ng_content_spec.ts b/packages/core/test/view/ng_content_spec.ts index a2be95f301168..ae393ba29dec7 100644 --- a/packages/core/test/view/ng_content_spec.ts +++ b/packages/core/test/view/ng_content_spec.ts @@ -8,7 +8,7 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {TemplateRef, ViewContainerRef} from '@angular/core'; -import {NodeDef, NodeFlags, ViewData, ViewDefinition, anchorDef, asElementData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, rootRenderNodes, textDef} from '@angular/core/src/view/index'; +import {anchorDef, asElementData, asTextData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, ngContentDef, NodeDef, NodeFlags, rootRenderNodes, textDef, ViewData, ViewDefinition} from '@angular/core/src/view/index'; import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isBrowser} from './helper'; @@ -74,27 +74,23 @@ import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isB } } - const {view, rootNodes} = - createAndGetRootNodes( - compViewDef( - hostElDef(0, - [ - anchorDef( - NodeFlags.EmbeddedViews, null, 0, 1, null, - compViewDefFactory([textDef(0, null, ['a'])])), - directiveDef(3, - NodeFlags.None, null, 0, CreateViewService, - [TemplateRef, ViewContainerRef]), - ], - [ - elementDef(0, NodeFlags.None, null, null, 1, 'div'), - ngContentDef(null, 0), - ]))); + const {view, rootNodes} = createAndGetRootNodes(compViewDef(hostElDef( + 0, + [ + anchorDef(NodeFlags.EmbeddedViews, null, 0, 1, null, compViewDefFactory([textDef( + 0, null, ['a'])])), + directiveDef( + 3, NodeFlags.None, null, 0, CreateViewService, [TemplateRef, ViewContainerRef]), + ], + [ + elementDef(0, NodeFlags.None, null, null, 1, 'div'), + ngContentDef(null, 0), + ]))); const anchor = asElementData(view, 2); const child = rootNodes[0].firstChild; expect(child.childNodes[0]).toBe(anchor.renderElement); - const embeddedView = anchor.viewContainer !._embeddedViews[0]; + const embeddedView = anchor.viewContainer!._embeddedViews[0]; expect(child.childNodes[1]).toBe(asTextData(embeddedView, 0).renderText); }); @@ -118,9 +114,9 @@ import {compViewDef, compViewDefFactory, createEmbeddedView, createRootView, isB expect(child.childNodes.length).toBe(3); expect(child.childNodes[1]).toBe(asTextData(view, 2).renderText); - rf.begin !(); + rf.begin!(); detachEmbeddedView(asElementData(componentView, 1), 0); - rf.end !(); + rf.end!(); child = rootNodes[0].firstChild; expect(child.childNodes.length).toBe(1); }); diff --git a/packages/core/test/view/ng_module_spec.ts b/packages/core/test/view/ng_module_spec.ts index 249ecf5bbcf04..0d8d313e1b168 100644 --- a/packages/core/test/view/ng_module_spec.ts +++ b/packages/core/test/view/ng_module_spec.ts @@ -7,10 +7,10 @@ */ import {NgModuleRef, ɵINJECTOR_SCOPE as INJECTOR_SCOPE} from '@angular/core'; -import {InjectFlags, inject} from '@angular/core/src/di'; +import {inject, InjectFlags} from '@angular/core/src/di'; import {Injector} from '@angular/core/src/di/injector'; import {INJECTOR} from '@angular/core/src/di/injector_compatibility'; -import {ɵɵInjectableDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs'; +import {ɵɵdefineInjectable, ɵɵInjectableDef} from '@angular/core/src/di/interface/defs'; import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/src/view'; import {moduleDef} from '@angular/core/src/view/ng_module'; import {createNgModuleRef} from '@angular/core/src/view/refs'; @@ -94,25 +94,28 @@ class FromChildWithSkipSelfDep { static ɵprov: ɵɵInjectableDef<FromChildWithSkipSelfDep> = ɵɵdefineInjectable({ token: FromChildWithSkipSelfDep, factory: () => new FromChildWithSkipSelfDep( - inject(ChildDep, InjectFlags.SkipSelf|InjectFlags.Optional), - inject(ChildDep, InjectFlags.Self), - inject(Bar, InjectFlags.Self|InjectFlags.Optional), ), + inject(ChildDep, InjectFlags.SkipSelf|InjectFlags.Optional), + inject(ChildDep, InjectFlags.Self), + inject(Bar, InjectFlags.Self|InjectFlags.Optional), + ), providedIn: MyChildModule, }); } class UsesInject { - constructor() { inject(INJECTOR); } + constructor() { + inject(INJECTOR); + } } function makeProviders(classes: any[], modules: any[]): NgModuleDefinition { - const providers = - classes.map((token, index) => ({ - index, - deps: [], - flags: NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, token, - value: token, - })); + const providers = classes.map((token, index) => ({ + index, + deps: [], + flags: NodeFlags.TypeClassProvider | NodeFlags.LazyProvider, + token, + value: token, + })); return makeModule(modules, providers); } @@ -144,14 +147,17 @@ describe('NgModuleRef_ injector', () => { MyChildModule, ref.injector, [], makeProviders([MyChildModule], [MyChildModule])); }); - it('injects a provided value', - () => { expect(ref.injector.get(Foo) instanceof Foo).toBeTruthy(); }); + it('injects a provided value', () => { + expect(ref.injector.get(Foo) instanceof Foo).toBeTruthy(); + }); - it('injects an InjectableDef value', - () => { expect(ref.injector.get(Bar) instanceof Bar).toBeTruthy(); }); + it('injects an InjectableDef value', () => { + expect(ref.injector.get(Bar) instanceof Bar).toBeTruthy(); + }); - it('caches InjectableDef values', - () => { expect(ref.injector.get(Bar)).toBe(ref.injector.get(Bar)); }); + it('caches InjectableDef values', () => { + expect(ref.injector.get(Bar)).toBe(ref.injector.get(Bar)); + }); it('injects provided deps properly', () => { const instance = ref.injector.get(HasNormalDep); @@ -179,27 +185,32 @@ describe('NgModuleRef_ injector', () => { expect(instance.optionalSelfBar).toBeNull(); }); - it('does not inject something not scoped to the module', - () => { expect(ref.injector.get(Baz, null)).toBeNull(); }); + it('does not inject something not scoped to the module', () => { + expect(ref.injector.get(Baz, null)).toBeNull(); + }); - it('injects with the current injector always set', - () => { expect(() => ref.injector.get(UsesInject)).not.toThrow(); }); + it('injects with the current injector always set', () => { + expect(() => ref.injector.get(UsesInject)).not.toThrow(); + }); it('calls ngOnDestroy on services created via factory', () => { class Module {} class Service { static destroyed = 0; - ngOnDestroy(): void { Service.destroyed++; } + ngOnDestroy(): void { + Service.destroyed++; + } } const ref = createNgModuleRef( - Module, Injector.NULL, [], makeFactoryProviders( - [{ - token: Service, - factory: () => new Service(), - }], - [Module])); + Module, Injector.NULL, [], + makeFactoryProviders( + [{ + token: Service, + factory: () => new Service(), + }], + [Module])); expect(ref.injector.get(Service)).toBeDefined(); expect(Service.destroyed).toBe(0); @@ -213,7 +224,9 @@ describe('NgModuleRef_ injector', () => { class Service { static destroyed = 0; - ngOnDestroy(): void { Service.destroyed++; } + ngOnDestroy(): void { + Service.destroyed++; + } static ɵprov: ɵɵInjectableDef<Service> = ɵɵdefineInjectable({ token: Service, @@ -235,25 +248,28 @@ describe('NgModuleRef_ injector', () => { class Service { static destroyed = 0; - ngOnDestroy(): void { Service.destroyed++; } + ngOnDestroy(): void { + Service.destroyed++; + } } class OtherToken {} const instance = new Service(); const ref = createNgModuleRef( - Module, Injector.NULL, [], makeFactoryProviders( - [ - { - token: Service, - factory: () => instance, - }, - { - token: OtherToken, - factory: () => instance, - } - ], - [Module])); + Module, Injector.NULL, [], + makeFactoryProviders( + [ + { + token: Service, + factory: () => instance, + }, + { + token: OtherToken, + factory: () => instance, + } + ], + [Module])); expect(ref.injector.get(Service)).toBe(instance); expect(ref.injector.get(OtherToken)).toBe(instance); @@ -267,7 +283,9 @@ describe('NgModuleRef_ injector', () => { return { index: 0, flags: NodeFlags.TypeValueProvider | NodeFlags.LazyProvider, - deps: [], token, value + deps: [], + token, + value }; } diff --git a/packages/core/test/view/provider_spec.ts b/packages/core/test/view/provider_spec.ts index cab5b26bc83f3..041b237b12679 100644 --- a/packages/core/test/view/provider_spec.ts +++ b/packages/core/test/view/provider_spec.ts @@ -6,26 +6,29 @@ * found in the LICENSE file at https://angular.io/license */ +import {ɵgetDOM as getDOM} from '@angular/common'; import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, ChangeDetectorRef, DoCheck, ElementRef, ErrorHandler, EventEmitter, Injector, OnChanges, OnDestroy, OnInit, Renderer2, SimpleChange, TemplateRef, ViewContainerRef,} from '@angular/core'; import {getDebugContext} from '@angular/core/src/errors'; -import {ArgumentType, DepFlags, NodeFlags, Services, anchorDef, asElementData, directiveDef, elementDef, providerDef, textDef} from '@angular/core/src/view/index'; +import {anchorDef, ArgumentType, asElementData, DepFlags, directiveDef, elementDef, NodeFlags, providerDef, Services, textDef} from '@angular/core/src/view/index'; import {TestBed, withModule} from '@angular/core/testing'; -import {ɵgetDOM as getDOM} from '@angular/common'; import {ivyEnabled} from '@angular/private/testing'; -import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetRootNodes, compViewDef, compViewDefFactory} from './helper'; +import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, compViewDefFactory, createAndGetRootNodes, createRootView} from './helper'; { describe(`View Providers`, () => { - describe('create', () => { let instance: SomeService; class SomeService { - constructor(public dep: any) { instance = this; } + constructor(public dep: any) { + instance = this; + } } - beforeEach(() => { instance = null !; }); + beforeEach(() => { + instance = null!; + }); it('should create providers eagerly', () => { createAndGetRootNodes(compViewDef([ @@ -37,9 +40,11 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR }); it('should create providers lazily', () => { - let lazy: LazyService = undefined !; + let lazy: LazyService = undefined!; class LazyService { - constructor() { lazy = this; } + constructor() { + lazy = this; + } } createAndGetRootNodes(compViewDef([ @@ -66,7 +71,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR }); it('should create factory providers', () => { - function someFactory() { return 'someValue'; } + function someFactory() { + return 'someValue'; + } createAndGetRootNodes(compViewDef([ elementDef(0, NodeFlags.None, null, null, 2, 'span'), @@ -91,7 +98,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR it('should add a DebugContext to errors in provider factories', () => { class SomeService { - constructor() { throw new Error('Test'); } + constructor() { + throw new Error('Test'); + } } let err: any; @@ -148,7 +157,10 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR expect(() => createAndGetRootNodes(compViewDef(rootElNodes))) .toThrowError( - `${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` + + `${ + ivyEnabled ? + 'R3InjectorError' : + 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` + ' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' + ' NullInjectorError: No provider for Dep!'); @@ -162,7 +174,10 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR expect(() => createAndGetRootNodes(compViewDef(nonRootElNodes))) .toThrowError( - `${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` + + `${ + ivyEnabled ? + 'R3InjectorError' : + 'StaticInjectorError'}(DynamicTestModule)[SomeService -> Dep]: \n` + ' StaticInjectorError(Platform: core)[SomeService -> Dep]: \n' + ' NullInjectorError: No provider for Dep!'); }); @@ -187,7 +202,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR directiveDef(1, NodeFlags.None, null, 0, SomeService, ['nonExistingDep']) ]))) .toThrowError( - `${ivyEnabled ? 'R3InjectorError' : 'StaticInjectorError'}(DynamicTestModule)[nonExistingDep]: \n` + + `${ + ivyEnabled ? 'R3InjectorError' : + 'StaticInjectorError'}(DynamicTestModule)[nonExistingDep]: \n` + ' StaticInjectorError(Platform: core)[nonExistingDep]: \n' + ' NullInjectorError: No provider for nonExistingDep!'); }); @@ -196,8 +213,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR createAndGetRootNodes(compViewDef([ elementDef(0, NodeFlags.None, null, null, 1, 'span'), directiveDef( - 1, NodeFlags.None, null, 0, SomeService, - [[DepFlags.Optional, 'nonExistingDep']]) + 1, NodeFlags.None, null, 0, SomeService, [[DepFlags.Optional, 'nonExistingDep']]) ])); expect(instance.dep).toBe(null); }); @@ -295,22 +311,21 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR expect(instance.dep.createElement).toBeTruthy(); }); - }); - }); }); describe('data binding', () => { - ARG_TYPE_VALUES.forEach((inlineDynamic) => { it(`should update via strategy ${inlineDynamic}`, () => { - let instance: SomeService = undefined !; + let instance: SomeService = undefined!; class SomeService { a: any; b: any; - constructor() { instance = this; } + constructor() { + instance = this; + } } const {view, rootNodes} = createAndGetRootNodes(compViewDef( @@ -331,7 +346,6 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR const el = rootNodes[0]; expect(el.getAttribute('ng-reflect-a')).toBe('v1'); }); - }); }); @@ -376,7 +390,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR const {view, rootNodes} = createAndGetRootNodes(compViewDef([ elementDef( 0, NodeFlags.None, null, null, 1, 'span', null, null, null, - () => { throw new Error('Test'); }), + () => { + throw new Error('Test'); + }), directiveDef( 1, NodeFlags.None, null, 0, SomeService, [], null, {emitter: 'someEventName'}) ])); @@ -397,18 +413,37 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR let log: string[] = []; class SomeService implements OnInit, DoCheck, OnChanges, AfterContentInit, - AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy { + AfterContentChecked, AfterViewInit, AfterViewChecked, + OnDestroy { id: number; a: any; - ngOnInit() { log.push(`${this.id}_ngOnInit`); } - ngDoCheck() { log.push(`${this.id}_ngDoCheck`); } - ngOnChanges() { log.push(`${this.id}_ngOnChanges`); } - ngAfterContentInit() { log.push(`${this.id}_ngAfterContentInit`); } - ngAfterContentChecked() { log.push(`${this.id}_ngAfterContentChecked`); } - ngAfterViewInit() { log.push(`${this.id}_ngAfterViewInit`); } - ngAfterViewChecked() { log.push(`${this.id}_ngAfterViewChecked`); } - ngOnDestroy() { log.push(`${this.id}_ngOnDestroy`); } - constructor() { this.id = instanceCount++; } + ngOnInit() { + log.push(`${this.id}_ngOnInit`); + } + ngDoCheck() { + log.push(`${this.id}_ngDoCheck`); + } + ngOnChanges() { + log.push(`${this.id}_ngOnChanges`); + } + ngAfterContentInit() { + log.push(`${this.id}_ngAfterContentInit`); + } + ngAfterContentChecked() { + log.push(`${this.id}_ngAfterContentChecked`); + } + ngAfterViewInit() { + log.push(`${this.id}_ngAfterViewInit`); + } + ngAfterViewChecked() { + log.push(`${this.id}_ngAfterViewChecked`); + } + ngOnDestroy() { + log.push(`${this.id}_ngOnDestroy`); + } + constructor() { + this.id = instanceCount++; + } } const allFlags = NodeFlags.OnInit | NodeFlags.DoCheck | NodeFlags.OnChanges | @@ -479,7 +514,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR directiveDef( 1, NodeFlags.OnChanges, null, 0, SomeService, [], {a: [0, 'nonMinifiedA']}) ], - (check, view) => { check(view, 1, ArgumentType.Inline, currValue); })); + (check, view) => { + check(view, 1, ArgumentType.Inline, currValue); + })); Services.checkAndUpdateView(view); expect(changesLog).toEqual([new SimpleChange(undefined, 'v1', true)]); @@ -492,7 +529,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR it('should add a DebugContext to errors in provider afterXXX lifecycles', () => { class SomeService implements AfterContentChecked { - ngAfterContentChecked() { throw new Error('Test'); } + ngAfterContentChecked() { + throw new Error('Test'); + } } const {view, rootNodes} = createAndGetRootNodes(compViewDef([ @@ -515,7 +554,9 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, createRootView, createAndGetR it('should add a DebugContext to errors inServices.destroyView', () => { class SomeService implements OnDestroy { - ngOnDestroy() { throw new Error('Test'); } + ngOnDestroy() { + throw new Error('Test'); + } } const {view, rootNodes} = createAndGetRootNodes(compViewDef([ diff --git a/packages/core/test/view/pure_expression_spec.ts b/packages/core/test/view/pure_expression_spec.ts index 03e42cd2ceba7..373522c75228e 100644 --- a/packages/core/test/view/pure_expression_spec.ts +++ b/packages/core/test/view/pure_expression_spec.ts @@ -7,19 +7,17 @@ */ import {PipeTransform} from '@angular/core'; -import {NodeFlags, Services, asProviderData, directiveDef, elementDef, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef} from '@angular/core/src/view/index'; +import {asProviderData, directiveDef, elementDef, NodeFlags, nodeValue, pipeDef, pureArrayDef, pureObjectDef, purePipeDef, Services} from '@angular/core/src/view/index'; import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper'; { describe(`View Pure Expressions`, () => { - class Service { data: any; } describe('pure arrays', () => { - ARG_TYPE_VALUES.forEach((inlineDynamic) => { it(`should update via strategy ${inlineDynamic}`, () => { let values: any[]; @@ -52,9 +50,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot expect(arr1).not.toBe(arr0); expect(arr1).toEqual([3, 2]); }); - }); - }); describe('pure objects', () => { @@ -90,7 +86,6 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot expect(obj1).not.toBe(obj0); expect(obj1).toEqual({a: 3, b: 2}); }); - }); }); @@ -98,14 +93,16 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot ARG_TYPE_VALUES.forEach((inlineDynamic) => { it(`should update via strategy ${inlineDynamic}`, () => { class SomePipe implements PipeTransform { - transform(v1: any, v2: any) { return [v1 + 10, v2 + 20]; } + transform(v1: any, v2: any) { + return [v1 + 10, v2 + 20]; + } } let values: any[]; const {view, rootNodes} = createAndGetRootNodes(compViewDef( [ - elementDef(0, NodeFlags.None, null !, null !, 3, 'span'), + elementDef(0, NodeFlags.None, null!, null!, 3, 'span'), pipeDef(NodeFlags.None, SomePipe, []), purePipeDef(2, 2), directiveDef(3, NodeFlags.None, null, 0, Service, [], {data: [0, 'data']}), @@ -133,7 +130,6 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot expect(obj1).not.toBe(obj0); expect(obj1).toEqual([13, 22]); }); - }); }); }); diff --git a/packages/core/test/view/query_spec.ts b/packages/core/test/view/query_spec.ts index 1eba518ca9865..a5063d8a74403 100644 --- a/packages/core/test/view/query_spec.ts +++ b/packages/core/test/view/query_spec.ts @@ -8,20 +8,19 @@ import {ElementRef, QueryList, TemplateRef, ViewContainerRef} from '@angular/core'; import {getDebugContext} from '@angular/core/src/errors'; -import {NodeDef, NodeFlags, QueryBindingType, QueryValueType, Services, anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, queryDef} from '@angular/core/src/view/index'; +import {anchorDef, asElementData, asProviderData, attachEmbeddedView, detachEmbeddedView, directiveDef, elementDef, NodeDef, NodeFlags, QueryBindingType, queryDef, QueryValueType, Services} from '@angular/core/src/view/index'; import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedView} from './helper'; { describe(`Query Views`, () => { - const someQueryId = 1; class AService {} class QueryService { // TODO(issue/24571): remove '!'. - a !: QueryList<AService>; + a!: QueryList<AService>; } function contentQueryProviders(checkIndex: number) { @@ -47,7 +46,15 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi ...nodes ])), directiveDef( - checkIndex + 1, NodeFlags.Component, null !, 0, QueryService, [], null !, null !, ), + checkIndex + 1, + NodeFlags.Component, + null!, + 0, + QueryService, + [], + null!, + null!, + ), ]; } @@ -60,7 +67,6 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi } describe('content queries', () => { - it('should query providers on the same element and child elements', () => { const {view} = createAndGetRootNodes(compViewDef([ elementDef(0, NodeFlags.None, null, null, 5, 'div'), @@ -77,12 +83,11 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi const as = qs.a.toArray(); expect(as.length).toBe(2); - expect(as[0]).toBe(asProviderData(view, 3).instance); - expect(as[1]).toBe(asProviderData(view, 5).instance); + expect(as [0]).toBe(asProviderData(view, 3).instance); + expect(as [1]).toBe(asProviderData(view, 5).instance); }); it('should not query providers on sibling or parent elements', () => { - const {view} = createAndGetRootNodes(compViewDef([ elementDef(0, NodeFlags.None, null, null, 6, 'div'), aServiceProvider(1), @@ -249,7 +254,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi it('should query all matches', () => { class QueryService { // TODO(issue/24571): remove '!'. - a !: QueryList<AService>; + a!: QueryList<AService>; } const {view} = createAndGetRootNodes(compViewDef([ @@ -275,7 +280,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi it('should query the first match', () => { class QueryService { // TODO(issue/24571): remove '!'. - a !: AService; + a!: AService; } const {view} = createAndGetRootNodes(compViewDef([ @@ -299,7 +304,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi it('should query ElementRef', () => { class QueryService { // TODO(issue/24571): remove '!'. - a !: ElementRef; + a!: ElementRef; } const {view} = createAndGetRootNodes(compViewDef([ @@ -319,7 +324,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi it('should query TemplateRef', () => { class QueryService { // TODO(issue/24571): remove '!'. - a !: TemplateRef<any>; + a!: TemplateRef<any>; } const {view} = createAndGetRootNodes(compViewDef([ @@ -341,7 +346,7 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi it('should query ViewContainerRef', () => { class QueryService { // TODO(issue/24571): remove '!'. - a !: ViewContainerRef; + a!: ViewContainerRef; } const {view} = createAndGetRootNodes(compViewDef([ @@ -363,7 +368,9 @@ import {compViewDef, compViewDefFactory, createAndGetRootNodes, createEmbeddedVi describe('general binding behavior', () => { it('should report debug info on binding errors', () => { class QueryService { - set a(value: any) { throw new Error('Test'); } + set a(value: any) { + throw new Error('Test'); + } } const {view} = createAndGetRootNodes(compViewDef([ diff --git a/packages/core/test/view/services_spec.ts b/packages/core/test/view/services_spec.ts index c97ff6c7b5cad..7ce90cf40bda0 100644 --- a/packages/core/test/view/services_spec.ts +++ b/packages/core/test/view/services_spec.ts @@ -6,13 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {DebugContext, NodeFlags, QueryValueType, Services, asElementData, asTextData, directiveDef, elementDef, textDef} from '@angular/core/src/view/index'; +import {asElementData, asTextData, DebugContext, directiveDef, elementDef, NodeFlags, QueryValueType, Services, textDef} from '@angular/core/src/view/index'; import {compViewDef, createAndGetRootNodes} from './helper'; { describe('View Services', () => { - describe('DebugContext', () => { class AComp {} diff --git a/packages/core/test/view/text_spec.ts b/packages/core/test/view/text_spec.ts index ad169872e10fd..e5e907721df4d 100644 --- a/packages/core/test/view/text_spec.ts +++ b/packages/core/test/view/text_spec.ts @@ -8,13 +8,12 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {getDebugNode} from '@angular/core'; -import {NodeFlags, Services, asTextData, elementDef, textDef} from '@angular/core/src/view/index'; +import {asTextData, elementDef, NodeFlags, Services, textDef} from '@angular/core/src/view/index'; import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRootNodes} from './helper'; { describe(`View Text`, () => { - describe('create', () => { it('should create text nodes without parents', () => { const rootNodes = createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])])).rootNodes; @@ -44,7 +43,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot const someContext = {}; const {view, rootNodes} = createAndGetRootNodes(compViewDef([textDef(0, null, ['a'])]), someContext); - expect(getDebugNode(rootNodes[0]) !.nativeNode).toBe(asTextData(view, 0).renderText); + expect(getDebugNode(rootNodes[0])!.nativeNode).toBe(asTextData(view, 0).renderText); }); }); @@ -55,7 +54,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot [ textDef(0, null, ['0', '1', '2']), ], - null !, (check, view) => { + null!, (check, view) => { checkNodeInlineOrDynamic(check, view, 0, inlineDynamic, ['a', 'b']); })); @@ -63,9 +62,7 @@ import {ARG_TYPE_VALUES, checkNodeInlineOrDynamic, compViewDef, createAndGetRoot expect(rootNodes[0].textContent).toBe('0a1b2'); }); - }); }); - }); } diff --git a/packages/core/test/view/view_def_spec.ts b/packages/core/test/view/view_def_spec.ts index 99fc389ce9f25..b7c3b7afcf97d 100644 --- a/packages/core/test/view/view_def_spec.ts +++ b/packages/core/test/view/view_def_spec.ts @@ -6,14 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {NodeFlags, QueryValueType, ViewDefinition, ViewFlags, anchorDef, directiveDef, elementDef, textDef, viewDef} from '@angular/core/src/view/index'; +import {anchorDef, directiveDef, elementDef, NodeFlags, QueryValueType, textDef, viewDef, ViewDefinition, ViewFlags} from '@angular/core/src/view/index'; import {filterQueryId} from '@angular/core/src/view/util'; { describe('viewDef', () => { - describe('parent', () => { - function parents(viewDef: ViewDefinition): (number | null)[] { + function parents(viewDef: ViewDefinition): (number|null)[] { return viewDef.nodes.map(node => node.parent ? node.parent.nodeIndex : null); } @@ -54,7 +53,6 @@ import {filterQueryId} from '@angular/core/src/view/util'; }); describe('childFlags', () => { - function childFlags(viewDef: ViewDefinition): number[] { return viewDef.nodes.map(node => node.childFlags); } @@ -122,7 +120,7 @@ import {filterQueryId} from '@angular/core/src/view/util'; const vd = viewDef(ViewFlags.None, [ elementDef(0, NodeFlags.None, null, null, 2, 'span'), elementDef(1, NodeFlags.None, null, null, 1, 'span'), - directiveDef(2, NodeFlags.AfterContentChecked, null !, 0, AService, []), + directiveDef(2, NodeFlags.AfterContentChecked, null!, 0, AService, []), elementDef(3, NodeFlags.None, null, null, 2, 'span'), directiveDef(4, NodeFlags.AfterContentInit, null, 0, AService, []), directiveDef(5, NodeFlags.AfterViewInit, null, 0, AService, []), diff --git a/packages/core/test/zone/ng_zone_spec.ts b/packages/core/test/zone/ng_zone_spec.ts index ba8e79572717e..13d0d5389bf2d 100644 --- a/packages/core/test/zone/ng_zone_spec.ts +++ b/packages/core/test/zone/ng_zone_spec.ts @@ -8,8 +8,9 @@ import {EventEmitter, NgZone} from '@angular/core'; import {async, fakeAsync, flushMicrotasks} from '@angular/core/testing'; -import {AsyncTestCompleter, Log, beforeEach, describe, expect, inject, it, xit} from '@angular/core/testing/src/testing_internal'; +import {AsyncTestCompleter, beforeEach, describe, expect, inject, it, Log, xit} from '@angular/core/testing/src/testing_internal'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; + import {scheduleMicroTask} from '../../src/util/microtask'; import {NoopNgZone} from '../../src/zone/ng_zone'; @@ -89,7 +90,9 @@ function runNgZoneNoLog(fn: () => any) { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { macroTask(() => { let resolve: (result: any) => void; - const promise: Promise<any> = new Promise((res) => { resolve = res; }); + const promise: Promise<any> = new Promise((res) => { + resolve = res; + }); _zone.run(() => { setTimeout(() => { @@ -112,7 +115,9 @@ function runNgZoneNoLog(fn: () => any) { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { macroTask(() => { let resolve: (result: any) => void; - const promise: Promise<any> = new Promise((res) => { resolve = res; }); + const promise: Promise<any> = new Promise((res) => { + resolve = res; + }); _zone.run(() => { scheduleMicroTask(() => { @@ -147,7 +152,9 @@ function runNgZoneNoLog(fn: () => any) { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { macroTask(() => { let resolve: (result: any) => void; - const promise: Promise<any> = new Promise((res) => { resolve = res; }); + const promise: Promise<any> = new Promise((res) => { + resolve = res; + }); _zone.run(() => { setTimeout(() => { @@ -177,7 +184,11 @@ function runNgZoneNoLog(fn: () => any) { it('should run', () => { let runs = false; ngZone.run(() => { - ngZone.runGuarded(() => { ngZone.runOutsideAngular(() => { runs = true; }); }); + ngZone.runGuarded(() => { + ngZone.runOutsideAngular(() => { + runs = true; + }); + }); }); expect(runs).toBe(true); }); @@ -223,33 +234,47 @@ function runNgZoneNoLog(fn: () => any) { function commonTests() { describe('hasPendingMicrotasks', () => { - it('should be false', () => { expect(_zone.hasPendingMicrotasks).toBe(false); }); + it('should be false', () => { + expect(_zone.hasPendingMicrotasks).toBe(false); + }); it('should be true', () => { - runNgZoneNoLog(() => { scheduleMicroTask(() => {}); }); + runNgZoneNoLog(() => { + scheduleMicroTask(() => {}); + }); expect(_zone.hasPendingMicrotasks).toBe(true); }); }); describe('hasPendingTimers', () => { - it('should be false', () => { expect(_zone.hasPendingMacrotasks).toBe(false); }); + it('should be false', () => { + expect(_zone.hasPendingMacrotasks).toBe(false); + }); it('should be true', () => { - runNgZoneNoLog(() => { setTimeout(() => {}, 0); }); + runNgZoneNoLog(() => { + setTimeout(() => {}, 0); + }); expect(_zone.hasPendingMacrotasks).toBe(true); }); }); describe('hasPendingAsyncTasks', () => { - it('should be false', () => { expect(_zone.hasPendingMicrotasks).toBe(false); }); + it('should be false', () => { + expect(_zone.hasPendingMicrotasks).toBe(false); + }); it('should be true when microtask is scheduled', () => { - runNgZoneNoLog(() => { scheduleMicroTask(() => {}); }); + runNgZoneNoLog(() => { + scheduleMicroTask(() => {}); + }); expect(_zone.hasPendingMicrotasks).toBe(true); }); it('should be true when timer is scheduled', () => { - runNgZoneNoLog(() => { setTimeout(() => {}, 0); }); + runNgZoneNoLog(() => { + setTimeout(() => {}, 0); + }); expect(_zone.hasPendingMacrotasks).toBe(true); }); }); @@ -257,23 +282,33 @@ function commonTests() { describe('isInInnerZone', () => { it('should return whether the code executes in the inner zone', () => { expect(NgZone.isInAngularZone()).toEqual(false); - runNgZoneNoLog(() => { expect(NgZone.isInAngularZone()).toEqual(true); }); + runNgZoneNoLog(() => { + expect(NgZone.isInAngularZone()).toEqual(true); + }); }, testTimeout); }); describe('run', () => { it('should return the body return value from run', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - macroTask(() => { expect(_zone.run(() => 6)).toEqual(6); }); + macroTask(() => { + expect(_zone.run(() => 6)).toEqual(6); + }); - macroTask(() => { async.done(); }); + macroTask(() => { + async.done(); + }); }), testTimeout); it('should return the body return value from runTask', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - macroTask(() => { expect(_zone.runTask(() => 6)).toEqual(6); }); + macroTask(() => { + expect(_zone.runTask(() => 6)).toEqual(6); + }); - macroTask(() => { async.done(); }); + macroTask(() => { + async.done(); + }); }), testTimeout); it('should call onUnstable and onMicrotaskEmpty', @@ -299,7 +334,9 @@ function commonTests() { _log.add(`onMicrotaskEmpty ${times}`); if (times < 2) { // Scheduling a microtask causes a second digest - runNgZoneNoLog(() => { scheduleMicroTask(() => {}); }); + runNgZoneNoLog(() => { + scheduleMicroTask(() => {}); + }); } } }); @@ -358,7 +395,9 @@ function commonTests() { } }); - macroTask(() => { _zone.run(_log.fn('run')); }); + macroTask(() => { + _zone.run(_log.fn('run')); + }); macroTask(() => { expect(_log.result()).toEqual('onUnstable; run; onMicrotaskEmpty; onStable'); @@ -377,7 +416,9 @@ function commonTests() { next: () => { _log.add('onMyMicrotaskEmpty'); if (turnDone) return; - _zone.run(() => { scheduleMicroTask(() => {}); }); + _zone.run(() => { + scheduleMicroTask(() => {}); + }); turnDone = true; } }); @@ -490,8 +531,12 @@ function commonTests() { runNgZoneNoLog(() => { macroTask(() => { - aPromise = new Promise(res => { aResolve = res; }); - bPromise = new Promise(res => { bResolve = res; }); + aPromise = new Promise(res => { + aResolve = res; + }); + bPromise = new Promise(res => { + bResolve = res; + }); _log.add('run start'); aPromise.then(_log.fn('a then')); @@ -516,7 +561,9 @@ function commonTests() { it('should run a function outside of the angular zone', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - macroTask(() => { _zone.runOutsideAngular(_log.fn('run')); }); + macroTask(() => { + _zone.runOutsideAngular(_log.fn('run')); + }); macroTask(() => { expect(_log.result()).toEqual('run'); @@ -526,12 +573,14 @@ function commonTests() { it('should call onUnstable and onMicrotaskEmpty when an inner microtask is scheduled from outside angular', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - let resolve: (result: string | null) => void; + let resolve: (result: string|null) => void; let promise: Promise<string|null>; macroTask(() => { NgZone.assertNotInAngularZone(); - promise = new Promise<string|null>(res => { resolve = res; }); + promise = new Promise<string|null>(res => { + resolve = res; + }); }); runNgZoneNoLog(() => { @@ -657,7 +706,9 @@ function commonTests() { _log.add('onUnstable(begin)'); if (!startPromiseRan) { _log.add('onUnstable(schedulePromise)'); - _zone.run(() => { scheduleMicroTask(_log.fn('onUnstable(executePromise)')); }); + _zone.run(() => { + scheduleMicroTask(_log.fn('onUnstable(executePromise)')); + }); startPromiseRan = true; } _log.add('onUnstable(end)'); @@ -669,7 +720,9 @@ function commonTests() { _log.add('onMicrotaskEmpty(begin)'); if (!donePromiseRan) { _log.add('onMicrotaskEmpty(schedulePromise)'); - _zone.run(() => { scheduleMicroTask(_log.fn('onMicrotaskEmpty(executePromise)')); }); + _zone.run(() => { + scheduleMicroTask(_log.fn('onMicrotaskEmpty(executePromise)')); + }); donePromiseRan = true; } _log.add('onMicrotaskEmpty(end)'); @@ -695,24 +748,36 @@ function commonTests() { it('should call onUnstable and onMicrotaskEmpty before and after each turn, respectively', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - let aResolve: (result: string | null) => void; + let aResolve: (result: string|null) => void; let aPromise: Promise<string|null>; - let bResolve: (result: string | null) => void; + let bResolve: (result: string|null) => void; let bPromise: Promise<string|null>; runNgZoneNoLog(() => { macroTask(() => { - aPromise = new Promise<string|null>(res => { aResolve = res; }); - bPromise = new Promise<string|null>(res => { bResolve = res; }); + aPromise = new Promise<string|null>(res => { + aResolve = res; + }); + bPromise = new Promise<string|null>(res => { + bResolve = res; + }); aPromise.then(_log.fn('a then')); bPromise.then(_log.fn('b then')); _log.add('run start'); }); }); - runNgZoneNoLog(() => { macroTask(() => { aResolve(null); }, 10); }); + runNgZoneNoLog(() => { + macroTask(() => { + aResolve(null); + }, 10); + }); - runNgZoneNoLog(() => { macroTask(() => { bResolve(null); }, 20); }); + runNgZoneNoLog(() => { + macroTask(() => { + bResolve(null); + }, 20); + }); macroTask(() => { expect(_log.result()) @@ -754,8 +819,9 @@ function commonTests() { runNgZoneNoLog(() => { macroTask(() => { - _zone.runOutsideAngular( - () => { promise = Promise.resolve(4).then((x) => Promise.resolve(x)); }); + _zone.runOutsideAngular(() => { + promise = Promise.resolve(4).then((x) => Promise.resolve(x)); + }); promise.then(_log.fn('promise then')); _log.add('zone run'); @@ -778,7 +844,9 @@ function commonTests() { macroTask(() => { const exception = new Error('sync'); - _zone.runGuarded(() => { throw exception; }); + _zone.runGuarded(() => { + throw exception; + }); expect(_errors.length).toBe(1); expect(_errors[0]).toBe(exception); @@ -790,7 +858,9 @@ function commonTests() { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { macroTask(() => { const exception = new Error('sync'); - expect(() => _zone.run(() => { throw exception; })).toThrowError('sync'); + expect(() => _zone.run(() => { + throw exception; + })).toThrowError('sync'); expect(_errors.length).toBe(0); async.done(); @@ -801,7 +871,13 @@ function commonTests() { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const exception = new Error('async'); - macroTask(() => { _zone.run(() => { scheduleMicroTask(() => { throw exception; }); }); }); + macroTask(() => { + _zone.run(() => { + scheduleMicroTask(() => { + throw exception; + }); + }); + }); macroTask(() => { expect(_errors.length).toBe(1); @@ -821,7 +897,7 @@ function commonTests() { })); it('should fakeAsync even if the NgZone was created outside.', fakeAsync(() => { - let result: string = null !; + let result: string = null!; // try to escape the current fakeAsync zone by using NgZone which was created outside. ngZone.run(() => { Promise.resolve('works').then((v) => result = v); @@ -834,7 +910,9 @@ function commonTests() { let asyncResult: string; const waitLongerThenTestFrameworkAsyncTimeout = 5; - beforeEach(() => { asyncResult = null !; }); + beforeEach(() => { + asyncResult = null!; + }); it('should async even if the NgZone was created outside.', async(() => { // try to escape the current async zone by using NgZone which was created outside. @@ -845,8 +923,9 @@ function commonTests() { }); })); - afterEach(() => { expect(asyncResult).toEqual('works'); }); - + afterEach(() => { + expect(asyncResult).toEqual('works'); + }); }); }); }); diff --git a/packages/core/testing/src/async_fallback.ts b/packages/core/testing/src/async_fallback.ts index 7fa0ad73a5b10..897da61d79f8d 100644 --- a/packages/core/testing/src/async_fallback.ts +++ b/packages/core/testing/src/async_fallback.ts @@ -41,7 +41,9 @@ export function asyncFallback(fn: Function): (done: any) => any { // if we run beforeEach in @angular/core/testing/testing_internal then we get no done // fake it here and assume sync. done = function() {}; - done.fail = function(e: any) { throw e; }; + done.fail = function(e: any) { + throw e; + }; } runInTestZone(fn, this, done, (err: any) => { if (typeof err === 'string') { @@ -87,7 +89,7 @@ function runInTestZone( // If we do it in ProxyZone then we will get to infinite recursion. const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec'); const previousDelegate = proxyZoneSpec.getDelegate(); - proxyZone !.parent !.run(() => { + proxyZone!.parent!.run(() => { const testZoneSpec: ZoneSpec = new AsyncTestZoneSpec( () => { // Need to restore the original zone. diff --git a/packages/core/testing/src/async_test_completer.ts b/packages/core/testing/src/async_test_completer.ts index cfa94d650e2e7..064e9b6d4d55a 100644 --- a/packages/core/testing/src/async_test_completer.ts +++ b/packages/core/testing/src/async_test_completer.ts @@ -11,16 +11,22 @@ */ export class AsyncTestCompleter { // TODO(issue/24571): remove '!'. - private _resolve !: (result: any) => void; + private _resolve!: (result: any) => void; // TODO(issue/24571): remove '!'. - private _reject !: (err: any) => void; + private _reject!: (err: any) => void; private _promise: Promise<any> = new Promise((res, rej) => { this._resolve = res; this._reject = rej; }); - done(value?: any) { this._resolve(value); } + done(value?: any) { + this._resolve(value); + } - fail(error?: any, stackTrace?: string) { this._reject(error); } + fail(error?: any, stackTrace?: string) { + this._reject(error); + } - get promise(): Promise<any> { return this._promise; } + get promise(): Promise<any> { + return this._promise; + } } diff --git a/packages/core/testing/src/component_fixture.ts b/packages/core/testing/src/component_fixture.ts index bb15761f22245..38e2f102db8f8 100644 --- a/packages/core/testing/src/component_fixture.ts +++ b/packages/core/testing/src/component_fixture.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectorRef, ComponentRef, DebugElement, ElementRef, NgZone, RendererFactory2, getDebugNode} from '@angular/core'; +import {ChangeDetectorRef, ComponentRef, DebugElement, ElementRef, getDebugNode, NgZone, RendererFactory2} from '@angular/core'; /** @@ -65,8 +65,11 @@ export class ComponentFixture<T> { // Create subscriptions outside the NgZone so that the callbacks run oustide // of NgZone. ngZone.runOutsideAngular(() => { - this._onUnstableSubscription = - ngZone.onUnstable.subscribe({next: () => { this._isStable = false; }}); + this._onUnstableSubscription = ngZone.onUnstable.subscribe({ + next: () => { + this._isStable = false; + } + }); this._onMicrotaskEmptySubscription = ngZone.onMicrotaskEmpty.subscribe({ next: () => { if (this._autoDetect) { @@ -87,7 +90,7 @@ export class ComponentFixture<T> { scheduleMicroTask(() => { if (!ngZone.hasPendingMacrotasks) { if (this._promise !== null) { - this._resolve !(true); + this._resolve!(true); this._resolve = null; this._promise = null; } @@ -97,8 +100,11 @@ export class ComponentFixture<T> { } }); - this._onErrorSubscription = - ngZone.onError.subscribe({next: (error: any) => { throw error; }}); + this._onErrorSubscription = ngZone.onError.subscribe({ + next: (error: any) => { + throw error; + } + }); }); } } @@ -117,7 +123,9 @@ export class ComponentFixture<T> { if (this.ngZone != null) { // Run the change detection inside the NgZone so that any async tasks as part of the change // detection are captured by the zone and can be waited for in isStable. - this.ngZone.run(() => { this._tick(checkNoChanges); }); + this.ngZone.run(() => { + this._tick(checkNoChanges); + }); } else { // Running without zone. Just do the change detection. this._tick(checkNoChanges); @@ -127,7 +135,9 @@ export class ComponentFixture<T> { /** * Do a change detection run to make sure there were no changes. */ - checkNoChanges(): void { this.changeDetectorRef.checkNoChanges(); } + checkNoChanges(): void { + this.changeDetectorRef.checkNoChanges(); + } /** * Set whether the fixture should autodetect changes. @@ -146,7 +156,9 @@ export class ComponentFixture<T> { * Return whether the fixture is currently stable or has async tasks that have not been completed * yet. */ - isStable(): boolean { return this._isStable && !this.ngZone !.hasPendingMacrotasks; } + isStable(): boolean { + return this._isStable && !this.ngZone!.hasPendingMacrotasks; + } /** * Get a promise that resolves when the fixture is stable. @@ -160,7 +172,9 @@ export class ComponentFixture<T> { } else if (this._promise !== null) { return this._promise; } else { - this._promise = new Promise(res => { this._resolve = res; }); + this._promise = new Promise(res => { + this._resolve = res; + }); return this._promise; } } @@ -174,8 +188,8 @@ export class ComponentFixture<T> { } /** - * Get a promise that resolves when the ui state is stable following animations. - */ + * Get a promise that resolves when the ui state is stable following animations. + */ whenRenderingDone(): Promise<any> { const renderer = this._getRenderer(); if (renderer && renderer.whenRenderingDone) { diff --git a/packages/core/testing/src/logger.ts b/packages/core/testing/src/logger.ts index a0d3b9c58a5dd..38c074b8d0037 100644 --- a/packages/core/testing/src/logger.ts +++ b/packages/core/testing/src/logger.ts @@ -12,9 +12,13 @@ import {Injectable} from '@angular/core'; export class Log { logItems: any[]; - constructor() { this.logItems = []; } + constructor() { + this.logItems = []; + } - add(value: any /** TODO #9100 */): void { this.logItems.push(value); } + add(value: any /** TODO #9100 */): void { + this.logItems.push(value); + } fn(value: any /** TODO #9100 */) { return (a1: any = null, a2: any = null, a3: any = null, a4: any = null, a5: any = null) => { @@ -22,7 +26,11 @@ export class Log { }; } - clear(): void { this.logItems = []; } + clear(): void { + this.logItems = []; + } - result(): string { return this.logItems.join('; '); } + result(): string { + return this.logItems.join('; '); + } } diff --git a/packages/core/testing/src/metadata_overrider.ts b/packages/core/testing/src/metadata_overrider.ts index 4a5bf7846719d..81bfbf806472b 100644 --- a/packages/core/testing/src/metadata_overrider.ts +++ b/packages/core/testing/src/metadata_overrider.ts @@ -22,7 +22,7 @@ export class MetadataOverrider { * based on an old instance and overrides. */ overrideMetadata<C extends T, T>( - metadataClass: {new (options: T): C;}, oldMetadata: C, override: MetadataOverride<T>): C { + metadataClass: {new(options: T): C;}, oldMetadata: C, override: MetadataOverride<T>): C { const props: StringMap = {}; if (oldMetadata) { _valueProps(oldMetadata).forEach((prop) => props[prop] = (<any>oldMetadata)[prop]); @@ -49,8 +49,9 @@ function removeMetadata(metadata: StringMap, remove: any, references: Map<any, s for (const prop in remove) { const removeValue = remove[prop]; if (Array.isArray(removeValue)) { - removeValue.forEach( - (value: any) => { removeObjects.add(_propHashKey(prop, value, references)); }); + removeValue.forEach((value: any) => { + removeObjects.add(_propHashKey(prop, value, references)); + }); } else { removeObjects.add(_propHashKey(prop, removeValue, references)); } diff --git a/packages/core/testing/src/ng_zone_mock.ts b/packages/core/testing/src/ng_zone_mock.ts index cad1508c9bf5a..65373def5aeef 100644 --- a/packages/core/testing/src/ng_zone_mock.ts +++ b/packages/core/testing/src/ng_zone_mock.ts @@ -16,11 +16,19 @@ import {EventEmitter, Injectable, NgZone} from '@angular/core'; export class MockNgZone extends NgZone { onStable: EventEmitter<any> = new EventEmitter(false); - constructor() { super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: false}); } + constructor() { + super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: false}); + } - run(fn: Function): any { return fn(); } + run(fn: Function): any { + return fn(); + } - runOutsideAngular(fn: Function): any { return fn(); } + runOutsideAngular(fn: Function): any { + return fn(); + } - simulateZoneExit(): void { this.onStable.emit(null); } + simulateZoneExit(): void { + this.onStable.emit(null); + } } diff --git a/packages/core/testing/src/r3_test_bed.ts b/packages/core/testing/src/r3_test_bed.ts index 6a749280fec02..178b3ba5e40fd 100644 --- a/packages/core/testing/src/r3_test_bed.ts +++ b/packages/core/testing/src/r3_test_bed.ts @@ -9,7 +9,8 @@ // The formatter and CI disagree on how this import statement should be formatted. Both try to keep // it on one line, too, which has gotten very hard to read & manage. So disable the formatter for // this statement only. -// clang-format off + +/* clang-format off */ import { AbstractType, Component, @@ -22,19 +23,20 @@ import { Pipe, PlatformRef, Type, + ɵflushModuleScopingQueueAsMuchAsPossible as flushModuleScopingQueueAsMuchAsPossible, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, - ɵflushModuleScopingQueueAsMuchAsPossible as flushModuleScopingQueueAsMuchAsPossible, ɵresetCompiledComponents as resetCompiledComponents, ɵstringify as stringify, } from '@angular/core'; -// clang-format on + +/* clang-format on */ import {ComponentFixture} from './component_fixture'; import {MetadataOverride} from './metadata_override'; +import {R3TestBedCompiler} from './r3_test_bed_compiler'; import {TestBed} from './test_bed'; import {ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, TestBedStatic, TestComponentRenderer, TestModuleMetadata} from './test_bed_common'; -import {R3TestBedCompiler} from './r3_test_bed_compiler'; let _nextRootElementId = 0; @@ -75,7 +77,9 @@ export class TestBedRender3 implements TestBed { * * @publicApi */ - static resetTestEnvironment(): void { _getTestBedRender3().resetTestEnvironment(); } + static resetTestEnvironment(): void { + _getTestBedRender3().resetTestEnvironment(); + } static configureCompiler(config: {providers?: any[]; useJit?: boolean;}): TestBedStatic { _getTestBedRender3().configureCompiler(config); @@ -96,7 +100,9 @@ export class TestBedRender3 implements TestBed { * It is necessary to call this function * as fetching urls is asynchronous. */ - static compileComponents(): Promise<any> { return _getTestBedRender3().compileComponents(); } + static compileComponents(): Promise<any> { + return _getTestBedRender3().compileComponents(); + } static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): TestBedStatic { _getTestBedRender3().overrideModule(ngModule, override); @@ -121,7 +127,7 @@ export class TestBedRender3 implements TestBed { } static overrideTemplate(component: Type<any>, template: string): TestBedStatic { - _getTestBedRender3().overrideComponent(component, {set: {template, templateUrl: null !}}); + _getTestBedRender3().overrideComponent(component, {set: {template, templateUrl: null!}}); return TestBedRender3 as any as TestBedStatic; } @@ -183,8 +189,8 @@ export class TestBedRender3 implements TestBed { // Properties - platform: PlatformRef = null !; - ngModule: Type<any>|Type<any>[] = null !; + platform: PlatformRef = null!; + ngModule: Type<any>|Type<any>[] = null!; private _compiler: R3TestBedCompiler|null = null; private _testModuleRef: NgModuleRef<any>|null = null; @@ -223,8 +229,8 @@ export class TestBedRender3 implements TestBed { resetTestEnvironment(): void { this.resetTestingModule(); this._compiler = null; - this.platform = null !; - this.ngModule = null !; + this.platform = null!; + this.ngModule = null!; } resetTestingModule(): void { @@ -253,7 +259,9 @@ export class TestBedRender3 implements TestBed { this.compiler.configureTestingModule(moduleDef); } - compileComponents(): Promise<any> { return this.compiler.compileComponents(); } + compileComponents(): Promise<any> { + return this.compiler.compileComponents(); + } inject<T>( token: Type<T>|InjectionToken<T>|AbstractType<T>, notFoundValue?: T, flags?: InjectFlags): T; diff --git a/packages/core/testing/src/r3_test_bed_compiler.ts b/packages/core/testing/src/r3_test_bed_compiler.ts index a01aec19cf6a4..6d3a93c1fa008 100644 --- a/packages/core/testing/src/r3_test_bed_compiler.ts +++ b/packages/core/testing/src/r3_test_bed_compiler.ts @@ -7,7 +7,7 @@ */ import {ResourceLoader} from '@angular/compiler'; -import {ApplicationInitStatus, COMPILER_OPTIONS, Compiler, Component, Directive, Injector, InjectorType, LOCALE_ID, ModuleWithComponentFactories, ModuleWithProviders, NgModule, NgModuleFactory, NgZone, Pipe, PlatformRef, Provider, Type, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵDirectiveDef as DirectiveDef, ɵNG_COMP_DEF as NG_COMP_DEF, ɵNG_DIR_DEF as NG_DIR_DEF, ɵNG_INJ_DEF as NG_INJ_DEF, ɵNG_MOD_DEF as NG_MOD_DEF, ɵNG_PIPE_DEF as NG_PIPE_DEF, ɵNgModuleFactory as R3NgModuleFactory, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵNgModuleType as NgModuleType, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵsetLocaleId as setLocaleId, ɵtransitiveScopesFor as transitiveScopesFor, ɵɵInjectableDef as InjectableDef} from '@angular/core'; +import {ApplicationInitStatus, Compiler, COMPILER_OPTIONS, Component, Directive, Injector, InjectorType, LOCALE_ID, ModuleWithComponentFactories, ModuleWithProviders, NgModule, NgModuleFactory, NgZone, Pipe, PlatformRef, Provider, Type, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵDirectiveDef as DirectiveDef, ɵgetInjectableDef as getInjectableDef, ɵNG_COMP_DEF as NG_COMP_DEF, ɵNG_DIR_DEF as NG_DIR_DEF, ɵNG_INJ_DEF as NG_INJ_DEF, ɵNG_MOD_DEF as NG_MOD_DEF, ɵNG_PIPE_DEF as NG_PIPE_DEF, ɵNgModuleFactory as R3NgModuleFactory, ɵNgModuleTransitiveScopes as NgModuleTransitiveScopes, ɵNgModuleType as NgModuleType, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, ɵsetLocaleId as setLocaleId, ɵtransitiveScopesFor as transitiveScopesFor, ɵɵInjectableDef as InjectableDef} from '@angular/core'; import {clearResolutionOfComponentResourcesQueue, isComponentDefPendingResolution, resolveComponentResources, restoreComponentResolutionQueue} from '../../src/metadata/resource_loading'; @@ -194,7 +194,7 @@ export class R3TestBedCompiler { overrideTemplateUsingTestingModule(type: Type<any>, template: string): void { const def = (type as any)[NG_COMP_DEF]; const hasStyleUrls = (): boolean => { - const metadata = this.resolvers.component.resolve(type) !as Component; + const metadata = this.resolvers.component.resolve(type)! as Component; return !!metadata.styleUrls && metadata.styleUrls.length > 0; }; const overrideStyleUrls = !!def && !isComponentDefPendingResolution(type) && hasStyleUrls(); @@ -295,7 +295,9 @@ export class R3TestBedCompiler { /** * @internal */ - _getModuleResolver(): Resolver<NgModule> { return this.resolvers.module; } + _getModuleResolver(): Resolver<NgModule> { + return this.resolvers.module; + } /** * @internal @@ -303,7 +305,7 @@ export class R3TestBedCompiler { _getComponentFactories(moduleType: NgModuleType): ComponentFactory<any>[] { return maybeUnwrapFn(moduleType.ɵmod.declarations).reduce((factories, declaration) => { const componentDef = (declaration as any).ɵcmp; - componentDef && factories.push(new ComponentFactory(componentDef, this.testModuleRef !)); + componentDef && factories.push(new ComponentFactory(componentDef, this.testModuleRef!)); return factories; }, [] as ComponentFactory<any>[]); } @@ -348,7 +350,7 @@ export class R3TestBedCompiler { private applyTransitiveScopes(): void { const moduleToScope = new Map<Type<any>|TestingModuleOverride, NgModuleTransitiveScopes>(); const getScopeOfModule = - (moduleType: Type<any>| TestingModuleOverride): NgModuleTransitiveScopes => { + (moduleType: Type<any>|TestingModuleOverride): NgModuleTransitiveScopes => { if (!moduleToScope.has(moduleType)) { const isTestingModule = isTestingModuleOverride(moduleType); const realType = isTestingModule ? this.testModuleType : moduleType as Type<any>; @@ -363,7 +365,7 @@ export class R3TestBedCompiler { } moduleToScope.set(moduleType, transitiveScopesFor(realType)); } - return moduleToScope.get(moduleType) !; + return moduleToScope.get(moduleType)!; }; this.componentToModuleScope.forEach((moduleType, componentType) => { @@ -379,7 +381,7 @@ export class R3TestBedCompiler { private applyProviderOverrides(): void { const maybeApplyOverrides = (field: string) => (type: Type<any>) => { const resolver = field === NG_COMP_DEF ? this.resolvers.component : this.resolvers.directive; - const metadata = resolver.resolve(type) !; + const metadata = resolver.resolve(type)!; if (this.hasProviderOverrides(metadata.providers)) { this.patchDefWithProviderOverrides(type, field); } @@ -553,7 +555,7 @@ export class R3TestBedCompiler { this.originalComponentResolutionQueue = new Map(); } clearResolutionOfComponentResourcesQueue().forEach( - (value, key) => this.originalComponentResolutionQueue !.set(key, value)); + (value, key) => this.originalComponentResolutionQueue!.set(key, value)); } /* @@ -575,21 +577,20 @@ export class R3TestBedCompiler { op.object[op.fieldName] = op.originalValue; }); // Restore initial component/directive/pipe defs - this.initialNgDefs.forEach( - (value: [string, PropertyDescriptor | undefined], type: Type<any>) => { - const [prop, descriptor] = value; - if (!descriptor) { - // Delete operations are generally undesirable since they have performance implications - // on objects they were applied to. In this particular case, situations where this code - // is invoked should be quite rare to cause any noticeable impact, since it's applied - // only to some test cases (for example when class with no annotations extends some - // @Component) when we need to clear 'ɵcmp' field on a given class to restore - // its original state (before applying overrides and running tests). - delete (type as any)[prop]; - } else { - Object.defineProperty(type, prop, descriptor); - } - }); + this.initialNgDefs.forEach((value: [string, PropertyDescriptor|undefined], type: Type<any>) => { + const [prop, descriptor] = value; + if (!descriptor) { + // Delete operations are generally undesirable since they have performance implications + // on objects they were applied to. In this particular case, situations where this code + // is invoked should be quite rare to cause any noticeable impact, since it's applied + // only to some test cases (for example when class with no annotations extends some + // @Component) when we need to clear 'ɵcmp' field on a given class to restore + // its original state (before applying overrides and running tests). + delete (type as any)[prop]; + } else { + Object.defineProperty(type, prop, descriptor); + } + }); this.initialNgDefs.clear(); this.moduleProvidersOverridden.clear(); this.restoreComponentResolutionQueue(); @@ -726,7 +727,7 @@ function hasNgModuleDef<T>(value: Type<T>): value is NgModuleType<T> { return value.hasOwnProperty('ɵmod'); } -function maybeUnwrapFn<T>(maybeFn: (() => T) | T): T { +function maybeUnwrapFn<T>(maybeFn: (() => T)|T): T { return maybeFn instanceof Function ? maybeFn() : maybeFn; } diff --git a/packages/core/testing/src/resolvers.ts b/packages/core/testing/src/resolvers.ts index 6bf7456f92391..fa2f7b35317bc 100644 --- a/packages/core/testing/src/resolvers.ts +++ b/packages/core/testing/src/resolvers.ts @@ -40,7 +40,9 @@ abstract class OverrideResolver<T> implements Resolver<T> { setOverrides(overrides: Array<[Type<any>, MetadataOverride<T>]>) { this.overrides.clear(); - overrides.forEach(([type, override]) => { this.addOverride(type, override); }); + overrides.forEach(([type, override]) => { + this.addOverride(type, override); + }); } getAnnotation(type: Type<any>): T|null { @@ -71,7 +73,7 @@ abstract class OverrideResolver<T> implements Resolver<T> { if (overrides) { const overrider = new MetadataOverrider(); overrides.forEach(override => { - resolved = overrider.overrideMetadata(this.type, resolved !, override); + resolved = overrider.overrideMetadata(this.type, resolved!, override); }); } } @@ -84,17 +86,25 @@ abstract class OverrideResolver<T> implements Resolver<T> { export class DirectiveResolver extends OverrideResolver<Directive> { - get type() { return Directive; } + get type() { + return Directive; + } } export class ComponentResolver extends OverrideResolver<Component> { - get type() { return Component; } + get type() { + return Component; + } } export class PipeResolver extends OverrideResolver<Pipe> { - get type() { return Pipe; } + get type() { + return Pipe; + } } export class NgModuleResolver extends OverrideResolver<NgModule> { - get type() { return NgModule; } + get type() { + return NgModule; + } } diff --git a/packages/core/testing/src/styling.ts b/packages/core/testing/src/styling.ts index dcb4ba904fcf0..d843d6d1aae25 100644 --- a/packages/core/testing/src/styling.ts +++ b/packages/core/testing/src/styling.ts @@ -7,11 +7,11 @@ */ /** - * Returns element classes in form of a stable (sorted) string. - * - * @param element HTML Element. - * @returns Returns element classes in form of a stable (sorted) string. - */ + * Returns element classes in form of a stable (sorted) string. + * + * @param element HTML Element. + * @returns Returns element classes in form of a stable (sorted) string. + */ export function getSortedClassName(element: Element): string { const names: string[] = Object.keys(getElementClasses(element)); names.sort(); diff --git a/packages/core/testing/src/test_bed.ts b/packages/core/testing/src/test_bed.ts index 3f260aee63b89..38ebcfe41d775 100644 --- a/packages/core/testing/src/test_bed.ts +++ b/packages/core/testing/src/test_bed.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {AbstractType, ApplicationInitStatus, CompilerOptions, Component, Directive, InjectFlags, InjectionToken, Injector, NgModule, NgModuleFactory, NgModuleRef, NgZone, Optional, Pipe, PlatformRef, Provider, SchemaMetadata, SkipSelf, StaticProvider, Type, ɵDepFlags as DepFlags, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵNodeFlags as NodeFlags, ɵclearOverrides as clearOverrides, ɵgetInjectableDef as getInjectableDef, ɵivyEnabled as ivyEnabled, ɵoverrideComponentView as overrideComponentView, ɵoverrideProvider as overrideProvider, ɵstringify as stringify, ɵɵInjectableDef} from '@angular/core'; +import {AbstractType, ApplicationInitStatus, CompilerOptions, Component, Directive, InjectFlags, InjectionToken, Injector, NgModule, NgModuleFactory, NgModuleRef, NgZone, Optional, Pipe, PlatformRef, Provider, SchemaMetadata, SkipSelf, StaticProvider, Type, ɵclearOverrides as clearOverrides, ɵDepFlags as DepFlags, ɵgetInjectableDef as getInjectableDef, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵivyEnabled as ivyEnabled, ɵNodeFlags as NodeFlags, ɵoverrideComponentView as overrideComponentView, ɵoverrideProvider as overrideProvider, ɵstringify as stringify, ɵɵInjectableDef} from '@angular/core'; import {AsyncTestCompleter} from './async_test_completer'; import {ComponentFixture} from './component_fixture'; import {MetadataOverride} from './metadata_override'; -import {TestBedRender3, _getTestBedRender3} from './r3_test_bed'; +import {_getTestBedRender3, TestBedRender3} from './r3_test_bed'; import {ComponentFixtureAutoDetect, ComponentFixtureNoNgZone, TestBedStatic, TestComponentRenderer, TestModuleMetadata} from './test_bed_common'; import {TestingCompiler, TestingCompilerFactory} from './test_compiler'; @@ -123,7 +123,9 @@ export class TestBedViewEngine implements TestBed { /** * Reset the providers for the test injector. */ - static resetTestEnvironment(): void { _getTestBedViewEngine().resetTestEnvironment(); } + static resetTestEnvironment(): void { + _getTestBedViewEngine().resetTestEnvironment(); + } static resetTestingModule(): TestBedStatic { _getTestBedViewEngine().resetTestingModule(); @@ -153,7 +155,9 @@ export class TestBedViewEngine implements TestBed { * It is necessary to call this function * as fetching urls is asynchronous. */ - static compileComponents(): Promise<any> { return getTestBed().compileComponents(); } + static compileComponents(): Promise<any> { + return getTestBed().compileComponents(); + } static overrideModule(ngModule: Type<any>, override: MetadataOverride<NgModule>): TestBedStatic { _getTestBedViewEngine().overrideModule(ngModule, override); @@ -178,7 +182,7 @@ export class TestBedViewEngine implements TestBed { } static overrideTemplate(component: Type<any>, template: string): TestBedStatic { - _getTestBedViewEngine().overrideComponent(component, {set: {template, templateUrl: null !}}); + _getTestBedViewEngine().overrideComponent(component, {set: {template, templateUrl: null!}}); return TestBedViewEngine as any as TestBedStatic; } @@ -243,9 +247,9 @@ export class TestBedViewEngine implements TestBed { private _instantiated: boolean = false; - private _compiler: TestingCompiler = null !; - private _moduleRef: NgModuleRef<any> = null !; - private _moduleFactory: NgModuleFactory<any> = null !; + private _compiler: TestingCompiler = null!; + private _moduleRef: NgModuleRef<any> = null!; + private _moduleFactory: NgModuleFactory<any> = null!; private _compilerOptions: CompilerOptions[] = []; @@ -267,9 +271,9 @@ export class TestBedViewEngine implements TestBed { private _isRoot: boolean = true; private _rootProviderOverrides: Provider[] = []; - platform: PlatformRef = null !; + platform: PlatformRef = null!; - ngModule: Type<any>|Type<any>[] = null !; + ngModule: Type<any>|Type<any>[] = null!; /** * Initialize the environment for testing with a compiler factory, a PlatformRef, and an @@ -299,8 +303,8 @@ export class TestBedViewEngine implements TestBed { */ resetTestEnvironment(): void { this.resetTestingModule(); - this.platform = null !; - this.ngModule = null !; + this.platform = null!; + this.ngModule = null!; this._testEnvAotSummaries = () => []; } @@ -308,7 +312,7 @@ export class TestBedViewEngine implements TestBed { clearOverrides(); this._aotSummaries = []; this._templateOverrides = []; - this._compiler = null !; + this._compiler = null!; this._moduleOverrides = []; this._componentOverrides = []; this._directiveOverrides = []; @@ -317,8 +321,8 @@ export class TestBedViewEngine implements TestBed { this._isRoot = true; this._rootProviderOverrides = []; - this._moduleRef = null !; - this._moduleFactory = null !; + this._moduleRef = null!; + this._moduleFactory = null!; this._compilerOptions = []; this._providers = []; this._declarations = []; @@ -387,7 +391,9 @@ export class TestBedViewEngine implements TestBed { const errorCompType = this._compiler.getComponentFromError(e); if (errorCompType) { throw new Error( - `This test module uses the component ${stringify(errorCompType)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` + + `This test module uses the component ${ + stringify( + errorCompType)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` + `Please call "TestBed.compileComponents" before your test.`); } else { throw e; @@ -593,8 +599,8 @@ export class TestBedViewEngine implements TestBed { const componentFactory = this._compiler.getComponentFactory(component); if (!componentFactory) { - throw new Error( - `Cannot create the component ${stringify(component)} as it was not imported into the testing module!`); + throw new Error(`Cannot create the component ${ + stringify(component)} as it was not imported into the testing module!`); } // TODO: Don't cast as `InjectionToken<boolean>`, declared type is boolean[] @@ -688,7 +694,9 @@ export function inject(tokens: any[], fn: Function): () => any { }; } else { // Not using an arrow function to preserve context passed from call site - return function(this: unknown) { return testBed.execute(tokens, fn, this); }; + return function(this: unknown) { + return testBed.execute(tokens, fn, this); + }; } } @@ -720,7 +728,7 @@ export class InjectSetupWrapper { */ export function withModule(moduleDef: TestModuleMetadata): InjectSetupWrapper; export function withModule(moduleDef: TestModuleMetadata, fn: Function): () => any; -export function withModule(moduleDef: TestModuleMetadata, fn?: Function | null): (() => any)| +export function withModule(moduleDef: TestModuleMetadata, fn?: Function|null): (() => any)| InjectSetupWrapper { if (fn) { // Not using an arrow function to preserve context passed from call site diff --git a/packages/core/testing/src/test_bed_common.ts b/packages/core/testing/src/test_bed_common.ts index 071179a1b0e9d..93c2123bc118f 100644 --- a/packages/core/testing/src/test_bed_common.ts +++ b/packages/core/testing/src/test_bed_common.ts @@ -49,7 +49,7 @@ export type TestModuleMetadata = { * @publicApi */ export interface TestBedStatic { - new (...args: any[]): TestBed; + new(...args: any[]): TestBed; initTestEnvironment( ngModule: Type<any>|Type<any>[], platform: PlatformRef, aotSummaries?: () => any[]): TestBed; diff --git a/packages/core/testing/src/test_compiler.ts b/packages/core/testing/src/test_compiler.ts index 518d7484e06f7..4b7337eb3793e 100644 --- a/packages/core/testing/src/test_compiler.ts +++ b/packages/core/testing/src/test_compiler.ts @@ -21,7 +21,9 @@ function unimplemented(): any { */ @Injectable() export class TestingCompiler extends Compiler { - get injector(): Injector { throw unimplemented(); } + get injector(): Injector { + throw unimplemented(); + } overrideModule(module: Type<any>, overrides: MetadataOverride<NgModule>): void { throw unimplemented(); } @@ -38,20 +40,26 @@ export class TestingCompiler extends Compiler { * Allows to pass the compile summary from AOT compilation to the JIT compiler, * so that it can use the code generated by AOT. */ - loadAotSummaries(summaries: () => any[]) { throw unimplemented(); } + loadAotSummaries(summaries: () => any[]) { + throw unimplemented(); + } /** * Gets the component factory for the given component. * This assumes that the component has been compiled before calling this call using * `compileModuleAndAllComponents*`. */ - getComponentFactory<T>(component: Type<T>): ComponentFactory<T> { throw unimplemented(); } + getComponentFactory<T>(component: Type<T>): ComponentFactory<T> { + throw unimplemented(); + } /** * Returns the component type that is stored in the given error. * This can be used for errors created by compileModule... */ - getComponentFromError(error: Error): Type<any>|null { throw unimplemented(); } + getComponentFromError(error: Error): Type<any>|null { + throw unimplemented(); + } } /** diff --git a/packages/core/testing/src/testing_internal.ts b/packages/core/testing/src/testing_internal.ts index 00ce5136ab06b..8e28a62432b44 100644 --- a/packages/core/testing/src/testing_internal.ts +++ b/packages/core/testing/src/testing_internal.ts @@ -39,7 +39,7 @@ const globalTimeOut = jasmine.DEFAULT_TIMEOUT_INTERVAL; const testBed = getTestBed(); -export type TestFn = ((done: DoneFn) => any) | (() => any); +export type TestFn = ((done: DoneFn) => any)|(() => any); /** * Mechanism to run `beforeEach()` functions of Angular tests. @@ -51,20 +51,26 @@ class BeforeEachRunner { constructor(private _parent: BeforeEachRunner) {} - beforeEach(fn: Function): void { this._fns.push(fn); } + beforeEach(fn: Function): void { + this._fns.push(fn); + } run(): void { if (this._parent) this._parent.run(); - this._fns.forEach((fn) => { fn(); }); + this._fns.forEach((fn) => { + fn(); + }); } } // Reset the test providers before each test -jsmBeforeEach(() => { testBed.resetTestingModule(); }); +jsmBeforeEach(() => { + testBed.resetTestingModule(); +}); function _describe(jsmFn: Function, ...args: any[]) { const parentRunner = runnerStack.length === 0 ? null : runnerStack[runnerStack.length - 1]; - const runner = new BeforeEachRunner(parentRunner !); + const runner = new BeforeEachRunner(parentRunner!); runnerStack.push(runner); const suite = jsmFn(...args); runnerStack.pop(); @@ -138,7 +144,7 @@ function _it(jsmFn: Function, testName: string, testFn: TestFn, testTimeout = 0) if (testFn.length === 0) { // TypeScript doesn't infer the TestFn type without parameters here, so we // need to manually cast it. - const retVal = (testFn as() => any)(); + const retVal = (testFn as () => any)(); if (isPromise(retVal)) { // Asynchronous test function that returns a Promise - wait for completion. retVal.then(done, done.fail); @@ -192,7 +198,9 @@ export class SpyObject { return (this as any)[name]; } - prop(name: string, value: any) { (this as any)[name] = value; } + prop(name: string, value: any) { + (this as any)[name] = value; + } static stub(object: any = null, config: any = null, overrides: any = null) { if (!(object instanceof SpyObject)) { @@ -202,7 +210,9 @@ export class SpyObject { } const m = {...config, ...overrides}; - Object.keys(m).forEach(key => { object.spy(key).and.returnValue(m[key]); }); + Object.keys(m).forEach(key => { + object.spy(key).and.returnValue(m[key]); + }); return object; } } diff --git a/packages/elements/public_api.ts b/packages/elements/public_api.ts index 0b501cc0d7d56..98a3d66c23cbb 100644 --- a/packages/elements/public_api.ts +++ b/packages/elements/public_api.ts @@ -11,7 +11,7 @@ * @description * Entry point for all public APIs of the `elements` package. */ -export {NgElement, NgElementConfig, NgElementConstructor, WithProperties, createCustomElement} from './src/create-custom-element'; +export {createCustomElement, NgElement, NgElementConfig, NgElementConstructor, WithProperties} from './src/create-custom-element'; export {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from './src/element-strategy'; export {VERSION} from './src/version'; diff --git a/packages/elements/schematics/ng-add/index.ts b/packages/elements/schematics/ng-add/index.ts index ad8c0afcd1134..4db7a43f95833 100644 --- a/packages/elements/schematics/ng-add/index.ts +++ b/packages/elements/schematics/ng-add/index.ts @@ -5,9 +5,9 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {Rule, SchematicContext, SchematicsException, Tree, chain, noop} from '@angular-devkit/schematics'; +import {chain, noop, Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics'; import {NodePackageInstallTask} from '@angular-devkit/schematics/tasks'; -import {NodeDependencyType, addPackageJsonDependency} from '@schematics/angular/utility/dependencies'; +import {addPackageJsonDependency, NodeDependencyType} from '@schematics/angular/utility/dependencies'; import {getWorkspace} from '@schematics/angular/utility/workspace'; import {Schema} from './schema'; @@ -36,7 +36,7 @@ function addPolyfillDependency(): Rule { /** Adds the document-register-element.js to the polyfills file. */ function addPolyfill(options: Schema): Rule { - return async(host: Tree, context: SchematicContext) => { + return async (host: Tree, context: SchematicContext) => { const projectName = options.project; if (!projectName) { diff --git a/packages/elements/schematics/ng-add/index_spec.ts b/packages/elements/schematics/ng-add/index_spec.ts index 4e4d8737f274c..0cb6ba047287a 100644 --- a/packages/elements/schematics/ng-add/index_spec.ts +++ b/packages/elements/schematics/ng-add/index_spec.ts @@ -13,7 +13,9 @@ import {Schema as ElementsOptions} from './schema'; // tslint:disable:max-line-length describe('Elements Schematics', () => { const schematicRunner = new SchematicTestRunner( - '@angular/elements', path.join(__dirname, '../test-collection.json'), ); + '@angular/elements', + path.join(__dirname, '../test-collection.json'), + ); const defaultOptions: ElementsOptions = {project: 'elements', skipPackageJson: false}; let appTree: UnitTestTree; @@ -35,7 +37,7 @@ describe('Elements Schematics', () => { skipTests: false, }; - beforeEach(async() => { + beforeEach(async () => { appTree = await schematicRunner .runExternalSchematicAsync('@schematics/angular', 'workspace', workspaceOptions) .toPromise(); @@ -45,14 +47,14 @@ describe('Elements Schematics', () => { .toPromise(); }); - it('should run the ng-add schematic', async() => { + it('should run the ng-add schematic', async () => { const tree = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise(); expect(tree.readContent('/projects/elements/src/polyfills.ts')) .toContain(`import 'document-register-element';`); }); - it('should add polyfill as a dependency in package.json', async() => { + it('should add polyfill as a dependency in package.json', async () => { const tree = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise(); const pkgJsonText = tree.readContent('/package.json'); diff --git a/packages/elements/src/component-factory-strategy.ts b/packages/elements/src/component-factory-strategy.ts index fafe335b84fa9..e5b691b680051 100644 --- a/packages/elements/src/component-factory-strategy.ts +++ b/packages/elements/src/component-factory-strategy.ts @@ -7,7 +7,7 @@ */ import {ApplicationRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, EventEmitter, Injector, OnChanges, SimpleChange, SimpleChanges, Type} from '@angular/core'; -import {Observable, merge} from 'rxjs'; +import {merge, Observable} from 'rxjs'; import {map} from 'rxjs/operators'; import {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from './element-strategy'; @@ -45,11 +45,11 @@ export class ComponentNgElementStrategyFactory implements NgElementStrategyFacto export class ComponentNgElementStrategy implements NgElementStrategy { /** Merged stream of the component's output events. */ // TODO(issue/24571): remove '!'. - events !: Observable<NgElementStrategyEvent>; + events!: Observable<NgElementStrategyEvent>; /** Reference to the component that was created on connect. */ // TODO(issue/24571): remove '!'. - private componentRef !: ComponentRef<any>| null; + private componentRef!: ComponentRef<any>|null; /** Changes that have been made to the component ref since the last time onChanges was called. */ private inputChanges: SimpleChanges|null = null; @@ -105,7 +105,7 @@ export class ComponentNgElementStrategy implements NgElementStrategy { // moved elsewhere in the DOM this.scheduledDestroyFn = scheduler.schedule(() => { if (this.componentRef) { - this.componentRef !.destroy(); + this.componentRef!.destroy(); this.componentRef = null; } }, DESTROY_DELAY); @@ -190,7 +190,7 @@ export class ComponentNgElementStrategy implements NgElementStrategy { /** Sets up listeners for the component's outputs so that the events stream emits the events. */ protected initializeOutputs(): void { const eventEmitters = this.componentFactory.outputs.map(({propName, templateName}) => { - const emitter = (this.componentRef !.instance as any)[propName] as EventEmitter<any>; + const emitter = (this.componentRef!.instance as any)[propName] as EventEmitter<any>; return emitter.pipe(map((value: any) => ({name: templateName, value}))); }); @@ -207,7 +207,7 @@ export class ComponentNgElementStrategy implements NgElementStrategy { // during ngOnChanges. const inputChanges = this.inputChanges; this.inputChanges = null; - (this.componentRef !.instance as any as OnChanges).ngOnChanges(inputChanges); + (this.componentRef!.instance as any as OnChanges).ngOnChanges(inputChanges); } /** @@ -260,6 +260,6 @@ export class ComponentNgElementStrategy implements NgElementStrategy { } this.callNgOnChanges(); - this.componentRef !.changeDetectorRef.detectChanges(); + this.componentRef!.changeDetectorRef.detectChanges(); } } diff --git a/packages/elements/src/create-custom-element.ts b/packages/elements/src/create-custom-element.ts index 791a5656f4887..79763b63deeea 100644 --- a/packages/elements/src/create-custom-element.ts +++ b/packages/elements/src/create-custom-element.ts @@ -31,7 +31,7 @@ export interface NgElementConstructor<P> { * Initializes a constructor instance. * @param injector If provided, overrides the configured injector. */ - new (injector?: Injector): NgElement&WithProperties<P>; + new(injector?: Injector): NgElement&WithProperties<P>; } /** @@ -44,20 +44,20 @@ export abstract class NgElement extends HTMLElement { * The strategy that controls how a component is transformed in a custom element. */ // TODO(issue/24571): remove '!'. - protected ngElementStrategy !: NgElementStrategy; + protected ngElementStrategy!: NgElementStrategy; /** * A subscription to change, connect, and disconnect events in the custom element. */ protected ngElementEventsSubscription: Subscription|null = null; /** - * Prototype for a handler that responds to a change in an observed attribute. - * @param attrName The name of the attribute that has changed. - * @param oldValue The previous value of the attribute. - * @param newValue The new value of the attribute. - * @param namespace The namespace in which the attribute is defined. - * @returns Nothing. - */ + * Prototype for a handler that responds to a change in an observed attribute. + * @param attrName The name of the attribute that has changed. + * @param oldValue The previous value of the attribute. + * @param newValue The new value of the attribute. + * @param namespace The namespace in which the attribute is defined. + * @returns Nothing. + */ abstract attributeChangedCallback( attrName: string, oldValue: string|null, newValue: string, namespace?: string): void; /** @@ -152,7 +152,7 @@ export function createCustomElement<P>( this.ngElementStrategy = strategyFactory.create(config.injector); } - const propName = attributeToPropertyInputs[attrName] !; + const propName = attributeToPropertyInputs[attrName]!; this.ngElementStrategy.setInputValue(propName, newValue); } @@ -165,7 +165,7 @@ export function createCustomElement<P>( // Listen for events from the strategy and dispatch them as custom events this.ngElementEventsSubscription = this.ngElementStrategy.events.subscribe(e => { - const customEvent = createCustomEvent(this.ownerDocument !, e.name, e.value); + const customEvent = createCustomEvent(this.ownerDocument!, e.name, e.value); this.dispatchEvent(customEvent); }); } @@ -186,8 +186,12 @@ export function createCustomElement<P>( // contain property inputs, use all inputs by default. inputs.map(({propName}) => propName).forEach(property => { Object.defineProperty(NgElementImpl.prototype, property, { - get: function() { return this.ngElementStrategy.getInputValue(property); }, - set: function(newValue: any) { this.ngElementStrategy.setInputValue(property, newValue); }, + get: function() { + return this.ngElementStrategy.getInputValue(property); + }, + set: function(newValue: any) { + this.ngElementStrategy.setInputValue(property, newValue); + }, configurable: true, enumerable: true, }); diff --git a/packages/elements/src/utils.ts b/packages/elements/src/utils.ts index 2333eb40b34a4..2e9bf93e2ac62 100644 --- a/packages/elements/src/utils.ts +++ b/packages/elements/src/utils.ts @@ -22,8 +22,10 @@ export const scheduler = { * * Returns a function that when executed will cancel the scheduled function. */ - schedule(taskFn: () => void, delay: number): () => - void{const id = setTimeout(taskFn, delay); return () => clearTimeout(id);}, + schedule(taskFn: () => void, delay: number): () => void { + const id = setTimeout(taskFn, delay); + return () => clearTimeout(id); + }, /** * Schedule a callback to be called before the next render. @@ -31,7 +33,7 @@ export const scheduler = { * * Returns a function that when executed will cancel the scheduled function. */ - scheduleBeforeRender(taskFn: () => void): () => void{ + scheduleBeforeRender(taskFn: () => void): () => void { // TODO(gkalpak): Implement a better way of accessing `requestAnimationFrame()` // (e.g. accounting for vendor prefix, SSR-compatibility, etc). if (typeof window === 'undefined') { @@ -76,7 +78,7 @@ export function createCustomEvent(doc: Document, name: string, detail: any): Cus /** * Check whether the input is an `Element`. */ -export function isElement(node: Node | null): node is Element { +export function isElement(node: Node|null): node is Element { return !!node && node.nodeType === Node.ELEMENT_NODE; } diff --git a/packages/elements/test/component-factory-strategy_spec.ts b/packages/elements/test/component-factory-strategy_spec.ts index 7887b55abf7f4..c93e182986b2f 100644 --- a/packages/elements/test/component-factory-strategy_spec.ts +++ b/packages/elements/test/component-factory-strategy_spec.ts @@ -53,11 +53,13 @@ describe('ComponentFactoryNgElementStrategy', () => { strategy.connect(document.createElement('div')); }); - it('should attach the component to the view', - () => { expect(applicationRef.attachView).toHaveBeenCalledWith(componentRef.hostView); }); + it('should attach the component to the view', () => { + expect(applicationRef.attachView).toHaveBeenCalledWith(componentRef.hostView); + }); - it('should detect changes', - () => { expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalled(); }); + it('should detect changes', () => { + expect(componentRef.changeDetectorRef.detectChanges).toHaveBeenCalled(); + }); it('should listen to output events', () => { const events: NgElementStrategyEvent[] = []; @@ -140,7 +142,9 @@ describe('ComponentFactoryNgElementStrategy', () => { }); describe('when inputs change and is connected', () => { - beforeEach(() => { strategy.connect(document.createElement('div')); }); + beforeEach(() => { + strategy.connect(document.createElement('div')); + }); it('should be set on the component instance', () => { strategy.setInputValue('fooFoo', 'fooFoo-1'); @@ -249,7 +253,9 @@ export class FakeComponent { // Keep track of the simple changes passed to ngOnChanges simpleChanges: SimpleChanges[] = []; - ngOnChanges(simpleChanges: SimpleChanges) { this.simpleChanges.push(simpleChanges); } + ngOnChanges(simpleChanges: SimpleChanges) { + this.simpleChanges.push(simpleChanges); + } } export class FakeComponentFactory extends ComponentFactory<any> { @@ -263,9 +269,15 @@ export class FakeComponentFactory extends ComponentFactory<any> { jasmine.createSpyObj('changeDetectorRef', ['detectChanges']); } - get selector(): string { return 'fake-component'; } - get componentType(): Type<any> { return FakeComponent; } - get ngContentSelectors(): string[] { return ['content-1', 'content-2']; } + get selector(): string { + return 'fake-component'; + } + get componentType(): Type<any> { + return FakeComponent; + } + get ngContentSelectors(): string[] { + return ['content-1', 'content-2']; + } get inputs(): {propName: string; templateName: string}[] { return [ {propName: 'fooFoo', templateName: 'fooFoo'}, @@ -293,8 +305,9 @@ export class FakeComponentFactory extends ComponentFactory<any> { } function expectSimpleChanges(actual: SimpleChanges, expected: SimpleChanges) { - Object.keys(actual).forEach( - key => { expect(expected[key]).toBeTruthy(`Change included additional key ${key}`); }); + Object.keys(actual).forEach(key => { + expect(expected[key]).toBeTruthy(`Change included additional key ${key}`); + }); Object.keys(expected).forEach(key => { expect(actual[key]).toBeTruthy(`Change should have included key ${key}`); diff --git a/packages/elements/test/create-custom-element_spec.ts b/packages/elements/test/create-custom-element_spec.ts index 34180a1e814db..450e1eed53031 100644 --- a/packages/elements/test/create-custom-element_spec.ts +++ b/packages/elements/test/create-custom-element_spec.ts @@ -6,13 +6,13 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, DoBootstrap, EventEmitter, Injector, Input, NgModule, Output, destroyPlatform} from '@angular/core'; +import {Component, destroyPlatform, DoBootstrap, EventEmitter, Injector, Input, NgModule, Output} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; import {Subject} from 'rxjs'; -import {NgElementConstructor, createCustomElement} from '../src/create-custom-element'; +import {createCustomElement, NgElementConstructor} from '../src/create-custom-element'; import {NgElementStrategy, NgElementStrategyEvent, NgElementStrategyFactory} from '../src/element-strategy'; type WithFooBar = { @@ -105,7 +105,7 @@ if (browserDetection.supportsCustomElements) { class TestComponent { @Input() fooFoo: string = 'foo'; // TODO(issue/24571): remove '!'. - @Input('barbar') barBar !: string; + @Input('barbar') barBar!: string; @Output() bazBaz = new EventEmitter<boolean>(); @Output('quxqux') quxQux = new EventEmitter<Object>(); @@ -126,17 +126,27 @@ export class TestStrategy implements NgElementStrategy { events = new Subject<NgElementStrategyEvent>(); - connect(element: HTMLElement): void { this.connectedElement = element; } + connect(element: HTMLElement): void { + this.connectedElement = element; + } - disconnect(): void { this.disconnectCalled = true; } + disconnect(): void { + this.disconnectCalled = true; + } - getInputValue(propName: string): any { return this.inputs.get(propName); } + getInputValue(propName: string): any { + return this.inputs.get(propName); + } - setInputValue(propName: string, value: string): void { this.inputs.set(propName, value); } + setInputValue(propName: string, value: string): void { + this.inputs.set(propName, value); + } } export class TestStrategyFactory implements NgElementStrategyFactory { testStrategy = new TestStrategy(); - create(): NgElementStrategy { return this.testStrategy; } + create(): NgElementStrategy { + return this.testStrategy; + } } diff --git a/packages/elements/test/slots_spec.ts b/packages/elements/test/slots_spec.ts index 1a8bc7e150cda..f69c526c95b12 100644 --- a/packages/elements/test/slots_spec.ts +++ b/packages/elements/test/slots_spec.ts @@ -6,12 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, ComponentFactoryResolver, EventEmitter, Input, NgModule, Output, ViewEncapsulation, destroyPlatform} from '@angular/core'; +import {Component, ComponentFactoryResolver, destroyPlatform, EventEmitter, Input, NgModule, Output, ViewEncapsulation} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; -import {NgElement, createCustomElement} from '../src/create-custom-element'; +import {createCustomElement, NgElement} from '../src/create-custom-element'; // we only run these tests in browsers that support Shadom DOM slots natively @@ -46,9 +46,9 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo it('should use slots to project content', () => { const tpl = `<default-slot-el><span class="projected"></span></default-slot-el>`; testContainer.innerHTML = tpl; - const testEl = testContainer.querySelector('default-slot-el') !; - const content = testContainer.querySelector('span.projected') !; - const slot = testEl.shadowRoot !.querySelector('slot') !; + const testEl = testContainer.querySelector('default-slot-el')!; + const content = testContainer.querySelector('span.projected')!; + const slot = testEl.shadowRoot!.querySelector('slot')!; const assignedNodes = slot.assignedNodes(); expect(assignedNodes[0]).toBe(content); }); @@ -56,9 +56,9 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo it('should use a named slot to project content', () => { const tpl = `<named-slot-el><span class="projected" slot="header"></span></named-slot-el>`; testContainer.innerHTML = tpl; - const testEl = testContainer.querySelector('named-slot-el') !; - const content = testContainer.querySelector('span.projected') !; - const slot = testEl.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement; + const testEl = testContainer.querySelector('named-slot-el')!; + const content = testContainer.querySelector('span.projected')!; + const slot = testEl.shadowRoot!.querySelector('slot[name=header]') as HTMLSlotElement; const assignedNodes = slot.assignedNodes(); expect(assignedNodes[0]).toBe(content); }); @@ -70,11 +70,11 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo <span class="projected-body" slot="body"></span> </named-slots-el>`; testContainer.innerHTML = tpl; - const testEl = testContainer.querySelector('named-slots-el') !; - const headerContent = testContainer.querySelector('span.projected-header') !; - const bodyContent = testContainer.querySelector('span.projected-body') !; - const headerSlot = testEl.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement; - const bodySlot = testEl.shadowRoot !.querySelector('slot[name=body]') as HTMLSlotElement; + const testEl = testContainer.querySelector('named-slots-el')!; + const headerContent = testContainer.querySelector('span.projected-header')!; + const bodyContent = testContainer.querySelector('span.projected-body')!; + const headerSlot = testEl.shadowRoot!.querySelector('slot[name=header]') as HTMLSlotElement; + const bodySlot = testEl.shadowRoot!.querySelector('slot[name=body]') as HTMLSlotElement; expect(headerContent.assignedSlot).toBe(headerSlot); expect(bodyContent.assignedSlot).toBe(bodySlot); @@ -88,7 +88,7 @@ if (browserDetection.supportsCustomElements && browserDetection.supportsShadowDo </slot-events-el>`; templateEl.innerHTML = tpl; const template = templateEl.content.cloneNode(true) as DocumentFragment; - const testEl = template.querySelector('slot-events-el') !as NgElement & SlotEventsComponent; + const testEl = template.querySelector('slot-events-el')! as NgElement & SlotEventsComponent; testEl.addEventListener('slotEventsChange', e => { expect(testEl.slotEvents.length).toEqual(1); done(); diff --git a/packages/examples/common/location/ts/hash_location_component.ts b/packages/examples/common/location/ts/hash_location_component.ts index 4021655b8e082..3bff5e48e4736 100644 --- a/packages/examples/common/location/ts/hash_location_component.ts +++ b/packages/examples/common/location/ts/hash_location_component.ts @@ -21,6 +21,8 @@ import {Component} from '@angular/core'; }) export class HashLocationComponent { location: Location; - constructor(location: Location) { this.location = location; } + constructor(location: Location) { + this.location = location; + } } // #enddocregion diff --git a/packages/examples/common/location/ts/path_location_component.ts b/packages/examples/common/location/ts/path_location_component.ts index 3984f23e6139e..7718afbb17d3c 100644 --- a/packages/examples/common/location/ts/path_location_component.ts +++ b/packages/examples/common/location/ts/path_location_component.ts @@ -21,6 +21,8 @@ import {Component} from '@angular/core'; }) export class PathLocationComponent { location: Location; - constructor(location: Location) { this.location = location; } + constructor(location: Location) { + this.location = location; + } } // #enddocregion diff --git a/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts b/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts index 6dd03cfed86ad..fb8922060876e 100644 --- a/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts +++ b/packages/examples/common/ngComponentOutlet/ts/e2e_test/ngComponentOutlet_spec.ts @@ -7,7 +7,7 @@ */ import {modifiedInIvy} from '@angular/private/testing'; -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; import {verifyNoBrowserErrors} from '../../../../test-utils'; diff --git a/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts b/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts index 941e1ed05d322..7ebd8299c930f 100644 --- a/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts +++ b/packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts @@ -7,7 +7,8 @@ */ import {modifiedInIvy} from '@angular/private/testing'; -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { diff --git a/packages/examples/common/ngIf/ts/module.ts b/packages/examples/common/ngIf/ts/module.ts index 913b6e3dc3388..9a258fbf2f40b 100644 --- a/packages/examples/common/ngIf/ts/module.ts +++ b/packages/examples/common/ngIf/ts/module.ts @@ -60,16 +60,16 @@ export class NgIfThenElse implements OnInit { thenBlock: TemplateRef<any>|null = null; show: boolean = true; - @ViewChild('primaryBlock', {static: true}) - primaryBlock: TemplateRef<any>|null = null; - @ViewChild('secondaryBlock', {static: true}) - secondaryBlock: TemplateRef<any>|null = null; + @ViewChild('primaryBlock', {static: true}) primaryBlock: TemplateRef<any>|null = null; + @ViewChild('secondaryBlock', {static: true}) secondaryBlock: TemplateRef<any>|null = null; switchPrimary() { this.thenBlock = this.thenBlock === this.primaryBlock ? this.secondaryBlock : this.primaryBlock; } - ngOnInit() { this.thenBlock = this.primaryBlock; } + ngOnInit() { + this.thenBlock = this.primaryBlock; + } } // #enddocregion diff --git a/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts b/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts index 508a68b01e7aa..cbdf0958ec67c 100644 --- a/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts +++ b/packages/examples/common/ngTemplateOutlet/ts/e2e_test/ngTemplateOutlet_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { diff --git a/packages/examples/common/pipes/ts/async_pipe.ts b/packages/examples/common/pipes/ts/async_pipe.ts index c1a6028f1fc50..109e83f57dfb8 100644 --- a/packages/examples/common/pipes/ts/async_pipe.ts +++ b/packages/examples/common/pipes/ts/async_pipe.ts @@ -24,18 +24,22 @@ export class AsyncPromisePipeComponent { private resolve: Function|null = null; - constructor() { this.reset(); } + constructor() { + this.reset(); + } reset() { this.arrived = false; - this.greeting = new Promise<string>((resolve, reject) => { this.resolve = resolve; }); + this.greeting = new Promise<string>((resolve, reject) => { + this.resolve = resolve; + }); } clicked() { if (this.arrived) { this.reset(); } else { - this.resolve !('hi there!'); + this.resolve!('hi there!'); this.arrived = true; } } @@ -64,6 +68,8 @@ function setInterval(fn: Function, delay: number) { rootZone = rootZone.parent; } rootZone.run(() => { - window.setInterval(function(this: unknown) { zone.run(fn, this, arguments as any); }, delay); + window.setInterval(function(this: unknown) { + zone.run(fn, this, arguments as any); + }, delay); }); } diff --git a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts index 6c75ea63d849b..00224b17f861b 100644 --- a/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts +++ b/packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; function waitForElement(selector: string) { diff --git a/packages/examples/common/pipes/ts/lowerupper_pipe.ts b/packages/examples/common/pipes/ts/lowerupper_pipe.ts index 4e466b0cbbd84..9783156c2078d 100644 --- a/packages/examples/common/pipes/ts/lowerupper_pipe.ts +++ b/packages/examples/common/pipes/ts/lowerupper_pipe.ts @@ -19,7 +19,9 @@ import {Component} from '@angular/core'; }) export class LowerUpperPipeComponent { // TODO(issue/24571): remove '!'. - value !: string; - change(value: string) { this.value = value; } + value!: string; + change(value: string) { + this.value = value; + } } // #enddocregion diff --git a/packages/examples/core/animation/ts/dsl/animation_example.ts b/packages/examples/core/animation/ts/dsl/animation_example.ts index dc3e527ed72f6..3b8a563b22e10 100644 --- a/packages/examples/core/animation/ts/dsl/animation_example.ts +++ b/packages/examples/core/animation/ts/dsl/animation_example.ts @@ -30,8 +30,7 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; [ state('collapsed, void', style({height: '0px', color: 'maroon', borderColor: 'maroon'})), state('expanded', style({height: '*', borderColor: 'green', color: 'green'})), - transition( - 'collapsed <=> expanded', [animate(500, style({height: '250px'})), animate(500)]) + transition('collapsed <=> expanded', [animate(500, style({height: '250px'})), animate(500)]) ])], template: ` <button (click)="expand()">Open</button> @@ -44,10 +43,16 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; }) export class MyExpandoCmp { // TODO(issue/24571): remove '!'. - stateExpression !: string; - constructor() { this.collapse(); } - expand() { this.stateExpression = 'expanded'; } - collapse() { this.stateExpression = 'collapsed'; } + stateExpression!: string; + constructor() { + this.collapse(); + } + expand() { + this.stateExpression = 'expanded'; + } + collapse() { + this.stateExpression = 'collapsed'; + } } @NgModule( diff --git a/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts b/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts index 550af8d2a58e0..c10a054fb36a6 100644 --- a/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts +++ b/packages/examples/core/animation/ts/dsl/e2e_test/animation_example_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {$, ExpectedConditions, browser, by, element} from 'protractor'; +import {$, browser, by, element, ExpectedConditions} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../../test-utils'; function waitForElement(selector: string) { diff --git a/packages/examples/core/debug/ts/debug_element/debug_element.ts b/packages/examples/core/debug/ts/debug_element/debug_element.ts index 63cf722dc0aad..ba2edc338d12d 100644 --- a/packages/examples/core/debug/ts/debug_element/debug_element.ts +++ b/packages/examples/core/debug/ts/debug_element/debug_element.ts @@ -8,7 +8,7 @@ import {DebugElement} from '@angular/core'; -let debugElement: DebugElement = undefined !; +let debugElement: DebugElement = undefined!; let predicate: any; // #docregion scope_all diff --git a/packages/examples/core/di/ts/contentChild/content_child_example.ts b/packages/examples/core/di/ts/contentChild/content_child_example.ts index f24a611c1f5dc..5ffd18fed9a61 100644 --- a/packages/examples/core/di/ts/contentChild/content_child_example.ts +++ b/packages/examples/core/di/ts/contentChild/content_child_example.ts @@ -11,7 +11,7 @@ import {Component, ContentChild, Directive, Input} from '@angular/core'; @Directive({selector: 'pane'}) export class Pane { - @Input() id !: string; + @Input() id!: string; } @Component({ @@ -21,7 +21,7 @@ export class Pane { ` }) export class Tab { - @ContentChild(Pane) pane !: Pane; + @ContentChild(Pane) pane!: Pane; } @Component({ @@ -38,6 +38,8 @@ export class Tab { export class ContentChildComp { shouldShow = true; - toggle() { this.shouldShow = !this.shouldShow; } + toggle() { + this.shouldShow = !this.shouldShow; + } } // #enddocregion diff --git a/packages/examples/core/di/ts/contentChild/content_child_howto.ts b/packages/examples/core/di/ts/contentChild/content_child_howto.ts index d062b703f81c0..b8786393eac54 100644 --- a/packages/examples/core/di/ts/contentChild/content_child_howto.ts +++ b/packages/examples/core/di/ts/contentChild/content_child_howto.ts @@ -15,7 +15,7 @@ class ChildDirective { @Directive({selector: 'someDir'}) class SomeDir implements AfterContentInit { - @ContentChild(ChildDirective) contentChild !: ChildDirective; + @ContentChild(ChildDirective) contentChild!: ChildDirective; ngAfterContentInit() { // contentChild is set diff --git a/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts b/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts index 8c88393838d65..96290c5f650e6 100644 --- a/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts +++ b/packages/examples/core/di/ts/contentChild/e2e_test/content_child_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('contentChild example', () => { diff --git a/packages/examples/core/di/ts/contentChildren/content_children_example.ts b/packages/examples/core/di/ts/contentChildren/content_children_example.ts index 99e981b87b68a..d4de03552ed1a 100644 --- a/packages/examples/core/di/ts/contentChildren/content_children_example.ts +++ b/packages/examples/core/di/ts/contentChildren/content_children_example.ts @@ -11,7 +11,7 @@ import {Component, ContentChildren, Directive, Input, QueryList} from '@angular/ @Directive({selector: 'pane'}) export class Pane { - @Input() id !: string; + @Input() id!: string; } @Component({ @@ -22,8 +22,8 @@ export class Pane { ` }) export class Tab { - @ContentChildren(Pane) topLevelPanes !: QueryList<Pane>; - @ContentChildren(Pane, {descendants: true}) arbitraryNestedPanes !: QueryList<Pane>; + @ContentChildren(Pane) topLevelPanes!: QueryList<Pane>; + @ContentChildren(Pane, {descendants: true}) arbitraryNestedPanes!: QueryList<Pane>; get serializedPanes(): string { return this.topLevelPanes ? this.topLevelPanes.map(p => p.id).join(', ') : ''; @@ -53,6 +53,8 @@ export class Tab { export class ContentChildrenComp { shouldShow = false; - show() { this.shouldShow = true; } + show() { + this.shouldShow = true; + } } // #enddocregion diff --git a/packages/examples/core/di/ts/contentChildren/content_children_howto.ts b/packages/examples/core/di/ts/contentChildren/content_children_howto.ts index 32c5b4b81cd7c..6cec0762d1bfa 100644 --- a/packages/examples/core/di/ts/contentChildren/content_children_howto.ts +++ b/packages/examples/core/di/ts/contentChildren/content_children_howto.ts @@ -15,7 +15,7 @@ class ChildDirective { @Directive({selector: 'someDir'}) class SomeDir implements AfterContentInit { - @ContentChildren(ChildDirective) contentChildren !: QueryList<ChildDirective>; + @ContentChildren(ChildDirective) contentChildren!: QueryList<ChildDirective>; ngAfterContentInit() { // contentChildren is set diff --git a/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts b/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts index 068e457704269..fcf4f2ddd1b58 100644 --- a/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts +++ b/packages/examples/core/di/ts/contentChildren/e2e_test/content_children_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('contentChildren example', () => { diff --git a/packages/examples/core/di/ts/injector_spec.ts b/packages/examples/core/di/ts/injector_spec.ts index 600bc132e884e..d89f6c8fe340a 100644 --- a/packages/examples/core/di/ts/injector_spec.ts +++ b/packages/examples/core/di/ts/injector_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {InjectFlags, InjectionToken, Injector, Type, inject, ɵsetCurrentInjector as setCurrentInjector} from '@angular/core'; +import {inject, InjectFlags, InjectionToken, Injector, Type, ɵsetCurrentInjector as setCurrentInjector} from '@angular/core'; class MockRootScopeInjector implements Injector { constructor(readonly parent: Injector) {} diff --git a/packages/examples/core/di/ts/metadata_spec.ts b/packages/examples/core/di/ts/metadata_spec.ts index 811790dd96b9a..48d2f038783c1 100644 --- a/packages/examples/core/di/ts/metadata_spec.ts +++ b/packages/examples/core/di/ts/metadata_spec.ts @@ -59,9 +59,8 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; } const injector = Injector.create({ - providers: [ - {provide: NeedsService, deps: [UsefulService]}, {provide: UsefulService, deps: []} - ] + providers: + [{provide: NeedsService, deps: [UsefulService]}, {provide: UsefulService, deps: []}] }); expect(injector.get(NeedsService).service instanceof UsefulService).toBe(true); // #enddocregion @@ -104,7 +103,9 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; @Injectable() class NeedsDependency { - constructor(@SkipSelf() public dependency: Dependency) { this.dependency = dependency; } + constructor(@SkipSelf() public dependency: Dependency) { + this.dependency = dependency; + } } const parent = Injector.create({providers: [{provide: Dependency, deps: []}]}); @@ -158,7 +159,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; declarations: [App, ParentCmp, ChildDirective], }); - let cmp: ComponentFixture<App> = undefined !; + let cmp: ComponentFixture<App> = undefined!; expect(() => cmp = TestBed.createComponent(App)).not.toThrow(); expect(cmp.debugElement.children[0].children[0].injector.get(ChildDirective).logs).toEqual([ @@ -167,6 +168,5 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; ]); }); }); - }); } diff --git a/packages/examples/core/di/ts/provider_spec.ts b/packages/examples/core/di/ts/provider_spec.ts index b08423e55ccd1..17462158cfd78 100644 --- a/packages/examples/core/di/ts/provider_spec.ts +++ b/packages/examples/core/di/ts/provider_spec.ts @@ -55,7 +55,9 @@ import {Injectable, InjectionToken, Injector, Optional, ReflectiveInjector} from describe('ClassProvider', () => { it('works', () => { // #docregion ClassProvider - abstract class Shape { name !: string; } + abstract class Shape { + name!: string; + } class Square extends Shape { name = 'square'; @@ -92,7 +94,9 @@ import {Injectable, InjectionToken, Injector, Optional, ReflectiveInjector} from describe('StaticClassProvider', () => { it('works', () => { // #docregion StaticClassProvider - abstract class Shape { name !: string; } + abstract class Shape { + name!: string; + } class Square extends Shape { name = 'square'; @@ -200,6 +204,5 @@ import {Injectable, InjectionToken, Injector, Optional, ReflectiveInjector} from // #enddocregion }); }); - }); } diff --git a/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts b/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts index 295cd1dbf1fde..dae43e8b59874 100644 --- a/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts +++ b/packages/examples/core/di/ts/viewChild/e2e_test/view_child_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('viewChild example', () => { diff --git a/packages/examples/core/di/ts/viewChild/view_child_example.ts b/packages/examples/core/di/ts/viewChild/view_child_example.ts index 6601fed8f9a9f..50b72216d1e7a 100644 --- a/packages/examples/core/di/ts/viewChild/view_child_example.ts +++ b/packages/examples/core/di/ts/viewChild/view_child_example.ts @@ -11,7 +11,7 @@ import {Component, Directive, Input, ViewChild} from '@angular/core'; @Directive({selector: 'pane'}) export class Pane { - @Input() id !: string; + @Input() id!: string; } @Component({ @@ -28,10 +28,14 @@ export class Pane { export class ViewChildComp { @ViewChild(Pane) set pane(v: Pane) { - setTimeout(() => { this.selectedPane = v.id; }, 0); + setTimeout(() => { + this.selectedPane = v.id; + }, 0); } selectedPane: string = ''; shouldShow = true; - toggle() { this.shouldShow = !this.shouldShow; } + toggle() { + this.shouldShow = !this.shouldShow; + } } // #enddocregion diff --git a/packages/examples/core/di/ts/viewChild/view_child_howto.ts b/packages/examples/core/di/ts/viewChild/view_child_howto.ts index 74c906bff6256..cfa5f923acca9 100644 --- a/packages/examples/core/di/ts/viewChild/view_child_howto.ts +++ b/packages/examples/core/di/ts/viewChild/view_child_howto.ts @@ -15,7 +15,7 @@ class ChildDirective { @Component({selector: 'someCmp', templateUrl: 'someCmp.html'}) class SomeCmp implements AfterViewInit { - @ViewChild(ChildDirective) child !: ChildDirective; + @ViewChild(ChildDirective) child!: ChildDirective; ngAfterViewInit() { // child is set diff --git a/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts b/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts index 701e8cc389bf6..09cd00945dde1 100644 --- a/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts +++ b/packages/examples/core/di/ts/viewChildren/e2e_test/view_children_spec.ts @@ -7,7 +7,8 @@ */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../../test-utils'; describe('viewChildren example', () => { diff --git a/packages/examples/core/di/ts/viewChildren/view_children_example.ts b/packages/examples/core/di/ts/viewChildren/view_children_example.ts index f89bf47524461..3f8fa48b99702 100644 --- a/packages/examples/core/di/ts/viewChildren/view_children_example.ts +++ b/packages/examples/core/di/ts/viewChildren/view_children_example.ts @@ -11,7 +11,7 @@ import {AfterViewInit, Component, Directive, Input, QueryList, ViewChildren} fro @Directive({selector: 'pane'}) export class Pane { - @Input() id !: string; + @Input() id!: string; } @Component({ @@ -27,20 +27,26 @@ export class Pane { `, }) export class ViewChildrenComp implements AfterViewInit { - @ViewChildren(Pane) panes !: QueryList<Pane>; + @ViewChildren(Pane) panes!: QueryList<Pane>; serializedPanes: string = ''; shouldShow = false; - show() { this.shouldShow = true; } + show() { + this.shouldShow = true; + } ngAfterViewInit() { this.calculateSerializedPanes(); - this.panes.changes.subscribe((r) => { this.calculateSerializedPanes(); }); + this.panes.changes.subscribe((r) => { + this.calculateSerializedPanes(); + }); } calculateSerializedPanes() { - setTimeout(() => { this.serializedPanes = this.panes.map(p => p.id).join(', '); }, 0); + setTimeout(() => { + this.serializedPanes = this.panes.map(p => p.id).join(', '); + }, 0); } } // #enddocregion diff --git a/packages/examples/core/di/ts/viewChildren/view_children_howto.ts b/packages/examples/core/di/ts/viewChildren/view_children_howto.ts index 4d4273e5ba920..efb68d7394d80 100644 --- a/packages/examples/core/di/ts/viewChildren/view_children_howto.ts +++ b/packages/examples/core/di/ts/viewChildren/view_children_howto.ts @@ -15,7 +15,7 @@ class ChildDirective { @Component({selector: 'someCmp', templateUrl: 'someCmp.html'}) class SomeCmp implements AfterViewInit { - @ViewChildren(ChildDirective) viewChildren !: QueryList<ChildDirective>; + @ViewChildren(ChildDirective) viewChildren!: QueryList<ChildDirective>; ngAfterViewInit() { // viewChildren is set diff --git a/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts b/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts index 9ffc27a77446b..5bf7a58c8283b 100644 --- a/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts +++ b/packages/examples/core/testability/ts/whenStable/e2e_test/testability_example_spec.ts @@ -29,7 +29,9 @@ describe('testability example', () => { let waitWithResultScript = function(done: any) { let rootEl = document.querySelector('example-app'); let testability = window.getAngularTestability(rootEl); - testability.whenStable((didWork: boolean, tasks: any) => { done(tasks); }, 1000); + testability.whenStable((didWork: boolean, tasks: any) => { + done(tasks); + }, 1000); }; element(by.css('.start-button')).click(); @@ -43,6 +45,8 @@ describe('testability example', () => { }); }); - afterAll(() => { browser.ignoreSynchronization = false; }); + afterAll(() => { + browser.ignoreSynchronization = false; + }); }); }); diff --git a/packages/examples/core/testability/ts/whenStable/testability_example.ts b/packages/examples/core/testability/ts/whenStable/testability_example.ts index d2df32fdcadd9..ec5633e237be9 100644 --- a/packages/examples/core/testability/ts/whenStable/testability_example.ts +++ b/packages/examples/core/testability/ts/whenStable/testability_example.ts @@ -20,7 +20,9 @@ export class StableTestCmp { status = 'none'; start() { this.status = 'running'; - setTimeout(() => { this.status = 'done'; }, 5000); + setTimeout(() => { + this.status = 'done'; + }, 5000); } } diff --git a/packages/examples/core/testing/ts/fake_async.ts b/packages/examples/core/testing/ts/fake_async.ts index 10e9ca2f33230..805289003af8a 100644 --- a/packages/examples/core/testing/ts/fake_async.ts +++ b/packages/examples/core/testing/ts/fake_async.ts @@ -13,7 +13,9 @@ import {discardPeriodicTasks, fakeAsync, tick} from '@angular/core/testing'; describe('this test', () => { it('looks async but is synchronous', <any>fakeAsync((): void => { let flag = false; - setTimeout(() => { flag = true; }, 100); + setTimeout(() => { + flag = true; + }, 100); expect(flag).toBe(false); tick(50); expect(flag).toBe(false); diff --git a/packages/examples/core/ts/change_detect/change-detection.ts b/packages/examples/core/ts/change_detect/change-detection.ts index 4b4b8b9bd0e39..c78d345e1d3a0 100644 --- a/packages/examples/core/ts/change_detect/change-detection.ts +++ b/packages/examples/core/ts/change_detect/change-detection.ts @@ -33,7 +33,9 @@ class AppComponent { // #docregion detach class DataListProvider { // in a real application the returned data will be different every time - get data() { return [1, 2, 3, 4, 5]; } + get data() { + return [1, 2, 3, 4, 5]; + } } @Component({ @@ -45,7 +47,9 @@ class DataListProvider { class GiantList { constructor(private ref: ChangeDetectorRef, public dataProvider: DataListProvider) { ref.detach(); - setInterval(() => { this.ref.detectChanges(); }, 5000); + setInterval(() => { + this.ref.detectChanges(); + }, 5000); } } @@ -64,7 +68,9 @@ class App { class DataProvider { data = 1; constructor() { - setInterval(() => { this.data = 2; }, 500); + setInterval(() => { + this.data = 2; + }, 500); } } diff --git a/packages/examples/core/ts/metadata/directives.ts b/packages/examples/core/ts/metadata/directives.ts index 49aa0ea6b1bab..9443de82d0da6 100644 --- a/packages/examples/core/ts/metadata/directives.ts +++ b/packages/examples/core/ts/metadata/directives.ts @@ -60,8 +60,12 @@ export class IntervalDirComponent { ` }) export class MyOutputComponent { - onEverySecond() { console.log('second'); } - onEveryFiveSeconds() { console.log('five seconds'); } + onEverySecond() { + console.log('second'); + } + onEveryFiveSeconds() { + console.log('five seconds'); + } } // #enddocregion component-output-interval diff --git a/packages/examples/core/ts/metadata/lifecycle_hooks_spec.ts b/packages/examples/core/ts/metadata/lifecycle_hooks_spec.ts index a4a0d76b5963f..7eac18007ccfb 100644 --- a/packages/examples/core/ts/metadata/lifecycle_hooks_spec.ts +++ b/packages/examples/core/ts/metadata/lifecycle_hooks_spec.ts @@ -10,142 +10,143 @@ import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, import {TestBed} from '@angular/core/testing'; (function() { - describe('lifecycle hooks examples', () => { - it('should work with ngOnInit', () => { - // #docregion OnInit - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements OnInit { - ngOnInit() { - // ... - } +describe('lifecycle hooks examples', () => { + it('should work with ngOnInit', () => { + // #docregion OnInit + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements OnInit { + ngOnInit() { + // ... } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngOnInit', []]]); - }); - - it('should work with ngDoCheck', () => { - // #docregion DoCheck - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements DoCheck { - ngDoCheck() { - // ... - } - } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngDoCheck', []]]); - }); - - it('should work with ngAfterContentChecked', () => { - // #docregion AfterContentChecked - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements AfterContentChecked { - ngAfterContentChecked() { - // ... - } - } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentChecked', []]]); - }); - - it('should work with ngAfterContentInit', () => { - // #docregion AfterContentInit - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements AfterContentInit { - ngAfterContentInit() { - // ... - } + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngOnInit', []]]); + }); + + it('should work with ngDoCheck', () => { + // #docregion DoCheck + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements DoCheck { + ngDoCheck() { + // ... } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentInit', []]]); - }); - - it('should work with ngAfterViewChecked', () => { - // #docregion AfterViewChecked - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements AfterViewChecked { - ngAfterViewChecked() { - // ... - } + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngDoCheck', []]]); + }); + + it('should work with ngAfterContentChecked', () => { + // #docregion AfterContentChecked + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements AfterContentChecked { + ngAfterContentChecked() { + // ... } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewChecked', []]]); - }); - - it('should work with ngAfterViewInit', () => { - // #docregion AfterViewInit - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements AfterViewInit { - ngAfterViewInit() { - // ... - } + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentChecked', []]]); + }); + + it('should work with ngAfterContentInit', () => { + // #docregion AfterContentInit + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements AfterContentInit { + ngAfterContentInit() { + // ... } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewInit', []]]); - }); - - it('should work with ngOnDestroy', () => { - // #docregion OnDestroy - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements OnDestroy { - ngOnDestroy() { - // ... - } + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentInit', []]]); + }); + + it('should work with ngAfterViewChecked', () => { + // #docregion AfterViewChecked + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements AfterViewChecked { + ngAfterViewChecked() { + // ... } - // #enddocregion - - expect(createAndLogComponent(MyComponent)).toEqual([['ngOnDestroy', []]]); - }); - - it('should work with ngOnChanges', () => { - // #docregion OnChanges - @Component({selector: 'my-cmp', template: `...`}) - class MyComponent implements OnChanges { - // TODO(issue/24571): remove '!'. - @Input() - prop !: number; - - ngOnChanges(changes: SimpleChanges) { - // changes.prop contains the old and the new value... - } + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewChecked', []]]); + }); + + it('should work with ngAfterViewInit', () => { + // #docregion AfterViewInit + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements AfterViewInit { + ngAfterViewInit() { + // ... } - // #enddocregion - - const log = createAndLogComponent(MyComponent, ['prop']); - expect(log.length).toBe(1); - expect(log[0][0]).toBe('ngOnChanges'); - const changes: SimpleChanges = log[0][1][0]; - expect(changes['prop'].currentValue).toBe(true); - }); + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewInit', []]]); }); - function createAndLogComponent(clazz: Type<any>, inputs: string[] = []): any[] { - const log: any[] = []; - createLoggingSpiesFromProto(clazz, log); + it('should work with ngOnDestroy', () => { + // #docregion OnDestroy + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements OnDestroy { + ngOnDestroy() { + // ... + } + } + // #enddocregion + + expect(createAndLogComponent(MyComponent)).toEqual([['ngOnDestroy', []]]); + }); - const inputBindings = inputs.map(input => `[${input}] = true`).join(' '); + it('should work with ngOnChanges', () => { + // #docregion OnChanges + @Component({selector: 'my-cmp', template: `...`}) + class MyComponent implements OnChanges { + // TODO(issue/24571): remove '!'. + @Input() prop!: number; - @Component({template: `<my-cmp ${inputBindings}></my-cmp>`}) - class ParentComponent { + ngOnChanges(changes: SimpleChanges) { + // changes.prop contains the old and the new value... + } } + // #enddocregion + const log = createAndLogComponent(MyComponent, ['prop']); + expect(log.length).toBe(1); + expect(log[0][0]).toBe('ngOnChanges'); + const changes: SimpleChanges = log[0][1][0]; + expect(changes['prop'].currentValue).toBe(true); + }); +}); - const fixture = TestBed.configureTestingModule({declarations: [ParentComponent, clazz]}) - .createComponent(ParentComponent); - fixture.detectChanges(); - fixture.destroy(); - return log; - } +function createAndLogComponent(clazz: Type<any>, inputs: string[] = []): any[] { + const log: any[] = []; + createLoggingSpiesFromProto(clazz, log); + + const inputBindings = inputs.map(input => `[${input}] = true`).join(' '); - function createLoggingSpiesFromProto(clazz: Type<any>, log: any[]) { - const proto = clazz.prototype; - Object.keys(proto).forEach((method) => { - proto[method] = (...args: any[]) => { log.push([method, args]); }; - }); + @Component({template: `<my-cmp ${inputBindings}></my-cmp>`}) + class ParentComponent { } + + + const fixture = TestBed.configureTestingModule({declarations: [ParentComponent, clazz]}) + .createComponent(ParentComponent); + fixture.detectChanges(); + fixture.destroy(); + return log; +} + +function createLoggingSpiesFromProto(clazz: Type<any>, log: any[]) { + const proto = clazz.prototype; + Object.keys(proto).forEach((method) => { + proto[method] = (...args: any[]) => { + log.push([method, args]); + }; + }); +} })(); diff --git a/packages/examples/core/ts/metadata/metadata.ts b/packages/examples/core/ts/metadata/metadata.ts index 179436741e4a9..9d7bdb02d1e26 100644 --- a/packages/examples/core/ts/metadata/metadata.ts +++ b/packages/examples/core/ts/metadata/metadata.ts @@ -21,7 +21,9 @@ class Greet { @Component({selector: 'page', template: 'Title: {{title}}'}) class Page { title: string; - constructor(@Attribute('title') title: string) { this.title = title; } + constructor(@Attribute('title') title: string) { + this.title = title; + } } // #enddocregion @@ -46,6 +48,8 @@ class InputDirective { // #docregion pipe @Pipe({name: 'lowercase'}) class Lowercase { - transform(v: string, args: any[]) { return v.toLowerCase(); } + transform(v: string, args: any[]) { + return v.toLowerCase(); + } } // #enddocregion diff --git a/packages/examples/core/ts/prod_mode/prod_mode_example.ts b/packages/examples/core/ts/prod_mode/prod_mode_example.ts index 34cc039b4e7dc..d71b801a4bd09 100644 --- a/packages/examples/core/ts/prod_mode/prod_mode_example.ts +++ b/packages/examples/core/ts/prod_mode/prod_mode_example.ts @@ -7,9 +7,10 @@ */ // #docregion enableProdMode -import {NgModule, enableProdMode} from '@angular/core'; +import {enableProdMode, NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; + import {MyComponent} from './my_component'; enableProdMode(); diff --git a/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts b/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts index 03c964d0c6bc9..f7147df783382 100644 --- a/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts +++ b/packages/examples/forms/ts/formBuilder/e2e_test/form_builder_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('formBuilder example', () => { @@ -33,5 +34,4 @@ describe('formBuilder example', () => { inputs.get(0).sendKeys('a'); expect(paragraphs.get(1).getText()).toEqual('Validation status: INVALID'); }); - }); diff --git a/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts b/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts index 9baaac992c6f2..8f67dfd19d50d 100644 --- a/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts +++ b/packages/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('nestedFormArray example', () => { @@ -39,5 +40,4 @@ describe('nestedFormArray example', () => { expect(inputs.get(0).getAttribute('value')).toEqual('LA'); expect(inputs.get(1).getAttribute('value')).toEqual('MTV'); }); - }); diff --git a/packages/examples/forms/ts/nestedFormArray/nested_form_array_example.ts b/packages/examples/forms/ts/nestedFormArray/nested_form_array_example.ts index 1554c7ef17831..6713e04ac904b 100644 --- a/packages/examples/forms/ts/nestedFormArray/nested_form_array_example.ts +++ b/packages/examples/forms/ts/nestedFormArray/nested_form_array_example.ts @@ -35,15 +35,21 @@ export class NestedFormArray { ]), }); - get cities(): FormArray { return this.form.get('cities') as FormArray; } + get cities(): FormArray { + return this.form.get('cities') as FormArray; + } - addCity() { this.cities.push(new FormControl()); } + addCity() { + this.cities.push(new FormControl()); + } onSubmit() { console.log(this.cities.value); // ['SF', 'NY'] console.log(this.form.value); // { cities: ['SF', 'NY'] } } - setPreset() { this.cities.patchValue(['LA', 'MTV']); } + setPreset() { + this.cities.patchValue(['LA', 'MTV']); + } } // #enddocregion diff --git a/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts b/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts index a3fb76047c9f4..3049a4cd6cb02 100644 --- a/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts +++ b/packages/examples/forms/ts/nestedFormGroup/e2e_test/nested_form_group_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('nestedFormGroup example', () => { @@ -40,5 +41,4 @@ describe('nestedFormGroup example', () => { expect(firstInput.getAttribute('value')).toEqual('Bess'); expect(lastInput.getAttribute('value')).toEqual('Marvin'); }); - }); diff --git a/packages/examples/forms/ts/nestedFormGroup/module.ts b/packages/examples/forms/ts/nestedFormGroup/module.ts index 0d5503f1ae55e..851450eb5eb3b 100644 --- a/packages/examples/forms/ts/nestedFormGroup/module.ts +++ b/packages/examples/forms/ts/nestedFormGroup/module.ts @@ -1,10 +1,10 @@ /** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ import {NgModule} from '@angular/core'; import {ReactiveFormsModule} from '@angular/forms'; diff --git a/packages/examples/forms/ts/nestedFormGroup/nested_form_group_example.ts b/packages/examples/forms/ts/nestedFormGroup/nested_form_group_example.ts index 38c61535b8716..d5e56370dcc11 100644 --- a/packages/examples/forms/ts/nestedFormGroup/nested_form_group_example.ts +++ b/packages/examples/forms/ts/nestedFormGroup/nested_form_group_example.ts @@ -37,9 +37,13 @@ export class NestedFormGroupComp { email: new FormControl() }); - get first(): any { return this.form.get('name.first'); } + get first(): any { + return this.form.get('name.first'); + } - get name(): any { return this.form.get('name'); } + get name(): any { + return this.form.get('name'); + } onSubmit() { console.log(this.first.value); // 'Nancy' @@ -48,6 +52,8 @@ export class NestedFormGroupComp { console.log(this.form.status); // VALID } - setPreset() { this.name.setValue({first: 'Bess', last: 'Marvin'}); } + setPreset() { + this.name.setValue({first: 'Bess', last: 'Marvin'}); + } } // #enddocregion diff --git a/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts b/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts index 6d700e69ee422..e27a692309f98 100644 --- a/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts +++ b/packages/examples/forms/ts/ngModelGroup/e2e_test/ng_model_group_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('ngModelGroup example', () => { @@ -38,5 +39,4 @@ describe('ngModelGroup example', () => { expect(inputs.get(0).getAttribute('value')).toEqual('Bess'); expect(inputs.get(1).getAttribute('value')).toEqual('Marvin'); }); - }); diff --git a/packages/examples/forms/ts/ngModelGroup/ng_model_group_example.ts b/packages/examples/forms/ts/ngModelGroup/ng_model_group_example.ts index fe794843f153a..a0f6b853b4221 100644 --- a/packages/examples/forms/ts/ngModelGroup/ng_model_group_example.ts +++ b/packages/examples/forms/ts/ngModelGroup/ng_model_group_example.ts @@ -37,6 +37,8 @@ export class NgModelGroupComp { console.log(f.valid); // true } - setValue() { this.name = {first: 'Bess', last: 'Marvin'}; } + setValue() { + this.name = {first: 'Bess', last: 'Marvin'}; + } } // #enddocregion diff --git a/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts b/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts index 56f668ec14499..8976d9b77c5eb 100644 --- a/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts +++ b/packages/examples/forms/ts/radioButtons/e2e_test/radio_button_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('radioButtons example', () => { diff --git a/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts b/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts index 4b23a8ffd5996..14f4870d2ad5a 100644 --- a/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts +++ b/packages/examples/forms/ts/reactiveRadioButtons/e2e_test/reactive_radio_button_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('radioButtons example', () => { diff --git a/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts b/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts index 1da4d5eff0b10..a3b406eef7979 100644 --- a/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts +++ b/packages/examples/forms/ts/reactiveSelectControl/e2e_test/reactive_select_control_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('reactiveSelectControl example', () => { @@ -33,5 +34,4 @@ describe('reactiveSelectControl example', () => { expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }'); }); - }); diff --git a/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts b/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts index 2fbbc22fd308d..53397400b6347 100644 --- a/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts +++ b/packages/examples/forms/ts/selectControl/e2e_test/select_control_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('selectControl example', () => { @@ -22,8 +23,9 @@ describe('selectControl example', () => { p = element(by.css('p')); }); - it('should initially select the placeholder option', - () => { expect(options.get(0).getAttribute('selected')).toBe('true'); }); + it('should initially select the placeholder option', () => { + expect(options.get(0).getAttribute('selected')).toBe('true'); + }); it('should update the model when the value changes in the UI', () => { select.click(); @@ -31,5 +33,4 @@ describe('selectControl example', () => { expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }'); }); - }); diff --git a/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts b/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts index 0588a5882de98..a97431bf33902 100644 --- a/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts +++ b/packages/examples/forms/ts/simpleForm/e2e_test/simple_form_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('simpleForm example', () => { @@ -40,5 +41,4 @@ describe('simpleForm example', () => { expect(paragraphs.get(1).getText()).toEqual('First name valid: true'); expect(paragraphs.get(3).getText()).toEqual('Form valid: true'); }); - }); diff --git a/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts b/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts index 810064705c6cd..240e3df9dc93d 100644 --- a/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts +++ b/packages/examples/forms/ts/simpleFormControl/e2e_test/simple_form_control_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('simpleFormControl example', () => { @@ -49,6 +50,5 @@ describe('simpleFormControl example', () => { element(by.css('button')).click(); expect(input.getAttribute('value')).toEqual('new value'); }); - }); }); diff --git a/packages/examples/forms/ts/simpleFormControl/simple_form_control_example.ts b/packages/examples/forms/ts/simpleFormControl/simple_form_control_example.ts index cd799034c7bf8..782e89b79d926 100644 --- a/packages/examples/forms/ts/simpleFormControl/simple_form_control_example.ts +++ b/packages/examples/forms/ts/simpleFormControl/simple_form_control_example.ts @@ -24,6 +24,8 @@ import {FormControl, Validators} from '@angular/forms'; export class SimpleFormControl { control: FormControl = new FormControl('value', Validators.minLength(2)); - setValue() { this.control.setValue('new value'); } + setValue() { + this.control.setValue('new value'); + } } // #enddocregion diff --git a/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts b/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts index 76fdf8e7c6493..9bca0217d216e 100644 --- a/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts +++ b/packages/examples/forms/ts/simpleFormGroup/e2e_test/simple_form_group_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../test-utils'; describe('formControlName example', () => { @@ -40,6 +41,5 @@ describe('formControlName example', () => { expect(firstInput.getAttribute('value')).toEqual('Carson'); expect(lastInput.getAttribute('value')).toEqual('Drew'); }); - }); }); diff --git a/packages/examples/forms/ts/simpleFormGroup/simple_form_group_example.ts b/packages/examples/forms/ts/simpleFormGroup/simple_form_group_example.ts index 7ca0d21abe4ac..15dced1bcd133 100644 --- a/packages/examples/forms/ts/simpleFormGroup/simple_form_group_example.ts +++ b/packages/examples/forms/ts/simpleFormGroup/simple_form_group_example.ts @@ -31,13 +31,17 @@ export class SimpleFormGroup { last: new FormControl('Drew'), }); - get first(): any { return this.form.get('first'); } + get first(): any { + return this.form.get('first'); + } onSubmit(): void { console.log(this.form.value); // {first: 'Nancy', last: 'Drew'} } - setValue() { this.form.setValue({first: 'Carson', last: 'Drew'}); } + setValue() { + this.form.setValue({first: 'Carson', last: 'Drew'}); + } } diff --git a/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts b/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts index 6241b2e2b92c9..4791139f5009e 100644 --- a/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts +++ b/packages/examples/forms/ts/simpleNgModel/e2e_test/simple_ng_model_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; import {verifyNoBrowserErrors} from '../../../../test-utils'; @@ -42,5 +42,4 @@ describe('simpleNgModel example', () => { button.click(); expect(input.getAttribute('value')).toEqual('Nancy'); }); - }); diff --git a/packages/examples/forms/ts/simpleNgModel/simple_ng_model_example.ts b/packages/examples/forms/ts/simpleNgModel/simple_ng_model_example.ts index 3b0c068d54460..50775cec1672f 100644 --- a/packages/examples/forms/ts/simpleNgModel/simple_ng_model_example.ts +++ b/packages/examples/forms/ts/simpleNgModel/simple_ng_model_example.ts @@ -23,6 +23,8 @@ import {Component} from '@angular/core'; export class SimpleNgModelComp { name: string = ''; - setValue() { this.name = 'Nancy'; } + setValue() { + this.name = 'Nancy'; + } } // #enddocregion diff --git a/packages/examples/platform-browser/dom/debug/ts/by/by.ts b/packages/examples/platform-browser/dom/debug/ts/by/by.ts index 70283ebda742f..4bdffd8585ecf 100644 --- a/packages/examples/platform-browser/dom/debug/ts/by/by.ts +++ b/packages/examples/platform-browser/dom/debug/ts/by/by.ts @@ -9,7 +9,7 @@ import {DebugElement} from '@angular/core'; import {By} from '@angular/platform-browser'; -let debugElement: DebugElement = undefined !; +let debugElement: DebugElement = undefined!; class MyDirective {} // #docregion by_all diff --git a/packages/examples/test-utils/index.ts b/packages/examples/test-utils/index.ts index 4bf0dd2b5d03f..61d4c395083fb 100644 --- a/packages/examples/test-utils/index.ts +++ b/packages/examples/test-utils/index.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ /* tslint:disable:no-console */ -import {WebDriver, logging} from 'selenium-webdriver'; +import {logging, WebDriver} from 'selenium-webdriver'; declare var browser: WebDriver; declare var expect: any; diff --git a/packages/examples/testing/ts/testing.ts b/packages/examples/testing/ts/testing.ts index ac193163a224e..c859f842170f0 100644 --- a/packages/examples/testing/ts/testing.ts +++ b/packages/examples/testing/ts/testing.ts @@ -13,68 +13,88 @@ class MyMockService implements MyService {} // #docregion describeIt describe('some component', () => { - it('does something', () => { - // This is a test. - }); + it('does something', + () => { + // This is a test. + }); }); // #enddocregion // #docregion fdescribe /* tslint:disable-next-line:no-jasmine-focus */ fdescribe('some component', () => { - it('has a test', () => { - // This test will run. - }); + it('has a test', + () => { + // This test will run. + }); }); describe('another component', () => { - it('also has a test', () => { throw 'This test will not run.'; }); + it('also has a test', () => { + throw 'This test will not run.'; + }); }); // #enddocregion // #docregion xdescribe -xdescribe( - 'some component', () => { it('has a test', () => { throw 'This test will not run.'; }); }); +xdescribe('some component', () => { + it('has a test', () => { + throw 'This test will not run.'; + }); +}); describe('another component', () => { - it('also has a test', () => { - // This test will run. - }); + it('also has a test', + () => { + // This test will run. + }); }); // #enddocregion // #docregion fit describe('some component', () => { /* tslint:disable-next-line:no-jasmine-focus */ - fit('has a test', () => { - // This test will run. - }); - it('has another test', () => { throw 'This test will not run.'; }); + fit('has a test', + () => { + // This test will run. + }); + it('has another test', () => { + throw 'This test will not run.'; + }); }); // #enddocregion // #docregion xit describe('some component', () => { - xit('has a test', () => { throw 'This test will not run.'; }); - it('has another test', () => { - // This test will run. - }); + xit('has a test', () => { + throw 'This test will not run.'; + }); + it('has another test', + () => { + // This test will run. + }); }); // #enddocregion // #docregion beforeEach describe('some component', () => { - beforeEach(() => { db.connect(); }); - it('uses the db', () => { - // Database is connected. - }); + beforeEach(() => { + db.connect(); + }); + it('uses the db', + () => { + // Database is connected. + }); }); // #enddocregion // #docregion afterEach describe('some component', () => { - afterEach((done: Function) => { db.reset().then((_: any) => done()); }); - it('uses the db', () => { - // This test can leave the database in a dirty state. - // The afterEach will ensure it gets reset. - }); + afterEach((done: Function) => { + db.reset().then((_: any) => done()); + }); + it('uses the db', + () => { + // This test can leave the database in a dirty state. + // The afterEach will ensure it gets reset. + }); }); // #enddocregion diff --git a/packages/examples/upgrade/static/ts/full/module.spec.ts b/packages/examples/upgrade/static/ts/full/module.spec.ts index 1a51f76aa208e..2f6db0bdb9595 100644 --- a/packages/examples/upgrade/static/ts/full/module.spec.ts +++ b/packages/examples/upgrade/static/ts/full/module.spec.ts @@ -10,13 +10,12 @@ import {TestBed} from '@angular/core/testing'; import {createAngularJSTestingModule, createAngularTestingModule} from '@angular/upgrade/static/testing'; -import {HeroesService, Ng2AppModule, ng1AppModule} from './module'; +import {HeroesService, ng1AppModule, Ng2AppModule} from './module'; const {module, inject} = (window as any).angular.mock; // #enddocregion angular-setup describe('HeroesService (from Angular)', () => { - // #docregion angular-setup beforeEach(() => { TestBed.configureTestingModule( @@ -40,7 +39,8 @@ describe('HeroesService (from AngularJS)', () => { // #enddocregion angularjs-setup // #docregion angularjs-spec - it('should have access to the HeroesService', - inject((heroesService: HeroesService) => { expect(heroesService).toBeDefined(); })); + it('should have access to the HeroesService', inject((heroesService: HeroesService) => { + expect(heroesService).toBeDefined(); + })); // #enddocregion angularjs-spec }); diff --git a/packages/examples/upgrade/static/ts/full/module.ts b/packages/examples/upgrade/static/ts/full/module.ts index 2e908f0ed0940..8c84f4787a5b8 100644 --- a/packages/examples/upgrade/static/ts/full/module.ts +++ b/packages/examples/upgrade/static/ts/full/module.ts @@ -9,7 +9,7 @@ import {Component, Directive, ElementRef, EventEmitter, Injectable, Injector, Input, NgModule, Output} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {UpgradeComponent, UpgradeModule, downgradeComponent, downgradeInjectable} from '@angular/upgrade/static'; +import {downgradeComponent, downgradeInjectable, UpgradeComponent, UpgradeModule} from '@angular/upgrade/static'; declare var angular: ng.IAngularStatic; @@ -20,7 +20,9 @@ export interface Hero { // #docregion ng1-text-formatter-service export class TextFormatter { - titleCase(value: string) { return value.replace(/((^|\s)[a-z])/g, (_, c) => c.toUpperCase()); } + titleCase(value: string) { + return value.replace(/((^|\s)[a-z])/g, (_, c) => c.toUpperCase()); + } } // #enddocregion @@ -39,7 +41,7 @@ export class TextFormatter { <button (click)="addHero.emit()">Add Hero</button>`, }) export class Ng2HeroesComponent { - @Input() heroes !: Hero[]; + @Input() heroes!: Hero[]; @Output() addHero = new EventEmitter(); @Output() removeHero = new EventEmitter(); } @@ -67,7 +69,9 @@ export class HeroesService { this.heroes.concat([{name: 'Kamala Khan', description: 'Epic shape-shifting healer'}]); } - removeHero(hero: Hero) { this.heroes = this.heroes.filter((item: Hero) => item !== hero); } + removeHero(hero: Hero) { + this.heroes = this.heroes.filter((item: Hero) => item !== hero); + } } // #enddocregion @@ -77,8 +81,8 @@ export class HeroesService { export class Ng1HeroComponentWrapper extends UpgradeComponent { // The names of the input and output properties here must match the names of the // `<` and `&` bindings in the AngularJS component that is being wrapped - @Input() hero !: Hero; - @Output() onRemove !: EventEmitter<void>; + @Input() hero!: Hero; + @Output() onRemove!: EventEmitter<void>; constructor(elementRef: ElementRef, injector: Injector) { // We must pass the name of the directive as used by AngularJS to the super @@ -159,7 +163,10 @@ ng1AppModule.component('exampleApp', { // (We don't need the `HeroesService` type for AngularJS DI - it just helps with TypeScript // compilation) controller: [ - 'heroesService', function(heroesService: HeroesService) { this.heroesService = heroesService; } + 'heroesService', + function(heroesService: HeroesService) { + this.heroesService = heroesService; + } ], // This template makes use of the downgraded `ng2-heroes` component // Note that because its element is compiled by AngularJS we must use kebab-case attributes diff --git a/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts b/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts index 9a7c6e45d2b19..bb493e641a589 100644 --- a/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts +++ b/packages/examples/upgrade/static/ts/lite-multi-shared/e2e_test/static_lite_multi_shared_spec.ts @@ -24,6 +24,7 @@ describe('upgrade/static (lite with multiple downgraded modules and shared root expect(compB.getText()).toBe('Component B (Service ID: 2)'); }); - it('should use a different injectable instance on downgraded module C', - () => { expect(compC.getText()).toBe('Component C (Service ID: 1)'); }); + it('should use a different injectable instance on downgraded module C', () => { + expect(compC.getText()).toBe('Component C (Service ID: 1)'); + }); }); diff --git a/packages/examples/upgrade/static/ts/lite-multi-shared/module.ts b/packages/examples/upgrade/static/ts/lite-multi-shared/module.ts index 0024f14850a98..48ecc21156366 100644 --- a/packages/examples/upgrade/static/ts/lite-multi-shared/module.ts +++ b/packages/examples/upgrade/static/ts/lite-multi-shared/module.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Compiler, Component, Injectable, Injector, NgModule, StaticProvider, getPlatform} from '@angular/core'; +import {Compiler, Component, getPlatform, Injectable, Injector, NgModule, StaticProvider} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {downgradeComponent, downgradeModule} from '@angular/upgrade/static'; @@ -100,12 +100,12 @@ const getRootInjector = (extraProviders: StaticProvider[]) => { return rootInjectorPromise; }; -const downgradedNg2AModule = downgradeModule(async(extraProviders: StaticProvider[]) => { +const downgradedNg2AModule = downgradeModule(async (extraProviders: StaticProvider[]) => { const rootInjector = await getRootInjector(extraProviders); const moduleAFactory = await rootInjector.get(Compiler).compileModuleAsync(Ng2AModule); return moduleAFactory.create(rootInjector); }); -const downgradedNg2BModule = downgradeModule(async(extraProviders: StaticProvider[]) => { +const downgradedNg2BModule = downgradeModule(async (extraProviders: StaticProvider[]) => { const rootInjector = await getRootInjector(extraProviders); const moduleBFactory = await rootInjector.get(Compiler).compileModuleAsync(Ng2BModule); return moduleBFactory.create(rootInjector); diff --git a/packages/examples/upgrade/static/ts/lite-multi/module.ts b/packages/examples/upgrade/static/ts/lite-multi/module.ts index 9f7468bbcb86f..efe7bf38895db 100644 --- a/packages/examples/upgrade/static/ts/lite-multi/module.ts +++ b/packages/examples/upgrade/static/ts/lite-multi/module.ts @@ -7,10 +7,10 @@ */ // #docplaster -import {Component, Directive, ElementRef, Injectable, Injector, NgModule, StaticProvider, getPlatform} from '@angular/core'; +import {Component, Directive, ElementRef, getPlatform, Injectable, Injector, NgModule, StaticProvider} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {UpgradeComponent, downgradeComponent, downgradeInjectable, downgradeModule} from '@angular/upgrade/static'; +import {downgradeComponent, downgradeInjectable, downgradeModule, UpgradeComponent} from '@angular/upgrade/static'; declare var angular: ng.IAngularStatic; @@ -28,12 +28,16 @@ export class Ng2AComponent { selector: 'ng1A', }) export class Ng1AComponentFacade extends UpgradeComponent { - constructor(elementRef: ElementRef, injector: Injector) { super('ng1A', elementRef, injector); } + constructor(elementRef: ElementRef, injector: Injector) { + super('ng1A', elementRef, injector); + } } @Injectable() export class Ng2AService { - getValue() { return 'ng2'; } + getValue() { + return 'ng2'; + } } @NgModule({ @@ -91,13 +95,17 @@ const appModule = <ng2-b ng-switch-when="B"></ng2-b> </main> `, - controller: class ExampleAppController{page = 'A';}, + controller: class ExampleAppController { + page = 'A'; + }, }) .component('ng1A', { template: 'ng1({{ $ctrl.value }})', controller: [ - 'ng2AService', class Ng1AController{ - value = this.ng2AService.getValue(); constructor(private ng2AService: Ng2AService) {} + 'ng2AService', + class Ng1AController { + value = this.ng2AService.getValue(); + constructor(private ng2AService: Ng2AService) {} } ], }) diff --git a/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts b/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts index c429b50000240..778e7fd35d9ed 100644 --- a/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts +++ b/packages/examples/upgrade/static/ts/lite/e2e_test/e2e_util.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementFinder, by} from 'protractor'; +import {by, ElementFinder} from 'protractor'; declare global { namespace jasmine { - interface Matchers<T> { - toBeAHero(): Promise<void>; - toHaveName(exectedName: string): Promise<void>; - } + interface Matchers<T> { + toBeAHero(): Promise<void>; + toHaveName(exectedName: string): Promise<void>; + } } } @@ -22,43 +22,41 @@ const isTitleCased = (text: string) => export function addCustomMatchers() { jasmine.addMatchers({ - toBeAHero: - () => ({ - compare(actualNg1Hero: ElementFinder | undefined) { - const getText = (selector: string) => - actualNg1Hero !.element(by.css(selector)).getText(); - const result = { - message: 'Expected undefined to be an `ng1Hero` ElementFinder.', - pass: !!actualNg1Hero && - Promise.all(['.title', 'h2', 'p'].map(getText) as PromiseLike<string>[]) - .then(([actualTitle, actualName, actualDescription]) => { - const pass = (actualTitle === 'Super Hero') && isTitleCased(actualName) && - (actualDescription.length > 0); + toBeAHero: () => ({ + compare(actualNg1Hero: ElementFinder|undefined) { + const getText = (selector: string) => actualNg1Hero!.element(by.css(selector)).getText(); + const result = { + message: 'Expected undefined to be an `ng1Hero` ElementFinder.', + pass: !!actualNg1Hero && + Promise.all(['.title', 'h2', 'p'].map(getText) as PromiseLike<string>[]) + .then(([actualTitle, actualName, actualDescription]) => { + const pass = (actualTitle === 'Super Hero') && isTitleCased(actualName) && + (actualDescription.length > 0); - const actualHero = - `Hero(${actualTitle}, ${actualName}, ${actualDescription})`; - result.message = - `Expected ${actualHero}'${pass ? ' not' : ''} to be a real hero.`; + const actualHero = `Hero(${actualTitle}, ${actualName}, ${actualDescription})`; + result.message = + `Expected ${actualHero}'${pass ? ' not' : ''} to be a real hero.`; - return pass; - }) - }; - return result; - } - }), - toHaveName: () => ({ - compare(actualNg1Hero: ElementFinder | undefined, expectedName: string) { - const result = { - message: 'Expected undefined to be an `ng1Hero` ElementFinder.', - pass: !!actualNg1Hero && actualNg1Hero.element(by.css('h2')).getText().then(actualName => { + return pass; + }) + }; + return result; + } + }), + toHaveName: () => ({ + compare(actualNg1Hero: ElementFinder|undefined, expectedName: string) { + const result = { + message: 'Expected undefined to be an `ng1Hero` ElementFinder.', + pass: + !!actualNg1Hero && actualNg1Hero.element(by.css('h2')).getText().then(actualName => { const pass = actualName === expectedName; - result.message = - `Expected Hero(${actualName})${pass ? ' not' : ''} to have name '${expectedName}'.`; + result.message = `Expected Hero(${actualName})${pass ? ' not' : ''} to have name '${ + expectedName}'.`; return pass; }) - }; - return result; - } - }), + }; + return result; + } + }), } as any); } diff --git a/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts b/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts index 61bf67d64edee..cbf61a7506e04 100644 --- a/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts +++ b/packages/examples/upgrade/static/ts/lite/e2e_test/static_lite_spec.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor'; +import {browser, by, element, ElementArrayFinder, ElementFinder} from 'protractor'; + import {verifyNoBrowserErrors} from '../../../../../test-utils'; import {addCustomMatchers} from './e2e_util'; diff --git a/packages/examples/upgrade/static/ts/lite/module.ts b/packages/examples/upgrade/static/ts/lite/module.ts index 806c8022e8f96..a99d1350d1603 100644 --- a/packages/examples/upgrade/static/ts/lite/module.ts +++ b/packages/examples/upgrade/static/ts/lite/module.ts @@ -51,7 +51,9 @@ class HeroesService { return newHero; } - removeHero(hero: Hero) { this.heroes = this.heroes.filter((item: Hero) => item !== hero); } + removeHero(hero: Hero) { + this.heroes = this.heroes.filter((item: Hero) => item !== hero); + } } @@ -103,8 +105,8 @@ class Ng2HeroesComponent { class Ng1HeroComponentWrapper extends UpgradeComponent { // The names of the input and output properties here must match the names of the // `<` and `&` bindings in the AngularJS component that is being wrapped. - @Input() hero !: Hero; - @Output() onRemove !: EventEmitter<void>; + @Input() hero!: Hero; + @Output() onRemove!: EventEmitter<void>; constructor(elementRef: ElementRef, injector: Injector) { // We must pass the name of the directive as used by AngularJS to the super. diff --git a/packages/http/src/backends/browser_jsonp.ts b/packages/http/src/backends/browser_jsonp.ts index d5112c7a886f2..ab7f2082394ed 100644 --- a/packages/http/src/backends/browser_jsonp.ts +++ b/packages/http/src/backends/browser_jsonp.ts @@ -30,9 +30,13 @@ export class BrowserJsonp { return node; } - nextRequestID(): string { return `__req${_nextRequestId++}`; } + nextRequestID(): string { + return `__req${_nextRequestId++}`; + } - requestCallback(id: string): string { return `${JSONP_HOME}.${id}.finished`; } + requestCallback(id: string): string { + return `${JSONP_HOME}.${id}.finished`; + } exposeConnection(id: string, connection: any) { const connections = _getJsonpConnections(); @@ -45,7 +49,9 @@ export class BrowserJsonp { } // Attach the <script> element to the DOM - send(node: any) { document.body.appendChild(<Node>(node)); } + send(node: any) { + document.body.appendChild(<Node>(node)); + } // Remove <script> element from the DOM cleanup(node: any) { diff --git a/packages/http/src/backends/browser_xhr.ts b/packages/http/src/backends/browser_xhr.ts index d093413efa6dd..a71ee62d20d59 100644 --- a/packages/http/src/backends/browser_xhr.ts +++ b/packages/http/src/backends/browser_xhr.ts @@ -19,5 +19,7 @@ import {Injectable} from '@angular/core'; @Injectable() export class BrowserXhr { constructor() {} - build(): any { return <any>(new XMLHttpRequest()); } + build(): any { + return <any>(new XMLHttpRequest()); + } } diff --git a/packages/http/src/backends/jsonp_backend.ts b/packages/http/src/backends/jsonp_backend.ts index 00dcaa35e23af..beedfb1f8271a 100644 --- a/packages/http/src/backends/jsonp_backend.ts +++ b/packages/http/src/backends/jsonp_backend.ts @@ -28,9 +28,9 @@ const JSONP_ERR_WRONG_METHOD = 'JSONP requests must use GET request method.'; */ export class JSONPConnection implements Connection { // TODO(issue/24571): remove '!'. - private _id !: string; + private _id!: string; // TODO(issue/24571): remove '!'. - private _script !: Element; + private _script!: Element; private _responseData: any; private _finished: boolean = false; @@ -38,7 +38,7 @@ export class JSONPConnection implements Connection { * The {@link ReadyState} of this request. */ // TODO(issue/24571): remove '!'. - readyState !: ReadyState; + readyState!: ReadyState; /** * The outgoing HTTP request. @@ -58,7 +58,6 @@ export class JSONPConnection implements Connection { } this.request = req; this.response = new Observable<Response>((responseObserver: Observer<Response>) => { - this.readyState = ReadyState.Loading; const id = this._id = _dom.nextRequestID(); diff --git a/packages/http/src/backends/xhr_backend.ts b/packages/http/src/backends/xhr_backend.ts index 54256b2810248..7881d64f1aeaa 100644 --- a/packages/http/src/backends/xhr_backend.ts +++ b/packages/http/src/backends/xhr_backend.ts @@ -39,7 +39,7 @@ export class XHRConnection implements Connection { */ response: Observable<Response>; // TODO(issue/24571): remove '!'. - readyState !: ReadyState; + readyState!: ReadyState; constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions) { this.request = req; this.response = new Observable<Response>((responseObserver: Observer<Response>) => { @@ -116,7 +116,7 @@ export class XHRConnection implements Connection { if (!req.headers.has('Accept')) { req.headers.append('Accept', 'application/json, text/plain, */*'); } - req.headers.forEach((values, name) => _xhr.setRequestHeader(name !, values.join(','))); + req.headers.forEach((values, name) => _xhr.setRequestHeader(name!, values.join(','))); // Select the correct buffer type to store the response if (req.responseType != null && _xhr.responseType != null) { diff --git a/packages/http/src/base_request_options.ts b/packages/http/src/base_request_options.ts index beda7bba39fd9..d48b95d8a29c2 100644 --- a/packages/http/src/base_request_options.ts +++ b/packages/http/src/base_request_options.ts @@ -65,11 +65,15 @@ export class RequestOptions { /** * @deprecated from 4.0.0. Use params instead. */ - get search(): URLSearchParams { return this.params; } + get search(): URLSearchParams { + return this.params; + } /** * @deprecated from 4.0.0. Use params instead. */ - set search(params: URLSearchParams) { this.params = params; } + set search(params: URLSearchParams) { + this.params = params; + } /** * Enable use credentials for a {@link Request}. */ @@ -143,7 +147,7 @@ export class RequestOptions { return this._parseParams(params); } - private _parseParams(objParams: {[key: string]: any | any[]} = {}): URLSearchParams { + private _parseParams(objParams: {[key: string]: any|any[]} = {}): URLSearchParams { const params = new URLSearchParams(); Object.keys(objParams).forEach((key: string) => { const value: any|any[] = objParams[key]; @@ -206,5 +210,7 @@ export class RequestOptions { */ @Injectable() export class BaseRequestOptions extends RequestOptions { - constructor() { super({method: RequestMethod.Get, headers: new Headers()}); } + constructor() { + super({method: RequestMethod.Get, headers: new Headers()}); + } } diff --git a/packages/http/src/body.ts b/packages/http/src/body.ts index 18e4c7b7e4638..84fd52481746a 100644 --- a/packages/http/src/body.ts +++ b/packages/http/src/body.ts @@ -92,8 +92,8 @@ export abstract class Body { } /** - * Returns the request's body as a Blob, assuming that body exists. - */ + * Returns the request's body as a Blob, assuming that body exists. + */ blob(): Blob { if (this._body instanceof Blob) { return this._body; diff --git a/packages/http/src/headers.ts b/packages/http/src/headers.ts index ba2c4c2162cd2..7311a6e89ba3b 100644 --- a/packages/http/src/headers.ts +++ b/packages/http/src/headers.ts @@ -96,7 +96,7 @@ export class Headers { /** * Deletes all header values for the given name. */ - delete (name: string): void { + delete(name: string): void { const lcName = name.toLowerCase(); this._normalizedNames.delete(lcName); this._headers.delete(lcName); @@ -124,12 +124,16 @@ export class Headers { /** * Checks for existence of header by given name. */ - has(name: string): boolean { return this._headers.has(name.toLowerCase()); } + has(name: string): boolean { + return this._headers.has(name.toLowerCase()); + } /** * Returns the names of the headers */ - keys(): string[] { return Array.from(this._normalizedNames.values()); } + keys(): string[] { + return Array.from(this._normalizedNames.values()); + } /** * Sets or overrides header value for given name. @@ -148,7 +152,9 @@ export class Headers { /** * Returns values of all headers. */ - values(): string[][] { return Array.from(this._headers.values()); } + values(): string[][] { + return Array.from(this._headers.values()); + } /** * Returns string of all headers. @@ -160,7 +166,7 @@ export class Headers { this._headers.forEach((values: string[], name: string) => { const split: string[] = []; values.forEach(v => split.push(...v.split(','))); - serialized[this._normalizedNames.get(name) !] = split; + serialized[this._normalizedNames.get(name)!] = split; }); return serialized; @@ -176,7 +182,9 @@ export class Headers { /** * This method is not implemented. */ - entries() { throw new Error('"entries" method is not implemented on Headers class'); } + entries() { + throw new Error('"entries" method is not implemented on Headers class'); + } private mayBeSetNormalizedName(name: string): void { const lcName = name.toLowerCase(); diff --git a/packages/http/src/http.ts b/packages/http/src/http.ts index f46f472d3c974..9946162640789 100644 --- a/packages/http/src/http.ts +++ b/packages/http/src/http.ts @@ -20,7 +20,7 @@ function httpRequest(backend: ConnectionBackend, request: Request): Observable<R } function mergeOptions( - defaultOpts: BaseRequestOptions, providedOpts: RequestOptionsArgs | undefined, + defaultOpts: BaseRequestOptions, providedOpts: RequestOptionsArgs|undefined, method: RequestMethod, url: string): RequestArgs { const newOptions = defaultOpts; if (providedOpts) { @@ -156,7 +156,7 @@ export class Http { /** * Performs a request with `delete` http method. */ - delete (url: string, options?: RequestOptionsArgs): Observable<Response> { + delete(url: string, options?: RequestOptionsArgs): Observable<Response> { return this.request( new Request(mergeOptions(this._defaultOptions, options, RequestMethod.Delete, url))); } diff --git a/packages/http/src/http_utils.ts b/packages/http/src/http_utils.ts index 694d40eebd3b6..8c04c28aa994b 100644 --- a/packages/http/src/http_utils.ts +++ b/packages/http/src/http_utils.ts @@ -8,7 +8,7 @@ import {RequestMethod} from './enums'; -export function normalizeMethodName(method: string | RequestMethod): RequestMethod { +export function normalizeMethodName(method: string|RequestMethod): RequestMethod { if (typeof method !== 'string') return method; switch (method.toUpperCase()) { diff --git a/packages/http/src/interfaces.ts b/packages/http/src/interfaces.ts index 257544989532d..f1bc08c43b22c 100644 --- a/packages/http/src/interfaces.ts +++ b/packages/http/src/interfaces.ts @@ -20,7 +20,9 @@ import {URLSearchParams} from './url_search_params'; * @deprecated see https://angular.io/guide/http * @publicApi */ -export abstract class ConnectionBackend { abstract createConnection(request: any): Connection; } +export abstract class ConnectionBackend { + abstract createConnection(request: any): Connection; +} /** * Abstract class from which real connections are derived. @@ -30,9 +32,9 @@ export abstract class ConnectionBackend { abstract createConnection(request: any */ export abstract class Connection { // TODO(issue/24571): remove '!'. - readyState !: ReadyState; + readyState!: ReadyState; // TODO(issue/24571): remove '!'. - request !: Request; + request!: Request; response: any; // TODO: generic of <Response>; } @@ -42,7 +44,9 @@ export abstract class Connection { * @deprecated see https://angular.io/guide/http * @publicApi */ -export abstract class XSRFStrategy { abstract configureRequest(req: Request): void; } +export abstract class XSRFStrategy { + abstract configureRequest(req: Request): void; +} /** * Interface for options to construct a RequestOptions, based on @@ -66,7 +70,9 @@ export interface RequestOptionsArgs { /** * Required structure when constructing new Request(); */ -export interface RequestArgs extends RequestOptionsArgs { url: string|null; } +export interface RequestArgs extends RequestOptionsArgs { + url: string|null; +} /** * Interface for options to construct a Response, based on diff --git a/packages/http/src/static_request.ts b/packages/http/src/static_request.ts index c48cd252cb585..1e50c53a2d779 100644 --- a/packages/http/src/static_request.ts +++ b/packages/http/src/static_request.ts @@ -76,7 +76,7 @@ export class Request extends Body { super(); // TODO: assert that url is present const url = requestOptions.url; - this.url = requestOptions.url !; + this.url = requestOptions.url!; const paramsArg = requestOptions.params || requestOptions.search; if (paramsArg) { let params: string; @@ -95,13 +95,13 @@ export class Request extends Body { } } this._body = requestOptions.body; - this.method = normalizeMethodName(requestOptions.method !); + this.method = normalizeMethodName(requestOptions.method!); // TODO(jeffbcross): implement behavior // Defaults to 'omit', consistent with browser this.headers = new Headers(requestOptions.headers); this.contentType = this.detectContentType(); - this.withCredentials = requestOptions.withCredentials !; - this.responseType = requestOptions.responseType !; + this.withCredentials = requestOptions.withCredentials!; + this.responseType = requestOptions.responseType!; } /** diff --git a/packages/http/src/static_response.ts b/packages/http/src/static_response.ts index 66b760186df5e..71869a5eb3d23 100644 --- a/packages/http/src/static_response.ts +++ b/packages/http/src/static_response.ts @@ -73,14 +73,14 @@ export class Response extends Body { * the result of a progress event. */ // TODO(issue/24571): remove '!'. - bytesLoaded !: number; + bytesLoaded!: number; /** * Non-standard property * * Denotes how many bytes are expected in the final response body. */ // TODO(issue/24571): remove '!'. - totalBytes !: number; + totalBytes!: number; /** * Headers object based on the `Headers` class in the [Fetch * Spec](https://fetch.spec.whatwg.org/#headers-class). @@ -90,12 +90,12 @@ export class Response extends Body { constructor(responseOptions: ResponseOptions) { super(); this._body = responseOptions.body; - this.status = responseOptions.status !; + this.status = responseOptions.status!; this.ok = (this.status >= 200 && this.status <= 299); this.statusText = responseOptions.statusText; this.headers = responseOptions.headers; - this.type = responseOptions.type !; - this.url = responseOptions.url !; + this.type = responseOptions.type!; + this.url = responseOptions.url!; } toString(): string { diff --git a/packages/http/src/url_search_params.ts b/packages/http/src/url_search_params.ts index 6d8e8cd70af86..55ee366451ee3 100644 --- a/packages/http/src/url_search_params.ts +++ b/packages/http/src/url_search_params.ts @@ -26,9 +26,13 @@ function paramParser(rawParams: string = ''): Map<string, string[]> { * @publicApi **/ export class QueryEncoder { - encodeKey(key: string): string { return standardEncoding(key); } + encodeKey(key: string): string { + return standardEncoding(key); + } - encodeValue(value: string): string { return standardEncoding(value); } + encodeValue(value: string): string { + return standardEncoding(value); + } } function standardEncoding(v: string): string { @@ -93,7 +97,9 @@ export class URLSearchParams { return clone; } - has(param: string): boolean { return this.paramsMap.has(param); } + has(param: string): boolean { + return this.paramsMap.has(param); + } get(param: string): string|null { const storedParam = this.paramsMap.get(param); @@ -101,7 +107,9 @@ export class URLSearchParams { return Array.isArray(storedParam) ? storedParam[0] : null; } - getAll(param: string): string[] { return this.paramsMap.get(param) || []; } + getAll(param: string): string[] { + return this.paramsMap.get(param) || []; + } set(param: string, val: string) { if (val === void 0 || val === null) { @@ -182,5 +190,7 @@ export class URLSearchParams { return paramsList.join('&'); } - delete (param: string): void { this.paramsMap.delete(param); } + delete(param: string): void { + this.paramsMap.delete(param); + } } diff --git a/packages/http/test/backends/jsonp_backend_spec.ts b/packages/http/test/backends/jsonp_backend_spec.ts index 724cec7107d77..528cef5b4acb2 100644 --- a/packages/http/test/backends/jsonp_backend_spec.ts +++ b/packages/http/test/backends/jsonp_backend_spec.ts @@ -7,7 +7,7 @@ */ import {Injector} from '@angular/core'; -import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; +import {afterEach, AsyncTestCompleter, beforeEach, describe, inject, it, SpyObject} from '@angular/core/testing/src/testing_internal'; import {BrowserJsonp} from '@angular/http/src/backends/browser_jsonp'; import {JSONPBackend, JSONPConnection} from '@angular/http/src/backends/jsonp_backend'; import {BaseRequestOptions, RequestOptions} from '@angular/http/src/base_request_options'; @@ -21,12 +21,16 @@ let existingScripts: MockBrowserJsonp[] = []; class MockBrowserJsonp extends BrowserJsonp { // TODO(issue/24571): remove '!'. - src !: string; + src!: string; callbacks = new Map<string, (data: any) => any>(); - addEventListener(type: string, cb: (data: any) => any) { this.callbacks.set(type, cb); } + addEventListener(type: string, cb: (data: any) => any) { + this.callbacks.set(type, cb); + } - removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); } + removeEventListener(type: string, cb: Function) { + this.callbacks.delete(type); + } dispatchEvent(type: string, argument: any = {}) { const cb = this.callbacks.get(type); @@ -65,10 +69,12 @@ class MockBrowserJsonp extends BrowserJsonp { new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any); }); - afterEach(() => { existingScripts = []; }); + afterEach(() => { + existingScripts = []; + }); it('should create a connection', () => { - let instance: JSONPConnection = undefined !; + let instance: JSONPConnection = undefined!; expect(() => instance = backend.createConnection(sampleRequest)).not.toThrow(); expect(instance).toBeAnInstanceOf(JSONPConnection); }); @@ -141,8 +147,9 @@ class MockBrowserJsonp extends BrowserJsonp { RequestMethod.Head, RequestMethod.Patch] .forEach(method => { const base = new BaseRequestOptions(); - const req = new Request(base.merge( - new RequestOptions({url: 'https://google.com', method: method})) as any); + const req = new Request( + base.merge(new RequestOptions({url: 'https://google.com', method: method})) as + any); expect( () => new (JSONPConnection as any)(req, new MockBrowserJsonp()) .response.subscribe()) diff --git a/packages/http/test/backends/mock_backend_spec.ts b/packages/http/test/backends/mock_backend_spec.ts index ade1e47c674ee..97c5c5e11f510 100644 --- a/packages/http/test/backends/mock_backend_spec.ts +++ b/packages/http/test/backends/mock_backend_spec.ts @@ -18,7 +18,6 @@ import {ReplaySubject} from 'rxjs'; { describe('MockBackend', () => { - let backend: MockBackend; let sampleRequest1: Request; let sampleResponse1: Response; @@ -40,7 +39,9 @@ import {ReplaySubject} from 'rxjs'; sampleResponse2 = new Response(new ResponseOptions({body: 'response2'})); }); - it('should create a new MockBackend', () => { expect(backend).toBeAnInstanceOf(MockBackend); }); + it('should create a new MockBackend', () => { + expect(backend).toBeAnInstanceOf(MockBackend); + }); it('should create a new MockConnection', () => { expect(backend.createConnection(sampleRequest1)).toBeAnInstanceOf(MockConnection); @@ -54,7 +55,9 @@ import {ReplaySubject} from 'rxjs'; it('should allow responding after subscription', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const connection: MockConnection = backend.createConnection(sampleRequest1); - connection.response.subscribe(() => { async.done(); }); + connection.response.subscribe(() => { + async.done(); + }); connection.mockRespond(sampleResponse1); })); @@ -62,20 +65,26 @@ import {ReplaySubject} from 'rxjs'; inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const connection: MockConnection = backend.createConnection(sampleRequest1); connection.mockRespond(sampleResponse1); - connection.response.subscribe(() => { async.done(); }); + connection.response.subscribe(() => { + async.done(); + }); })); it('should allow responding after subscription with an error', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const connection: MockConnection = backend.createConnection(sampleRequest1); - connection.response.subscribe(null !, () => { async.done(); }); + connection.response.subscribe(null!, () => { + async.done(); + }); connection.mockError(new Error('nope')); })); it('should not throw when there are no unresolved requests', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const connection: MockConnection = backend.createConnection(sampleRequest1); - connection.response.subscribe(() => { async.done(); }); + connection.response.subscribe(() => { + async.done(); + }); connection.mockRespond(sampleResponse1); backend.verifyNoPendingRequests(); })); @@ -83,7 +92,9 @@ import {ReplaySubject} from 'rxjs'; xit('should throw when there are unresolved requests', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const connection: MockConnection = backend.createConnection(sampleRequest1); - connection.response.subscribe(() => { async.done(); }); + connection.response.subscribe(() => { + async.done(); + }); backend.verifyNoPendingRequests(); })); @@ -91,7 +102,9 @@ import {ReplaySubject} from 'rxjs'; inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const connection1: MockConnection = backend.createConnection(sampleRequest1); const connection2: MockConnection = backend.createConnection(sampleRequest1); - connection1.response.subscribe(() => { async.done(); }); + connection1.response.subscribe(() => { + async.done(); + }); connection2.response.subscribe(() => {}); connection2.mockRespond(sampleResponse1); connection1.mockRespond(sampleResponse1); @@ -101,12 +114,12 @@ import {ReplaySubject} from 'rxjs'; xit('should allow double subscribing', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const responses: Response[] = [sampleResponse1, sampleResponse2]; - backend.connections.subscribe((c: MockConnection) => c.mockRespond(responses.shift() !)); + backend.connections.subscribe((c: MockConnection) => c.mockRespond(responses.shift()!)); const responseObservable: ReplaySubject<Response> = backend.createConnection(sampleRequest1).response; responseObservable.subscribe(res => expect(res.text()).toBe('response1')); responseObservable.subscribe( - res => expect(res.text()).toBe('response2'), null !, async.done); + res => expect(res.text()).toBe('response2'), null!, async.done); })); // TODO(robwormald): readyStates are leaving? diff --git a/packages/http/test/backends/xhr_backend_spec.ts b/packages/http/test/backends/xhr_backend_spec.ts index 3fb285f204687..ace4085f1e43b 100644 --- a/packages/http/test/backends/xhr_backend_spec.ts +++ b/packages/http/test/backends/xhr_backend_spec.ts @@ -8,7 +8,7 @@ import {ɵgetDOM as getDOM} from '@angular/common'; import {Injectable} from '@angular/core'; -import {AsyncTestCompleter, SpyObject, afterEach, beforeEach, beforeEachProviders, describe, expect, inject, it} from '@angular/core/testing/src/testing_internal'; +import {afterEach, AsyncTestCompleter, beforeEach, beforeEachProviders, describe, expect, inject, it, SpyObject} from '@angular/core/testing/src/testing_internal'; import {BrowserXhr} from '@angular/http/src/backends/browser_xhr'; import {CookieXSRFStrategy, XHRBackend, XHRConnection} from '@angular/http/src/backends/xhr_backend'; import {BaseRequestOptions, RequestOptions} from '@angular/http/src/base_request_options'; @@ -34,19 +34,19 @@ class MockBrowserXHR extends BrowserXhr { response: any; responseType: string; // TODO(issue/24571): remove '!'. - responseText !: string; + responseText!: string; setRequestHeader: any; callbacks = new Map<string, Function>(); // TODO(issue/24571): remove '!'. - status !: number; + status!: number; // TODO(issue/24571): remove '!'. - responseHeaders !: string; + responseHeaders!: string; // TODO(issue/24571): remove '!'. - responseURL !: string; + responseURL!: string; // TODO(issue/24571): remove '!'. - statusText !: string; + statusText!: string; // TODO(issue/24571): remove '!'. - withCredentials !: boolean; + withCredentials!: boolean; constructor() { super(); @@ -60,29 +60,49 @@ class MockBrowserXHR extends BrowserXhr { this.responseType = ''; } - setStatusCode(status: number) { this.status = status; } + setStatusCode(status: number) { + this.status = status; + } - setStatusText(statusText: string) { this.statusText = statusText; } + setStatusText(statusText: string) { + this.statusText = statusText; + } - setResponse(value: string) { this.response = value; } + setResponse(value: string) { + this.response = value; + } - setResponseText(value: string) { this.responseText = value; } + setResponseText(value: string) { + this.responseText = value; + } - setResponseURL(value: string) { this.responseURL = value; } + setResponseURL(value: string) { + this.responseURL = value; + } - setResponseHeaders(value: string) { this.responseHeaders = value; } + setResponseHeaders(value: string) { + this.responseHeaders = value; + } - getAllResponseHeaders() { return this.responseHeaders || ''; } + getAllResponseHeaders() { + return this.responseHeaders || ''; + } getResponseHeader(key: string) { return Headers.fromResponseHeaderString(this.responseHeaders).get(key); } - addEventListener(type: string, cb: Function) { this.callbacks.set(type, cb); } + addEventListener(type: string, cb: Function) { + this.callbacks.set(type, cb); + } - removeEventListener(type: string, cb: Function) { this.callbacks.delete(type); } + removeEventListener(type: string, cb: Function) { + this.callbacks.delete(type); + } - dispatchEvent(type: string) { this.callbacks.get(type) !({}); } + dispatchEvent(type: string) { + this.callbacks.get(type)!({}); + } build() { const xhr = new MockBrowserXHR(); @@ -99,7 +119,8 @@ class MockBrowserXHR extends BrowserXhr { beforeEachProviders( () => [{provide: ResponseOptions, useClass: BaseResponseOptions}, - {provide: BrowserXhr, useClass: MockBrowserXHR}, XHRBackend, + {provide: BrowserXhr, useClass: MockBrowserXHR}, + XHRBackend, {provide: XSRFStrategy, useValue: new CookieXSRFStrategy()}, ]); @@ -110,7 +131,9 @@ class MockBrowserXHR extends BrowserXhr { new Request(base.merge(new RequestOptions({url: 'https://google.com'})) as any); })); - afterEach(() => { existingXHRs = []; }); + afterEach(() => { + existingXHRs = []; + }); describe('creating a connection', () => { @Injectable() @@ -119,8 +142,9 @@ class MockBrowserXHR extends BrowserXhr { } beforeEachProviders(() => [{provide: XSRFStrategy, useClass: NoopXsrfStrategy}]); - it('succeeds', - () => { expect(() => backend.createConnection(sampleRequest)).not.toThrow(); }); + it('succeeds', () => { + expect(() => backend.createConnection(sampleRequest)).not.toThrow(); + }); }); if (getDOM().supportsCookies()) { @@ -171,8 +195,13 @@ class MockBrowserXHR extends BrowserXhr { sampleRequest, new MockBrowserXHR(), new ResponseOptions({type: ResponseType.Error})); connection.response.subscribe( - (res: Response) => { expect(res.type).toBe(ResponseType.Error); }, null !, - () => { async.done(); }); + (res: Response) => { + expect(res.type).toBe(ResponseType.Error); + }, + null!, + () => { + async.done(); + }); existingXHRs[0].setStatusCode(200); existingXHRs[0].dispatchEvent('load'); })); @@ -189,7 +218,7 @@ class MockBrowserXHR extends BrowserXhr { const connection = new XHRConnection( sampleRequest, new MockBrowserXHR(), new ResponseOptions({type: ResponseType.Error})); - connection.response.subscribe(null !, (res: Response) => { + connection.response.subscribe(null!, (res: Response) => { expect(res.type).toBe(ResponseType.Error); async.done(); }); @@ -201,7 +230,7 @@ class MockBrowserXHR extends BrowserXhr { const connection = new XHRConnection( sampleRequest, new MockBrowserXHR(), new ResponseOptions({type: ResponseType.Error})); - connection.response.subscribe(null !, (res: Response) => { + connection.response.subscribe(null!, (res: Response) => { expect(res.type).toBe(ResponseType.Error); expect(res.status).toEqual(0); expect(res.statusText).toEqual(''); @@ -365,7 +394,7 @@ class MockBrowserXHR extends BrowserXhr { }); it('should use blob body without type to the request', () => { - const body = createBlob(['body { color: red; }'], null !); + const body = createBlob(['body { color: red; }'], null!); const base = new BaseRequestOptions(); const connection = new XHRConnection( new Request(base.merge(new RequestOptions({body: body}))), new MockBrowserXHR()); @@ -377,7 +406,7 @@ class MockBrowserXHR extends BrowserXhr { it('should use blob body without type with custom content type header to the request', () => { const headers = new Headers({'Content-Type': 'text/css'}); - const body = createBlob(['body { color: red; }'], null !); + const body = createBlob(['body { color: red; }'], null!); const base = new BaseRequestOptions(); const connection = new XHRConnection( new Request(base.merge(new RequestOptions({body: body, headers: headers}))), @@ -451,7 +480,9 @@ class MockBrowserXHR extends BrowserXhr { nextCalled = true; expect(res.status).toBe(statusCode); }, - (errRes: Response) => { errorCalled = true; }, + (errRes: Response) => { + errorCalled = true; + }, () => { expect(nextCalled).toBe(true); expect(errorCalled).toBe(false); @@ -484,7 +515,9 @@ class MockBrowserXHR extends BrowserXhr { sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode})); connection.response.subscribe( - (res: Response) => { throw 'should not be called'; }, + (res: Response) => { + throw 'should not be called'; + }, (errRes: Response) => { expect(errRes.ok).toBe(false); async.done(); @@ -503,13 +536,17 @@ class MockBrowserXHR extends BrowserXhr { sampleRequest, new MockBrowserXHR(), new ResponseOptions({status: statusCode})); connection.response.subscribe( - (res: Response) => { nextCalled = true; }, + (res: Response) => { + nextCalled = true; + }, (errRes: Response) => { expect(errRes.status).toBe(statusCode); expect(nextCalled).toBe(false); async.done(); }, - () => { throw 'should not be called'; }); + () => { + throw 'should not be called'; + }); existingXHRs[0].setStatusCode(statusCode); existingXHRs[0].dispatchEvent('load'); @@ -601,7 +638,7 @@ class MockBrowserXHR extends BrowserXhr { inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { const conn = new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions()); - conn.response.subscribe(null !, (res: Response) => { + conn.response.subscribe(null!, (res: Response) => { expect(res.text()).toBe('{json: "object"}'); async.done(); }); @@ -622,10 +659,10 @@ Transfer-Encoding: chunked Connection: keep-alive`; connection.response.subscribe((res: Response) => { - expect(res.headers !.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT'); - expect(res.headers !.get('Content-Type')).toEqual('application/json; charset=utf-8'); - expect(res.headers !.get('Transfer-Encoding')).toEqual('chunked'); - expect(res.headers !.get('Connection')).toEqual('keep-alive'); + expect(res.headers!.get('Date')).toEqual('Fri, 20 Nov 2015 01:45:26 GMT'); + expect(res.headers!.get('Content-Type')).toEqual('application/json; charset=utf-8'); + expect(res.headers!.get('Transfer-Encoding')).toEqual('chunked'); + expect(res.headers!.get('Connection')).toEqual('keep-alive'); async.done(); }); diff --git a/packages/http/test/headers_spec.ts b/packages/http/test/headers_spec.ts index f5684ceeb913c..f0d61ebff5823 100644 --- a/packages/http/test/headers_spec.ts +++ b/packages/http/test/headers_spec.ts @@ -10,7 +10,6 @@ import {Headers} from '@angular/http/src/headers'; { describe('Headers', () => { - describe('initialization', () => { it('should conform to spec', () => { const httpHeaders = { @@ -165,8 +164,9 @@ import {Headers} from '@angular/http/src/headers'; ref = {'Accept': values}; }); - it('should be serializable with toJSON', - () => { expect(JSON.stringify(headers)).toEqual(JSON.stringify(ref)); }); + it('should be serializable with toJSON', () => { + expect(JSON.stringify(headers)).toEqual(JSON.stringify(ref)); + }); it('should be able to recreate serializedHeaders', () => { const parsedHeaders = JSON.parse(JSON.stringify(headers)); diff --git a/packages/http/test/http_spec.ts b/packages/http/test/http_spec.ts index 24f95fb531ec2..459e2fbcf3a8b 100644 --- a/packages/http/test/http_spec.ts +++ b/packages/http/test/http_spec.ts @@ -7,14 +7,14 @@ */ import {Injector} from '@angular/core'; -import {TestBed, getTestBed} from '@angular/core/testing'; -import {AsyncTestCompleter, afterEach, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; +import {getTestBed, TestBed} from '@angular/core/testing'; +import {afterEach, AsyncTestCompleter, beforeEach, describe, inject, it} from '@angular/core/testing/src/testing_internal'; import {stringToArrayBuffer} from '@angular/http/src/http_utils'; import {MockBackend, MockConnection} from '@angular/http/testing/src/mock_backend'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {Observable, zip} from 'rxjs'; -import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, JSONPBackend, Jsonp, JsonpModule, Request, RequestMethod, RequestOptions, Response, ResponseContentType, ResponseOptions, URLSearchParams, XHRBackend} from '../index'; +import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, Jsonp, JSONPBackend, JsonpModule, Request, RequestMethod, RequestOptions, Response, ResponseContentType, ResponseOptions, URLSearchParams, XHRBackend} from '../index'; { describe('injectables', () => { @@ -38,7 +38,6 @@ import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, JSONPBackend, J it('should allow using jsonpInjectables and httpInjectables in same injector', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - http = injector.get(Http); jsonp = injector.get(Jsonp); jsonpBackend = injector.get(JSONPBackend) as any as MockBackend; @@ -105,8 +104,9 @@ import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, JSONPBackend, J describe('Http', () => { describe('.request()', () => { - it('should return an Observable', - () => { expect(http.request(url)).toBeAnInstanceOf(Observable); }); + it('should return an Observable', () => { + expect(http.request(url)).toBeAnInstanceOf(Observable); + }); it('should accept a fully-qualified request as its only parameter', @@ -174,8 +174,13 @@ import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, JSONPBackend, J backend.connections.subscribe((c: MockConnection) => c.mockRespond(baseResponse)); http.request('http://basic.connection') .subscribe( - (res: Response) => { expect(res.text()).toBe('base response'); }, null !, - () => { async.done(); }); + (res: Response) => { + expect(res.text()).toBe('base response'); + }, + null!, + () => { + async.done(); + }); })); it('should perform multiple get requests and complete the responses', @@ -187,8 +192,13 @@ import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, JSONPBackend, J }); http.request('http://basic.connection') .subscribe( - (res: Response) => { expect(res.text()).toBe('base response'); }, null !, - () => { async.done(); }); + (res: Response) => { + expect(res.text()).toBe('base response'); + }, + null!, + () => { + async.done(); + }); })); it('should throw if url is not a string or Request', () => { @@ -422,7 +432,6 @@ import {BaseRequestOptions, ConnectionBackend, Http, HttpModule, JSONPBackend, J }); describe('response buffer', () => { - it('should attach the provided buffer to the response', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { backend.connections.subscribe((c: MockConnection) => { diff --git a/packages/http/test/static_request_spec.ts b/packages/http/test/static_request_spec.ts index 570ef334ccfa1..816816611691d 100644 --- a/packages/http/test/static_request_spec.ts +++ b/packages/http/test/static_request_spec.ts @@ -27,66 +27,67 @@ import {supportsWebAnimation} from '@angular/platform-browser/testing/src/browse it('should return ContentType.JSON', () => { const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: null, - headers: new Headers({'content-type': 'application/json'}) - }) as any); + url: 'test', + method: 'GET', + body: null, + headers: new Headers({'content-type': 'application/json'}) + }) as any); expect(req.detectContentType()).toEqual(ContentType.JSON); }); it('should return ContentType.FORM', () => { - const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: null, - headers: new Headers({'content-type': 'application/x-www-form-urlencoded'}) - }) as any); + const req = new Request( + new RequestOptions({ + url: 'test', + method: 'GET', + body: null, + headers: new Headers({'content-type': 'application/x-www-form-urlencoded'}) + }) as any); expect(req.detectContentType()).toEqual(ContentType.FORM); }); it('should return ContentType.FORM_DATA', () => { const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: null, - headers: new Headers({'content-type': 'multipart/form-data'}) - }) as any); + url: 'test', + method: 'GET', + body: null, + headers: new Headers({'content-type': 'multipart/form-data'}) + }) as any); expect(req.detectContentType()).toEqual(ContentType.FORM_DATA); }); it('should return ContentType.TEXT', () => { const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: null, - headers: new Headers({'content-type': 'text/plain'}) - }) as any); + url: 'test', + method: 'GET', + body: null, + headers: new Headers({'content-type': 'text/plain'}) + }) as any); expect(req.detectContentType()).toEqual(ContentType.TEXT); }); it('should return ContentType.BLOB', () => { const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: null, - headers: new Headers({'content-type': 'application/octet-stream'}) - }) as any); + url: 'test', + method: 'GET', + body: null, + headers: new Headers({'content-type': 'application/octet-stream'}) + }) as any); expect(req.detectContentType()).toEqual(ContentType.BLOB); }); it('should not create a blob out of ArrayBuffer', () => { const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: new ArrayBuffer(1), - headers: new Headers({'content-type': 'application/octet-stream'}) - }) as any); + url: 'test', + method: 'GET', + body: new ArrayBuffer(1), + headers: new Headers({'content-type': 'application/octet-stream'}) + }) as any); expect(req.detectContentType()).toEqual(ContentType.ARRAY_BUFFER); }); @@ -94,11 +95,11 @@ import {supportsWebAnimation} from '@angular/platform-browser/testing/src/browse it('should return empty string if no body is present', () => { const req = new Request(new RequestOptions({ - url: 'test', - method: 'GET', - body: null, - headers: new Headers({'content-type': 'application/json'}) - }) as any); + url: 'test', + method: 'GET', + body: null, + headers: new Headers({'content-type': 'application/json'}) + }) as any); expect(req.text()).toEqual(''); }); diff --git a/packages/http/test/url_search_params_spec.ts b/packages/http/test/url_search_params_spec.ts index 8144ce95ae9a0..5d1fcfb9f5a62 100644 --- a/packages/http/test/url_search_params_spec.ts +++ b/packages/http/test/url_search_params_spec.ts @@ -36,8 +36,12 @@ import {URLSearchParams} from '@angular/http/src/url_search_params'; it('should optionally accept a custom parser', () => { const fooEveryThingParser = { - encodeKey() { return 'I AM KEY'; }, - encodeValue() { return 'I AM VALUE'; } + encodeKey() { + return 'I AM KEY'; + }, + encodeValue() { + return 'I AM VALUE'; + } }; const params = new URLSearchParams('', fooEveryThingParser); params.set('myKey', 'myValue'); @@ -68,8 +72,9 @@ import {URLSearchParams} from '@angular/http/src/url_search_params'; **/ let params = new URLSearchParams(); - '! $ \' ( ) * + , ; A 9 - . _ ~ ? / ='.split(' ').forEach( - (char, idx) => { params.set(`a${idx}`, char); }); + '! $ \' ( ) * + , ; A 9 - . _ ~ ? / ='.split(' ').forEach((char, idx) => { + params.set(`a${idx}`, char); + }); expect(params.toString()) .toBe( `a0=!&a1=$&a2=\'&a3=(&a4=)&a5=*&a6=+&a7=,&a8=;&a9=A&a10=9&a11=-&a12=.&a13=_&a14=~&a15=?&a16=/&a17==` @@ -130,8 +135,12 @@ import {URLSearchParams} from '@angular/http/src/url_search_params'; it('should support a clone operation via clone()', () => { const fooQueryEncoder = { - encodeKey(k: string) { return encodeURIComponent(k); }, - encodeValue(v: string) { return encodeURIComponent(v); } + encodeKey(k: string) { + return encodeURIComponent(k); + }, + encodeValue(v: string) { + return encodeURIComponent(v); + } }; const paramsA = new URLSearchParams('', fooQueryEncoder); paramsA.set('a', '2'); @@ -151,21 +160,20 @@ import {URLSearchParams} from '@angular/http/src/url_search_params'; it('should remove the parameter when set to undefined or null', () => { const params = new URLSearchParams('q=Q'); - params.set('q', undefined !); + params.set('q', undefined!); expect(params.has('q')).toBe(false); expect(params.toString()).toEqual(''); - params.set('q', null !); + params.set('q', null!); expect(params.has('q')).toBe(false); expect(params.toString()).toEqual(''); }); it('should ignore the value when append undefined or null', () => { const params = new URLSearchParams('q=Q'); - params.append('q', undefined !); + params.append('q', undefined!); expect(params.toString()).toEqual('q=Q'); - params.append('q', null !); + params.append('q', null!); expect(params.toString()).toEqual('q=Q'); }); - }); } diff --git a/packages/http/testing/src/mock_backend.ts b/packages/http/testing/src/mock_backend.ts index 5c8a5aeb8838b..64be8e2893a27 100644 --- a/packages/http/testing/src/mock_backend.ts +++ b/packages/http/testing/src/mock_backend.ts @@ -245,7 +245,9 @@ export class MockBackend implements ConnectionBackend { * * This method only exists in the mock implementation, not in real Backends. */ - resolveAllConnections() { this.connections.subscribe((c: MockConnection) => c.readyState = 4); } + resolveAllConnections() { + this.connections.subscribe((c: MockConnection) => c.readyState = 4); + } /** * Creates a new {@link MockConnection}. This is equivalent to calling `new diff --git a/packages/localize/init/index.ts b/packages/localize/init/index.ts index 536786ba0f74e..6361e0371ef40 100644 --- a/packages/localize/init/index.ts +++ b/packages/localize/init/index.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {$localize, LocalizeFn, _global} from '../src/localize'; +import {$localize, _global, LocalizeFn} from '../src/localize'; export {LocalizeFn, TranslateFn} from '../src/localize'; diff --git a/packages/localize/private.ts b/packages/localize/private.ts index 902c2af0a48b4..824a2e69d1279 100644 --- a/packages/localize/private.ts +++ b/packages/localize/private.ts @@ -8,4 +8,4 @@ // This file exports all the `utils` as private exports so that other parts of `@angular/localize` // can make use of them. -export {MessageId as ɵMessageId, MissingTranslationError as ɵMissingTranslationError, ParsedMessage as ɵParsedMessage, ParsedTranslation as ɵParsedTranslation, ParsedTranslations as ɵParsedTranslations, SourceMessage as ɵSourceMessage, TargetMessage as ɵTargetMessage, computeMsgId as ɵcomputeMsgId, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, splitBlock as ɵsplitBlock, translate as ɵtranslate} from './src/utils'; +export {computeMsgId as ɵcomputeMsgId, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, MessageId as ɵMessageId, MissingTranslationError as ɵMissingTranslationError, ParsedMessage as ɵParsedMessage, ParsedTranslation as ɵParsedTranslation, ParsedTranslations as ɵParsedTranslations, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, SourceMessage as ɵSourceMessage, splitBlock as ɵsplitBlock, TargetMessage as ɵTargetMessage, translate as ɵtranslate} from './src/utils'; diff --git a/packages/localize/schematics/ng-add/index.ts b/packages/localize/schematics/ng-add/index.ts index 903d3eddca066..94ec56b5a018a 100644 --- a/packages/localize/schematics/ng-add/index.ts +++ b/packages/localize/schematics/ng-add/index.ts @@ -9,7 +9,7 @@ */ import {virtualFs} from '@angular-devkit/core'; -import {Rule, Tree, chain} from '@angular-devkit/schematics'; +import {chain, Rule, Tree} from '@angular-devkit/schematics'; import {getWorkspace} from '@schematics/angular/utility/config'; import {getProjectTargets} from '@schematics/angular/utility/project-targets'; import {validateProjectName} from '@schematics/angular/utility/validation'; @@ -25,13 +25,12 @@ function getAllOptionValues<T>( const targets = getProjectTargets(host, projectName); // Find all targets of a specific build in a project. - const builderTargets: (BrowserBuilderTarget | ServeBuilderTarget)[] = - Object.values(targets).filter( - (target: BrowserBuilderTarget | ServeBuilderTarget) => target.builder === builderName); + const builderTargets: (BrowserBuilderTarget|ServeBuilderTarget)[] = Object.values(targets).filter( + (target: BrowserBuilderTarget|ServeBuilderTarget) => target.builder === builderName); // Get all options contained in target configuration partials. const configurationOptions = builderTargets.filter(t => t.configurations) - .map(t => Object.values(t.configurations !)) + .map(t => Object.values(t.configurations!)) .reduce((acc, cur) => acc.concat(...cur), []); // Now we have all option sets. We can use it to find all references to a given property. diff --git a/packages/localize/schematics/ng-add/index_spec.ts b/packages/localize/schematics/ng-add/index_spec.ts index 68588f8f4ef63..9d4cb6fedfd7d 100644 --- a/packages/localize/schematics/ng-add/index_spec.ts +++ b/packages/localize/schematics/ng-add/index_spec.ts @@ -13,7 +13,6 @@ import {localizePolyfill} from './index'; describe('ng-add schematic', () => { - const countInstances = (str: string, substr: string) => str.split(substr).length - 1; const defaultOptions = {name: 'demo'}; let host: UnitTestTree; @@ -112,25 +111,25 @@ export { renderModule, renderModuleFactory } from '@angular/platform-server';`; new SchematicTestRunner('@angular/localize', require.resolve('../collection.json')); }); - it('should add localize polyfill to polyfill files', async() => { + it('should add localize polyfill to polyfill files', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); expect(host.readContent('/src/polyfills.ts')).toContain(localizePolyfill); expect(host.readContent('/src/another-polyfills.ts')).toContain(localizePolyfill); }); - it('should add localize polyfill to server main files', async() => { + it('should add localize polyfill to server main files', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); expect(host.readContent('/src/main.server.ts')).toContain(localizePolyfill); expect(host.readContent('/src/another-main.server.ts')).toContain(localizePolyfill); }); - it('should add localize polyfill at the start of file', async() => { + it('should add localize polyfill at the start of file', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const content = host.readContent('/src/polyfills.ts'); expect(content.indexOf(localizePolyfill)).toBeLessThan(content.indexOf(polyfillsContent)); }); - it('should not add localize polyfill to files referenced in other targets files', async() => { + it('should not add localize polyfill to files referenced in other targets files', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); expect(host.readContent('/src/unrelated-polyfills.ts')).not.toContain(localizePolyfill); expect(host.readContent('/src/another-unrelated-polyfills.ts')).not.toContain(localizePolyfill); @@ -139,13 +138,13 @@ export { renderModule, renderModuleFactory } from '@angular/platform-server';`; .not.toContain(localizePolyfill); }); - it('should only add localize polyfill once if multiple builds reference it', async() => { + it('should only add localize polyfill once if multiple builds reference it', async () => { host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise(); const content = host.readContent('/src/polyfills.ts'); expect(countInstances(content, localizePolyfill)).toBe(1); }); - it('should not add localize polyfill if it\'s already there', async() => { + it('should not add localize polyfill if it\'s already there', async () => { const polyfillVariation = localizePolyfill.replace(/'/g, '"'); host.overwrite('/src/polyfills.ts', `${localizePolyfill}\n${polyfillsContent}`); host.overwrite('/src/another-polyfills.ts', `${polyfillVariation}\n${polyfillsContent}`); @@ -154,7 +153,7 @@ export { renderModule, renderModuleFactory } from '@angular/platform-server';`; expect(countInstances(host.readContent('/src/another-polyfills.ts'), localizePolyfill)).toBe(0); }); - it('should not break when there are no polyfills', async() => { + it('should not break when there are no polyfills', async () => { host.overwrite('angular.json', JSON.stringify({ projects: { 'demo': { diff --git a/packages/localize/src/localize/test/localize_spec.ts b/packages/localize/src/localize/test/localize_spec.ts index 53c2d039beabe..6fdf9f5a16f88 100644 --- a/packages/localize/src/localize/test/localize_spec.ts +++ b/packages/localize/src/localize/test/localize_spec.ts @@ -11,77 +11,87 @@ describe('$localize tag', () => { describe('with no `translate()` defined (the default)', () => { it('should render template literals as-is', () => { expect($localize.translate).toBeUndefined(); - expect($localize `abc`).toEqual('abc'); - expect($localize `abc${1 + 2 + 3}`).toEqual('abc6'); - expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def'); - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15'); + expect($localize`abc`).toEqual('abc'); + expect($localize`abc${1 + 2 + 3}`).toEqual('abc6'); + expect($localize`abc${1 + 2 + 3}def`).toEqual('abc6def'); + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15'); const getName = () => 'World'; - expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!'); + expect($localize`Hello, ${getName()}!`).toEqual('Hello, World!'); }); it('should strip metadata block from message parts', () => { expect($localize.translate).toBeUndefined(); - expect($localize `:meaning|description@@custom-id:abcdef`).toEqual('abcdef'); + expect($localize`:meaning|description@@custom-id:abcdef`).toEqual('abcdef'); }); it('should ignore escaped metadata block marker', () => { expect($localize.translate).toBeUndefined(); - expect($localize `\:abc:def`).toEqual(':abc:def'); + expect($localize`\:abc:def`).toEqual(':abc:def'); }); it('should strip metadata block containing escaped block markers', () => { expect($localize.translate).toBeUndefined(); - expect($localize `:abc\:def:content`).toEqual('content'); + expect($localize`:abc\:def:content`).toEqual('content'); }); it('should strip placeholder names from message parts', () => { expect($localize.translate).toBeUndefined(); - expect($localize `abc${1 + 2 + 3}:ph1:def${4 + 5 + 6}:ph2:`).toEqual('abc6def15'); + expect($localize`abc${1 + 2 + 3}:ph1:def${4 + 5 + 6}:ph2:`).toEqual('abc6def15'); }); it('should ignore escaped placeholder name marker', () => { expect($localize.translate).toBeUndefined(); - expect($localize `abc${1 + 2 + 3}\:ph1:def${4 + 5 + 6}\:ph2:`).toEqual('abc6:ph1:def15:ph2:'); + expect($localize`abc${1 + 2 + 3}\:ph1:def${4 + 5 + 6}\:ph2:`).toEqual('abc6:ph1:def15:ph2:'); }); }); describe('with `translate()` defined as an identity', () => { - beforeEach(() => { $localize.translate = identityTranslate; }); - afterEach(() => { $localize.translate = undefined; }); + beforeEach(() => { + $localize.translate = identityTranslate; + }); + afterEach(() => { + $localize.translate = undefined; + }); it('should render template literals as-is', () => { - - expect($localize `abc`).toEqual('abc'); - expect($localize `abc${1 + 2 + 3}`).toEqual('abc6'); - expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def'); - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15'); + expect($localize`abc`).toEqual('abc'); + expect($localize`abc${1 + 2 + 3}`).toEqual('abc6'); + expect($localize`abc${1 + 2 + 3}def`).toEqual('abc6def'); + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15'); const getName = () => 'World'; - expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!'); + expect($localize`Hello, ${getName()}!`).toEqual('Hello, World!'); }); }); describe('with `translate()` defined to upper-case messageParts', () => { - beforeEach(() => { $localize.translate = upperCaseTranslate; }); - afterEach(() => { $localize.translate = undefined; }); + beforeEach(() => { + $localize.translate = upperCaseTranslate; + }); + afterEach(() => { + $localize.translate = undefined; + }); it('should render template literals with messages upper-cased', () => { - - expect($localize `abc`).toEqual('ABC'); - expect($localize `abc${1 + 2 + 3}`).toEqual('ABC6'); - expect($localize `abc${1 + 2 + 3}def`).toEqual('ABC6DEF'); - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15'); + expect($localize`abc`).toEqual('ABC'); + expect($localize`abc${1 + 2 + 3}`).toEqual('ABC6'); + expect($localize`abc${1 + 2 + 3}def`).toEqual('ABC6DEF'); + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15'); const getName = () => 'World'; - expect($localize `Hello, ${getName()}!`).toEqual('HELLO, World!'); + expect($localize`Hello, ${getName()}!`).toEqual('HELLO, World!'); }); }); describe('with `translate()` defined to reverse expressions', () => { - beforeEach(() => { $localize.translate = reverseTranslate; }); - afterEach(() => { $localize.translate = undefined; }); + beforeEach(() => { + $localize.translate = reverseTranslate; + }); + afterEach(() => { + $localize.translate = undefined; + }); it('should render template literals with expressions reversed', () => { const getName = () => 'World'; - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`) + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`) .toEqual('abcWorlddef15 - Hello, 6!'); }); }); diff --git a/packages/localize/src/tools/src/diagnostics.ts b/packages/localize/src/tools/src/diagnostics.ts index 1be6a7cccbf01..73f2945b68bb7 100644 --- a/packages/localize/src/tools/src/diagnostics.ts +++ b/packages/localize/src/tools/src/diagnostics.ts @@ -11,13 +11,19 @@ * of the tools. */ export class Diagnostics { - readonly messages: {type: 'warning' | 'error', message: string}[] = []; - get hasErrors() { return this.messages.some(m => m.type === 'error'); } - warn(message: string) { this.messages.push({type: 'warning', message}); } - error(message: string) { this.messages.push({type: 'error', message}); } + readonly messages: {type: 'warning'|'error', message: string}[] = []; + get hasErrors() { + return this.messages.some(m => m.type === 'error'); + } + warn(message: string) { + this.messages.push({type: 'warning', message}); + } + error(message: string) { + this.messages.push({type: 'error', message}); + } formatDiagnostics(message: string): string { - const errors = this.messages !.filter(d => d.type === 'error').map(d => ' - ' + d.message); - const warnings = this.messages !.filter(d => d.type === 'warning').map(d => ' - ' + d.message); + const errors = this.messages!.filter(d => d.type === 'error').map(d => ' - ' + d.message); + const warnings = this.messages!.filter(d => d.type === 'warning').map(d => ' - ' + d.message); if (errors.length) { message += '\nERRORS:\n' + errors.join('\n'); } diff --git a/packages/localize/src/tools/src/file_utils.ts b/packages/localize/src/tools/src/file_utils.ts index 4477e7036cf03..d34f57abcc49b 100644 --- a/packages/localize/src/tools/src/file_utils.ts +++ b/packages/localize/src/tools/src/file_utils.ts @@ -9,9 +9,13 @@ import * as fs from 'fs'; import * as path from 'path'; export class FileUtils { - static readFile(absolutePath: string): string { return fs.readFileSync(absolutePath, 'utf8'); } + static readFile(absolutePath: string): string { + return fs.readFileSync(absolutePath, 'utf8'); + } - static readFileBuffer(absolutePath: string): Buffer { return fs.readFileSync(absolutePath); } + static readFileBuffer(absolutePath: string): Buffer { + return fs.readFileSync(absolutePath); + } static writeFile(absolutePath: string, contents: string|Buffer) { FileUtils.ensureDir(path.dirname(absolutePath)); @@ -25,7 +29,7 @@ export class FileUtils { absolutePath = path.dirname(absolutePath); } while (parents.length) { - fs.mkdirSync(parents.pop() !); + fs.mkdirSync(parents.pop()!); } } diff --git a/packages/localize/src/tools/src/translate/asset_files/asset_translation_handler.ts b/packages/localize/src/tools/src/translate/asset_files/asset_translation_handler.ts index ed552d0514197..ae70ba7c86c0f 100644 --- a/packages/localize/src/tools/src/translate/asset_files/asset_translation_handler.ts +++ b/packages/localize/src/tools/src/translate/asset_files/asset_translation_handler.ts @@ -14,7 +14,9 @@ import {TranslationBundle, TranslationHandler} from '../translator'; * Translate an asset file by simply copying it to the appropriate translation output paths. */ export class AssetTranslationHandler implements TranslationHandler { - canTranslate(_relativeFilePath: string, _contents: Buffer): boolean { return true; } + canTranslate(_relativeFilePath: string, _contents: Buffer): boolean { + return true; + } translate( diagnostics: Diagnostics, _sourceRoot: string, relativeFilePath: string, contents: Buffer, outputPathFn: OutputPathFn, translations: TranslationBundle[], sourceLocale?: string): void { diff --git a/packages/localize/src/tools/src/translate/main.ts b/packages/localize/src/tools/src/translate/main.ts index e811b870714ac..8ac671cee643c 100644 --- a/packages/localize/src/tools/src/translate/main.ts +++ b/packages/localize/src/tools/src/translate/main.ts @@ -88,8 +88,16 @@ if (require.main === module) { const sourceLocale: string|undefined = options['l']; const translationFileLocales: string[] = options['target-locales'] || []; - translateFiles({sourceRootPath, sourceFilePaths, translationFilePaths, translationFileLocales, - outputPathFn, diagnostics, missingTranslation, sourceLocale}); + translateFiles({ + sourceRootPath, + sourceFilePaths, + translationFilePaths, + translationFileLocales, + outputPathFn, + diagnostics, + missingTranslation, + sourceLocale + }); diagnostics.messages.forEach(m => console.warn(`${m.type}: ${m.message}`)); process.exit(diagnostics.hasErrors ? 1 : 0); @@ -135,9 +143,16 @@ export interface TranslateFilesOptions { sourceLocale?: string; } -export function translateFiles({sourceRootPath, sourceFilePaths, translationFilePaths, - translationFileLocales, outputPathFn, diagnostics, - missingTranslation, sourceLocale}: TranslateFilesOptions) { +export function translateFiles({ + sourceRootPath, + sourceFilePaths, + translationFilePaths, + translationFileLocales, + outputPathFn, + diagnostics, + missingTranslation, + sourceLocale +}: TranslateFilesOptions) { const translationLoader = new TranslationLoader( [ new Xliff2TranslationParser(), diff --git a/packages/localize/src/tools/src/translate/output_path.ts b/packages/localize/src/tools/src/translate/output_path.ts index 89f33cb0d5203..f33a65c5cecbc 100644 --- a/packages/localize/src/tools/src/translate/output_path.ts +++ b/packages/localize/src/tools/src/translate/output_path.ts @@ -7,7 +7,9 @@ */ import {join} from 'path'; -export interface OutputPathFn { (locale: string, relativePath: string): string; } +export interface OutputPathFn { + (locale: string, relativePath: string): string; +} /** * Create a function that will compute the absolute path to where a translated file should be diff --git a/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts b/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts index 51d1e44f9a928..4c8c48a63264a 100644 --- a/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts +++ b/packages/localize/src/tools/src/translate/source_files/es2015_translate_plugin.ts @@ -8,8 +8,10 @@ import {ɵParsedTranslation} from '@angular/localize'; import {NodePath, PluginObj} from '@babel/core'; import {TaggedTemplateExpression} from '@babel/types'; + import {Diagnostics} from '../../diagnostics'; -import {TranslatePluginOptions, buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromTemplateLiteral} from './source_file_utils'; + +import {buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, TranslatePluginOptions, unwrapMessagePartsFromTemplateLiteral} from './source_file_utils'; export function makeEs2015TranslatePlugin( diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>, diff --git a/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts b/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts index 30f87cfcede55..787579f64dd60 100644 --- a/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts +++ b/packages/localize/src/tools/src/translate/source_files/es5_translate_plugin.ts @@ -8,8 +8,10 @@ import {ɵParsedTranslation} from '@angular/localize'; import {NodePath, PluginObj} from '@babel/core'; import {CallExpression} from '@babel/types'; + import {Diagnostics} from '../../diagnostics'; -import {TranslatePluginOptions, buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromLocalizeCall, unwrapSubstitutionsFromLocalizeCall} from './source_file_utils'; + +import {buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, TranslatePluginOptions, unwrapMessagePartsFromLocalizeCall, unwrapSubstitutionsFromLocalizeCall} from './source_file_utils'; export function makeEs5TranslatePlugin( diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>, diff --git a/packages/localize/src/tools/src/translate/source_files/locale_plugin.ts b/packages/localize/src/tools/src/translate/source_files/locale_plugin.ts index aaa0237628fa1..e4a81041cb1bc 100644 --- a/packages/localize/src/tools/src/translate/source_files/locale_plugin.ts +++ b/packages/localize/src/tools/src/translate/source_files/locale_plugin.ts @@ -8,7 +8,7 @@ import {NodePath, PluginObj} from '@babel/core'; import {MemberExpression, stringLiteral} from '@babel/types'; -import {TranslatePluginOptions, isLocalize} from './source_file_utils'; +import {isLocalize, TranslatePluginOptions} from './source_file_utils'; /** * This Babel plugin will replace the following code forms with a string literal containing the diff --git a/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts b/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts index 04eb96ebc7b57..9a264b0e9303d 100644 --- a/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts +++ b/packages/localize/src/tools/src/translate/source_files/source_file_utils.ts @@ -5,9 +5,10 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {ɵParsedTranslation, ɵisMissingTranslationError, ɵmakeTemplateObject, ɵtranslate} from '@angular/localize'; +import {ɵisMissingTranslationError, ɵmakeTemplateObject, ɵParsedTranslation, ɵtranslate} from '@angular/localize'; import {NodePath} from '@babel/traverse'; import * as t from '@babel/types'; + import {Diagnostics} from '../../diagnostics'; /** @@ -33,18 +34,18 @@ export function isNamedIdentifier( } /** -* Is the given `identifier` declared globally. -* @param identifier The identifier to check. -*/ + * Is the given `identifier` declared globally. + * @param identifier The identifier to check. + */ export function isGlobalIdentifier(identifier: NodePath<t.Identifier>) { return !identifier.scope || !identifier.scope.hasBinding(identifier.node.name); } /** -* Build a translated expression to replace the call to `$localize`. -* @param messageParts The static parts of the message. -* @param substitutions The expressions to substitute into the message. -*/ + * Build a translated expression to replace the call to `$localize`. + * @param messageParts The static parts of the message. + * @param substitutions The expressions to substitute into the message. + */ export function buildLocalizeReplacement( messageParts: TemplateStringsArray, substitutions: readonly t.Expression[]): t.Expression { let mappedString: t.Expression = t.stringLiteral(messageParts[0]); @@ -57,13 +58,13 @@ export function buildLocalizeReplacement( } /** -* Extract the message parts from the given `call` (to `$localize`). -* -* The message parts will either by the first argument to the `call` or it will be wrapped in call -* to a helper function like `__makeTemplateObject`. -* -* @param call The AST node of the call to process. -*/ + * Extract the message parts from the given `call` (to `$localize`). + * + * The message parts will either by the first argument to the `call` or it will be wrapped in call + * to a helper function like `__makeTemplateObject`. + * + * @param call The AST node of the call to process. + */ export function unwrapMessagePartsFromLocalizeCall(call: NodePath<t.CallExpression>): TemplateStringsArray { let cooked = call.get('arguments')[0]; @@ -144,7 +145,7 @@ export function unwrapMessagePartsFromLocalizeCall(call: NodePath<t.CallExpressi export function unwrapSubstitutionsFromLocalizeCall(call: t.CallExpression): t.Expression[] { const expressions = call.arguments.splice(1); if (!isArrayOfExpressions(expressions)) { - const badExpression = expressions.find(expression => !t.isExpression(expression)) !; + const badExpression = expressions.find(expression => !t.isExpression(expression))!; throw new BabelParseError( badExpression, 'Invalid substitutions for `$localize` (expected all substitution arguments to be expressions).'); @@ -166,12 +167,12 @@ export function unwrapMessagePartsFromTemplateLiteral(elements: t.TemplateElemen } /** -* Wrap the given `expression` in parentheses if it is a binary expression. -* -* This ensures that this expression is evaluated correctly if it is embedded in another expression. -* -* @param expression The expression to potentially wrap. -*/ + * Wrap the given `expression` in parentheses if it is a binary expression. + * + * This ensures that this expression is evaluated correctly if it is embedded in another expression. + * + * @param expression The expression to potentially wrap. + */ export function wrapInParensIfNecessary(expression: t.Expression): t.Expression { if (t.isBinaryExpression(expression)) { return t.parenthesizedExpression(expression); @@ -181,9 +182,9 @@ export function wrapInParensIfNecessary(expression: t.Expression): t.Expression } /** -* Extract the string values from an `array` of string literals. -* @param array The array to unwrap. -*/ + * Extract the string values from an `array` of string literals. + * @param array The array to unwrap. + */ export function unwrapStringLiteralArray(array: t.Expression): string[] { if (!isStringLiteralArray(array)) { throw new BabelParseError( @@ -280,19 +281,19 @@ function getReturnedExpression(fn: NodePath<t.FunctionDeclaration>): NodePath<t. } /** -* Is the given `node` an array of literal strings? -* -* @param node The node to test. -*/ + * Is the given `node` an array of literal strings? + * + * @param node The node to test. + */ export function isStringLiteralArray(node: t.Node): node is t.Expression& {elements: t.StringLiteral[]} { return t.isArrayExpression(node) && node.elements.every(element => t.isStringLiteral(element)); } /** -* Are all the given `nodes` expressions? -* @param nodes The nodes to test. -*/ + * Are all the given `nodes` expressions? + * @param nodes The nodes to test. + */ export function isArrayOfExpressions(nodes: t.Node[]): nodes is t.Expression[] { return nodes.every(element => t.isExpression(element)); } @@ -306,7 +307,7 @@ export interface TranslatePluginOptions { /** * How to handle missing translations. */ -export type MissingTranslationStrategy = 'error' | 'warning' | 'ignore'; +export type MissingTranslationStrategy = 'error'|'warning'|'ignore'; /** * Translate the text of the given message, using the given translations. @@ -340,7 +341,9 @@ export function translate( export class BabelParseError extends Error { private readonly type = 'BabelParseError'; - constructor(public node: t.Node, message: string) { super(message); } + constructor(public node: t.Node, message: string) { + super(message); + } } export function isBabelParseError(e: any): e is BabelParseError { diff --git a/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts b/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts index bea939fe4153b..f9ac0fef76b3f 100644 --- a/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts +++ b/packages/localize/src/tools/src/translate/translation_files/message_serialization/message_serializer.ts @@ -9,7 +9,7 @@ import {Element, Expansion, ExpansionCase, Node, Text, visitAll} from '@angular/ import {BaseVisitor} from '../base_visitor'; import {TranslationParseError} from '../translation_parsers/translation_parse_error'; -import {getAttrOrThrow, getAttribute} from '../translation_parsers/translation_utils'; +import {getAttribute, getAttrOrThrow} from '../translation_parsers/translation_utils'; import {MessageRenderer} from './message_renderer'; @@ -55,7 +55,9 @@ export class MessageSerializer<T> extends BaseVisitor { } } - visitText(text: Text): void { this.renderer.text(text.value); } + visitText(text: Text): void { + this.renderer.text(text.value); + } visitExpansion(expansion: Expansion): void { this.renderer.startIcu(); @@ -109,6 +111,6 @@ export class MessageSerializer<T> extends BaseVisitor { } private isPlaceholderContainer(node: Node): boolean { - return node instanceof Element && node.name === this.config.placeholderContainer !.elementName; + return node instanceof Element && node.name === this.config.placeholderContainer!.elementName; } } diff --git a/packages/localize/src/tools/src/translate/translation_files/message_serialization/target_message_renderer.ts b/packages/localize/src/tools/src/translate/translation_files/message_serialization/target_message_renderer.ts index 449dfaf7123ac..e4f43317d14dd 100644 --- a/packages/localize/src/tools/src/translate/translation_files/message_serialization/target_message_renderer.ts +++ b/packages/localize/src/tools/src/translate/translation_files/message_serialization/target_message_renderer.ts @@ -5,7 +5,8 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {ɵParsedTranslation, ɵmakeParsedTranslation} from '@angular/localize'; +import {ɵmakeParsedTranslation, ɵParsedTranslation} from '@angular/localize'; + import {MessageRenderer} from './message_renderer'; /** @@ -20,11 +21,21 @@ export class TargetMessageRenderer implements MessageRenderer<ɵParsedTranslatio return ɵmakeParsedTranslation(messageParts, placeholderNames); } startRender(): void {} - endRender(): void { this.storeMessagePart(); } - text(text: string): void { this.current.text += text; } - placeholder(name: string, body: string|undefined): void { this.renderPlaceholder(name); } - startPlaceholder(name: string): void { this.renderPlaceholder(name); } - closePlaceholder(name: string): void { this.renderPlaceholder(name); } + endRender(): void { + this.storeMessagePart(); + } + text(text: string): void { + this.current.text += text; + } + placeholder(name: string, body: string|undefined): void { + this.renderPlaceholder(name); + } + startPlaceholder(name: string): void { + this.renderPlaceholder(name); + } + closePlaceholder(name: string): void { + this.renderPlaceholder(name); + } startContainer(): void {} closeContainer(): void {} startIcu(): void { @@ -35,7 +46,9 @@ export class TargetMessageRenderer implements MessageRenderer<ɵParsedTranslatio this.icuDepth--; this.text('}'); } - private normalizePlaceholderName(name: string) { return name.replace(/-/g, '_'); } + private normalizePlaceholderName(name: string) { + return name.replace(/-/g, '_'); + } private renderPlaceholder(name: string) { name = this.normalizePlaceholderName(name); if (this.icuDepth > 0) { diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_loader.ts b/packages/localize/src/tools/src/translate/translation_files/translation_loader.ts index 8c37a985faab3..a0abd83781c7f 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_loader.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_loader.ts @@ -51,14 +51,15 @@ export class TranslationLoader { const providedLocale = translationFileLocales[index]; const locale = providedLocale || parsedLocale; if (locale === undefined) { - throw new Error( - `The translation file "${filePath}" does not contain a target locale and no explicit locale was provided for this file.`); + throw new Error(`The translation file "${ + filePath}" does not contain a target locale and no explicit locale was provided for this file.`); } if (parsedLocale !== undefined && providedLocale !== undefined && parsedLocale !== providedLocale) { diagnostics.warn( - `The provided locale "${providedLocale}" does not match the target locale "${parsedLocale}" found in the translation file "${filePath}".`); + `The provided locale "${providedLocale}" does not match the target locale "${ + parsedLocale}" found in the translation file "${filePath}".`); } // If we were passed a diagnostics object then copy the messages over to it. diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts index e21299215d845..7a3ce587385b3 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/simple_json_translation_parser.ts @@ -24,7 +24,9 @@ import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; * ``` */ export class SimpleJsonTranslationParser implements TranslationParser { - canParse(filePath: string, _contents: string): boolean { return (extname(filePath) === '.json'); } + canParse(filePath: string, _contents: string): boolean { + return (extname(filePath) === '.json'); + } parse(_filePath: string, contents: string): ParsedTranslationBundle { const {locale: parsedLocale, translations} = JSON.parse(contents); diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_parser.ts index 14b2ab71bcf7c..7a45a32d9dbc3 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_parser.ts @@ -9,8 +9,8 @@ import {ɵMessageId, ɵParsedTranslation} from '@angular/localize/private'; import {Diagnostics} from '../../../diagnostics'; /** -* An object that holds translations that have been parsed from a translation file. -*/ + * An object that holds translations that have been parsed from a translation file. + */ export interface ParsedTranslationBundle { locale: string|undefined; translations: Record<ɵMessageId, ɵParsedTranslation>; diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_utils.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_utils.ts index 731bfa30b1f52..3edb796917c33 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_utils.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/translation_utils.ts @@ -47,8 +47,8 @@ export function parseInnerRange(element: Element): Node[] { * @param element The element whose inner range we want to compute. */ function getInnerRange(element: Element): LexerRange { - const start = element.startSourceSpan !.end; - const end = element.endSourceSpan !.start; + const start = element.startSourceSpan!.end; + const end = element.endSourceSpan!.start; return { startPos: start.offset, startLine: start.line, diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts index 2656cc8584905..ab40ba2685500 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff1_translation_parser.ts @@ -14,7 +14,7 @@ import {MessageSerializer} from '../message_serialization/message_serializer'; import {TargetMessageRenderer} from '../message_serialization/target_message_renderer'; import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; -import {XmlTranslationParserHint, addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange} from './translation_utils'; +import {addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange, XmlTranslationParserHint} from './translation_utils'; /** * A translation parser that can load XLIFF 1.2 files. @@ -74,7 +74,8 @@ export class Xliff1TranslationParser implements TranslationParser<XmlTranslation if (localesFound.size > 1) { addParseDiagnostic( diagnostics, element.sourceSpan, - `More than one locale found in translation file: ${JSON.stringify(Array.from(localesFound))}. Using "${bundle.locale}"`, + `More than one locale found in translation file: ${ + JSON.stringify(Array.from(localesFound))}. Using "${bundle.locale}"`, ParseErrorLevel.WARNING); } diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts index debeafcd1011f..d60c38535e59e 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xliff2_translation_parser.ts @@ -14,7 +14,7 @@ import {MessageSerializer} from '../message_serialization/message_serializer'; import {TargetMessageRenderer} from '../message_serialization/target_message_renderer'; import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; -import {XmlTranslationParserHint, addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange} from './translation_utils'; +import {addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange, XmlTranslationParserHint} from './translation_utils'; /** * A translation parser that can load translations from XLIFF 2 files. diff --git a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xtb_translation_parser.ts b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xtb_translation_parser.ts index c3a6388d185be..6e1e7512d5245 100644 --- a/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xtb_translation_parser.ts +++ b/packages/localize/src/tools/src/translate/translation_files/translation_parsers/xtb_translation_parser.ts @@ -15,7 +15,7 @@ import {MessageSerializer} from '../message_serialization/message_serializer'; import {TargetMessageRenderer} from '../message_serialization/target_message_renderer'; import {ParsedTranslationBundle, TranslationParser} from './translation_parser'; -import {XmlTranslationParserHint, addParseDiagnostic, addParseError, canParseXml, getAttribute, parseInnerRange} from './translation_utils'; +import {addParseDiagnostic, addParseError, canParseXml, getAttribute, parseInnerRange, XmlTranslationParserHint} from './translation_utils'; /** @@ -94,7 +94,8 @@ class XtbVisitor extends BaseVisitor { } catch (error) { if (typeof error === 'string') { bundle.diagnostics.warn( - `Could not parse message with id "${id}" - perhaps it has an unrecognised ICU format?\n` + + `Could not parse message with id "${ + id}" - perhaps it has an unrecognised ICU format?\n` + error); } else if (error.span && error.msg && error.level) { addParseDiagnostic(bundle.diagnostics, error.span, error.msg, error.level); diff --git a/packages/localize/src/tools/test/translate/integration/main_spec.ts b/packages/localize/src/tools/test/translate/integration/main_spec.ts index 6f15de78075ad..07a9835196f5c 100644 --- a/packages/localize/src/tools/test/translate/integration/main_spec.ts +++ b/packages/localize/src/tools/test/translate/integration/main_spec.ts @@ -19,7 +19,9 @@ describe('translateFiles()', () => { const testDir = resolve(tmpDir, 'translatedFiles_tests'); beforeEach(() => FileUtils.ensureDir(testDir)); - afterEach(() => { FileUtils.remove(testDir); }); + afterEach(() => { + FileUtils.remove(testDir); + }); it('should copy non-code files to the destination folders', () => { const diagnostics = new Diagnostics(); @@ -31,7 +33,8 @@ describe('translateFiles()', () => { translationFilePaths: resolveAll( __dirname + '/locales', ['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']), - translationFileLocales: [], diagnostics, + translationFileLocales: [], + diagnostics, missingTranslation: 'error' }); @@ -60,11 +63,13 @@ describe('translateFiles()', () => { const outputPathFn = getOutputPathFn(resolve(testDir, '{{LOCALE}}')); translateFiles({ sourceRootPath: resolve(__dirname, 'test_files'), - sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']), outputPathFn, + sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']), + outputPathFn, translationFilePaths: resolveAll( __dirname + '/locales', ['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']), - translationFileLocales: [], diagnostics, + translationFileLocales: [], + diagnostics, missingTranslation: 'error', }); @@ -85,11 +90,13 @@ describe('translateFiles()', () => { const outputPathFn = getOutputPathFn(resolve(testDir, '{{LOCALE}}')); translateFiles({ sourceRootPath: resolve(__dirname, 'test_files'), - sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']), outputPathFn, + sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']), + outputPathFn, translationFilePaths: resolveAll( __dirname + '/locales', ['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']), - translationFileLocales: ['xde', undefined, 'fr'], diagnostics, + translationFileLocales: ['xde', undefined, 'fr'], + diagnostics, missingTranslation: 'error', }); @@ -97,7 +104,8 @@ describe('translateFiles()', () => { expect(diagnostics.messages).toContain({ type: 'warning', message: - `The provided locale "xde" does not match the target locale "de" found in the translation file "${resolve(__dirname, 'locales', 'messages.de.json')}".` + `The provided locale "xde" does not match the target locale "de" found in the translation file "${ + resolve(__dirname, 'locales', 'messages.de.json')}".` }); expect(FileUtils.readFile(resolve(testDir, 'xde', 'test.js'))) @@ -121,7 +129,8 @@ describe('translateFiles()', () => { translationFilePaths: resolveAll( __dirname + '/locales', ['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']), - translationFileLocales: [], diagnostics, + translationFileLocales: [], + diagnostics, missingTranslation: 'error', }); diff --git a/packages/localize/src/tools/test/translate/integration/test_files/test.js b/packages/localize/src/tools/test/translate/integration/test_files/test.js index 8b3009345fac2..bc82ba72b7625 100644 --- a/packages/localize/src/tools/test/translate/integration/test_files/test.js +++ b/packages/localize/src/tools/test/translate/integration/test_files/test.js @@ -1,2 +1,2 @@ var name = 'World'; -var message = $localize `Hello, ${name}!`; \ No newline at end of file +var message = $localize`Hello, ${name}!`; \ No newline at end of file diff --git a/packages/localize/src/tools/test/translate/source_files/es2015_translate_plugin_spec.ts b/packages/localize/src/tools/test/translate/source_files/es2015_translate_plugin_spec.ts index d25e90d8307d4..783493941a850 100644 --- a/packages/localize/src/tools/test/translate/source_files/es2015_translate_plugin_spec.ts +++ b/packages/localize/src/tools/test/translate/source_files/es2015_translate_plugin_spec.ts @@ -16,24 +16,21 @@ describe('makeEs2015Plugin', () => { it('should transform `$localize` tags with binary expression', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize`try\\n${40 + b}\\n me`;'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";'); }); it('should strip meta blocks', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize `:description:try\\n${40 + b}\\n me`;'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";'); }); it('should not strip escaped meta blocks', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize `\\:description:try\\n${40 + b}\\n me`;'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('const b = 10;\n":description:try\\n" + (40 + b) + "\\n me";'); }); @@ -41,24 +38,21 @@ describe('makeEs2015Plugin', () => { it('should transform nested `$localize` tags', () => { const diagnostics = new Diagnostics(); const input = '$localize`a${1}b${$localize`x${5}y${6}z`}c`;'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"a" + 1 + "b" + ("x" + 5 + "y" + 6 + "z") + "c";'); }); it('should transform tags inside functions', () => { const diagnostics = new Diagnostics(); const input = 'function foo() { $localize`a${1}b${2}c`; }'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('function foo() {\n "a" + 1 + "b" + 2 + "c";\n}'); }); it('should ignore tags with the wrong name', () => { const diagnostics = new Diagnostics(); const input = 'other`a${1}b${2}c`;'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('other`a${1}b${2}c`;'); }); @@ -66,16 +60,14 @@ describe('makeEs2015Plugin', () => { const diagnostics = new Diagnostics(); const input = 'other`a${1}b${2}c`;'; const output = transformSync( - input, - {plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]}) !; + input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]})!; expect(output.code).toEqual('"a" + 1 + "b" + 2 + "c";'); }); it('should ignore tags if the identifier is not global', () => { const diagnostics = new Diagnostics(); const input = 'function foo($localize) { $localize`a${1}b${2}c`; }'; - const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('function foo($localize) {\n $localize`a${1}b${2}c`;\n}'); }); @@ -85,12 +77,12 @@ describe('makeEs2015Plugin', () => { const input = 'const b = 10;\n$localize `try\\n${40 + b}\\n me`;'; transformSync(input, { plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'error'})] - }) !; + })!; expect(diagnostics.hasErrors).toBe(true); expect(diagnostics.messages[0]).toEqual({ type: 'error', - message: - `No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` + message: `No translation found for "${ + ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` }); }); @@ -99,14 +91,13 @@ describe('makeEs2015Plugin', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize `try\\n${40 + b}\\n me`;'; transformSync(input, { - plugins: - [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'warning'})] - }) !; + plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'warning'})] + })!; expect(diagnostics.hasErrors).toBe(false); expect(diagnostics.messages[0]).toEqual({ type: 'warning', - message: - `No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` + message: `No translation found for "${ + ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` }); }); @@ -115,9 +106,8 @@ describe('makeEs2015Plugin', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize `try\\n${40 + b}\\n me`;'; transformSync(input, { - plugins: - [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'ignore'})] - }) !; + plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'ignore'})] + })!; expect(diagnostics.hasErrors).toBe(false); expect(diagnostics.messages).toEqual([]); }); @@ -139,7 +129,7 @@ describe('makeEs2015Plugin', () => { '$localize `abc${1 + 2 + 3}def${4 + 5 + 6}`;\n' + '$localize `Hello, ${getName()}!`;'; const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!; expect(output.code) .toEqual( '"abc";\n' + @@ -164,7 +154,7 @@ describe('makeEs2015Plugin', () => { '$localize `abc${1 + 2 + 3}def${4 + 5 + 6}`;\n' + '$localize `Hello, ${getName()}!`;'; const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!; expect(output.code) .toEqual( '"ABC";\n' + @@ -182,7 +172,7 @@ describe('makeEs2015Plugin', () => { }; const input = '$localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`;'; const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!; expect(output.code) .toEqual('"abc" + getName() + "def" + (4 + 5 + 6) + " - Hello, " + (1 + 2 + 3) + "!";'); }); @@ -195,7 +185,7 @@ describe('makeEs2015Plugin', () => { }; const input = '$localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`;'; const output = - transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!; expect(output.code).toEqual('"abc" + (1 + 2 + 3) + " - Hello, " + getName() + "!";'); }); }); diff --git a/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts b/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts index eb3db70de7868..a47dff362ed4d 100644 --- a/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts +++ b/packages/localize/src/tools/test/translate/source_files/es5_translate_plugin_spec.ts @@ -16,7 +16,7 @@ describe('makeEs5Plugin', () => { it('should transform `$localize` calls with binary expression', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize(["try\\n", "\\n me"], 40 + b);'; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";'); }); @@ -24,7 +24,7 @@ describe('makeEs5Plugin', () => { const diagnostics = new Diagnostics(); const input = 'const b = 10;\n$localize([":description:try\\n", ":placeholder:\\n me"], 40 + b);'; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";'); }); @@ -32,28 +32,28 @@ describe('makeEs5Plugin', () => { const diagnostics = new Diagnostics(); const input = `$localize(__makeTemplateObject([':desc:try', 'me'], ['\\\\\\:desc:try', 'me']), 40 + 2);`; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('":desc:try" + (40 + 2) + "me";'); }); it('should transform nested `$localize` calls', () => { const diagnostics = new Diagnostics(); const input = '$localize(["a", "b", "c"], 1, $localize(["x", "y", "z"], 5, 6));'; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"a" + 1 + "b" + ("x" + 5 + "y" + 6 + "z") + "c";'); }); it('should transform calls inside functions', () => { const diagnostics = new Diagnostics(); const input = 'function foo() { $localize(["a", "b", "c"], 1, 2); }'; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('function foo() {\n "a" + 1 + "b" + 2 + "c";\n}'); }); it('should ignore tags with the wrong name', () => { const diagnostics = new Diagnostics(); const input = 'other(["a", "b", "c"], 1, 2);'; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('other(["a", "b", "c"], 1, 2);'); }); @@ -61,14 +61,14 @@ describe('makeEs5Plugin', () => { const diagnostics = new Diagnostics(); const input = 'other(["a", "b", "c"], 1, 2);'; const output = transformSync( - input, {plugins: [makeEs5TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]}) !; + input, {plugins: [makeEs5TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]})!; expect(output.code).toEqual('"a" + 1 + "b" + 2 + "c";'); }); it('should ignore tags if the identifier is not global', () => { const diagnostics = new Diagnostics(); const input = 'function foo($localize) { $localize(["a", "b", "c"], 1, 2); }'; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code) .toEqual('function foo($localize) {\n $localize(["a", "b", "c"], 1, 2);\n}'); }); @@ -76,14 +76,14 @@ describe('makeEs5Plugin', () => { it('should handle template object helper calls', () => { const diagnostics = new Diagnostics(); const input = `$localize(__makeTemplateObject(['try', 'me'], ['try', 'me']), 40 + 2);`; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"try" + (40 + 2) + "me";'); }); it('should handle template object aliased helper calls', () => { const diagnostics = new Diagnostics(); const input = `$localize(m(['try', 'me'], ['try', 'me']), 40 + 2);`; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"try" + (40 + 2) + "me";'); }); @@ -91,7 +91,7 @@ describe('makeEs5Plugin', () => { const diagnostics = new Diagnostics(); const input = `$localize((this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})(['try', 'me'], ['try', 'me']), 40 + 2);`; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"try" + (40 + 2) + "me";'); }); @@ -99,7 +99,7 @@ describe('makeEs5Plugin', () => { const diagnostics = new Diagnostics(); const input = `$localize(cachedObj||(cachedObj=__makeTemplateObject(['try', 'me'],['try', 'me'])),40 + 2)`; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"try" + (40 + 2) + "me";'); }); @@ -115,7 +115,7 @@ describe('makeEs5Plugin', () => { cookedParts.raw=rawParts, cachedObj=cookedParts ),40 + 2)`; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toEqual('"try" + (40 + 2) + "me";'); }); @@ -139,7 +139,7 @@ describe('makeEs5Plugin', () => { console.log($localize(_templateObject(), '\ufffd0\ufffd')); } `; - const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !; + const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!; expect(output.code).toContain('const message = ":escaped-colons:Welcome to the i18n app."'); expect(output.code).toContain('console.log(" Hello " + \'\ufffd0\ufffd\' + "! ");'); expect(output.code).not.toContain('templateObject'); @@ -290,8 +290,8 @@ describe('makeEs5Plugin', () => { expect(diagnostics.hasErrors).toBe(true); expect(diagnostics.messages[0]).toEqual({ type: 'error', - message: - `No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` + message: `No translation found for "${ + ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` }); }); @@ -305,8 +305,8 @@ describe('makeEs5Plugin', () => { expect(diagnostics.hasErrors).toBe(false); expect(diagnostics.messages[0]).toEqual({ type: 'warning', - message: - `No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` + message: `No translation found for "${ + ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").` }); }); @@ -338,7 +338,7 @@ describe('(with translations)', () => { '$localize(["abc", "def", ""], 1 + 2 + 3, 4 + 5 + 6);\n' + '$localize(["Hello, ", "!"], getName());'; const output = - transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!; expect(output.code) .toEqual( '"abc";\n' + @@ -363,7 +363,7 @@ describe('(with translations)', () => { '$localize(["abc", "def", ""], 1 + 2 + 3, 4 + 5 + 6);\n' + '$localize(["Hello, ", "!"], getName());'; const output = - transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!; expect(output.code) .toEqual( '"ABC";\n' + @@ -381,7 +381,7 @@ describe('(with translations)', () => { }; const input = '$localize(["abc", "def", " - Hello, ", "!"], 1 + 2 + 3, 4 + 5 + 6, getName());'; const output = - transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!; expect(output.code) .toEqual('"abc" + getName() + "def" + (4 + 5 + 6) + " - Hello, " + (1 + 2 + 3) + "!";'); }); @@ -394,7 +394,7 @@ describe('(with translations)', () => { }; const input = '$localize(["abc", "def", " - Hello, ", "!"], 1 + 2 + 3, 4 + 5 + 6, getName());'; const output = - transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !; + transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!; expect(output.code).toEqual('"abc" + (1 + 2 + 3) + " - Hello, " + getName() + "!";'); }); }); diff --git a/packages/localize/src/tools/test/translate/source_files/locale_plugin_spec.ts b/packages/localize/src/tools/test/translate/source_files/locale_plugin_spec.ts index b1033c4191048..637c10a05cf3e 100644 --- a/packages/localize/src/tools/test/translate/source_files/locale_plugin_spec.ts +++ b/packages/localize/src/tools/test/translate/source_files/locale_plugin_spec.ts @@ -11,88 +11,88 @@ import {makeLocalePlugin} from '../../../src/translate/source_files/locale_plugi describe('makeLocalePlugin', () => { it('should replace $localize.locale with the locale string', () => { const input = '$localize.locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('"fr";'); }); it('should replace $localize.locale with the locale string in the context of a variable assignment', () => { const input = 'const a = $localize.locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('const a = "fr";'); }); it('should replace $localize.locale with the locale string in the context of a binary expression', () => { const input = '$localize.locale || "default";'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('"fr" || "default";'); }); it('should remove reference to `$localize` if used to guard the locale', () => { const input = 'typeof $localize !== "undefined" && $localize.locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('"fr";'); }); it('should remove reference to `$localize` if used in a longer logical expression to guard the locale', () => { const input1 = 'x || y && typeof $localize !== "undefined" && $localize.locale;'; - const output1 = transformSync(input1, {plugins: [makeLocalePlugin('fr')]}) !; + const output1 = transformSync(input1, {plugins: [makeLocalePlugin('fr')]})!; expect(output1.code).toEqual('x || y && "fr";'); const input2 = 'x || y && "undefined" !== typeof $localize && $localize.locale;'; - const output2 = transformSync(input2, {plugins: [makeLocalePlugin('fr')]}) !; + const output2 = transformSync(input2, {plugins: [makeLocalePlugin('fr')]})!; expect(output2.code).toEqual('x || y && "fr";'); const input3 = 'x || y && typeof $localize != "undefined" && $localize.locale;'; - const output3 = transformSync(input3, {plugins: [makeLocalePlugin('fr')]}) !; + const output3 = transformSync(input3, {plugins: [makeLocalePlugin('fr')]})!; expect(output3.code).toEqual('x || y && "fr";'); const input4 = 'x || y && "undefined" != typeof $localize && $localize.locale;'; - const output4 = transformSync(input4, {plugins: [makeLocalePlugin('fr')]}) !; + const output4 = transformSync(input4, {plugins: [makeLocalePlugin('fr')]})!; expect(output4.code).toEqual('x || y && "fr";'); }); it('should ignore properties on $localize other than `locale`', () => { const input = '$localize.notLocale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('$localize.notLocale;'); }); it('should ignore indexed property on $localize', () => { const input = '$localize["locale"];'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('$localize["locale"];'); }); it('should ignore `locale` on objects other than $localize', () => { const input = '$notLocalize.locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('$notLocalize.locale;'); }); it('should ignore `$localize.locale` if `$localize` is not global', () => { const input = 'const $localize = {};\n$localize.locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('const $localize = {};\n$localize.locale;'); }); it('should ignore `locale` if it is not directly accessed from `$localize`', () => { const input = 'const {locale} = $localize;\nconst a = locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('const {\n locale\n} = $localize;\nconst a = locale;'); }); it('should ignore `$localize.locale` on LHS of an assignment', () => { const input = 'let a;\na = $localize.locale = "de";'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('let a;\na = $localize.locale = "de";'); }); it('should handle `$localize.locale on RHS of an assignment', () => { const input = 'let a;\na = $localize.locale;'; - const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !; + const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!; expect(output.code).toEqual('let a;\na = "fr";'); }); }); diff --git a/packages/localize/src/tools/test/translate/source_files/source_file_translation_handler_spec.ts b/packages/localize/src/tools/test/translate/source_files/source_file_translation_handler_spec.ts index 97749abd77653..ef56567330ddd 100644 --- a/packages/localize/src/tools/test/translate/source_files/source_file_translation_handler_spec.ts +++ b/packages/localize/src/tools/test/translate/source_files/source_file_translation_handler_spec.ts @@ -20,7 +20,9 @@ describe('SourceFileTranslationHandler', () => { }); describe('translate()', () => { - beforeEach(() => { spyOn(FileUtils, 'writeFile'); }); + beforeEach(() => { + spyOn(FileUtils, 'writeFile'); + }); it('should copy files for each translation locale if they contain no reference to `$localize`', () => { diff --git a/packages/localize/src/tools/test/translate/source_files/source_file_utils_spec.ts b/packages/localize/src/tools/test/translate/source_files/source_file_utils_spec.ts index 38b8c5f18a110..b6c777a2fcfd8 100644 --- a/packages/localize/src/tools/test/translate/source_files/source_file_utils_spec.ts +++ b/packages/localize/src/tools/test/translate/source_files/source_file_utils_spec.ts @@ -114,7 +114,7 @@ describe('utils', () => { describe('unwrapSubstitutionsFromLocalizeCall', () => { it('should return the substitutions from a direct call to a tag function', () => { - const ast = template.ast `$localize(['a', 'b\t', 'c'], 1, 2)` as ExpressionStatement; + const ast = template.ast`$localize(['a', 'b\t', 'c'], 1, 2)` as ExpressionStatement; const call = ast.expression as CallExpression; const substitutions = unwrapSubstitutionsFromLocalizeCall(call); expect(substitutions.map(s => (s as NumericLiteral).value)).toEqual([1, 2]); @@ -140,13 +140,13 @@ describe('utils', () => { describe('wrapInParensIfNecessary', () => { it('should wrap the expression in parentheses if it is binary', () => { - const ast = template.ast `a + b` as ExpressionStatement; + const ast = template.ast`a + b` as ExpressionStatement; const wrapped = wrapInParensIfNecessary(ast.expression); expect(isParenthesizedExpression(wrapped)).toBe(true); }); it('should return the expression untouched if it is not binary', () => { - const ast = template.ast `a` as ExpressionStatement; + const ast = template.ast`a` as ExpressionStatement; const wrapped = wrapInParensIfNecessary(ast.expression); expect(isParenthesizedExpression(wrapped)).toBe(false); }); @@ -154,12 +154,12 @@ describe('utils', () => { describe('unwrapStringLiteralArray', () => { it('should return an array of string from an array expression', () => { - const ast = template.ast `['a', 'b', 'c']` as ExpressionStatement; + const ast = template.ast`['a', 'b', 'c']` as ExpressionStatement; expect(unwrapStringLiteralArray(ast.expression)).toEqual(['a', 'b', 'c']); }); it('should throw an error if any elements of the array are not literal strings', () => { - const ast = template.ast `['a', 2, 'c']` as ExpressionStatement; + const ast = template.ast`['a', 2, 'c']` as ExpressionStatement; expect(() => unwrapStringLiteralArray(ast.expression)) .toThrowError('Unexpected messageParts for `$localize` (expected an array of strings).'); }); @@ -167,29 +167,29 @@ describe('utils', () => { describe('isStringLiteralArray()', () => { it('should return true if the ast is an array of strings', () => { - const ast = template.ast `['a', 'b', 'c']` as ExpressionStatement; + const ast = template.ast`['a', 'b', 'c']` as ExpressionStatement; expect(isStringLiteralArray(ast.expression)).toBe(true); }); it('should return false if the ast is not an array', () => { - const ast = template.ast `'a'` as ExpressionStatement; + const ast = template.ast`'a'` as ExpressionStatement; expect(isStringLiteralArray(ast.expression)).toBe(false); }); it('should return false if at least on of the array elements is not a string', () => { - const ast = template.ast `['a', 1, 'b']` as ExpressionStatement; + const ast = template.ast`['a', 1, 'b']` as ExpressionStatement; expect(isStringLiteralArray(ast.expression)).toBe(false); }); }); describe('isArrayOfExpressions()', () => { it('should return true if all the nodes are expressions', () => { - const ast = template.ast `function foo(a, b, c) {}` as FunctionDeclaration; + const ast = template.ast`function foo(a, b, c) {}` as FunctionDeclaration; expect(isArrayOfExpressions(ast.params)).toBe(true); }); it('should return false if any of the nodes is not an expression', () => { - const ast = template.ast `function foo(a, b, ...c) {}` as FunctionDeclaration; + const ast = template.ast`function foo(a, b, ...c) {}` as FunctionDeclaration; expect(isArrayOfExpressions(ast.params)).toBe(false); }); }); @@ -203,13 +203,25 @@ function getTaggedTemplate(code: string): NodePath<TaggedTemplateExpression> { function collectExpressionsPlugin() { const expressions: NodePath<Expression>[] = []; - const visitor = {Expression: (path: NodePath<Expression>) => { expressions.push(path); }}; + const visitor = { + Expression: (path: NodePath<Expression>) => { + expressions.push(path); + } + }; return {expressions, plugin: {visitor}}; } function getLocalizeCall(code: string): NodePath<CallExpression> { let callPaths: NodePath<CallExpression>[] = []; - transformSync(code, {plugins: [{visitor: {CallExpression(path) { callPaths.push(path); }}}]}); + transformSync(code, { + plugins: [{ + visitor: { + CallExpression(path) { + callPaths.push(path); + } + } + }] + }); const localizeCall = callPaths.find(p => { const callee = p.get('callee'); return (callee.isIdentifier() && callee.node.name === '$localize'); diff --git a/packages/localize/src/tools/test/translate/translation_files/translation_loader_spec.ts b/packages/localize/src/tools/test/translate/translation_files/translation_loader_spec.ts index 0d9995d55747b..48bd2be07b522 100644 --- a/packages/localize/src/tools/test/translate/translation_files/translation_loader_spec.ts +++ b/packages/localize/src/tools/test/translate/translation_files/translation_loader_spec.ts @@ -84,11 +84,14 @@ describe('TranslationLoader', () => { loader.loadBundles( ['/src/locale/messages.en.xlf', '/src/locale/messages.fr.xlf'], [undefined, 'FR']); expect(diagnostics.messages.length).toEqual(1); - expect(diagnostics.messages).toContain({ - type: 'warning', - message: - `The provided locale "FR" does not match the target locale "pl" found in the translation file "/src/locale/messages.fr.xlf".`, - }, ); + expect(diagnostics.messages) + .toContain( + { + type: 'warning', + message: + `The provided locale "FR" does not match the target locale "pl" found in the translation file "/src/locale/messages.fr.xlf".`, + }, + ); }); it('should throw an error if there is no provided nor parsed target locale', () => { diff --git a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts index 869149b1c9017..438106dd4c556 100644 --- a/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts +++ b/packages/localize/src/tools/test/translate/translation_files/translation_parsers/xliff2_translation_parser_spec.ts @@ -421,7 +421,6 @@ describe('Xliff2TranslationParser', () => { .toEqual(ɵmakeParsedTranslation( ['', ' tnemele elbatalsnart ', 'sredlohecalp htiw', ''], ['INTERPOLATION', 'START_BOLD_TEXT', 'CLOSE_BOLD_TEXT'])); - }); describe('[structure errors]', () => { @@ -969,7 +968,6 @@ describe('Xliff2TranslationParser', () => { .toEqual(ɵmakeParsedTranslation( ['', ' tnemele elbatalsnart ', 'sredlohecalp htiw', ''], ['INTERPOLATION', 'START_BOLD_TEXT', 'CLOSE_BOLD_TEXT'])); - }); describe('[structure errors]', () => { diff --git a/packages/localize/src/tools/test/translate/translator_spec.ts b/packages/localize/src/tools/test/translate/translator_spec.ts index 9b1191189c4c2..17acdeba766da 100644 --- a/packages/localize/src/tools/test/translate/translator_spec.ts +++ b/packages/localize/src/tools/test/translate/translator_spec.ts @@ -12,7 +12,6 @@ import {TranslationBundle, TranslationHandler, Translator} from '../../src/trans describe('Translator', () => { describe('translateFiles()', () => { - beforeEach(() => { spyOn(FileUtils, 'readFileBuffer') .and.returnValues(Buffer.from('resource file 1'), Buffer.from('resource file 2')); diff --git a/packages/localize/src/translate.ts b/packages/localize/src/translate.ts index b1f2792063aed..aa045aa378e5f 100644 --- a/packages/localize/src/translate.ts +++ b/packages/localize/src/translate.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {LocalizeFn} from './localize'; -import {MessageId, ParsedTranslation, TargetMessage, parseTranslation, translate as _translate} from './utils'; +import {MessageId, ParsedTranslation, parseTranslation, TargetMessage, translate as _translate} from './utils'; /** * We augment the `$localize` object to also store the translations. diff --git a/packages/localize/src/utils/src/messages.ts b/packages/localize/src/utils/src/messages.ts index a781266e1016d..827c5c242ed98 100644 --- a/packages/localize/src/utils/src/messages.ts +++ b/packages/localize/src/utils/src/messages.ts @@ -131,7 +131,8 @@ export function parseMessage( messageString, meaning: metadata.meaning || '', description: metadata.description || '', - messageParts: cleanedMessageParts, placeholderNames, + messageParts: cleanedMessageParts, + placeholderNames, }; } @@ -176,7 +177,7 @@ export function parseMetadata(cooked: string, raw: string): MessageMetadata { } else { const [meaningDescAndId, ...legacyIds] = block.split(LEGACY_ID_INDICATOR); const [meaningAndDesc, id] = meaningDescAndId.split(ID_SEPARATOR, 2); - let [meaning, description]: (string | undefined)[] = meaningAndDesc.split(MEANING_SEPARATOR, 2); + let [meaning, description]: (string|undefined)[] = meaningAndDesc.split(MEANING_SEPARATOR, 2); if (description === undefined) { description = meaning; meaning = undefined; @@ -236,9 +237,9 @@ function computePlaceholderName(index: number) { */ export function findEndOfBlock(cooked: string, raw: string): number { /************************************************************************************************ - * This function is repeated in `src/localize/src/localize.ts` and the two should be kept in sync. - * (See that file for more explanation of why.) - ************************************************************************************************/ + * This function is repeated in `src/localize/src/localize.ts` and the two should be kept in sync. + * (See that file for more explanation of why.) + ************************************************************************************************/ for (let cookedIndex = 1, rawIndex = 1; cookedIndex < cooked.length; cookedIndex++, rawIndex++) { if (raw[rawIndex] === '\\') { rawIndex++; diff --git a/packages/localize/src/utils/src/translations.ts b/packages/localize/src/utils/src/translations.ts index 4b5c51e3464b4..e638377a7fe91 100644 --- a/packages/localize/src/utils/src/translations.ts +++ b/packages/localize/src/utils/src/translations.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ import {BLOCK_MARKER} from './constants'; -import {MessageId, ParsedMessage, TargetMessage, parseMessage} from './messages'; +import {MessageId, ParsedMessage, parseMessage, TargetMessage} from './messages'; /** @@ -68,8 +68,10 @@ export function translate( return message.substitutions[placeholder]; } else { throw new Error( - `There is a placeholder name mismatch with the translation provided for the message ${describeMessage(message)}.\n` + - `The translation contains a placeholder with name ${placeholder}, which does not exist in the message.`); + `There is a placeholder name mismatch with the translation provided for the message ${ + describeMessage(message)}.\n` + + `The translation contains a placeholder with name ${ + placeholder}, which does not exist in the message.`); } }) ]; diff --git a/packages/localize/src/utils/test/messages_spec.ts b/packages/localize/src/utils/test/messages_spec.ts index 49f6552b07db7..40a55ecc88209 100644 --- a/packages/localize/src/utils/test/messages_spec.ts +++ b/packages/localize/src/utils/test/messages_spec.ts @@ -119,12 +119,12 @@ describe('messages utils', () => { const message = parseMessage(makeTemplateObject(['a', 'b', 'c'], ['a', 'b', 'c']), [1, 2]); expect(message.substitutions).toEqual({PH: 1, PH_1: 2}); }); - }); describe('splitBlock()', () => { - it('should return just the text if there is no block', - () => { expect(splitBlock('abc def', 'abc def')).toEqual({text: 'abc def'}); }); + it('should return just the text if there is no block', () => { + expect(splitBlock('abc def', 'abc def')).toEqual({text: 'abc def'}); + }); it('should return just the text and block if there is one', () => { expect(splitBlock(':block info:abc def', ':block info:abc def')) diff --git a/packages/localize/src/utils/test/translations_spec.ts b/packages/localize/src/utils/test/translations_spec.ts index 267320534d01e..1938e5e6a3d4a 100644 --- a/packages/localize/src/utils/test/translations_spec.ts +++ b/packages/localize/src/utils/test/translations_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {ParsedTranslation, TargetMessage, computeMsgId, makeTemplateObject, parseTranslation, translate} from '..'; +import {computeMsgId, makeTemplateObject, ParsedTranslation, parseTranslation, TargetMessage, translate} from '..'; describe('utils', () => { describe('makeTemplateObject', () => { @@ -80,9 +80,9 @@ describe('utils', () => { describe('translate', () => { it('should throw an error if there is no matching translation', () => { - expect(() => doTranslate({}, parts `abc`)) + expect(() => doTranslate({}, parts`abc`)) .toThrowError('No translation found for "2674653928643152084" ("abc").'); - expect(() => doTranslate({}, parts `:meaning|:abc`)) + expect(() => doTranslate({}, parts`:meaning|:abc`)) .toThrowError('No translation found for "1071947593002928768" ("abc" - "meaning").'); }); @@ -90,7 +90,7 @@ describe('utils', () => { () => { expect( () => doTranslate( - {'abc{$INTERPOLATION}def': 'a{$PH}bc'}, parts `abc${1 + 2}:INTERPOLATION:def`)) + {'abc{$INTERPOLATION}def': 'a{$PH}bc'}, parts`abc${1 + 2}:INTERPOLATION:def`)) .toThrowError( `There is a placeholder name mismatch with the translation provided for the message "8986527425650846693" ("abc{$INTERPOLATION}def").\n` + `The translation contains a placeholder with name PH, which does not exist in the message.`); @@ -104,15 +104,15 @@ describe('utils', () => { 'abc{$PH}def{$PH_1}': 'abc{$PH}def{$PH_1}', 'Hello, {$PH}!': 'Hello, {$PH}!', }; - expect(doTranslate(translations, parts `abc`)).toEqual(parts `abc`); - expect(doTranslate(translations, parts `abc${1 + 2 + 3}`)).toEqual(parts `abc${1 + 2 + 3}`); - expect(doTranslate(translations, parts `abc${1 + 2 + 3}def`)) - .toEqual(parts `abc${1 + 2 + 3}def`); - expect(doTranslate(translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6}`)) - .toEqual(parts `abc${1 + 2 + 3}def${4 + 5 + 6}`); + expect(doTranslate(translations, parts`abc`)).toEqual(parts`abc`); + expect(doTranslate(translations, parts`abc${1 + 2 + 3}`)).toEqual(parts`abc${1 + 2 + 3}`); + expect(doTranslate(translations, parts`abc${1 + 2 + 3}def`)) + .toEqual(parts`abc${1 + 2 + 3}def`); + expect(doTranslate(translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6}`)) + .toEqual(parts`abc${1 + 2 + 3}def${4 + 5 + 6}`); const getName = () => 'World'; - expect(doTranslate(translations, parts `Hello, ${getName()}!`)) - .toEqual(parts `Hello, ${'World'}!`); + expect(doTranslate(translations, parts`Hello, ${getName()}!`)) + .toEqual(parts`Hello, ${'World'}!`); }); it('(with upper-casing translations) should render template literals with messages upper-cased', @@ -124,16 +124,15 @@ describe('utils', () => { 'abc{$PH}def{$PH_1}': 'ABC{$PH}DEF{$PH_1}', 'Hello, {$PH}!': 'HELLO, {$PH}!', }; - expect(doTranslate(translations, parts `abc`)).toEqual(parts `ABC`); - expect(doTranslate(translations, parts `abc${1 + 2 + 3}`)) - .toEqual(parts `ABC${1 + 2 + 3}`); - expect(doTranslate(translations, parts `abc${1 + 2 + 3}def`)) - .toEqual(parts `ABC${1 + 2 + 3}DEF`); - expect(doTranslate(translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6}`)) - .toEqual(parts `ABC${1 + 2 + 3}DEF${4 + 5 + 6}`); + expect(doTranslate(translations, parts`abc`)).toEqual(parts`ABC`); + expect(doTranslate(translations, parts`abc${1 + 2 + 3}`)).toEqual(parts`ABC${1 + 2 + 3}`); + expect(doTranslate(translations, parts`abc${1 + 2 + 3}def`)) + .toEqual(parts`ABC${1 + 2 + 3}DEF`); + expect(doTranslate(translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6}`)) + .toEqual(parts`ABC${1 + 2 + 3}DEF${4 + 5 + 6}`); const getName = () => 'World'; - expect(doTranslate(translations, parts `Hello, ${getName()}!`)) - .toEqual(parts `HELLO, ${'World'}!`); + expect(doTranslate(translations, parts`Hello, ${getName()}!`)) + .toEqual(parts`HELLO, ${'World'}!`); }); it('(with translations to reverse expressions) should render template literals with expressions reversed', @@ -143,8 +142,8 @@ describe('utils', () => { }; const getName = () => 'World'; expect(doTranslate( - translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)) - .toEqual(parts `abc${'World'}def${4 + 5 + 6} - Hello, ${1 + 2 + 3}!`); + translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)) + .toEqual(parts`abc${'World'}def${4 + 5 + 6} - Hello, ${1 + 2 + 3}!`); }); it('(with translations to remove expressions) should render template literals with expressions removed', @@ -154,8 +153,8 @@ describe('utils', () => { }; const getName = () => 'World'; expect(doTranslate( - translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)) - .toEqual(parts `abc${1 + 2 + 3} - Hello, ${'World'}!`); + translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)) + .toEqual(parts`abc${1 + 2 + 3} - Hello, ${'World'}!`); }); function parts(messageParts: TemplateStringsArray, ...substitutions: any[]): @@ -167,7 +166,6 @@ describe('utils', () => { Record<string, ParsedTranslation> { const parsedTranslations: Record<string, ParsedTranslation> = {}; Object.keys(translations).forEach(key => { - parsedTranslations[computeMsgId(key, '')] = parseTranslation(translations[key]); }); return parsedTranslations; diff --git a/packages/localize/test/translate_spec.ts b/packages/localize/test/translate_spec.ts index 246978b4dda8b..9e3a98fb1d932 100644 --- a/packages/localize/test/translate_spec.ts +++ b/packages/localize/test/translate_spec.ts @@ -9,7 +9,7 @@ import '@angular/localize/init'; import {clearTranslations, loadTranslations} from '../localize'; -import {MessageId, TargetMessage, computeMsgId} from '../src/utils'; +import {computeMsgId, MessageId, TargetMessage} from '../src/utils'; describe('$localize tag with translations', () => { describe('identities', () => { @@ -22,15 +22,17 @@ describe('$localize tag with translations', () => { 'Hello, {$PH}!': 'Hello, {$PH}!', })); }); - afterEach(() => { clearTranslations(); }); + afterEach(() => { + clearTranslations(); + }); it('should render template literals as-is', () => { - expect($localize `abc`).toEqual('abc'); - expect($localize `abc${1 + 2 + 3}`).toEqual('abc6'); - expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def'); - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15'); + expect($localize`abc`).toEqual('abc'); + expect($localize`abc${1 + 2 + 3}`).toEqual('abc6'); + expect($localize`abc${1 + 2 + 3}def`).toEqual('abc6def'); + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15'); const getName = () => 'World'; - expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!'); + expect($localize`Hello, ${getName()}!`).toEqual('Hello, World!'); }); }); @@ -44,15 +46,17 @@ describe('$localize tag with translations', () => { 'Hello, {$PH}!': 'HELLO, {$PH}!', })); }); - afterEach(() => { clearTranslations(); }); + afterEach(() => { + clearTranslations(); + }); it('should render template literals with messages upper-cased', () => { - expect($localize `abc`).toEqual('ABC'); - expect($localize `abc${1 + 2 + 3}`).toEqual('ABC6'); - expect($localize `abc${1 + 2 + 3}def`).toEqual('ABC6DEF'); - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15'); + expect($localize`abc`).toEqual('ABC'); + expect($localize`abc${1 + 2 + 3}`).toEqual('ABC6'); + expect($localize`abc${1 + 2 + 3}def`).toEqual('ABC6DEF'); + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15'); const getName = () => 'World'; - expect($localize `Hello, ${getName()}!`).toEqual('HELLO, World!'); + expect($localize`Hello, ${getName()}!`).toEqual('HELLO, World!'); }); }); @@ -62,11 +66,13 @@ describe('$localize tag with translations', () => { 'abc{$PH}def{$PH_1} - Hello, {$PH_2}!': 'abc{$PH_2}def{$PH_1} - Hello, {$PH}!', })); }); - afterEach(() => { clearTranslations(); }); + afterEach(() => { + clearTranslations(); + }); it('should render template literals with expressions reversed', () => { const getName = () => 'World'; - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`) + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`) .toEqual('abcWorlddef15 - Hello, 6!'); }); }); @@ -77,11 +83,13 @@ describe('$localize tag with translations', () => { 'abc{$PH}def{$PH_1} - Hello, {$PH_2}!': 'abc{$PH} - Hello, {$PH_2}!', })); }); - afterEach(() => { clearTranslations(); }); + afterEach(() => { + clearTranslations(); + }); it('should render template literals with expressions removed', () => { const getName = () => 'World'; - expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`) + expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`) .toEqual('abc6 - Hello, World!'); }); }); diff --git a/packages/platform-browser-dynamic/src/compiler_factory.ts b/packages/platform-browser-dynamic/src/compiler_factory.ts index ac0a1ed8d5298..e8540bccf4bb7 100644 --- a/packages/platform-browser-dynamic/src/compiler_factory.ts +++ b/packages/platform-browser-dynamic/src/compiler_factory.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileMetadataResolver, CompileReflector, CompilerConfig, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, ElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitCompiler, JitEvaluator, JitSummaryResolver, Lexer, NgModuleCompiler, NgModuleResolver, Parser, PipeResolver, ProviderMeta, ResourceLoader, StaticSymbolCache, StyleCompiler, SummaryResolver, TemplateParser, UrlResolver, ViewCompiler} from '@angular/compiler'; -import {Compiler, CompilerFactory, CompilerOptions, ComponentFactory, Inject, InjectionToken, Injector, MissingTranslationStrategy, ModuleWithComponentFactories, NgModuleFactory, Optional, PACKAGE_ROOT_URL, StaticProvider, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, isDevMode, ɵConsole as Console} from '@angular/core'; +import {CompileMetadataResolver, CompilerConfig, CompileReflector, DirectiveNormalizer, DirectiveResolver, DomElementSchemaRegistry, ElementSchemaRegistry, HtmlParser, I18NHtmlParser, JitCompiler, JitEvaluator, JitSummaryResolver, Lexer, NgModuleCompiler, NgModuleResolver, Parser, PipeResolver, ProviderMeta, ResourceLoader, StaticSymbolCache, StyleCompiler, SummaryResolver, TemplateParser, UrlResolver, ViewCompiler} from '@angular/compiler'; +import {Compiler, CompilerFactory, CompilerOptions, ComponentFactory, Inject, InjectionToken, Injector, isDevMode, MissingTranslationStrategy, ModuleWithComponentFactories, NgModuleFactory, Optional, PACKAGE_ROOT_URL, StaticProvider, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, ɵConsole as Console} from '@angular/core'; import {JitReflector} from './compiler_reflector'; @@ -22,9 +22,10 @@ export const DEFAULT_PACKAGE_URL_PROVIDER = { }; const _NO_RESOURCE_LOADER: ResourceLoader = { - get(url: string): Promise<string>{ - throw new Error( - `No ResourceLoader implementation has been provided. Can't read the url "${url}"`);} + get(url: string): Promise<string> { + throw new Error( + `No ResourceLoader implementation has been provided. Can't read the url "${url}"`); + } }; const baseHtmlParser = new InjectionToken('HtmlParser'); @@ -71,13 +72,21 @@ export class CompilerImpl implements Compiler { componentFactories: result.componentFactories as ComponentFactory<any>[], })); } - loadAotSummaries(summaries: () => any[]) { this._delegate.loadAotSummaries(summaries); } - hasAotSummary(ref: Type<any>): boolean { return this._delegate.hasAotSummary(ref); } + loadAotSummaries(summaries: () => any[]) { + this._delegate.loadAotSummaries(summaries); + } + hasAotSummary(ref: Type<any>): boolean { + return this._delegate.hasAotSummary(ref); + } getComponentFactory<T>(component: Type<T>): ComponentFactory<T> { return this._delegate.getComponentFactory(component) as ComponentFactory<T>; } - clearCache(): void { this._delegate.clearCache(); } - clearCacheFor(type: Type<any>) { this._delegate.clearCacheFor(type); } + clearCache(): void { + this._delegate.clearCache(); + } + clearCacheFor(type: Type<any>) { + this._delegate.clearCacheFor(type); + } getModuleId(moduleType: Type<any>): string|undefined { const meta = this._metadataResolver.getNgModuleMetadata(moduleType); return meta && meta.id || undefined; @@ -102,13 +111,14 @@ const COMPILER_PROVIDERS__PRE_R3__ = <StaticProvider[]>[ }, { provide: I18NHtmlParser, - useFactory: (parser: HtmlParser, translations: string | null, format: string, - config: CompilerConfig, console: Console) => { - translations = translations || ''; - const missingTranslation = - translations ? config.missingTranslation ! : MissingTranslationStrategy.Ignore; - return new I18NHtmlParser(parser, translations, format, missingTranslation, console); - }, + useFactory: + (parser: HtmlParser, translations: string|null, format: string, config: CompilerConfig, + console: Console) => { + translations = translations || ''; + const missingTranslation = + translations ? config.missingTranslation! : MissingTranslationStrategy.Ignore; + return new I18NHtmlParser(parser, translations, format, missingTranslation, console); + }, deps: [ baseHtmlParser, [new Optional(), new Inject(TRANSLATIONS)], @@ -122,36 +132,38 @@ const COMPILER_PROVIDERS__PRE_R3__ = <StaticProvider[]>[ useExisting: I18NHtmlParser, }, { - provide: TemplateParser, deps: [CompilerConfig, CompileReflector, - Parser, ElementSchemaRegistry, - I18NHtmlParser, Console] + provide: TemplateParser, + deps: [CompilerConfig, CompileReflector, Parser, ElementSchemaRegistry, I18NHtmlParser, Console] + }, + {provide: JitEvaluator, useClass: JitEvaluator, deps: []}, + {provide: DirectiveNormalizer, deps: [ResourceLoader, UrlResolver, HtmlParser, CompilerConfig]}, + { + provide: CompileMetadataResolver, + deps: [ + CompilerConfig, HtmlParser, NgModuleResolver, DirectiveResolver, PipeResolver, + SummaryResolver, ElementSchemaRegistry, DirectiveNormalizer, Console, + [Optional, StaticSymbolCache], CompileReflector, [Optional, ERROR_COLLECTOR_TOKEN] + ] }, - { provide: JitEvaluator, useClass: JitEvaluator, deps: [] }, - { provide: DirectiveNormalizer, deps: [ResourceLoader, UrlResolver, HtmlParser, CompilerConfig]}, - { provide: CompileMetadataResolver, deps: [CompilerConfig, HtmlParser, NgModuleResolver, - DirectiveResolver, PipeResolver, - SummaryResolver, - ElementSchemaRegistry, - DirectiveNormalizer, Console, - [Optional, StaticSymbolCache], - CompileReflector, - [Optional, ERROR_COLLECTOR_TOKEN]]}, DEFAULT_PACKAGE_URL_PROVIDER, - { provide: StyleCompiler, deps: [UrlResolver]}, - { provide: ViewCompiler, deps: [CompileReflector]}, - { provide: NgModuleCompiler, deps: [CompileReflector] }, - { provide: CompilerConfig, useValue: new CompilerConfig()}, - { provide: Compiler, useClass: CompilerImpl, deps: [Injector, CompileMetadataResolver, - TemplateParser, StyleCompiler, - ViewCompiler, NgModuleCompiler, - SummaryResolver, CompileReflector, JitEvaluator, CompilerConfig, - Console]}, - { provide: DomElementSchemaRegistry, deps: []}, - { provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry}, - { provide: UrlResolver, deps: [PACKAGE_ROOT_URL]}, - { provide: DirectiveResolver, deps: [CompileReflector]}, - { provide: PipeResolver, deps: [CompileReflector]}, - { provide: NgModuleResolver, deps: [CompileReflector]}, + {provide: StyleCompiler, deps: [UrlResolver]}, + {provide: ViewCompiler, deps: [CompileReflector]}, + {provide: NgModuleCompiler, deps: [CompileReflector]}, + {provide: CompilerConfig, useValue: new CompilerConfig()}, + { + provide: Compiler, + useClass: CompilerImpl, + deps: [ + Injector, CompileMetadataResolver, TemplateParser, StyleCompiler, ViewCompiler, + NgModuleCompiler, SummaryResolver, CompileReflector, JitEvaluator, CompilerConfig, Console + ] + }, + {provide: DomElementSchemaRegistry, deps: []}, + {provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry}, + {provide: UrlResolver, deps: [PACKAGE_ROOT_URL]}, + {provide: DirectiveResolver, deps: [CompileReflector]}, + {provide: PipeResolver, deps: [CompileReflector]}, + {provide: NgModuleResolver, deps: [CompileReflector]}, ]; export const COMPILER_PROVIDERS__POST_R3__ = @@ -193,7 +205,7 @@ export class JitCompilerFactory implements CompilerFactory { }, deps: [] }, - opts.providers ! + opts.providers! ]); return injector.get(Compiler); } @@ -203,7 +215,7 @@ function _mergeOptions(optionsArr: CompilerOptions[]): CompilerOptions { return { useJit: _lastDefined(optionsArr.map(options => options.useJit)), defaultEncapsulation: _lastDefined(optionsArr.map(options => options.defaultEncapsulation)), - providers: _mergeArrays(optionsArr.map(options => options.providers !)), + providers: _mergeArrays(optionsArr.map(options => options.providers!)), missingTranslation: _lastDefined(optionsArr.map(options => options.missingTranslation)), preserveWhitespaces: _lastDefined(optionsArr.map(options => options.preserveWhitespaces)), }; diff --git a/packages/platform-browser-dynamic/src/compiler_reflector.ts b/packages/platform-browser-dynamic/src/compiler_reflector.ts index 25904ae730219..3ac0515f2f0ec 100644 --- a/packages/platform-browser-dynamic/src/compiler_reflector.ts +++ b/packages/platform-browser-dynamic/src/compiler_reflector.ts @@ -6,8 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {CompileReflector, ExternalReference, Identifiers, getUrlScheme, syntaxError} from '@angular/compiler'; -import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, NgModuleRef, QueryList, Renderer2, SecurityContext, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation, ɵCodegenComponentFactoryResolver, ɵEMPTY_ARRAY, ɵEMPTY_MAP, ɵReflectionCapabilities as ReflectionCapabilities, ɵand, ɵccf, ɵcmf, ɵcrt, ɵdid, ɵeld, ɵinlineInterpolate, ɵinterpolate, ɵmod, ɵmpd, ɵncd, ɵnov, ɵpad, ɵpid, ɵpod, ɵppd, ɵprd, ɵqud, ɵregisterModuleFactory, ɵstringify as stringify, ɵted, ɵunv, ɵvid} from '@angular/core'; +import {CompileReflector, ExternalReference, getUrlScheme, Identifiers, syntaxError} from '@angular/compiler'; +import {ANALYZE_FOR_ENTRY_COMPONENTS, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, NgModuleRef, QueryList, Renderer2, SecurityContext, TemplateRef, TRANSLATIONS_FORMAT, ViewContainerRef, ViewEncapsulation, ɵand, ɵccf, ɵcmf, ɵCodegenComponentFactoryResolver, ɵcrt, ɵdid, ɵeld, ɵEMPTY_ARRAY, ɵEMPTY_MAP, ɵinlineInterpolate, ɵinterpolate, ɵmod, ɵmpd, ɵncd, ɵnov, ɵpad, ɵpid, ɵpod, ɵppd, ɵprd, ɵqud, ɵReflectionCapabilities as ReflectionCapabilities, ɵregisterModuleFactory, ɵstringify as stringify, ɵted, ɵunv, ɵvid} from '@angular/core'; export const MODULE_SUFFIX = ''; const builtinExternalReferences = createBuiltinExternalReferencesMap(); @@ -23,7 +23,8 @@ export class JitReflector implements CompileReflector { return scheme ? moduleId : `package:${moduleId}${MODULE_SUFFIX}`; } else if (moduleId !== null && moduleId !== void 0) { throw syntaxError( - `moduleId should be a string in "${stringify(type)}". See https://goo.gl/wIDDiL for more information.\n` + + `moduleId should be a string in "${ + stringify(type)}". See https://goo.gl/wIDDiL for more information.\n` + `If you're using Webpack you should inline the template and the styles, see https://goo.gl/X2J8zc.`); } @@ -32,7 +33,9 @@ export class JitReflector implements CompileReflector { parameters(typeOrFunc: /*Type*/ any): any[][] { return this.reflectionCapabilities.parameters(typeOrFunc); } - tryAnnotations(typeOrFunc: /*Type*/ any): any[] { return this.annotations(typeOrFunc); } + tryAnnotations(typeOrFunc: /*Type*/ any): any[] { + return this.annotations(typeOrFunc); + } annotations(typeOrFunc: /*Type*/ any): any[] { return this.reflectionCapabilities.annotations(typeOrFunc); } @@ -45,7 +48,9 @@ export class JitReflector implements CompileReflector { hasLifecycleHook(type: any, lcProperty: string): boolean { return this.reflectionCapabilities.hasLifecycleHook(type, lcProperty); } - guards(type: any): {[key: string]: any} { return this.reflectionCapabilities.guards(type); } + guards(type: any): {[key: string]: any} { + return this.reflectionCapabilities.guards(type); + } resolveExternalReference(ref: ExternalReference): any { return builtinExternalReferences.get(ref) || ref.runtime; } diff --git a/packages/platform-browser-dynamic/src/platform-browser-dynamic.ts b/packages/platform-browser-dynamic/src/platform-browser-dynamic.ts index f34d09d475733..322f51ad7c54a 100644 --- a/packages/platform-browser-dynamic/src/platform-browser-dynamic.ts +++ b/packages/platform-browser-dynamic/src/platform-browser-dynamic.ts @@ -7,7 +7,7 @@ */ import {ResourceLoader} from '@angular/compiler'; -import {CompilerFactory, PlatformRef, Provider, StaticProvider, createPlatformFactory, platformCore} from '@angular/core'; +import {CompilerFactory, createPlatformFactory, platformCore, PlatformRef, Provider, StaticProvider} from '@angular/core'; import {platformCoreDynamic} from './platform_core_dynamic'; import {INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from './platform_providers'; diff --git a/packages/platform-browser-dynamic/src/platform_core_dynamic.ts b/packages/platform-browser-dynamic/src/platform_core_dynamic.ts index b035b7b0245ee..3a0a63f457ec2 100644 --- a/packages/platform-browser-dynamic/src/platform_core_dynamic.ts +++ b/packages/platform-browser-dynamic/src/platform_core_dynamic.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {COMPILER_OPTIONS, CompilerFactory, PlatformRef, StaticProvider, createPlatformFactory, platformCore} from '@angular/core'; +import {COMPILER_OPTIONS, CompilerFactory, createPlatformFactory, platformCore, PlatformRef, StaticProvider} from '@angular/core'; + import {JitCompilerFactory} from './compiler_factory'; /** diff --git a/packages/platform-browser-dynamic/src/resource_loader/resource_loader_impl.ts b/packages/platform-browser-dynamic/src/resource_loader/resource_loader_impl.ts index 4e5dfd6e5e3b9..812914a7dd9dc 100644 --- a/packages/platform-browser-dynamic/src/resource_loader/resource_loader_impl.ts +++ b/packages/platform-browser-dynamic/src/resource_loader/resource_loader_impl.ts @@ -45,7 +45,9 @@ export class ResourceLoaderImpl extends ResourceLoader { } }; - xhr.onerror = function() { reject(`Failed to load ${url}`); }; + xhr.onerror = function() { + reject(`Failed to load ${url}`); + }; xhr.send(); return promise; diff --git a/packages/platform-browser-dynamic/test/metadata_overrider_spec.ts b/packages/platform-browser-dynamic/test/metadata_overrider_spec.ts index 42933442a7f2d..3bf4c38979e5a 100644 --- a/packages/platform-browser-dynamic/test/metadata_overrider_spec.ts +++ b/packages/platform-browser-dynamic/test/metadata_overrider_spec.ts @@ -25,9 +25,9 @@ class SomeMetadata implements SomeMetadataType { arrayProp: any[]; constructor(options: SomeMetadataType) { - this.plainProp = options.plainProp !; - this._getterProp = options.getterProp !; - this.arrayProp = options.arrayProp !; + this.plainProp = options.plainProp!; + this._getterProp = options.getterProp!; + this.arrayProp = options.arrayProp!; Object.defineProperty(this, 'getterProp', { enumerable: true, // getters are non-enumerable by default in es2015 get: () => this._getterProp, @@ -45,7 +45,7 @@ class OtherMetadata extends SomeMetadata implements OtherMetadataType { arrayProp: options.arrayProp }); - this.otherPlainProp = options.otherPlainProp !; + this.otherPlainProp = options.otherPlainProp!; } } @@ -53,7 +53,9 @@ class OtherMetadata extends SomeMetadata implements OtherMetadataType { describe('metadata overrider', () => { let overrider: MetadataOverrider; - beforeEach(() => { overrider = new MetadataOverrider(); }); + beforeEach(() => { + overrider = new MetadataOverrider(); + }); it('should return a new instance with the same values', () => { const oldInstance = new SomeMetadata({plainProp: 'somePlainProp', getterProp: 'someInput'}); @@ -130,7 +132,6 @@ class OtherMetadata extends SomeMetadata implements OtherMetadataType { const instance3 = overrider.overrideMetadata(SomeMetadata, instance2, {remove: {arrayProp: [Class3]}}); expect(instance3).toEqual(new SomeMetadata({arrayProp: [Class2]})); - }); }); @@ -149,7 +150,6 @@ class OtherMetadata extends SomeMetadata implements OtherMetadataType { otherPlainProp: 'newOtherProp' })); }); - }); }); } diff --git a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts index 316152f7b9115..4caf9e57f24b3 100644 --- a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts +++ b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_cache_spec.ts @@ -8,7 +8,7 @@ import {ResourceLoader, UrlResolver} from '@angular/compiler'; import {Component} from '@angular/core'; -import {TestBed, async, fakeAsync, tick} from '@angular/core/testing'; +import {async, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {CachedResourceLoader} from '@angular/platform-browser-dynamic/src/resource_loader/resource_loader_cache'; import {setTemplateCache} from '@angular/platform-browser-dynamic/test/resource_loader/resource_loader_cache_setter'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -31,7 +31,9 @@ if (isBrowser) { it('should resolve the Promise with the cached file content on success', async(() => { resourceLoader = createCachedResourceLoader(); - resourceLoader.get('test.html').then((text) => { expect(text).toBe('<div>Hello</div>'); }); + resourceLoader.get('test.html').then((text) => { + expect(text).toBe('<div>Hello</div>'); + }); })); it('should reject the Promise on failure', async(() => { diff --git a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts index 480cb97de176c..feef70f34969f 100644 --- a/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts +++ b/packages/platform-browser-dynamic/test/resource_loader/resource_loader_impl_spec.ts @@ -22,7 +22,9 @@ if (isBrowser) { const url200 = '/base/angular/packages/platform-browser/test/browser/static_assets/200.html'; const url404 = '/bad/path/404.html'; - beforeEach(() => { resourceLoader = new ResourceLoaderImpl(); }); + beforeEach(() => { + resourceLoader = new ResourceLoaderImpl(); + }); it('should resolve the Promise with the file content on success', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { diff --git a/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts b/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts index 7bac854e87361..6adde8f4a4771 100644 --- a/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts +++ b/packages/platform-browser-dynamic/test/testing_public_browser_spec.ts @@ -8,8 +8,7 @@ import {ResourceLoader} from '@angular/compiler'; import {Compiler, Component, NgModule} from '@angular/core'; -import {TestBed, async, fakeAsync, inject, tick} from '@angular/core/testing'; - +import {async, fakeAsync, inject, TestBed, tick} from '@angular/core/testing'; import {ResourceLoaderImpl} from '@angular/platform-browser-dynamic/src/resource_loader/resource_loader_impl'; @@ -17,10 +16,15 @@ import {ResourceLoaderImpl} from '@angular/platform-browser-dynamic/src/resource // Components for the tests. class FancyService { value: string = 'real value'; - getAsyncValue() { return Promise.resolve('async value'); } + getAsyncValue() { + return Promise.resolve('async value'); + } getTimeoutValue() { - return new Promise( - (resolve, reject) => { setTimeout(() => { resolve('timeout value'); }, 10); }); + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve('timeout value'); + }, 10); + }); } } @@ -42,15 +46,21 @@ if (isBrowser) { describe('using the async helper', () => { let actuallyDone: boolean; - beforeEach(() => { actuallyDone = false; }); + beforeEach(() => { + actuallyDone = false; + }); - afterEach(() => { expect(actuallyDone).toEqual(true); }); + afterEach(() => { + expect(actuallyDone).toEqual(true); + }); it('should run async tests with ResourceLoaders', async(() => { const resourceLoader = new ResourceLoaderImpl(); resourceLoader .get('/base/angular/packages/platform-browser/test/static_assets/test.html') - .then(() => { actuallyDone = true; }); + .then(() => { + actuallyDone = true; + }); }), 10000); // Long timeout here because this test makes an actual ResourceLoader. }); @@ -70,7 +80,9 @@ if (isBrowser) { it('should allow the use of fakeAsync', fakeAsync(inject([FancyService], (service: any /** TODO #9100 */) => { let value: any /** TODO #9100 */; - service.getAsyncValue().then(function(val: any /** TODO #9100 */) { value = val; }); + service.getAsyncValue().then(function(val: any /** TODO #9100 */) { + value = val; + }); tick(); expect(value).toEqual('async value'); }))); @@ -113,7 +125,9 @@ if (isBrowser) { return promise; }; - const restoreJasmineIt = () => { jasmine.getEnv().it = originalJasmineIt; }; + const restoreJasmineIt = () => { + jasmine.getEnv().it = originalJasmineIt; + }; it('should fail when an ResourceLoader fails', done => { const itPromise = patchJasmineIt(); @@ -124,7 +138,9 @@ if (isBrowser) { })); itPromise.then( - () => { done.fail('Expected test to fail, but it did not'); }, + () => { + done.fail('Expected test to fail, but it did not'); + }, (err: any) => { expect(err.message) .toEqual('Uncaught (in promise): Failed to load non-existent.html'); diff --git a/packages/platform-browser-dynamic/testing/src/compiler_factory.ts b/packages/platform-browser-dynamic/testing/src/compiler_factory.ts index 28fcfde2b2f32..1f5ff43e85eda 100644 --- a/packages/platform-browser-dynamic/testing/src/compiler_factory.ts +++ b/packages/platform-browser-dynamic/testing/src/compiler_factory.ts @@ -39,7 +39,9 @@ export class TestingCompilerImpl implements TestingCompiler { constructor( private _compiler: CompilerImpl, private _directiveResolver: MockDirectiveResolver, private _pipeResolver: MockPipeResolver, private _moduleResolver: MockNgModuleResolver) {} - get injector(): Injector { return this._compiler.injector; } + get injector(): Injector { + return this._compiler.injector; + } compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> { return this._compiler.compileModuleSync(moduleType); @@ -78,14 +80,14 @@ export class TestingCompilerImpl implements TestingCompiler { this.checkOverrideAllowed(directive); const oldMetadata = this._directiveResolver.resolve(directive, false); this._directiveResolver.setDirective( - directive, this._overrider.overrideMetadata(Directive, oldMetadata !, override)); + directive, this._overrider.overrideMetadata(Directive, oldMetadata!, override)); this.clearCacheFor(directive); } overrideComponent(component: Type<any>, override: MetadataOverride<Component>): void { this.checkOverrideAllowed(component); const oldMetadata = this._directiveResolver.resolve(component, false); this._directiveResolver.setDirective( - component, this._overrider.overrideMetadata(Component, oldMetadata !, override)); + component, this._overrider.overrideMetadata(Component, oldMetadata!, override)); this.clearCacheFor(component); } overridePipe(pipe: Type<any>, override: MetadataOverride<Pipe>): void { @@ -94,11 +96,19 @@ export class TestingCompilerImpl implements TestingCompiler { this._pipeResolver.setPipe(pipe, this._overrider.overrideMetadata(Pipe, oldMetadata, override)); this.clearCacheFor(pipe); } - loadAotSummaries(summaries: () => any[]) { this._compiler.loadAotSummaries(summaries); } - clearCache(): void { this._compiler.clearCache(); } - clearCacheFor(type: Type<any>) { this._compiler.clearCacheFor(type); } + loadAotSummaries(summaries: () => any[]) { + this._compiler.loadAotSummaries(summaries); + } + clearCache(): void { + this._compiler.clearCache(); + } + clearCacheFor(type: Type<any>) { + this._compiler.clearCacheFor(type); + } - getComponentFromError(error: Error) { return (error as any)[ERROR_COMPONENT_TYPE] || null; } + getComponentFromError(error: Error) { + return (error as any)[ERROR_COMPONENT_TYPE] || null; + } getModuleId(moduleType: Type<any>): string|undefined { return this._moduleResolver.resolve(moduleType, true).id; diff --git a/packages/platform-browser-dynamic/testing/src/dom_test_component_renderer.ts b/packages/platform-browser-dynamic/testing/src/dom_test_component_renderer.ts index 46e3ea96abf2f..33e55e07bae37 100644 --- a/packages/platform-browser-dynamic/testing/src/dom_test_component_renderer.ts +++ b/packages/platform-browser-dynamic/testing/src/dom_test_component_renderer.ts @@ -15,7 +15,9 @@ import {TestComponentRenderer} from '@angular/core/testing'; */ @Injectable() export class DOMTestComponentRenderer extends TestComponentRenderer { - constructor(@Inject(DOCUMENT) private _doc: any) { super(); } + constructor(@Inject(DOCUMENT) private _doc: any) { + super(); + } insertRootElement(rootElId: string) { const template = getDOM().getDefaultDocument().createElement('template'); diff --git a/packages/platform-browser-dynamic/testing/src/platform_core_dynamic_testing.ts b/packages/platform-browser-dynamic/testing/src/platform_core_dynamic_testing.ts index 7e7f24266efa2..1c540f5fad1ec 100644 --- a/packages/platform-browser-dynamic/testing/src/platform_core_dynamic_testing.ts +++ b/packages/platform-browser-dynamic/testing/src/platform_core_dynamic_testing.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {COMPILER_OPTIONS, CompilerFactory, Injector, PlatformRef, createPlatformFactory} from '@angular/core'; +import {COMPILER_OPTIONS, CompilerFactory, createPlatformFactory, Injector, PlatformRef} from '@angular/core'; import {ɵTestingCompilerFactory as TestingCompilerFactory} from '@angular/core/testing'; import {ɵplatformCoreDynamic as platformCoreDynamic} from '@angular/platform-browser-dynamic'; diff --git a/packages/platform-browser-dynamic/testing/src/testing.ts b/packages/platform-browser-dynamic/testing/src/testing.ts index 9454590a91e54..8109454b4b1c2 100644 --- a/packages/platform-browser-dynamic/testing/src/testing.ts +++ b/packages/platform-browser-dynamic/testing/src/testing.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {NgModule, PlatformRef, StaticProvider, createPlatformFactory} from '@angular/core'; +import {createPlatformFactory, NgModule, PlatformRef, StaticProvider} from '@angular/core'; import {TestComponentRenderer} from '@angular/core/testing'; import {ɵINTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS as INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from '@angular/platform-browser-dynamic'; import {BrowserTestingModule} from '@angular/platform-browser/testing'; diff --git a/packages/platform-browser/animations/src/animation_builder.ts b/packages/platform-browser/animations/src/animation_builder.ts index 2028af8bbb22b..b705d54623394 100644 --- a/packages/platform-browser/animations/src/animation_builder.ts +++ b/packages/platform-browser/animations/src/animation_builder.ts @@ -18,12 +18,9 @@ export class BrowserAnimationBuilder extends AnimationBuilder { constructor(rootRenderer: RendererFactory2, @Inject(DOCUMENT) doc: any) { super(); - const typeData = { - id: '0', - encapsulation: ViewEncapsulation.None, - styles: [], - data: {animation: []} - } as RendererType2; + const typeData = + {id: '0', encapsulation: ViewEncapsulation.None, styles: [], data: {animation: []}} as + RendererType2; this._renderer = rootRenderer.createRenderer(doc.body, typeData) as AnimationRenderer; } @@ -37,7 +34,9 @@ export class BrowserAnimationBuilder extends AnimationBuilder { } export class BrowserAnimationFactory extends AnimationFactory { - constructor(private _id: string, private _renderer: AnimationRenderer) { super(); } + constructor(private _id: string, private _renderer: AnimationRenderer) { + super(); + } create(element: any, options?: AnimationOptions): AnimationPlayer { return new RendererAnimationPlayer(this._id, element, options || {}, this._renderer); @@ -62,34 +61,58 @@ export class RendererAnimationPlayer implements AnimationPlayer { return issueAnimationCommand(this._renderer, this.element, this.id, command, args); } - onDone(fn: () => void): void { this._listen('done', fn); } + onDone(fn: () => void): void { + this._listen('done', fn); + } - onStart(fn: () => void): void { this._listen('start', fn); } + onStart(fn: () => void): void { + this._listen('start', fn); + } - onDestroy(fn: () => void): void { this._listen('destroy', fn); } + onDestroy(fn: () => void): void { + this._listen('destroy', fn); + } - init(): void { this._command('init'); } + init(): void { + this._command('init'); + } - hasStarted(): boolean { return this._started; } + hasStarted(): boolean { + return this._started; + } play(): void { this._command('play'); this._started = true; } - pause(): void { this._command('pause'); } + pause(): void { + this._command('pause'); + } - restart(): void { this._command('restart'); } + restart(): void { + this._command('restart'); + } - finish(): void { this._command('finish'); } + finish(): void { + this._command('finish'); + } - destroy(): void { this._command('destroy'); } + destroy(): void { + this._command('destroy'); + } - reset(): void { this._command('reset'); } + reset(): void { + this._command('reset'); + } - setPosition(p: number): void { this._command('setPosition', p); } + setPosition(p: number): void { + this._command('setPosition', p); + } - getPosition(): number { return 0; } + getPosition(): number { + return 0; + } public totalTime = 0; } diff --git a/packages/platform-browser/animations/src/animation_renderer.ts b/packages/platform-browser/animations/src/animation_renderer.ts index 02ae8cf58d853..af2f739b111cc 100644 --- a/packages/platform-browser/animations/src/animation_renderer.ts +++ b/packages/platform-browser/animations/src/animation_renderer.ts @@ -15,7 +15,7 @@ const DISABLE_ANIMATIONS_FLAG = '@.disabled'; // Define a recursive type to allow for nested arrays of `AnimationTriggerMetadata`. Note that an // interface declaration is used as TypeScript prior to 3.7 does not support recursive type // references, see https://github.com/microsoft/TypeScript/pull/33050 for details. -type NestedAnimationTriggerMetadata = AnimationTriggerMetadata | RecursiveAnimationTriggerMetadata; +type NestedAnimationTriggerMetadata = AnimationTriggerMetadata|RecursiveAnimationTriggerMetadata; interface RecursiveAnimationTriggerMetadata extends Array<NestedAnimationTriggerMetadata> {} @Injectable() @@ -84,7 +84,9 @@ export class AnimationRendererFactory implements RendererFactory2 { private _scheduleCountTask() { // always use promise to schedule microtask instead of use Zone - this.promise.then(() => { this._microtaskId++; }); + this.promise.then(() => { + this._microtaskId++; + }); } /** @internal */ @@ -125,16 +127,20 @@ export class AnimationRendererFactory implements RendererFactory2 { } } - whenRenderingDone(): Promise<any> { return this.engine.whenRenderingDone(); } + whenRenderingDone(): Promise<any> { + return this.engine.whenRenderingDone(); + } } export class BaseAnimationRenderer implements Renderer2 { constructor( protected namespaceId: string, public delegate: Renderer2, public engine: AnimationEngine) { - this.destroyNode = this.delegate.destroyNode ? (n) => delegate.destroyNode !(n) : null; + this.destroyNode = this.delegate.destroyNode ? (n) => delegate.destroyNode!(n) : null; } - get data() { return this.delegate.data; } + get data() { + return this.delegate.data; + } destroyNode: ((n: any) => void)|null; @@ -147,9 +153,13 @@ export class BaseAnimationRenderer implements Renderer2 { return this.delegate.createElement(name, namespace); } - createComment(value: string) { return this.delegate.createComment(value); } + createComment(value: string) { + return this.delegate.createComment(value); + } - createText(value: string) { return this.delegate.createText(value); } + createText(value: string) { + return this.delegate.createText(value); + } appendChild(parent: any, newChild: any): void { this.delegate.appendChild(parent, newChild); @@ -169,9 +179,13 @@ export class BaseAnimationRenderer implements Renderer2 { return this.delegate.selectRootElement(selectorOrNode, preserveContent); } - parentNode(node: any) { return this.delegate.parentNode(node); } + parentNode(node: any) { + return this.delegate.parentNode(node); + } - nextSibling(node: any) { return this.delegate.nextSibling(node); } + nextSibling(node: any) { + return this.delegate.nextSibling(node); + } setAttribute(el: any, name: string, value: string, namespace?: string|null|undefined): void { this.delegate.setAttribute(el, name, value, namespace); @@ -181,9 +195,13 @@ export class BaseAnimationRenderer implements Renderer2 { this.delegate.removeAttribute(el, name, namespace); } - addClass(el: any, name: string): void { this.delegate.addClass(el, name); } + addClass(el: any, name: string): void { + this.delegate.addClass(el, name); + } - removeClass(el: any, name: string): void { this.delegate.removeClass(el, name); } + removeClass(el: any, name: string): void { + this.delegate.removeClass(el, name); + } setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2|undefined): void { this.delegate.setStyle(el, style, value, flags); @@ -201,7 +219,9 @@ export class BaseAnimationRenderer implements Renderer2 { } } - setValue(node: any, value: string): void { this.delegate.setValue(node, value); } + setValue(node: any, value: string): void { + this.delegate.setValue(node, value); + } listen(target: any, eventName: string, callback: (event: any) => boolean | void): () => void { return this.delegate.listen(target, eventName, callback); @@ -253,7 +273,7 @@ export class AnimationRenderer extends BaseAnimationRenderer implements Renderer } } -function resolveElementFromTarget(target: 'window' | 'document' | 'body' | any): any { +function resolveElementFromTarget(target: 'window'|'document'|'body'|any): any { switch (target) { case 'body': return document.body; diff --git a/packages/platform-browser/animations/src/providers.ts b/packages/platform-browser/animations/src/providers.ts index 1df032529a878..105f7ced1311a 100644 --- a/packages/platform-browser/animations/src/providers.ts +++ b/packages/platform-browser/animations/src/providers.ts @@ -7,7 +7,7 @@ */ import {AnimationBuilder} from '@angular/animations'; -import {AnimationDriver, ɵAnimationEngine as AnimationEngine, ɵAnimationStyleNormalizer as AnimationStyleNormalizer, ɵCssKeyframesDriver as CssKeyframesDriver, ɵNoopAnimationDriver as NoopAnimationDriver, ɵWebAnimationsDriver as WebAnimationsDriver, ɵWebAnimationsStyleNormalizer as WebAnimationsStyleNormalizer, ɵsupportsWebAnimations as supportsWebAnimations} from '@angular/animations/browser'; +import {AnimationDriver, ɵAnimationEngine as AnimationEngine, ɵAnimationStyleNormalizer as AnimationStyleNormalizer, ɵCssKeyframesDriver as CssKeyframesDriver, ɵNoopAnimationDriver as NoopAnimationDriver, ɵsupportsWebAnimations as supportsWebAnimations, ɵWebAnimationsDriver as WebAnimationsDriver, ɵWebAnimationsStyleNormalizer as WebAnimationsStyleNormalizer} from '@angular/animations/browser'; import {DOCUMENT} from '@angular/common'; import {Inject, Injectable, InjectionToken, NgZone, Provider, RendererFactory2} from '@angular/core'; import {ɵDomRendererFactory2 as DomRendererFactory2} from '@angular/platform-browser'; diff --git a/packages/platform-browser/animations/test/animation_renderer_spec.ts b/packages/platform-browser/animations/test/animation_renderer_spec.ts index 6b5b49fa09021..44da1541af4b3 100644 --- a/packages/platform-browser/animations/test/animation_renderer_spec.ts +++ b/packages/platform-browser/animations/test/animation_renderer_spec.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AnimationPlayer, AnimationTriggerMetadata, animate, state, style, transition, trigger} from '@angular/animations'; +import {animate, AnimationPlayer, AnimationTriggerMetadata, state, style, transition, trigger} from '@angular/animations'; import {ɵAnimationEngine as AnimationEngine} from '@angular/animations/browser'; import {Component, Injectable, NgZone, RendererFactory2, RendererType2, ViewChild} from '@angular/core'; import {TestBed} from '@angular/core/testing'; @@ -15,309 +15,314 @@ import {DomRendererFactory2} from '@angular/platform-browser/src/dom/dom_rendere import {el} from '../../testing/src/browser_util'; (function() { - if (isNode) return; - describe('AnimationRenderer', () => { - let element: any; - beforeEach(() => { - element = el('<div></div>'); - - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: MockAnimationEngine}], - imports: [BrowserAnimationsModule] - }); +if (isNode) return; +describe('AnimationRenderer', () => { + let element: any; + beforeEach(() => { + element = el('<div></div>'); + + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: MockAnimationEngine}], + imports: [BrowserAnimationsModule] }); + }); - function makeRenderer(animationTriggers: any[] = []) { - const type = <RendererType2>{ - id: 'id', - encapsulation: null !, - styles: [], - data: {'animation': animationTriggers} - }; - return (TestBed.inject(RendererFactory2) as AnimationRendererFactory) - .createRenderer(element, type); - } + function makeRenderer(animationTriggers: any[] = []) { + const type = <RendererType2>{ + id: 'id', + encapsulation: null!, + styles: [], + data: {'animation': animationTriggers} + }; + return (TestBed.inject(RendererFactory2) as AnimationRendererFactory) + .createRenderer(element, type); + } - it('should hook into the engine\'s insert operations when appending children', () => { - const renderer = makeRenderer(); - const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; - const container = el('<div></div>'); + it('should hook into the engine\'s insert operations when appending children', () => { + const renderer = makeRenderer(); + const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; + const container = el('<div></div>'); - renderer.appendChild(container, element); - expect(engine.captures['onInsert'].pop()).toEqual([element]); - }); + renderer.appendChild(container, element); + expect(engine.captures['onInsert'].pop()).toEqual([element]); + }); - it('should hook into the engine\'s insert operations when inserting a child before another', - () => { - const renderer = makeRenderer(); - const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; - const container = el('<div></div>'); - const element2 = el('<div></div>'); - container.appendChild(element2); + it('should hook into the engine\'s insert operations when inserting a child before another', + () => { + const renderer = makeRenderer(); + const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; + const container = el('<div></div>'); + const element2 = el('<div></div>'); + container.appendChild(element2); + + renderer.insertBefore(container, element, element2); + expect(engine.captures['onInsert'].pop()).toEqual([element]); + }); + + it('should hook into the engine\'s insert operations when removing children', () => { + const renderer = makeRenderer(); + const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; + const container = el('<div></div>'); + + renderer.removeChild(container, element); + expect(engine.captures['onRemove'].pop()).toEqual([element]); + }); - renderer.insertBefore(container, element, element2); - expect(engine.captures['onInsert'].pop()).toEqual([element]); - }); + it('should hook into the engine\'s setProperty call if the property begins with `@`', () => { + const renderer = makeRenderer(); + const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; - it('should hook into the engine\'s insert operations when removing children', () => { - const renderer = makeRenderer(); - const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; - const container = el('<div></div>'); + renderer.setProperty(element, 'prop', 'value'); + expect(engine.captures['setProperty']).toBeFalsy(); - renderer.removeChild(container, element); - expect(engine.captures['onRemove'].pop()).toEqual([element]); - }); + renderer.setProperty(element, '@prop', 'value'); + expect(engine.captures['setProperty'].pop()).toEqual([element, 'prop', 'value']); + }); - it('should hook into the engine\'s setProperty call if the property begins with `@`', () => { - const renderer = makeRenderer(); - const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; + // https://github.com/angular/angular/issues/32794 + it('should support nested animation triggers', () => { + makeRenderer([[trigger('myAnimation', [])]]); - renderer.setProperty(element, 'prop', 'value'); - expect(engine.captures['setProperty']).toBeFalsy(); + const {triggers} = TestBed.inject(AnimationEngine) as MockAnimationEngine; - renderer.setProperty(element, '@prop', 'value'); - expect(engine.captures['setProperty'].pop()).toEqual([element, 'prop', 'value']); - }); + expect(triggers.length).toEqual(1); + expect(triggers[0].name).toEqual('myAnimation'); + }); + + describe('listen', () => { + it('should hook into the engine\'s listen call if the property begins with `@`', () => { + const renderer = makeRenderer(); + const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; - // https://github.com/angular/angular/issues/32794 - it('should support nested animation triggers', () => { - makeRenderer([[trigger('myAnimation', [])]]); + const cb = (event: any): boolean => { + return true; + }; - const {triggers} = TestBed.inject(AnimationEngine) as MockAnimationEngine; + renderer.listen(element, 'event', cb); + expect(engine.captures['listen']).toBeFalsy(); - expect(triggers.length).toEqual(1); - expect(triggers[0].name).toEqual('myAnimation'); + renderer.listen(element, '@event.phase', cb); + expect(engine.captures['listen'].pop()).toEqual([element, 'event', 'phase']); }); - describe('listen', () => { - it('should hook into the engine\'s listen call if the property begins with `@`', () => { - const renderer = makeRenderer(); - const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; + it('should resolve the body|document|window nodes given their values as strings as input', + () => { + const renderer = makeRenderer(); + const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; - const cb = (event: any): boolean => { return true; }; + const cb = (event: any): boolean => { + return true; + }; - renderer.listen(element, 'event', cb); - expect(engine.captures['listen']).toBeFalsy(); + renderer.listen('body', '@event', cb); + expect(engine.captures['listen'].pop()[0]).toBe(document.body); - renderer.listen(element, '@event.phase', cb); - expect(engine.captures['listen'].pop()).toEqual([element, 'event', 'phase']); - }); + renderer.listen('document', '@event', cb); + expect(engine.captures['listen'].pop()[0]).toBe(document); - it('should resolve the body|document|window nodes given their values as strings as input', - () => { - const renderer = makeRenderer(); - const engine = TestBed.inject(AnimationEngine) as MockAnimationEngine; + renderer.listen('window', '@event', cb); + expect(engine.captures['listen'].pop()[0]).toBe(window); + }); + }); - const cb = (event: any): boolean => { return true; }; + describe('registering animations', () => { + it('should only create a trigger definition once even if the registered multiple times'); + }); - renderer.listen('body', '@event', cb); - expect(engine.captures['listen'].pop()[0]).toBe(document.body); + describe('flushing animations', () => { + // these tests are only mean't to be run within the DOM + if (isNode) return; - renderer.listen('document', '@event', cb); - expect(engine.captures['listen'].pop()[0]).toBe(document); + it('should flush and fire callbacks when the zone becomes stable', (async) => { + @Component({ + selector: 'my-cmp', + template: '<div [@myAnimation]="exp" (@myAnimation.start)="onStart($event)"></div>', + animations: [trigger( + 'myAnimation', + [transition( + '* => state', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any; + event: any; + onStart(event: any) { + this.event = event; + } + } - renderer.listen('window', '@event', cb); - expect(engine.captures['listen'].pop()[0]).toBe(window); - }); - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], + declarations: [Cmp] + }); - describe('registering animations', () => { - it('should only create a trigger definition once even if the registered multiple times'); + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = 'state'; + fixture.detectChanges(); + fixture.whenStable().then(() => { + expect(cmp.event.triggerName).toEqual('myAnimation'); + expect(cmp.event.phaseName).toEqual('start'); + cmp.event = null; + + engine.flush(); + expect(cmp.event).toBeFalsy(); + async(); + }); }); - describe('flushing animations', () => { - // these tests are only mean't to be run within the DOM - if (isNode) return; - - it('should flush and fire callbacks when the zone becomes stable', (async) => { - @Component({ - selector: 'my-cmp', - template: '<div [@myAnimation]="exp" (@myAnimation.start)="onStart($event)"></div>', - animations: [trigger( - 'myAnimation', - [transition( - '* => state', - [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any; - event: any; - onStart(event: any) { this.event = event; } - } + it('should properly insert/remove nodes through the animation renderer that do not contain animations', + (async) => { + @Component({ + selector: 'my-cmp', + template: '<div #elm *ngIf="exp"></div>', + animations: [trigger( + 'someAnimation', + [transition( + '* => *', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], + }) + class Cmp { + exp: any; + @ViewChild('elm') public element: any; + } + + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], + declarations: [Cmp] + }); - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], - declarations: [Cmp] - }); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = 'state'; - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(cmp.event.triggerName).toEqual('myAnimation'); - expect(cmp.event.phaseName).toEqual('start'); - cmp.event = null; - - engine.flush(); - expect(cmp.event).toBeFalsy(); - async(); - }); - }); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + cmp.exp = true; + fixture.detectChanges(); - it('should properly insert/remove nodes through the animation renderer that do not contain animations', - (async) => { - @Component({ - selector: 'my-cmp', - template: '<div #elm *ngIf="exp"></div>', - animations: [trigger( - 'someAnimation', - [transition( - '* => *', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], - }) - class Cmp { - exp: any; - @ViewChild('elm') public element: any; - } - - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], - declarations: [Cmp] - }); + fixture.whenStable().then(() => { + cmp.exp = false; + const element = cmp.element; + expect(element.nativeElement.parentNode).toBeTruthy(); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - cmp.exp = true; fixture.detectChanges(); - fixture.whenStable().then(() => { - cmp.exp = false; - const element = cmp.element; - expect(element.nativeElement.parentNode).toBeTruthy(); - - fixture.detectChanges(); - fixture.whenStable().then(() => { - expect(element.nativeElement.parentNode).toBeFalsy(); - async(); - }); + expect(element.nativeElement.parentNode).toBeFalsy(); + async(); }); }); + }); - it('should only queue up dom removals if the element itself contains a valid leave animation', - () => { - @Component({ - selector: 'my-cmp', - template: ` + it('should only queue up dom removals if the element itself contains a valid leave animation', + () => { + @Component({ + selector: 'my-cmp', + template: ` <div #elm1 *ngIf="exp1"></div> <div #elm2 @animation1 *ngIf="exp2"></div> <div #elm3 @animation2 *ngIf="exp3"></div> `, - animations: [ - trigger('animation1', [transition('a => b', [])]), - trigger('animation2', [transition(':leave', [])]), - ] - }) - class Cmp { - exp1: any = true; - exp2: any = true; - exp3: any = true; - - @ViewChild('elm1') public elm1: any; - - @ViewChild('elm2') public elm2: any; - - @ViewChild('elm3') public elm3: any; - } - - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], - declarations: [Cmp] - }); - - const engine = TestBed.inject(AnimationEngine); - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; - - fixture.detectChanges(); - const elm1 = cmp.elm1; - const elm2 = cmp.elm2; - const elm3 = cmp.elm3; - assertHasParent(elm1); - assertHasParent(elm2); - assertHasParent(elm3); - engine.flush(); - finishPlayers(engine.players); - - cmp.exp1 = false; - fixture.detectChanges(); - assertHasParent(elm1, false); - assertHasParent(elm2); - assertHasParent(elm3); - engine.flush(); - expect(engine.players.length).toEqual(0); - - cmp.exp2 = false; - fixture.detectChanges(); - assertHasParent(elm1, false); - assertHasParent(elm2, false); - assertHasParent(elm3); - engine.flush(); - expect(engine.players.length).toEqual(0); - - cmp.exp3 = false; - fixture.detectChanges(); - assertHasParent(elm1, false); - assertHasParent(elm2, false); - assertHasParent(elm3); - engine.flush(); - expect(engine.players.length).toEqual(1); + animations: [ + trigger('animation1', [transition('a => b', [])]), + trigger('animation2', [transition(':leave', [])]), + ] + }) + class Cmp { + exp1: any = true; + exp2: any = true; + exp3: any = true; + + @ViewChild('elm1') public elm1: any; + + @ViewChild('elm2') public elm2: any; + + @ViewChild('elm3') public elm3: any; + } + + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], + declarations: [Cmp] }); - }); - }); - describe('AnimationRendererFactory', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ - provide: RendererFactory2, - useClass: ExtendedAnimationRendererFactory, - deps: [DomRendererFactory2, AnimationEngine, NgZone] - }], - imports: [BrowserAnimationsModule] - }); + const engine = TestBed.inject(AnimationEngine); + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; + + fixture.detectChanges(); + const elm1 = cmp.elm1; + const elm2 = cmp.elm2; + const elm3 = cmp.elm3; + assertHasParent(elm1); + assertHasParent(elm2); + assertHasParent(elm3); + engine.flush(); + finishPlayers(engine.players); + + cmp.exp1 = false; + fixture.detectChanges(); + assertHasParent(elm1, false); + assertHasParent(elm2); + assertHasParent(elm3); + engine.flush(); + expect(engine.players.length).toEqual(0); + + cmp.exp2 = false; + fixture.detectChanges(); + assertHasParent(elm1, false); + assertHasParent(elm2, false); + assertHasParent(elm3); + engine.flush(); + expect(engine.players.length).toEqual(0); + + cmp.exp3 = false; + fixture.detectChanges(); + assertHasParent(elm1, false); + assertHasParent(elm2, false); + assertHasParent(elm3); + engine.flush(); + expect(engine.players.length).toEqual(1); + }); + }); +}); + +describe('AnimationRendererFactory', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [{ + provide: RendererFactory2, + useClass: ExtendedAnimationRendererFactory, + deps: [DomRendererFactory2, AnimationEngine, NgZone] + }], + imports: [BrowserAnimationsModule] }); + }); - it('should provide hooks at the start and end of change detection', () => { - @Component({ - selector: 'my-cmp', - template: ` + it('should provide hooks at the start and end of change detection', () => { + @Component({ + selector: 'my-cmp', + template: ` <div [@myAnimation]="exp"></div> `, - animations: [trigger('myAnimation', [])] - }) - class Cmp { - public exp: any; - } + animations: [trigger('myAnimation', [])] + }) + class Cmp { + public exp: any; + } - TestBed.configureTestingModule({ - providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], - declarations: [Cmp] - }); + TestBed.configureTestingModule({ + providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], + declarations: [Cmp] + }); - const renderer = TestBed.inject(RendererFactory2) as ExtendedAnimationRendererFactory; - const fixture = TestBed.createComponent(Cmp); - const cmp = fixture.componentInstance; + const renderer = TestBed.inject(RendererFactory2) as ExtendedAnimationRendererFactory; + const fixture = TestBed.createComponent(Cmp); + const cmp = fixture.componentInstance; - renderer.log = []; - fixture.detectChanges(); - expect(renderer.log).toEqual(['begin', 'end']); + renderer.log = []; + fixture.detectChanges(); + expect(renderer.log).toEqual(['begin', 'end']); - renderer.log = []; - fixture.detectChanges(); - expect(renderer.log).toEqual(['begin', 'end']); - }); + renderer.log = []; + fixture.detectChanges(); + expect(renderer.log).toEqual(['begin', 'end']); }); +}); })(); @Injectable() @@ -336,7 +341,9 @@ class MockAnimationEngine extends InjectableAnimationEngine { this.triggers.push(metadata); } - onInsert(namespaceId: string, element: any): void { this._capture('onInsert', [element]); } + onInsert(namespaceId: string, element: any): void { + this._capture('onInsert', [element]); + } onRemove(namespaceId: string, element: any, domFn: () => any): void { this._capture('onRemove', [element]); diff --git a/packages/platform-browser/animations/test/browser_animation_builder_spec.ts b/packages/platform-browser/animations/test/browser_animation_builder_spec.ts index 38535fcda584e..a254629119fa6 100644 --- a/packages/platform-browser/animations/test/browser_animation_builder_spec.ts +++ b/packages/platform-browser/animations/test/browser_animation_builder_spec.ts @@ -5,11 +5,11 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {AnimationBuilder, animate, style} from '@angular/animations'; +import {animate, AnimationBuilder, style} from '@angular/animations'; import {AnimationDriver} from '@angular/animations/browser'; import {MockAnimationDriver} from '@angular/animations/browser/testing'; import {Component, ViewChild} from '@angular/core'; -import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; +import {fakeAsync, flushMicrotasks, TestBed} from '@angular/core/testing'; import {NoopAnimationsModule, ɵBrowserAnimationBuilder as BrowserAnimationBuilder} from '@angular/platform-browser/animations'; import {el} from '../../testing/src/browser_util'; diff --git a/packages/platform-browser/animations/test/noop_animations_module_spec.ts b/packages/platform-browser/animations/test/noop_animations_module_spec.ts index b71d58320e52d..3a8d24470669b 100644 --- a/packages/platform-browser/animations/test/noop_animations_module_spec.ts +++ b/packages/platform-browser/animations/test/noop_animations_module_spec.ts @@ -13,7 +13,9 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations'; { describe('NoopAnimationsModule', () => { - beforeEach(() => { TestBed.configureTestingModule({imports: [NoopAnimationsModule]}); }); + beforeEach(() => { + TestBed.configureTestingModule({imports: [NoopAnimationsModule]}); + }); it('should flush and fire callbacks when the zone becomes stable', (async) => { @Component({ @@ -29,8 +31,12 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations'; exp: any; startEvent: any; doneEvent: any; - onStart(event: any) { this.startEvent = event; } - onDone(event: any) { this.doneEvent = event; } + onStart(event: any) { + this.startEvent = event; + } + onDone(event: any) { + this.doneEvent = event; + } } TestBed.configureTestingModule({declarations: [Cmp]}); @@ -63,8 +69,12 @@ import {NoopAnimationsModule} from '@angular/platform-browser/animations'; exp: any; startEvent: any; doneEvent: any; - onStart(event: any) { this.startEvent = event; } - onDone(event: any) { this.doneEvent = event; } + onStart(event: any) { + this.startEvent = event; + } + onDone(event: any) { + this.doneEvent = event; + } } TestBed.configureTestingModule({declarations: [Cmp]}); diff --git a/packages/platform-browser/src/browser.ts b/packages/platform-browser/src/browser.ts index 44fad7407a3a7..52d601ac8a894 100644 --- a/packages/platform-browser/src/browser.ts +++ b/packages/platform-browser/src/browser.ts @@ -7,7 +7,8 @@ */ import {CommonModule, DOCUMENT, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; -import {APP_ID, ApplicationModule, ErrorHandler, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, PlatformRef, RendererFactory2, Sanitizer, SkipSelf, StaticProvider, Testability, createPlatformFactory, platformCore, ɵConsole as Console, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core'; +import {APP_ID, ApplicationModule, createPlatformFactory, ErrorHandler, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, RendererFactory2, Sanitizer, SkipSelf, StaticProvider, Testability, ɵConsole as Console, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core'; + import {BrowserDomAdapter} from './browser/browser_adapter'; import {SERVER_TRANSITION_PROVIDERS, TRANSITION_ID} from './browser/server-transition'; import {BrowserGetTestability} from './browser/testability'; diff --git a/packages/platform-browser/src/browser/browser_adapter.ts b/packages/platform-browser/src/browser/browser_adapter.ts index ced19976b57fd..cb56e52db29bd 100644 --- a/packages/platform-browser/src/browser/browser_adapter.ts +++ b/packages/platform-browser/src/browser/browser_adapter.ts @@ -29,8 +29,12 @@ const nodeContains: (this: Node, other: Node) => boolean = (() => { */ /* tslint:disable:requireParameterType no-console */ export class BrowserDomAdapter extends GenericBrowserDomAdapter { - static makeCurrent() { setRootDomAdapter(new BrowserDomAdapter()); } - getProperty(el: Node, name: string): any { return (<any>el)[name]; } + static makeCurrent() { + setRootDomAdapter(new BrowserDomAdapter()); + } + getProperty(el: Node, name: string): any { + return (<any>el)[name]; + } log(error: string): void { if (window.console) { @@ -54,16 +58,22 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { el.addEventListener(evt, listener, false); // Needed to follow Dart's subscription semantic, until fix of // https://code.google.com/p/dart/issues/detail?id=17406 - return () => { el.removeEventListener(evt, listener, false); }; + return () => { + el.removeEventListener(evt, listener, false); + }; + } + dispatchEvent(el: Node, evt: any) { + el.dispatchEvent(evt); } - dispatchEvent(el: Node, evt: any) { el.dispatchEvent(evt); } remove(node: Node): Node { if (node.parentNode) { node.parentNode.removeChild(node); } return node; } - getValue(el: any): string { return el.value; } + getValue(el: any): string { + return el.value; + } createElement(tagName: string, doc?: Document): HTMLElement { doc = doc || this.getDefaultDocument(); return doc.createElement(tagName); @@ -71,11 +81,17 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { createHtmlDocument(): HTMLDocument { return document.implementation.createHTMLDocument('fakeTitle'); } - getDefaultDocument(): Document { return document; } + getDefaultDocument(): Document { + return document; + } - isElementNode(node: Node): boolean { return node.nodeType === Node.ELEMENT_NODE; } + isElementNode(node: Node): boolean { + return node.nodeType === Node.ELEMENT_NODE; + } - isShadowRoot(node: any): boolean { return node instanceof DocumentFragment; } + isShadowRoot(node: any): boolean { + return node instanceof DocumentFragment; + } getGlobalEventTarget(doc: Document, target: string): EventTarget|null { if (target === 'window') { @@ -89,14 +105,22 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { } return null; } - getHistory(): History { return window.history; } - getLocation(): Location { return window.location; } + getHistory(): History { + return window.history; + } + getLocation(): Location { + return window.location; + } getBaseHref(doc: Document): string|null { const href = getBaseElementHref(); return href == null ? null : relativePath(href); } - resetBaseElement(): void { baseElement = null; } - getUserAgent(): string { return window.navigator.userAgent; } + resetBaseElement(): void { + baseElement = null; + } + getUserAgent(): string { + return window.navigator.userAgent; + } performanceNow(): number { // performance.now() is not available in all browsers, see // http://caniuse.com/#search=performance.now @@ -104,15 +128,19 @@ export class BrowserDomAdapter extends GenericBrowserDomAdapter { new Date().getTime(); } - supportsCookies(): boolean { return true; } + supportsCookies(): boolean { + return true; + } - getCookie(name: string): string|null { return parseCookieValue(document.cookie, name); } + getCookie(name: string): string|null { + return parseCookieValue(document.cookie, name); + } } let baseElement: HTMLElement|null = null; function getBaseElementHref(): string|null { if (!baseElement) { - baseElement = document.querySelector('base') !; + baseElement = document.querySelector('base')!; if (!baseElement) { return null; } diff --git a/packages/platform-browser/src/browser/generic_browser_adapter.ts b/packages/platform-browser/src/browser/generic_browser_adapter.ts index 174567359c354..cd4c956a4c036 100644 --- a/packages/platform-browser/src/browser/generic_browser_adapter.ts +++ b/packages/platform-browser/src/browser/generic_browser_adapter.ts @@ -17,7 +17,11 @@ import {ɵDomAdapter as DomAdapter} from '@angular/common'; * can introduce XSS risks. */ export abstract class GenericBrowserDomAdapter extends DomAdapter { - constructor() { super(); } + constructor() { + super(); + } - supportsDOMEvents(): boolean { return true; } + supportsDOMEvents(): boolean { + return true; + } } diff --git a/packages/platform-browser/src/browser/meta.ts b/packages/platform-browser/src/browser/meta.ts index 0962e4656ce35..a595f2cb92710 100644 --- a/packages/platform-browser/src/browser/meta.ts +++ b/packages/platform-browser/src/browser/meta.ts @@ -15,13 +15,16 @@ import {Inject, Injectable, ɵɵinject} from '@angular/core'; * @publicApi */ export type MetaDefinition = { - charset?: string; content?: string; httpEquiv?: string; id?: string; itemprop?: string; + charset?: string; + content?: string; + httpEquiv?: string; + id?: string; + itemprop?: string; name?: string; property?: string; scheme?: string; url?: string; -} & -{ +}&{ // TODO(IgorMinar): this type looks wrong [prop: string]: string; }; @@ -41,7 +44,9 @@ export function createMeta() { @Injectable({providedIn: 'root', useFactory: createMeta, deps: []}) export class Meta { private _dom: DomAdapter; - constructor(@Inject(DOCUMENT) private _doc: any) { this._dom = getDOM(); } + constructor(@Inject(DOCUMENT) private _doc: any) { + this._dom = getDOM(); + } addTag(tag: MetaDefinition, forceCreation: boolean = false): HTMLMetaElement|null { if (!tag) return null; @@ -72,14 +77,16 @@ export class Meta { updateTag(tag: MetaDefinition, selector?: string): HTMLMetaElement|null { if (!tag) return null; selector = selector || this._parseSelector(tag); - const meta: HTMLMetaElement = this.getTag(selector) !; + const meta: HTMLMetaElement = this.getTag(selector)!; if (meta) { return this._setMetaElementAttributes(tag, meta); } return this._getOrCreateElement(tag, true); } - removeTag(attrSelector: string): void { this.removeTagElement(this.getTag(attrSelector) !); } + removeTag(attrSelector: string): void { + this.removeTagElement(this.getTag(attrSelector)!); + } removeTagElement(meta: HTMLMetaElement): void { if (meta) { @@ -91,7 +98,7 @@ export class Meta { HTMLMetaElement { if (!forceCreation) { const selector: string = this._parseSelector(meta); - const elem: HTMLMetaElement = this.getTag(selector) !; + const elem: HTMLMetaElement = this.getTag(selector)!; // It's allowed to have multiple elements with the same name so it's not enough to // just check that element with the same name already present on the page. We also need to // check if element has tag attributes diff --git a/packages/platform-browser/src/browser/testability.ts b/packages/platform-browser/src/browser/testability.ts index bddcc9700d781..2592657566aaf 100644 --- a/packages/platform-browser/src/browser/testability.ts +++ b/packages/platform-browser/src/browser/testability.ts @@ -7,10 +7,12 @@ */ import {ɵgetDOM as getDOM} from '@angular/common'; -import {GetTestability, Testability, TestabilityRegistry, setTestabilityGetter, ɵglobal as global} from '@angular/core'; +import {GetTestability, setTestabilityGetter, Testability, TestabilityRegistry, ɵglobal as global} from '@angular/core'; export class BrowserGetTestability implements GetTestability { - static init() { setTestabilityGetter(new BrowserGetTestability()); } + static init() { + setTestabilityGetter(new BrowserGetTestability()); + } addToWindow(registry: TestabilityRegistry): void { global['getAngularTestability'] = (elem: any, findInAncestors: boolean = true) => { diff --git a/packages/platform-browser/src/browser/title.ts b/packages/platform-browser/src/browser/title.ts index 81ec5f29742c3..b262c08042c76 100644 --- a/packages/platform-browser/src/browser/title.ts +++ b/packages/platform-browser/src/browser/title.ts @@ -33,11 +33,15 @@ export class Title { /** * Get the title of the current HTML document. */ - getTitle(): string { return this._doc.title; } + getTitle(): string { + return this._doc.title; + } /** * Set the title of the current HTML document. * @param newTitle */ - setTitle(newTitle: string) { this._doc.title = newTitle || ''; } + setTitle(newTitle: string) { + this._doc.title = newTitle || ''; + } } diff --git a/packages/platform-browser/src/browser/tools/common_tools.ts b/packages/platform-browser/src/browser/tools/common_tools.ts index 37e12036f7a38..a4d0a62f9c178 100644 --- a/packages/platform-browser/src/browser/tools/common_tools.ts +++ b/packages/platform-browser/src/browser/tools/common_tools.ts @@ -21,7 +21,9 @@ export class ChangeDetectionPerfRecord { export class AngularProfiler { appRef: ApplicationRef; - constructor(ref: ComponentRef<any>) { this.appRef = ref.injector.get(ApplicationRef); } + constructor(ref: ComponentRef<any>) { + this.appRef = ref.injector.get(ApplicationRef); + } // tslint:disable:no-console /** diff --git a/packages/platform-browser/src/browser/transfer_state.ts b/packages/platform-browser/src/browser/transfer_state.ts index a9bf935df500a..f0bbe053e62bb 100644 --- a/packages/platform-browser/src/browser/transfer_state.ts +++ b/packages/platform-browser/src/browser/transfer_state.ts @@ -45,7 +45,7 @@ export function unescapeHtml(text: string): string { * * @publicApi */ -export type StateKey<T> = string & {__not_a_string: never}; +export type StateKey<T> = string&{__not_a_string: never}; /** * Create a `StateKey<T>` that can be used to store value of type T with `TransferState`. @@ -80,7 +80,7 @@ export function makeStateKey<T = void>(key: string): StateKey<T> { */ @Injectable() export class TransferState { - private store: {[k: string]: {} | undefined} = {}; + private store: {[k: string]: {}|undefined} = {}; private onSerializeCallbacks: {[k: string]: () => {} | undefined} = {}; /** @internal */ @@ -100,17 +100,23 @@ export class TransferState { /** * Set the value corresponding to a key. */ - set<T>(key: StateKey<T>, value: T): void { this.store[key] = value; } + set<T>(key: StateKey<T>, value: T): void { + this.store[key] = value; + } /** * Remove a key from the store. */ - remove<T>(key: StateKey<T>): void { delete this.store[key]; } + remove<T>(key: StateKey<T>): void { + delete this.store[key]; + } /** * Test whether a key exists in the store. */ - hasKey<T>(key: StateKey<T>) { return this.store.hasOwnProperty(key); } + hasKey<T>(key: StateKey<T>) { + return this.store.hasOwnProperty(key); + } /** * Register a callback to provide the value for a key when `toJson` is called. diff --git a/packages/platform-browser/src/dom/debug/by.ts b/packages/platform-browser/src/dom/debug/by.ts index d35e4055f64a3..f0799cd4f448c 100644 --- a/packages/platform-browser/src/dom/debug/by.ts +++ b/packages/platform-browser/src/dom/debug/by.ts @@ -25,7 +25,9 @@ export class By { * * {@example platform-browser/dom/debug/ts/by/by.ts region='by_all'} */ - static all(): Predicate<DebugNode> { return () => true; } + static all(): Predicate<DebugNode> { + return () => true; + } /** * Match elements by the given CSS selector. @@ -52,7 +54,7 @@ export class By { * {@example platform-browser/dom/debug/ts/by/by.ts region='by_directive'} */ static directive(type: Type<any>): Predicate<DebugNode> { - return (debugNode) => debugNode.providerTokens !.indexOf(type) !== -1; + return (debugNode) => debugNode.providerTokens!.indexOf(type) !== -1; } } diff --git a/packages/platform-browser/src/dom/dom_renderer.ts b/packages/platform-browser/src/dom/dom_renderer.ts index 80fc39d85a5de..9362a0881de60 100644 --- a/packages/platform-browser/src/dom/dom_renderer.ts +++ b/packages/platform-browser/src/dom/dom_renderer.ts @@ -137,11 +137,17 @@ class DefaultDomRenderer2 implements Renderer2 { return document.createElement(name); } - createComment(value: string): any { return document.createComment(value); } + createComment(value: string): any { + return document.createComment(value); + } - createText(value: string): any { return document.createTextNode(value); } + createText(value: string): any { + return document.createTextNode(value); + } - appendChild(parent: any, newChild: any): void { parent.appendChild(newChild); } + appendChild(parent: any, newChild: any): void { + parent.appendChild(newChild); + } insertBefore(parent: any, newChild: any, refChild: any): void { if (parent) { @@ -167,9 +173,13 @@ class DefaultDomRenderer2 implements Renderer2 { return el; } - parentNode(node: any): any { return node.parentNode; } + parentNode(node: any): any { + return node.parentNode; + } - nextSibling(node: any): any { return node.nextSibling; } + nextSibling(node: any): any { + return node.nextSibling; + } setAttribute(el: any, name: string, value: string, namespace?: string): void { if (namespace) { @@ -205,9 +215,13 @@ class DefaultDomRenderer2 implements Renderer2 { } } - addClass(el: any, name: string): void { el.classList.add(name); } + addClass(el: any, name: string): void { + el.classList.add(name); + } - removeClass(el: any, name: string): void { el.classList.remove(name); } + removeClass(el: any, name: string): void { + el.classList.remove(name); + } setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void { if (flags & RendererStyleFlags2.DashCase) { @@ -233,7 +247,9 @@ class DefaultDomRenderer2 implements Renderer2 { el[name] = value; } - setValue(node: any, value: string): void { node.nodeValue = value; } + setValue(node: any, value: string): void { + node.nodeValue = value; + } listen(target: 'window'|'document'|'body'|any, event: string, callback: (event: any) => boolean): () => void { @@ -243,15 +259,15 @@ class DefaultDomRenderer2 implements Renderer2 { target, event, decoratePreventDefault(callback)); } return <() => void>this.eventManager.addEventListener( - target, event, decoratePreventDefault(callback)) as() => void; + target, event, decoratePreventDefault(callback)) as () => void; } } const AT_CHARCODE = (() => '@'.charCodeAt(0))(); function checkNoSyntheticProp(name: string, nameKind: string) { if (name.charCodeAt(0) === AT_CHARCODE) { - throw new Error( - `Found the synthetic ${nameKind} ${name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`); + throw new Error(`Found the synthetic ${nameKind} ${ + name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`); } } @@ -270,7 +286,9 @@ class EmulatedEncapsulationDomRenderer2 extends DefaultDomRenderer2 { this.hostAttr = shimHostAttribute(appId + '-' + component.id); } - applyToHost(element: any) { super.setAttribute(element, this.hostAttr, ''); } + applyToHost(element: any) { + super.setAttribute(element, this.hostAttr, ''); + } createElement(parent: any, name: string): Element { const el = super.createElement(parent, name); @@ -300,9 +318,13 @@ class ShadowDomRenderer extends DefaultDomRenderer2 { } } - private nodeOrShadowRoot(node: any): any { return node === this.hostEl ? this.shadowRoot : node; } + private nodeOrShadowRoot(node: any): any { + return node === this.hostEl ? this.shadowRoot : node; + } - destroy() { this.sharedStylesHost.removeHost(this.shadowRoot); } + destroy() { + this.sharedStylesHost.removeHost(this.shadowRoot); + } appendChild(parent: any, newChild: any): void { return super.appendChild(this.nodeOrShadowRoot(parent), newChild); diff --git a/packages/platform-browser/src/dom/events/dom_events.ts b/packages/platform-browser/src/dom/events/dom_events.ts index d080fba80ea19..77152c4e7d800 100644 --- a/packages/platform-browser/src/dom/events/dom_events.ts +++ b/packages/platform-browser/src/dom/events/dom_events.ts @@ -13,11 +13,15 @@ import {EventManagerPlugin} from './event_manager'; @Injectable() export class DomEventsPlugin extends EventManagerPlugin { - constructor(@Inject(DOCUMENT) doc: any) { super(doc); } + constructor(@Inject(DOCUMENT) doc: any) { + super(doc); + } // This plugin should come last in the list of plugins, because it accepts all // events. - supports(eventName: string): boolean { return true; } + supports(eventName: string): boolean { + return true; + } addEventListener(element: HTMLElement, eventName: string, handler: Function): Function { element.addEventListener(eventName, handler as EventListener, false); diff --git a/packages/platform-browser/src/dom/events/event_manager.ts b/packages/platform-browser/src/dom/events/event_manager.ts index 460f19110cab6..0a69b867cb05f 100644 --- a/packages/platform-browser/src/dom/events/event_manager.ts +++ b/packages/platform-browser/src/dom/events/event_manager.ts @@ -67,7 +67,9 @@ export class EventManager { /** * Retrieves the compilation zone in which event listeners are registered. */ - getZone(): NgZone { return this._zone; } + getZone(): NgZone { + return this._zone; + } /** @internal */ _findPluginFor(eventName: string): EventManagerPlugin { @@ -92,7 +94,7 @@ export abstract class EventManagerPlugin { constructor(private _doc: any) {} // TODO(issue/24571): remove '!'. - manager !: EventManager; + manager!: EventManager; abstract supports(eventName: string): boolean; diff --git a/packages/platform-browser/src/dom/events/hammer_gestures.ts b/packages/platform-browser/src/dom/events/hammer_gestures.ts index 27f7e961fb4a1..dcfb894003ddd 100644 --- a/packages/platform-browser/src/dom/events/hammer_gestures.ts +++ b/packages/platform-browser/src/dom/events/hammer_gestures.ts @@ -99,21 +99,21 @@ export class HammerGestureConfig { events: string[] = []; /** - * Maps gesture event names to a set of configuration options - * that specify overrides to the default values for specific properties. - * - * The key is a supported event name to be configured, - * and the options object contains a set of properties, with override values - * to be applied to the named recognizer event. - * For example, to disable recognition of the rotate event, specify - * `{"rotate": {"enable": false}}`. - * - * Properties that are not present take the HammerJS default values. - * For information about which properties are supported for which events, - * and their allowed and default values, see - * [HammerJS documentation](http://hammerjs.github.io/). - * - */ + * Maps gesture event names to a set of configuration options + * that specify overrides to the default values for specific properties. + * + * The key is a supported event name to be configured, + * and the options object contains a set of properties, with override values + * to be applied to the named recognizer event. + * For example, to disable recognition of the rotate event, specify + * `{"rotate": {"enable": false}}`. + * + * Properties that are not present take the HammerJS default values. + * For information about which properties are supported for which events, + * and their allowed and default values, see + * [HammerJS documentation](http://hammerjs.github.io/). + * + */ overrides: {[key: string]: Object} = {}; /** @@ -124,7 +124,9 @@ export class HammerGestureConfig { * [HammerJS documentation](http://hammerjs.github.io/). */ options?: { - cssProps?: any; domEvents?: boolean; enable?: boolean | ((manager: any) => boolean); + cssProps?: any; + domEvents?: boolean; + enable?: boolean | ((manager: any) => boolean); preset?: any[]; touchAction?: string; recognizers?: any[]; @@ -139,7 +141,7 @@ export class HammerGestureConfig { * @returns A HammerJS event-manager object. */ buildHammer(element: HTMLElement): HammerInstance { - const mc = new Hammer !(element, this.options); + const mc = new Hammer!(element, this.options); mc.get('pinch').set({enable: true}); mc.get('rotate').set({enable: true}); @@ -192,7 +194,9 @@ export class HammerGesturesPlugin extends EventManagerPlugin { // Until Hammer is loaded, the returned function needs to *cancel* the registration rather // than remove anything. let cancelRegistration = false; - let deregister: Function = () => { cancelRegistration = true; }; + let deregister: Function = () => { + cancelRegistration = true; + }; this.loader() .then(() => { @@ -220,14 +224,18 @@ export class HammerGesturesPlugin extends EventManagerPlugin { // Return a function that *executes* `deregister` (and not `deregister` itself) so that we // can change the behavior of `deregister` once the listener is added. Using a closure in // this way allows us to avoid any additional data structures to track listener removal. - return () => { deregister(); }; + return () => { + deregister(); + }; } return zone.runOutsideAngular(() => { // Creating the manager bind events, must be done outside of angular const mc = this._config.buildHammer(element); const callback = function(eventObj: HammerInput) { - zone.runGuarded(function() { handler(eventObj); }); + zone.runGuarded(function() { + handler(eventObj); + }); }; mc.on(eventName, callback); return () => { @@ -240,7 +248,9 @@ export class HammerGesturesPlugin extends EventManagerPlugin { }); } - isCustomEvent(eventName: string): boolean { return this._config.events.indexOf(eventName) > -1; } + isCustomEvent(eventName: string): boolean { + return this._config.events.indexOf(eventName) > -1; + } } /** diff --git a/packages/platform-browser/src/dom/events/key_events.ts b/packages/platform-browser/src/dom/events/key_events.ts index e7516ae591a3c..151b6e289ace2 100644 --- a/packages/platform-browser/src/dom/events/key_events.ts +++ b/packages/platform-browser/src/dom/events/key_events.ts @@ -79,14 +79,18 @@ export class KeyEventsPlugin extends EventManagerPlugin { * Initializes an instance of the browser plug-in. * @param doc The document in which key events will be detected. */ - constructor(@Inject(DOCUMENT) doc: any) { super(doc); } + constructor(@Inject(DOCUMENT) doc: any) { + super(doc); + } /** - * Reports whether a named key event is supported. - * @param eventName The event name to query. - * @return True if the named key event is supported. + * Reports whether a named key event is supported. + * @param eventName The event name to query. + * @return True if the named key event is supported. */ - supports(eventName: string): boolean { return KeyEventsPlugin.parseEventName(eventName) != null; } + supports(eventName: string): boolean { + return KeyEventsPlugin.parseEventName(eventName) != null; + } /** * Registers a handler for a specific element and key event. @@ -95,9 +99,9 @@ export class KeyEventsPlugin extends EventManagerPlugin { * @param handler A function to call when the notification occurs. Receives the * event object as an argument. * @returns The key event that was registered. - */ + */ addEventListener(element: HTMLElement, eventName: string, handler: Function): Function { - const parsedEvent = KeyEventsPlugin.parseEventName(eventName) !; + const parsedEvent = KeyEventsPlugin.parseEventName(eventName)!; const outsideHandler = KeyEventsPlugin.eventCallback(parsedEvent['fullKey'], handler, this.manager.getZone()); @@ -115,7 +119,7 @@ export class KeyEventsPlugin extends EventManagerPlugin { return null; } - const key = KeyEventsPlugin._normalizeKey(parts.pop() !); + const key = KeyEventsPlugin._normalizeKey(parts.pop()!); let fullKey = ''; MODIFIER_KEYS.forEach(modifierName => { diff --git a/packages/platform-browser/src/dom/shared_styles_host.ts b/packages/platform-browser/src/dom/shared_styles_host.ts index 54745b63b6ba3..e53bc046469e2 100644 --- a/packages/platform-browser/src/dom/shared_styles_host.ts +++ b/packages/platform-browser/src/dom/shared_styles_host.ts @@ -27,7 +27,9 @@ export class SharedStylesHost { onStylesAdded(additions: Set<string>): void {} - getAllStyles(): string[] { return Array.from(this._stylesSet); } + getAllStyles(): string[] { + return Array.from(this._stylesSet); + } } @Injectable() @@ -52,11 +54,15 @@ export class DomSharedStylesHost extends SharedStylesHost implements OnDestroy { this._hostNodes.add(hostNode); } - removeHost(hostNode: Node): void { this._hostNodes.delete(hostNode); } + removeHost(hostNode: Node): void { + this._hostNodes.delete(hostNode); + } onStylesAdded(additions: Set<string>): void { this._hostNodes.forEach(hostNode => this._addStylesToHost(additions, hostNode)); } - ngOnDestroy(): void { this._styleNodes.forEach(styleNode => getDOM().remove(styleNode)); } + ngOnDestroy(): void { + this._styleNodes.forEach(styleNode => getDOM().remove(styleNode)); + } } diff --git a/packages/platform-browser/src/dom/util.ts b/packages/platform-browser/src/dom/util.ts index 7f5b18cb6a7e0..2cc75227befac 100644 --- a/packages/platform-browser/src/dom/util.ts +++ b/packages/platform-browser/src/dom/util.ts @@ -33,7 +33,7 @@ export function exportNgVar(name: string, value: any): void { // - closure declares globals itself for minified names, which sometimes clobber our `ng` global // - we can't declare a closure extern as the namespace `ng` is already used within Google // for typings for angularJS (via `goog.provide('ng....')`). - const ng = global['ng'] = (global['ng'] as{[key: string]: any} | undefined) || {}; + const ng = global['ng'] = (global['ng'] as {[key: string]: any} | undefined) || {}; ng[name] = value; } } diff --git a/packages/platform-browser/src/platform-browser.ts b/packages/platform-browser/src/platform-browser.ts index 5c3d5ac11fe4d..3f072b3fb1d88 100644 --- a/packages/platform-browser/src/platform-browser.ts +++ b/packages/platform-browser/src/platform-browser.ts @@ -10,7 +10,7 @@ export {BrowserModule, platformBrowser} from './browser'; export {Meta, MetaDefinition} from './browser/meta'; export {Title} from './browser/title'; export {disableDebugTools, enableDebugTools} from './browser/tools/tools'; -export {BrowserTransferStateModule, StateKey, TransferState, makeStateKey} from './browser/transfer_state'; +export {BrowserTransferStateModule, makeStateKey, StateKey, TransferState} from './browser/transfer_state'; export {By} from './dom/debug/by'; export {EVENT_MANAGER_PLUGINS, EventManager} from './dom/events/event_manager'; export {HAMMER_GESTURE_CONFIG, HAMMER_LOADER, HAMMER_PROVIDERS__POST_R3__ as ɵHAMMER_PROVIDERS__POST_R3__, HammerGestureConfig, HammerLoader, HammerModule} from './dom/events/hammer_gestures'; diff --git a/packages/platform-browser/src/private_export.ts b/packages/platform-browser/src/private_export.ts index f6159130c3e23..c37af45559035 100644 --- a/packages/platform-browser/src/private_export.ts +++ b/packages/platform-browser/src/private_export.ts @@ -7,13 +7,13 @@ */ export {ɵgetDOM} from '@angular/common'; -export {BROWSER_SANITIZATION_PROVIDERS as ɵBROWSER_SANITIZATION_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS__POST_R3__ as ɵBROWSER_SANITIZATION_PROVIDERS__POST_R3__, INTERNAL_BROWSER_PLATFORM_PROVIDERS as ɵINTERNAL_BROWSER_PLATFORM_PROVIDERS, initDomAdapter as ɵinitDomAdapter} from './browser'; +export {BROWSER_SANITIZATION_PROVIDERS as ɵBROWSER_SANITIZATION_PROVIDERS, BROWSER_SANITIZATION_PROVIDERS__POST_R3__ as ɵBROWSER_SANITIZATION_PROVIDERS__POST_R3__, initDomAdapter as ɵinitDomAdapter, INTERNAL_BROWSER_PLATFORM_PROVIDERS as ɵINTERNAL_BROWSER_PLATFORM_PROVIDERS} from './browser'; export {BrowserDomAdapter as ɵBrowserDomAdapter} from './browser/browser_adapter'; export {TRANSITION_ID as ɵTRANSITION_ID} from './browser/server-transition'; export {BrowserGetTestability as ɵBrowserGetTestability} from './browser/testability'; export {escapeHtml as ɵescapeHtml} from './browser/transfer_state'; export {ELEMENT_PROBE_PROVIDERS as ɵELEMENT_PROBE_PROVIDERS} from './dom/debug/ng_probe'; -export {DomRendererFactory2 as ɵDomRendererFactory2, NAMESPACE_URIS as ɵNAMESPACE_URIS, flattenStyles as ɵflattenStyles, shimContentAttribute as ɵshimContentAttribute, shimHostAttribute as ɵshimHostAttribute} from './dom/dom_renderer'; +export {DomRendererFactory2 as ɵDomRendererFactory2, flattenStyles as ɵflattenStyles, NAMESPACE_URIS as ɵNAMESPACE_URIS, shimContentAttribute as ɵshimContentAttribute, shimHostAttribute as ɵshimHostAttribute} from './dom/dom_renderer'; export {DomEventsPlugin as ɵDomEventsPlugin} from './dom/events/dom_events'; export {HammerGesturesPlugin as ɵHammerGesturesPlugin} from './dom/events/hammer_gestures'; export {KeyEventsPlugin as ɵKeyEventsPlugin} from './dom/events/key_events'; diff --git a/packages/platform-browser/src/security/dom_sanitization_service.ts b/packages/platform-browser/src/security/dom_sanitization_service.ts index c448588b340dd..4bb39ff56efb8 100644 --- a/packages/platform-browser/src/security/dom_sanitization_service.ts +++ b/packages/platform-browser/src/security/dom_sanitization_service.ts @@ -7,7 +7,7 @@ */ import {DOCUMENT} from '@angular/common'; -import {Inject, Injectable, Injector, Sanitizer, SecurityContext, forwardRef, ɵBypassType as BypassType, ɵ_sanitizeHtml as _sanitizeHtml, ɵ_sanitizeStyle as _sanitizeStyle, ɵ_sanitizeUrl as _sanitizeUrl, ɵallowSanitizationBypassAndThrow as allowSanitizationBypassOrThrow, ɵbypassSanitizationTrustHtml as bypassSanitizationTrustHtml, ɵbypassSanitizationTrustResourceUrl as bypassSanitizationTrustResourceUrl, ɵbypassSanitizationTrustScript as bypassSanitizationTrustScript, ɵbypassSanitizationTrustStyle as bypassSanitizationTrustStyle, ɵbypassSanitizationTrustUrl as bypassSanitizationTrustUrl, ɵgetSanitizationBypassType as getSanitizationBypassType, ɵunwrapSafeValue as unwrapSafeValue} from '@angular/core'; +import {forwardRef, Inject, Injectable, Injector, Sanitizer, SecurityContext, ɵ_sanitizeHtml as _sanitizeHtml, ɵ_sanitizeStyle as _sanitizeStyle, ɵ_sanitizeUrl as _sanitizeUrl, ɵallowSanitizationBypassAndThrow as allowSanitizationBypassOrThrow, ɵbypassSanitizationTrustHtml as bypassSanitizationTrustHtml, ɵbypassSanitizationTrustResourceUrl as bypassSanitizationTrustResourceUrl, ɵbypassSanitizationTrustScript as bypassSanitizationTrustScript, ɵbypassSanitizationTrustStyle as bypassSanitizationTrustStyle, ɵbypassSanitizationTrustUrl as bypassSanitizationTrustUrl, ɵBypassType as BypassType, ɵgetSanitizationBypassType as getSanitizationBypassType, ɵunwrapSafeValue as unwrapSafeValue} from '@angular/core'; export {SecurityContext}; @@ -149,7 +149,9 @@ export function domSanitizerImplFactory(injector: Injector) { @Injectable({providedIn: 'root', useFactory: domSanitizerImplFactory, deps: [Injector]}) export class DomSanitizerImpl extends DomSanitizer { - constructor(@Inject(DOCUMENT) private _doc: any) { super(); } + constructor(@Inject(DOCUMENT) private _doc: any) { + super(); + } sanitize(ctx: SecurityContext, value: SafeValue|string|null): string|null { if (value == null) return null; @@ -188,12 +190,18 @@ export class DomSanitizerImpl extends DomSanitizer { } } - bypassSecurityTrustHtml(value: string): SafeHtml { return bypassSanitizationTrustHtml(value); } - bypassSecurityTrustStyle(value: string): SafeStyle { return bypassSanitizationTrustStyle(value); } + bypassSecurityTrustHtml(value: string): SafeHtml { + return bypassSanitizationTrustHtml(value); + } + bypassSecurityTrustStyle(value: string): SafeStyle { + return bypassSanitizationTrustStyle(value); + } bypassSecurityTrustScript(value: string): SafeScript { return bypassSanitizationTrustScript(value); } - bypassSecurityTrustUrl(value: string): SafeUrl { return bypassSanitizationTrustUrl(value); } + bypassSecurityTrustUrl(value: string): SafeUrl { + return bypassSanitizationTrustUrl(value); + } bypassSecurityTrustResourceUrl(value: string): SafeResourceUrl { return bypassSanitizationTrustResourceUrl(value); } diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index 0fbf42f4c6852..f7ecc854139ae 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -7,12 +7,12 @@ */ import {DOCUMENT, isPlatformBrowser, ɵgetDOM as getDOM} from '@angular/common'; -import {APP_INITIALIZER, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, Directive, ErrorHandler, Inject, Injector, Input, LOCALE_ID, NgModule, OnDestroy, PLATFORM_ID, PLATFORM_INITIALIZER, Pipe, Provider, Sanitizer, StaticProvider, Type, VERSION, createPlatformFactory} from '@angular/core'; +import {APP_INITIALIZER, Compiler, Component, createPlatformFactory, CUSTOM_ELEMENTS_SCHEMA, Directive, ErrorHandler, Inject, Injector, Input, LOCALE_ID, NgModule, OnDestroy, Pipe, PLATFORM_ID, PLATFORM_INITIALIZER, Provider, Sanitizer, StaticProvider, Type, VERSION} from '@angular/core'; import {ApplicationRef, destroyPlatform} from '@angular/core/src/application_ref'; import {Console} from '@angular/core/src/console'; import {ComponentRef} from '@angular/core/src/linker/component_factory'; import {Testability, TestabilityRegistry} from '@angular/core/src/testability/testability'; -import {AsyncTestCompleter, Log, afterEach, beforeEach, beforeEachProviders, describe, inject, it} from '@angular/core/testing/src/testing_internal'; +import {afterEach, AsyncTestCompleter, beforeEach, beforeEachProviders, describe, inject, it, Log} from '@angular/core/testing/src/testing_internal'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -25,7 +25,9 @@ class NonExistentComp { @Component({selector: 'hello-app', template: '{{greeting}} world!'}) class HelloRootCmp { greeting: string; - constructor() { this.greeting = 'hello'; } + constructor() { + this.greeting = 'hello'; + } } @Component({selector: 'hello-app', template: 'before: <ng-content></ng-content> after: done'}) @@ -36,7 +38,9 @@ class HelloRootCmpContent { @Component({selector: 'hello-app-2', template: '{{greeting}} world, again!'}) class HelloRootCmp2 { greeting: string; - constructor() { this.greeting = 'hello'; } + constructor() { + this.greeting = 'hello'; + } } @Component({selector: 'hello-app', template: ''}) @@ -52,7 +56,9 @@ class HelloRootCmp3 { class HelloRootCmp4 { appRef: any /** TODO #9100 */; - constructor(@Inject(ApplicationRef) appRef: ApplicationRef) { this.appRef = appRef; } + constructor(@Inject(ApplicationRef) appRef: ApplicationRef) { + this.appRef = appRef; + } } @Component({selector: 'hello-app'}) @@ -66,9 +72,13 @@ class HelloRootDirectiveIsNotCmp { @Component({selector: 'hello-app', template: ''}) class HelloOnDestroyTickCmp implements OnDestroy { appRef: ApplicationRef; - constructor(@Inject(ApplicationRef) appRef: ApplicationRef) { this.appRef = appRef; } + constructor(@Inject(ApplicationRef) appRef: ApplicationRef) { + this.appRef = appRef; + } - ngOnDestroy(): void { this.appRef.tick(); } + ngOnDestroy(): void { + this.appRef.tick(); + } } @Component({selector: 'hello-app', templateUrl: './sometemplate.html'}) @@ -79,13 +89,14 @@ class HelloUrlCmp { @Directive({selector: '[someDir]', host: {'[title]': 'someDir'}}) class SomeDirective { // TODO(issue/24571): remove '!'. - @Input() - someDir !: string; + @Input() someDir!: string; } @Pipe({name: 'somePipe'}) class SomePipe { - transform(value: string): any { return `transformed ${value}`; } + transform(value: string): any { + return `transformed ${value}`; + } } @Component({selector: 'hello-app', template: `<div [someDir]="'someValue' | somePipe"></div>`}) @@ -99,7 +110,9 @@ class HelloCmpUsingCustomElement { class MockConsole { res: any[][] = []; - error(...s: any[]): void { this.res.push(s); } + error(...s: any[]): void { + this.res.push(s); + } } @@ -107,7 +120,9 @@ class DummyConsole implements Console { public warnings: string[] = []; log(message: string) {} - warn(message: string) { this.warnings.push(message); } + warn(message: string) { + this.warnings.push(message); + } } @@ -135,7 +150,9 @@ function bootstrap( if (isNode) return; let compilerConsole: DummyConsole; - beforeEachProviders(() => { return [Log]; }); + beforeEachProviders(() => { + return [Log]; + }); beforeEach(inject([DOCUMENT], (doc: any) => { destroyPlatform(); @@ -419,7 +436,6 @@ function bootstrap( it('should remove styles when transitioning from a server render', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { - @Component({ selector: 'root', template: 'root', @@ -449,8 +465,9 @@ function bootstrap( platform.bootstrapModule(TestModule).then(() => { const styles: HTMLElement[] = Array.prototype.slice.apply(document.getElementsByTagName('style') || []); - styles.forEach( - style => { expect(style.getAttribute('ng-transition')).not.toBe('my-app'); }); + styles.forEach(style => { + expect(style.getAttribute('ng-transition')).not.toBe('my-app'); + }); async.done(); }); })); @@ -487,7 +504,9 @@ function bootstrap( }) class CompA { title: string = ''; - ngDoCheck() { log.push('CompA:ngDoCheck'); } + ngDoCheck() { + log.push('CompA:ngDoCheck'); + } onClick() { this.title = 'CompA'; log.push('CompA:onClick'); @@ -500,7 +519,9 @@ function bootstrap( }) class CompB { title: string = ''; - ngDoCheck() { log.push('CompB:ngDoCheck'); } + ngDoCheck() { + log.push('CompB:ngDoCheck'); + } onClick() { this.title = 'CompB'; log.push('CompB:onClick'); diff --git a/packages/platform-browser/test/browser/meta_spec.ts b/packages/platform-browser/test/browser/meta_spec.ts index 41d59fcd3df99..a959a4134c567 100644 --- a/packages/platform-browser/test/browser/meta_spec.ts +++ b/packages/platform-browser/test/browser/meta_spec.ts @@ -30,14 +30,14 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; afterEach(() => getDOM().remove(defaultMeta)); it('should return meta tag matching selector', () => { - const actual: HTMLMetaElement = metaService.getTag('property="fb:app_id"') !; + const actual: HTMLMetaElement = metaService.getTag('property="fb:app_id"')!; expect(actual).not.toBeNull(); expect(actual.getAttribute('content')).toEqual('123456789'); }); it('should return all meta tags matching selector', () => { - const tag1 = metaService.addTag({name: 'author', content: 'page author'}) !; - const tag2 = metaService.addTag({name: 'author', content: 'another page author'}) !; + const tag1 = metaService.addTag({name: 'author', content: 'page author'})!; + const tag2 = metaService.addTag({name: 'author', content: 'another page author'})!; const actual: HTMLMetaElement[] = metaService.getTags('name=author'); expect(actual.length).toEqual(2); @@ -50,7 +50,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); it('should return null if meta tag does not exist', () => { - const actual: HTMLMetaElement = metaService.getTag('fake=fake') !; + const actual: HTMLMetaElement = metaService.getTag('fake=fake')!; expect(actual).toBeNull(); }); @@ -73,7 +73,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; metaService.addTags([{name: 'keywords', content: 'meta test'}]); - const meta = metaService.getTag(selector) !; + const meta = metaService.getTag(selector)!; expect(meta).not.toBeNull(); metaService.removeTagElement(meta); @@ -87,7 +87,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; const actual = metaService.getTag(selector); expect(actual).not.toBeNull(); - expect(actual !.getAttribute('content')).toEqual('4321'); + expect(actual!.getAttribute('content')).toEqual('4321'); }); it('should extract selector from the tag definition', () => { @@ -96,7 +96,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; const actual = metaService.getTag(selector); expect(actual).not.toBeNull(); - expect(actual !.getAttribute('content')).toEqual('666'); + expect(actual!.getAttribute('content')).toEqual('666'); }); it('should create meta tag if it does not exist', () => { @@ -104,7 +104,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; metaService.updateTag({name: 'twitter:title', content: 'Content Title'}, selector); - const actual = metaService.getTag(selector) !; + const actual = metaService.getTag(selector)!; expect(actual).not.toBeNull(); expect(actual.getAttribute('content')).toEqual('Content Title'); @@ -118,7 +118,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; metaService.addTag({name: 'og:title', content: 'Content Title'}); - const actual = metaService.getTag(selector) !; + const actual = metaService.getTag(selector)!; expect(actual).not.toBeNull(); expect(actual.getAttribute('content')).toEqual('Content Title'); @@ -136,8 +136,8 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; {name: 'twitter:title', content: 'Content Title'}, {property: 'og:title', content: 'Content Title'} ]); - const twitterMeta = metaService.getTag(nameSelector) !; - const fbMeta = metaService.getTag(propertySelector) !; + const twitterMeta = metaService.getTag(nameSelector)!; + const fbMeta = metaService.getTag(propertySelector)!; expect(twitterMeta).not.toBeNull(); expect(fbMeta).not.toBeNull(); @@ -160,7 +160,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; const selector = 'property="fb:app_id"'; expect(metaService.getTags(selector).length).toEqual(1); - const meta = metaService.addTag({property: 'fb:app_id', content: '666'}) !; + const meta = metaService.addTag({property: 'fb:app_id', content: '666'})!; expect(metaService.getTags(selector).length).toEqual(2); @@ -172,18 +172,16 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; const selector = 'property="fb:app_id"'; expect(metaService.getTags(selector).length).toEqual(1); - const meta = metaService.addTag({property: 'fb:app_id', content: '123456789'}, true) !; + const meta = metaService.addTag({property: 'fb:app_id', content: '123456789'}, true)!; expect(metaService.getTags(selector).length).toEqual(2); // clean up metaService.removeTagElement(meta); }); - }); describe('integration test', () => { - @Injectable() class DependsOnMeta { constructor(public meta: Meta) {} diff --git a/packages/platform-browser/test/browser/title_spec.ts b/packages/platform-browser/test/browser/title_spec.ts index e99244ab7304d..4f885fc27873e 100644 --- a/packages/platform-browser/test/browser/title_spec.ts +++ b/packages/platform-browser/test/browser/title_spec.ts @@ -24,10 +24,13 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; titleService = new Title(doc); }); - afterEach(() => { doc.title = initialTitle; }); + afterEach(() => { + doc.title = initialTitle; + }); - it('should allow reading initial title', - () => { expect(titleService.getTitle()).toEqual(initialTitle); }); + it('should allow reading initial title', () => { + expect(titleService.getTitle()).toEqual(initialTitle); + }); it('should set a title on the injected document', () => { titleService.setTitle('test title'); @@ -36,13 +39,12 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); it('should reset title to empty string if title not provided', () => { - titleService.setTitle(null !); + titleService.setTitle(null!); expect(doc.title).toEqual(''); }); }); describe('integration test', () => { - @Injectable() class DependsOnTitle { constructor(public title: Title) {} @@ -55,7 +57,8 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; }); }); - it('should inject Title service when using BrowserModule', - () => { expect(TestBed.inject(DependsOnTitle).title).toBeAnInstanceOf(Title); }); + it('should inject Title service when using BrowserModule', () => { + expect(TestBed.inject(DependsOnTitle).title).toBeAnInstanceOf(Title); + }); }); } diff --git a/packages/platform-browser/test/browser/tools/spies.ts b/packages/platform-browser/test/browser/tools/spies.ts index 40f3bdce9e981..84bd9a8e29634 100644 --- a/packages/platform-browser/test/browser/tools/spies.ts +++ b/packages/platform-browser/test/browser/tools/spies.ts @@ -11,7 +11,9 @@ import {ApplicationRef} from '@angular/core/src/application_ref'; import {SpyObject} from '@angular/core/testing/src/testing_internal'; export class SpyApplicationRef extends SpyObject { - constructor() { super(ApplicationRef); } + constructor() { + super(ApplicationRef); + } } export class SpyComponentRef extends SpyObject { diff --git a/packages/platform-browser/test/browser/tools/tools_spec.ts b/packages/platform-browser/test/browser/tools/tools_spec.ts index e66f217d4585d..f747f987c6379 100644 --- a/packages/platform-browser/test/browser/tools/tools_spec.ts +++ b/packages/platform-browser/test/browser/tools/tools_spec.ts @@ -8,18 +8,25 @@ import {disableDebugTools, enableDebugTools} from '@angular/platform-browser'; -import {SpyComponentRef, callNgProfilerTimeChangeDetection} from './spies'; +import {callNgProfilerTimeChangeDetection, SpyComponentRef} from './spies'; { describe('profiler', () => { if (isNode) return; - beforeEach(() => { enableDebugTools((<any>new SpyComponentRef())); }); + beforeEach(() => { + enableDebugTools((<any>new SpyComponentRef())); + }); - afterEach(() => { disableDebugTools(); }); + afterEach(() => { + disableDebugTools(); + }); - it('should time change detection', () => { callNgProfilerTimeChangeDetection(); }); + it('should time change detection', () => { + callNgProfilerTimeChangeDetection(); + }); - it('should time change detection with recording', - () => { callNgProfilerTimeChangeDetection({'record': true}); }); + it('should time change detection with recording', () => { + callNgProfilerTimeChangeDetection({'record': true}); + }); }); } diff --git a/packages/platform-browser/test/browser/transfer_state_spec.ts b/packages/platform-browser/test/browser/transfer_state_spec.ts index f2a3fa0ed4e00..56cb3e9dddd19 100644 --- a/packages/platform-browser/test/browser/transfer_state_spec.ts +++ b/packages/platform-browser/test/browser/transfer_state_spec.ts @@ -9,124 +9,126 @@ import {DOCUMENT} from '@angular/common'; import {TestBed} from '@angular/core/testing'; import {BrowserModule, BrowserTransferStateModule, TransferState} from '@angular/platform-browser'; -import {StateKey, escapeHtml, makeStateKey, unescapeHtml} from '@angular/platform-browser/src/browser/transfer_state'; +import {escapeHtml, makeStateKey, StateKey, unescapeHtml} from '@angular/platform-browser/src/browser/transfer_state'; (function() { - function removeScriptTag(doc: Document, id: string) { - const existing = doc.getElementById(id); - if (existing) { - doc.body.removeChild(existing); - } +function removeScriptTag(doc: Document, id: string) { + const existing = doc.getElementById(id); + if (existing) { + doc.body.removeChild(existing); } - - function addScriptTag(doc: Document, appId: string, data: {}) { - const script = doc.createElement('script'); - const id = appId + '-state'; - script.id = id; - script.setAttribute('type', 'application/json'); - script.textContent = escapeHtml(JSON.stringify(data)); - - // Remove any stale script tags. - removeScriptTag(doc, id); - - doc.body.appendChild(script); - } - - describe('TransferState', () => { - const APP_ID = 'test-app'; - let doc: Document; - - const TEST_KEY = makeStateKey<number>('test'); - const DELAYED_KEY = makeStateKey<string>('delayed'); - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - BrowserModule.withServerTransition({appId: APP_ID}), - BrowserTransferStateModule, - ] - }); - doc = TestBed.inject(DOCUMENT); +} + +function addScriptTag(doc: Document, appId: string, data: {}) { + const script = doc.createElement('script'); + const id = appId + '-state'; + script.id = id; + script.setAttribute('type', 'application/json'); + script.textContent = escapeHtml(JSON.stringify(data)); + + // Remove any stale script tags. + removeScriptTag(doc, id); + + doc.body.appendChild(script); +} + +describe('TransferState', () => { + const APP_ID = 'test-app'; + let doc: Document; + + const TEST_KEY = makeStateKey<number>('test'); + const DELAYED_KEY = makeStateKey<string>('delayed'); + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + BrowserModule.withServerTransition({appId: APP_ID}), + BrowserTransferStateModule, + ] }); + doc = TestBed.inject(DOCUMENT); + }); - afterEach(() => { removeScriptTag(doc, APP_ID + '-state'); }); + afterEach(() => { + removeScriptTag(doc, APP_ID + '-state'); + }); - it('is initialized from script tag', () => { - addScriptTag(doc, APP_ID, {test: 10}); - const transferState: TransferState = TestBed.inject(TransferState); - expect(transferState.get(TEST_KEY, 0)).toBe(10); - }); + it('is initialized from script tag', () => { + addScriptTag(doc, APP_ID, {test: 10}); + const transferState: TransferState = TestBed.inject(TransferState); + expect(transferState.get(TEST_KEY, 0)).toBe(10); + }); - it('is initialized to empty state if script tag not found', () => { - const transferState: TransferState = TestBed.inject(TransferState); - expect(transferState.get(TEST_KEY, 0)).toBe(0); - }); + it('is initialized to empty state if script tag not found', () => { + const transferState: TransferState = TestBed.inject(TransferState); + expect(transferState.get(TEST_KEY, 0)).toBe(0); + }); - it('supports adding new keys using set', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, 20); - expect(transferState.get(TEST_KEY, 0)).toBe(20); - expect(transferState.hasKey(TEST_KEY)).toBe(true); - }); + it('supports adding new keys using set', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, 20); + expect(transferState.get(TEST_KEY, 0)).toBe(20); + expect(transferState.hasKey(TEST_KEY)).toBe(true); + }); - it('supports setting and accessing value \'0\' via get', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, 0); - expect(transferState.get(TEST_KEY, 20)).toBe(0); - expect(transferState.hasKey(TEST_KEY)).toBe(true); - }); + it('supports setting and accessing value \'0\' via get', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, 0); + expect(transferState.get(TEST_KEY, 20)).toBe(0); + expect(transferState.hasKey(TEST_KEY)).toBe(true); + }); - it('supports setting and accessing value \'false\' via get', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, false); - expect(transferState.get(TEST_KEY, true)).toBe(false); - expect(transferState.hasKey(TEST_KEY)).toBe(true); - }); + it('supports setting and accessing value \'false\' via get', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, false); + expect(transferState.get(TEST_KEY, true)).toBe(false); + expect(transferState.hasKey(TEST_KEY)).toBe(true); + }); - it('supports setting and accessing value \'null\' via get', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, null); - expect(transferState.get(TEST_KEY, 20 as any)).toBe(null); - expect(transferState.hasKey(TEST_KEY)).toBe(true); - }); + it('supports setting and accessing value \'null\' via get', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, null); + expect(transferState.get(TEST_KEY, 20 as any)).toBe(null); + expect(transferState.hasKey(TEST_KEY)).toBe(true); + }); - it('supports removing keys', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, 20); - transferState.remove(TEST_KEY); - expect(transferState.get(TEST_KEY, 0)).toBe(0); - expect(transferState.hasKey(TEST_KEY)).toBe(false); - }); + it('supports removing keys', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, 20); + transferState.remove(TEST_KEY); + expect(transferState.get(TEST_KEY, 0)).toBe(0); + expect(transferState.hasKey(TEST_KEY)).toBe(false); + }); - it('supports serialization using toJson()', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, 20); - expect(transferState.toJson()).toBe('{"test":20}'); - }); + it('supports serialization using toJson()', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, 20); + expect(transferState.toJson()).toBe('{"test":20}'); + }); - it('calls onSerialize callbacks when calling toJson()', () => { - const transferState: TransferState = TestBed.inject(TransferState); - transferState.set(TEST_KEY, 20); + it('calls onSerialize callbacks when calling toJson()', () => { + const transferState: TransferState = TestBed.inject(TransferState); + transferState.set(TEST_KEY, 20); - let value = 'initial'; - transferState.onSerialize(DELAYED_KEY, () => value); - value = 'changed'; + let value = 'initial'; + transferState.onSerialize(DELAYED_KEY, () => value); + value = 'changed'; - expect(transferState.toJson()).toBe('{"test":20,"delayed":"changed"}'); - }); + expect(transferState.toJson()).toBe('{"test":20,"delayed":"changed"}'); }); - - describe('escape/unescape', () => { - it('works with all escaped characters', () => { - const testString = '</script><script>alert(\'Hello&\' + "World");'; - const testObj = {testString}; - const escaped = escapeHtml(JSON.stringify(testObj)); - expect(escaped).toBe( - '{&q;testString&q;:&q;&l;/script&g;&l;script&g;' + - 'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}'); - - const unescapedObj = JSON.parse(unescapeHtml(escaped)); - expect(unescapedObj['testString']).toBe(testString); - }); +}); + +describe('escape/unescape', () => { + it('works with all escaped characters', () => { + const testString = '</script><script>alert(\'Hello&\' + "World");'; + const testObj = {testString}; + const escaped = escapeHtml(JSON.stringify(testObj)); + expect(escaped).toBe( + '{&q;testString&q;:&q;&l;/script&g;&l;script&g;' + + 'alert(&s;Hello&a;&s; + \\&q;World\\&q;);&q;}'); + + const unescapedObj = JSON.parse(unescapeHtml(escaped)); + expect(unescapedObj['testString']).toBe(testString); }); +}); })(); diff --git a/packages/platform-browser/test/browser_util_spec.ts b/packages/platform-browser/test/browser_util_spec.ts index 664f2cc3667f6..d67a429724633 100644 --- a/packages/platform-browser/test/browser_util_spec.ts +++ b/packages/platform-browser/test/browser_util_spec.ts @@ -11,7 +11,6 @@ import {BrowserDetection} from '../testing/src/browser_util'; { describe('BrowserDetection', () => { - const browsers = [ { name: 'Chrome', @@ -224,7 +223,7 @@ import {BrowserDetection} from '../testing/src/browser_util'; ]; browsers.forEach((browser: {[key: string]: any}) => { - it(`should detect ${browser[ 'name']}`, () => { + it(`should detect ${browser['name']}`, () => { const bd = new BrowserDetection(<string>browser['ua']); expect(bd.isFirefox).toBe(browser['isFirefox']); expect(bd.isAndroid).toBe(browser['isAndroid']); diff --git a/packages/platform-browser/test/dom/events/event_manager_spec.ts b/packages/platform-browser/test/dom/events/event_manager_spec.ts index 8c433500fd1ba..6dc8fa356e4b2 100644 --- a/packages/platform-browser/test/dom/events/event_manager_spec.ts +++ b/packages/platform-browser/test/dom/events/event_manager_spec.ts @@ -14,361 +14,393 @@ import {EventManager, EventManagerPlugin} from '@angular/platform-browser/src/do import {createMouseEvent, el} from '../../../testing/src/browser_util'; (function() { - if (isNode) return; - let domEventPlugin: DomEventsPlugin; - let doc: any; - let zone: NgZone; - - describe('EventManager', () => { - beforeEach(() => { - doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument(); - zone = new NgZone({}); - domEventPlugin = new DomEventsPlugin(doc); - }); +if (isNode) return; +let domEventPlugin: DomEventsPlugin; +let doc: any; +let zone: NgZone; + +describe('EventManager', () => { + beforeEach(() => { + doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument(); + zone = new NgZone({}); + domEventPlugin = new DomEventsPlugin(doc); + }); - it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one', - () => { - const element = el('<div></div>'); - const handler = (e: any /** TODO #9100 */) => e; - const plugin = new FakeEventManagerPlugin(doc, ['click']); - const manager = new EventManager([domEventPlugin, plugin], new FakeNgZone()); - manager.addEventListener(element, 'click', handler); - expect(plugin.eventHandler['click']).toBe(handler); - }); - - it('should delegate event bindings to the first plugin supporting the event', () => { - const element = el('<div></div>'); - const clickHandler = (e: any /** TODO #9100 */) => e; - const dblClickHandler = (e: any /** TODO #9100 */) => e; - const plugin1 = new FakeEventManagerPlugin(doc, ['dblclick']); - const plugin2 = new FakeEventManagerPlugin(doc, ['click', 'dblclick']); - const manager = new EventManager([plugin2, plugin1], new FakeNgZone()); - manager.addEventListener(element, 'click', clickHandler); - manager.addEventListener(element, 'dblclick', dblClickHandler); - expect(plugin2.eventHandler['click']).toBe(clickHandler); - expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler); - }); + it('should delegate event bindings to plugins that are passed in from the most generic one to the most specific one', + () => { + const element = el('<div></div>'); + const handler = (e: any /** TODO #9100 */) => e; + const plugin = new FakeEventManagerPlugin(doc, ['click']); + const manager = new EventManager([domEventPlugin, plugin], new FakeNgZone()); + manager.addEventListener(element, 'click', handler); + expect(plugin.eventHandler['click']).toBe(handler); + }); + + it('should delegate event bindings to the first plugin supporting the event', () => { + const element = el('<div></div>'); + const clickHandler = (e: any /** TODO #9100 */) => e; + const dblClickHandler = (e: any /** TODO #9100 */) => e; + const plugin1 = new FakeEventManagerPlugin(doc, ['dblclick']); + const plugin2 = new FakeEventManagerPlugin(doc, ['click', 'dblclick']); + const manager = new EventManager([plugin2, plugin1], new FakeNgZone()); + manager.addEventListener(element, 'click', clickHandler); + manager.addEventListener(element, 'dblclick', dblClickHandler); + expect(plugin2.eventHandler['click']).toBe(clickHandler); + expect(plugin1.eventHandler['dblclick']).toBe(dblClickHandler); + }); - it('should throw when no plugin can handle the event', () => { - const element = el('<div></div>'); - const plugin = new FakeEventManagerPlugin(doc, ['dblclick']); - const manager = new EventManager([plugin], new FakeNgZone()); - expect(() => manager.addEventListener(element, 'click', null !)) - .toThrowError('No event manager plugin found for event click'); - }); + it('should throw when no plugin can handle the event', () => { + const element = el('<div></div>'); + const plugin = new FakeEventManagerPlugin(doc, ['dblclick']); + const manager = new EventManager([plugin], new FakeNgZone()); + expect(() => manager.addEventListener(element, 'click', null!)) + .toThrowError('No event manager plugin found for event click'); + }); - it('events are caught when fired from a child', () => { - const element = el('<div><div></div></div>'); - // Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755 - doc.body.appendChild(element); + it('events are caught when fired from a child', () => { + const element = el('<div><div></div></div>'); + // Workaround for https://bugs.webkit.org/show_bug.cgi?id=122755 + doc.body.appendChild(element); + + const child = element.firstChild as Element; + const dispatchedEvent = createMouseEvent('click'); + let receivedEvent: any /** TODO #9100 */ = null; + const handler = (e: any /** TODO #9100 */) => { + receivedEvent = e; + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + manager.addEventListener(element, 'click', handler); + getDOM().dispatchEvent(child, dispatchedEvent); + + expect(receivedEvent).toBe(dispatchedEvent); + }); - const child = element.firstChild as Element; - const dispatchedEvent = createMouseEvent('click'); - let receivedEvent: any /** TODO #9100 */ = null; - const handler = (e: any /** TODO #9100 */) => { receivedEvent = e; }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - manager.addEventListener(element, 'click', handler); - getDOM().dispatchEvent(child, dispatchedEvent); + it('should add and remove global event listeners', () => { + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvent: any /** TODO #9100 */ = null; + const handler = (e: any /** TODO #9100 */) => { + receivedEvent = e; + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + const remover = manager.addGlobalEventListener('document', 'click', handler); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvent).toBe(dispatchedEvent); + + receivedEvent = null; + remover(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvent).toBe(null); + }); - expect(receivedEvent).toBe(dispatchedEvent); + it('should keep zone when addEventListener', () => { + const Zone = (window as any)['Zone']; + + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvent: any /** TODO #9100 */ = null; + let receivedZone: any = null; + const handler = (e: any /** TODO #9100 */) => { + receivedEvent = e; + receivedZone = Zone.current; + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + let remover: any = null; + Zone.root.run(() => { + remover = manager.addEventListener(element, 'click', handler); }); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvent).toBe(dispatchedEvent); + expect(receivedZone.name).toBe(Zone.root.name); + + receivedEvent = null; + remover && remover(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvent).toBe(null); + }); - it('should add and remove global event listeners', () => { - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvent: any /** TODO #9100 */ = null; - const handler = (e: any /** TODO #9100 */) => { receivedEvent = e; }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - const remover = manager.addGlobalEventListener('document', 'click', handler); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvent).toBe(dispatchedEvent); - - receivedEvent = null; - remover(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvent).toBe(null); + it('should keep zone when addEventListener multiple times', () => { + const Zone = (window as any)['Zone']; + + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvents: any[] /** TODO #9100 */ = []; + let receivedZones: any[] = []; + const handler1 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const handler2 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + let remover1: any = null; + let remover2: any = null; + Zone.root.run(() => { + remover1 = manager.addEventListener(element, 'click', handler1); }); - - it('should keep zone when addEventListener', () => { - const Zone = (window as any)['Zone']; - - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvent: any /** TODO #9100 */ = null; - let receivedZone: any = null; - const handler = (e: any /** TODO #9100 */) => { - receivedEvent = e; - receivedZone = Zone.current; - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - let remover: any = null; - Zone.root.run(() => { remover = manager.addEventListener(element, 'click', handler); }); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvent).toBe(dispatchedEvent); - expect(receivedZone.name).toBe(Zone.root.name); - - receivedEvent = null; - remover && remover(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvent).toBe(null); + Zone.root.fork({name: 'test'}).run(() => { + remover2 = manager.addEventListener(element, 'click', handler2); }); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]); + expect(receivedZones).toEqual([Zone.root.name, 'test']); + + receivedEvents = []; + remover1 && remover1(); + remover2 && remover2(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([]); + }); - it('should keep zone when addEventListener multiple times', () => { - const Zone = (window as any)['Zone']; - - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvents: any[] /** TODO #9100 */ = []; - let receivedZones: any[] = []; - const handler1 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const handler2 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - let remover1: any = null; - let remover2: any = null; - Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); }); - Zone.root.fork({name: 'test'}).run(() => { - remover2 = manager.addEventListener(element, 'click', handler2); - }); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]); - expect(receivedZones).toEqual([Zone.root.name, 'test']); - - receivedEvents = []; - remover1 && remover1(); - remover2 && remover2(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([]); + it('should support event.stopImmediatePropagation', () => { + const Zone = (window as any)['Zone']; + + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvents: any[] /** TODO #9100 */ = []; + let receivedZones: any[] = []; + const handler1 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + e.stopImmediatePropagation(); + }; + const handler2 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + let remover1: any = null; + let remover2: any = null; + Zone.root.run(() => { + remover1 = manager.addEventListener(element, 'click', handler1); }); - - it('should support event.stopImmediatePropagation', () => { - const Zone = (window as any)['Zone']; - - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvents: any[] /** TODO #9100 */ = []; - let receivedZones: any[] = []; - const handler1 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - e.stopImmediatePropagation(); - }; - const handler2 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - let remover1: any = null; - let remover2: any = null; - Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); }); - Zone.root.fork({name: 'test'}).run(() => { - remover2 = manager.addEventListener(element, 'click', handler2); - }); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([dispatchedEvent]); - expect(receivedZones).toEqual([Zone.root.name]); - - receivedEvents = []; - remover1 && remover1(); - remover2 && remover2(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([]); + Zone.root.fork({name: 'test'}).run(() => { + remover2 = manager.addEventListener(element, 'click', handler2); }); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([dispatchedEvent]); + expect(receivedZones).toEqual([Zone.root.name]); + + receivedEvents = []; + remover1 && remover1(); + remover2 && remover2(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([]); + }); - it('should handle event correctly when one handler remove itself ', () => { - const Zone = (window as any)['Zone']; - - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvents: any[] /** TODO #9100 */ = []; - let receivedZones: any[] = []; - let remover1: any = null; - let remover2: any = null; - const handler1 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - remover1 && remover1(); - }; - const handler2 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); }); - Zone.root.fork({name: 'test'}).run(() => { - remover2 = manager.addEventListener(element, 'click', handler2); - }); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]); - expect(receivedZones).toEqual([Zone.root.name, 'test']); - - receivedEvents = []; + it('should handle event correctly when one handler remove itself ', () => { + const Zone = (window as any)['Zone']; + + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvents: any[] /** TODO #9100 */ = []; + let receivedZones: any[] = []; + let remover1: any = null; + let remover2: any = null; + const handler1 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); remover1 && remover1(); - remover2 && remover2(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([]); + }; + const handler2 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + Zone.root.run(() => { + remover1 = manager.addEventListener(element, 'click', handler1); }); - - it('should only add same callback once when addEventListener', () => { - const Zone = (window as any)['Zone']; - - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvents: any[] /** TODO #9100 */ = []; - let receivedZones: any[] = []; - const handler = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - let remover1: any = null; - let remover2: any = null; - Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler); }); - Zone.root.fork({name: 'test'}).run(() => { - remover2 = manager.addEventListener(element, 'click', handler); - }); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([dispatchedEvent]); - expect(receivedZones).toEqual([Zone.root.name]); - - receivedEvents = []; - remover1 && remover1(); - remover2 && remover2(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([]); + Zone.root.fork({name: 'test'}).run(() => { + remover2 = manager.addEventListener(element, 'click', handler2); }); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]); + expect(receivedZones).toEqual([Zone.root.name, 'test']); + + receivedEvents = []; + remover1 && remover1(); + remover2 && remover2(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([]); + }); - it('should be able to remove event listener which was added inside of ngZone', () => { - const Zone = (window as any)['Zone']; - - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvents: any[] /** TODO #9100 */ = []; - let receivedZones: any[] = []; - const handler1 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const handler2 = (e: any /** TODO #9100 */) => { - receivedEvents.push(e); - receivedZones.push(Zone.current.name); - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - let remover1: any = null; - let remover2: any = null; - // handler1 is added in root zone - Zone.root.run(() => { remover1 = manager.addEventListener(element, 'click', handler1); }); - // handler2 is added in 'angular' zone - Zone.root.fork({name: 'fakeAngularZone', properties: {isAngularZone: true}}).run(() => { - remover2 = manager.addEventListener(element, 'click', handler2); - }); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]); - expect(receivedZones).toEqual([Zone.root.name, 'fakeAngularZone']); - - receivedEvents = []; - remover1 && remover1(); - remover2 && remover2(); - getDOM().dispatchEvent(element, dispatchedEvent); - // handler1 and handler2 are added in different zone - // one is angular zone, the other is not - // should still be able to remove them correctly - expect(receivedEvents).toEqual([]); + it('should only add same callback once when addEventListener', () => { + const Zone = (window as any)['Zone']; + + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvents: any[] /** TODO #9100 */ = []; + let receivedZones: any[] = []; + const handler = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + let remover1: any = null; + let remover2: any = null; + Zone.root.run(() => { + remover1 = manager.addEventListener(element, 'click', handler); + }); + Zone.root.fork({name: 'test'}).run(() => { + remover2 = manager.addEventListener(element, 'click', handler); }); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([dispatchedEvent]); + expect(receivedZones).toEqual([Zone.root.name]); + + receivedEvents = []; + remover1 && remover1(); + remover2 && remover2(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([]); + }); - it('should run blackListedEvents handler outside of ngZone', () => { - const Zone = (window as any)['Zone']; - const element = el('<div><div></div></div>'); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('scroll'); - let receivedEvent: any /** TODO #9100 */ = null; - let receivedZone: any = null; - const handler = (e: any /** TODO #9100 */) => { - receivedEvent = e; - receivedZone = Zone.current; - }; - const manager = new EventManager([domEventPlugin], new FakeNgZone()); - - let remover = manager.addEventListener(element, 'scroll', handler); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvent).toBe(dispatchedEvent); - expect(receivedZone.name).not.toEqual('angular'); - - receivedEvent = null; - remover && remover(); - getDOM().dispatchEvent(element, dispatchedEvent); - expect(receivedEvent).toBe(null); + it('should be able to remove event listener which was added inside of ngZone', () => { + const Zone = (window as any)['Zone']; + + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvents: any[] /** TODO #9100 */ = []; + let receivedZones: any[] = []; + const handler1 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const handler2 = (e: any /** TODO #9100 */) => { + receivedEvents.push(e); + receivedZones.push(Zone.current.name); + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + let remover1: any = null; + let remover2: any = null; + // handler1 is added in root zone + Zone.root.run(() => { + remover1 = manager.addEventListener(element, 'click', handler1); + }); + // handler2 is added in 'angular' zone + Zone.root.fork({name: 'fakeAngularZone', properties: {isAngularZone: true}}).run(() => { + remover2 = manager.addEventListener(element, 'click', handler2); }); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvents).toEqual([dispatchedEvent, dispatchedEvent]); + expect(receivedZones).toEqual([Zone.root.name, 'fakeAngularZone']); + + receivedEvents = []; + remover1 && remover1(); + remover2 && remover2(); + getDOM().dispatchEvent(element, dispatchedEvent); + // handler1 and handler2 are added in different zone + // one is angular zone, the other is not + // should still be able to remove them correctly + expect(receivedEvents).toEqual([]); + }); + + it('should run blackListedEvents handler outside of ngZone', () => { + const Zone = (window as any)['Zone']; + const element = el('<div><div></div></div>'); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('scroll'); + let receivedEvent: any /** TODO #9100 */ = null; + let receivedZone: any = null; + const handler = (e: any /** TODO #9100 */) => { + receivedEvent = e; + receivedZone = Zone.current; + }; + const manager = new EventManager([domEventPlugin], new FakeNgZone()); + + let remover = manager.addEventListener(element, 'scroll', handler); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvent).toBe(dispatchedEvent); + expect(receivedZone.name).not.toEqual('angular'); + + receivedEvent = null; + remover && remover(); + getDOM().dispatchEvent(element, dispatchedEvent); + expect(receivedEvent).toBe(null); + }); - it('should only trigger one Change detection when bubbling', (done: DoneFn) => { - doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument(); - zone = new NgZone({shouldCoalesceEventChangeDetection: true}); - domEventPlugin = new DomEventsPlugin(doc); - const element = el('<div></div>'); - const child = el('<div></div>'); - element.appendChild(child); - doc.body.appendChild(element); - const dispatchedEvent = createMouseEvent('click'); - let receivedEvents: any = []; - let stables: any = []; - const handler = (e: any) => { receivedEvents.push(e); }; - const manager = new EventManager([domEventPlugin], zone); - let removerChild: any; - let removerParent: any; - - zone.run(() => { - removerChild = manager.addEventListener(child, 'click', handler); - removerParent = manager.addEventListener(element, 'click', handler); - }); - zone.onStable.subscribe((isStable: any) => { stables.push(isStable); }); - getDOM().dispatchEvent(child, dispatchedEvent); - requestAnimationFrame(() => { - expect(receivedEvents.length).toBe(2); - expect(stables.length).toBe(1); - - removerChild && removerChild(); - removerParent && removerParent(); - done(); - }); + it('should only trigger one Change detection when bubbling', (done: DoneFn) => { + doc = getDOM().supportsDOMEvents() ? document : getDOM().createHtmlDocument(); + zone = new NgZone({shouldCoalesceEventChangeDetection: true}); + domEventPlugin = new DomEventsPlugin(doc); + const element = el('<div></div>'); + const child = el('<div></div>'); + element.appendChild(child); + doc.body.appendChild(element); + const dispatchedEvent = createMouseEvent('click'); + let receivedEvents: any = []; + let stables: any = []; + const handler = (e: any) => { + receivedEvents.push(e); + }; + const manager = new EventManager([domEventPlugin], zone); + let removerChild: any; + let removerParent: any; + + zone.run(() => { + removerChild = manager.addEventListener(child, 'click', handler); + removerParent = manager.addEventListener(element, 'click', handler); + }); + zone.onStable.subscribe((isStable: any) => { + stables.push(isStable); + }); + getDOM().dispatchEvent(child, dispatchedEvent); + requestAnimationFrame(() => { + expect(receivedEvents.length).toBe(2); + expect(stables.length).toBe(1); + + removerChild && removerChild(); + removerParent && removerParent(); + done(); }); }); +}); })(); /** @internal */ class FakeEventManagerPlugin extends EventManagerPlugin { eventHandler: {[event: string]: Function} = {}; - constructor(doc: any, public supportedEvents: string[]) { super(doc); } + constructor(doc: any, public supportedEvents: string[]) { + super(doc); + } - supports(eventName: string): boolean { return this.supportedEvents.indexOf(eventName) > -1; } + supports(eventName: string): boolean { + return this.supportedEvents.indexOf(eventName) > -1; + } addEventListener(element: any, eventName: string, handler: Function) { this.eventHandler[eventName] = handler; - return () => { delete this.eventHandler[eventName]; }; + return () => { + delete this.eventHandler[eventName]; + }; } } class FakeNgZone extends NgZone { - constructor() { super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: true}); } - run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T { return fn(); } - runOutsideAngular(fn: Function) { return fn(); } + constructor() { + super({enableLongStackTrace: false, shouldCoalesceEventChangeDetection: true}); + } + run<T>(fn: (...args: any[]) => T, applyThis?: any, applyArgs?: any[]): T { + return fn(); + } + runOutsideAngular(fn: Function) { + return fn(); + } } diff --git a/packages/platform-browser/test/dom/shadow_dom_spec.ts b/packages/platform-browser/test/dom/shadow_dom_spec.ts index 0570dd9ee235e..54a0c472f1ada 100644 --- a/packages/platform-browser/test/dom/shadow_dom_spec.ts +++ b/packages/platform-browser/test/dom/shadow_dom_spec.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Component, EventEmitter, Injector, Input, NgModule, Output, Renderer2, ViewEncapsulation, destroyPlatform} from '@angular/core'; +import {Component, destroyPlatform, EventEmitter, Injector, Input, NgModule, Output, Renderer2, ViewEncapsulation} from '@angular/core'; import {TestBed} from '@angular/core/testing'; import {BrowserModule} from '@angular/platform-browser'; import {browserDetection} from '@angular/platform-browser/testing/src/browser_util'; @@ -15,14 +15,15 @@ import {expect} from '@angular/platform-browser/testing/src/matchers'; if (browserDetection.supportsShadowDom) { describe('ShadowDOM Support', () => { - let testContainer: HTMLDivElement; - beforeEach(() => { TestBed.configureTestingModule({imports: [TestModule]}); }); + beforeEach(() => { + TestBed.configureTestingModule({imports: [TestModule]}); + }); it('should attach and use a shadowRoot when ViewEncapsulation.Native is set', () => { const compEl = TestBed.createComponent(ShadowComponent).nativeElement; - expect(compEl.shadowRoot !.textContent).toEqual('Hello World'); + expect(compEl.shadowRoot!.textContent).toEqual('Hello World'); }); it('should use the shadow root to encapsulate styles', () => { @@ -40,10 +41,10 @@ if (browserDetection.supportsShadowDom) { const el = TestBed.createComponent(ShadowSlotComponent).nativeElement; const projectedContent = document.createTextNode('Hello Slot!'); el.appendChild(projectedContent); - const slot = el.shadowRoot !.querySelector('slot'); + const slot = el.shadowRoot!.querySelector('slot'); - expect(slot !.assignedNodes().length).toBe(1); - expect(slot !.assignedNodes()[0].textContent).toBe('Hello Slot!'); + expect(slot!.assignedNodes().length).toBe(1); + expect(slot!.assignedNodes()[0].textContent).toBe('Hello Slot!'); }); it('should allow the usage of named <slot> elements', () => { @@ -65,16 +66,16 @@ if (browserDetection.supportsShadowDom) { el.appendChild(articleContent); el.appendChild(articleSubcontent); - const headerSlot = el.shadowRoot !.querySelector('slot[name=header]') as HTMLSlotElement; - const articleSlot = el.shadowRoot !.querySelector('slot[name=article]') as HTMLSlotElement; + const headerSlot = el.shadowRoot!.querySelector('slot[name=header]') as HTMLSlotElement; + const articleSlot = el.shadowRoot!.querySelector('slot[name=article]') as HTMLSlotElement; - expect(headerSlot !.assignedNodes().length).toBe(1); - expect(headerSlot !.assignedNodes()[0].textContent).toBe('Header Text!'); + expect(headerSlot!.assignedNodes().length).toBe(1); + expect(headerSlot!.assignedNodes()[0].textContent).toBe('Header Text!'); expect(headerContent.assignedSlot).toBe(headerSlot); - expect(articleSlot !.assignedNodes().length).toBe(2); - expect(articleSlot !.assignedNodes()[0].textContent).toBe('Article Text!'); - expect(articleSlot !.assignedNodes()[1].textContent).toBe('Article Subtext!'); + expect(articleSlot!.assignedNodes().length).toBe(2); + expect(articleSlot!.assignedNodes()[0].textContent).toBe('Article Text!'); + expect(articleSlot!.assignedNodes()[1].textContent).toBe('Article Subtext!'); expect(articleContent.assignedSlot).toBe(articleSlot); expect(articleSubcontent.assignedSlot).toBe(articleSlot); }); diff --git a/packages/platform-browser/test/testing_public_spec.ts b/packages/platform-browser/test/testing_public_spec.ts index 24608a88bdef6..600e1415f1334 100644 --- a/packages/platform-browser/test/testing_public_spec.ts +++ b/packages/platform-browser/test/testing_public_spec.ts @@ -7,8 +7,8 @@ */ import {CompilerConfig, ResourceLoader} from '@angular/compiler'; -import {CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, ComponentFactoryResolver, Directive, Inject, Injectable, InjectionToken, Injector, Input, NgModule, Optional, Pipe, SkipSelf, ɵstringify as stringify} from '@angular/core'; -import {TestBed, async, fakeAsync, getTestBed, inject, tick, withModule} from '@angular/core/testing'; +import {Compiler, Component, ComponentFactoryResolver, CUSTOM_ELEMENTS_SCHEMA, Directive, Inject, Injectable, InjectionToken, Injector, Input, NgModule, Optional, Pipe, SkipSelf, ɵstringify as stringify} from '@angular/core'; +import {async, fakeAsync, getTestBed, inject, TestBed, tick, withModule} from '@angular/core/testing'; import {expect} from '@angular/platform-browser/testing/src/matchers'; import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/private/testing'; @@ -18,7 +18,9 @@ import {ivyEnabled, modifiedInIvy, obsoleteInIvy, onlyInIvy} from '@angular/priv @Injectable() class ChildComp { childBinding: string; - constructor() { this.childBinding = 'Child'; } + constructor() { + this.childBinding = 'Child'; + } } @Component({selector: 'child-comp', template: `<span>Mock</span>`}) @@ -52,12 +54,16 @@ class ChildChildComp { @Injectable() class ChildWithChildComp { childBinding: string; - constructor() { this.childBinding = 'Child'; } + constructor() { + this.childBinding = 'Child'; + } } class FancyService { value: string = 'real value'; - getAsyncValue() { return Promise.resolve('async value'); } + getAsyncValue() { + return Promise.resolve('async value'); + } getTimeoutValue() { return new Promise<string>((resolve, reject) => setTimeout(() => resolve('timeout value'), 10)); } @@ -88,13 +94,14 @@ class TestViewProvidersComp { @Directive({selector: '[someDir]', host: {'[title]': 'someDir'}}) class SomeDirective { // TODO(issue/24571): remove '!'. - @Input() - someDir !: string; + @Input() someDir!: string; } @Pipe({name: 'somePipe'}) class SomePipe { - transform(value: string) { return `transformed ${value}`; } + transform(value: string) { + return `transformed ${value}`; + } } @Component({selector: 'comp', template: `<div [someDir]="'someValue' | somePipe"></div>`}) @@ -120,11 +127,17 @@ const bTok = new InjectionToken<string>('b'); describe('using the async helper with context passing', () => { type TestContext = {actuallyDone: boolean}; - beforeEach(function(this: TestContext) { this.actuallyDone = false; }); + beforeEach(function(this: TestContext) { + this.actuallyDone = false; + }); - afterEach(function(this: TestContext) { expect(this.actuallyDone).toEqual(true); }); + afterEach(function(this: TestContext) { + expect(this.actuallyDone).toEqual(true); + }); - it('should run normal tests', function(this: TestContext) { this.actuallyDone = true; }); + it('should run normal tests', function(this: TestContext) { + this.actuallyDone = true; + }); it('should run normal async tests', function(this: TestContext, done) { setTimeout(() => { @@ -133,8 +146,9 @@ const bTok = new InjectionToken<string>('b'); }, 0); }); - it('should run async tests with tasks', - async(function(this: TestContext) { setTimeout(() => this.actuallyDone = true, 0); })); + it('should run async tests with tasks', async(function(this: TestContext) { + setTimeout(() => this.actuallyDone = true, 0); + })); it('should run async tests with promises', async(function(this: TestContext) { const p = new Promise((resolve, reject) => setTimeout(resolve, 10)); @@ -149,18 +163,26 @@ const bTok = new InjectionToken<string>('b'); type TestContext = {contextModified: boolean}; - beforeEach(function(this: TestContext) { this.contextModified = false; }); + beforeEach(function(this: TestContext) { + this.contextModified = false; + }); - afterEach(function(this: TestContext) { expect(this.contextModified).toEqual(true); }); + afterEach(function(this: TestContext) { + expect(this.contextModified).toEqual(true); + }); - it('should pass context to inject helper', - inject([], function(this: TestContext) { this.contextModified = true; })); + it('should pass context to inject helper', inject([], function(this: TestContext) { + this.contextModified = true; + })); - it('should pass context to fakeAsync helper', - fakeAsync(function(this: TestContext) { this.contextModified = true; })); + it('should pass context to fakeAsync helper', fakeAsync(function(this: TestContext) { + this.contextModified = true; + })); it('should pass context to withModule helper - simple', - withModule(moduleConfig, function(this: TestContext) { this.contextModified = true; })); + withModule(moduleConfig, function(this: TestContext) { + this.contextModified = true; + })); it('should pass context to withModule helper - advanced', withModule(moduleConfig) @@ -199,7 +221,7 @@ const bTok = new InjectionToken<string>('b'); it('should allow the use of fakeAsync', fakeAsync(inject([FancyService], (service: FancyService) => { - let value: string = undefined !; + let value: string = undefined!; service.getAsyncValue().then((val) => value = val); tick(); expect(value).toEqual('async value'); @@ -329,7 +351,9 @@ const bTok = new InjectionToken<string>('b'); describe('overwriting metadata', () => { @Pipe({name: 'undefined'}) class SomePipe { - transform(value: string): string { return `transformed ${value}`; } + transform(value: string): string { + return `transformed ${value}`; + } } @Directive({selector: '[undefined]'}) @@ -418,7 +442,6 @@ const bTok = new InjectionToken<string>('b'); }); describe('overriding providers', () => { - describe('in core', () => { it('ComponentFactoryResolver', () => { const componentFactoryMock = @@ -429,7 +452,6 @@ const bTok = new InjectionToken<string>('b'); }); describe('in NgModules', () => { - it('should support useValue', () => { TestBed.configureTestingModule({ providers: [ @@ -501,7 +523,9 @@ const bTok = new InjectionToken<string>('b'); @NgModule() class SomeModule { - constructor() { someModule = this; } + constructor() { + someModule = this; + } } TestBed.configureTestingModule({ @@ -731,11 +755,12 @@ const bTok = new InjectionToken<string>('b'); @Directive({selector: '[test]'}) class TestDir { - constructor() { testDir = this; } + constructor() { + testDir = this; + } // TODO(issue/24571): remove '!'. - @Input('test') - test !: string; + @Input('test') test!: string; } TestBed.overrideTemplateUsingTestingModule( @@ -746,7 +771,7 @@ const bTok = new InjectionToken<string>('b'); fixture.detectChanges(); expect(fixture.nativeElement).toHaveText('Hello world!'); expect(testDir).toBeAnInstanceOf(TestDir); - expect(testDir !.test).toBe('some prop'); + expect(testDir!.test).toBe('some prop'); }); it('should throw if the TestBed is already created', () => { @@ -776,9 +801,7 @@ const bTok = new InjectionToken<string>('b'); }); describe('setting up the compiler', () => { - describe('providers', () => { - it('should use set up providers', fakeAsync(() => { // Keeping this component inside the test is needed to make sure it's not resolved // prior to this test, thus having ɵcmp and a reference in resource @@ -869,8 +892,9 @@ const bTok = new InjectionToken<string>('b'); const itPromise = patchJasmineIt(); const barError = new Error('bar'); - it('throws an async error', - async(inject([], () => setTimeout(() => { throw barError; }, 0)))); + it('throws an async error', async(inject([], () => setTimeout(() => { + throw barError; + }, 0)))); itPromise.then(() => done.fail('Expected test to fail, but it did not'), (err) => { expect(err).toEqual(barError); @@ -883,7 +907,7 @@ const bTok = new InjectionToken<string>('b'); const itPromise = patchJasmineIt(); it('should fail with an error from a promise', async(inject([], () => { - let reject: (error: any) => void = undefined !; + let reject: (error: any) => void = undefined!; const promise = new Promise((_, rej) => reject = rej); const p = promise.then(() => expect(1).toEqual(2)); @@ -919,21 +943,23 @@ const bTok = new InjectionToken<string>('b'); } expect( - () => it( - 'should fail', withModule( - {declarations: [InlineCompWithUrlTemplate]}, - () => TestBed.createComponent(InlineCompWithUrlTemplate)))) + () => + it('should fail', + withModule( + {declarations: [InlineCompWithUrlTemplate]}, + () => TestBed.createComponent(InlineCompWithUrlTemplate)))) .toThrowError( ivyEnabled ? `Component 'InlineCompWithUrlTemplate' is not resolved: - templateUrl: /base/angular/packages/platform-browser/test/static_assets/test.html Did you run and wait for 'resolveComponentResources()'?` : - `This test module uses the component ${stringify(InlineCompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` + + `This test module uses the component ${ + stringify( + InlineCompWithUrlTemplate)} which is using a "templateUrl" or "styleUrls", but they were never compiled. ` + `Please call "TestBed.compileComponents" before your test.`); restoreJasmineIt(); }); - }); @@ -972,7 +998,6 @@ Did you run and wait for 'resolveComponentResources()'?` : }); describe('creating components', () => { - beforeEach(() => { TestBed.configureTestingModule({ declarations: [ @@ -1008,7 +1033,6 @@ Did you run and wait for 'resolveComponentResources()'?` : const componentFixture = TestBed.createComponent(ChildComp); componentFixture.detectChanges(); expect(componentFixture.nativeElement).toHaveText('Mock'); - })); it('should override a provider', async(() => { diff --git a/packages/platform-browser/testing/src/browser.ts b/packages/platform-browser/testing/src/browser.ts index 77f9d7675f12d..e9d931e98601a 100644 --- a/packages/platform-browser/testing/src/browser.ts +++ b/packages/platform-browser/testing/src/browser.ts @@ -5,8 +5,9 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import {APP_ID, NgModule, NgZone, PLATFORM_INITIALIZER, PlatformRef, StaticProvider, createPlatformFactory, platformCore} from '@angular/core'; +import {APP_ID, createPlatformFactory, NgModule, NgZone, PLATFORM_INITIALIZER, platformCore, PlatformRef, StaticProvider} from '@angular/core'; import {BrowserModule, ɵBrowserDomAdapter as BrowserDomAdapter, ɵELEMENT_PROBE_PROVIDERS as ELEMENT_PROBE_PROVIDERS} from '@angular/platform-browser'; + import {BrowserDetection, createNgZone} from './browser_util'; function initBrowserTests() { diff --git a/packages/platform-browser/testing/src/browser_util.ts b/packages/platform-browser/testing/src/browser_util.ts index 31d1382061732..8ebf893807570 100644 --- a/packages/platform-browser/testing/src/browser_util.ts +++ b/packages/platform-browser/testing/src/browser_util.ts @@ -19,11 +19,17 @@ export class BrowserDetection { return getDOM() ? getDOM().getUserAgent() : ''; } - static setup() { return new BrowserDetection(null); } + static setup() { + return new BrowserDetection(null); + } - constructor(ua: string|null) { this._overrideUa = ua; } + constructor(ua: string|null) { + this._overrideUa = ua; + } - get isFirefox(): boolean { return this._ua.indexOf('Firefox') > -1; } + get isFirefox(): boolean { + return this._ua.indexOf('Firefox') > -1; + } get isAndroid(): boolean { return this._ua.indexOf('Mozilla/5.0') > -1 && this._ua.indexOf('Android') > -1 && @@ -31,9 +37,13 @@ export class BrowserDetection { this._ua.indexOf('IEMobile') == -1; } - get isEdge(): boolean { return this._ua.indexOf('Edge') > -1; } + get isEdge(): boolean { + return this._ua.indexOf('Edge') > -1; + } - get isIE(): boolean { return this._ua.indexOf('Trident') > -1; } + get isIE(): boolean { + return this._ua.indexOf('Trident') > -1; + } get isWebkit(): boolean { return this._ua.indexOf('AppleWebKit') > -1 && this._ua.indexOf('Edge') == -1 && @@ -45,7 +55,9 @@ export class BrowserDetection { this._ua.indexOf('IEMobile') == -1; } - get isSlow(): boolean { return this.isAndroid || this.isIE || this.isIOS7; } + get isSlow(): boolean { + return this.isAndroid || this.isIE || this.isIOS7; + } // The Intl API is only natively supported in Chrome, Firefox, IE11 and Edge. // This detector is needed in tests to make the difference between: @@ -67,13 +79,17 @@ export class BrowserDetection { this._ua.indexOf('Edge') == -1; } - get supportsCustomElements() { return (typeof(<any>global).customElements !== 'undefined'); } + get supportsCustomElements() { + return (typeof (<any>global).customElements !== 'undefined'); + } get supportsDeprecatedCustomCustomElementsV0() { - return (typeof(document as any).registerElement !== 'undefined'); + return (typeof (document as any).registerElement !== 'undefined'); } - get supportsRegExUnicodeFlag(): boolean { return RegExp.prototype.hasOwnProperty('unicode'); } + get supportsRegExUnicodeFlag(): boolean { + return RegExp.prototype.hasOwnProperty('unicode'); + } get supportsShadowDom() { const testEl = document.createElement('div'); @@ -203,10 +219,10 @@ export function setCookie(name: string, value: string) { } export function supportsWebAnimation(): boolean { - return typeof(<any>Element).prototype['animate'] === 'function'; + return typeof (<any>Element).prototype['animate'] === 'function'; } -export function hasStyle(element: any, styleName: string, styleValue?: string | null): boolean { +export function hasStyle(element: any, styleName: string, styleValue?: string|null): boolean { const value = element.style[styleName] || ''; return styleValue ? value == styleValue : value.length > 0; } diff --git a/packages/platform-browser/testing/src/matchers.ts b/packages/platform-browser/testing/src/matchers.ts index b582f4e599bbb..a6290562696ef 100644 --- a/packages/platform-browser/testing/src/matchers.ts +++ b/packages/platform-browser/testing/src/matchers.ts @@ -123,7 +123,9 @@ export const expect: <T = any>(actual: T) => NgMatchers<T> = _global.expect; return '' + m; } const res: any[] = []; - m.forEach((v: any, k: any) => { res.push(`${String(k)}:${String(v)}`); }); + m.forEach((v: any, k: any) => { + res.push(`${String(k)}:${String(v)}`); + }); return `{ ${res.join(',')} }`; }; @@ -141,7 +143,7 @@ _global.beforeEach(function() { return pass; } else { // TODO(misko): we should change the return, but jasmine.d.ts is not null safe - return undefined !; + return undefined!; } }); jasmine.addMatchers({ @@ -149,7 +151,12 @@ _global.beforeEach(function() { return { compare: function(actual: any) { const pass = typeof actual === 'object' && typeof actual.then === 'function'; - return {pass: pass, get message() { return 'Expected ' + actual + ' to be a promise'; }}; + return { + pass: pass, + get message() { + return 'Expected ' + actual + ' to be a promise'; + } + }; } }; }, @@ -174,7 +181,9 @@ _global.beforeEach(function() { const actualText = elementText(actual); return { pass: actualText == expectedText, - get message() { return 'Expected ' + actualText + ' to be equal to ' + expectedText; } + get message() { + return 'Expected ' + actualText + ' to be equal to ' + expectedText; + } }; } }; @@ -188,7 +197,8 @@ _global.beforeEach(function() { return { pass: hasClass(actual, className) == !isNot, get message() { - return `Expected ${actual.outerHTML} ${isNot ? 'not ' : ''}to contain the CSS class "${className}"`; + return `Expected ${actual.outerHTML} ${ + isNot ? 'not ' : ''}to contain the CSS class "${className}"`; } }; }; @@ -203,8 +213,9 @@ _global.beforeEach(function() { allPassed = hasStyle(actual, styles); } else { allPassed = Object.keys(styles).length !== 0; - Object.keys(styles).forEach( - prop => { allPassed = allPassed && hasStyle(actual, prop, styles[prop]); }); + Object.keys(styles).forEach(prop => { + allPassed = allPassed && hasStyle(actual, prop, styles[prop]); + }); } return { @@ -212,7 +223,8 @@ _global.beforeEach(function() { get message() { const expectedValueStr = typeof styles === 'string' ? styles : JSON.stringify(styles); return `Expected ${actual.outerHTML} ${!allPassed ? ' ' : 'not '}to contain the - CSS ${typeof styles === 'string' ? 'property' : 'styles'} "${expectedValueStr}"`; + CSS ${typeof styles === 'string' ? 'property' : 'styles'} "${ + expectedValueStr}"`; } }; } @@ -225,7 +237,9 @@ _global.beforeEach(function() { const errorMessage = actual.toString(); return { pass: errorMessage.indexOf(expectedText) > -1, - get message() { return 'Expected ' + errorMessage + ' to contain ' + expectedText; } + get message() { + return 'Expected ' + errorMessage + ' to contain ' + expectedText; + } }; } }; @@ -244,8 +258,8 @@ _global.beforeEach(function() { return { pass: missedMethods.length == 0, get message() { - return 'Expected ' + actualObject + ' to have the following methods: ' + - missedMethods.join(', '); + return 'Expected ' + actualObject + + ' to have the following methods: ' + missedMethods.join(', '); } }; } @@ -262,8 +276,8 @@ _global.beforeEach(function() { if (!(actualFixture instanceof ComponentFixture)) { return { pass: false, - message: msgFn( - `Expected actual to be of type \'ComponentFixture\' [actual=${actualFixture.constructor.name}]`) + message: msgFn(`Expected actual to be of type \'ComponentFixture\' [actual=${ + actualFixture.constructor.name}]`) }; } diff --git a/packages/platform-server/src/domino_adapter.ts b/packages/platform-server/src/domino_adapter.ts index 87370fd9fbfee..c8f8f255dd7f4 100644 --- a/packages/platform-server/src/domino_adapter.ts +++ b/packages/platform-server/src/domino_adapter.ts @@ -52,11 +52,15 @@ export class DominoAdapter extends BrowserDomAdapter { console.log(error); } - logGroup(error: string) { console.error(error); } + logGroup(error: string) { + console.error(error); + } logGroupEnd() {} - supportsDOMEvents(): boolean { return false; } + supportsDOMEvents(): boolean { + return false; + } createHtmlDocument(): HTMLDocument { return parseDocument('<html><head><title>fakeTitle'); @@ -72,7 +76,9 @@ export class DominoAdapter extends BrowserDomAdapter { isElementNode(node: any): boolean { return node ? node.nodeType === DominoAdapter.defaultDoc.ELEMENT_NODE : false; } - isShadowRoot(node: any): boolean { return node.shadowRoot == node; } + isShadowRoot(node: any): boolean { + return node.shadowRoot == node; + } getProperty(el: Element, name: string): any { if (name === 'href') { @@ -100,10 +106,10 @@ export class DominoAdapter extends BrowserDomAdapter { } getBaseHref(doc: Document): string { - const base = doc.documentElement !.querySelector('base'); + const base = doc.documentElement!.querySelector('base'); let href = ''; if (base) { - href = base.getAttribute('href') !; + href = base.getAttribute('href')!; } // TODO(alxhub): Need relative path logic from BrowserDomAdapter here? return href; @@ -120,12 +126,24 @@ export class DominoAdapter extends BrowserDomAdapter { } } - getHistory(): History { throw _notImplemented('getHistory'); } - getLocation(): Location { throw _notImplemented('getLocation'); } - getUserAgent(): string { return 'Fake user agent'; } + getHistory(): History { + throw _notImplemented('getHistory'); + } + getLocation(): Location { + throw _notImplemented('getLocation'); + } + getUserAgent(): string { + return 'Fake user agent'; + } - performanceNow(): number { return Date.now(); } + performanceNow(): number { + return Date.now(); + } - supportsCookies(): boolean { return false; } - getCookie(name: string): string { throw _notImplemented('getCookie'); } + supportsCookies(): boolean { + return false; + } + getCookie(name: string): string { + throw _notImplemented('getCookie'); + } } diff --git a/packages/platform-server/src/http.ts b/packages/platform-server/src/http.ts index 37fec07dd8f70..981490dc47e28 100644 --- a/packages/platform-server/src/http.ts +++ b/packages/platform-server/src/http.ts @@ -17,13 +17,15 @@ import {Observable, Observer, Subscription} from 'rxjs'; @Injectable() export class ServerXhr implements XhrFactory { - build(): XMLHttpRequest { return new xhr2.XMLHttpRequest(); } + build(): XMLHttpRequest { + return new xhr2.XMLHttpRequest(); + } } export abstract class ZoneMacroTaskWrapper { wrap(request: S): Observable { return new Observable((observer: Observer) => { - let task: Task = null !; + let task: Task = null!; let scheduled: boolean = false; let sub: Subscription|null = null; let savedResult: any = null; @@ -100,9 +102,13 @@ export abstract class ZoneMacroTaskWrapper { export class ZoneClientBackend extends ZoneMacroTaskWrapper, HttpEvent> implements HttpBackend { - constructor(private backend: HttpBackend) { super(); } + constructor(private backend: HttpBackend) { + super(); + } - handle(request: HttpRequest): Observable> { return this.wrap(request); } + handle(request: HttpRequest): Observable> { + return this.wrap(request); + } protected delegate(request: HttpRequest): Observable> { return this.backend.handle(request); @@ -115,9 +121,6 @@ export function zoneWrappedInterceptingHandler(backend: HttpBackend, injector: I } export const SERVER_HTTP_PROVIDERS: Provider[] = [ - {provide: XhrFactory, useClass: ServerXhr}, { - provide: HttpHandler, - useFactory: zoneWrappedInterceptingHandler, - deps: [HttpBackend, Injector] - } + {provide: XhrFactory, useClass: ServerXhr}, + {provide: HttpHandler, useFactory: zoneWrappedInterceptingHandler, deps: [HttpBackend, Injector]} ]; diff --git a/packages/platform-server/src/location.ts b/packages/platform-server/src/location.ts index 55849154cea97..052e22334a145 100644 --- a/packages/platform-server/src/location.ts +++ b/packages/platform-server/src/location.ts @@ -54,34 +54,40 @@ export class ServerPlatformLocation implements PlatformLocation { } } - getBaseHrefFromDOM(): string { return getDOM().getBaseHref(this._doc) !; } + getBaseHrefFromDOM(): string { + return getDOM().getBaseHref(this._doc)!; + } onPopState(fn: LocationChangeListener): void { // No-op: a state stack is not implemented, so // no events will ever come. } - onHashChange(fn: LocationChangeListener): void { this._hashUpdate.subscribe(fn); } + onHashChange(fn: LocationChangeListener): void { + this._hashUpdate.subscribe(fn); + } - get url(): string { return `${this.pathname}${this.search}${this.hash}`; } + get url(): string { + return `${this.pathname}${this.search}${this.hash}`; + } private setHash(value: string, oldUrl: string) { if (this.hash === value) { // Don't fire events if the hash has not changed. return; } - (this as{hash: string}).hash = value; + (this as {hash: string}).hash = value; const newUrl = this.url; - scheduleMicroTask(() => this._hashUpdate.next({ - type: 'hashchange', state: null, oldUrl, newUrl - } as LocationChangeEvent)); + scheduleMicroTask( + () => this._hashUpdate.next( + {type: 'hashchange', state: null, oldUrl, newUrl} as LocationChangeEvent)); } replaceState(state: any, title: string, newUrl: string): void { const oldUrl = this.url; const parsedUrl = parseUrl(newUrl); - (this as{pathname: string}).pathname = parsedUrl.pathname; - (this as{search: string}).search = parsedUrl.search; + (this as {pathname: string}).pathname = parsedUrl.pathname; + (this as {search: string}).search = parsedUrl.search; this.setHash(parsedUrl.hash, oldUrl); } @@ -89,12 +95,18 @@ export class ServerPlatformLocation implements PlatformLocation { this.replaceState(state, title, newUrl); } - forward(): void { throw new Error('Not implemented'); } + forward(): void { + throw new Error('Not implemented'); + } - back(): void { throw new Error('Not implemented'); } + back(): void { + throw new Error('Not implemented'); + } // History API isn't available on server, therefore return undefined - getState(): unknown { return undefined; } + getState(): unknown { + return undefined; + } } export function scheduleMicroTask(fn: Function) { diff --git a/packages/platform-server/src/platform-server.ts b/packages/platform-server/src/platform-server.ts index 762cefdd88f27..b898bbda544c3 100644 --- a/packages/platform-server/src/platform-server.ts +++ b/packages/platform-server/src/platform-server.ts @@ -7,7 +7,7 @@ */ export {PlatformState} from './platform_state'; -export {ServerModule, platformDynamicServer, platformServer} from './server'; +export {platformDynamicServer, platformServer, ServerModule} from './server'; export {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, PlatformConfig} from './tokens'; export {ServerTransferStateModule} from './transfer_state'; export {renderModule, renderModuleFactory} from './utils'; diff --git a/packages/platform-server/src/platform_state.ts b/packages/platform-server/src/platform_state.ts index 73ecd298ecade..833fb7c1f9981 100644 --- a/packages/platform-server/src/platform_state.ts +++ b/packages/platform-server/src/platform_state.ts @@ -23,10 +23,14 @@ export class PlatformState { /** * Renders the current state of the platform to string. */ - renderToString(): string { return serializeDocument(this._doc); } + renderToString(): string { + return serializeDocument(this._doc); + } /** * Returns the current DOM state. */ - getDocument(): any { return this._doc; } + getDocument(): any { + return this._doc; + } } diff --git a/packages/platform-server/src/server.ts b/packages/platform-server/src/server.ts index 3b1d3d7e933e1..be960ab22cbdb 100644 --- a/packages/platform-server/src/server.ts +++ b/packages/platform-server/src/server.ts @@ -7,9 +7,9 @@ */ import {ɵAnimationEngine} from '@angular/animations/browser'; -import {DOCUMENT, PlatformLocation, ViewportScroller, ɵNullViewportScroller as NullViewportScroller, ɵPLATFORM_SERVER_ID as PLATFORM_SERVER_ID, ɵgetDOM as getDOM} from '@angular/common'; +import {DOCUMENT, PlatformLocation, ViewportScroller, ɵgetDOM as getDOM, ɵNullViewportScroller as NullViewportScroller, ɵPLATFORM_SERVER_ID as PLATFORM_SERVER_ID} from '@angular/common'; import {HttpClientModule} from '@angular/common/http'; -import {Injector, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, PlatformRef, Provider, RendererFactory2, StaticProvider, Testability, createPlatformFactory, platformCore, ɵALLOW_MULTIPLE_PLATFORMS as ALLOW_MULTIPLE_PLATFORMS, ɵsetDocument} from '@angular/core'; +import {createPlatformFactory, Injector, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, StaticProvider, Testability, ɵALLOW_MULTIPLE_PLATFORMS as ALLOW_MULTIPLE_PLATFORMS, ɵsetDocument} from '@angular/core'; import {BrowserModule, EVENT_MANAGER_PLUGINS, ɵSharedStylesHost as SharedStylesHost} from '@angular/platform-browser'; import {ɵplatformCoreDynamic as platformCoreDynamic} from '@angular/platform-browser-dynamic'; import {NoopAnimationsModule, ɵAnimationRendererFactory} from '@angular/platform-browser/animations'; @@ -41,7 +41,9 @@ export const INTERNAL_SERVER_PLATFORM_PROVIDERS: StaticProvider[] = [ ]; function initDominoAdapter(injector: Injector) { - return () => { DominoAdapter.makeCurrent(); }; + return () => { + DominoAdapter.makeCurrent(); + }; } export function instantiateServerRendererFactory( @@ -91,7 +93,7 @@ function _document(injector: Injector) { /** * @publicApi */ -export const platformServer: (extraProviders?: StaticProvider[] | undefined) => PlatformRef = +export const platformServer: (extraProviders?: StaticProvider[]|undefined) => PlatformRef = createPlatformFactory(platformCore, 'server', INTERNAL_SERVER_PLATFORM_PROVIDERS); /** diff --git a/packages/platform-server/src/server_events.ts b/packages/platform-server/src/server_events.ts index 82405f632ca48..ecae52dd8fffe 100644 --- a/packages/platform-server/src/server_events.ts +++ b/packages/platform-server/src/server_events.ts @@ -14,7 +14,9 @@ export class ServerEventManagerPlugin /* extends EventManagerPlugin which is pri constructor(@Inject(DOCUMENT) private doc: any) {} // Handle all events on the server. - supports(eventName: string) { return true; } + supports(eventName: string) { + return true; + } addEventListener(element: HTMLElement, eventName: string, handler: Function): Function { return getDOM().onAndCancel(element, eventName, handler); diff --git a/packages/platform-server/src/server_renderer.ts b/packages/platform-server/src/server_renderer.ts index 306632219ad0e..906052efc8a02 100644 --- a/packages/platform-server/src/server_renderer.ts +++ b/packages/platform-server/src/server_renderer.ts @@ -9,7 +9,7 @@ import {DOCUMENT, ɵgetDOM as getDOM} from '@angular/common'; import {DomElementSchemaRegistry} from '@angular/compiler'; import {Inject, Injectable, NgZone, Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2, ViewEncapsulation} from '@angular/core'; -import {EventManager, ɵNAMESPACE_URIS as NAMESPACE_URIS, ɵSharedStylesHost as SharedStylesHost, ɵflattenStyles as flattenStyles, ɵshimContentAttribute as shimContentAttribute, ɵshimHostAttribute as shimHostAttribute} from '@angular/platform-browser'; +import {EventManager, ɵflattenStyles as flattenStyles, ɵNAMESPACE_URIS as NAMESPACE_URIS, ɵSharedStylesHost as SharedStylesHost, ɵshimContentAttribute as shimContentAttribute, ɵshimHostAttribute as shimHostAttribute} from '@angular/platform-browser'; const EMPTY_ARRAY: any[] = []; @@ -90,7 +90,9 @@ class DefaultServerRenderer2 implements Renderer2 { return doc.createTextNode(value); } - appendChild(parent: any, newChild: any): void { parent.appendChild(newChild); } + appendChild(parent: any, newChild: any): void { + parent.appendChild(newChild); + } insertBefore(parent: any, newChild: any, refChild: any): void { if (parent) { @@ -120,9 +122,13 @@ class DefaultServerRenderer2 implements Renderer2 { return el; } - parentNode(node: any): any { return node.parentNode; } + parentNode(node: any): any { + return node.parentNode; + } - nextSibling(node: any): any { return node.nextSibling; } + nextSibling(node: any): any { + return node.nextSibling; + } setAttribute(el: any, name: string, value: string, namespace?: string): void { if (namespace) { @@ -144,9 +150,13 @@ class DefaultServerRenderer2 implements Renderer2 { } } - addClass(el: any, name: string): void { el.classList.add(name); } + addClass(el: any, name: string): void { + el.classList.add(name); + } - removeClass(el: any, name: string): void { el.classList.remove(name); } + removeClass(el: any, name: string): void { + el.classList.remove(name); + } setStyle(el: any, style: string, value: any, flags: RendererStyleFlags2): void { style = style.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); @@ -189,7 +199,9 @@ class DefaultServerRenderer2 implements Renderer2 { } } - setValue(node: any, value: string): void { node.textContent = value; } + setValue(node: any, value: string): void { + node.textContent = value; + } listen( target: 'document'|'window'|'body'|any, eventName: string, @@ -200,7 +212,7 @@ class DefaultServerRenderer2 implements Renderer2 { target, eventName, this.decoratePreventDefault(callback)); } return <() => void>this.eventManager.addEventListener( - target, eventName, this.decoratePreventDefault(callback)) as() => void; + target, eventName, this.decoratePreventDefault(callback)) as () => void; } private decoratePreventDefault(eventHandler: Function): Function { @@ -227,8 +239,8 @@ class DefaultServerRenderer2 implements Renderer2 { const AT_CHARCODE = '@'.charCodeAt(0); function checkNoSyntheticProp(name: string, nameKind: string) { if (name.charCodeAt(0) === AT_CHARCODE) { - throw new Error( - `Found the synthetic ${nameKind} ${name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`); + throw new Error(`Found the synthetic ${nameKind} ${ + name}. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.`); } } @@ -249,7 +261,9 @@ class EmulatedEncapsulationServerRenderer2 extends DefaultServerRenderer2 { this.hostAttr = shimHostAttribute(componentId); } - applyToHost(element: any) { super.setAttribute(element, this.hostAttr, ''); } + applyToHost(element: any) { + super.setAttribute(element, this.hostAttr, ''); + } createElement(parent: any, name: string): Element { const el = super.createElement(parent, name, this.document); diff --git a/packages/platform-server/src/styles_host.ts b/packages/platform-server/src/styles_host.ts index 243125d784e7a..ceab0cca86de7 100644 --- a/packages/platform-server/src/styles_host.ts +++ b/packages/platform-server/src/styles_host.ts @@ -31,5 +31,7 @@ export class ServerStylesHost extends SharedStylesHost { this.head.appendChild(el); } - onStylesAdded(additions: Set) { additions.forEach(style => this._addStyle(style)); } + onStylesAdded(additions: Set) { + additions.forEach(style => this._addStyle(style)); + } } diff --git a/packages/platform-server/src/utils.ts b/packages/platform-server/src/utils.ts index d83f7d619919b..19a7fcff08bf0 100644 --- a/packages/platform-server/src/utils.ts +++ b/packages/platform-server/src/utils.ts @@ -77,8 +77,9 @@ the server-rendered app can be properly bootstrapped into a client app.`); return Promise .all(asyncPromises.map(asyncPromise => { - return asyncPromise.catch( - e => { console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e); }); + return asyncPromise.catch(e => { + console.warn('Ignoring BEFORE_APP_SERIALIZED Exception: ', e); + }); })) .then(complete); }); diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts index 630d2b78c2a61..d073987afffa5 100644 --- a/packages/platform-server/test/integration_spec.ts +++ b/packages/platform-server/test/integration_spec.ts @@ -6,14 +6,14 @@ * found in the LICENSE file at https://angular.io/license */ -import {AnimationBuilder, animate, state, style, transition, trigger} from '@angular/animations'; -import {DOCUMENT, PlatformLocation, isPlatformServer, ɵgetDOM as getDOM} from '@angular/common'; +import {animate, AnimationBuilder, state, style, transition, trigger} from '@angular/animations'; +import {DOCUMENT, isPlatformServer, PlatformLocation, ɵgetDOM as getDOM} from '@angular/common'; import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; -import {ApplicationRef, CompilerFactory, Component, HostListener, Inject, Injectable, Input, NgModule, NgZone, PLATFORM_ID, PlatformRef, ViewEncapsulation, destroyPlatform, getPlatform} from '@angular/core'; +import {ApplicationRef, CompilerFactory, Component, destroyPlatform, getPlatform, HostListener, Inject, Injectable, Input, NgModule, NgZone, PLATFORM_ID, PlatformRef, ViewEncapsulation} from '@angular/core'; import {async, inject} from '@angular/core/testing'; -import {BrowserModule, Title, TransferState, makeStateKey} from '@angular/platform-browser'; -import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, PlatformState, ServerModule, ServerTransferStateModule, platformDynamicServer, renderModule, renderModuleFactory} from '@angular/platform-server'; +import {BrowserModule, makeStateKey, Title, TransferState} from '@angular/platform-browser'; +import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG, platformDynamicServer, PlatformState, renderModule, renderModuleFactory, ServerModule, ServerTransferStateModule} from '@angular/platform-server'; import {ivyEnabled, modifiedInIvy} from '@angular/private/testing'; import {Observable} from 'rxjs'; import {first} from 'rxjs/operators'; @@ -64,7 +64,11 @@ function getAsyncTitleRenderHook(doc: any) { function asyncRejectRenderHook() { return () => { - return new Promise((_resolve, reject) => { setTimeout(() => { reject('reject'); }); }); + return new Promise((_resolve, reject) => { + setTimeout(() => { + reject('reject'); + }); + }); }; } @@ -136,7 +140,9 @@ class ExampleModule2 { @Component({selector: 'app', template: ``}) class TitleApp { constructor(private title: Title) {} - ngOnInit() { this.title.setTitle('Test App Title'); } + ngOnInit() { + this.title.setTitle('Test App Title'); + } } @NgModule({declarations: [TitleApp], imports: [ServerModule], bootstrap: [TitleApp]}) @@ -149,7 +155,9 @@ class MyAsyncServerApp { h1 = ''; @HostListener('window:scroll') - track() { console.error('scroll'); } + track() { + console.error('scroll'); + } ngOnInit() { Promise.resolve(null).then(() => setTimeout(() => { @@ -192,7 +200,8 @@ class SVGServerModule { 'transform': 'translate3d(0, 0, 0)', // not natively supported by Domino })), transition('void => *', [animate('0ms')]), - ], )] + ], + )] }) class MyAnimationApp { state = 'active'; @@ -281,7 +290,7 @@ class NativeExampleModule { @Component({selector: 'my-child', template: 'Works!'}) class MyChildComponent { // TODO(issue/24571): remove '!'. - @Input() public attr !: boolean; + @Input() public attr!: boolean; } @Component({selector: 'app', template: ''}) @@ -311,8 +320,7 @@ class InnerTextModule { @Component({selector: 'app', template: ''}) class MyInputComponent { - @Input() - name = ''; + @Input() name = ''; } @NgModule({ @@ -343,7 +351,9 @@ const STRING_KEY = makeStateKey('testString'); @Component({selector: 'app', template: 'Works!'}) class TransferComponent { constructor(private transferStore: TransferState) {} - ngOnInit() { this.transferStore.set(TEST_KEY, 10); } + ngOnInit() { + this.transferStore.set(TEST_KEY, 10); + } } @Component({selector: 'esc-app', template: 'Works!'}) @@ -380,8 +390,7 @@ class EscapedTransferStoreModule { @Component({selector: 'app', template: ''}) class MyHiddenComponent { - @Input() - name = ''; + @Input() name = ''; } @NgModule({ @@ -393,470 +402,474 @@ class HiddenModule { } (function() { - if (getDOM().supportsDOMEvents()) return; // NODE only +if (getDOM().supportsDOMEvents()) return; // NODE only - describe('platform-server integration', () => { - beforeEach(() => { - if (getPlatform()) destroyPlatform(); - }); +describe('platform-server integration', () => { + beforeEach(() => { + if (getPlatform()) destroyPlatform(); + }); - it('should bootstrap', async(() => { + it('should bootstrap', async(() => { + const platform = + platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + + platform.bootstrapModule(ExampleModule).then((moduleRef) => { + expect(isPlatformServer(moduleRef.injector.get(PLATFORM_ID))).toBe(true); + const doc = moduleRef.injector.get(DOCUMENT); + + expect(doc.head).toBe(doc.querySelector('head')!); + expect(doc.body).toBe(doc.querySelector('body')!); + + expect(doc.documentElement.textContent).toEqual('Works!'); + + platform.destroy(); + }); + })); + + it('should allow multiple platform instances', async(() => { + const platform = + platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + + const platform2 = + platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + + + platform.bootstrapModule(ExampleModule).then((moduleRef) => { + const doc = moduleRef.injector.get(DOCUMENT); + expect(doc.documentElement.textContent).toEqual('Works!'); + platform.destroy(); + }); + + platform2.bootstrapModule(ExampleModule2).then((moduleRef) => { + const doc = moduleRef.injector.get(DOCUMENT); + expect(doc.documentElement.textContent).toEqual('Works too!'); + platform2.destroy(); + }); + })); + + it('adds title to the document using Title service', async(() => { + const platform = platformDynamicServer([{ + provide: INITIAL_CONFIG, + useValue: {document: ''} + }]); + platform.bootstrapModule(TitleAppModule).then(ref => { + const state = ref.injector.get(PlatformState); + const doc = ref.injector.get(DOCUMENT); + const title = doc.querySelector('title')!; + expect(title.textContent).toBe('Test App Title'); + expect(state.renderToString()).toContain('Test App Title'); + }); + })); + + it('should get base href from document', async(() => { + const platform = platformDynamicServer([{ + provide: INITIAL_CONFIG, + useValue: {document: ''} + }]); + platform.bootstrapModule(ExampleModule).then((moduleRef) => { + const location = moduleRef.injector.get(PlatformLocation); + expect(location.getBaseHrefFromDOM()).toEqual('/'); + platform.destroy(); + }); + })); + + it('adds styles with ng-transition attribute', async(() => { + const platform = platformDynamicServer([{ + provide: INITIAL_CONFIG, + useValue: {document: ''} + }]); + platform.bootstrapModule(ExampleStylesModule).then(ref => { + const doc = ref.injector.get(DOCUMENT); + const head = doc.getElementsByTagName('head')[0]; + const styles: any[] = head.children as any; + expect(styles.length).toBe(1); + expect(styles[0].textContent).toContain('color: red'); + expect(styles[0].getAttribute('ng-transition')).toBe('example-styles'); + }); + })); + + it('copies known properties to attributes', async(() => { + const platform = + platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + platform.bootstrapModule(ImageExampleModule).then(ref => { + const appRef: ApplicationRef = ref.injector.get(ApplicationRef); + const app = appRef.components[0].location.nativeElement; + const img = app.getElementsByTagName('img')[0] as any; + expect(img.attributes['src'].value).toEqual('link'); + }); + })); + + describe('PlatformLocation', () => { + it('is injectable', async(() => { const platform = platformDynamicServer( [{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + platform.bootstrapModule(ExampleModule).then(appRef => { + const location: PlatformLocation = appRef.injector.get(PlatformLocation); + expect(location.pathname).toBe('/'); + platform.destroy(); + }); + })); + it('is configurable via INITIAL_CONFIG', () => { + platformDynamicServer([{ + provide: INITIAL_CONFIG, + useValue: {document: '', url: 'http://test.com/deep/path?query#hash'} + }]) + .bootstrapModule(ExampleModule) + .then(appRef => { + const location: PlatformLocation = appRef.injector.get(PlatformLocation); + expect(location.pathname).toBe('/deep/path'); + expect(location.search).toBe('?query'); + expect(location.hash).toBe('#hash'); + }); + }); + it('parses component pieces of a URL', () => { + platformDynamicServer([{ + provide: INITIAL_CONFIG, + useValue: {document: '', url: 'http://test.com:80/deep/path?query#hash'} + }]) + .bootstrapModule(ExampleModule) + .then(appRef => { + const location: PlatformLocation = appRef.injector.get(PlatformLocation); + expect(location.hostname).toBe('test.com'); + expect(location.protocol).toBe('http:'); + expect(location.port).toBe('80'); + expect(location.pathname).toBe('/deep/path'); + expect(location.search).toBe('?query'); + expect(location.hash).toBe('#hash'); + }); + }); + it('handles empty search and hash portions of the url', () => { + platformDynamicServer([{ + provide: INITIAL_CONFIG, + useValue: {document: '', url: 'http://test.com/deep/path'} + }]) + .bootstrapModule(ExampleModule) + .then(appRef => { + const location: PlatformLocation = appRef.injector.get(PlatformLocation); + expect(location.pathname).toBe('/deep/path'); + expect(location.search).toBe(''); + expect(location.hash).toBe(''); + }); + }); + it('pushState causes the URL to update', async(() => { + const platform = platformDynamicServer( + [{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + platform.bootstrapModule(ExampleModule).then(appRef => { + const location: PlatformLocation = appRef.injector.get(PlatformLocation); + location.pushState(null, 'Test', '/foo#bar'); + expect(location.pathname).toBe('/foo'); + expect(location.hash).toBe('#bar'); + platform.destroy(); + }); + })); + it('allows subscription to the hash state', done => { + const platform = + platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + platform.bootstrapModule(ExampleModule).then(appRef => { + const location: PlatformLocation = appRef.injector.get(PlatformLocation); + expect(location.pathname).toBe('/'); + location.onHashChange((e: any) => { + expect(e.type).toBe('hashchange'); + expect(e.oldUrl).toBe('/'); + expect(e.newUrl).toBe('/foo#bar'); + platform.destroy(); + done(); + }); + location.pushState(null, 'Test', '/foo#bar'); + }); + }); + }); - platform.bootstrapModule(ExampleModule).then((moduleRef) => { - expect(isPlatformServer(moduleRef.injector.get(PLATFORM_ID))).toBe(true); - const doc = moduleRef.injector.get(DOCUMENT); + describe('render', () => { + let doc: string; + let called: boolean; + let expectedOutput = + 'Works!

fine

'; - expect(doc.head).toBe(doc.querySelector('head') !); - expect(doc.body).toBe(doc.querySelector('body') !); + beforeEach(() => { + // PlatformConfig takes in a parsed document so that it can be cached across requests. + doc = ''; + called = false; + // We use `window` and `document` directly in some parts of render3 for ivy + // Only set it to undefined for legacy + if (!ivyEnabled) { + (global as any)['window'] = undefined; + (global as any)['document'] = undefined; + } + }); + afterEach(() => { + expect(called).toBe(true); + }); - expect(doc.documentElement.textContent).toEqual('Works!'); + it('using long form should work', async(() => { + const platform = + platformDynamicServer([{provide: INITIAL_CONFIG, useValue: {document: doc}}]); + + platform.bootstrapModule(AsyncServerModule) + .then((moduleRef) => { + const applicationRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); + return applicationRef.isStable.pipe(first((isStable: boolean) => isStable)) + .toPromise(); + }) + .then((b) => { + expect(platform.injector.get(PlatformState).renderToString()).toBe(expectedOutput); + platform.destroy(); + called = true; + }); + })); - platform.destroy(); + it('using renderModule should work', async(() => { + renderModule(AsyncServerModule, {document: doc}).then(output => { + expect(output).toBe(expectedOutput); + called = true; }); })); - it('should allow multiple platform instances', async(() => { - const platform = platformDynamicServer( - [{provide: INITIAL_CONFIG, useValue: {document: ''}}]); - - const platform2 = platformDynamicServer( - [{provide: INITIAL_CONFIG, useValue: {document: ''}}]); + modifiedInIvy('Will not support binding to innerText in Ivy since domino does not') + .it('should support binding to innerText', async(() => { + renderModule(InnerTextModule, {document: doc}).then(output => { + expect(output).toBe( + '
Some text
'); + called = true; + }); + })); + + it('using renderModuleFactory should work', + async(inject([PlatformRef], (defaultPlatform: PlatformRef) => { + const compilerFactory: CompilerFactory = + defaultPlatform.injector.get(CompilerFactory, null)!; + const moduleFactory = + compilerFactory.createCompiler().compileModuleSync(AsyncServerModule); + renderModuleFactory(moduleFactory, {document: doc}).then(output => { + expect(output).toBe(expectedOutput); + called = true; + }); + }))); + + it('works with SVG elements', async(() => { + renderModule(SVGServerModule, {document: doc}).then(output => { + expect(output).toBe( + '' + + ''); + called = true; + }); + })); + it('works with animation', async(() => { + renderModule(AnimationServerModule, {document: doc}).then(output => { + expect(output).toContain('Works!'); + expect(output).toContain('ng-trigger-myAnimation'); + expect(output).toContain('opacity:1;'); + expect(output).toContain('transform:translate3d(0 , 0 , 0);'); + expect(output).toContain('font-weight:bold;'); + called = true; + }); + })); - platform.bootstrapModule(ExampleModule).then((moduleRef) => { - const doc = moduleRef.injector.get(DOCUMENT); - expect(doc.documentElement.textContent).toEqual('Works!'); - platform.destroy(); + it('should handle ViewEncapsulation.Native', async(() => { + renderModule(NativeExampleModule, {document: doc}).then(output => { + expect(output).not.toBe(''); + expect(output).toContain('color: red'); + called = true; }); + })); + - platform2.bootstrapModule(ExampleModule2).then((moduleRef) => { - const doc = moduleRef.injector.get(DOCUMENT); - expect(doc.documentElement.textContent).toEqual('Works too!'); - platform2.destroy(); + it('sets a prefix for the _nghost and _ngcontent attributes', async(() => { + renderModule(ExampleStylesModule, {document: doc}).then(output => { + expect(output).toMatch( + / +To explore a sample app featuring the router's primary features, see the . +## Prerequisites -## Overview +Before creating a route, you should be familiar with the following: -The browser is a familiar model of application navigation: +* [Basics of components](guide/architecture-components) +* [Basics of templates](guide/glossary#template) +* An Angular app—you can generate a basic Angular app using the [Angular CLI](cli). -* Enter a URL in the address bar and the browser navigates to a corresponding page. -* Click links on the page and the browser navigates to a new page. -* Click the browser's back and forward buttons and the browser navigates - backward and forward through the history of pages you've seen. +For an introduction to Angular with a ready-made app, see [Getting Started](start). +For a more in-depth experience of building an Angular app, see the [Tour of Heroes](tutorial) tutorial. Both guide you through using component classes and templates. -The Angular `Router` ("the router") borrows from this model. -It can interpret a browser URL as an instruction to navigate to a client-generated view. -It can pass optional parameters along to the supporting view component that help it decide what specific content to present. -You can bind the router to links on a page and it will navigate to -the appropriate application view when the user clicks a link. -You can navigate imperatively when the user clicks a button, selects from a drop box, -or in response to some other stimulus from any source. And the router logs activity -in the browser's history journal so the back and forward buttons work as well. +
{@a basics} +## Generate an app with routing enabled -## The Basics +The following command uses the Angular CLI to generate a basic Angular app with an app routing module, called `AppRoutingModule`, which is an NgModule where you can configure your routes. +The app name in the following example is `routing-app`. -This guide proceeds in phases, marked by milestones, starting from a simple two-pager -and building toward a modular, multi-view design with child routes. + + ng new routing-app --routing + + +When generating a new app, the CLI prompts you to select CSS or a CSS preprocessor. +For this example, accept the default of `CSS`. + +### Adding components for routing + +To use the Angular router, an app needs to have at least two components so that it can navigate from one to the other. To create a component using the CLI, enter the following at the command line where `first` is the name of your component: + + + ng generate component first + -An introduction to a few core router concepts will help orient you to the details that follow. +Repeat this step for a second component but give it a different name. +Here, the new name is `second`. + + ng generate component second + + +The CLI automatically appends `Component`, so if you were to write `first-component`, your component would be `FirstComponentComponent`. {@a basics-base-href} +
-### *<base href>* + #### `` -Most routing applications should add a `` element to the `index.html` as the first child in the `` tag -to tell the router how to compose navigation URLs. + This guide works with a CLI-generated Angular app. + If you are working manually, make sure that you have `` in the `` of your index.html file. + This assumes that the `app` folder is the application root, and uses `"/"`. -If the `app` folder is the application root, as it is for the sample application, -set the `href` value *exactly* as shown here. + +
- +### Importing your new components +To use your new components, import them into `AppRoutingModule` at the top of the file, as follows: -{@a basics-router-imports} + +import { FirstComponent } from './first/first.component'; +import { SecondComponent } from './second/second.component'; -### Router imports + -The Angular Router is an optional service that presents a particular component view for a given URL. -It is not part of the Angular core. It is in its own library package, `@angular/router`. -Import what you need from it as you would from any other Angular package. +{@a basic-route} +## Defining a basic route - +There are three fundamental building blocks to creating a route. +Import the `AppRoutingModule` into `AppModule` and add it to the `imports` array. +The Angular CLI performs this step for you. +However, if you are creating an app manually or working with an existing, non-CLI app, verify that the imports and configuration are correct. +The following is the default `AppModule` using the CLI with the `--routing` flag. -
+ + + 1. Import `RouterModule` and `Routes` into your routing module. -You'll learn about more options in the [details below](#browser-url-styles). + The Angular CLI performs this step automatically. + The CLI also sets up a `Routes` array for your routes and configures the `imports` and `exports` arrays for `@NgModule()`. + -
+ +1. Define your routes in your `Routes` array. + Each route in this array is a JavaScript object that contains two properties. + The first property, `path`, defines the URL path for the route. + The second property, `component`, defines the component Angular should use for the corresponding path. -{@a basics-config} + + -### Configuration + 1. Add your routes to your application. -A routed Angular application has one singleton instance of the *`Router`* service. -When the browser's URL changes, that router looks for a corresponding `Route` -from which it can determine the component to display. + Now that you have defined your routes, you can add them to your application. + First, add links to the two components. + Assign the anchor tag that you want to add the route to the `routerLink` attribute. + Set the value of the attribute to the component to show when a user clicks on each link. + Next, update your component template to include ``. + This element informs Angular to update the application view with the component for the selected route. -A router has no routes until you configure it. -The following example creates five route definitions, configures the router via the `RouterModule.forRoot()` method, -and adds the result to the `AppModule`'s `imports` array. + +{@a route-order} - +### Route order +The order of routes is important because the `Router` uses a first-match wins strategy when matching routes, so more specific routes should be placed above less specific routes. +List routes with a static path first, followed by an empty path route, which matches the default route. +The [wildcard route](guide/router#setting-up-wildcard-routes) comes last because it matches every URL and the `Router` selects it only if no other routes match first. +{@a activated-route} -{@a example-config} +## Getting route information +Often, as a user navigates your application, you want to pass information from one component to another. +For example, consider an application that displays a shopping list of grocery items. +Each item in the list has a unique `id`. +To edit an item, users click an Edit button, which opens an `EditGroceryItem` component. +You want that component to retrieve the `id` for the grocery item so it can display the right information to the user. -The `appRoutes` array of *routes* describes how to navigate. -Pass it to the `RouterModule.forRoot()` method in the module `imports` to configure the router. +You can use a route to pass this type of information to your application components. +To do so, you use the [ActivatedRoute](api/router/ActivatedRoute) interface. -Each `Route` maps a URL `path` to a component. -There are _no leading slashes_ in the _path_. -The router parses and builds the final URL for you, -allowing you to use both relative and absolute paths when navigating between application views. +To get information from a route: -The `:id` in the second route is a token for a route parameter. In a URL such as `/hero/42`, "42" -is the value of the `id` parameter. The corresponding `HeroDetailComponent` -will use that value to find and present the hero whose `id` is 42. -You'll learn more about route parameters later in this guide. + 1. Import `ActivatedRoute` and `ParamMap` to your component. -The `data` property in the third route is a place to store arbitrary data associated with -this specific route. The data property is accessible within each activated route. Use it to store -items such as page titles, breadcrumb text, and other read-only, _static_ data. -You'll use the [resolve guard](#resolve-guard) to retrieve _dynamic_ data later in the guide. + + -The **empty path** in the fourth route represents the default path for the application, -the place to go when the path in the URL is empty, as it typically is at the start. -This default route redirects to the route for the `/heroes` URL and, therefore, will display the `HeroesListComponent`. + These `import` statements add several important elements that your component needs. + To learn more about each, see the following API pages: -The `**` path in the last route is a **wildcard**. The router will select this route -if the requested URL doesn't match any paths for routes defined earlier in the configuration. -This is useful for displaying a "404 - Not Found" page or redirecting to another route. + * [`Router`](api/router) + * [`ActivatedRoute`](api/router/ActivatedRoute) + * [`ParamMap`](api/router/ParamMap) -**The order of the routes in the configuration matters** and this is by design. The router uses a **first-match wins** -strategy when matching routes, so more specific routes should be placed above less specific routes. -In the configuration above, routes with a static path are listed first, followed by an empty path route, -that matches the default route. -The wildcard route comes last because it matches _every URL_ and should be selected _only_ if no other routes are matched first. + 1. Inject an instance of `ActivatedRoute` by adding it to your application's constructor: -If you need to see what events are happening during the navigation lifecycle, there is the **enableTracing** option as part of the router's default configuration. This outputs each router event that took place during each navigation lifecycle to the browser console. This should only be used for _debugging_ purposes. You set the `enableTracing: true` option in the object passed as the second argument to the `RouterModule.forRoot()` method. + + -{@a basics-router-outlet} + 1. Update the `ngOnInit()` method to access the `ActivatedRoute` and track the `id` parameter: + + ngOnInit() { + this.activatedRoute.queryParams.subscribe(params => { + this.name = params['name']; + }); + } + -### Router outlet + Note: The preceding example uses a variable, `name`, and assigns it the value based on the `name` parameter. -The `RouterOutlet` is a directive from the router library that is used like a component. -It acts as a placeholder that marks the spot in the template where the router should -display the components for that outlet. +{@a wildcard-route-how-to} +## Setting up wildcard routes - - <router-outlet></router-outlet> - <!-- Routed components go here --> +A well-functioning application should gracefully handle when users attempt to navigate to a part of your application that does not exist. +To add this functionality to your application, you set up a wildcard route. +The Angular router selects this route any time the requested URL doesn't match any router paths. - +To set up a wildcard route, add the following code to your `routes` definition. -Given the configuration above, when the browser URL for this application becomes `/heroes`, -the router matches that URL to the route path `/heroes` and displays the `HeroListComponent` -as a sibling element to the `RouterOutlet` that you've placed in the host component's template. + -{@a basics-router-links} -{@a router-link} +{ path: '**', component: } + -### Router links -Now you have routes configured and a place to render them, but -how do you navigate? The URL could arrive directly from the browser address bar. -But most of the time you navigate as a result of some user action such as the click of -an anchor tag. +The two asterisks, `**`, indicate to Angular that this `routes` definition is a wildcard route. +For the component property, you can define any component in your application. +Common choices include an application-specific `PageNotFoundComponent`, which you can define to [display a 404 page](guide/router#404-page-how-to) to your users; or a redirect to your application's main component. +A wildcard route is the last route because it matches any URL. +For more detail on why order matters for routes, see [Route order](guide/router#route-order). -Consider the following template: +{@a 404-page-how-to} - +## Displaying a 404 page -The `RouterLink` directives on the anchor tags give the router control over those elements. -The navigation paths are fixed, so you can assign a string to the `routerLink` (a "one-time" binding). +To display a 404 page, set up a [wildcard route](guide/router#wildcard-route-how-to) with the `component` property set to the component you'd like to use for your 404 page as follows: -Had the navigation path been more dynamic, you could have bound to a template expression that -returned an array of route link parameters (the _link parameters array_). -The router resolves that array into a complete URL. + + -{@a router-link-active} +The last route with the `path` of `**` is a wildcard route. +The router selects this route if the requested URL doesn't match any of the paths earlier in the list and sends the user to the `PageNotFoundComponent`. +## Setting up redirects -### Active router links +To set up a redirect, configure a route with the `path` you want to redirect from, the `component` you want to redirect to, and a `pathMatch` value that tells the router how to match the URL. -The `RouterLinkActive` directive toggles css classes for active `RouterLink` bindings based on the current `RouterState`. + -On each anchor tag, you see a [property binding](guide/template-syntax#property-binding) to the `RouterLinkActive` directive that look like `routerLinkActive="..."`. + -The template expression to the right of the equals (=) contains a space-delimited string of CSS classes -that the Router will add when this link is active (and remove when the link is inactive). You set the `RouterLinkActive` -directive to a string of classes such as `[routerLinkActive]="'active fluffy'"` or bind it to a component -property that returns such a string. +In this example, the third route is a redirect so that the router defaults to the `first-component` route. +Notice that this redirect precedes the wildcard route. +Here, `path: ''` means to use the initial relative URL (`''`). -Active route links cascade down through each level of the route tree, so parent and child router links can be active at the same time. To override this behavior, you can bind to the `[routerLinkActiveOptions]` input binding with the `{ exact: true }` expression. By using `{ exact: true }`, a given `RouterLink` will only be active if its URL is an exact match to the current URL. +For more details on `pathMatch` see [Spotlight on `pathMatch`](guide/router#pathmatch). +{@a nesting-routes} -{@a basics-router-state} +## Nesting routes +As your application grows more complex, you may want to create routes that are relative to a component other than your root component. +These types of nested routes are called child routes. +This means you're adding a second `` to your app, because it is in addition to the `` in `AppComponent`. -### Router state +In this example, there are two additional child components, `child-a`, and `child-b`. +Here, `FirstComponent` has its own `