mirror of
https://github.com/valitydev/fe-core.git
synced 2024-11-06 02:25:18 +00:00
FRONTEND-509: Configure CommitLint, Add Partial-Fetcher & Component Changes Util (#2)
This commit is contained in:
parent
44f1047cb0
commit
171118c831
3
.commitlintrc.json
Normal file
3
.commitlintrc.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": ["@commitlint/config-conventional"]
|
||||
}
|
26
.eslintrc.js
Normal file
26
.eslintrc.js
Normal file
@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: ['plugin:prettier/recommended', 'eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 12,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint'],
|
||||
rules: {
|
||||
'sort-imports': [
|
||||
'error',
|
||||
{
|
||||
ignoreCase: false,
|
||||
ignoreDeclarationSort: false,
|
||||
ignoreMemberSort: false,
|
||||
memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'],
|
||||
allowSeparatedGroups: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
20
.github/workflows/publish.yml
vendored
Normal file
20
.github/workflows/publish.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15
|
||||
registry-url: https://npm.pkg.github.com/
|
||||
- run: npm ci
|
||||
- run: npm run release
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
5
.github/workflows/test.yaml
vendored
5
.github/workflows/test.yaml
vendored
@ -10,5 +10,6 @@ jobs:
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 15
|
||||
- run: npm run bootstrap
|
||||
- run: npm run test
|
||||
- run: npm ci
|
||||
- run: npm run test
|
||||
- run: npm run build
|
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
_
|
4
.husky/commit-msg
Executable file
4
.husky/commit-msg
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx commitlint --edit ${HUSKY_GIT_PARAMS}
|
26
README.md
26
README.md
@ -1,3 +1,27 @@
|
||||
# Frontend Libs Monorepo
|
||||
|
||||
- [NPM Workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces)
|
||||
- [NPM Workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces)
|
||||
- [Lerna](https://github.com/lerna/lerna)
|
||||
|
||||
- CommitLint
|
||||
- [Prettier](https://prettier.io/)
|
||||
- ESLint
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm i '@rbkmoney/<PACKAGE_NAME>'
|
||||
```
|
||||
|
||||
## Development / Usage
|
||||
|
||||
```sh
|
||||
npm link '<PATH>/fe-core/packages/<PACKAGE_DIR>'
|
||||
```
|
||||
|
||||
## Publish
|
||||
|
||||
1. Bump package version
|
||||
2. ```sh
|
||||
npm publish
|
||||
```
|
||||
|
@ -8,6 +8,7 @@
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://npm.pkg.github.com/"
|
||||
}
|
||||
}
|
||||
|
3991
package-lock.json
generated
3991
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
21
package.json
21
package.json
@ -1,13 +1,12 @@
|
||||
{
|
||||
"name": "fe-root",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"bootstrap": "npx lerna bootstrap",
|
||||
"build": "lerna run build",
|
||||
"test": "lerna run test",
|
||||
"clean": "shx rm -rf **/node_modules",
|
||||
"release": "lerna run build & lerna publish --no-commit-hooks"
|
||||
"release": "lerna run build & lerna publish --no-commit-hooks --yes",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"workspaces": [
|
||||
"./packages/*"
|
||||
@ -17,7 +16,21 @@
|
||||
"url": "https://github.com/rbkmoney/fe-core"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^12.1.1",
|
||||
"@commitlint/config-conventional": "^12.1.1",
|
||||
"@types/jasmine": "^3.6.9",
|
||||
"@typescript-eslint/eslint-plugin": "^4.21.0",
|
||||
"@typescript-eslint/parser": "^4.21.0",
|
||||
"eslint": "^7.23.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"husky": "^6.0.0",
|
||||
"jasmine": "^3.7.0",
|
||||
"jasmine-console-reporter": "^3.1.0",
|
||||
"jasmine-marbles": "^0.8.1",
|
||||
"lerna": "^4.0.0",
|
||||
"shx": "^0.3.3"
|
||||
"prettier": "^2.2.1",
|
||||
"shx": "^0.3.3",
|
||||
"ts-node": "^9.1.1",
|
||||
"typescript": "^4.2.4"
|
||||
}
|
||||
}
|
||||
|
1
packages/partial-fetcher/.npmrc
Normal file
1
packages/partial-fetcher/.npmrc
Normal file
@ -0,0 +1 @@
|
||||
@rbkmoney:registry=https://npm.pkg.github.com/
|
3
packages/partial-fetcher/.prettierignore
Normal file
3
packages/partial-fetcher/.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
package.json
|
||||
package-lock.json
|
||||
node_modules
|
5
packages/partial-fetcher/README.md
Normal file
5
packages/partial-fetcher/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Partial Fetcher
|
||||
|
||||
```sh
|
||||
npm i @rbkmoney/partial-fetcher
|
||||
```
|
24
packages/partial-fetcher/package.json
Normal file
24
packages/partial-fetcher/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@rbkmoney/partial-fetcher",
|
||||
"version": "0.0.0",
|
||||
"description": "Partial Fetcher",
|
||||
"author": "rbkmoney",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.js",
|
||||
"scripts": {
|
||||
"build": "npm run clean & tsc -p tsconfig.json",
|
||||
"clean": "shx rm -rf lib",
|
||||
"test": "ts-node ../../node_modules/jasmine/bin/jasmine src/**/*.spec.ts --reporter=jasmine-console-reporter"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rbkmoney/fe-core"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com/@rbkmoney"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ngneat/until-destroy": "^8.0.4",
|
||||
"rxjs": "^6.6.7"
|
||||
}
|
||||
}
|
1
packages/partial-fetcher/src/index.ts
Normal file
1
packages/partial-fetcher/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './partial-fetcher';
|
4
packages/partial-fetcher/src/partial-fetcher/consts.ts
Normal file
4
packages/partial-fetcher/src/partial-fetcher/consts.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const DEBOUNCE_FETCHER_ACTION_TIME = new InjectionToken<number>('debounceFetcherActionTime');
|
||||
export const DEFAULT_FETCHER_DEBOUNCE_ACTION_TIME = 300;
|
@ -0,0 +1,4 @@
|
||||
export interface FetchAction<P extends any = any> {
|
||||
type: 'search' | 'fetchMore';
|
||||
value?: P;
|
||||
}
|
5
packages/partial-fetcher/src/partial-fetcher/fetch-fn.ts
Normal file
5
packages/partial-fetcher/src/partial-fetcher/fetch-fn.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { FetchResult } from './fetch-result';
|
||||
|
||||
export type FetchFn<P, R> = (params: P, continuationToken?: string) => Observable<FetchResult<R>>;
|
@ -0,0 +1,5 @@
|
||||
export interface FetchResult<T> {
|
||||
result?: T[];
|
||||
continuationToken?: string;
|
||||
error?: any;
|
||||
}
|
4
packages/partial-fetcher/src/partial-fetcher/index.ts
Normal file
4
packages/partial-fetcher/src/partial-fetcher/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './partial-fetcher';
|
||||
export * from './fetch-result';
|
||||
export * from './fetch-action';
|
||||
export * from './consts';
|
@ -0,0 +1,2 @@
|
||||
export * from './scan-action';
|
||||
export * from './scan-search-result';
|
@ -0,0 +1,5 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { scan } from 'rxjs/operators';
|
||||
|
||||
export const scanAction = <T>(s: Observable<T>) =>
|
||||
s.pipe(scan<T, T>((lastAction, currentAction) => ({ ...lastAction, ...currentAction }), null));
|
@ -0,0 +1,44 @@
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { catchError, first, map, mergeScan } from 'rxjs/operators';
|
||||
|
||||
import { FetchAction } from '../fetch-action';
|
||||
import { FetchFn } from '../fetch-fn';
|
||||
import { FetchResult } from '../fetch-result';
|
||||
|
||||
export const handleFetchResultError = <R>(result: R[] = [], continuationToken?: string) => (
|
||||
s: Observable<FetchResult<R>>
|
||||
): Observable<FetchResult<R>> =>
|
||||
s.pipe(
|
||||
catchError((error) =>
|
||||
of<FetchResult<R>>({
|
||||
result,
|
||||
continuationToken,
|
||||
error,
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
export const scanFetchResult = <P, R>(fn: FetchFn<P, R>) => (
|
||||
s: Observable<FetchAction<P>>
|
||||
): Observable<FetchResult<R>> =>
|
||||
s.pipe(
|
||||
mergeScan<FetchAction<P>, FetchResult<R>>(
|
||||
({ result, continuationToken }, { type, value }) => {
|
||||
switch (type) {
|
||||
case 'search':
|
||||
return fn(value).pipe(first(), handleFetchResultError());
|
||||
case 'fetchMore':
|
||||
return fn(value, continuationToken).pipe(
|
||||
first(),
|
||||
map((r) => ({
|
||||
result: result.concat(r.result),
|
||||
continuationToken: r.continuationToken,
|
||||
})),
|
||||
handleFetchResultError(result, continuationToken)
|
||||
);
|
||||
}
|
||||
},
|
||||
{ result: [] },
|
||||
1
|
||||
)
|
||||
);
|
@ -0,0 +1,118 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
import { FetchResult } from './fetch-result';
|
||||
import { PartialFetcher } from './partial-fetcher';
|
||||
|
||||
function assertDeepEqual(actual: any, expected: any) {
|
||||
expect(actual).toEqual(expected);
|
||||
}
|
||||
|
||||
function createScheduler() {
|
||||
return new TestScheduler(assertDeepEqual);
|
||||
}
|
||||
|
||||
describe('PartialFetch', () => {
|
||||
class PartialFetched extends PartialFetcher<any, any> {
|
||||
constructor(private fetchFn: (params?: any, continuationToken?: string) => Observable<any>, debounce?: number) {
|
||||
super(debounce);
|
||||
}
|
||||
|
||||
protected fetch(params: any, continuationToken: string) {
|
||||
return this.fetchFn(params, continuationToken);
|
||||
}
|
||||
}
|
||||
|
||||
it('should init', () => {
|
||||
createScheduler().run(({ cold, expectObservable }) => {
|
||||
const result: FetchResult<any> = { result: ['test'] };
|
||||
const partialFetched = new PartialFetched(() => cold('--x|', { x: result }), 100);
|
||||
expectObservable(partialFetched.searchResult$).toBe('');
|
||||
expectObservable(partialFetched.errors$).toBe('');
|
||||
expectObservable(partialFetched.doAction$).toBe('0', [true]);
|
||||
expectObservable(partialFetched.hasMore$).toBe('0', [null]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should search with debounce', () => {
|
||||
createScheduler().run(({ cold, expectObservable }) => {
|
||||
const result: FetchResult<any> = { result: ['test'] };
|
||||
const partialFetched = new PartialFetched(() => cold('--x|', { x: result }), 100);
|
||||
partialFetched.search(null);
|
||||
expectObservable(partialFetched.searchResult$).toBe('100ms --0', [['test']]);
|
||||
expectObservable(partialFetched.errors$).toBe('');
|
||||
expectObservable(partialFetched.doAction$).toBe('0 100ms -1', [true, false]);
|
||||
expectObservable(partialFetched.hasMore$).toBe('0 100ms -1', [null, false]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should load more with last token', () => {
|
||||
createScheduler().run(({ cold, expectObservable }) => {
|
||||
const partialFetched = new PartialFetched(
|
||||
(_params, token) =>
|
||||
cold('--x|', {
|
||||
x: { result: [token], continuationToken: token ? token + '0' : 'token' },
|
||||
} as FetchResult<any>),
|
||||
0
|
||||
);
|
||||
partialFetched.search('token');
|
||||
partialFetched.fetchMore();
|
||||
partialFetched.fetchMore();
|
||||
partialFetched.fetchMore();
|
||||
expectObservable(partialFetched.searchResult$).toBe('--0-1-2-3', [
|
||||
[undefined],
|
||||
[undefined, 'token'],
|
||||
[undefined, 'token', 'token0'],
|
||||
[undefined, 'token', 'token0', 'token00'],
|
||||
]);
|
||||
expectObservable(partialFetched.errors$).toBe('');
|
||||
expectObservable(partialFetched.doAction$).toBe('0-1', [true, false]);
|
||||
expectObservable(partialFetched.hasMore$).toBe('0-1', [null, true]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should reload with old params', () => {
|
||||
createScheduler().run(({ cold, expectObservable }) => {
|
||||
const partialFetched = new PartialFetched(
|
||||
(params) => cold('--x|', { x: { result: [params], continuationToken: 'token' } as FetchResult<any> }),
|
||||
0
|
||||
);
|
||||
partialFetched.search('params');
|
||||
partialFetched.fetchMore();
|
||||
partialFetched.refresh();
|
||||
expectObservable(partialFetched.searchResult$).toBe('--0-1-2', [
|
||||
['params'],
|
||||
['params', 'params'],
|
||||
['params'],
|
||||
]);
|
||||
expectObservable(partialFetched.errors$).toBe('');
|
||||
expectObservable(partialFetched.doAction$).toBe('0-1', [true, false]);
|
||||
expectObservable(partialFetched.hasMore$).toBe('0-1', [null, true]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('throw error', () => {
|
||||
it('should return error with delay', () => {
|
||||
createScheduler().run(({ cold, expectObservable }) => {
|
||||
const partialFetched = new PartialFetched(() => cold('--#|'), 100);
|
||||
partialFetched.search(null);
|
||||
expectObservable(partialFetched.searchResult$).toBe('100ms --0', [[]]);
|
||||
expectObservable(partialFetched.errors$).toBe('100ms --0', ['error']);
|
||||
expectObservable(partialFetched.doAction$).toBe('0 100ms -1', [true, false]);
|
||||
expectObservable(partialFetched.hasMore$).toBe('0 100ms -1', [null, false]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch after error', () => {
|
||||
createScheduler().run(({ cold, expectObservable }) => {
|
||||
const partialFetched = new PartialFetched(() => cold('--#|'), 0);
|
||||
partialFetched.search(null);
|
||||
partialFetched.fetchMore();
|
||||
expectObservable(partialFetched.searchResult$).toBe('--0-1', [[], []]);
|
||||
expectObservable(partialFetched.errors$).toBe('--0-1', ['error', 'error']);
|
||||
expectObservable(partialFetched.doAction$).toBe('0-1', [true, false]);
|
||||
expectObservable(partialFetched.hasMore$).toBe('0-1', [null, false]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
106
packages/partial-fetcher/src/partial-fetcher/partial-fetcher.ts
Normal file
106
packages/partial-fetcher/src/partial-fetcher/partial-fetcher.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { EMPTY, merge, Observable, of, Subject } from 'rxjs';
|
||||
import {
|
||||
debounceTime,
|
||||
distinctUntilChanged,
|
||||
filter,
|
||||
map,
|
||||
pluck,
|
||||
share,
|
||||
shareReplay,
|
||||
startWith,
|
||||
switchMap,
|
||||
tap,
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import { FetchAction } from './fetch-action';
|
||||
import { FetchFn } from './fetch-fn';
|
||||
import { FetchResult } from './fetch-result';
|
||||
import { scanAction, scanFetchResult } from './operators';
|
||||
import { SHARE_REPLAY_CONF } from './utils/share-replay-conf';
|
||||
import { progress } from './utils/progress';
|
||||
|
||||
// TODO: make free of subscription & UntilDestroy
|
||||
// TODO: share public props together
|
||||
// TODO: make fetcher injectable
|
||||
@UntilDestroy()
|
||||
export abstract class PartialFetcher<R, P> {
|
||||
readonly fetchResultChanges$: Observable<{ result: R[]; hasMore: boolean; continuationToken: string }>;
|
||||
|
||||
readonly searchResult$: Observable<R[]>;
|
||||
readonly hasMore$: Observable<boolean>;
|
||||
readonly doAction$: Observable<boolean>;
|
||||
readonly doSearchAction$: Observable<boolean>;
|
||||
readonly errors$: Observable<any>;
|
||||
|
||||
private action$ = new Subject<FetchAction<P>>();
|
||||
|
||||
// TODO: make a dependency for DI
|
||||
constructor(debounceActionTime: number = 300) {
|
||||
const actionWithParams$ = this.getActionWithParams(debounceActionTime);
|
||||
const fetchResult$ = this.getFetchResult(actionWithParams$);
|
||||
|
||||
this.fetchResultChanges$ = fetchResult$.pipe(
|
||||
map(({ result, continuationToken }) => ({
|
||||
result: result ?? [],
|
||||
continuationToken,
|
||||
hasMore: !!continuationToken,
|
||||
})),
|
||||
share()
|
||||
);
|
||||
this.searchResult$ = this.fetchResultChanges$.pipe(pluck('result'), shareReplay(SHARE_REPLAY_CONF));
|
||||
|
||||
this.hasMore$ = this.fetchResultChanges$.pipe(
|
||||
pluck('hasMore'),
|
||||
startWith(null as boolean),
|
||||
distinctUntilChanged(),
|
||||
shareReplay(SHARE_REPLAY_CONF)
|
||||
);
|
||||
|
||||
this.doAction$ = progress(actionWithParams$, fetchResult$, true).pipe(shareReplay(SHARE_REPLAY_CONF));
|
||||
this.doSearchAction$ = progress(
|
||||
actionWithParams$.pipe(filter(({ type }) => type === 'search')),
|
||||
fetchResult$,
|
||||
true
|
||||
).pipe(shareReplay(SHARE_REPLAY_CONF));
|
||||
this.errors$ = fetchResult$.pipe(
|
||||
switchMap(({ error }) => (error ? of(error) : EMPTY)),
|
||||
tap((error) => console.error('Partial fetcher error: ', error)),
|
||||
share()
|
||||
);
|
||||
|
||||
merge(
|
||||
this.searchResult$,
|
||||
this.hasMore$,
|
||||
this.doAction$,
|
||||
this.doSearchAction$,
|
||||
this.errors$,
|
||||
this.fetchResultChanges$
|
||||
)
|
||||
.pipe(untilDestroyed(this))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
search(value: P) {
|
||||
this.action$.next({ type: 'search', value });
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.action$.next({ type: 'search' });
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.action$.next({ type: 'fetchMore' });
|
||||
}
|
||||
|
||||
protected abstract fetch(...args: Parameters<FetchFn<P, R>>): ReturnType<FetchFn<P, R>>;
|
||||
|
||||
private getActionWithParams(debounceActionTime: number): Observable<FetchAction<P>> {
|
||||
return this.action$.pipe(scanAction, debounceActionTime ? debounceTime(debounceActionTime) : tap(), share());
|
||||
}
|
||||
|
||||
private getFetchResult(actionWithParams$: Observable<FetchAction<P>>): Observable<FetchResult<R>> {
|
||||
const fetchFn = this.fetch.bind(this) as FetchFn<P, R>;
|
||||
return actionWithParams$.pipe(scanFetchResult(fetchFn), shareReplay(SHARE_REPLAY_CONF));
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { merge, Observable, of } from 'rxjs';
|
||||
import { catchError, distinctUntilChanged, map, startWith } from 'rxjs/operators';
|
||||
|
||||
export const progress = (start$: Observable<any>, end$: Observable<any>, startValue = false): Observable<boolean> =>
|
||||
merge(start$.pipe(map(() => true)), end$.pipe(map(() => false))).pipe(
|
||||
catchError(() => of(false)),
|
||||
startWith(startValue),
|
||||
distinctUntilChanged()
|
||||
);
|
@ -0,0 +1,4 @@
|
||||
import { ShareReplayConfig } from 'rxjs/internal/operators/shareReplay';
|
||||
|
||||
// Default share replay config
|
||||
export const SHARE_REPLAY_CONF: ShareReplayConfig = { bufferSize: 1, refCount: true };
|
8
packages/partial-fetcher/tsconfig.json
Normal file
8
packages/partial-fetcher/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src/index.ts"]
|
||||
}
|
1
packages/utils/.npmrc
Normal file
1
packages/utils/.npmrc
Normal file
@ -0,0 +1 @@
|
||||
@rbkmoney:registry=https://npm.pkg.github.com/
|
3
packages/utils/.prettierignore
Normal file
3
packages/utils/.prettierignore
Normal file
@ -0,0 +1,3 @@
|
||||
package.json
|
||||
package-lock.json
|
||||
node_modules
|
5
packages/utils/README.md
Normal file
5
packages/utils/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# Utils
|
||||
|
||||
```sh
|
||||
npm i @rbkmoney/utils
|
||||
```
|
22
packages/utils/package.json
Normal file
22
packages/utils/package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "@rbkmoney/utils",
|
||||
"version": "0.0.0",
|
||||
"description": "Utils",
|
||||
"author": "rbkmoney",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.js",
|
||||
"scripts": {
|
||||
"build": "npm run clean & tsc -p tsconfig.json",
|
||||
"clean": "shx rm -rf lib"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rbkmoney/fe-core"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com/@rbkmoney"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@angular/core": "^11.2.9"
|
||||
}
|
||||
}
|
10
packages/utils/src/component-changes/component-changes.ts
Normal file
10
packages/utils/src/component-changes/component-changes.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { SimpleChange } from '@angular/core';
|
||||
|
||||
export interface ComponentChange<T, P extends keyof T> extends Omit<SimpleChange, 'previousValue' | 'currentValue'> {
|
||||
previousValue: T[P];
|
||||
currentValue: T[P];
|
||||
}
|
||||
|
||||
export type ComponentChanges<T> = {
|
||||
[P in keyof T]?: ComponentChange<T, P>;
|
||||
};
|
1
packages/utils/src/component-changes/index.ts
Normal file
1
packages/utils/src/component-changes/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './component-changes';
|
1
packages/utils/src/index.ts
Normal file
1
packages/utils/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './component-changes';
|
8
packages/utils/tsconfig.json
Normal file
8
packages/utils/tsconfig.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "lib"
|
||||
},
|
||||
"include": ["src/index.ts"]
|
||||
}
|
13
tsconfig.json
Normal file
13
tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2015",
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user