Commit 4ee41b3b by Vladislav Lagunov

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

parents 43640cd7 e337828b
...@@ -14,10 +14,10 @@ ...@@ -14,10 +14,10 @@
следующим образом следующим образом
``` ```
- import { Eff, eff, ... } from '@bitmaster/core'; - import { Eff, eff, ... } from '~/common/core';
+ import { Eff, eff, ... } from './src/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 { pgettxt, Gettext, ... } from './src/common/utils/gettext;
- import Pagination from '@bitmaster/components/Pagination'; - import Pagination from '@bitmaster/components/Pagination';
......
import * as t from '../decoder'; import * as t from '../decoder';
import * as camelCase from 'lodash/camelCase'; import { camelCase } from 'lodash';
import { absurd } from '../types'; import { absurd } from '../types';
import { WithDefault, RecordDecoder, Decoder } from '../decoder'; import { WithDefault, RecordDecoder, Decoder } from '../decoder';
import { Either } from '../either'; import { Either } from '../either';
/** /**
* Источник данных для чтения конфигов * Источник данных для чтения конфигов
*/ */
...@@ -14,45 +13,39 @@ export type ConfigSource = ...@@ -14,45 +13,39 @@ export type ConfigSource =
| { tag: 'JSON', value: object } | { tag: 'JSON', value: object }
| { tag: 'Concat', sources: ConfigSource[] } | { tag: 'Concat', sources: ConfigSource[] }
export function cli(args: string[], prefix: string = ''): ConfigSource { export function cli(args: string[], prefix: string = ''): ConfigSource {
return { tag: 'Cli', args, prefix }; return { tag: 'Cli', args, prefix };
} }
export function queryString(value: string, transformKey = camelCase): ConfigSource { export function queryString(value: string, transformKey = camelCase): ConfigSource {
return { tag: 'Location/search', value, transformKey }; return { tag: 'Location/search', value, transformKey };
} }
export function json(value: object): ConfigSource { export function json(value: object): ConfigSource {
return { tag: 'JSON', value }; return { tag: 'JSON', value };
} }
export function concat(...sources: ConfigSource[]): ConfigSource { export function concat(...sources: ConfigSource[]): ConfigSource {
return { tag: 'Concat', sources }; return { tag: 'Concat', sources };
} }
export function validate<A>(config: ConfigSource, decoder: RecordDecoder<A>) { export function validate<A>(config: ConfigSource, decoder: RecordDecoder<A>) {
return decoder.validate(merge(decoder, config)); return decoder.validate(merge(decoder, config));
} }
export function merge<A>(decoder: RecordDecoder<A>, ...srcs: ConfigSource[]): object { export function merge<A>(decoder: RecordDecoder<A>, ...srcs: ConfigSource[]): object {
const source = srcs.length === 1 ? srcs[0] : concat(...srcs); const source = srcs.length === 1 ? srcs[0] : concat(...srcs);
if (source.tag === 'Cli') { if (source.tag === 'Cli') {
const value: Record<string, any> = {}; const output: Record<string, any> = {};
for (let i = 0; i < source.args.length; i++) { for (let i = 0; i < source.args.length; i++) {
const prefixLen = '--'.length + source.prefix.length; const prefixLen = '--'.length + source.prefix.length;
if (!source.args[i].startsWith('--' + source.prefix)) continue;
const rest = source.args[i].substr(prefixLen); const rest = source.args[i].substr(prefixLen);
const [k, v] = rest.indexOf('=') === -1 ? [rest, source.args[++i] || ''] : source.args[i].split('='); const [key, value] = rest.indexOf('=') === -1 ? [rest, source.args[++i] || ''] : rest.split('=');
// Проверка того что это известно if (!decoder._description.hasOwnProperty(key)) continue;
if (!decoder._description.hasOwnProperty(k)) continue; output[key] = fromString(decoder._description[key], value);
value[k] = fromString(decoder._description[k], v);
} }
return value; return output;
} }
if (source.tag === 'Location/search') { if (source.tag === 'Location/search') {
...@@ -153,7 +146,6 @@ export function fromString(d: Decoder<any>, value: string): unknown { ...@@ -153,7 +146,6 @@ export function fromString(d: Decoder<any>, value: string): unknown {
return absurd(d); return absurd(d);
} }
export class ConfigDescription<A> extends t.ToDecoder<A> { export class ConfigDescription<A> extends t.ToDecoder<A> {
constructor( constructor(
readonly _decoder: Decoder<A>, readonly _decoder: Decoder<A>,
...@@ -168,7 +160,6 @@ export class ConfigDescription<A> extends t.ToDecoder<A> { ...@@ -168,7 +160,6 @@ export class ConfigDescription<A> extends t.ToDecoder<A> {
// Информация о cli параметрe // Информация о cli параметрe
export type InfoItem = { type: string; default?: unknown; description?: string }; export type InfoItem = { type: string; default?: unknown; description?: string };
export function configInfo(decoder: RecordDecoder<any>, prefix=''): Record<string, InfoItem> { 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), {}); 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 ...@@ -247,7 +238,6 @@ export function configInfo(decoder: RecordDecoder<any>, prefix=''): Record<strin
} }
} }
declare module "../decoder" { declare module "../decoder" {
interface DecoderBase<A> { interface DecoderBase<A> {
withDescription(description: string): Decoder<A>; withDescription(description: string): Decoder<A>;
......
...@@ -412,8 +412,8 @@ export const literals = variants; ...@@ -412,8 +412,8 @@ export const literals = variants;
* Кортежи разных размеров. Проверяемое значение необязательно должно * Кортежи разных размеров. Проверяемое значение необязательно должно
* быть массивом * быть массивом
* ```ts * ```ts
* const pair = t.tuple(t.string, t.number); * const pair = t.tuple(t.string, t.float);
* const pair_2 = t.record({ '0': t.string, '1': t.number }); // тоже самое * const pair_2 = t.record({ '0': t.string, '1': t.float }); // тоже самое
* ``` * ```
*/ */
// @ts-ignore // @ts-ignore
...@@ -525,10 +525,10 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl ...@@ -525,10 +525,10 @@ export function doValidate<A>(decoder: Decoder<A>, value: unknown): Either<Probl
if (decoder instanceof Primitive) { if (decoder instanceof Primitive) {
switch (decoder._type) { switch (decoder._type) {
case 'null': return value === null ? Either.of(value as A) : Either.failure(projectProblem(`expected null, 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(value as A) : Either.failure(projectProblem(`expected undefined, 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(value as any) : Either.failure(projectProblem(`expected a string, 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(value as any) : Either.failure(projectProblem(`expected a boolean, 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 '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 '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')) 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 { ...@@ -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 Custom) return `t.decoder(${JSON.stringify(decoder._name)}, <func>)`;
if (decoder instanceof ArrayDecoder) return `t.array(${decoder._decoder.prettyPrint()})`; if (decoder instanceof ArrayDecoder) return `t.array(${decoder._decoder.prettyPrint()})`;
if (decoder instanceof Dict) return `t.dict(${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 AtDecoder) return `t.at(${JSON.stringify(decoder._path)}, ${decoder._decoder.prettyPrint()})`;
if (decoder instanceof Primitive) return `t.${decoder._type}`; if (decoder instanceof Primitive) return `t.${decoder._type}`;
if (decoder instanceof Pure) return `t.of(${JSON.stringify(decoder._value)})`; if (decoder instanceof Pure) return `t.of(${JSON.stringify(decoder._value)})`;
......
...@@ -37,15 +37,17 @@ declare module 'rxjs/internal/Observable' { ...@@ -37,15 +37,17 @@ declare module 'rxjs/internal/Observable' {
performSuccess<R,A>(this: Eff<never, R>, onSuccess: (x: R) => A): Cmd<A>; 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,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>; 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,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>; 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 // 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,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>; 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>; mapEff<L,R,R2>(this: Eff<L, R>, f: (x: R) => R2): Eff<L, R2>;
...@@ -73,6 +75,14 @@ declare module 'rxjs/internal/Observable' { ...@@ -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)); 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> { (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>)); 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> { ...@@ -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))); 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 */ /** traverse an array */
export function traverse<ERR, A, B>(array: A[], f: (a: A, idx: number) => Eff<ERR, B>): Eff<ERR, B[]> { 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< ...@@ -213,13 +213,14 @@ export function related(doc: Document, res: Resource, name: string): Validation<
/** validate related resource (one-to-many) */ /** validate related resource (one-to-many) */
export function relatedCollection(doc: Document, res: Resource, name: string): Validation<Resource[]> { 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]; const rel: Relationship = res.relationships[name];
if (Array.isArray(rel.data)) { if (Array.isArray(rel.data)) {
const acc: Resource[] = []; const acc: Resource[] = [];
for (let i in rel.data) { for (let i in rel.data) {
const { id, type } = rel.data[i]; 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) { if (result) {
acc.push(result); acc.push(result);
} else { } else {
......
...@@ -30,7 +30,7 @@ export type JsonApi<A> = ...@@ -30,7 +30,7 @@ export type JsonApi<A> =
| RelatedMany<A> | RelatedMany<A>
| WithName<A> | WithName<A>
| WithDefault<A> | WithDefault<A>
; ;
// Базовый класс для наследования методов // Базовый класс для наследования методов
......
export * from '../../jsonapi/resources'; 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 { ...@@ -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>(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>(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; 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