forms-reactive
Version:
Reactive Form Web Component
1,538 lines (1,498 loc) • 120 kB
JavaScript
function isFunction(x) {
return typeof x === 'function';
}
let _enable_super_gross_mode_that_will_cause_bad_things = false;
const config = {
Promise: undefined,
set useDeprecatedSynchronousErrorHandling(value) {
if (value) {
const error = new Error();
console.warn('DEPRECATED! RxJS was set to use deprecated synchronous error handling behavior by code at: \n' + error.stack);
}
else if (_enable_super_gross_mode_that_will_cause_bad_things) {
console.log('RxJS: Back to a better error behavior. Thank you. <3');
}
_enable_super_gross_mode_that_will_cause_bad_things = value;
},
get useDeprecatedSynchronousErrorHandling() {
return _enable_super_gross_mode_that_will_cause_bad_things;
},
};
function hostReportError(err) {
setTimeout(() => { throw err; }, 0);
}
const empty = {
closed: true,
next(value) { },
error(err) {
if (config.useDeprecatedSynchronousErrorHandling) {
throw err;
}
else {
hostReportError(err);
}
},
complete() { }
};
const isArray = (() => Array.isArray || ((x) => x && typeof x.length === 'number'))();
function isObject(x) {
return x !== null && typeof x === 'object';
}
const UnsubscriptionErrorImpl = (() => {
function UnsubscriptionErrorImpl(errors) {
Error.call(this);
this.message = errors ?
`${errors.length} errors occurred during unsubscription:
${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\n ')}` : '';
this.name = 'UnsubscriptionError';
this.errors = errors;
return this;
}
UnsubscriptionErrorImpl.prototype = Object.create(Error.prototype);
return UnsubscriptionErrorImpl;
})();
const UnsubscriptionError = UnsubscriptionErrorImpl;
class Subscription {
constructor(unsubscribe) {
this.closed = false;
this._parentOrParents = null;
this._subscriptions = null;
if (unsubscribe) {
this._ctorUnsubscribe = true;
this._unsubscribe = unsubscribe;
}
}
unsubscribe() {
let errors;
if (this.closed) {
return;
}
let { _parentOrParents, _ctorUnsubscribe, _unsubscribe, _subscriptions } = this;
this.closed = true;
this._parentOrParents = null;
this._subscriptions = null;
if (_parentOrParents instanceof Subscription) {
_parentOrParents.remove(this);
}
else if (_parentOrParents !== null) {
for (let index = 0; index < _parentOrParents.length; ++index) {
const parent = _parentOrParents[index];
parent.remove(this);
}
}
if (isFunction(_unsubscribe)) {
if (_ctorUnsubscribe) {
this._unsubscribe = undefined;
}
try {
_unsubscribe.call(this);
}
catch (e) {
errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e];
}
}
if (isArray(_subscriptions)) {
let index = -1;
let len = _subscriptions.length;
while (++index < len) {
const sub = _subscriptions[index];
if (isObject(sub)) {
try {
sub.unsubscribe();
}
catch (e) {
errors = errors || [];
if (e instanceof UnsubscriptionError) {
errors = errors.concat(flattenUnsubscriptionErrors(e.errors));
}
else {
errors.push(e);
}
}
}
}
}
if (errors) {
throw new UnsubscriptionError(errors);
}
}
add(teardown) {
let subscription = teardown;
if (!teardown) {
return Subscription.EMPTY;
}
switch (typeof teardown) {
case 'function':
subscription = new Subscription(teardown);
case 'object':
if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') {
return subscription;
}
else if (this.closed) {
subscription.unsubscribe();
return subscription;
}
else if (!(subscription instanceof Subscription)) {
const tmp = subscription;
subscription = new Subscription();
subscription._subscriptions = [tmp];
}
break;
default: {
throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
}
}
let { _parentOrParents } = subscription;
if (_parentOrParents === null) {
subscription._parentOrParents = this;
}
else if (_parentOrParents instanceof Subscription) {
if (_parentOrParents === this) {
return subscription;
}
subscription._parentOrParents = [_parentOrParents, this];
}
else if (_parentOrParents.indexOf(this) === -1) {
_parentOrParents.push(this);
}
else {
return subscription;
}
const subscriptions = this._subscriptions;
if (subscriptions === null) {
this._subscriptions = [subscription];
}
else {
subscriptions.push(subscription);
}
return subscription;
}
remove(subscription) {
const subscriptions = this._subscriptions;
if (subscriptions) {
const subscriptionIndex = subscriptions.indexOf(subscription);
if (subscriptionIndex !== -1) {
subscriptions.splice(subscriptionIndex, 1);
}
}
}
}
Subscription.EMPTY = (function (empty) {
empty.closed = true;
return empty;
}(new Subscription()));
function flattenUnsubscriptionErrors(errors) {
return errors.reduce((errs, err) => errs.concat((err instanceof UnsubscriptionError) ? err.errors : err), []);
}
const rxSubscriber = (() => typeof Symbol === 'function'
? Symbol('rxSubscriber')
: '@@rxSubscriber_' + Math.random())();
class Subscriber extends Subscription {
constructor(destinationOrNext, error, complete) {
super();
this.syncErrorValue = null;
this.syncErrorThrown = false;
this.syncErrorThrowable = false;
this.isStopped = false;
switch (arguments.length) {
case 0:
this.destination = empty;
break;
case 1:
if (!destinationOrNext) {
this.destination = empty;
break;
}
if (typeof destinationOrNext === 'object') {
if (destinationOrNext instanceof Subscriber) {
this.syncErrorThrowable = destinationOrNext.syncErrorThrowable;
this.destination = destinationOrNext;
destinationOrNext.add(this);
}
else {
this.syncErrorThrowable = true;
this.destination = new SafeSubscriber(this, destinationOrNext);
}
break;
}
default:
this.syncErrorThrowable = true;
this.destination = new SafeSubscriber(this, destinationOrNext, error, complete);
break;
}
}
[rxSubscriber]() { return this; }
static create(next, error, complete) {
const subscriber = new Subscriber(next, error, complete);
subscriber.syncErrorThrowable = false;
return subscriber;
}
next(value) {
if (!this.isStopped) {
this._next(value);
}
}
error(err) {
if (!this.isStopped) {
this.isStopped = true;
this._error(err);
}
}
complete() {
if (!this.isStopped) {
this.isStopped = true;
this._complete();
}
}
unsubscribe() {
if (this.closed) {
return;
}
this.isStopped = true;
super.unsubscribe();
}
_next(value) {
this.destination.next(value);
}
_error(err) {
this.destination.error(err);
this.unsubscribe();
}
_complete() {
this.destination.complete();
this.unsubscribe();
}
_unsubscribeAndRecycle() {
const { _parentOrParents } = this;
this._parentOrParents = null;
this.unsubscribe();
this.closed = false;
this.isStopped = false;
this._parentOrParents = _parentOrParents;
return this;
}
}
class SafeSubscriber extends Subscriber {
constructor(_parentSubscriber, observerOrNext, error, complete) {
super();
this._parentSubscriber = _parentSubscriber;
let next;
let context = this;
if (isFunction(observerOrNext)) {
next = observerOrNext;
}
else if (observerOrNext) {
next = observerOrNext.next;
error = observerOrNext.error;
complete = observerOrNext.complete;
if (observerOrNext !== empty) {
context = Object.create(observerOrNext);
if (isFunction(context.unsubscribe)) {
this.add(context.unsubscribe.bind(context));
}
context.unsubscribe = this.unsubscribe.bind(this);
}
}
this._context = context;
this._next = next;
this._error = error;
this._complete = complete;
}
next(value) {
if (!this.isStopped && this._next) {
const { _parentSubscriber } = this;
if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(this._next, value);
}
else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
this.unsubscribe();
}
}
}
error(err) {
if (!this.isStopped) {
const { _parentSubscriber } = this;
const { useDeprecatedSynchronousErrorHandling } = config;
if (this._error) {
if (!useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(this._error, err);
this.unsubscribe();
}
else {
this.__tryOrSetError(_parentSubscriber, this._error, err);
this.unsubscribe();
}
}
else if (!_parentSubscriber.syncErrorThrowable) {
this.unsubscribe();
if (useDeprecatedSynchronousErrorHandling) {
throw err;
}
hostReportError(err);
}
else {
if (useDeprecatedSynchronousErrorHandling) {
_parentSubscriber.syncErrorValue = err;
_parentSubscriber.syncErrorThrown = true;
}
else {
hostReportError(err);
}
this.unsubscribe();
}
}
}
complete() {
if (!this.isStopped) {
const { _parentSubscriber } = this;
if (this._complete) {
const wrappedComplete = () => this._complete.call(this._context);
if (!config.useDeprecatedSynchronousErrorHandling || !_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(wrappedComplete);
this.unsubscribe();
}
else {
this.__tryOrSetError(_parentSubscriber, wrappedComplete);
this.unsubscribe();
}
}
else {
this.unsubscribe();
}
}
}
__tryOrUnsub(fn, value) {
try {
fn.call(this._context, value);
}
catch (err) {
this.unsubscribe();
if (config.useDeprecatedSynchronousErrorHandling) {
throw err;
}
else {
hostReportError(err);
}
}
}
__tryOrSetError(parent, fn, value) {
if (!config.useDeprecatedSynchronousErrorHandling) {
throw new Error('bad call');
}
try {
fn.call(this._context, value);
}
catch (err) {
if (config.useDeprecatedSynchronousErrorHandling) {
parent.syncErrorValue = err;
parent.syncErrorThrown = true;
return true;
}
else {
hostReportError(err);
return true;
}
}
return false;
}
_unsubscribe() {
const { _parentSubscriber } = this;
this._context = null;
this._parentSubscriber = null;
_parentSubscriber.unsubscribe();
}
}
function canReportError(observer) {
while (observer) {
const { closed, destination, isStopped } = observer;
if (closed || isStopped) {
return false;
}
else if (destination && destination instanceof Subscriber) {
observer = destination;
}
else {
observer = null;
}
}
return true;
}
function toSubscriber(nextOrObserver, error, complete) {
if (nextOrObserver) {
if (nextOrObserver instanceof Subscriber) {
return nextOrObserver;
}
if (nextOrObserver[rxSubscriber]) {
return nextOrObserver[rxSubscriber]();
}
}
if (!nextOrObserver && !error && !complete) {
return new Subscriber(empty);
}
return new Subscriber(nextOrObserver, error, complete);
}
const observable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
function identity(x) {
return x;
}
function pipeFromArray(fns) {
if (fns.length === 0) {
return identity;
}
if (fns.length === 1) {
return fns[0];
}
return function piped(input) {
return fns.reduce((prev, fn) => fn(prev), input);
};
}
class Observable {
constructor(subscribe) {
this._isScalar = false;
if (subscribe) {
this._subscribe = subscribe;
}
}
lift(operator) {
const observable = new Observable();
observable.source = this;
observable.operator = operator;
return observable;
}
subscribe(observerOrNext, error, complete) {
const { operator } = this;
const sink = toSubscriber(observerOrNext, error, complete);
if (operator) {
sink.add(operator.call(sink, this.source));
}
else {
sink.add(this.source || (config.useDeprecatedSynchronousErrorHandling && !sink.syncErrorThrowable) ?
this._subscribe(sink) :
this._trySubscribe(sink));
}
if (config.useDeprecatedSynchronousErrorHandling) {
if (sink.syncErrorThrowable) {
sink.syncErrorThrowable = false;
if (sink.syncErrorThrown) {
throw sink.syncErrorValue;
}
}
}
return sink;
}
_trySubscribe(sink) {
try {
return this._subscribe(sink);
}
catch (err) {
if (config.useDeprecatedSynchronousErrorHandling) {
sink.syncErrorThrown = true;
sink.syncErrorValue = err;
}
if (canReportError(sink)) {
sink.error(err);
}
else {
console.warn(err);
}
}
}
forEach(next, promiseCtor) {
promiseCtor = getPromiseCtor(promiseCtor);
return new promiseCtor((resolve, reject) => {
let subscription;
subscription = this.subscribe((value) => {
try {
next(value);
}
catch (err) {
reject(err);
if (subscription) {
subscription.unsubscribe();
}
}
}, reject, resolve);
});
}
_subscribe(subscriber) {
const { source } = this;
return source && source.subscribe(subscriber);
}
[observable]() {
return this;
}
pipe(...operations) {
if (operations.length === 0) {
return this;
}
return pipeFromArray(operations)(this);
}
toPromise(promiseCtor) {
promiseCtor = getPromiseCtor(promiseCtor);
return new promiseCtor((resolve, reject) => {
let value;
this.subscribe((x) => value = x, (err) => reject(err), () => resolve(value));
});
}
}
Observable.create = (subscribe) => {
return new Observable(subscribe);
};
function getPromiseCtor(promiseCtor) {
if (!promiseCtor) {
promiseCtor = config.Promise || Promise;
}
if (!promiseCtor) {
throw new Error('no Promise impl found');
}
return promiseCtor;
}
const ObjectUnsubscribedErrorImpl = (() => {
function ObjectUnsubscribedErrorImpl() {
Error.call(this);
this.message = 'object unsubscribed';
this.name = 'ObjectUnsubscribedError';
return this;
}
ObjectUnsubscribedErrorImpl.prototype = Object.create(Error.prototype);
return ObjectUnsubscribedErrorImpl;
})();
const ObjectUnsubscribedError = ObjectUnsubscribedErrorImpl;
class SubjectSubscription extends Subscription {
constructor(subject, subscriber) {
super();
this.subject = subject;
this.subscriber = subscriber;
this.closed = false;
}
unsubscribe() {
if (this.closed) {
return;
}
this.closed = true;
const subject = this.subject;
const observers = subject.observers;
this.subject = null;
if (!observers || observers.length === 0 || subject.isStopped || subject.closed) {
return;
}
const subscriberIndex = observers.indexOf(this.subscriber);
if (subscriberIndex !== -1) {
observers.splice(subscriberIndex, 1);
}
}
}
class SubjectSubscriber extends Subscriber {
constructor(destination) {
super(destination);
this.destination = destination;
}
}
class Subject extends Observable {
constructor() {
super();
this.observers = [];
this.closed = false;
this.isStopped = false;
this.hasError = false;
this.thrownError = null;
}
[rxSubscriber]() {
return new SubjectSubscriber(this);
}
lift(operator) {
const subject = new AnonymousSubject(this, this);
subject.operator = operator;
return subject;
}
next(value) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
if (!this.isStopped) {
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].next(value);
}
}
}
error(err) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
this.hasError = true;
this.thrownError = err;
this.isStopped = true;
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].error(err);
}
this.observers.length = 0;
}
complete() {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
this.isStopped = true;
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].complete();
}
this.observers.length = 0;
}
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null;
}
_trySubscribe(subscriber) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
else {
return super._trySubscribe(subscriber);
}
}
_subscribe(subscriber) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
else if (this.hasError) {
subscriber.error(this.thrownError);
return Subscription.EMPTY;
}
else if (this.isStopped) {
subscriber.complete();
return Subscription.EMPTY;
}
else {
this.observers.push(subscriber);
return new SubjectSubscription(this, subscriber);
}
}
asObservable() {
const observable = new Observable();
observable.source = this;
return observable;
}
}
Subject.create = (destination, source) => {
return new AnonymousSubject(destination, source);
};
class AnonymousSubject extends Subject {
constructor(destination, source) {
super();
this.destination = destination;
this.source = source;
}
next(value) {
const { destination } = this;
if (destination && destination.next) {
destination.next(value);
}
}
error(err) {
const { destination } = this;
if (destination && destination.error) {
this.destination.error(err);
}
}
complete() {
const { destination } = this;
if (destination && destination.complete) {
this.destination.complete();
}
}
_subscribe(subscriber) {
const { source } = this;
if (source) {
return this.source.subscribe(subscriber);
}
else {
return Subscription.EMPTY;
}
}
}
const subscribeToArray = (array) => (subscriber) => {
for (let i = 0, len = array.length; i < len && !subscriber.closed; i++) {
subscriber.next(array[i]);
}
subscriber.complete();
};
function scheduleArray(input, scheduler) {
return new Observable(subscriber => {
const sub = new Subscription();
let i = 0;
sub.add(scheduler.schedule(function () {
if (i === input.length) {
subscriber.complete();
return;
}
subscriber.next(input[i++]);
if (!subscriber.closed) {
sub.add(this.schedule());
}
}));
return sub;
});
}
function map(project, thisArg) {
return function mapOperation(source) {
if (typeof project !== 'function') {
throw new TypeError('argument is not a function. Are you looking for `mapTo()`?');
}
return source.lift(new MapOperator(project, thisArg));
};
}
class MapOperator {
constructor(project, thisArg) {
this.project = project;
this.thisArg = thisArg;
}
call(subscriber, source) {
return source.subscribe(new MapSubscriber(subscriber, this.project, this.thisArg));
}
}
class MapSubscriber extends Subscriber {
constructor(destination, project, thisArg) {
super(destination);
this.project = project;
this.count = 0;
this.thisArg = thisArg || this;
}
_next(value) {
let result;
try {
result = this.project.call(this.thisArg, value, this.count++);
}
catch (err) {
this.destination.error(err);
return;
}
this.destination.next(result);
}
}
const subscribeToPromise = (promise) => (subscriber) => {
promise.then((value) => {
if (!subscriber.closed) {
subscriber.next(value);
subscriber.complete();
}
}, (err) => subscriber.error(err))
.then(null, hostReportError);
return subscriber;
};
function getSymbolIterator() {
if (typeof Symbol !== 'function' || !Symbol.iterator) {
return '@@iterator';
}
return Symbol.iterator;
}
const iterator = getSymbolIterator();
const subscribeToIterable = (iterable) => (subscriber) => {
const iterator$1 = iterable[iterator]();
do {
let item;
try {
item = iterator$1.next();
}
catch (err) {
subscriber.error(err);
return subscriber;
}
if (item.done) {
subscriber.complete();
break;
}
subscriber.next(item.value);
if (subscriber.closed) {
break;
}
} while (true);
if (typeof iterator$1.return === 'function') {
subscriber.add(() => {
if (iterator$1.return) {
iterator$1.return();
}
});
}
return subscriber;
};
const subscribeToObservable = (obj) => (subscriber) => {
const obs = obj[observable]();
if (typeof obs.subscribe !== 'function') {
throw new TypeError('Provided object does not correctly implement Symbol.observable');
}
else {
return obs.subscribe(subscriber);
}
};
const isArrayLike = ((x) => x && typeof x.length === 'number' && typeof x !== 'function');
function isPromise(value) {
return !!value && typeof value.subscribe !== 'function' && typeof value.then === 'function';
}
const subscribeTo = (result) => {
if (!!result && typeof result[observable] === 'function') {
return subscribeToObservable(result);
}
else if (isArrayLike(result)) {
return subscribeToArray(result);
}
else if (isPromise(result)) {
return subscribeToPromise(result);
}
else if (!!result && typeof result[iterator] === 'function') {
return subscribeToIterable(result);
}
else {
const value = isObject(result) ? 'an invalid object' : `'${result}'`;
const msg = `You provided ${value} where a stream was expected.`
+ ' You can provide an Observable, Promise, Array, or Iterable.';
throw new TypeError(msg);
}
};
function scheduleObservable(input, scheduler) {
return new Observable(subscriber => {
const sub = new Subscription();
sub.add(scheduler.schedule(() => {
const observable$1 = input[observable]();
sub.add(observable$1.subscribe({
next(value) { sub.add(scheduler.schedule(() => subscriber.next(value))); },
error(err) { sub.add(scheduler.schedule(() => subscriber.error(err))); },
complete() { sub.add(scheduler.schedule(() => subscriber.complete())); },
}));
}));
return sub;
});
}
function schedulePromise(input, scheduler) {
return new Observable(subscriber => {
const sub = new Subscription();
sub.add(scheduler.schedule(() => input.then(value => {
sub.add(scheduler.schedule(() => {
subscriber.next(value);
sub.add(scheduler.schedule(() => subscriber.complete()));
}));
}, err => {
sub.add(scheduler.schedule(() => subscriber.error(err)));
})));
return sub;
});
}
function scheduleIterable(input, scheduler) {
if (!input) {
throw new Error('Iterable cannot be null');
}
return new Observable(subscriber => {
const sub = new Subscription();
let iterator$1;
sub.add(() => {
if (iterator$1 && typeof iterator$1.return === 'function') {
iterator$1.return();
}
});
sub.add(scheduler.schedule(() => {
iterator$1 = input[iterator]();
sub.add(scheduler.schedule(function () {
if (subscriber.closed) {
return;
}
let value;
let done;
try {
const result = iterator$1.next();
value = result.value;
done = result.done;
}
catch (err) {
subscriber.error(err);
return;
}
if (done) {
subscriber.complete();
}
else {
subscriber.next(value);
this.schedule();
}
}));
}));
return sub;
});
}
function isInteropObservable(input) {
return input && typeof input[observable] === 'function';
}
function isIterable(input) {
return input && typeof input[iterator] === 'function';
}
function scheduled(input, scheduler) {
if (input != null) {
if (isInteropObservable(input)) {
return scheduleObservable(input, scheduler);
}
else if (isPromise(input)) {
return schedulePromise(input, scheduler);
}
else if (isArrayLike(input)) {
return scheduleArray(input, scheduler);
}
else if (isIterable(input) || typeof input === 'string') {
return scheduleIterable(input, scheduler);
}
}
throw new TypeError((input !== null && typeof input || input) + ' is not observable');
}
function from(input, scheduler) {
if (!scheduler) {
if (input instanceof Observable) {
return input;
}
return new Observable(subscribeTo(input));
}
else {
return scheduled(input, scheduler);
}
}
function forkJoin(...sources) {
if (sources.length === 1) {
const first = sources[0];
if (isArray(first)) {
return forkJoinInternal(first, null);
}
if (isObject(first) && Object.getPrototypeOf(first) === Object.prototype) {
const keys = Object.keys(first);
return forkJoinInternal(keys.map(key => first[key]), keys);
}
}
if (typeof sources[sources.length - 1] === 'function') {
const resultSelector = sources.pop();
sources = (sources.length === 1 && isArray(sources[0])) ? sources[0] : sources;
return forkJoinInternal(sources, null).pipe(map((args) => resultSelector(...args)));
}
return forkJoinInternal(sources, null);
}
function forkJoinInternal(sources, keys) {
return new Observable(subscriber => {
const len = sources.length;
if (len === 0) {
subscriber.complete();
return;
}
const values = new Array(len);
let completed = 0;
let emitted = 0;
for (let i = 0; i < len; i++) {
const source = from(sources[i]);
let hasValue = false;
subscriber.add(source.subscribe({
next: value => {
if (!hasValue) {
hasValue = true;
emitted++;
}
values[i] = value;
},
error: err => subscriber.error(err),
complete: () => {
completed++;
if (completed === len || !hasValue) {
if (emitted === len) {
subscriber.next(keys ?
keys.reduce((result, key, i) => (result[key] = values[i], result), {}) :
values);
}
subscriber.complete();
}
}
}));
}
});
}
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
function isEmptyInputValue(value) {
// we don't check for string here so it also works with arrays
return value == null || value.length === 0;
}
function hasValidLength(value) {
// non-strict comparison is intentional, to check for both `null` and `undefined` values
return value != null && typeof value.length === 'number';
}
// eslint-disable-next-line max-len
const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
function isPresent(o) {
return o != null;
}
function mergeErrors(arrayOfErrors) {
let res = {};
// Not using Array.reduce here due to a Chrome 80 bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
arrayOfErrors.forEach((errors) => {
res = errors != null ? Object.assign(Object.assign({}, res), errors) : res;
});
return Object.keys(res).length === 0 ? null : res;
}
function executeValidators(control, validators) {
return validators.map(validator => validator(control));
}
function isValidatorFn(validator) {
return !validator || !validator.validate;
}
function toObservable(r) {
const obs = r instanceof Promise ? from(r) : r;
if (!(obs instanceof Observable)) {
throw new Error('Expected validator to return Promise or Observable.');
}
return obs;
}
/**
* @description
* Provides a set of built-in validators that can be used by form controls.
*
* A validator is a function that processes a `FormControl` or collection of
* controls and returns an error map or null. A null map means that validation has passed.
*
* @see [Form Validation](/guide/form-validation)
*
* @publicApi
*/
class Validators {
/**
* @description
* Validator that requires the control's value to be greater than or equal to the provided number.
* The validator exists only as a function and not as a directive.
*
* @usageNotes
*
* ### Validate against a minimum of 3
*
* ```typescript
* const control = new FormControl(2, Validators.min(3));
*
* console.log(control.errors); // {min: {min: 3, actual: 2}}
* ```
*
* @returns A validator function that returns an error map with the
* `min` property if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static min(min) {
return (control) => {
if (isEmptyInputValue(control.value) || isEmptyInputValue(min)) {
return null; // don't validate empty values to allow optional controls
}
const value = parseFloat(control.value);
// Controls with NaN values after parsing should be treated as not having a
// minimum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-min
// tslint:disable-next-line: object-literal-key-quotes
return !Number.isNaN(value) && value < min ? { min: { min, actual: control.value } } : null;
};
}
/**
* @description
* Validator that requires the control's value to be less than or equal to the provided number.
* The validator exists only as a function and not as a directive.
*
* @usageNotes
*
* ### Validate against a maximum of 15
*
* ```typescript
* const control = new FormControl(16, Validators.max(15));
*
* console.log(control.errors); // {max: {max: 15, actual: 16}}
* ```
*
* @returns A validator function that returns an error map with the
* `max` property if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static max(max) {
return (control) => {
if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
return null; // don't validate empty values to allow optional controls
}
const value = parseFloat(control.value);
// Controls with NaN values after parsing should be treated as not having a
// maximum, per the HTML forms spec: https://www.w3.org/TR/html5/forms.html#attr-input-max
// tslint:disable-next-line: object-literal-key-quotes
return !Number.isNaN(value) && value > max ? { max: { max, actual: control.value } } : null;
};
}
/**
* @description
* Validator that requires the control have a non-empty value.
*
* @usageNotes
*
* ### Validate that the field is non-empty
*
* ```typescript
* const control = new FormControl('', Validators.required);
*
* console.log(control.errors); // {required: true}
* ```
*
* @returns An error map with the `required` property
* if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static required(control) {
// tslint:disable-next-line: object-literal-key-quotes
return isEmptyInputValue(control.value) ? { required: true } : null;
}
/**
* @description
* Validator that requires the control's value be true. This validator is commonly
* used for required checkboxes.
*F
* @usageNotes
*
* ### Validate that the field value is true
*
* ```typescript
* const control = new FormControl('', Validators.requiredTrue);
*
* console.log(control.errors); // {required: true}
* ```
*
* @returns An error map that contains the `required` property
* set to `true` if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static requiredTrue(control) {
// tslint:disable-next-line: object-literal-key-quotes
return control.value === true ? null : { required: true };
}
/**
* @description
* Validator that requires the control's value pass an email validation test.
*
* Tests the value using a [regular
* expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
* pattern suitable for common usecases. The pattern is based on the definition of a valid email
* address in the [WHATWG HTML
* specification](https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address) with
* some enhancements to incorporate more RFC rules (such as rules related to domain names and the
* lengths of different parts of the address).
*
* The differences from the WHATWG version include:
* - Disallow `local-part` (the part before the `@` symbol) to begin or end with a period (`.`).
* - Disallow `local-part` to be longer than 64 characters.
* - Disallow the whole address to be longer than 254 characters.
*
* If this pattern does not satisfy your business needs, you can use `Validators.pattern()` to
* validate the value against a different pattern.
*
* @usageNotes
*
* ### Validate that the field matches a valid email pattern
*
* ```typescript
* const control = new FormControl('bad@', Validators.email);
*
* console.log(control.errors); // {email: true}
* ```
*
* @returns An error map with the `email` property
* if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static email(control) {
if (isEmptyInputValue(control.value)) {
return null; // don't validate empty values to allow optional controls
}
// tslint:disable-next-line: object-literal-key-quotes
EMAIL_REGEXP.lastIndex = 0;
return EMAIL_REGEXP.test(control.value) ? null : { email: true };
}
/**
* @description
* Validator that requires the length of the control's value to be greater than or equal
* to the provided minimum length. This validator is also provided by default if you use the
* the HTML5 `minlength` attribute. Note that the `minLength` validator is intended to be used
* only for types that have a numeric `length` property, such as strings or arrays. The
* `minLength` validator logic is also not invoked for values when their `length` property is 0
* (for example in case of an empty string or an empty array), to support optional controls. You
* can use the standard `required` validator if empty values should not be considered valid.
*
* @usageNotes
*
* ### Validate that the field has a minimum of 3 characters
*
* ```typescript
* const control = new FormControl('ng', Validators.minLength(3));
*
* console.log(control.errors); // {minlength: {requiredLength: 3, actualLength: 2}}
* ```
*
* ```html
* <input minlength="5">
* ```
*
* @returns A validator function that returns an error map with the
* `minlength` if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static minLength(minLength) {
return (control) => {
if (isEmptyInputValue(control.value) || !hasValidLength(control.value)) {
// don't validate empty values to allow optional controls
// don't validate values without `length` property
return null;
}
return control.value.length < minLength
// tslint:disable-next-line: object-literal-key-quotes
? { minlength: { requiredLength: minLength, actualLength: control.value.length } }
: null;
};
}
/**
* @description
* Validator that requires the length of the control's value to be less than or equal
* to the provided maximum length. This validator is also provided by default if you use the
* the HTML5 `maxlength` attribute. Note that the `maxLength` validator is intended to be used
* only for types that have a numeric `length` property, such as strings or arrays.
*
* @usageNotes
*
* ### Validate that the field has maximum of 5 characters
*
* ```typescript
* const control = new FormControl('Angular', Validators.maxLength(5));
*
* console.log(control.errors); // {maxlength: {requiredLength: 5, actualLength: 7}}
* ```
*
* ```html
* <input maxlength="5">
* ```
*
* @returns A validator function that returns an error map with the
* `maxlength` property if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static maxLength(maxLength) {
return (control) => (hasValidLength(control.value) && control.value.length > maxLength
// tslint:disable-next-line: object-literal-key-quotes
? { maxlength: { requiredLength: maxLength, actualLength: control.value.length } }
: null);
}
/**
* @description
* Validator that requires the control's value to match a regex pattern. This validator is also
* provided by default if you use the HTML5 `pattern` attribute.
*
* @usageNotes
*
* ### Validate that the field only contains letters or spaces
*
* ```typescript
* const control = new FormControl('1', Validators.pattern('[a-zA-Z ]*'));
*
* console.log(control.errors); // {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'}}
* ```
*
* ```html
* <input pattern="[a-zA-Z ]*">
* ```
*
* @param pattern A regular expression to be used as is to test the values, or a string.
* If a string is passed, the `^` character is prepended and the `$` character is
* appended to the provided string (if not already present), and the resulting regular
* expression is used to test the values.
*
* @returns A validator function that returns an error map with the
* `pattern` property if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static pattern(pattern) {
if (!pattern) {
return Validators.nullValidator;
}
let regex;
let regexStr;
if (typeof pattern === 'string') {
regexStr = '';
if (pattern.charAt(0) !== '^')
regexStr += '^';
regexStr += pattern;
if (pattern.charAt(pattern.length - 1) !== '$')
regexStr += '$';
regex = new RegExp(regexStr);
}
else {
regexStr = pattern.toString();
regex = pattern;
}
return (control) => {
if (isEmptyInputValue(control.value)) {
return null; // don't validate empty values to allow optional controls
}
const { value } = control;
regex.lastIndex = 0; // Reset regex!!
return regex.test(value) ? null
: { pattern: { requiredPattern: regexStr, actualValue: value } };
};
}
/**
* @description
* Validator that performs no operation.
*
* @see `updateValueAndValidity()`
*
*/
static nullValidator(_control) {
return null;
}
static compose(validators) {
if (!validators)
return null;
const presentValidators = validators.filter(isPresent);
if (presentValidators.length === 0)
return null;
return function (control) {
return mergeErrors(executeValidators(control, presentValidators));
};
}
/**
* @description
* Compose multiple async validators into a single function that returns the union
* of the individual error objects for the provided control.
*
* @returns A validator function that returns an error map with the
* merged error objects of the async validators if the validation check fails, otherwise `null`.
*
* @see `updateValueAndValidity()`
*
*/
static composeAsync(validators) {
if (!validators)
return null;
const presentValidators = validators.filter(isPresent);
if (presentValidators.length === 0)
return null;
return (control) => {
const observables = executeValidators(control, presentValidators).map(toObservable);
return forkJoin(observables).pipe(map(mergeErrors));
};
}
}
/**
* Given a validator that may be a function or a class, return the
* validator function (convert validator classes into validator functions).
*
* @param validators The validator that may be a plain function
* as well as represented as a validator class.
*/
function normalizeValidator(validator) {
return isValidatorFn(validator)
? validator
: ((c) => validator.validate(c));
}
/**
* Given the list of validators that may contain both functions as well as classes, return the list
* of validator functions (convert validator classes into validator functions). This is needed to
* have consistent structure in validators list before composing them.
*
* @param validators The set of validators that may contain validators both in plain function form
* as well as represented as a validator class.
*/
function normalizeValidators(validators) {
return validators.map(validator => normalizeValidator(validator));
}
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// tslint:disable-next-line: prefer-array-literal
function composeValidators(validators) {
return validators != null ? Validators.compose(normalizeValidators(validators))
: null;
}
// tslint:disable-next-line: prefer-array-literal
function composeAsyncValidators(validators) {
return validators != null
? Validators.composeAsync(normalizeValidators(validators))
: null;
}
var ReactiveFormStatus;
(function (ReactiveFormStatus) {
/**
* Reports that a FormControl is valid, meaning that no errors exist in the input value.
*
* @see `status`
*/
ReactiveFormStatus["VALID"] = "VALID";
/**
* Reports that a FormControl is invalid, meaning that an error exists in the input value.
*
* @see `status`
*/
ReactiveFormStatus["INVALID"] = "INVALID";
/**
* Reports that a FormControl is pending, meaning that that async validation is occurring and
* errors are not yet available for the input value.
*
* @see `markAsPending`
* @see `status`
*/
ReactiveFormStatus["PENDING"] = "PENDING";
/**
* Reports that a FormControl is disabled, meaning that the control is exempt from ancestor
* calculations of validity or value.
*
* @see `markAsDisabled`
* @see `status`
*/
ReactiveFormStatus["DISABLED"] = "DISABLED";
})(ReactiveFormStatus || (ReactiveFormStatus = {}));
/* eslint-disable @typescript-eslint/no-use-before-define */
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
function _find(control, path, delimiter) {
let mPath = path;
if (mPath == null) {
return null;
}
if (!Array.isArray(mPath)) {
mPath = mPath.split(delimiter);
}
if (Array.isArray(mPath) && mPath.length === 0)
ret