This commit is contained in:
Garrett Serack 2019-09-07 19:40:26 -07:00
Родитель 7b0398e17a
Коммит cb7d1a45a9
12 изменённых файлов: 444 добавлений и 34 удалений

Просмотреть файл

@ -178,7 +178,7 @@ export function pall<T, U>(array: Array<T>, callbackfn: (value: T, index: number
export function deconstruct(identifier: string | Array<string>): Array<string> { export function deconstruct(identifier: string | Array<string>): Array<string> {
if (Array.isArray(identifier)) { if (Array.isArray(identifier)) {
return [...values(identifier).linq.selectMany(deconstruct)]; return [...values(identifier).selectMany(deconstruct)];
} }
return identifier. return identifier.
replace(/([a-z]+)([A-Z])/g, '$1 $2'). replace(/([a-z]+)([A-Z])/g, '$1 $2').

Просмотреть файл

@ -119,11 +119,11 @@ export class Schema extends Extensions implements Schema {
export function getPolymorphicBases(schema: Schema): Array<Schema> { export function getPolymorphicBases(schema: Schema): Array<Schema> {
// are any of my parents polymorphic directly, or any of their parents? // are any of my parents polymorphic directly, or any of their parents?
return [...values(schema.allOf).linq.where(parent => parent.discriminator ? true : false), ...values(schema.allOf).linq.selectMany(getPolymorphicBases)]; return [...values(schema.allOf).where(parent => parent.discriminator ? true : false), ...values(schema.allOf).selectMany(getPolymorphicBases)];
} }
export function getAllProperties(schema: Schema): Array<Property> { export function getAllProperties(schema: Schema): Array<Property> {
return [...values(schema.allOf).linq.selectMany(getAllProperties), ...values(schema.properties)]; return [...values(schema.allOf).selectMany(getAllProperties), ...values(schema.properties)];
} }
export function getAllPublicVirtualProperties(virtualProperties?: VirtualProperties): Array<VirtualProperty> { export function getAllPublicVirtualProperties(virtualProperties?: VirtualProperties): Array<VirtualProperty> {
@ -133,7 +133,7 @@ export function getAllPublicVirtualProperties(virtualProperties?: VirtualPropert
inlined: [] inlined: []
}; };
return [...values([...props.owned, ...props.inherited, ...props.inlined]).linq.where(each => !each.private)]; return [...values([...props.owned, ...props.inherited, ...props.inlined]).where(each => !each.private)];
} }
export function getAllVirtualProperties(virtualProperties?: VirtualProperties): Array<VirtualProperty> { export function getAllVirtualProperties(virtualProperties?: VirtualProperties): Array<VirtualProperty> {
@ -152,7 +152,7 @@ export function getVirtualPropertyFromPropertyName(virtualProperties: VirtualPro
inherited: [], inherited: [],
inlined: [] inlined: []
}; };
return values([...props.owned, ...props.inherited, ...props.inlined]).linq.first(each => each.property.serializedName === propertyName); return values([...props.owned, ...props.inherited, ...props.inlined]).first(each => each.property.serializedName === propertyName);
} }

Просмотреть файл

@ -19,7 +19,7 @@ export class MemoryFileSystem implements IFileSystem {
public constructor(files: Map<string, string>) { public constructor(files: Map<string, string>) {
this.filesByUri = new Map<string, string>( this.filesByUri = new Map<string, string>(
items(files).linq.select( items(files).select(
each => [ each => [
ResolveUri(MemoryFileSystem.DefaultVirtualRootUri, each.key), ResolveUri(MemoryFileSystem.DefaultVirtualRootUri, each.key),
each.value each.value
@ -44,7 +44,7 @@ export class MemoryFileSystem implements IFileSystem {
async EnumerateFileUris(folderUri: string = MemoryFileSystem.DefaultVirtualRootUri): Promise<Array<string>> { async EnumerateFileUris(folderUri: string = MemoryFileSystem.DefaultVirtualRootUri): Promise<Array<string>> {
// return await [...From(this.filesByUri.keys()).Where(uri => { // return await [...From(this.filesByUri.keys()).Where(uri => {
return keys(this.filesByUri).linq.where(uri => { return keys(this.filesByUri).where(uri => {
// in folder? // in folder?
if (!uri.startsWith(folderUri)) { if (!uri.startsWith(folderUri)) {
return false; return false;
@ -53,7 +53,7 @@ export class MemoryFileSystem implements IFileSystem {
// not in subfolder? // not in subfolder?
// return uri.substr(folderUri.length).indexOf("/") === -1; // return uri.substr(folderUri.length).indexOf("/") === -1;
return uri.substr(folderUri.length).indexOf('/') === -1; return uri.substr(folderUri.length).indexOf('/') === -1;
}).linq.toArray(); }).toArray();
//})]; //})];
} }

Просмотреть файл

@ -1,5 +1,5 @@
'use strict'; 'use strict';
import { Dictionary, items, keys, values, any } from '@azure-tools/linq'; import { Dictionary, items } from '@azure-tools/linq';
export type JsonPointer = string; export type JsonPointer = string;
export type JsonPointerTokens = Array<string>; export type JsonPointerTokens = Array<string>;

Просмотреть файл

@ -53,6 +53,6 @@ export class BlameTree {
// recurse // recurse
todos.push(...todo.blaming); todos.push(...todo.blaming);
} }
return values(result).linq.distinct(x => JSON.stringify(x)).linq.toArray(); return values(result).distinct(x => JSON.stringify(x)).toArray();
} }
} }

18
linq/common.ts Normal file
Просмотреть файл

@ -0,0 +1,18 @@
export interface Index<T> {
[key: number]: T;
}
export interface Dictionary<T> {
[key: string]: T;
}
export class Dictionary<T> implements Dictionary<T> {
}
export function ToDictionary<T>(keys: Array<string>, each: (index: string) => T) {
const result = new Dictionary<T>();
keys.map((v, i, a) => result[v] = each(v));
return result;
}
export type IndexOf<T> = T extends Map<T, infer V> ? T : T extends Array<infer V> ? number : string;

9
linq/exports.ts Normal file
Просмотреть файл

@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export * from './new-linq';
export * from './freeze';
export * from './visitor';
export * from './common';

301
linq/new-linq.ts Normal file
Просмотреть файл

@ -0,0 +1,301 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IndexOf, Dictionary } from './common';
/*
* Reverses the elements in an Array.
* reverse(): T[];
*/
export interface IterableWithLinq<T> extends Iterable<T> {
linq: IterableWithLinq<T>;
any(predicate?: (each: T) => boolean): boolean;
all(predicate: (each: T) => boolean): boolean;
bifurcate(predicate: (each: T) => boolean): Array<Array<T>>;
concat(more: Iterable<T>): IterableWithLinq<T>;
distinct(selector?: (each: T) => any): IterableWithLinq<T>;
first(predicate?: (each: T) => boolean): T | undefined;
selectNonNullable<V>(selector: (each: T) => V): IterableWithLinq<NonNullable<V>>;
select<V>(selector: (each: T) => V): IterableWithLinq<V>;
selectMany<V>(selector: (each: T) => Iterable<V>): IterableWithLinq<V>;
where(predicate: (each: T) => boolean): IterableWithLinq<T>;
forEach(action: (each: T) => void): void;
aggregate<A, R>(accumulator: (current: T | A, next: T) => A, seed?: T | A, resultAction?: (result?: T | A) => A | R): T | A | R | undefined;
toArray(): Array<T>;
/**
* Gets or sets the length of the iterable. This is a number one higher than the highest element defined in an array.
*/
count(): number;
/**
* Adds all the elements of an array separated by the specified separator string.
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
*/
join(separator?: string): string;
}
/* eslint-disable */
function linqify<T>(iterable: Iterable<T>): IterableWithLinq<T> {
if ((<any>iterable)['linq'] === iterable) {
return <IterableWithLinq<T>>iterable;
}
const r = <any>{
[Symbol.iterator]: iterable[Symbol.iterator].bind(iterable),
all: <any>all.bind(iterable),
any: <any>any.bind(iterable),
bifurcate: <any>bifurcate.bind(iterable),
concat: <any>concat.bind(iterable),
distinct: <any>distinct.bind(iterable),
first: <any>first.bind(iterable),
select: <any>select.bind(iterable),
selectMany: <any>selectMany.bind(iterable),
selectNonNullable: <any>selectNonNullable.bind(iterable),
toArray: <any>toArray.bind(iterable),
where: <any>where.bind(iterable),
forEach: <any>forEach.bind(iterable),
aggregate: <any>aggregate.bind(iterable),
join: <any>join.bind(iterable),
count: len.bind(iterable)
};
r.linq = r;
return r;
}
function len<T>(this: Iterable<T>): number {
return length(this);
}
/** returns an IterableWithLinq<> for keys in the collection */
export function keys<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)>(source: TSrc & (Array<T> | Dictionary<T> | Map<K, T>) | null | undefined): IterableWithLinq<IndexOf<TSrc>> {
if (source) {
if (Array.isArray(source)) {
return <IterableWithLinq<IndexOf<TSrc>>>linqify((<Array<T>>source).keys());
}
if (source instanceof Map) {
return <IterableWithLinq<IndexOf<TSrc>>><unknown>linqify((<Map<K, T>>source).keys());
}
return <IterableWithLinq<IndexOf<TSrc>>>linqify((Object.getOwnPropertyNames(source)));
}
// undefined/null
return linqify([]);
}
function isIterable<T>(source: any): source is Iterable<T> {
return !!source && !!source[Symbol.iterator];
}
/** returns an IterableWithLinq<> for values in the collection */
export function values<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)>(source: (Iterable<T> | Array<T> | Dictionary<T> | Map<K, T>) | null | undefined): IterableWithLinq<T> {
if (source) {
// map
if (source instanceof Map) {
return linqify(source.values());
}
// any iterable source
if (isIterable(source)) {
return linqify(source);
}
// dictionary (object keys)
return linqify(function* () {
for (const key of keys(source)) {
const value = source[key];
if (typeof value !== 'function') {
yield value;
}
}
}());
}
// null/undefined
return linqify([]);
}
/** returns an IterableWithLinq<{key,value}> for the source */
export function items<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)>(source: TSrc & (Array<T> | Dictionary<T> | Map<K, T>) | null | undefined): IterableWithLinq<{ key: IndexOf<TSrc>; value: T }> {
if (source) {
if (Array.isArray(source)) {
return <IterableWithLinq<{ key: IndexOf<TSrc>; value: T }>>linqify(function* () { for (let i = 0; i < source.length; i++) { yield { key: i, value: source[i] }; } }());
}
if (source instanceof Map) {
return <IterableWithLinq<{ key: IndexOf<TSrc>; value: T }>>linqify(function* () { for (const [key, value] of source.entries()) { yield { key, value }; } }());
}
return <IterableWithLinq<{ key: IndexOf<TSrc>; value: T }>><unknown>linqify(function* () {
for (const key of keys(source)) {
const value = source[<string>key];
if (typeof value !== 'function') {
yield {
key, value: source[<string>key]
};
}
}
}());
}
// undefined/null
return linqify([]);
}
export function length<T, K>(source?: Iterable<T> | Dictionary<T> | Array<T> | Map<K, T>): number {
if (source) {
if (Array.isArray(source)) {
return source.length;
}
if (source instanceof Map) {
return source.size;
}
if (isIterable(source)) {
return [...source].length;
}
return source ? Object.getOwnPropertyNames(source).length : 0;
}
return 0;
}
function any<T>(this: Iterable<T>, predicate?: (each: T) => boolean): boolean {
for (const each of this) {
if (!predicate || predicate(each)) {
return true;
}
}
return false;
}
function all<T>(this: Iterable<T>, predicate: (each: T) => boolean): boolean {
for (const each of this) {
if (!predicate(each)) {
return false;
}
}
return true;
}
function concat<T>(this: Iterable<T>, more: Iterable<T>): IterableWithLinq<T> {
return linqify(function* (this: Iterable<T>) {
for (const each of this) {
yield each;
}
for (const each of more) {
yield each;
}
}.bind(this)());
}
function select<T, V>(this: Iterable<T>, selector: (each: T) => V): IterableWithLinq<V> {
return linqify(function* (this: Iterable<T>) {
for (const each of this) {
yield selector(each);
}
}.bind(this)());
}
function selectMany<T, V>(this: Iterable<T>, selector: (each: T) => Iterable<V>): IterableWithLinq<V> {
return linqify(function* (this: Iterable<T>) {
for (const each of this) {
for (const item of selector(each)) {
yield item;
}
}
}.bind(this)());
}
function where<T>(this: Iterable<T>, predicate: (each: T) => boolean): IterableWithLinq<T> {
return linqify(function* (this: Iterable<T>) {
for (const each of this) {
if (predicate(each)) {
yield each;
}
}
}.bind(this)());
}
function forEach<T>(this: Iterable<T>, action: (each: T) => void) {
for (const each of this) {
action(each);
}
}
function aggregate<T, A, R>(this: Iterable<T>, accumulator: (current: T | A, next: T) => A, seed?: T | A, resultAction?: (result?: T | A) => A | R): T | A | R | undefined {
let result: T | A | undefined = seed;
for (const each of this) {
if (result === undefined) {
result = each;
continue;
}
result = accumulator(result, each);
}
return resultAction !== undefined ? resultAction(result) : result;
}
function selectNonNullable<T, V>(this: Iterable<T>, selector: (each: T) => V): IterableWithLinq<NonNullable<V>> {
return linqify(function* (this: Iterable<T>) {
for (const each of this) {
const value = selector(each);
if (value) {
yield <NonNullable<V>><any>value;
}
}
}.bind(this)());
}
function nonNullable<T>(this: Iterable<T>): IterableWithLinq<NonNullable<T>> {
return linqify(function* (this: Iterable<T>) {
for (const each of this) {
if (each) {
yield <NonNullable<T>><any>each;
}
}
}.bind(this)());
}
function first<T>(this: Iterable<T>, predicate?: (each: T) => boolean): T | undefined {
for (const each of this) {
if (!predicate || predicate(each)) {
return each;
}
}
return undefined;
}
function toArray<T>(this: Iterable<T>): Array<T> {
return [...this];
}
function join<T>(this: Iterable<T>, separator: string): string {
return [...this].join(separator);
}
function bifurcate<T>(this: Iterable<T>, predicate: (each: T) => boolean): Array<Array<T>> {
const result = [new Array<T>(), new Array<T>()];
for (const each of this) {
result[predicate(each) ? 0 : 1].push(each);
}
return result;
}
function distinct<T>(this: Iterable<T>, selector?: (each: T) => any): IterableWithLinq<T> {
const hash = new Dictionary<boolean>();
return linqify(function* (this: Iterable<T>) {
if (!selector) {
selector = i => i;
}
for (const each of this) {
const k = JSON.stringify(selector(each));
if (!hash[k]) {
hash[k] = true;
yield each;
}
}
}.bind(this)());
}

Просмотреть файл

@ -2,28 +2,24 @@
* Copyright (c) Microsoft Corporation. All rights reserved. * Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
export * from './freeze'; import { IndexOf, Dictionary } from './common';
export * from './visitor';
export interface Index<T> { export interface Linqed<T> extends Iterable<T> {
[key: number]: T; any(predicate?: (each: T) => boolean): boolean;
all(predicate: (each: T) => boolean): boolean;
bifurcate(predicate: (each: T) => boolean): Array<Array<T>>;
concat(more: Iterable<T>): Linqable<T>;
distinct(selector?: (each: T) => any): Linqable<T>;
first(predicate?: (each: T) => boolean): T | undefined;
selectNonNullable<V>(selector: (each: T) => V): Linqable<NonNullable<V>>;
select<V>(selector: (each: T) => V): Linqable<V>;
selectMany<V>(selector: (each: T) => Iterable<V>): Linqable<V>;
where(predicate: (each: T) => boolean): Linqable<T>;
forEach(action: (each: T) => void): void;
aggregate<A, R>(accumulator: (current: T | A, next: T) => A, seed?: T | A, resultAction?: (result?: T | A) => A | R): T | A | R | undefined;
toArray(): Array<T>;
} }
export interface Dictionary<T> {
[key: string]: T;
}
export class Dictionary<T> implements Dictionary<T> {
}
export function ToDictionary<T>(keys: Array<string>, each: (index: string) => T) {
const result = new Dictionary<T>();
keys.map((v, i, a) => result[v] = each(v));
return result;
}
export type IndexOf<T> = T extends Map<T, infer V> ? T : T extends Array<infer V> ? number : string;
export interface Linqable<T> extends Iterable<T> { export interface Linqable<T> extends Iterable<T> {
linq: { linq: {
any(predicate?: (each: T) => boolean): boolean; any(predicate?: (each: T) => boolean): boolean;
@ -41,14 +37,33 @@ export interface Linqable<T> extends Iterable<T> {
toArray(): Array<T>; toArray(): Array<T>;
}; };
} }
/* eslint-disable */
function enlinq<T>(iterable: Iterable<T>): Linqed<T> {
return {
...iterable,
all: <any>all.bind(iterable),
any: <any>any.bind(iterable),
bifurcate: <any>bifurcate.bind(iterable),
concat: <any>concat.bind(iterable),
distinct: <any>distinct.bind(iterable),
first: <any>first.bind(iterable),
select: <any>select.bind(iterable),
selectMany: <any>selectMany.bind(iterable),
selectNonNullable: <any>selectNonNullable.bind(iterable),
toArray: <any>toArray.bind(iterable),
where: <any>where.bind(iterable),
forEach: <any>forEach.bind(iterable),
aggregate: <any>aggregate.bind(iterable),
};
}
function linqify<T>(iterable: Iterable<T>): Linqable<T> { function linqify<T>(iterable: Iterable<T>): Linqable<T> {
if (!!(<any>iterable)['linq']) { if ((<any>iterable)['linq']) {
return <Linqable<T>>iterable; return <Linqable<T>>iterable;
} }
return Object.defineProperty(iterable, 'linq', { return Object.defineProperty(iterable, 'linq', {
get: () => { get: () => {
/* eslint-disable */
return { return {
all: all.bind(iterable), all: all.bind(iterable),
any: any.bind(iterable), any: any.bind(iterable),
@ -111,10 +126,41 @@ export function values<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)
}()); }());
} }
// null/undefined // null/undefined
return linqify([]); return linqify([]);
} }
/** returns an Linqable<> for values in the collection */
export function evalues<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)>(source: (Iterable<T> | Array<T> | Dictionary<T> | Map<K, T>) | null | undefined): Linqed<T> {
if (source) {
// map
if (source instanceof Map) {
return enlinq(source.values());
}
// any iterable source
if (isIterable(source)) {
return enlinq(source);
}
// dictionary (object keys)
return enlinq(function* () {
for (const key of keys(source)) {
const value = source[key];
if (typeof value !== 'function') {
yield value;
}
}
}());
}
// null/undefined
return enlinq([]);
}
/** returns an Linqable<{key,value}> for the Collection */ /** returns an Linqable<{key,value}> for the Collection */
export function items<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)>(source: TSrc & (Array<T> | Dictionary<T> | Map<K, T>) | null | undefined): Linqable<{ key: IndexOf<TSrc>; value: T }> { export function items<K, T, TSrc extends (Array<T> | Dictionary<T> | Map<K, T>)>(source: TSrc & (Array<T> | Dictionary<T> | Map<K, T>) | null | undefined): Linqable<{ key: IndexOf<TSrc>; value: T }> {
if (source) { if (source) {

Просмотреть файл

@ -3,8 +3,8 @@
"version": "3.0.0", "version": "3.0.0",
"patchOffset": 100, "patchOffset": 100,
"description": "LINQ-like functionality for Typescript.", "description": "LINQ-like functionality for Typescript.",
"main": "./dist/main.js", "main": "./dist/exports.js",
"typings": "./dist/main.d.ts", "typings": "./dist/exports.d.ts",
"engines": { "engines": {
"node": ">=10.12.0" "node": ">=10.12.0"
}, },

Просмотреть файл

@ -1,6 +1,6 @@
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript'; import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
import * as assert from 'assert'; import * as assert from 'assert';
import { values, length } from '../main'; import { values, length, evalues, } from '../old-linq';
@suite class MyTests { @suite class MyTests {

36
linq/test/new-linq.ts Normal file
Просмотреть файл

@ -0,0 +1,36 @@
import { suite, test, slow, timeout, skip, only } from 'mocha-typescript';
import * as assert from 'assert';
import { values, length, } from '../new-linq';
@suite class NewLinq {
private anArray = ['A', 'B', 'C', 'D', 'E'];
@test async 'distinct'() {
const items = ['one', 'two', 'two', 'three'];
const distinct = values(items).distinct().toArray();
assert.equal(length(distinct), 3);
const dic = {
happy: 'hello',
sad: 'hello',
more: 'name',
maybe: 'foo',
};
const result = values(dic).distinct().toArray();
assert.equal(length(distinct), 3);
}
@test async 'iterating thru collections'() {
// items are items.
assert.equal([...values(this.anArray)].join(','), this.anArray.join(','));
assert.equal(values(this.anArray).count(), 5);
}
}