chore: remove tsdx and upgrade dependencies

This commit is contained in:
Josep M Sobrepere 2021-05-31 12:30:46 +02:00
parent 03ef720011
commit 80a9fd67ee
42 changed files with 1841 additions and 4721 deletions

View File

@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '12'
node-version: '14'
- run: yarn install --frozen-lockfile
- run: yarn lint

6
.gitignore vendored
View File

@ -4,8 +4,8 @@ node_modules
coverage
.cache
packages/core/dist/**
!packages/core/dist/index.js
!packages/core/dist/index.cjs
packages/utils/dist/**
!packages/utils/dist/index.js
!packages/utils/dist/index.cjs
packages/dom/dist/**
!packages/dom/dist/index.js
!packages/dom/dist/index.cjs

View File

@ -18,7 +18,7 @@
},
{
"path": "./packages/dom/dist/dom.cjs.production.min.js",
"maxSize": "1 kB",
"maxSize": "2 kB",
"compression": "none"
},
{
@ -40,22 +40,29 @@
"trailingComma": "all"
},
"devDependencies": {
"cross-env": "^7.0.3",
"esbuild": "^0.11.2",
"eslint-plugin-prettier": "^3.3.1",
"@babel/preset-env": "^7.14.2",
"@babel/preset-typescript": "^7.13.0",
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/react": "^11.2.7",
"@testing-library/react-hooks": "^7.0.0",
"@types/jest": "^26.0.23",
"@types/react": "^17.0.8",
"@types/react-dom": "^17.0.5",
"esbuild": "^0.12.3",
"jest": "^27.0.1",
"jest-marbles": "^2.5.1",
"husky": "^4.3.7",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"typescript": "^4.2.3",
"prettier": "^2.3.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-test-renderer": "^17.0.2",
"rxjs": "^7.1.0",
"typescript": "^4.2.4",
"ts-jest": "^27.0.1",
"tslib": "^2.2.0",
"wsrun": "^5.2.4"
},
"resolutions": {
"**/@typescript-eslint/eslint-plugin": "^4.11.1",
"**/@typescript-eslint/parser": "^4.11.1",
"**/jest": "^26.6.3",
"**/ts-jest": "^26.4.4",
"**/typescript": "^4.2.3"
},
"lint-staged": {
"*.{js,jsx,ts,tsx,json,md}": "prettier --write"
},

View File

@ -0,0 +1,21 @@
// Only used by Jest
module.exports = {
presets: [
[
"@babel/preset-env",
{ useBuiltIns: "entry", corejs: "2", targets: { node: "current" } },
],
"@babel/preset-typescript",
],
plugins: [
function () {
return {
visitor: {
MetaProperty(path) {
path.replaceWithSourceString("process")
},
},
}
},
],
}

View File

@ -1,7 +1,13 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "jsdom",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
setupFilesAfterEnv: ["<rootDir>/setupTests.ts"],
globals: {
"ts-jest": {
diagnostics: false,
babelConfig: true,
},
},
}

View File

@ -6,23 +6,25 @@
},
"license": "MIT",
"sideEffects": false,
"exports": "dist/core.esm2019.js",
"module": "dist/core.esm2017.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"exports": {
"import": "./dist/core.es2019.mjs",
"require": "./dist/index.cjs"
},
"module": "./dist/core.es2017.mjs",
"main": "./dist/index.cjs",
"typings": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"start": "tsdx watch",
"build": "yarn build:ts && yarn build:esm2017 && yarn build:esm2019 && yarn build:cjs:dev && yarn build:cjs:prod",
"build:esm2019": "esbuild src/index.tsx --bundle --outfile=./dist/core.esm2019.js --target=es2019 --external:react --external:rxjs --format=esm --sourcemap",
"build:esm2017": "esbuild src/index.tsx --bundle --outfile=./dist/core.esm2017.js --target=es2017 --external:react --external:rxjs --format=esm --sourcemap",
"build:esm2019": "esbuild src/index.tsx --bundle --outfile=./dist/core.es2019.mjs --target=es2019 --external:react --external:rxjs --format=esm --sourcemap",
"build:esm2017": "esbuild src/index.tsx --bundle --outfile=./dist/core.es2017.mjs --target=es2017 --external:react --external:rxjs --format=esm --sourcemap",
"build:cjs:dev": "esbuild src/index.tsx --bundle --outfile=./dist/core.cjs.development.js --target=es2015 --external:react --external:rxjs --format=cjs --sourcemap",
"build:cjs:prod": "esbuild src/index.tsx --bundle --outfile=./dist/core.cjs.production.min.js --target=es2015 --external:react --external:rxjs --format=cjs --minify --sourcemap",
"build:ts": "tsc -p ./tsconfig.json --outDir ./dist --skipLibCheck --emitDeclarationOnly",
"test": "tsdx test --coverage",
"lint": "prettier --check README.md && tsdx lint src",
"build:ts": "tsc -p ./tsconfig-build.json --outDir ./dist --skipLibCheck --emitDeclarationOnly",
"test": "jest --coverage",
"lint": "prettier --check README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"format": "prettier --write README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"prepare": "yarn build"
},
@ -39,22 +41,5 @@
"authors": [
"Josep M Sobrepere (https://github.com/josepot)",
"Victor Oliva (https://github.com/voliva)"
],
"devDependencies": {
"@testing-library/react": "^11.2.6",
"@testing-library/react-hooks": "^5.1.1",
"@types/jest": "^26.0.22",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"esbuild": "^0.11.2",
"jest-marbles": "^2.5.1",
"lint-staged": "^10.5.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-test-renderer": "^17.0.2",
"rxjs": "^6.6.7",
"tsdx": "^0.14.1",
"tslib": "^2.1.0",
"typescript": "^4.2.3"
}
}
]
}

View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom"

View File

@ -46,9 +46,8 @@ export const Subscribe: React.FC<{
subscriptionRef.current = new Subscription()
}
const [subscribedSource, setSubscribedSource] = useState<
Observable<any> | null | undefined
>(null)
const [subscribedSource, setSubscribedSource] =
useState<Observable<any> | null | undefined>(null)
if (subscribedSource !== null && subscribedSource !== source$) {
if (source$ === undefined) {

View File

@ -9,7 +9,6 @@ import {
merge,
EMPTY,
NEVER,
noop,
} from "rxjs"
import { renderHook, act as actHook } from "@testing-library/react-hooks"
import {
@ -145,11 +144,9 @@ describe("connectFactoryObservable", () => {
return from([1, 2, 3, 4, 5])
})
const [
useLatestNumber,
latestNumber$,
] = bind((id: number, value: { val: number }) =>
concat(observable$, of(id + value.val)),
const [useLatestNumber, latestNumber$] = bind(
(id: number, value: { val: number }) =>
concat(observable$, of(id + value.val)),
)
expect(subscriberCount).toBe(0)
@ -835,13 +832,15 @@ describe("connectFactoryObservable", () => {
it("does not crash when the observable lazily references its enhanced self", () => {
const [, obs$] = bind(
(key: number) => defer(() => obs$(key)).pipe(take(1)),
(key) => key,
)
(key: number) => key,
) as [(key: number) => number, (key: number) => Observable<number>]
let error = null
obs$(1)
.subscribe(noop, (e: any) => {
error = e
.subscribe({
error: (e: any) => {
error = e
},
})
.unsubscribe()

View File

@ -33,15 +33,15 @@ export default function connectFactoryObservable<A extends [], O>(
(...args: A) => Observable<O>,
] {
const cache = new NestedMap<A, BehaviorObservable<O>>()
const getDefaultValue = (typeof defaultValue === "function"
? defaultValue
: () => defaultValue) as (...args: A) => O
const getDefaultValue = (
typeof defaultValue === "function" ? defaultValue : () => defaultValue
) as (...args: A) => O
const getSharedObservables$ = (input: A): BehaviorObservable<O> => {
for (let i = input.length - 1; input[i] === undefined && i > -1; i--) {
input.splice(-1)
}
const keys = ([input.length, ...input] as any) as A
const keys = [input.length, ...input] as any as A
const cachedVal = cache.get(keys)
if (cachedVal !== undefined) {

View File

@ -224,7 +224,7 @@ describe("connectObservable", () => {
})
it("suspends the component when the observable emits SUSPENSE", async () => {
const subject$ = new Subject()
const subject$ = new Subject<void>()
const source$ = subject$.pipe(
scan((a) => a + 1, 0),
map((x) => {
@ -264,7 +264,7 @@ describe("connectObservable", () => {
})
it("keeps in suspense if more than two SUSPENSE are emitted in succesion", async () => {
const subject$ = new Subject()
const subject$ = new Subject<void>()
const source$ = subject$.pipe(
scan((a) => a + 1, 0),
map((x) => {
@ -308,7 +308,7 @@ describe("connectObservable", () => {
})
it("correctly unsubscribes when the Subscribe component gets unmounted", async () => {
const subject$ = new Subject()
const subject$ = new Subject<void>()
const [useNumber, number$] = bind(subject$.pipe(scan((a) => a + 1, 0)))
const Result: React.FC = () => <div>Result {useNumber()}</div>

View File

@ -51,10 +51,9 @@ export function bind<A extends unknown[], O>(
): [(...args: A) => Exclude<O, typeof SUSPENSE>, (...args: A) => Observable<O>]
export function bind(observable: any, defaultValue: any) {
return (typeof observable === "function"
? (connectFactoryObservable as any)
: connectObservable)(
observable,
arguments.length > 1 ? defaultValue : EMPTY_VALUE,
)
return (
typeof observable === "function"
? (connectFactoryObservable as any)
: connectObservable
)(observable, arguments.length > 1 ? defaultValue : EMPTY_VALUE)
}

View File

@ -49,22 +49,22 @@ const shareLatest = <T>(
subject = new Subject<T>()
innerSub = subject.subscribe(subscriber)
subscription = null
subscription = new Subscriber<T>(
(value: T) => {
subscription = new Subscriber<T>({
next: (value: T) => {
subject!.next((currentValue = value))
},
(err: any) => {
error: (err: any) => {
const _subject = subject
subscription = null
subject = null
_subject!.error(err)
},
() => {
complete: () => {
subscription = null
emitIfEmpty()
subject!.complete()
},
)
})
source$.subscribe(subscription)
emitIfEmpty()
} else {

View File

@ -56,7 +56,7 @@ describe("shareLatest", () => {
const values$ = hot('----b-c-d---')
const latest$ = hot('----------x-')
const expected = ' a---b-c-d-d-'
const input$ = merge(
const input$: any = merge(
values$,
latest$.pipe(
withLatestFrom(defer(() => result$)),
@ -64,7 +64,7 @@ describe("shareLatest", () => {
)
)
const result$ = input$.pipe(
const result$: any = input$.pipe(
startWith('a'),
shareLatest()
)

View File

@ -16,6 +16,7 @@ import { EMPTY_VALUE } from "./internal/empty-value"
* @remarks The enhanced observables returned from `connectObservable` and
* `connectFactoryObservable` have been enhanced with this operator.
*/
export const shareLatest = <T>(): MonoTypeOperatorFunction<T> => (
source$: Observable<T>,
) => internalShareLatest(source$, EMPTY_VALUE)
export const shareLatest =
<T>(): MonoTypeOperatorFunction<T> =>
(source$: Observable<T>) =>
internalShareLatest(source$, EMPTY_VALUE)

View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/*.test.*", "**/test-helpers/*.*"]
}

View File

@ -1,7 +1,7 @@
{
"include": ["src"],
"compilerOptions": {
"target": "es5",
"target": "esnext",
"module": "esnext",
"lib": ["dom", "esnext"],
"importHelpers": true,
@ -26,6 +26,5 @@
},
"jsx": "react",
"esModuleInterop": true
},
"exclude": ["**/*.test.*", "**/test-helpers/*.*"]
}
}

View File

@ -1,7 +1,13 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "jsdom",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
setupFilesAfterEnv: ["<rootDir>/setupTests.ts"],
globals: {
"ts-jest": {
diagnostics: false,
babelConfig: true,
},
},
}

View File

@ -6,23 +6,26 @@
},
"license": "MIT",
"sideEffects": false,
"exports": "dist/dom.esm2019.js",
"module": "dist/dom.esm2017.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"exports": {
"import": "./dist/dom.es2019.mjs",
"require": "./dist/index.cjs"
},
"module": "./dist/dom.es2017.mjs",
"main": "./dist/index.cjs",
"typings": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"start": "tsdx watch",
"build": "yarn build:ts && yarn build:esm2017 && yarn build:esm2019 && yarn build:cjs:dev && yarn build:cjs:prod",
"build:esm2019": "esbuild src/index.tsx --bundle --outfile=./dist/dom.esm2019.js --target=es2019 --external:react --external:rxjs --external:react-dom --format=esm --sourcemap",
"build:esm2017": "esbuild src/index.tsx --bundle --outfile=./dist/dom.esm2017.js --target=es2017 --external:react --external:rxjs --external:react-dom --format=esm --sourcemap",
"build:esm2019": "esbuild src/index.tsx --bundle --outfile=./dist/dom.es2019.mjs --target=es2019 --external:react --external:rxjs --external:react-dom --format=esm --sourcemap",
"build:esm2017": "esbuild src/index.tsx --bundle --outfile=./dist/dom.es2017.mjs --target=es2017 --external:react --external:rxjs --external:react-dom --format=esm --sourcemap",
"build:cjs:dev": "esbuild src/index.tsx --bundle --outfile=./dist/dom.cjs.development.js --target=es2015 --external:react --external:rxjs --external:react-dom --format=cjs --sourcemap",
"build:cjs:prod": "esbuild src/index.tsx --bundle --outfile=./dist/dom.cjs.production.min.js --target=es2015 --external:react --external:rxjs --external:react-dom --format=cjs --minify --sourcemap",
"build:ts": "tsc -p ./tsconfig.json --outDir ./dist --skipLibCheck --emitDeclarationOnly",
"test": "tsdx test --coverage",
"lint": "prettier --check README.md && tsdx lint src",
"test": "jest --coverage",
"lint": "prettier --check README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"format": "prettier --write README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"prepare": "yarn build"
},
@ -42,19 +45,6 @@
"Victor Oliva (https://github.com/voliva)"
],
"devDependencies": {
"@react-rxjs/core": "0.8.0",
"@testing-library/react": "^11.2.6",
"@testing-library/react-hooks": "^5.1.1",
"@types/jest": "^26.0.22",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"jest-marbles": "^2.5.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-test-renderer": "^17.0.2",
"rxjs": "^6.6.7",
"tsdx": "^0.14.1",
"tslib": "^2.1.0",
"typescript": "^4.2.3"
"@react-rxjs/core": "0.8.0"
}
}
}

View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom"

View File

@ -12,31 +12,31 @@ import { unstable_batchedUpdates } from "react-dom"
* automatically batches all synchronous updates. Meaning that with React CM,
* observing a stream through the asapScheduler accomplishes the same thing.
*/
export const batchUpdates = <T>() => (
source$: Observable<T>,
): Observable<T> => {
return new Observable<T>((observer) => {
const obs = {
n: (v: T) => observer.next(v),
c: () => observer.complete(),
e: (e: any) => observer.error(e),
}
let queue: ["n" | "c" | "e", any?][] = []
let promise: Promise<void> | null = null
const flush = () => {
promise = null
const originalQueue = queue
queue = []
unstable_batchedUpdates(() => {
originalQueue.forEach(([prop, val]) => obs[prop](val))
})
}
const push = (type: "n" | "c" | "e") => (val?: any) => {
queue.push([type, val])
if (!promise) {
promise = Promise.resolve().then(flush)
export const batchUpdates =
<T>() =>
(source$: Observable<T>): Observable<T> => {
return new Observable<T>((observer) => {
const obs = {
n: (v: T) => observer.next(v),
c: () => observer.complete(),
e: (e: any) => observer.error(e),
}
}
return source$.subscribe(push("n"), push("e"), push("c"))
})
}
let queue: ["n" | "c" | "e", any?][] = []
let promise: Promise<void> | null = null
const flush = () => {
promise = null
const originalQueue = queue
queue = []
unstable_batchedUpdates(() => {
originalQueue.forEach(([prop, val]) => obs[prop](val))
})
}
const push = (type: "n" | "c" | "e") => (val?: any) => {
queue.push([type, val])
if (!promise) {
promise = Promise.resolve().then(flush)
}
}
return source$.subscribe(push("n"), push("e"), push("c"))
})
}

View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/*.test.*", "**/test-helpers/*.*"]
}

View File

@ -1,7 +1,7 @@
{
"include": ["src"],
"compilerOptions": {
"target": "es5",
"target": "esnext",
"module": "esnext",
"lib": ["dom", "esnext"],
"importHelpers": true,
@ -26,6 +26,5 @@
},
"jsx": "react",
"esModuleInterop": true
},
"exclude": ["**/*.test.ts"]
}
}

View File

@ -1,7 +1,13 @@
module.exports = {
preset: "ts-jest",
testEnvironment: "jsdom",
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
setupFilesAfterEnv: ["<rootDir>/setupTests.ts"],
globals: {
"ts-jest": {
diagnostics: false,
babelConfig: true,
},
},
}

View File

@ -6,23 +6,25 @@
},
"license": "MIT",
"sideEffects": false,
"exports": "dist/utils.esm2019.js",
"module": "dist/utils.esm2017.js",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"exports": {
"import": "./dist/utils.es2019.mjs",
"require": "./dist/index.cjs"
},
"module": "./dist/utils.es2017.mjs",
"main": "./dist/index.cjs",
"typings": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"start": "tsdx watch",
"build": "yarn build:ts && yarn build:esm2017 && yarn build:esm2019 && yarn build:cjs:dev && yarn build:cjs:prod",
"build:esm2019": "esbuild src/index.tsx --bundle --outfile=./dist/utils.esm2019.js --target=es2019 --external:react --external:rxjs --external:@react-rxjs/core --format=esm --sourcemap",
"build:esm2017": "esbuild src/index.tsx --bundle --outfile=./dist/utils.esm2017.js --target=es2017 --external:react --external:rxjs --external:@react-rxjs/core --format=esm --sourcemap",
"build:esm2019": "esbuild src/index.tsx --bundle --outfile=./dist/utils.es2019.mjs --target=es2019 --external:react --external:rxjs --external:@react-rxjs/core --format=esm --sourcemap",
"build:esm2017": "esbuild src/index.tsx --bundle --outfile=./dist/utils.es2017.mjs --target=es2017 --external:react --external:rxjs --external:@react-rxjs/core --format=esm --sourcemap",
"build:cjs:dev": "esbuild src/index.tsx --bundle --outfile=./dist/utils.cjs.development.js --target=es2015 --external:react --external:rxjs --external:@react-rxjs/core --format=cjs --sourcemap",
"build:cjs:prod": "esbuild src/index.tsx --bundle --outfile=./dist/utils.cjs.production.min.js --target=es2015 --external:react --external:rxjs --external:@react-rxjs/core --format=cjs --minify --sourcemap",
"build:ts": "tsc -p ./tsconfig.json --outDir ./dist --skipLibCheck --emitDeclarationOnly",
"test": "tsdx test --coverage",
"lint": "prettier --check README.md && tsdx lint src",
"build:ts": "tsc -p ./tsconfig-build.json --outDir ./dist --skipLibCheck --emitDeclarationOnly",
"test": "jest --coverage",
"lint": "prettier --check README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"format": "prettier --write README.md \"src/**/*.{js,jsx,ts,tsx,json,md}\"",
"prepare": "yarn build"
},
@ -42,19 +44,6 @@
"Victor Oliva (https://github.com/voliva)"
],
"devDependencies": {
"@react-rxjs/core": "0.8.0",
"@testing-library/react": "^11.2.6",
"@testing-library/react-hooks": "^5.1.1",
"@types/jest": "^26.0.22",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"jest-marbles": "^2.5.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-test-renderer": "^17.0.2",
"rxjs": "^6.6.7",
"tsdx": "^0.14.1",
"tslib": "^2.1.0",
"typescript": "^4.2.3"
"@react-rxjs/core": "0.8.0"
}
}
}

View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom"

View File

@ -16,7 +16,7 @@ describe("collect", () => {
string,
string
>
result.key = key
;(result as any).key = key
return result
}

View File

@ -11,14 +11,16 @@ const scheduler = () =>
describe("combineKeys", () => {
it("emits a map with the latest value of the stream of each key", () => {
scheduler().run(({ expectObservable, cold }) => {
const keys = cold(" ab---cd---").pipe(scan((acc, v) => [...acc, v], []))
const keys = cold(" ab---cd---").pipe(
scan((acc, v) => [...acc, v], [] as Array<string>),
)
const a = cold(" --1---2---")
const b = cold(" ---------")
const c = cold(" 1----")
const d = cold(" 9---")
const expectedStr = "--e--f(gh)"
const innerStreams = { a, b, c, d }
const innerStreams: Record<string, Observable<string>> = { a, b, c, d }
const result = combineKeys(
keys,
@ -36,14 +38,16 @@ describe("combineKeys", () => {
it("doesn't emit if the inner value hasn't changed", () => {
scheduler().run(({ expectObservable, cold }) => {
const keys = cold(" ab---cd---").pipe(scan((acc, v) => [...acc, v], []))
const keys = cold(" ab---cd---").pipe(
scan((acc, v) => [...acc, v], [] as Array<string>),
)
const a = cold(" --11112---")
const b = cold(" ---------")
const c = cold(" 1----")
const d = cold(" 9---")
const expectedStr = "--e--f(gh)"
const innerStreams = { a, b, c, d }
const innerStreams: Record<string, Observable<string>> = { a, b, c, d }
const result = combineKeys(
keys,
@ -67,7 +71,7 @@ describe("combineKeys", () => {
const c = cold(" ---5")
const expectedStr = "e--f"
const innerStreams = { a, b, c }
const innerStreams: Record<string, Observable<string>> = { a, b, c }
const result = combineKeys(
keys,
@ -89,7 +93,7 @@ describe("combineKeys", () => {
const c = cold(" -2-3")
const expectedStr = "---e-fgh-i"
const innerStreams = { a, b, c }
const innerStreams: Record<string, Observable<string>> = { a, b, c }
const result = combineKeys(
keys,
@ -108,12 +112,14 @@ describe("combineKeys", () => {
it("completes when the key stream completes", () => {
scheduler().run(({ expectObservable, cold }) => {
const keys = cold(" a-b---|").pipe(scan((acc, v) => [...acc, v], []))
const keys = cold(" a-b---|").pipe(
scan((acc, v) => [...acc, v], [] as Array<string>),
)
const a = cold(" -1-----")
const b = cold(" -1---")
const expectedStr = "-e-f--|"
const innerStreams = { a, b }
const innerStreams: Record<string, Observable<string>> = { a, b }
const result = combineKeys(
keys,
@ -129,12 +135,14 @@ describe("combineKeys", () => {
it("propagates errors from the inner streams", () => {
scheduler().run(({ expectObservable, cold }) => {
const keys = cold(" a-b---|").pipe(scan((acc, v) => [...acc, v], []))
const keys = cold(" a-b---|").pipe(
scan((acc, v) => [...acc, v], [] as Array<string>),
)
const a = cold(" -1-----")
const b = cold(" -#")
const expectedStr = "-e-#"
const innerStreams = { a, b }
const innerStreams: Record<string, Observable<string>> = { a, b }
const result = combineKeys(
keys,
@ -149,12 +157,14 @@ describe("combineKeys", () => {
it("propagates errors from the key stream", () => {
scheduler().run(({ expectObservable, cold }) => {
const keys = cold(" a-b#").pipe(scan((acc, v) => [...acc, v], []))
const keys = cold(" a-b#").pipe(
scan((acc, v) => [...acc, v], [] as Array<string>),
)
const a = cold(" -1--")
const b = cold(" -1")
const expectedStr = "-e-#"
const innerStreams = { a, b }
const innerStreams: Record<string, Observable<string>> = { a, b }
const result = combineKeys(
keys,
@ -180,7 +190,7 @@ describe("combineKeys", () => {
const b = cold(" 2---")
const expectedStr = "efgef"
const innerStreams = { a, b }
const innerStreams: Record<string, Observable<string>> = { a, b }
const result = combineKeys(
keys,

View File

@ -19,7 +19,7 @@ export function contextBinder<
A extends (() => any)[],
OT extends {
[K in keyof A]: A[K] extends () => infer V ? V : unknown
}
},
>(
...args: A
): <AA extends any[], T, ARGS extends [...OT, ...AA]>(

View File

@ -72,7 +72,7 @@ export function createKeyedSignal<K, T, A extends any[]>(
}
}
}) as GroupedObservable<K, T>
res.key = key
;(res as any).key = key
return res
},
(...args: A) => {

View File

@ -17,7 +17,7 @@ describe("getGroupedObservable", () => {
string,
string
>
result.key = key
;(result as any).key = key
return result
}

View File

@ -22,6 +22,6 @@ export const getGroupedObservable = <K, T>(
outterSub.unsubscribe()
}
}) as GroupedObservable<K, T>
result.key = key
;(result as any).key = key
return result
}

View File

@ -1,69 +1,73 @@
import { Observable, GroupedObservable, Subscription } from "rxjs"
import { shareLatest } from "@react-rxjs/core"
export const defaultStart = <T, D>(value: D) => (source$: Observable<T>) =>
new Observable<T | D>((observer) => {
let emitted = false
const subscription = source$.subscribe(
(x) => {
emitted = true
observer.next(x)
},
(e) => {
observer.error(e)
},
() => {
observer.complete()
},
)
if (!emitted) {
observer.next(value)
}
return subscription
})
export const collector = <K, V, VV>(
enhancer: (source: GroupedObservable<K, V>) => Observable<VV>,
): ((
source: Observable<GroupedObservable<K, V>>,
) => Observable<Map<K, VV>>) => (source$) =>
new Observable<Map<K, VV>>((observer) => {
const subscription = new Subscription()
const map = new Map<K, VV>()
let emitted = false
subscription.add(
source$.subscribe(
export const defaultStart =
<T, D>(value: D) =>
(source$: Observable<T>) =>
new Observable<T | D>((observer) => {
let emitted = false
const subscription = source$.subscribe(
(x) => {
subscription.add(
enhancer(x).subscribe(
(v) => {
map.set(x.key, v)
emitted = true
observer.next(map)
},
(e) => {
observer.error(e)
},
() => {
map.delete(x.key)
observer.next(map)
},
),
)
emitted = true
observer.next(x)
},
(e) => {
observer.error(e)
},
() => {
map.clear()
observer.next(map)
observer.complete()
},
),
)
if (!emitted) observer.next(map)
return subscription
}).pipe(shareLatest())
)
if (!emitted) {
observer.next(value)
}
return subscription
})
export const collector =
<K, V, VV>(
enhancer: (source: GroupedObservable<K, V>) => Observable<VV>,
): ((
source: Observable<GroupedObservable<K, V>>,
) => Observable<Map<K, VV>>) =>
(source$) =>
new Observable<Map<K, VV>>((observer) => {
const subscription = new Subscription()
const map = new Map<K, VV>()
let emitted = false
subscription.add(
source$.subscribe(
(x) => {
subscription.add(
enhancer(x).subscribe(
(v) => {
map.set(x.key, v)
emitted = true
observer.next(map)
},
(e) => {
observer.error(e)
},
() => {
map.delete(x.key)
observer.next(map)
},
),
)
},
(e) => {
observer.error(e)
},
() => {
map.clear()
observer.next(map)
observer.complete()
},
),
)
if (!emitted) observer.next(map)
return subscription
}).pipe(shareLatest())

View File

@ -13,13 +13,13 @@ export const mergeWithKey: <
[K in keyof O]: O[K] extends ObservableInput<infer V>
? { type: K; payload: V }
: unknown
}
},
>(
x: O,
concurrent?: number,
scheduler?: SchedulerLike,
) => Observable<OT[keyof O]> = (input, ...optionalArgs) =>
merge(
merge<any[]>(
...(Object.entries(input)
.map(
([type, stream]) =>

View File

@ -1,4 +1,4 @@
import { NEVER, Subject } from "rxjs"
import { NEVER, Observable, Subject } from "rxjs"
import { switchMap, take } from "rxjs/operators"
import { TestScheduler } from "rxjs/testing"
import { partitionByKey } from "./"
@ -37,7 +37,7 @@ describe("partitionByKey", () => {
const b = cold(" ---|")
const c = cold(" 1-|")
const expectedStr = "efg--hi-j"
const innerStreams = { a, b, c }
const innerStreams: Record<string, Observable<any>> = { a, b, c }
const [, result] = partitionByKey(
source,
(v) => v,
@ -71,7 +71,7 @@ describe("partitionByKey", () => {
const expectB = " -----|"
const expectC = " ------1-|"
const innerStreams = { a, b, c }
const innerStreams: Record<string, Observable<any>> = { a, b, c }
const [getInstance$] = partitionByKey(
source,
(v) => v,

View File

@ -55,11 +55,13 @@ export function split<T, K, R>(
: new ReplaySubject<T>(1)
groups.set(key, subject)
const res = (streamSelector
? streamSelector(subject, key).pipe(shareReplay(1))
: subject.asObservable()) as GroupedObservable<K, R>
const res = (
streamSelector
? streamSelector(subject, key).pipe(shareReplay(1))
: subject.asObservable()
) as GroupedObservable<K, R>
res.key = key
;(res as any).key = key
const onFinish = () => groups.delete(key)
res.subscribe(noop, onFinish, onFinish)

View File

@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["**/*.test.*", "**/test-helpers/*.*"]
}

View File

@ -1,7 +1,7 @@
{
"include": ["src"],
"compilerOptions": {
"target": "es5",
"target": "esnext",
"module": "esnext",
"lib": ["dom", "esnext"],
"importHelpers": true,
@ -26,6 +26,5 @@
},
"jsx": "react",
"esModuleInterop": true
},
"exclude": ["**/*.test.*"]
}
}

6006
yarn.lock

File diff suppressed because it is too large Load Diff