-
-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Init new package * Add API and typetests * Add base docs * Add implementation of startChain * Add implementation of freshChain * Introduce `@farfetched/atomic-router` * Fix types error * Increase size * Handle params passing
- Loading branch information
1 parent
302e380
commit 7790cb2
Showing
26 changed files
with
719 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@farfetched/atomic-router': patch | ||
'@farfetched/core': patch | ||
--- | ||
|
||
Introduce `@farfetched/atomic-router` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
--- | ||
outline: [2, 3] | ||
--- | ||
|
||
# Farfetched and Atomic Router | ||
|
||
Integration is distributed as a separate package, you have to install it and its peer dependencies before usage: | ||
|
||
::: code-group | ||
|
||
```sh [pnpm] | ||
pnpm install atomic-router @farfetched/atomic-router | ||
``` | ||
|
||
```sh [yarn] | ||
yarn add atomic-router @farfetched/atomic-router | ||
``` | ||
|
||
```sh [npm] | ||
npm install atomic-router @farfetched/atomic-router | ||
``` | ||
|
||
::: | ||
|
||
## API | ||
|
||
::: warning | ||
Atomic Router is still in development, so the API is not stable yet. This integration is tested with `[email protected]`, but it should work with any version of `atomic-router`. | ||
::: | ||
|
||
Integration provides the way to use any [_Query_](/api/primitives/query) in [`chainRoute` operator](https://atomic-router.github.io/api/chain-route.html). It has two options to transform [_Query_](/api/primitives/query) to the shape that `chainRoute` expects: | ||
|
||
### `freshChain` | ||
|
||
After opening a route with `freshChain`, `.refresh` [_Event_](https://effector.dev/docs/api/effector/event) would be executed. So, [_Query_](/api/primitives/query) will be **executed only if it is already `.$stale`**. | ||
|
||
```ts | ||
import { createJsonQuery } from '@farfetched/core'; | ||
import { freshChain } from '@farfetched/atomic-router'; | ||
import { chainRoute, createRoute } from 'atmoic-router'; | ||
|
||
const postRoute = createRoute<{ postId: string }>(); | ||
|
||
const postQuery = createJsonQuery({ | ||
/* ... */ | ||
}); | ||
|
||
const postLoadedRoute = chainRoute({ | ||
route: postRoute, | ||
...freshChain(postQuery), | ||
}); | ||
``` | ||
|
||
### `startChain` | ||
|
||
After opening a route with `freshChain`, `.start` [_Event_](https://effector.dev/docs/api/effector/event) would be executed. So, [_Query_](/api/primitives/query) will be **executed unconditionally**. | ||
|
||
```ts | ||
import { createJsonQuery } from '@farfetched/core'; | ||
import { startChain } from '@farfetched/atomic-router'; | ||
import { chainRoute, createRoute } from 'atmoic-router'; | ||
|
||
const postRoute = createRoute<{ postId: string }>(); | ||
|
||
const postQuery = createJsonQuery({ | ||
/* ... */ | ||
}); | ||
|
||
const postLoadedRoute = chainRoute({ | ||
route: postRoute, | ||
...startChain(postQuery), | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"presets": [ | ||
[ | ||
"@nrwl/js/babel", | ||
{ | ||
"useBuiltIns": false | ||
} | ||
] | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"extends": ["../../.eslintrc.json"], | ||
"ignorePatterns": ["!**/*", "node_modules"], | ||
"overrides": [ | ||
{ | ||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.ts", "*.tsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.js", "*.jsx"], | ||
"rules": {} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# @farfetched/atomic-router |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# atomic-router | ||
|
||
This library was generated with [Nx](https://nx.dev). | ||
|
||
## Building | ||
|
||
Run `nx build atomic-router` to build the library. | ||
|
||
## Running unit tests | ||
|
||
Run `nx test atomic-router` to execute the unit tests via [Jest](https://jestjs.io). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { freshChain } from './src/fresh'; | ||
export { startChain } from './src/start'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"name": "@farfetched/atomic-router", | ||
"version": "0.0.1", | ||
"type": "commonjs" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
{ | ||
"name": "atomic-router", | ||
"$schema": "../../node_modules/nx/schemas/project-schema.json", | ||
"sourceRoot": "packages/atomic-router/src", | ||
"projectType": "library", | ||
"targets": { | ||
"pack": { | ||
"executor": "nx:run-commands", | ||
"options": { | ||
"command": "node tools/scripts/typepack.mjs --package atomic-router" | ||
}, | ||
"dependsOn": [ | ||
{ | ||
"projects": "self", | ||
"target": "build" | ||
} | ||
] | ||
}, | ||
"build": { | ||
"executor": "@nrwl/rollup:rollup", | ||
"outputs": ["{options.outputPath}"], | ||
"options": { | ||
"project": "packages/atomic-router/package.json", | ||
"outputPath": "dist/packages/atomic-router", | ||
"entryFile": "packages/atomic-router/index.ts", | ||
"tsConfig": "packages/atomic-router/tsconfig.json", | ||
"format": ["esm", "cjs"], | ||
"generateExportsField": true, | ||
"compiler": "babel" | ||
} | ||
}, | ||
"publish": { | ||
"executor": "nx:run-commands", | ||
"options": { | ||
"command": "node tools/scripts/publish.mjs atomic-router" | ||
}, | ||
"dependsOn": [ | ||
{ | ||
"projects": "self", | ||
"target": "pack" | ||
} | ||
] | ||
}, | ||
"lint": { | ||
"executor": "@nrwl/linter:eslint", | ||
"outputs": ["{options.outputFile}"], | ||
"options": { | ||
"lintFilePatterns": ["packages/atomic-router/**/*.ts"] | ||
} | ||
}, | ||
"test": { | ||
"executor": "@nrwl/vite:test", | ||
"options": { | ||
"config": "vite.config.ts" | ||
} | ||
}, | ||
"typetest": { | ||
"executor": "@nrwl/vite:test", | ||
"options": { | ||
"config": "vite.config.ts", | ||
"mode": "typecheck" | ||
} | ||
}, | ||
"size": { | ||
"executor": "./tools/executors/size-limit:size-limit", | ||
"options": { | ||
"limit": "0.6 kB", | ||
"outputPath": "dist/packages/atomic-router" | ||
}, | ||
"dependsOn": [ | ||
{ | ||
"projects": "self", | ||
"target": "build" | ||
} | ||
] | ||
} | ||
}, | ||
"implicitDependencies": ["!test-utils"], | ||
"tags": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/** | ||
* Copy-pasted, original author is https://github.com/AlexandrHoroshih | ||
*/ | ||
import { test, expect, vi } from 'vitest'; | ||
|
||
import { createDefer } from '../defer'; | ||
|
||
test('returns promise that is resolved by command', async () => { | ||
const def = createDefer<number>(); | ||
|
||
setTimeout(() => def.resolve(7), 1); | ||
await expect(def.promise).resolves.toEqual(7); | ||
}); | ||
|
||
test('returns promise that is rejected by command', async () => { | ||
const def = createDefer<number>(); | ||
|
||
setTimeout(() => def.reject(7), 1); | ||
await expect(def.promise).rejects.toEqual(7); | ||
}); | ||
|
||
test('does not leave unhandled rejection, if now awaited', async () => { | ||
const rejected = vi.fn(); | ||
process.on('unhandledRejection', rejected); | ||
|
||
const def = createDefer(); | ||
def.reject(); | ||
|
||
await new Promise((r) => { | ||
setTimeout(r); | ||
}); | ||
|
||
expect(rejected).toBeCalledTimes(0); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
|
||
import { describe, test } from 'vitest'; | ||
import { type Query } from '@farfetched/core'; | ||
import { chainRoute, createRoute, RouteParamsAndQuery } from 'atomic-router'; | ||
|
||
import { freshChain } from '../fresh'; | ||
|
||
describe('freshChain', () => { | ||
test('infer params type from route, no mapping', () => { | ||
const correctQuery: Query<{ id: number }, number, string> = {} as any; | ||
|
||
const chainedRoute = chainRoute({ | ||
route: createRoute<{ id: number }>(), | ||
...freshChain(correctQuery), | ||
}); | ||
|
||
const incorrectQuery: Query<{ id: string }, number, string> = {} as any; | ||
|
||
// @ts-expect-error incorrect params type | ||
const incorrectChainedRoute = chainRoute({ | ||
route: createRoute<{ id: number }>(), | ||
...freshChain(incorrectQuery), | ||
}); | ||
}); | ||
|
||
test('infer params type from route, void query', () => { | ||
const someRoute = createRoute<{ id: number }>(); | ||
|
||
const correctQuery: Query<void, number, string> = {} as any; | ||
|
||
const chainedRoute = chainRoute({ | ||
route: someRoute, | ||
...freshChain(correctQuery), | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { createQuery } from '@farfetched/core'; | ||
import { chainRoute, createRoute } from 'atomic-router'; | ||
import { allSettled, createWatch, fork } from 'effector'; | ||
import { describe, expect, test, vi } from 'vitest'; | ||
|
||
import { createDefer } from '../defer'; | ||
import { freshChain } from '../fresh'; | ||
|
||
describe('freshChain', () => { | ||
test('should start query after beforeOpen call and call openOn, respect $stale state', async () => { | ||
const firstDefer = createDefer(); | ||
const secondDefer = createDefer(); | ||
|
||
const handler = vi | ||
.fn() | ||
.mockImplementationOnce(() => firstDefer.promise) | ||
.mockImplementationOnce(() => secondDefer.promise); | ||
|
||
const query = createQuery({ handler }); | ||
const chain = freshChain(query); | ||
|
||
const scope = fork(); | ||
|
||
const openOnListener = vi.fn(); | ||
createWatch({ unit: chain.openOn, fn: openOnListener, scope }); | ||
const cancelOnListener = vi.fn(); | ||
createWatch({ unit: chain.cancelOn, fn: cancelOnListener, scope }); | ||
|
||
// First open — execute | ||
allSettled(chain.beforeOpen, { | ||
scope, | ||
params: { params: 1, query: {} }, | ||
}); | ||
|
||
expect(handler).toBeCalledTimes(1); | ||
expect(openOnListener).not.toBeCalled(); | ||
expect(cancelOnListener).not.toBeCalled(); | ||
|
||
firstDefer.resolve(null); | ||
await allSettled(scope); | ||
|
||
expect(openOnListener).toBeCalledTimes(1); | ||
expect(cancelOnListener).not.toBeCalled(); | ||
|
||
// Second open — just openOp immediately | ||
await allSettled(chain.beforeOpen, { | ||
scope, | ||
params: { params: 1, query: {} }, | ||
}); | ||
|
||
expect(handler).toBeCalledTimes(1); | ||
expect(openOnListener).toBeCalledTimes(2); | ||
expect(cancelOnListener).not.toBeCalled(); | ||
|
||
// Third open — execute, because of changed params | ||
allSettled(chain.beforeOpen, { | ||
scope, | ||
params: { params: 2, query: {} }, | ||
}); | ||
|
||
expect(handler).toBeCalledTimes(2); | ||
expect(openOnListener).toBeCalledTimes(2); | ||
expect(cancelOnListener).not.toBeCalled(); | ||
|
||
secondDefer.resolve(null); | ||
await allSettled(scope); | ||
|
||
expect(openOnListener).toBeCalledTimes(3); | ||
expect(cancelOnListener).not.toBeCalled(); | ||
}); | ||
|
||
test('pass route params to query', async () => { | ||
const handler = vi.fn().mockImplementation(() => null); | ||
const query = createQuery({ | ||
handler, | ||
}); | ||
|
||
const route = createRoute<{ id: number }>(); | ||
const chainedRoute = chainRoute({ route, ...freshChain(query) }); | ||
|
||
const scope = fork(); | ||
|
||
await allSettled(route.open, { scope, params: { id: 1 } }); | ||
|
||
expect(handler).toBeCalledTimes(1); | ||
expect(handler).toBeCalledWith({ id: 1 }); | ||
|
||
await allSettled(route.open, { scope, params: { id: 2 } }); | ||
|
||
expect(handler).toBeCalledTimes(2); | ||
expect(handler).toBeCalledWith({ id: 2 }); | ||
}); | ||
}); |
Oops, something went wrong.