From 79e4d283e6f646b8b0b4740967679f7adc312081 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 21 Aug 2020 04:14:19 +0200 Subject: [PATCH] perf: allow assertions to be removed in production mode (#20146) Wraps all assertions in `ngDevMode` checks so that they can be stripped away in production mode. Furthermore, changes all the places where we were using the old `isDevMode` check. --- src/BUILD.bazel | 6 +++ src/cdk-experimental/combobox/BUILD.bazel | 1 + src/cdk-experimental/combobox/combobox.ts | 5 +- src/cdk-experimental/dialog/BUILD.bazel | 1 + .../dialog/dialog-container.ts | 6 +-- src/cdk-experimental/dialog/dialog.ts | 4 +- src/cdk-experimental/menu/BUILD.bazel | 1 + src/cdk-experimental/menu/context-menu.ts | 5 +- .../menu/menu-item-trigger.ts | 4 +- src/cdk-experimental/scrolling/BUILD.bazel | 1 + .../scrolling/auto-size-virtual-scroll.ts | 14 ++++-- src/cdk-experimental/selection/BUILD.bazel | 1 + src/cdk-experimental/selection/select-all.ts | 6 +-- .../selection/selection-column.ts | 9 ++-- .../selection/selection-set.ts | 8 ++-- .../selection/selection-toggle.ts | 3 +- src/cdk-experimental/selection/selection.ts | 9 ++-- src/cdk-experimental/tsconfig-tests.json | 3 +- src/cdk-experimental/tsconfig.json | 2 +- src/cdk/a11y/BUILD.bazel | 1 + src/cdk/a11y/focus-trap/focus-trap.ts | 4 +- src/cdk/a11y/key-manager/list-key-manager.ts | 3 +- src/cdk/collections/BUILD.bazel | 1 + src/cdk/collections/selection-model.ts | 2 +- src/cdk/drag-drop/BUILD.bazel | 1 + src/cdk/drag-drop/directives/drag.ts | 7 +-- src/cdk/drag-drop/directives/drop-list.ts | 3 +- src/cdk/overlay/BUILD.bazel | 1 + .../flexible-connected-position-strategy.ts | 27 ++++++----- .../overlay/scroll/close-scroll-strategy.ts | 2 +- .../scroll/reposition-scroll-strategy.ts | 2 +- src/cdk/portal/BUILD.bazel | 1 + src/cdk/portal/dom-portal-outlet.ts | 6 +-- src/cdk/portal/portal-directives.ts | 6 +-- src/cdk/portal/portal.ts | 46 +++++++++++-------- src/cdk/scrolling/BUILD.bazel | 1 + .../scrolling/fixed-size-virtual-scroll.ts | 2 +- src/cdk/scrolling/virtual-for-of.ts | 3 +- src/cdk/scrolling/virtual-scroll-viewport.ts | 4 +- src/cdk/stepper/BUILD.bazel | 1 + src/cdk/stepper/stepper.ts | 3 +- src/cdk/table/BUILD.bazel | 1 + src/cdk/table/table.ts | 32 +++++++------ src/cdk/table/text-column.ts | 5 +- src/cdk/tree/BUILD.bazel | 1 + src/cdk/tree/nested-node.ts | 2 +- src/cdk/tree/tree.ts | 16 ++++--- src/cdk/tsconfig-tests.json | 3 +- src/cdk/tsconfig.json | 2 +- src/dev-mode-types.d.ts | 2 + src/google-maps/BUILD.bazel | 1 + src/google-maps/google-map/google-map.ts | 4 +- src/google-maps/map-circle/map-circle.ts | 20 ++++---- .../map-ground-overlay/map-ground-overlay.ts | 22 +++++---- .../map-info-window/map-info-window.ts | 22 +++++---- .../map-kml-layer/map-kml-layer.ts | 20 ++++---- src/google-maps/map-marker/map-marker.ts | 20 ++++---- src/google-maps/map-polygon/map-polygon.ts | 20 ++++---- src/google-maps/map-polyline/map-polyline.ts | 20 ++++---- .../map-rectangle/map-rectangle.ts | 20 ++++---- src/google-maps/tsconfig-tests.json | 3 +- src/google-maps/tsconfig.json | 3 +- .../mdc-chips/BUILD.bazel | 1 + .../mdc-chips/chip-grid.ts | 2 +- .../mdc-form-field/BUILD.bazel | 1 + .../mdc-form-field/form-field.ts | 5 +- .../mdc-snack-bar/BUILD.bazel | 1 + .../mdc-snack-bar/snack-bar-container.ts | 2 +- .../mdc-snack-bar/tsconfig-build.json | 2 +- .../mdc-table/tsconfig-build.json | 2 +- .../mdc-tabs/BUILD.bazel | 1 + src/material-experimental/mdc-tabs/ink-bar.ts | 6 +-- .../selection/selection-column.ts | 5 +- src/material-experimental/tsconfig-tests.json | 3 +- src/material-experimental/tsconfig.json | 2 +- src/material-moment-adapter/BUILD.bazel | 1 + .../adapter/moment-date-adapter.ts | 16 ++++--- .../tsconfig-tests.json | 3 +- src/material-moment-adapter/tsconfig.json | 2 +- src/material/autocomplete/BUILD.bazel | 1 + .../autocomplete/autocomplete-trigger.ts | 2 +- src/material/badge/BUILD.bazel | 1 + src/material/badge/badge.ts | 3 +- src/material/bottom-sheet/BUILD.bazel | 1 + .../bottom-sheet/bottom-sheet-container.ts | 2 +- src/material/button-toggle/BUILD.bazel | 1 + src/material/button-toggle/button-toggle.ts | 2 +- src/material/core/BUILD.bazel | 1 + .../core/common-behaviors/common-module.ts | 4 ++ .../core/common-behaviors/initialized.ts | 2 +- .../core/datetime/native-date-adapter.ts | 18 ++++---- src/material/datepicker/BUILD.bazel | 1 + src/material/datepicker/calendar.ts | 12 +++-- src/material/datepicker/date-range-input.ts | 14 +++--- src/material/datepicker/datepicker-base.ts | 6 +-- .../datepicker/datepicker-input-base.ts | 13 ++++-- src/material/datepicker/month-view.ts | 13 ++++-- src/material/datepicker/multi-year-view.ts | 2 +- src/material/datepicker/year-view.ts | 13 ++++-- src/material/dialog/BUILD.bazel | 1 + src/material/dialog/dialog-container.ts | 6 +-- src/material/dialog/dialog.ts | 3 +- src/material/form-field/BUILD.bazel | 1 + src/material/form-field/form-field.ts | 7 +-- src/material/grid-list/BUILD.bazel | 1 + src/material/grid-list/grid-list.ts | 2 +- src/material/grid-list/tile-coordinator.ts | 2 +- src/material/grid-list/tile-styler.ts | 5 +- src/material/icon/BUILD.bazel | 1 + src/material/icon/icon-registry.ts | 24 +++++----- src/material/icon/icon.ts | 6 ++- src/material/input/BUILD.bazel | 1 + src/material/input/input.ts | 3 +- src/material/list/BUILD.bazel | 1 + src/material/list/selection-list.ts | 3 +- src/material/menu/BUILD.bazel | 1 + src/material/menu/menu-trigger.ts | 5 +- src/material/menu/menu.ts | 6 +-- src/material/select/BUILD.bazel | 1 + src/material/select/select.ts | 9 ++-- src/material/sidenav/BUILD.bazel | 1 + src/material/sidenav/drawer.ts | 4 +- src/material/snack-bar/BUILD.bazel | 1 + src/material/snack-bar/snack-bar-container.ts | 2 +- src/material/sort/BUILD.bazel | 1 + src/material/sort/sort-header.ts | 2 +- src/material/sort/sort.ts | 17 ++++--- src/material/toolbar/BUILD.bazel | 1 + src/material/toolbar/toolbar.ts | 31 ++++++------- src/material/tooltip/BUILD.bazel | 1 + src/material/tooltip/tooltip.ts | 12 ++--- src/material/tsconfig-tests.json | 3 +- src/material/tsconfig.json | 2 +- src/youtube-player/BUILD.bazel | 1 + src/youtube-player/tsconfig-tests.json | 3 +- src/youtube-player/tsconfig.json | 2 +- src/youtube-player/youtube-player.ts | 2 +- tslint.json | 3 +- 138 files changed, 453 insertions(+), 347 deletions(-) create mode 100644 src/dev-mode-types.d.ts diff --git a/src/BUILD.bazel b/src/BUILD.bazel index b7d222852a38..e0168d562b99 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -2,6 +2,7 @@ load("@npm_bazel_typescript//:index.bzl", "ts_config") load("//src/cdk:config.bzl", "CDK_ENTRYPOINTS") load("//src/material:config.bzl", "MATERIAL_ENTRYPOINTS", "MATERIAL_TESTING_ENTRYPOINTS") load("//tools/dgeni:index.bzl", "dgeni_api_docs") +load("//tools:defaults.bzl", "ts_library") package(default_visibility = ["//visibility:public"]) @@ -43,3 +44,8 @@ dgeni_api_docs( }, tags = ["docs-package"], ) + +ts_library( + name = "dev_mode_types", + srcs = ["dev-mode-types.d.ts"], +) diff --git a/src/cdk-experimental/combobox/BUILD.bazel b/src/cdk-experimental/combobox/BUILD.bazel index f6de49a05921..77a8e7192a2c 100644 --- a/src/cdk-experimental/combobox/BUILD.bazel +++ b/src/cdk-experimental/combobox/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ), module_name = "@angular/cdk-experimental/combobox", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/collections", diff --git a/src/cdk-experimental/combobox/combobox.ts b/src/cdk-experimental/combobox/combobox.ts index f63cacb017b8..c30a6faa1640 100644 --- a/src/cdk-experimental/combobox/combobox.ts +++ b/src/cdk-experimental/combobox/combobox.ts @@ -15,7 +15,7 @@ import { Directive, ElementRef, EventEmitter, - Input, isDevMode, + Input, OnDestroy, Optional, Output, ViewContainerRef @@ -273,7 +273,8 @@ export class CdkCombobox implements OnDestroy, AfterContentInit { private _coerceOpenActionProperty(input: string | OpenAction[]): OpenAction[] { let actions = typeof input === 'string' ? input.trim().split(/[ ,]+/) : input; - if (isDevMode() && actions.some(a => allowedOpenActions.indexOf(a) === -1)) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && + actions.some(a => allowedOpenActions.indexOf(a) === -1)) { throw Error(`${input} is not a support open action for CdkCombobox`); } return actions as OpenAction[]; diff --git a/src/cdk-experimental/dialog/BUILD.bazel b/src/cdk-experimental/dialog/BUILD.bazel index 87c7cb58f0d1..1cddc98b8320 100644 --- a/src/cdk-experimental/dialog/BUILD.bazel +++ b/src/cdk-experimental/dialog/BUILD.bazel @@ -11,6 +11,7 @@ ng_module( assets = [":dialog-container.css"] + glob(["**/*.html"]), module_name = "@angular/cdk-experimental/dialog", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/keycodes", diff --git a/src/cdk-experimental/dialog/dialog-container.ts b/src/cdk-experimental/dialog/dialog-container.ts index e94d47e7d874..a1182acfdf4e 100644 --- a/src/cdk-experimental/dialog/dialog-container.ts +++ b/src/cdk-experimental/dialog/dialog-container.ts @@ -171,7 +171,7 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy { * @param portal Portal to be attached as the dialog content. */ attachComponentPortal(portal: ComponentPortal): ComponentRef { - if (this._portalHost.hasAttached()) { + if (this._portalHost.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwDialogContentAlreadyAttachedError(); } @@ -183,7 +183,7 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy { * @param portal Portal to be attached as the dialog content. */ attachTemplatePortal(portal: TemplatePortal): EmbeddedViewRef { - if (this._portalHost.hasAttached()) { + if (this._portalHost.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwDialogContentAlreadyAttachedError(); } @@ -197,7 +197,7 @@ export class CdkDialogContainer extends BasePortalOutlet implements OnDestroy { * @breaking-change 10.0.0 */ attachDomPortal = (portal: DomPortal) => { - if (this._portalHost.hasAttached()) { + if (this._portalHost.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwDialogContentAlreadyAttachedError(); } diff --git a/src/cdk-experimental/dialog/dialog.ts b/src/cdk-experimental/dialog/dialog.ts index d60b6de3cc1f..63bd6bb52d09 100644 --- a/src/cdk-experimental/dialog/dialog.ts +++ b/src/cdk-experimental/dialog/dialog.ts @@ -106,7 +106,7 @@ export class Dialog implements OnDestroy { openFromComponent(component: ComponentType, config?: DialogConfig): DialogRef { config = this._applyConfigDefaults(config); - if (config.id && this.getById(config.id)) { + if (config.id && this.getById(config.id) && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Dialog with id "${config.id}" exists already. The dialog id must be unique.`); } @@ -125,7 +125,7 @@ export class Dialog implements OnDestroy { openFromTemplate(template: TemplateRef, config?: DialogConfig): DialogRef { config = this._applyConfigDefaults(config); - if (config.id && this.getById(config.id)) { + if (config.id && this.getById(config.id) && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Dialog with id "${config.id}" exists already. The dialog id must be unique.`); } diff --git a/src/cdk-experimental/menu/BUILD.bazel b/src/cdk-experimental/menu/BUILD.bazel index dd0df2dae0f4..25e7c96f21ed 100644 --- a/src/cdk-experimental/menu/BUILD.bazel +++ b/src/cdk-experimental/menu/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ), module_name = "@angular/cdk-experimental/menu", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/cdk-experimental/menu/context-menu.ts b/src/cdk-experimental/menu/context-menu.ts index 8fbc1ade6415..ed471285e78a 100644 --- a/src/cdk-experimental/menu/context-menu.ts +++ b/src/cdk-experimental/menu/context-menu.ts @@ -17,7 +17,6 @@ import { Inject, Injectable, InjectionToken, - isDevMode, } from '@angular/core'; import {DOCUMENT} from '@angular/common'; import {Directionality} from '@angular/cdk/bidi'; @@ -110,9 +109,7 @@ export class CdkContextMenuTrigger implements OnDestroy { return this._menuPanel; } set menuPanel(panel: CdkMenuPanel) { - // If the provided panel already has a stack, that means it already has a trigger configured - // TODO refactor once https://github.com/angular/components/pull/20146 lands - if (isDevMode() && panel._menuStack) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && panel._menuStack) { throwExistingMenuStackError(); } this._menuPanel = panel; diff --git a/src/cdk-experimental/menu/menu-item-trigger.ts b/src/cdk-experimental/menu/menu-item-trigger.ts index a2ede3f9d879..bef72fdfd57c 100644 --- a/src/cdk-experimental/menu/menu-item-trigger.ts +++ b/src/cdk-experimental/menu/menu-item-trigger.ts @@ -16,7 +16,6 @@ import { Inject, OnDestroy, Optional, - isDevMode, } from '@angular/core'; import {Directionality} from '@angular/cdk/bidi'; import {TemplatePortal} from '@angular/cdk/portal'; @@ -64,8 +63,7 @@ export class CdkMenuItemTrigger implements OnDestroy { // If the provided panel already has a stack, that means it already has a trigger configured. // Note however that there are some edge cases where two triggers **may** share the same menu, // e.g. two triggers in two separate menus. - // TODO refactor once https://github.com/angular/components/pull/20146 lands - if (isDevMode() && panel?._menuStack) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && panel?._menuStack) { throwExistingMenuStackError(); } diff --git a/src/cdk-experimental/scrolling/BUILD.bazel b/src/cdk-experimental/scrolling/BUILD.bazel index d36b23872f22..8503fc95967f 100644 --- a/src/cdk-experimental/scrolling/BUILD.bazel +++ b/src/cdk-experimental/scrolling/BUILD.bazel @@ -11,6 +11,7 @@ ng_module( ), module_name = "@angular/cdk-experimental/scrolling", deps = [ + "//src:dev_mode_types", "//src/cdk/coercion", "//src/cdk/collections", "//src/cdk/scrolling", diff --git a/src/cdk-experimental/scrolling/auto-size-virtual-scroll.ts b/src/cdk-experimental/scrolling/auto-size-virtual-scroll.ts index ac45aac9b9ff..418ac03c87ca 100644 --- a/src/cdk-experimental/scrolling/auto-size-virtual-scroll.ts +++ b/src/cdk-experimental/scrolling/auto-size-virtual-scroll.ts @@ -72,8 +72,10 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy { /** @docs-private Implemented as part of VirtualScrollStrategy. */ scrolledIndexChange = new Observable(() => { // TODO(mmalerba): Implement. - throw Error('cdk-virtual-scroll: scrolledIndexChange is currently not supported for the' + - ' autosize scroll strategy'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + throw Error('cdk-virtual-scroll: scrolledIndexChange is currently not supported for the' + + ' autosize scroll strategy'); + } }); /** The attached viewport. */ @@ -164,9 +166,11 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy { /** Scroll to the offset for the given index. */ scrollToIndex(): void { - // TODO(mmalerba): Implement. - throw Error('cdk-virtual-scroll: scrollToIndex is currently not supported for the autosize' - + ' scroll strategy'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + // TODO(mmalerba): Implement. + throw Error('cdk-virtual-scroll: scrollToIndex is currently not supported for the autosize' + + ' scroll strategy'); + } } /** diff --git a/src/cdk-experimental/selection/BUILD.bazel b/src/cdk-experimental/selection/BUILD.bazel index 69d04d366acb..ddb47374cf19 100644 --- a/src/cdk-experimental/selection/BUILD.bazel +++ b/src/cdk-experimental/selection/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ), module_name = "@angular/cdk-experimental/selection", deps = [ + "//src:dev_mode_types", "//src/cdk/coercion", "//src/cdk/collections", "//src/cdk/table", diff --git a/src/cdk-experimental/selection/select-all.ts b/src/cdk-experimental/selection/select-all.ts index 000587cdc1fa..495d5cc462d0 100644 --- a/src/cdk-experimental/selection/select-all.ts +++ b/src/cdk-experimental/selection/select-all.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Directive, Inject, isDevMode, OnDestroy, OnInit, Optional, Self} from '@angular/core'; +import {Directive, Inject, OnDestroy, OnInit, Optional, Self} from '@angular/core'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; import {Observable, of as observableOf, Subject} from 'rxjs'; import {switchMap, takeUntil} from 'rxjs/operators'; @@ -90,11 +90,11 @@ export class CdkSelectAll implements OnDestroy, OnInit { } private _assertValidParentSelection() { - if (!this._selection && isDevMode()) { + if (!this._selection && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelectAll: missing CdkSelection in the parent'); } - if (!this._selection.multiple && isDevMode()) { + if (!this._selection.multiple && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelectAll: CdkSelection must have cdkSelectionMultiple set to true'); } } diff --git a/src/cdk-experimental/selection/selection-column.ts b/src/cdk-experimental/selection/selection-column.ts index 0e5a0bbd8426..18b2928cc3bc 100644 --- a/src/cdk-experimental/selection/selection-column.ts +++ b/src/cdk-experimental/selection/selection-column.ts @@ -10,7 +10,6 @@ import {CdkCellDef, CdkColumnDef, CdkHeaderCellDef, CdkTable} from '@angular/cdk import { Component, Input, - isDevMode, OnDestroy, OnInit, Optional, @@ -77,7 +76,7 @@ export class CdkSelectionColumn implements OnInit, OnDestroy { ) {} ngOnInit() { - if (!this.selection && isDevMode()) { + if (!this.selection && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelectionColumn: missing CdkSelection in the parent'); } @@ -87,10 +86,8 @@ export class CdkSelectionColumn implements OnInit, OnDestroy { this._columnDef.cell = this._cell; this._columnDef.headerCell = this._headerCell; this._table.addColumnDef(this._columnDef); - } else { - if (isDevMode()) { - throw Error('CdkSelectionColumn: missing parent table'); - } + } else if ((typeof ngDevMode === 'undefined' || ngDevMode)) { + throw Error('CdkSelectionColumn: missing parent table'); } } diff --git a/src/cdk-experimental/selection/selection-set.ts b/src/cdk-experimental/selection/selection-set.ts index 59ab89d5f1ad..9c6e84e6c56c 100644 --- a/src/cdk-experimental/selection/selection-set.ts +++ b/src/cdk-experimental/selection/selection-set.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {isDevMode, TrackByFunction} from '@angular/core'; +import {TrackByFunction} from '@angular/core'; import {Subject} from 'rxjs'; /** @@ -55,7 +55,7 @@ export class SelectionSet implements TrackBySelection { } select(...selects: SelectableWithIndex[]) { - if (!this._multiple && selects.length > 1 && isDevMode()) { + if (!this._multiple && selects.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('SelectionSet: not multiple selection'); } @@ -81,7 +81,7 @@ export class SelectionSet implements TrackBySelection { } deselect(...selects: SelectableWithIndex[]) { - if (!this._multiple && selects.length > 1 && isDevMode()) { + if (!this._multiple && selects.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('SelectionSet: not multiple selection'); } @@ -114,7 +114,7 @@ export class SelectionSet implements TrackBySelection { return select.value; } - if (select.index == null && isDevMode()) { + if (select.index == null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('SelectionSet: index required when trackByFn is used.'); } diff --git a/src/cdk-experimental/selection/selection-toggle.ts b/src/cdk-experimental/selection/selection-toggle.ts index 0d2220af0dea..1d399a266f93 100644 --- a/src/cdk-experimental/selection/selection-toggle.ts +++ b/src/cdk-experimental/selection/selection-toggle.ts @@ -11,7 +11,6 @@ import { Directive, Inject, Input, - isDevMode, OnDestroy, OnInit, Optional, @@ -77,7 +76,7 @@ export class CdkSelectionToggle implements OnDestroy, OnInit { } private _assertValidParentSelection() { - if (!this._selection && isDevMode()) { + if (!this._selection && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelectAll: missing CdkSelection in the parent'); } } diff --git a/src/cdk-experimental/selection/selection.ts b/src/cdk-experimental/selection/selection.ts index 77734ab2d684..442e38a0918f 100644 --- a/src/cdk-experimental/selection/selection.ts +++ b/src/cdk-experimental/selection/selection.ts @@ -13,7 +13,6 @@ import { Directive, EventEmitter, Input, - isDevMode, OnDestroy, OnInit, Output, @@ -104,7 +103,7 @@ export class CdkSelection implements OnInit, AfterContentChecked, CollectionV dataStream = observableOf(this._dataSource); } - if (dataStream == null && isDevMode()) { + if (dataStream == null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Unknown data source'); } @@ -139,7 +138,7 @@ export class CdkSelection implements OnInit, AfterContentChecked, CollectionV /** Toggles selection for a given value. `index` is required if `trackBy` is used. */ toggleSelection(value: T, index?: number) { - if (this.trackByFn && index == null && isDevMode()) { + if (this.trackByFn && index == null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelection: index required when trackBy is used'); } @@ -155,7 +154,7 @@ export class CdkSelection implements OnInit, AfterContentChecked, CollectionV * values are selected, de-select all values. */ toggleSelectAll() { - if (!this._multiple && isDevMode()) { + if (!this._multiple && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelection: multiple selection not enabled'); } @@ -168,7 +167,7 @@ export class CdkSelection implements OnInit, AfterContentChecked, CollectionV /** Checks whether a value is selected. `index` is required if `trackBy` is used. */ isSelected(value: T, index?: number) { - if (this.trackByFn && index == null && isDevMode()) { + if (this.trackByFn && index == null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkSelection: index required when trackBy is used'); } diff --git a/src/cdk-experimental/tsconfig-tests.json b/src/cdk-experimental/tsconfig-tests.json index 10ff391a2c0c..4d8c837ea616 100644 --- a/src/cdk-experimental/tsconfig-tests.json +++ b/src/cdk-experimental/tsconfig-tests.json @@ -21,7 +21,8 @@ }, "include": [ "**/index.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "**/*.e2e.spec.ts" diff --git a/src/cdk-experimental/tsconfig.json b/src/cdk-experimental/tsconfig.json index 58cf626924cf..9dd6206feb19 100644 --- a/src/cdk-experimental/tsconfig.json +++ b/src/cdk-experimental/tsconfig.json @@ -9,5 +9,5 @@ "@angular/cdk-experimental/*": ["../cdk-experimental/*"] } }, - "include": ["./**/*.ts"] + "include": ["./**/*.ts", "../dev-mode-types.d.ts"] } diff --git a/src/cdk/a11y/BUILD.bazel b/src/cdk/a11y/BUILD.bazel index 992b525d754d..77703e0290ea 100644 --- a/src/cdk/a11y/BUILD.bazel +++ b/src/cdk/a11y/BUILD.bazel @@ -18,6 +18,7 @@ ng_module( ), module_name = "@angular/cdk/a11y", deps = [ + "//src:dev_mode_types", "//src/cdk/coercion", "//src/cdk/keycodes", "//src/cdk/observers", diff --git a/src/cdk/a11y/focus-trap/focus-trap.ts b/src/cdk/a11y/focus-trap/focus-trap.ts index f8843976117b..03ce6b595f0f 100644 --- a/src/cdk/a11y/focus-trap/focus-trap.ts +++ b/src/cdk/a11y/focus-trap/focus-trap.ts @@ -18,7 +18,6 @@ import { NgZone, OnDestroy, DoCheck, - isDevMode, SimpleChanges, OnChanges, } from '@angular/core'; @@ -213,7 +212,8 @@ export class FocusTrap { // Warn the consumer if the element they've pointed to // isn't focusable, when not in production mode. - if (isDevMode() && !this._checker.isFocusable(redirectToElement)) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && + !this._checker.isFocusable(redirectToElement)) { console.warn(`Element matching '[cdkFocusInitial]' is not focusable.`, redirectToElement); } diff --git a/src/cdk/a11y/key-manager/list-key-manager.ts b/src/cdk/a11y/key-manager/list-key-manager.ts index c3e4a135e56a..214c9bc1bb64 100644 --- a/src/cdk/a11y/key-manager/list-key-manager.ts +++ b/src/cdk/a11y/key-manager/list-key-manager.ts @@ -140,7 +140,8 @@ export class ListKeyManager { * @param debounceInterval Time to wait after the last keystroke before setting the active item. */ withTypeAhead(debounceInterval: number = 200): this { - if (this._items.length && this._items.some(item => typeof item.getLabel !== 'function')) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && (this._items.length && + this._items.some(item => typeof item.getLabel !== 'function'))) { throw Error('ListKeyManager items in typeahead mode must implement the `getLabel` method.'); } diff --git a/src/cdk/collections/BUILD.bazel b/src/cdk/collections/BUILD.bazel index 32f53807f349..70333a673c10 100644 --- a/src/cdk/collections/BUILD.bazel +++ b/src/cdk/collections/BUILD.bazel @@ -16,6 +16,7 @@ ng_module( ), module_name = "@angular/cdk/collections", deps = [ + "//src:dev_mode_types", "@npm//@angular/core", "@npm//rxjs", ], diff --git a/src/cdk/collections/selection-model.ts b/src/cdk/collections/selection-model.ts index dfbe3b42dffb..17eca7ddf274 100644 --- a/src/cdk/collections/selection-model.ts +++ b/src/cdk/collections/selection-model.ts @@ -178,7 +178,7 @@ export class SelectionModel { * including multiple values while the selection model is not supporting multiple values. */ private _verifyValueAssignment(values: T[]) { - if (values.length > 1 && !this._multiple) { + if (values.length > 1 && !this._multiple && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMultipleValuesInSingleSelectionError(); } } diff --git a/src/cdk/drag-drop/BUILD.bazel b/src/cdk/drag-drop/BUILD.bazel index 6108fc990bea..8c5c989007bb 100644 --- a/src/cdk/drag-drop/BUILD.bazel +++ b/src/cdk/drag-drop/BUILD.bazel @@ -16,6 +16,7 @@ ng_module( ), module_name = "@angular/cdk/drag-drop", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/coercion", "//src/cdk/platform", diff --git a/src/cdk/drag-drop/directives/drag.ts b/src/cdk/drag-drop/directives/drag.ts index 473ddfc1f39f..80a18f9dfe62 100644 --- a/src/cdk/drag-drop/directives/drag.ts +++ b/src/cdk/drag-drop/directives/drag.ts @@ -27,7 +27,6 @@ import { OnChanges, SimpleChanges, ChangeDetectorRef, - isDevMode, Self, } from '@angular/core'; import { @@ -326,7 +325,8 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { const rootElement = this.rootElementSelector ? getClosestMatchingAncestor(element, this.rootElementSelector) : element; - if (rootElement && rootElement.nodeType !== this._document.ELEMENT_NODE) { + if (rootElement && rootElement.nodeType !== this._document.ELEMENT_NODE && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`cdkDrag must be attached to an element node. ` + `Currently attached to "${rootElement.nodeName}".`); } @@ -348,7 +348,8 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy { const element = coerceElement(boundary); - if (isDevMode() && !element.contains(this.element.nativeElement)) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && + !element.contains(this.element.nativeElement)) { throw Error('Draggable element is not inside of the node passed into cdkDragBoundary.'); } diff --git a/src/cdk/drag-drop/directives/drop-list.ts b/src/cdk/drag-drop/directives/drop-list.ts index 5a4e3f9eef06..91eb6764f76e 100644 --- a/src/cdk/drag-drop/directives/drop-list.ts +++ b/src/cdk/drag-drop/directives/drop-list.ts @@ -19,7 +19,6 @@ import { SkipSelf, Inject, InjectionToken, - isDevMode, } from '@angular/core'; import {Directionality} from '@angular/cdk/bidi'; import {ScrollDispatcher} from '@angular/cdk/scrolling'; @@ -256,7 +255,7 @@ export class CdkDropList implements OnDestroy { if (typeof drop === 'string') { const correspondingDropList = CdkDropList._dropLists.find(list => list.id === drop); - if (!correspondingDropList && isDevMode()) { + if (!correspondingDropList && (typeof ngDevMode === 'undefined' || ngDevMode)) { console.warn(`CdkDropList could not find connected drop list with id "${drop}"`); } diff --git a/src/cdk/overlay/BUILD.bazel b/src/cdk/overlay/BUILD.bazel index c89b006a54e8..3775ea2571b7 100644 --- a/src/cdk/overlay/BUILD.bazel +++ b/src/cdk/overlay/BUILD.bazel @@ -20,6 +20,7 @@ ng_module( ), module_name = "@angular/cdk/overlay", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/coercion", "//src/cdk/keycodes", diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.ts index be0c54c18fa1..c8b2f1aeb31e 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.ts @@ -144,7 +144,8 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { /** Attaches this position strategy to an overlay. */ attach(overlayRef: OverlayReference): void { - if (this._overlayRef && overlayRef !== this._overlayRef) { + if (this._overlayRef && overlayRef !== this._overlayRef && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('This position strategy is already attached to an overlay'); } @@ -1065,18 +1066,20 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { /** Validates that the current position match the expected values. */ private _validatePositions(): void { - if (!this._preferredPositions.length) { - throw Error('FlexibleConnectedPositionStrategy: At least one position is required.'); - } + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._preferredPositions.length) { + throw Error('FlexibleConnectedPositionStrategy: At least one position is required.'); + } - // TODO(crisbeto): remove these once Angular's template type - // checking is advanced enough to catch these cases. - this._preferredPositions.forEach(pair => { - validateHorizontalPosition('originX', pair.originX); - validateVerticalPosition('originY', pair.originY); - validateHorizontalPosition('overlayX', pair.overlayX); - validateVerticalPosition('overlayY', pair.overlayY); - }); + // TODO(crisbeto): remove these once Angular's template type + // checking is advanced enough to catch these cases. + this._preferredPositions.forEach(pair => { + validateHorizontalPosition('originX', pair.originX); + validateVerticalPosition('originY', pair.originY); + validateHorizontalPosition('overlayX', pair.overlayX); + validateVerticalPosition('overlayY', pair.overlayY); + }); + } } /** Adds a single CSS class or an array of classes on the overlay panel. */ diff --git a/src/cdk/overlay/scroll/close-scroll-strategy.ts b/src/cdk/overlay/scroll/close-scroll-strategy.ts index cd3bf822ae0f..940a71a31059 100644 --- a/src/cdk/overlay/scroll/close-scroll-strategy.ts +++ b/src/cdk/overlay/scroll/close-scroll-strategy.ts @@ -35,7 +35,7 @@ export class CloseScrollStrategy implements ScrollStrategy { /** Attaches this scroll strategy to an overlay. */ attach(overlayRef: OverlayReference) { - if (this._overlayRef) { + if (this._overlayRef && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatScrollStrategyAlreadyAttachedError(); } diff --git a/src/cdk/overlay/scroll/reposition-scroll-strategy.ts b/src/cdk/overlay/scroll/reposition-scroll-strategy.ts index 43e260724665..564856fca7f4 100644 --- a/src/cdk/overlay/scroll/reposition-scroll-strategy.ts +++ b/src/cdk/overlay/scroll/reposition-scroll-strategy.ts @@ -39,7 +39,7 @@ export class RepositionScrollStrategy implements ScrollStrategy { /** Attaches this scroll strategy to an overlay. */ attach(overlayRef: OverlayReference) { - if (this._overlayRef) { + if (this._overlayRef && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatScrollStrategyAlreadyAttachedError(); } diff --git a/src/cdk/portal/BUILD.bazel b/src/cdk/portal/BUILD.bazel index 832f71a2517e..1d43d0f047fd 100644 --- a/src/cdk/portal/BUILD.bazel +++ b/src/cdk/portal/BUILD.bazel @@ -16,6 +16,7 @@ ng_module( ), module_name = "@angular/cdk/portal", deps = [ + "//src:dev_mode_types", "@npm//@angular/core", ], ) diff --git a/src/cdk/portal/dom-portal-outlet.ts b/src/cdk/portal/dom-portal-outlet.ts index b30f3bd110a5..0ce61f30f316 100644 --- a/src/cdk/portal/dom-portal-outlet.ts +++ b/src/cdk/portal/dom-portal-outlet.ts @@ -115,12 +115,12 @@ export class DomPortalOutlet extends BasePortalOutlet { attachDomPortal = (portal: DomPortal) => { // @breaking-change 10.0.0 Remove check and error once the // `_document` constructor parameter is required. - if (!this._document) { + if (!this._document && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Cannot attach DOM portal without _document constructor parameter'); } const element = portal.element; - if (!element.parentNode) { + if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('DOM portal content must be attached to a parent node.'); } @@ -128,7 +128,7 @@ export class DomPortalOutlet extends BasePortalOutlet { // that we can restore it when the portal is detached. const anchorNode = this._document.createComment('dom-portal'); - element.parentNode.insertBefore(anchorNode, element); + element.parentNode!.insertBefore(anchorNode, element); this.outletElement.appendChild(element); super.setDisposeFn(() => { diff --git a/src/cdk/portal/portal-directives.ts b/src/cdk/portal/portal-directives.ts index 2a45fed54306..f9e873aa6916 100644 --- a/src/cdk/portal/portal-directives.ts +++ b/src/cdk/portal/portal-directives.ts @@ -198,12 +198,12 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr attachDomPortal = (portal: DomPortal) => { // @breaking-change 9.0.0 Remove check and error once the // `_document` constructor parameter is required. - if (!this._document) { + if (!this._document && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Cannot attach DOM portal without _document constructor parameter'); } const element = portal.element; - if (!element.parentNode) { + if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('DOM portal content must be attached to a parent node.'); } @@ -212,7 +212,7 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr const anchorNode = this._document.createComment('dom-portal'); portal.setAttachedHost(this); - element.parentNode.insertBefore(anchorNode, element); + element.parentNode!.insertBefore(anchorNode, element); this._getRootNode().appendChild(element); super.setDisposeFn(() => { diff --git a/src/cdk/portal/portal.ts b/src/cdk/portal/portal.ts index 0d02211a7fe6..502d337770d6 100644 --- a/src/cdk/portal/portal.ts +++ b/src/cdk/portal/portal.ts @@ -38,12 +38,14 @@ export abstract class Portal { /** Attach this portal to a host. */ attach(host: PortalOutlet): T { - if (host == null) { - throwNullPortalOutletError(); - } - - if (host.hasAttached()) { - throwPortalAlreadyAttachedError(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (host == null) { + throwNullPortalOutletError(); + } + + if (host.hasAttached()) { + throwPortalAlreadyAttachedError(); + } } this._attachedHost = host; @@ -54,11 +56,11 @@ export abstract class Portal { detach(): void { let host = this._attachedHost; - if (host == null) { - throwNoPortalAttachedError(); - } else { + if (host != null) { this._attachedHost = null; host.detach(); + } else if (typeof ngDevMode === 'undefined' || ngDevMode) { + throwNoPortalAttachedError(); } } @@ -215,16 +217,18 @@ export abstract class BasePortalOutlet implements PortalOutlet { /** Attaches a portal. */ attach(portal: Portal): any { - if (!portal) { - throwNullPortalError(); - } - - if (this.hasAttached()) { - throwPortalAlreadyAttachedError(); - } - - if (this._isDisposed) { - throwPortalOutletAlreadyDisposedError(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!portal) { + throwNullPortalError(); + } + + if (this.hasAttached()) { + throwPortalAlreadyAttachedError(); + } + + if (this._isDisposed) { + throwPortalOutletAlreadyDisposedError(); + } } if (portal instanceof ComponentPortal) { @@ -239,7 +243,9 @@ export abstract class BasePortalOutlet implements PortalOutlet { return this.attachDomPortal(portal); } - throwUnknownPortalTypeError(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + throwUnknownPortalTypeError(); + } } abstract attachComponentPortal(portal: ComponentPortal): ComponentRef; diff --git a/src/cdk/scrolling/BUILD.bazel b/src/cdk/scrolling/BUILD.bazel index 7de8a2fb5a9e..7817d332def2 100644 --- a/src/cdk/scrolling/BUILD.bazel +++ b/src/cdk/scrolling/BUILD.bazel @@ -18,6 +18,7 @@ ng_module( assets = [":virtual-scroll-viewport.css"] + glob(["**/*.html"]), module_name = "@angular/cdk/scrolling", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/coercion", "//src/cdk/collections", diff --git a/src/cdk/scrolling/fixed-size-virtual-scroll.ts b/src/cdk/scrolling/fixed-size-virtual-scroll.ts index c7a66eab765e..87237087d5d9 100644 --- a/src/cdk/scrolling/fixed-size-virtual-scroll.ts +++ b/src/cdk/scrolling/fixed-size-virtual-scroll.ts @@ -67,7 +67,7 @@ export class FixedSizeVirtualScrollStrategy implements VirtualScrollStrategy { * @param maxBufferPx The amount of buffer (in pixels) to render when rendering more. */ updateItemAndBufferSize(itemSize: number, minBufferPx: number, maxBufferPx: number) { - if (maxBufferPx < minBufferPx) { + if (maxBufferPx < minBufferPx && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CDK virtual scroll: maxBufferPx must be greater than or equal to minBufferPx'); } this._itemSize = itemSize; diff --git a/src/cdk/scrolling/virtual-for-of.ts b/src/cdk/scrolling/virtual-for-of.ts index 5631abe05a30..45618929058b 100644 --- a/src/cdk/scrolling/virtual-for-of.ts +++ b/src/cdk/scrolling/virtual-for-of.ts @@ -215,7 +215,8 @@ export class CdkVirtualForOf implements if (range.start >= range.end) { return 0; } - if (range.start < this._renderedRange.start || range.end > this._renderedRange.end) { + if ((range.start < this._renderedRange.start || range.end > this._renderedRange.end) && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Error: attempted to measure an item that isn't rendered.`); } diff --git a/src/cdk/scrolling/virtual-scroll-viewport.ts b/src/cdk/scrolling/virtual-scroll-viewport.ts index 4f0aaedbeb36..a405694f4c99 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.ts +++ b/src/cdk/scrolling/virtual-scroll-viewport.ts @@ -166,7 +166,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O viewportRuler?: ViewportRuler) { super(elementRef, scrollDispatcher, ngZone, dir); - if (!_scrollStrategy) { + if (!_scrollStrategy && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.'); } @@ -217,7 +217,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O /** Attaches a `CdkVirtualScrollRepeater` to this viewport. */ attach(forOf: CdkVirtualScrollRepeater) { - if (this._forOf) { + if (this._forOf && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('CdkVirtualScrollViewport is already attached.'); } diff --git a/src/cdk/stepper/BUILD.bazel b/src/cdk/stepper/BUILD.bazel index 869e45011518..46fed4383a41 100644 --- a/src/cdk/stepper/BUILD.bazel +++ b/src/cdk/stepper/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ), module_name = "@angular/cdk/stepper", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/cdk/stepper/stepper.ts b/src/cdk/stepper/stepper.ts index f21d1da7ce38..4449e1a049cf 100644 --- a/src/cdk/stepper/stepper.ts +++ b/src/cdk/stepper/stepper.ts @@ -293,7 +293,8 @@ export class CdkStepper implements AfterContentInit, AfterViewInit, OnDestroy { if (this.steps && this._steps) { // Ensure that the index can't be out of bounds. - if (newIndex < 0 || newIndex > this.steps.length - 1) { + if ((newIndex < 0 || newIndex > this.steps.length - 1) && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('cdkStepper: Cannot assign out-of-bounds value to `selectedIndex`.'); } diff --git a/src/cdk/table/BUILD.bazel b/src/cdk/table/BUILD.bazel index 5284718aee7e..4c2de6cc1263 100644 --- a/src/cdk/table/BUILD.bazel +++ b/src/cdk/table/BUILD.bazel @@ -16,6 +16,7 @@ ng_module( ), module_name = "@angular/cdk/table", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/coercion", "//src/cdk/collections", diff --git a/src/cdk/table/table.ts b/src/cdk/table/table.ts index 1670b9bcdff5..6d073711bc54 100644 --- a/src/cdk/table/table.ts +++ b/src/cdk/table/table.ts @@ -34,7 +34,6 @@ import { EmbeddedViewRef, Inject, Input, - isDevMode, IterableChangeRecord, IterableDiffer, IterableDiffers, @@ -342,8 +341,7 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes return this._trackByFn; } set trackBy(fn: TrackByFunction) { - if (isDevMode() && fn != null && typeof fn !== 'function' && console && - console.warn) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && fn != null && typeof fn !== 'function') { console.warn(`trackBy must be a function, but received ${JSON.stringify(fn)}.`); } this._trackByFn = fn; @@ -482,7 +480,8 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes this._cacheColumnDefs(); // Make sure that the user has at least added header, footer, or data row def. - if (!this._headerRowDefs.length && !this._footerRowDefs.length && !this._rowDefs.length) { + if (!this._headerRowDefs.length && !this._footerRowDefs.length && !this._rowDefs.length && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableMissingRowDefsError(); } @@ -788,7 +787,8 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes const columnDefs = mergeArrayAndSet( this._getOwnDefs(this._contentColumnDefs), this._customColumnDefs); columnDefs.forEach(columnDef => { - if (this._columnDefsByName.has(columnDef.name)) { + if (this._columnDefsByName.has(columnDef.name) && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableDuplicateColumnNameError(columnDef.name); } this._columnDefsByName.set(columnDef.name, columnDef); @@ -806,7 +806,8 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes // After all row definitions are determined, find the row definition to be considered default. const defaultRowDefs = this._rowDefs.filter(def => !def.when); - if (!this.multiTemplateDataRows && defaultRowDefs.length > 1) { + if (!this.multiTemplateDataRows && defaultRowDefs.length > 1 && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableMultipleDefaultRowDefsError(); } this._defaultRowDef = defaultRowDefs[0]; @@ -885,14 +886,15 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes dataStream = observableOf(this.dataSource); } - if (dataStream === undefined) { + if (dataStream === undefined && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableUnknownDataSourceError(); } - this._renderChangeSubscription = dataStream.pipe(takeUntil(this._onDestroy)).subscribe(data => { - this._data = data || []; - this.renderRows(); - }); + this._renderChangeSubscription = dataStream!.pipe(takeUntil(this._onDestroy)) + .subscribe(data => { + this._data = data || []; + this.renderRows(); + }); } /** @@ -927,7 +929,7 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes private _addStickyColumnStyles(rows: HTMLElement[], rowDef: BaseRowDef) { const columnDefs = Array.from(rowDef.columns || []).map(columnName => { const columnDef = this._columnDefsByName.get(columnName); - if (!columnDef) { + if (!columnDef && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableUnknownColumnError(columnName); } return columnDef!; @@ -971,7 +973,7 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes } } - if (!rowDefs.length) { + if (!rowDefs.length && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableMissingMatchingRowDefError(data); } @@ -1046,11 +1048,11 @@ export class CdkTable implements AfterContentChecked, CollectionViewer, OnDes return Array.from(rowDef.columns, columnId => { const column = this._columnDefsByName.get(columnId); - if (!column) { + if (!column && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableUnknownColumnError(columnId); } - return rowDef.extractCellTemplate(column); + return rowDef.extractCellTemplate(column!); }); } diff --git a/src/cdk/table/text-column.ts b/src/cdk/table/text-column.ts index 0386faab6a2d..e4fb82d7fcb9 100644 --- a/src/cdk/table/text-column.ts +++ b/src/cdk/table/text-column.ts @@ -16,7 +16,6 @@ import { Optional, ViewChild, ViewEncapsulation, - isDevMode, } from '@angular/core'; import {CdkCellDef, CdkColumnDef, CdkHeaderCellDef} from './cell'; import {CdkTable} from './table'; @@ -138,7 +137,7 @@ export class CdkTextColumn implements OnDestroy, OnInit { this.columnDef.cell = this.cell; this.columnDef.headerCell = this.headerCell; this._table.addColumnDef(this.columnDef); - } else { + } else if (typeof ngDevMode === 'undefined' || ngDevMode) { throw getTableTextColumnMissingParentTableError(); } } @@ -156,7 +155,7 @@ export class CdkTextColumn implements OnDestroy, OnInit { _createDefaultHeaderText() { const name = this.name; - if (isDevMode() && !name) { + if (!name && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTableTextColumnMissingNameError(); } diff --git a/src/cdk/tree/BUILD.bazel b/src/cdk/tree/BUILD.bazel index d5b0971fe5fe..372f9c1862b5 100644 --- a/src/cdk/tree/BUILD.bazel +++ b/src/cdk/tree/BUILD.bazel @@ -16,6 +16,7 @@ ng_module( ), module_name = "@angular/cdk/tree", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/cdk/tree/nested-node.ts b/src/cdk/tree/nested-node.ts index 75108b1c2539..7c7178543fac 100644 --- a/src/cdk/tree/nested-node.ts +++ b/src/cdk/tree/nested-node.ts @@ -64,7 +64,7 @@ export class CdkNestedTreeNode extends CdkTreeNode implements AfterContent ngAfterContentInit() { this._dataDiffer = this._differs.find([]).create(this._tree.trackBy); - if (!this._tree.treeControl.getChildren) { + if (!this._tree.treeControl.getChildren && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTreeControlFunctionsMissingError(); } const childrenNodes = this._tree.treeControl.getChildren(this.data); diff --git a/src/cdk/tree/tree.ts b/src/cdk/tree/tree.ts index 9f6778c1c103..501767604168 100644 --- a/src/cdk/tree/tree.ts +++ b/src/cdk/tree/tree.ts @@ -132,7 +132,7 @@ export class CdkTree implements AfterContentChecked, CollectionViewer, OnDest ngOnInit() { this._dataDiffer = this._differs.find([]).create(this.trackBy); - if (!this.treeControl) { + if (!this.treeControl && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTreeControlMissingError(); } } @@ -156,7 +156,7 @@ export class CdkTree implements AfterContentChecked, CollectionViewer, OnDest ngAfterContentChecked() { const defaultNodeDefs = this._nodeDefs.filter(def => !def.when); - if (defaultNodeDefs.length > 1) { + if (defaultNodeDefs.length > 1 && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTreeMultipleDefaultNodeDefsError(); } this._defaultNodeDef = defaultNodeDefs[0]; @@ -211,7 +211,7 @@ export class CdkTree implements AfterContentChecked, CollectionViewer, OnDest if (dataStream) { this._dataSubscription = dataStream.pipe(takeUntil(this._onDestroy)) .subscribe(data => this.renderNodeChanges(data)); - } else { + } else if (typeof ngDevMode === 'undefined' || ngDevMode) { throw getTreeNoValidDataSourceError(); } } @@ -251,9 +251,12 @@ export class CdkTree implements AfterContentChecked, CollectionViewer, OnDest const nodeDef = this._nodeDefs.find(def => def.when && def.when(i, data)) || this._defaultNodeDef; - if (!nodeDef) { throw getTreeMissingMatchingNodeDefError(); } - return nodeDef; + if (!nodeDef && (typeof ngDevMode === 'undefined' || ngDevMode)) { + throw getTreeMissingMatchingNodeDefError(); + } + + return nodeDef!; } /** @@ -366,7 +369,8 @@ export class CdkTreeNode implements FocusableOption, OnDestroy { // TODO: role should eventually just be set in the component host protected _setRoleFromData(): void { - if (!this._tree.treeControl.isExpandable && !this._tree.treeControl.getChildren) { + if (!this._tree.treeControl.isExpandable && !this._tree.treeControl.getChildren && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getTreeControlFunctionsMissingError(); } this.role = 'treeitem'; diff --git a/src/cdk/tsconfig-tests.json b/src/cdk/tsconfig-tests.json index 08a24cd8f4a2..b645504ff910 100644 --- a/src/cdk/tsconfig-tests.json +++ b/src/cdk/tsconfig-tests.json @@ -21,7 +21,8 @@ "include": [ "**/index.ts", "**/*.spec.ts", - "**/*.d.ts" + "**/*.d.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "testing/protractor/**.ts", diff --git a/src/cdk/tsconfig.json b/src/cdk/tsconfig.json index db5560801237..52b341bde973 100644 --- a/src/cdk/tsconfig.json +++ b/src/cdk/tsconfig.json @@ -8,5 +8,5 @@ "@angular/cdk/*": ["./*"] } }, - "include": ["./**/*.ts"] + "include": ["./**/*.ts", "../dev-mode-types.d.ts"] } diff --git a/src/dev-mode-types.d.ts b/src/dev-mode-types.d.ts new file mode 100644 index 000000000000..167612cef1f1 --- /dev/null +++ b/src/dev-mode-types.d.ts @@ -0,0 +1,2 @@ +/** Variable replaced at build time that indicates whether the app is in development mode. */ +declare const ngDevMode: object | null; diff --git a/src/google-maps/BUILD.bazel b/src/google-maps/BUILD.bazel index fdf77cc735e0..d9481039ec40 100644 --- a/src/google-maps/BUILD.bazel +++ b/src/google-maps/BUILD.bazel @@ -10,6 +10,7 @@ ng_module( ), module_name = "@angular/google-maps", deps = [ + "//src:dev_mode_types", "@npm//@angular/common", "@npm//@angular/core", "@npm//@types/googlemaps", diff --git a/src/google-maps/google-map/google-map.ts b/src/google-maps/google-map/google-map.ts index 69a20b7b4bcc..9f6efcdd4bd7 100644 --- a/src/google-maps/google-map/google-map.ts +++ b/src/google-maps/google-map/google-map.ts @@ -243,7 +243,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { if (this._isBrowser) { const googleMapsWindow: GoogleMapsWindow = window; - if (!googleMapsWindow.google) { + if (!googleMapsWindow.google && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error( 'Namespace google not found, cannot construct embedded google ' + 'map. Please install the Google Maps JavaScript API: ' + @@ -508,7 +508,7 @@ export class GoogleMap implements OnChanges, OnInit, OnDestroy { /** Asserts that the map has been initialized. */ private _assertInitialized(): asserts this is {googleMap: google.maps.Map} { - if (!this.googleMap) { + if (!this.googleMap && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Cannot access Google Map information before the API has been initialized. ' + 'Please wait for the API to load before trying to interact with it.'); } diff --git a/src/google-maps/map-circle/map-circle.ts b/src/google-maps/map-circle/map-circle.ts index dc72219df1d6..535d77fb0c3b 100644 --- a/src/google-maps/map-circle/map-circle.ts +++ b/src/google-maps/map-circle/map-circle.ts @@ -280,15 +280,17 @@ export class MapCircle implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is {circle: google.maps.Circle} { - if (!this._map.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.circle) { - throw Error( - 'Cannot interact with a Google Map Circle before it has been ' + - 'initialized. Please wait for the Circle to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.circle) { + throw Error( + 'Cannot interact with a Google Map Circle before it has been ' + + 'initialized. Please wait for the Circle to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/map-ground-overlay/map-ground-overlay.ts b/src/google-maps/map-ground-overlay/map-ground-overlay.ts index 40c6266aa865..9214fba4d021 100644 --- a/src/google-maps/map-ground-overlay/map-ground-overlay.ts +++ b/src/google-maps/map-ground-overlay/map-ground-overlay.ts @@ -77,7 +77,7 @@ export class MapGroundOverlay implements OnInit, OnDestroy { constructor(private readonly _map: GoogleMap, private readonly _ngZone: NgZone) {} ngOnInit() { - if (!this.bounds) { + if (!this.bounds && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Image bounds are required'); } if (this._map._isBrowser) { @@ -170,15 +170,17 @@ export class MapGroundOverlay implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is {groundOverlay: google.maps.GroundOverlay} { - if (!this._map.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.groundOverlay) { - throw Error( - 'Cannot interact with a Google Map GroundOverlay before it has been initialized. ' + - 'Please wait for the GroundOverlay to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.groundOverlay) { + throw Error( + 'Cannot interact with a Google Map GroundOverlay before it has been initialized. ' + + 'Please wait for the GroundOverlay to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/map-info-window/map-info-window.ts b/src/google-maps/map-info-window/map-info-window.ts index 15a94cbb9f59..8bbc9cd7a42f 100644 --- a/src/google-maps/map-info-window/map-info-window.ts +++ b/src/google-maps/map-info-window/map-info-window.ts @@ -210,16 +210,18 @@ export class MapInfoWindow implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is {infoWindow: google.maps.InfoWindow} { - if (!this._googleMap.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.infoWindow) { - throw Error( - 'Cannot interact with a Google Map Info Window before it has been ' + - 'initialized. Please wait for the Info Window to load before trying to interact with ' + - 'it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._googleMap.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.infoWindow) { + throw Error( + 'Cannot interact with a Google Map Info Window before it has been ' + + 'initialized. Please wait for the Info Window to load before trying to interact with ' + + 'it.'); + } } } } diff --git a/src/google-maps/map-kml-layer/map-kml-layer.ts b/src/google-maps/map-kml-layer/map-kml-layer.ts index 562e5a1f8fef..32cf1c820924 100644 --- a/src/google-maps/map-kml-layer/map-kml-layer.ts +++ b/src/google-maps/map-kml-layer/map-kml-layer.ts @@ -176,15 +176,17 @@ export class MapKmlLayer implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is { kmlLayer: google.maps.KmlLayer } { - if (!this._map.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.kmlLayer) { - throw Error( - 'Cannot interact with a Google Map KmlLayer before it has been ' + - 'initialized. Please wait for the KmlLayer to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.kmlLayer) { + throw Error( + 'Cannot interact with a Google Map KmlLayer before it has been ' + + 'initialized. Please wait for the KmlLayer to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/map-marker/map-marker.ts b/src/google-maps/map-marker/map-marker.ts index 86fe4138bd83..363e7fa80636 100644 --- a/src/google-maps/map-marker/map-marker.ts +++ b/src/google-maps/map-marker/map-marker.ts @@ -441,15 +441,17 @@ export class MapMarker implements OnInit, OnDestroy, MapAnchorPoint { } private _assertInitialized(): asserts this is {marker: google.maps.Marker} { - if (!this._googleMap.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.marker) { - throw Error( - 'Cannot interact with a Google Map Marker before it has been ' + - 'initialized. Please wait for the Marker to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._googleMap.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.marker) { + throw Error( + 'Cannot interact with a Google Map Marker before it has been ' + + 'initialized. Please wait for the Marker to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/map-polygon/map-polygon.ts b/src/google-maps/map-polygon/map-polygon.ts index 469e6fd1922b..a16666e2904e 100644 --- a/src/google-maps/map-polygon/map-polygon.ts +++ b/src/google-maps/map-polygon/map-polygon.ts @@ -236,15 +236,17 @@ export class MapPolygon implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is {polygon: google.maps.Polygon} { - if (!this._map.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.polygon) { - throw Error( - 'Cannot interact with a Google Map Polygon before it has been ' + - 'initialized. Please wait for the Polygon to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.polygon) { + throw Error( + 'Cannot interact with a Google Map Polygon before it has been ' + + 'initialized. Please wait for the Polygon to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/map-polyline/map-polyline.ts b/src/google-maps/map-polyline/map-polyline.ts index e766b6d0ff77..082bb2ca4a05 100644 --- a/src/google-maps/map-polyline/map-polyline.ts +++ b/src/google-maps/map-polyline/map-polyline.ts @@ -227,15 +227,17 @@ export class MapPolyline implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is {polyline: google.maps.Polyline} { - if (!this._map.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.polyline) { - throw Error( - 'Cannot interact with a Google Map Polyline before it has been ' + - 'initialized. Please wait for the Polyline to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.polyline) { + throw Error( + 'Cannot interact with a Google Map Polyline before it has been ' + + 'initialized. Please wait for the Polyline to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/map-rectangle/map-rectangle.ts b/src/google-maps/map-rectangle/map-rectangle.ts index 73724cc1affa..a990d902a938 100644 --- a/src/google-maps/map-rectangle/map-rectangle.ts +++ b/src/google-maps/map-rectangle/map-rectangle.ts @@ -239,15 +239,17 @@ export class MapRectangle implements OnInit, OnDestroy { } private _assertInitialized(): asserts this is {rectangle: google.maps.Rectangle} { - if (!this._map.googleMap) { - throw Error( - 'Cannot access Google Map information before the API has been initialized. ' + - 'Please wait for the API to load before trying to interact with it.'); - } - if (!this.rectangle) { - throw Error( - 'Cannot interact with a Google Map Rectangle before it has been ' + - 'initialized. Please wait for the Rectangle to load before trying to interact with it.'); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._map.googleMap) { + throw Error( + 'Cannot access Google Map information before the API has been initialized. ' + + 'Please wait for the API to load before trying to interact with it.'); + } + if (!this.rectangle) { + throw Error( + 'Cannot interact with a Google Map Rectangle before it has been initialized. ' + + 'Please wait for the Rectangle to load before trying to interact with it.'); + } } } } diff --git a/src/google-maps/tsconfig-tests.json b/src/google-maps/tsconfig-tests.json index 6f1c8cb241aa..0b483e5010b7 100644 --- a/src/google-maps/tsconfig-tests.json +++ b/src/google-maps/tsconfig-tests.json @@ -16,7 +16,8 @@ "emitDecoratorMetadata": true }, "include": [ - "**/*.spec.ts" + "**/*.spec.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "**/*.e2e.spec.ts" diff --git a/src/google-maps/tsconfig.json b/src/google-maps/tsconfig.json index 1dae47577d3b..d57281895299 100644 --- a/src/google-maps/tsconfig.json +++ b/src/google-maps/tsconfig.json @@ -10,6 +10,7 @@ ] }, "include": [ - "./**/*.ts" + "./**/*.ts", + "../dev-mode-types.d.ts" ] } diff --git a/src/material-experimental/mdc-chips/BUILD.bazel b/src/material-experimental/mdc-chips/BUILD.bazel index 46614a13ed91..f76a5cbd78db 100644 --- a/src/material-experimental/mdc-chips/BUILD.bazel +++ b/src/material-experimental/mdc-chips/BUILD.bazel @@ -20,6 +20,7 @@ ng_module( assets = [":chips_scss"] + glob(["**/*.html"]), module_name = "@angular/material-experimental/mdc-chips", deps = [ + "//src:dev_mode_types", "//src/material/core", "//src/material/form-field", "@npm//@angular/animations", diff --git a/src/material-experimental/mdc-chips/chip-grid.ts b/src/material-experimental/mdc-chips/chip-grid.ts index 1c73dfa7dae7..c1c94462812f 100644 --- a/src/material-experimental/mdc-chips/chip-grid.ts +++ b/src/material-experimental/mdc-chips/chip-grid.ts @@ -269,7 +269,7 @@ export class MatChipGrid extends _MatChipGridMixinBase implements AfterContentIn ngAfterViewInit() { super.ngAfterViewInit(); - if (!this._chipInput) { + if (!this._chipInput && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('mat-chip-grid must be used in combination with matChipInputFor.'); } } diff --git a/src/material-experimental/mdc-form-field/BUILD.bazel b/src/material-experimental/mdc-form-field/BUILD.bazel index 950bd86633b1..0ada5faa55e9 100644 --- a/src/material-experimental/mdc-form-field/BUILD.bazel +++ b/src/material-experimental/mdc-form-field/BUILD.bazel @@ -16,6 +16,7 @@ ng_module( assets = [":form_field_scss"] + glob(["**/*.html"]), module_name = "@angular/material-experimental/mdc-form-field", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/observers", "//src/cdk/platform", diff --git a/src/material-experimental/mdc-form-field/form-field.ts b/src/material-experimental/mdc-form-field/form-field.ts index 12124b87d168..ab1c17d31685 100644 --- a/src/material-experimental/mdc-form-field/form-field.ts +++ b/src/material-experimental/mdc-form-field/form-field.ts @@ -20,7 +20,6 @@ import { Inject, InjectionToken, Input, - isDevMode, NgZone, OnDestroy, Optional, @@ -445,7 +444,7 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck /** Throws an error if the form field's control is missing. */ private _assertFormFieldControl() { - if (!this._control) { + if (!this._control && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatFormFieldMissingControlError(); } } @@ -558,7 +557,7 @@ export class MatFormField implements AfterViewInit, OnDestroy, AfterContentCheck * This method is a noop if Angular runs in production mode. */ private _validateHints() { - if (isDevMode() && this._hintChildren) { + if (this._hintChildren && (typeof ngDevMode === 'undefined' || ngDevMode)) { let startHint: MatHint; let endHint: MatHint; this._hintChildren.forEach((hint: MatHint) => { diff --git a/src/material-experimental/mdc-snack-bar/BUILD.bazel b/src/material-experimental/mdc-snack-bar/BUILD.bazel index a4c6cccd3cb9..08a5f6150c83 100644 --- a/src/material-experimental/mdc-snack-bar/BUILD.bazel +++ b/src/material-experimental/mdc-snack-bar/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material-experimental/mdc-snack-bar", deps = [ + "//src:dev_mode_types", "//src/material/core", "//src/material/snack-bar", "@npm//@angular/core", diff --git a/src/material-experimental/mdc-snack-bar/snack-bar-container.ts b/src/material-experimental/mdc-snack-bar/snack-bar-container.ts index 6b46589288f1..6ed19cf3eac8 100644 --- a/src/material-experimental/mdc-snack-bar/snack-bar-container.ts +++ b/src/material-experimental/mdc-snack-bar/snack-bar-container.ts @@ -184,7 +184,7 @@ export class MatSnackBarContainer extends BasePortalOutlet /** Asserts that no content is already attached to the container. */ private _assertNotAttached() { - if (this._portalOutlet.hasAttached()) { + if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Attempting to attach snack bar content after content is already attached'); } } diff --git a/src/material-experimental/mdc-snack-bar/tsconfig-build.json b/src/material-experimental/mdc-snack-bar/tsconfig-build.json index a99a3aadf9c9..c7f596c14adb 100644 --- a/src/material-experimental/mdc-snack-bar/tsconfig-build.json +++ b/src/material-experimental/mdc-snack-bar/tsconfig-build.json @@ -2,7 +2,7 @@ "extends": "../tsconfig-build", "files": [ "public-api.ts", - "../typings.d.ts" + "../dev-mode-types.d.ts" ], "angularCompilerOptions": { "annotateForClosureCompiler": true, diff --git a/src/material-experimental/mdc-table/tsconfig-build.json b/src/material-experimental/mdc-table/tsconfig-build.json index c8eea0933d7e..05628eb9342a 100644 --- a/src/material-experimental/mdc-table/tsconfig-build.json +++ b/src/material-experimental/mdc-table/tsconfig-build.json @@ -2,7 +2,7 @@ "extends": "../tsconfig-build", "files": [ "public-api.ts", - "../typings.d.ts" + "../dev-mode-types.d.ts" ], "angularCompilerOptions": { "annotateForClosureCompiler": true, diff --git a/src/material-experimental/mdc-tabs/BUILD.bazel b/src/material-experimental/mdc-tabs/BUILD.bazel index 43b58feb508b..d683573b0c6c 100644 --- a/src/material-experimental/mdc-tabs/BUILD.bazel +++ b/src/material-experimental/mdc-tabs/BUILD.bazel @@ -26,6 +26,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material-experimental/mdc-tabs", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material-experimental/mdc-tabs/ink-bar.ts b/src/material-experimental/mdc-tabs/ink-bar.ts index 8bc79662f849..388ce0a4ae57 100644 --- a/src/material-experimental/mdc-tabs/ink-bar.ts +++ b/src/material-experimental/mdc-tabs/ink-bar.ts @@ -163,7 +163,7 @@ export class MatInkBarFoundation { * the ink bar should fit to content. */ private _appendInkBarElement() { - if (!this._inkBarElement) { + if (!this._inkBarElement && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Ink bar element has not been created and cannot be appended'); } @@ -171,10 +171,10 @@ export class MatInkBarFoundation { this._hostElement.querySelector('.mdc-tab__content') : this._hostElement; - if (!parentElement) { + if (!parentElement && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Missing element to host the ink bar'); } - parentElement.appendChild(this._inkBarElement); + parentElement!.appendChild(this._inkBarElement); } } diff --git a/src/material-experimental/selection/selection-column.ts b/src/material-experimental/selection/selection-column.ts index 8fba868c49cd..6fe44671003f 100644 --- a/src/material-experimental/selection/selection-column.ts +++ b/src/material-experimental/selection/selection-column.ts @@ -10,7 +10,6 @@ import {MatCellDef, MatColumnDef, MatHeaderCellDef, MatTable} from '@angular/mat import { Component, Input, - isDevMode, OnDestroy, OnInit, Optional, @@ -73,7 +72,7 @@ export class MatSelectionColumn implements OnInit, OnDestroy { ) {} ngOnInit() { - if (!this.selection && isDevMode()) { + if (!this.selection && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('MatSelectionColumn: missing MatSelection in the parent'); } @@ -83,7 +82,7 @@ export class MatSelectionColumn implements OnInit, OnDestroy { this._columnDef.cell = this._cell; this._columnDef.headerCell = this._headerCell; this._table.addColumnDef(this._columnDef); - } else if (isDevMode()) { + } else if (typeof ngDevMode === 'undefined' || ngDevMode) { throw Error('MatSelectionColumn: missing parent table'); } } diff --git a/src/material-experimental/tsconfig-tests.json b/src/material-experimental/tsconfig-tests.json index 73270ad2b000..01a6b0420651 100644 --- a/src/material-experimental/tsconfig-tests.json +++ b/src/material-experimental/tsconfig-tests.json @@ -23,7 +23,8 @@ }, "include": [ "**/*.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "**/*.e2e.spec.ts" diff --git a/src/material-experimental/tsconfig.json b/src/material-experimental/tsconfig.json index 4c8e263f0463..14443497be8d 100644 --- a/src/material-experimental/tsconfig.json +++ b/src/material-experimental/tsconfig.json @@ -12,5 +12,5 @@ "@material/*": ["../../node_modules/@material/*/index.d.ts"] } }, - "include": ["./**/*.ts"] + "include": ["./**/*.ts", "../dev-mode-types.d.ts"] } diff --git a/src/material-moment-adapter/BUILD.bazel b/src/material-moment-adapter/BUILD.bazel index 8b1677cf359c..7852377662fb 100644 --- a/src/material-moment-adapter/BUILD.bazel +++ b/src/material-moment-adapter/BUILD.bazel @@ -14,6 +14,7 @@ ng_module( # because "moment" does not have a typed default import. tsconfig = ":tsconfig", deps = [ + "//src:dev_mode_types", "//src/material/core", "@npm//@angular/core", "@npm//moment", diff --git a/src/material-moment-adapter/adapter/moment-date-adapter.ts b/src/material-moment-adapter/adapter/moment-date-adapter.ts index 75b8a302b46b..2eb44cd682c1 100644 --- a/src/material-moment-adapter/adapter/moment-date-adapter.ts +++ b/src/material-moment-adapter/adapter/moment-date-adapter.ts @@ -157,18 +157,20 @@ export class MomentDateAdapter extends DateAdapter { createDate(year: number, month: number, date: number): Moment { // Moment.js will create an invalid date if any of the components are out of bounds, but we // explicitly check each case so we can throw more descriptive errors. - if (month < 0 || month > 11) { - throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`); - } + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (month < 0 || month > 11) { + throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`); + } - if (date < 1) { - throw Error(`Invalid date "${date}". Date has to be greater than 0.`); + if (date < 1) { + throw Error(`Invalid date "${date}". Date has to be greater than 0.`); + } } const result = this._createMoment({year, month, date}).locale(this.locale); // If the result isn't valid, the date must have been out of bounds for this month. - if (!result.isValid()) { + if (!result.isValid() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Invalid date "${date}" for month with index "${month}".`); } @@ -188,7 +190,7 @@ export class MomentDateAdapter extends DateAdapter { format(date: Moment, displayFormat: string): string { date = this.clone(date); - if (!this.isValid(date)) { + if (!this.isValid(date) && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('MomentDateAdapter: Cannot format invalid date.'); } return date.format(displayFormat); diff --git a/src/material-moment-adapter/tsconfig-tests.json b/src/material-moment-adapter/tsconfig-tests.json index 277891474207..260b8f8b286f 100644 --- a/src/material-moment-adapter/tsconfig-tests.json +++ b/src/material-moment-adapter/tsconfig-tests.json @@ -22,7 +22,8 @@ }, "include": [ "**/*.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "**/*.e2e.spec.ts" diff --git a/src/material-moment-adapter/tsconfig.json b/src/material-moment-adapter/tsconfig.json index a5a9f4cce0c5..7c93f175485f 100644 --- a/src/material-moment-adapter/tsconfig.json +++ b/src/material-moment-adapter/tsconfig.json @@ -12,5 +12,5 @@ "@angular/material": ["../material/public-api.ts"] } }, - "include": ["./**/*.ts"] + "include": ["./**/*.ts", "../dev-mode-types.d.ts"] } diff --git a/src/material/autocomplete/BUILD.bazel b/src/material/autocomplete/BUILD.bazel index 63b5df642f5a..042f5e3a0283 100644 --- a/src/material/autocomplete/BUILD.bazel +++ b/src/material/autocomplete/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( assets = [":autocomplete.css"] + glob(["**/*.html"]), module_name = "@angular/material/autocomplete", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts index c68aa48f03c4..a77584b1a327 100644 --- a/src/material/autocomplete/autocomplete-trigger.ts +++ b/src/material/autocomplete/autocomplete-trigger.ts @@ -572,7 +572,7 @@ export abstract class _MatAutocompleteTriggerBase implements ControlValueAccesso } private _attachOverlay(): void { - if (!this.autocomplete) { + if (!this.autocomplete && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatAutocompleteMissingPanelError(); } diff --git a/src/material/badge/BUILD.bazel b/src/material/badge/BUILD.bazel index 0364ce4e1570..07c8afba49df 100644 --- a/src/material/badge/BUILD.bazel +++ b/src/material/badge/BUILD.bazel @@ -17,6 +17,7 @@ ng_module( ), module_name = "@angular/material/badge", deps = [ + "//src:dev_mode_types", "@npm//@angular/common", "@npm//@angular/core", "@npm//@angular/platform-browser", diff --git a/src/material/badge/badge.ts b/src/material/badge/badge.ts index cc81ff30be80..2dda9b330aad 100644 --- a/src/material/badge/badge.ts +++ b/src/material/badge/badge.ts @@ -19,7 +19,6 @@ import { Optional, Renderer2, SimpleChanges, - isDevMode, } from '@angular/core'; import {CanDisable, CanDisableCtor, mixinDisabled, ThemePalette} from '@angular/material/core'; import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations'; @@ -131,7 +130,7 @@ export class MatBadge extends _MatBadgeMixinBase implements OnDestroy, OnChanges @Optional() @Inject(ANIMATION_MODULE_TYPE) private _animationMode?: string) { super(); - if (isDevMode()) { + if (typeof ngDevMode === 'undefined' || ngDevMode) { const nativeElement = _elementRef.nativeElement; if (nativeElement.nodeType !== nativeElement.ELEMENT_NODE) { throw Error('matBadge must be attached to an element node.'); diff --git a/src/material/bottom-sheet/BUILD.bazel b/src/material/bottom-sheet/BUILD.bazel index aa88fa854336..121c5c24176b 100644 --- a/src/material/bottom-sheet/BUILD.bazel +++ b/src/material/bottom-sheet/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material/bottom-sheet", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/keycodes", diff --git a/src/material/bottom-sheet/bottom-sheet-container.ts b/src/material/bottom-sheet/bottom-sheet-container.ts index 30108f75d7e8..eb365b438cdc 100644 --- a/src/material/bottom-sheet/bottom-sheet-container.ts +++ b/src/material/bottom-sheet/bottom-sheet-container.ts @@ -175,7 +175,7 @@ export class MatBottomSheetContainer extends BasePortalOutlet implements OnDestr } private _validatePortalAttached() { - if (this._portalOutlet.hasAttached()) { + if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Attempting to attach bottom sheet content after content is already attached'); } } diff --git a/src/material/button-toggle/BUILD.bazel b/src/material/button-toggle/BUILD.bazel index 835703b67a45..c9b8ddfd3577 100644 --- a/src/material/button-toggle/BUILD.bazel +++ b/src/material/button-toggle/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":button-toggle.css"] + glob(["**/*.html"]), module_name = "@angular/material/button-toggle", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/coercion", "//src/cdk/collections", diff --git a/src/material/button-toggle/button-toggle.ts b/src/material/button-toggle/button-toggle.ts index 4d7de8c15e53..95c7180e2e8b 100644 --- a/src/material/button-toggle/button-toggle.ts +++ b/src/material/button-toggle/button-toggle.ts @@ -331,7 +331,7 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After } if (this.multiple && value) { - if (!Array.isArray(value)) { + if (!Array.isArray(value) && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Value must be an array in multiple-selection mode.'); } diff --git a/src/material/core/BUILD.bazel b/src/material/core/BUILD.bazel index 0401fcbe3eb9..bafaeedb815d 100644 --- a/src/material/core/BUILD.bazel +++ b/src/material/core/BUILD.bazel @@ -26,6 +26,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material/core", deps = [ + "//src:dev_mode_types", "//src/cdk", "//src/cdk/a11y", "//src/cdk/bidi", diff --git a/src/material/core/common-behaviors/common-module.ts b/src/material/core/common-behaviors/common-module.ts index c2685f20bdc1..d1234acbe698 100644 --- a/src/material/core/common-behaviors/common-module.ts +++ b/src/material/core/common-behaviors/common-module.ts @@ -106,6 +106,10 @@ export class MatCommonModule { /** Whether any sanity checks are enabled. */ private _checksAreEnabled(): boolean { + // TODO(crisbeto): we can't use `ngDevMode` here yet, because ViewEngine apps might not support + // it. Since these checks can have performance implications and they aren't tree shakeable + // in their current form, we can leave the `isDevMode` check in for now. + // tslint:disable-next-line:ban return isDevMode() && !this._isTestEnv(); } diff --git a/src/material/core/common-behaviors/initialized.ts b/src/material/core/common-behaviors/initialized.ts index 9052ee351e86..8b0152135809 100644 --- a/src/material/core/common-behaviors/initialized.ts +++ b/src/material/core/common-behaviors/initialized.ts @@ -68,7 +68,7 @@ export function mixinInitialized>(base: T): * @docs-private */ _markInitialized(): void { - if (this._isInitialized) { + if (this._isInitialized && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('This directive has already been marked as initialized and ' + 'should not be called twice.'); } diff --git a/src/material/core/datetime/native-date-adapter.ts b/src/material/core/datetime/native-date-adapter.ts index ca78431d0ae4..654a41e0a8cf 100644 --- a/src/material/core/datetime/native-date-adapter.ts +++ b/src/material/core/datetime/native-date-adapter.ts @@ -160,19 +160,21 @@ export class NativeDateAdapter extends DateAdapter { } createDate(year: number, month: number, date: number): Date { - // Check for invalid month and date (except upper bound on date which we have to check after - // creating the Date). - if (month < 0 || month > 11) { - throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`); - } + if (typeof ngDevMode === 'undefined' || ngDevMode) { + // Check for invalid month and date (except upper bound on date which we have to check after + // creating the Date). + if (month < 0 || month > 11) { + throw Error(`Invalid month index "${month}". Month index has to be between 0 and 11.`); + } - if (date < 1) { - throw Error(`Invalid date "${date}". Date has to be greater than 0.`); + if (date < 1) { + throw Error(`Invalid date "${date}". Date has to be greater than 0.`); + } } let result = this._createDateWithOverflow(year, month, date); // Check that the date wasn't above the upper bound for the month, causing the month to overflow - if (result.getMonth() != month) { + if (result.getMonth() != month && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Invalid date "${date}" for month with index "${month}".`); } diff --git a/src/material/datepicker/BUILD.bazel b/src/material/datepicker/BUILD.bazel index e95cbb04a42d..0b6091fc8b08 100644 --- a/src/material/datepicker/BUILD.bazel +++ b/src/material/datepicker/BUILD.bazel @@ -25,6 +25,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material/datepicker", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material/datepicker/calendar.ts b/src/material/datepicker/calendar.ts index 19a0152e7363..bf0fe77f1b6b 100644 --- a/src/material/datepicker/calendar.ts +++ b/src/material/datepicker/calendar.ts @@ -315,12 +315,14 @@ export class MatCalendar implements AfterContentInit, AfterViewChecked, OnDes @Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats, private _changeDetectorRef: ChangeDetectorRef) { - if (!this._dateAdapter) { - throw createMissingDateImplError('DateAdapter'); - } + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } - if (!this._dateFormats) { - throw createMissingDateImplError('MAT_DATE_FORMATS'); + if (!this._dateFormats) { + throw createMissingDateImplError('MAT_DATE_FORMATS'); + } } this._intlChanges = _intl.changes.subscribe(() => { diff --git a/src/material/datepicker/date-range-input.ts b/src/material/datepicker/date-range-input.ts index e8d575e9830c..267a25366912 100644 --- a/src/material/datepicker/date-range-input.ts +++ b/src/material/datepicker/date-range-input.ts @@ -215,7 +215,7 @@ export class MatDateRangeInput implements MatFormFieldControl>, @Optional() private _dateAdapter: DateAdapter, @Optional() @Inject(MAT_FORM_FIELD) private _formField?: MatFormField) { - if (!_dateAdapter) { + if (!_dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw createMissingDateImplError('DateAdapter'); } @@ -246,12 +246,14 @@ export class MatDateRangeInput implements MatFormFieldControl>, } ngAfterContentInit() { - if (!this._startInput) { - throw Error('mat-date-range-input must contain a matStartDate input'); - } + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._startInput) { + throw Error('mat-date-range-input must contain a matStartDate input'); + } - if (!this._endInput) { - throw Error('mat-date-range-input must contain a matEndDate input'); + if (!this._endInput) { + throw Error('mat-date-range-input must contain a matEndDate input'); + } } if (this._model) { diff --git a/src/material/datepicker/datepicker-base.ts b/src/material/datepicker/datepicker-base.ts index 0e7d257fc29d..dc7dbe0a18a7 100644 --- a/src/material/datepicker/datepicker-base.ts +++ b/src/material/datepicker/datepicker-base.ts @@ -386,7 +386,7 @@ export abstract class MatDatepickerBase, S, @Optional() private _dir: Directionality, @Optional() @Inject(DOCUMENT) private _document: any, private _model: MatDateSelectionModel) { - if (!this._dateAdapter) { + if (!this._dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw createMissingDateImplError('DateAdapter'); } @@ -436,7 +436,7 @@ export abstract class MatDatepickerBase, S, * @returns Selection model that the input should hook itself up to. */ _registerInput(input: C): MatDateSelectionModel { - if (this._datepickerInput) { + if (this._datepickerInput && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('A MatDatepicker can only be associated with a single input.'); } this._inputStateChanges.unsubscribe(); @@ -451,7 +451,7 @@ export abstract class MatDatepickerBase, S, if (this._opened || this.disabled) { return; } - if (!this._datepickerInput) { + if (!this._datepickerInput && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Attempted to open an MatDatepicker with no associated input.'); } if (this._document) { diff --git a/src/material/datepicker/datepicker-input-base.ts b/src/material/datepicker/datepicker-input-base.ts index 0d5974de9043..7aa3223de98f 100644 --- a/src/material/datepicker/datepicker-input-base.ts +++ b/src/material/datepicker/datepicker-input-base.ts @@ -250,11 +250,14 @@ export abstract class MatDatepickerInputBase, @Optional() public _dateAdapter: DateAdapter, @Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats) { - if (!this._dateAdapter) { - throw createMissingDateImplError('DateAdapter'); - } - if (!this._dateFormats) { - throw createMissingDateImplError('MAT_DATE_FORMATS'); + + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MAT_DATE_FORMATS'); + } } // Update the displayed date when the locale changes. diff --git a/src/material/datepicker/month-view.ts b/src/material/datepicker/month-view.ts index 3f307ec1c746..0202f8695ff2 100644 --- a/src/material/datepicker/month-view.ts +++ b/src/material/datepicker/month-view.ts @@ -185,11 +185,14 @@ export class MatMonthView implements AfterContentInit, OnChanges, OnDestroy { @Optional() private _dir?: Directionality, @Inject(MAT_DATE_RANGE_SELECTION_STRATEGY) @Optional() private _rangeStrategy?: MatDateRangeSelectionStrategy) { - if (!this._dateAdapter) { - throw createMissingDateImplError('DateAdapter'); - } - if (!this._dateFormats) { - throw createMissingDateImplError('MAT_DATE_FORMATS'); + + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MAT_DATE_FORMATS'); + } } this._activeDate = this._dateAdapter.today(); diff --git a/src/material/datepicker/multi-year-view.ts b/src/material/datepicker/multi-year-view.ts index 7b40d577b59c..2bd6c4efe034 100644 --- a/src/material/datepicker/multi-year-view.ts +++ b/src/material/datepicker/multi-year-view.ts @@ -141,7 +141,7 @@ export class MatMultiYearView implements AfterContentInit, OnDestroy { constructor(private _changeDetectorRef: ChangeDetectorRef, @Optional() public _dateAdapter: DateAdapter, @Optional() private _dir?: Directionality) { - if (!this._dateAdapter) { + if (!this._dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw createMissingDateImplError('DateAdapter'); } diff --git a/src/material/datepicker/year-view.ts b/src/material/datepicker/year-view.ts index 80f732b88578..be6075c387f4 100644 --- a/src/material/datepicker/year-view.ts +++ b/src/material/datepicker/year-view.ts @@ -142,11 +142,14 @@ export class MatYearView implements AfterContentInit, OnDestroy { @Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats, @Optional() public _dateAdapter: DateAdapter, @Optional() private _dir?: Directionality) { - if (!this._dateAdapter) { - throw createMissingDateImplError('DateAdapter'); - } - if (!this._dateFormats) { - throw createMissingDateImplError('MAT_DATE_FORMATS'); + + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!this._dateAdapter) { + throw createMissingDateImplError('DateAdapter'); + } + if (!this._dateFormats) { + throw createMissingDateImplError('MAT_DATE_FORMATS'); + } } this._activeDate = this._dateAdapter.today(); diff --git a/src/material/dialog/BUILD.bazel b/src/material/dialog/BUILD.bazel index 76d1f6a2745b..a13a3df9f276 100644 --- a/src/material/dialog/BUILD.bazel +++ b/src/material/dialog/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":dialog.css"] + glob(["**/*.html"]), module_name = "@angular/material/dialog", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/keycodes", diff --git a/src/material/dialog/dialog-container.ts b/src/material/dialog/dialog-container.ts index 1a1b05906947..10dbe5c40bb0 100644 --- a/src/material/dialog/dialog-container.ts +++ b/src/material/dialog/dialog-container.ts @@ -114,7 +114,7 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet { * @param portal Portal to be attached as the dialog content. */ attachComponentPortal(portal: ComponentPortal): ComponentRef { - if (this._portalOutlet.hasAttached()) { + if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatDialogContentAlreadyAttachedError(); } @@ -126,7 +126,7 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet { * @param portal Portal to be attached as the dialog content. */ attachTemplatePortal(portal: TemplatePortal): EmbeddedViewRef { - if (this._portalOutlet.hasAttached()) { + if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatDialogContentAlreadyAttachedError(); } @@ -140,7 +140,7 @@ export abstract class _MatDialogContainerBase extends BasePortalOutlet { * @breaking-change 10.0.0 */ attachDomPortal = (portal: DomPortal) => { - if (this._portalOutlet.hasAttached()) { + if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatDialogContentAlreadyAttachedError(); } diff --git a/src/material/dialog/dialog.ts b/src/material/dialog/dialog.ts index 667e8b64db1f..51a0f9d3bfc6 100644 --- a/src/material/dialog/dialog.ts +++ b/src/material/dialog/dialog.ts @@ -126,7 +126,8 @@ export abstract class _MatDialogBase implemen config = _applyConfigDefaults(config, this._defaultOptions || new MatDialogConfig()); - if (config.id && this.getDialogById(config.id)) { + if (config.id && this.getDialogById(config.id) && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Dialog with id "${config.id}" exists already. The dialog id must be unique.`); } diff --git a/src/material/form-field/BUILD.bazel b/src/material/form-field/BUILD.bazel index 19541b01e0ed..40579a0f6560 100644 --- a/src/material/form-field/BUILD.bazel +++ b/src/material/form-field/BUILD.bazel @@ -24,6 +24,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material/form-field", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/coercion", "//src/cdk/observers", diff --git a/src/material/form-field/form-field.ts b/src/material/form-field/form-field.ts index f5394eb3ebc4..a25864928f30 100644 --- a/src/material/form-field/form-field.ts +++ b/src/material/form-field/form-field.ts @@ -458,7 +458,8 @@ export class MatFormField extends _MatFormFieldMixinBase * or child element with the `mat-placeholder` directive). */ private _validatePlaceholders() { - if (this._control.placeholder && this._placeholderChild) { + if (this._control.placeholder && this._placeholderChild && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatFormFieldPlaceholderConflictError(); } } @@ -474,7 +475,7 @@ export class MatFormField extends _MatFormFieldMixinBase * attribute being considered as `align="start"`. */ private _validateHints() { - if (this._hintChildren) { + if (this._hintChildren && (typeof ngDevMode === 'undefined' || ngDevMode)) { let startHint: MatHint; let endHint: MatHint; this._hintChildren.forEach((hint: MatHint) => { @@ -531,7 +532,7 @@ export class MatFormField extends _MatFormFieldMixinBase /** Throws an error if the form field's control is missing. */ protected _validateControlChild() { - if (!this._control) { + if (!this._control && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatFormFieldMissingControlError(); } } diff --git a/src/material/grid-list/BUILD.bazel b/src/material/grid-list/BUILD.bazel index 4f2ca1a6b046..a24e1e89af54 100644 --- a/src/material/grid-list/BUILD.bazel +++ b/src/material/grid-list/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":grid-list.css"] + glob(["**/*.html"]), module_name = "@angular/material/grid-list", deps = [ + "//src:dev_mode_types", "//src/cdk/bidi", "//src/cdk/coercion", "//src/material/core", diff --git a/src/material/grid-list/grid-list.ts b/src/material/grid-list/grid-list.ts index 4603b0c60cd0..3bbe08b67167 100644 --- a/src/material/grid-list/grid-list.ts +++ b/src/material/grid-list/grid-list.ts @@ -122,7 +122,7 @@ export class MatGridList implements MatGridListBase, OnInit, AfterContentChecked /** Throw a friendly error if cols property is missing */ private _checkCols() { - if (!this.cols) { + if (!this.cols && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`mat-grid-list: must pass in number of columns. ` + `Example: `); } diff --git a/src/material/grid-list/tile-coordinator.ts b/src/material/grid-list/tile-coordinator.ts index febec1e87f71..e7b11314f652 100644 --- a/src/material/grid-list/tile-coordinator.ts +++ b/src/material/grid-list/tile-coordinator.ts @@ -92,7 +92,7 @@ export class TileCoordinator { /** Finds the next available space large enough to fit the tile. */ private _findMatchingGap(tileCols: number): number { - if (tileCols > this.tracker.length) { + if (tileCols > this.tracker.length && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`mat-grid-list: tile with colspan ${tileCols} is wider than ` + `grid with cols="${this.tracker.length}".`); } diff --git a/src/material/grid-list/tile-styler.ts b/src/material/grid-list/tile-styler.ts index c3eea96152c9..404226d3558a 100644 --- a/src/material/grid-list/tile-styler.ts +++ b/src/material/grid-list/tile-styler.ts @@ -175,7 +175,8 @@ export class FixedTileStyler extends TileStyler { super.init(gutterSize, tracker, cols, direction); this.fixedRowHeight = normalizeUnits(this.fixedRowHeight); - if (!cssCalcAllowedValue.test(this.fixedRowHeight)) { + if (!cssCalcAllowedValue.test(this.fixedRowHeight) && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Invalid value "${this.fixedRowHeight}" set as rowHeight.`); } } @@ -250,7 +251,7 @@ export class RatioTileStyler extends TileStyler { private _parseRatio(value: string): void { const ratioParts = value.split(':'); - if (ratioParts.length !== 2) { + if (ratioParts.length !== 2 && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`mat-grid-list: invalid ratio given for row-height: "${value}"`); } diff --git a/src/material/icon/BUILD.bazel b/src/material/icon/BUILD.bazel index f684b9674774..edfb5fcb359f 100644 --- a/src/material/icon/BUILD.bazel +++ b/src/material/icon/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":icon.css"] + glob(["**/*.html"]), module_name = "@angular/material/icon", deps = [ + "//src:dev_mode_types", "//src/cdk/coercion", "//src/material/core", "@npm//@angular/common", diff --git a/src/material/icon/icon-registry.ts b/src/material/icon/icon-registry.ts index 7018f2604906..711bedb1998b 100644 --- a/src/material/icon/icon-registry.ts +++ b/src/material/icon/icon-registry.ts @@ -175,7 +175,7 @@ export class MatIconRegistry implements OnDestroy { options?: IconOptions): this { const cleanLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal); - if (!cleanLiteral) { + if (!cleanLiteral && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatIconFailedToSanitizeLiteralError(literal); } @@ -217,7 +217,7 @@ export class MatIconRegistry implements OnDestroy { options?: IconOptions): this { const cleanLiteral = this._sanitizer.sanitize(SecurityContext.HTML, literal); - if (!cleanLiteral) { + if (!cleanLiteral && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatIconFailedToSanitizeLiteralError(literal); } @@ -381,11 +381,11 @@ export class MatIconRegistry implements OnDestroy { return forkJoin(iconSetFetchRequests).pipe(map(() => { const foundIcon = this._extractIconWithNameFromAnySet(name, iconSetConfigs); - if (!foundIcon) { + if (!foundIcon && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatIconNameNotFoundError(name); } - return foundIcon; + return foundIcon!; })); } @@ -491,7 +491,7 @@ export class MatIconRegistry implements OnDestroy { div.innerHTML = str; const svg = div.querySelector('svg') as SVGElement; - if (!svg) { + if (!svg && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(' tag not found'); } @@ -552,31 +552,31 @@ export class MatIconRegistry implements OnDestroy { throw getMatIconNoHttpProviderError(); } - if (safeUrl == null) { + if (safeUrl == null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error(`Cannot fetch icon from URL "${safeUrl}".`); } const url = this._sanitizer.sanitize(SecurityContext.RESOURCE_URL, safeUrl); - if (!url) { - throw getMatIconFailedToSanitizeUrlError(safeUrl); + if (!url && (typeof ngDevMode === 'undefined' || ngDevMode)) { + throw getMatIconFailedToSanitizeUrlError(safeUrl!); } // Store in-progress fetches to avoid sending a duplicate request for a URL when there is // already a request in progress for that URL. It's necessary to call share() on the // Observable returned by http.get() so that multiple subscribers don't cause multiple XHRs. - const inProgressFetch = this._inProgressUrlFetches.get(url); + const inProgressFetch = this._inProgressUrlFetches.get(url!); if (inProgressFetch) { return inProgressFetch; } - const req = this._httpClient.get(url, {responseType: 'text', withCredentials}).pipe( - finalize(() => this._inProgressUrlFetches.delete(url)), + const req = this._httpClient.get(url!, {responseType: 'text', withCredentials}).pipe( + finalize(() => this._inProgressUrlFetches.delete(url!)), share(), ); - this._inProgressUrlFetches.set(url, req); + this._inProgressUrlFetches.set(url!, req); return req; } diff --git a/src/material/icon/icon.ts b/src/material/icon/icon.ts index 39218adf220e..173b11893810 100644 --- a/src/material/icon/icon.ts +++ b/src/material/icon/icon.ts @@ -222,7 +222,11 @@ export class MatIcon extends _MatIconMixinBase implements OnChanges, OnInit, Aft switch (parts.length) { case 1: return ['', parts[0]]; // Use default namespace. case 2: return <[string, string]>parts; - default: throw Error(`Invalid icon name: "${iconName}"`); + default: + if (typeof ngDevMode === 'undefined' || ngDevMode) { + throw Error(`Invalid icon name: "${iconName}"`); + } + return ['', '']; } } diff --git a/src/material/input/BUILD.bazel b/src/material/input/BUILD.bazel index 66a6752717c1..b3ad7b882b67 100644 --- a/src/material/input/BUILD.bazel +++ b/src/material/input/BUILD.bazel @@ -20,6 +20,7 @@ ng_module( assets = glob(["**/*.html"]), module_name = "@angular/material/input", deps = [ + "//src:dev_mode_types", "//src/cdk/coercion", "//src/cdk/platform", "//src/cdk/text-field", diff --git a/src/material/input/input.ts b/src/material/input/input.ts index 3c3dd6ba8288..3c0bdb5eac6b 100644 --- a/src/material/input/input.ts +++ b/src/material/input/input.ts @@ -387,7 +387,8 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl< /** Make sure the input is a supported type. */ protected _validateType() { - if (MAT_INPUT_INVALID_TYPES.indexOf(this._type) > -1) { + if (MAT_INPUT_INVALID_TYPES.indexOf(this._type) > -1 && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatInputUnsupportedTypeError(this._type); } } diff --git a/src/material/list/BUILD.bazel b/src/material/list/BUILD.bazel index ca60c4f45eea..e6579acad9a0 100644 --- a/src/material/list/BUILD.bazel +++ b/src/material/list/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":list.css"] + glob(["**/*.html"]), module_name = "@angular/material/list", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/coercion", "//src/cdk/collections", diff --git a/src/material/list/selection-list.ts b/src/material/list/selection-list.ts index 55a730d0f45a..d7539752d45b 100644 --- a/src/material/list/selection-list.ts +++ b/src/material/list/selection-list.ts @@ -32,7 +32,6 @@ import { forwardRef, Inject, Input, - isDevMode, OnChanges, OnDestroy, OnInit, @@ -386,7 +385,7 @@ export class MatSelectionList extends _MatSelectionListMixinBase implements CanD const newValue = coerceBooleanProperty(value); if (newValue !== this._multiple) { - if (isDevMode() && this._contentInitialized) { + if (this._contentInitialized && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw new Error( 'Cannot change `multiple` mode of mat-selection-list after initialization.'); } diff --git a/src/material/menu/BUILD.bazel b/src/material/menu/BUILD.bazel index 58af9691f6b4..c51259eecb86 100644 --- a/src/material/menu/BUILD.bazel +++ b/src/material/menu/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":menu.css"] + glob(["**/*.html"]), module_name = "@angular/material/menu", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material/menu/menu-trigger.ts b/src/material/menu/menu-trigger.ts index 182694aadc37..bbac1c649036 100644 --- a/src/material/menu/menu-trigger.ts +++ b/src/material/menu/menu-trigger.ts @@ -32,7 +32,6 @@ import { Output, Self, ViewContainerRef, - isDevMode, } from '@angular/core'; import {normalizePassiveListenerOptions} from '@angular/cdk/platform'; import {asapScheduler, merge, of as observableOf, Subscription} from 'rxjs'; @@ -122,7 +121,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { this._menuCloseSubscription.unsubscribe(); if (menu) { - if (isDevMode() && menu === this._parentMenu) { + if (menu === this._parentMenu && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatMenuRecursiveError(); } @@ -380,7 +379,7 @@ export class MatMenuTrigger implements AfterContentInit, OnDestroy { * matMenuTriggerFor. If not, an exception is thrown. */ private _checkMenu() { - if (isDevMode() && !this.menu) { + if (!this.menu && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatMenuMissingError(); } } diff --git a/src/material/menu/menu.ts b/src/material/menu/menu.ts index 43e4e2026ef7..3c3d7367aed1 100644 --- a/src/material/menu/menu.ts +++ b/src/material/menu/menu.ts @@ -39,7 +39,6 @@ import { ViewChild, ViewEncapsulation, OnInit, - isDevMode, } from '@angular/core'; import {merge, Observable, Subject, Subscription} from 'rxjs'; import {startWith, switchMap, take} from 'rxjs/operators'; @@ -151,7 +150,8 @@ export class _MatMenuBase implements AfterContentInit, MatMenuPanel @Input() get xPosition(): MenuPositionX { return this._xPosition; } set xPosition(value: MenuPositionX) { - if (isDevMode() && value !== 'before' && value !== 'after') { + if (value !== 'before' && value !== 'after' && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatMenuInvalidPositionX(); } this._xPosition = value; @@ -162,7 +162,7 @@ export class _MatMenuBase implements AfterContentInit, MatMenuPanel @Input() get yPosition(): MenuPositionY { return this._yPosition; } set yPosition(value: MenuPositionY) { - if (isDevMode() && value !== 'above' && value !== 'below') { + if (value !== 'above' && value !== 'below' && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatMenuInvalidPositionY(); } this._yPosition = value; diff --git a/src/material/select/BUILD.bazel b/src/material/select/BUILD.bazel index 9d6e7bebcd7d..aab394c625df 100644 --- a/src/material/select/BUILD.bazel +++ b/src/material/select/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( assets = [":select.css"] + glob(["**/*.html"]), module_name = "@angular/material/select", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material/select/select.ts b/src/material/select/select.ts index 9aed26c3529d..7ec347953566 100644 --- a/src/material/select/select.ts +++ b/src/material/select/select.ts @@ -49,7 +49,6 @@ import { Inject, InjectionToken, Input, - isDevMode, NgZone, OnChanges, OnDestroy, @@ -405,7 +404,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, @Input() get multiple(): boolean { return this._multiple; } set multiple(value: boolean) { - if (this._selectionModel) { + if (this._selectionModel && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatSelectDynamicMultipleError(); } @@ -427,7 +426,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, @Input() get compareWith() { return this._compareWith; } set compareWith(fn: (o1: any, o2: any) => boolean) { - if (typeof fn !== 'function') { + if (typeof fn !== 'function' && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatSelectNonFunctionValueError(); } this._compareWith = fn; @@ -889,7 +888,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, */ private _setSelectionByValue(value: any | any[]): void { if (this.multiple && value) { - if (!Array.isArray(value)) { + if (!Array.isArray(value) && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getMatSelectNonArrayValueError(); } @@ -924,7 +923,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, // Treat null as a special reset value. return option.value != null && this._compareWith(option.value, value); } catch (error) { - if (isDevMode()) { + if (typeof ngDevMode === 'undefined' || ngDevMode) { // Notify developers of errors in their comparator. console.warn(error); } diff --git a/src/material/sidenav/BUILD.bazel b/src/material/sidenav/BUILD.bazel index 7384311c27cc..9e56904f7a8c 100644 --- a/src/material/sidenav/BUILD.bazel +++ b/src/material/sidenav/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":drawer.css"] + glob(["**/*.html"]), module_name = "@angular/material/sidenav", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material/sidenav/drawer.ts b/src/material/sidenav/drawer.ts index f839e545ceab..273b591ac1ac 100644 --- a/src/material/sidenav/drawer.ts +++ b/src/material/sidenav/drawer.ts @@ -808,12 +808,12 @@ export class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy // Ensure that we have at most one start and one end drawer. this._drawers.forEach(drawer => { if (drawer.position == 'end') { - if (this._end != null) { + if (this._end != null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatDuplicatedDrawerError('end'); } this._end = drawer; } else { - if (this._start != null) { + if (this._start != null && (typeof ngDevMode === 'undefined' || ngDevMode)) { throwMatDuplicatedDrawerError('start'); } this._start = drawer; diff --git a/src/material/snack-bar/BUILD.bazel b/src/material/snack-bar/BUILD.bazel index fa702d6507e3..fe9d3b934f17 100644 --- a/src/material/snack-bar/BUILD.bazel +++ b/src/material/snack-bar/BUILD.bazel @@ -22,6 +22,7 @@ ng_module( ] + glob(["**/*.html"]), module_name = "@angular/material/snack-bar", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/layout", diff --git a/src/material/snack-bar/snack-bar-container.ts b/src/material/snack-bar/snack-bar-container.ts index be165badc071..d5f8cf707d11 100644 --- a/src/material/snack-bar/snack-bar-container.ts +++ b/src/material/snack-bar/snack-bar-container.ts @@ -217,7 +217,7 @@ export class MatSnackBarContainer extends BasePortalOutlet /** Asserts that no content is already attached to the container. */ private _assertNotAttached() { - if (this._portalOutlet.hasAttached()) { + if (this._portalOutlet.hasAttached() && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Attempting to attach snack bar content after content is already attached'); } } diff --git a/src/material/sort/BUILD.bazel b/src/material/sort/BUILD.bazel index 9012956d6210..a3a308a7e0e7 100644 --- a/src/material/sort/BUILD.bazel +++ b/src/material/sort/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( assets = [":sort-header.css"] + glob(["**/*.html"]), module_name = "@angular/material/sort", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/coercion", "//src/cdk/keycodes", diff --git a/src/material/sort/sort-header.ts b/src/material/sort/sort-header.ts index b2aa33c3cf92..cb35d053cb08 100644 --- a/src/material/sort/sort-header.ts +++ b/src/material/sort/sort-header.ts @@ -155,7 +155,7 @@ export class MatSortHeader extends _MatSortHeaderMixinBase // of this single reference. super(); - if (!_sort) { + if (!_sort && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getSortHeaderNotContainedWithinSortError(); } diff --git a/src/material/sort/sort.ts b/src/material/sort/sort.ts index 3352beb4a17d..ef0e4fd61a28 100644 --- a/src/material/sort/sort.ts +++ b/src/material/sort/sort.ts @@ -11,7 +11,6 @@ import { Directive, EventEmitter, Input, - isDevMode, OnChanges, OnDestroy, OnInit, @@ -88,7 +87,8 @@ export class MatSort extends _MatSortMixinBase @Input('matSortDirection') get direction(): SortDirection { return this._direction; } set direction(direction: SortDirection) { - if (isDevMode() && direction && direction !== 'asc' && direction !== 'desc') { + if (direction && direction !== 'asc' && direction !== 'desc' && + (typeof ngDevMode === 'undefined' || ngDevMode)) { throw getSortInvalidDirectionError(direction); } this._direction = direction; @@ -112,13 +112,16 @@ export class MatSort extends _MatSortMixinBase * collection of MatSortables. */ register(sortable: MatSortable): void { - if (!sortable.id) { - throw getSortHeaderMissingIdError(); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + if (!sortable.id) { + throw getSortHeaderMissingIdError(); + } + + if (this.sortables.has(sortable.id)) { + throw getSortDuplicateSortableIdError(sortable.id); + } } - if (this.sortables.has(sortable.id)) { - throw getSortDuplicateSortableIdError(sortable.id); - } this.sortables.set(sortable.id, sortable); } diff --git a/src/material/toolbar/BUILD.bazel b/src/material/toolbar/BUILD.bazel index 1f2a35da647f..6686ebedfce9 100644 --- a/src/material/toolbar/BUILD.bazel +++ b/src/material/toolbar/BUILD.bazel @@ -21,6 +21,7 @@ ng_module( assets = [":toolbar.css"] + glob(["**/*.html"]), module_name = "@angular/material/toolbar", deps = [ + "//src:dev_mode_types", "//src/cdk/platform", "//src/material/core", "@npm//@angular/common", diff --git a/src/material/toolbar/toolbar.ts b/src/material/toolbar/toolbar.ts index 4999ef442667..bd7effa85093 100644 --- a/src/material/toolbar/toolbar.ts +++ b/src/material/toolbar/toolbar.ts @@ -16,7 +16,6 @@ import { Directive, ElementRef, Inject, - isDevMode, QueryList, ViewEncapsulation, } from '@angular/core'; @@ -68,31 +67,27 @@ export class MatToolbar extends _MatToolbarMixinBase implements CanColor, AfterV } ngAfterViewInit() { - if (!isDevMode() || !this._platform.isBrowser) { - return; + if (this._platform.isBrowser) { + this._checkToolbarMixedModes(); + this._toolbarRows.changes.subscribe(() => this._checkToolbarMixedModes()); } - - this._checkToolbarMixedModes(); - this._toolbarRows.changes.subscribe(() => this._checkToolbarMixedModes()); } /** * Throws an exception when developers are attempting to combine the different toolbar row modes. */ private _checkToolbarMixedModes() { - if (!this._toolbarRows.length) { - return; - } - - // Check if there are any other DOM nodes that can display content but aren't inside of - // a element. - const isCombinedUsage = Array.from(this._elementRef.nativeElement.childNodes) - .filter(node => !(node.classList && node.classList.contains('mat-toolbar-row'))) - .filter(node => node.nodeType !== (this._document ? this._document.COMMENT_NODE : 8)) - .some(node => !!(node.textContent && node.textContent.trim())); + if (this._toolbarRows.length && (typeof ngDevMode === 'undefined' || ngDevMode)) { + // Check if there are any other DOM nodes that can display content but aren't inside of + // a element. + const isCombinedUsage = Array.from(this._elementRef.nativeElement.childNodes) + .filter(node => !(node.classList && node.classList.contains('mat-toolbar-row'))) + .filter(node => node.nodeType !== (this._document ? this._document.COMMENT_NODE : 8)) + .some(node => !!(node.textContent && node.textContent.trim())); - if (isCombinedUsage) { - throwToolbarMixedModesError(); + if (isCombinedUsage) { + throwToolbarMixedModesError(); + } } } } diff --git a/src/material/tooltip/BUILD.bazel b/src/material/tooltip/BUILD.bazel index 19ac07e2e8b1..2bb720c7225a 100644 --- a/src/material/tooltip/BUILD.bazel +++ b/src/material/tooltip/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( assets = [":tooltip.css"] + glob(["**/*.html"]), module_name = "@angular/material/tooltip", deps = [ + "//src:dev_mode_types", "//src/cdk/a11y", "//src/cdk/bidi", "//src/cdk/coercion", diff --git a/src/material/tooltip/tooltip.ts b/src/material/tooltip/tooltip.ts index f8d4e2d9dfbf..2bca7eadbe9f 100644 --- a/src/material/tooltip/tooltip.ts +++ b/src/material/tooltip/tooltip.ts @@ -458,14 +458,14 @@ export class MatTooltip implements OnDestroy, AfterViewInit { (position == 'right' && isLtr) || (position == 'left' && !isLtr)) { originPosition = {originX: 'end', originY: 'center'}; - } else { + } else if (typeof ngDevMode === 'undefined' || ngDevMode) { throw getMatTooltipInvalidPositionError(position); } - const {x, y} = this._invertPosition(originPosition.originX, originPosition.originY); + const {x, y} = this._invertPosition(originPosition!.originX, originPosition!.originY); return { - main: originPosition, + main: originPosition!, fallback: {originX: x, originY: y} }; } @@ -490,14 +490,14 @@ export class MatTooltip implements OnDestroy, AfterViewInit { (position == 'right' && isLtr) || (position == 'left' && !isLtr)) { overlayPosition = {overlayX: 'start', overlayY: 'center'}; - } else { + } else if (typeof ngDevMode === 'undefined' || ngDevMode) { throw getMatTooltipInvalidPositionError(position); } - const {x, y} = this._invertPosition(overlayPosition.overlayX, overlayPosition.overlayY); + const {x, y} = this._invertPosition(overlayPosition!.overlayX, overlayPosition!.overlayY); return { - main: overlayPosition, + main: overlayPosition!, fallback: {overlayX: x, overlayY: y} }; } diff --git a/src/material/tsconfig-tests.json b/src/material/tsconfig-tests.json index c0eb12812095..7c67f4b16d38 100644 --- a/src/material/tsconfig-tests.json +++ b/src/material/tsconfig-tests.json @@ -22,7 +22,8 @@ }, "include": [ "**/index.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "core/theming/tests/**/*.ts", diff --git a/src/material/tsconfig.json b/src/material/tsconfig.json index b28fddf76c6c..1ca1e8ec4759 100644 --- a/src/material/tsconfig.json +++ b/src/material/tsconfig.json @@ -10,5 +10,5 @@ "@angular/material/*": ["./*"] } }, - "include": ["./**/*.ts"] + "include": ["./**/*.ts", "../dev-mode-types.d.ts"] } diff --git a/src/youtube-player/BUILD.bazel b/src/youtube-player/BUILD.bazel index 8ccbe9e9cf66..b4d25dcf40c9 100644 --- a/src/youtube-player/BUILD.bazel +++ b/src/youtube-player/BUILD.bazel @@ -19,6 +19,7 @@ ng_module( ), module_name = "@angular/youtube-player", deps = [ + "//src:dev_mode_types", "@npm//@angular/common", "@npm//@angular/core", "@npm//@types/youtube", diff --git a/src/youtube-player/tsconfig-tests.json b/src/youtube-player/tsconfig-tests.json index 47b0f6630382..42801e3fe93a 100644 --- a/src/youtube-player/tsconfig-tests.json +++ b/src/youtube-player/tsconfig-tests.json @@ -17,7 +17,8 @@ }, "include": [ "**/*.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "../dev-mode-types.d.ts" ], "exclude": [ "**/*.e2e.spec.ts" diff --git a/src/youtube-player/tsconfig.json b/src/youtube-player/tsconfig.json index bb27efc808a1..19ef7205e54f 100644 --- a/src/youtube-player/tsconfig.json +++ b/src/youtube-player/tsconfig.json @@ -7,5 +7,5 @@ "paths": {}, "types": ["jasmine"] }, - "include": ["*.ts"] + "include": ["*.ts", "../dev-mode-types.d.ts"] } diff --git a/src/youtube-player/youtube-player.ts b/src/youtube-player/youtube-player.ts index 6cf80b43f4d0..a34a7f5b624a 100644 --- a/src/youtube-player/youtube-player.ts +++ b/src/youtube-player/youtube-player.ts @@ -211,7 +211,7 @@ export class YouTubePlayer implements AfterViewInit, OnDestroy, OnInit { let iframeApiAvailableObs: Observable = observableOf(true); if (!window.YT) { - if (this.showBeforeIframeApiLoads) { + if (this.showBeforeIframeApiLoads && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw new Error('Namespace YT not found, cannot construct embedded youtube player. ' + 'Please install the YouTube Player API Reference for iframe Embeds: ' + 'https://developers.google.com/youtube/iframe_api_reference'); diff --git a/tslint.json b/tslint.json index 2dddeb0d899b..99a8f8115a64 100644 --- a/tslint.json +++ b/tslint.json @@ -91,7 +91,8 @@ ["xdescribe"], {"name": ["first"], "message": "Use take(1) instead."}, {"name": ["Object", "assign"], "message": "Use the spread operator instead."}, - {"name": ["*", "asObservable"], "message": "Cast to Observable type instead."} + {"name": ["*", "asObservable"], "message": "Cast to Observable type instead."}, + {"name": ["isDevMode"], "message": "Use `typeof ngDevMode === 'undefined' || ngDevMode` instead"} ], // Avoids inconsistent linebreak styles in source files. Forces developers to use LF linebreaks. "linebreak-style": [true, "LF"],