@openxmldev/linq-to-xml
Version:
LINQ to XML for TypeScript
374 lines • 13.8 kB
JavaScript
/**
* @author Thomas Barnekow
* @license MIT
*/
import { defaultIfEmpty, skip, skipLast, skipWhile, take, takeLast, takeWhile, where, } from '@tsdotnet/linq/dist/filters.js';
import { all, any, count, first, firstOrDefault, last, lastOrDefault, single, singleOrDefault, toArray, } from '@tsdotnet/linq/dist/resolutions.js';
import { groupBy, select, selectMany } from '@tsdotnet/linq/dist/transforms.js';
import { filter } from './transformations/index.js';
/**
* Abstract base class for LINQ iterables.
*
* @remarks
* This abstract class serves as the generic base class for all LINQ iterables
* provided by this library. The {@linkcode LinqIterable<T>} class just derives
* from this class and adds no further features. Other classes such as
* {@linkcode LinqElements} inherit from this class and provide further methods.
* The generics-based pattern used in this case means that all filter methods,
* returning a `TLinq`, for example, will return instances of the subclasses.
*
* @typeParam T The type of the elements of the sequence.
* @typeParam TLinq The type of the LINQ iterable returned by filters.
*/
export class LinqIterableBase {
/**
* Initializes a new instance with the given sequence.
*
* @param source The source sequence.
*/
constructor(source, create) {
this.source = source;
this.create = create;
}
/**
* Returns the sequence of elements represented by this `LinqIterable<T>`.
*
* @returns The sequence of elements represented by this `LinqIterable<T>`.
*/
[Symbol.iterator]() {
return this.source[Symbol.iterator]();
}
/**
* Filters this sequence, using zero or more filters.
*
* @param filters The filters to use.
* @returns A filtered sequence.
*/
filter(...filters) {
return filters.length
? this.applyFilters(filters)
: this;
}
/**
* Filters this sequence, using the given filters.
*
* @param filters The filters to use.
* @returns A filtered sequence.
*/
applyFilters(filters) {
return this.create(filter(this.source, filters));
}
/**
* Transforms this sequence, using the given transformation.
*
* @transform TResult The type of the elements of the transformed sequence.
* @param transformation The transformation to use.
* @returns A transformed sequence.
*/
transform(transformation) {
return linqIterable(transformation(this.source));
}
/**
* Applies the given resolution to this sequence.
*
* @typeParam TResult The type of the result of the resolution.
* @param resolution The resolution to use.
* @returns The resolved value.
*/
resolve(resolution) {
return resolution(this.source);
}
//
// Filters
//
/**
* Returns the elements of the specified sequence or the default value if the
* sequence is empty.
*
* @param defaultValue The default value to be returned if this sequence is empty.
* @returns The elements of the specified sequence or the default value if the sequence is empty.
*/
defaultIfEmpty(defaultValue) {
return this.create(defaultIfEmpty(defaultValue)(this.source));
}
/**
* Returns a new sequence that contains the elements from this sequence with
* the first `count` elements omitted.
*
* @param count The number of elements to be omitted.
* @returns A new sequence that contains the elements from this sequence with
* the first `count` elements omitted.
*/
skip(count) {
return this.create(skip(count)(this.source));
}
/**
* Returns a new sequence that contains the elements from this sequence with
* the last `count` elements omitted.
*
* @param count The number of elements to be omitted.
* @returns A new sequence that contains the elements from this sequence with
* the first `count` elements omitted.
*/
skipLast(count) {
return this.create(skipLast(count)(this.source));
}
/**
* Bypasses elements in a sequence as long as a specified condition is true
* and then returns the remaining elements.
*
* @param predicate The specified condition.
* @returns A new sequence with the remaining elements.
*/
skipWhile(predicate) {
return this.create(skipWhile(predicate)(this.source));
}
/**
* Returns a new sequence that contains the specified number of contiguous
* elements from the start of this sequence.
*
* @param count The number of elements to take.
* @returns a new sequence that contains the specified number of contiguous
* elements from the start of this sequence.
*/
take(count) {
return this.create(take(count)(this.source));
}
/**
* Returns a new sequence that contains the specified number of contiguous
* elements from the end of this sequence.
*
* @param count The number of elements to take.
* @returns A new sequence that contains the specified number of contiguous
* elements from the end of this sequence.
*/
takeLast(count) {
return this.create(takeLast(count)(this.source));
}
/**
* Returns a new sequence that contains elements from this sequence that occur
* before the element at which the specified condition is false.
*
* @param predicate The specified condition.
* @returns A new sequence that contains elements from this sequence that occur
* before the element at which the specified condition is false.
*/
takeWhile(predicate) {
return this.create(takeWhile(predicate)(this.source));
}
/**
* Filters the sequence using the given predicate.
*
* @param predicate The predicate.
* @returns The filtered sequence.
*/
where(predicate) {
return this.create(where(predicate)(this.source));
}
//
// Resolutions
//
/**
* Returns true if the predicate is true for every element in the sequence or
* if the sequence is empty.
*
* @param predicate The predicate.
*/
all(predicate) {
return all(predicate)(this.source);
}
/**
* If a predicate is provided, returns true if the predicate is true for any
* element in the sequence.
* If no predicate is provided, returns true if the sequence has any entries.
*
* @param predicate The optional predicate.
*/
any(predicate) {
return any(predicate)(this.source);
}
/**
* Returns the number of elements in the sequence.
* If a predicate is provided, filters the sequence based on the predicate.
*
* @param predicate The optional predicate.
* @returns The number of elements in the sequence.
*/
count(predicate) {
return predicate
? count(where(predicate)(this.source))
: count(this.source);
}
/**
* Returns the first element of this sequence.
* If a predicate is provided, filters the sequence based on the predicate.
*
* @param predicate The optional predicate.
* @returns The first element.
* @throws If the (optionally filtered) sequence is empty.
* @see {@linkcode last} and {@linkcode single}
*/
first(predicate) {
return first(this.filterSequence(predicate));
}
firstOrDefault(predicateOrDefault, defaultValue) {
if (predicateOrDefault === undefined && defaultValue === undefined) {
// firstOrDefault(): T | undefined;
return firstOrDefault()(this.source);
}
else if (predicateOrDefault !== undefined && defaultValue === undefined) {
if (typeof predicateOrDefault === 'function') {
// firstOrDefault(predicate: PredicateWithIndex<T>): T | undefined;
return firstOrDefault()(this.filterSequence(predicateOrDefault));
}
else {
// firstOrDefault(defaultValue: T): T;
return firstOrDefault(predicateOrDefault)(this.source);
}
}
else {
// firstOrDefault(predicate: PredicateWithIndex<T>, defaultValue: T): T;
return firstOrDefault(defaultValue)(this.filterSequence(predicateOrDefault));
}
}
/**
* Returns the last element of the sequence.
* If a predicate is provided, filters the sequence based on the predicate.
*
* @param predicate The optional predicate.
* @returns The last element.
* @throws If the (optionally filtered) sequence is empty.
* @see {@linkcode first} and {@linkcode single}
*/
last(predicate) {
return last(this.filterSequence(predicate));
}
lastOrDefault(predicateOrDefault, defaultValue) {
if (predicateOrDefault === undefined && defaultValue === undefined) {
// lastOrDefault(): T | undefined;
return lastOrDefault()(this.source);
}
else if (predicateOrDefault !== undefined && defaultValue === undefined) {
if (typeof predicateOrDefault === 'function') {
// lastOrDefault(predicate: PredicateWithIndex<T>): T | undefined;
return lastOrDefault()(this.filterSequence(predicateOrDefault));
}
else {
// lastOrDefault(defaultValue: T): T;
return lastOrDefault(predicateOrDefault)(this.source);
}
}
else {
// lastOrDefault(predicate: PredicateWithIndex<T>, defaultValue: T): T;
return lastOrDefault(defaultValue)(this.filterSequence(predicateOrDefault));
}
}
/**
* Returns the single element of the sequence.
* If a predicate is provided, filters the sequence based on the predicate.
*
* @param predicate The optional predicate.
* @returns The single element.
* @throws If the (optionally filtered) sequence does not contain exactly one element.
* @see {@linkcode first} and {@linkcode last}
*/
single(predicate) {
return single(this.filterSequence(predicate));
}
singleOrDefault(predicateOrDefault, defaultValue) {
if (predicateOrDefault === undefined && defaultValue === undefined) {
// singleOrDefault(): T | undefined;
return singleOrDefault()(this.source);
}
else if (predicateOrDefault !== undefined && defaultValue === undefined) {
if (typeof predicateOrDefault === 'function') {
// singleOrDefault(predicate: PredicateWithIndex<T>): T | undefined;
return singleOrDefault()(this.filterSequence(predicateOrDefault));
}
else {
// singleOrDefault(defaultValue: T): T;
return singleOrDefault(predicateOrDefault)(this.source);
}
}
else {
// singleOrDefault(predicate: PredicateWithIndex<T>, defaultValue: T): T;
return singleOrDefault(defaultValue)(this.filterSequence(predicateOrDefault));
}
}
/**
* Returns all the elements in the sequence as an array.
*/
toArray() {
return toArray(this.source);
}
/** @internal */
filterSequence(predicate) {
return predicate ? where(predicate)(this.source) : this.source;
}
//
// Transformations
//
/**
* Groups elements by selected key.
*
* @typeParam TKey The type of the grouping keys.
* @param keySelector Selects the grouping keys.
* @returns The grouped elements.
*/
groupBy(keySelector) {
return this.transform(groupBy(keySelector)).select((g) => new LinqIterableGrouping(g));
}
/**
* Projects, or maps, each element of a sequence into a new form.
*
* @typeParam TResult The type of the elements of the projected, or mapped, sequence.
* @param selector The selector used to project, or map, the elements.
* @returns The projected, or mapped, sequence.
*/
select(selector) {
return linqIterable(select(selector)(this.source));
}
/**
* Merges the selected sequences into one flat sequence.
*
* @typeParam TResult The type of the elements of the flat sequence.
* @param selector The selector.
* @returns The merged, flat sequence.
*/
selectMany(selector) {
return linqIterable(selectMany(selector)(this.source));
}
}
/**
* A LINQ iterable.
*
* @typeParam T The type of the elements of the sequence.
*/
export class LinqIterable extends LinqIterableBase {
constructor(source) {
super(source, linqIterable);
}
}
/**
* Represents a grouping of sequence elements.
*
* @typeParam TKey The type of the grouping keys.
* @typeParam T The type of the grouped elements.
*/
export class LinqIterableGrouping extends LinqIterable {
constructor(grouping) {
super(grouping.elements);
this.key = grouping.key;
}
}
/**
* Converts any `Iterable<T>` into a LINQ-style iterable.
*
* @typeParam T The type of the elements of the `LinqIterable<T>`.
* @param source The source `Iterable<T>`.
* @returns A `LinqIterable<T>` instance.
*/
export function linqIterable(source) {
return source instanceof LinqIterable ? source : new LinqIterable(source);
}
//# sourceMappingURL=LinqIterable.js.map