Commit 4ee41b3b by Vladislav Lagunov

Merge branch 'master' of ssh://git.bitmaster.ru:34022/npm/common

parents 43640cd7 e337828b
......@@ -14,10 +14,10 @@
следующим образом
```
- import { Eff, eff, ... } from '@bitmaster/core';
- import { Eff, eff, ... } from '~/common/core';
+ import { Eff, eff, ... } from './src/common/core';
- import { pgettxt, Gettext, ... } from '@bitmaster/utils/gettext';
- import { pgettxt, Gettext, ... } from '~/common/utils/gettext';
+ import { pgettxt, Gettext, ... } from './src/common/utils/gettext;
- import Pagination from '@bitmaster/components/Pagination';
......
import * as t from '../decoder';
import * as camelCase from 'lodash/camelCase';
import { camelCase } from 'lodash';
import { absurd } from '../types';
import { WithDefault, RecordDecoder, Decoder } from '../decoder';
import { Either } from '../either';
/**
* Источник данных для чтения конфигов
*/
......@@ -14,45 +13,39 @@ export type ConfigSource =
| { tag: 'JSON', value: object }
| { tag: 'Concat', sources: ConfigSource[] }
export function cli(args: string[], prefix: string = ''): ConfigSource {
return { tag: 'Cli', args, prefix };
}
export function queryString(value: string, transformKey = camelCase): ConfigSource {
return { tag: 'Location/search', value, transformKey };
}
export function json(value: object): ConfigSource {
return { tag: 'JSON', value };
}
export function concat(...sources: ConfigSource[]): ConfigSource {
return { tag: 'Concat', sources };
}
export function validate<A>(config: ConfigSource, decoder: RecordDecoder<A>) {
return decoder.validate(merge(decoder, config));
}
export function merge<A>(decoder: RecordDecoder<A>, ...srcs: ConfigSource[]): object {
const source = srcs.length === 1 ? srcs[0] : concat(...srcs);
if (source.tag === 'Cli') {
const value: Record<string, any> = {};
const output: Record<string, any> = {};
for (let i = 0; i < source.args.length; i++) {
const prefixLen = '--'.length + source.prefix.length;
if (!source.args[i].startsWith('--' + source.prefix)) continue;
const rest = source.args[i].substr(prefixLen);
const [k, v] = rest.indexOf('=') === -1 ? [rest, source.args[++i] || ''] : source.args[i].split('=');
// Проверка того что это известно
if (!decoder._description.hasOwnProperty(k)) continue;
value[k] = fromString(decoder._description[k], v);
const [key, value] = rest.indexOf('=') === -1 ? [rest, source.args[++i] || ''] : rest.split('=');
if (!decoder._description.hasOwnProperty(key)) continue;
output[key] = fromString(decoder._description[key], value);
}
return value;
return output;
}
if (source.tag === 'Location/search') {
......@@ -153,7 +146,6 @@ export function fromString(d: Decoder<any>, value: string): unknown {
return absurd(d);
}
export class ConfigDescription<A> extends t.ToDecoder<A> {
constructor(
readonly _decoder: Decoder<A>,
......@@ -168,7 +160,6 @@ export class ConfigDescription<A> extends t.ToDecoder<A> {
// Информация о cli параметрe
export type InfoItem = { type: string; default?: unknown; description?: string };
export function configInfo(decoder: RecordDecoder<any>, prefix=''): Record<string, InfoItem> {
return Object.keys(decoder._description).reduce((acc, k) => (acc[k] = go(decoder._description[k]), acc), {});
......@@ -247,7 +238,6 @@ export function configInfo(decoder: RecordDecoder<any>, prefix=''): Record<strin
}
}
declare module "../decoder" {
interface DecoderBase<A> {
withDescription(description: string): Decoder<A>;
......
......@@ -412,8 +412,8 @@ export const literals = variants;
* Кортежи разных размеров. Проверяемое значение необязательно должно
* быть массивом
* ```ts
* const pair = t.tuple(t.string, t.number);
* const pair_2 = t.record({ '0': t.string, '1': t.number }); // тоже самое
* const pair = t.tuple(t.string, t.float);
* const pair_2 = t.record({ '0': t.string, '1': t.float }); // тоже самое
* ```
*/
// @ts-ignore
......@@ -525,10 +525,10 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
if (decoder instanceof Primitive) {
switch (decoder._type) {
case 'null': return value === null ? Either.of(value as A) : Either.failure(projectProblem(`expected null, got ${fancyTypeOf(value)}`));
case 'undefined': return value === undefined ? Either.of(value as A) : Either.failure(projectProblem(`expected undefined, got ${fancyTypeOf(value)}`));
case 'string': return typeof(value) === 'string' ? Either.of(value as any) : Either.failure(projectProblem(`expected a string, got ${fancyTypeOf(value)}`));
case 'boolean': return typeof(value) === 'boolean' ? Either.of(value as any) : Either.failure(projectProblem(`expected a boolean, got ${fancyTypeOf(value)}`));
case 'null': return value === null ? Either.of<any>(value) : Either.failure(projectProblem(`expected null, got ${fancyTypeOf(value)}`));
case 'undefined': return value === undefined ? Either.of<any>(value) : Either.failure(projectProblem(`expected undefined, got ${fancyTypeOf(value)}`));
case 'string': return typeof(value) === 'string' ? Either.of<any>(value) : Either.failure(projectProblem(`expected a string, got ${fancyTypeOf(value)}`));
case 'boolean': return typeof(value) === 'boolean' ? Either.of<any>(value) : Either.failure(projectProblem(`expected a boolean, got ${fancyTypeOf(value)}`));
case 'any': return Either.of(value as A);
case 'nat': return typeof (value) !== 'number' ? Either.failure(projectProblem('not a number')) : (value|0) === value && value >= 0 ? Either.of(value as any) : Either.failure(projectProblem('not a natural number'));
case 'int': return typeof (value) !== 'number' ? Either.failure(projectProblem('not a number')) : (value|0) === value ? Either.of(value as any) : Either.failure(projectProblem('not an integer'))
......@@ -594,7 +594,7 @@ export function prettyPrint(decoder: Decoder<any>): string {
if (decoder instanceof Custom) return `t.decoder(${JSON.stringify(decoder._name)}, <func>)`;
if (decoder instanceof ArrayDecoder) return `t.array(${decoder._decoder.prettyPrint()})`;
if (decoder instanceof Dict) return `t.dict(${decoder._decoder.prettyPrint()})`;
if (decoder instanceof RecordDecoder) return `t.record({ ${Object.keys(decoder._description).map(k => decoder._description[k].prettyPrint()).join(', ')} })`;
if (decoder instanceof RecordDecoder) return `t.record({ ${Object.keys(decoder._description).map(k => JSON.stringify(k) + ': ' + decoder._description[k].prettyPrint()).join(', ')} })`;
if (decoder instanceof AtDecoder) return `t.at(${JSON.stringify(decoder._path)}, ${decoder._decoder.prettyPrint()})`;
if (decoder instanceof Primitive) return `t.${decoder._type}`;
if (decoder instanceof Pure) return `t.of(${JSON.stringify(decoder._value)})`;
......
......@@ -37,15 +37,17 @@ declare module 'rxjs/internal/Observable' {
performSuccess<R,A>(this: Eff<never, R>, onSuccess: (x: R) => A): Cmd<A>;
onError<L,R,L2,R2>(this: Eff<L, R>, onFailure: (x: L) => Eff<L2, R2>): Eff<L2, R2|R>;
chain<L,R,R2>(this: Eff<L, R>, f: (x: R) => Eff<L, R2>): Eff<L, R2>;
chain<L,R,L2,R2>(this: Eff<L, R>, f: (x: R) => Eff<L2, R2>): Eff<L|L2, R2>;
chainTo<L,R,R2>(this: Eff<L, R>, effect: Eff<L, R2>): Eff<L, R2>;
chainTo<L,R,L2,R2>(this: Eff<L, R>, effect: Eff<L2, R2>): Eff<L|L2, R2>;
chainError<L,R,L2,R2>(this: Eff<L, R>, onFailure: (x: L) => Eff<L2, R2>): Eff<L2, R2|R>;
chainErrorTo<L,R,L2,R2>(this: Eff<L, R>, onFailure: Eff<L2, R2>): Eff<L2, R2|R>;
// DEPRECATED
onError<L,R,L2,R2>(this: Eff<L, R>, onFailure: (x: L) => Eff<L2, R2>): Eff<L2, R2|R>;
chainEff<L,R,R2>(this: Eff<L, R>, f: (x: R) => Eff<L, R2>): Eff<L, R2>;
chainEff<L,R,L2,R2>(this: Eff<L, R>, f: (x: R) => Eff<L2, R2>): Eff<L|L2, R2>;
mapEff<L,R,R2>(this: Eff<L, R>, f: (x: R) => R2): Eff<L, R2>;
......@@ -73,6 +75,14 @@ declare module 'rxjs/internal/Observable' {
return this.pipe(map((ethr: Either<any, any>) => ethr.tag === 'Left' ? onFailure(ethr.value) : Rx.of(ethr)), combineAll(x => x));
};
(Observable as any).prototype.chainError = function<L,R,L2,R2>(this: Eff<L, R>, onFailure: (x: L) => Eff<L2, R2>): Eff<L2, R2|R> {
return this.pipe(map((ethr: Either<any, any>) => ethr.tag === 'Left' ? onFailure(ethr.value) : Rx.of(ethr)), combineAll(x => x));
};
(Observable as any).prototype.chainErrorTo = function<L,R,L2,R2>(this: Eff<L, R>, onFailure: Eff<L2, R2>): Eff<L2, R2|R> {
return this.pipe(map((ethr: Either<any, any>) => ethr.tag === 'Left' ? onFailure : Rx.of(ethr)), combineAll(x => x));
};
(Observable as any).prototype.chain = function<L,R,R2>(this: Eff<L, R>, f: (x: R) => Eff<L, R2>): Eff<L, R2> {
return this.pipe(map(ethr => ethr.tag === 'Right' ? f(ethr.value) : Rx.of(ethr)), combineAll(x => x as Either<any , any>));
};
......@@ -152,6 +162,11 @@ export function ap(): Eff<any, any> {
return Rx.combineLatest(Array.apply(undefined, Array(arguments.length - 1)).map((_, idx) => _arguments[idx]), (...inputs) => either.traverse(inputs, x => x as any).map(inputs => _arguments[_arguments.length - 1].apply(undefined, inputs)));
}
export function record<R extends Record<string, Eff<any, any>>>(rec: R): Eff<{ [K in keyof R]: R[K]['_T']['_L'] }[keyof R], { [K in keyof R]: R[K]['_T']['_R'] }> {
const keys = Object.keys(rec);
return ap.apply(undefined, [...keys.map(k => rec[k]), (...values) => values.reduce((acc, v, idx) => (acc[keys[idx]] = v, acc), {})]);
}
/** traverse an array */
export function traverse<ERR, A, B>(array: A[], f: (a: A, idx: number) => Eff<ERR, B>): Eff<ERR, B[]> {
......
......@@ -213,13 +213,14 @@ export function related(doc: Document, res: Resource, name: string): Validation<
/** validate related resource (one-to-many) */
export function relatedCollection(doc: Document, res: Resource, name: string): Validation<Resource[]> {
if (doc.included && res.relationships && res.relationships[name]) {
if (res.relationships && res.relationships[name]) {
const included = doc.included || [];
const rel: Relationship = res.relationships[name];
if (Array.isArray(rel.data)) {
const acc: Resource[] = [];
for (let i in rel.data) {
const { id, type } = rel.data[i];
const result = doc.included.find(a => a.id === id && a.type === type);
const result = included.find(a => a.id === id && a.type === type);
if (result) {
acc.push(result);
} else {
......
......@@ -30,7 +30,7 @@ export type JsonApi<A> =
| RelatedMany<A>
| WithName<A>
| WithDefault<A>
;
;
// Базовый класс для наследования методов
......
export * from '../../jsonapi/resources';
// // Без этого экспорта TS видит JsonApiBase только как тип
// import { JsonApiBase } from '../../jsonapi/resources';
// export { JsonApiBase };
......@@ -11,7 +11,7 @@ export function cmpPtr(xs: IArguments, ys: IArguments): boolean {
}
/** cheap partial memoisation, only the last call results are preserved */
/** Cheap partial memoisation, only the last call results are preserved */
export default function memoize<A>(func: () => A, cmp?: ArgsComparator): typeof func;
export default function memoize<A,B>(func: (a: A) => B, cmp?: ArgsComparator): typeof func;
export default function memoize<A,B,C>(func: (a: A, b: B) => C, cmp?: ArgsComparator): typeof func;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment