Skip to content

feat: use workers for streamListDiff #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/node_modules
dist
.eslintcache
.eslintcache
# Ignore generated worker files
src/lib/stream-list-diff/server/worker/node-worker.cjs
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,12 @@ type ObjectDiff = {
diff: Diff[];
};

/** recursive diff in case of subproperties */
type Diff = {
property: string;
previousValue: unknown;
currentValue: unknown;
status: "added" | "deleted" | "equal" | "updated";
// recursive diff in case of subproperties
diff?: Diff[];
};
```
Expand Down Expand Up @@ -307,13 +307,15 @@ getListDiff(

```js
// If you are in a server environment
import { streamListDiff } from "@donedeal0/superdiff/server";
import { streamListDiff } from "@donedeal0/superdiff/server.cjs";
// If you are in a browser environment
import { streamListDiff } from "@donedeal0/superdiff/client";
```

Streams the diff of two object lists, ideal for large lists and maximum performance.

ℹ️ `streamListDiff` requires ESM support for browser usage. It will work out of the box if you use a modern bundler (Webpack, Rollup) or JavaScript framework (Next.js, Vue.js).

#### FORMAT

**Input**
Expand All @@ -330,6 +332,8 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default
chunksSize?: number, // 0 by default
considerMoveAsUpdate?: boolean; // false by default
useWorker?: boolean; // true by default
showWarnings?: boolean; // true by default
}
```

Expand All @@ -345,6 +349,9 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
showOnly?: ("added" | "deleted" | "moved" | "updated" | "equal")[], // [] by default
chunksSize?: number, // 0 by default
considerMoveAsUpdate?: boolean; // false by default
useWorker?: boolean; // true by default
showWarnings?: boolean; // true by default

}
```

Expand All @@ -355,6 +362,10 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
- `chunksSize` the number of object diffs returned by each streamed chunk. (e.g. `0` = 1 object diff per chunk, `10` = 10 object diffs per chunk).
- `showOnly` gives you the option to return only the values whose status you are interested in (e.g. `["added", "equal"]`).
- `considerMoveAsUpdate`: if set to `true` a `moved` value will be considered as `updated`.
- `useWorker`: if set to `true`, the diff will be run in a worker for maximum performance. Only recommended for large lists (e.g. +100,000 items).
- `showWarnings`: if set to `true`, potential warnings will be displayed in the console.

> ⚠️ Warning: using Readable streams may impact workers' performance since they need to be converted to arrays. Consider using arrays or files for optimal performance. Alternatively, you can turn the `useWorker` option off.

**Output**

Expand All @@ -364,20 +375,12 @@ The objects diff are grouped into arrays - called `chunks` - and are consumed th
- `error`: to be notified if an error occurs during the stream.

```ts
interface StreamListener<T extends Record<string, unknown>> {
on<E extends keyof EmitterEvents<T>>(
event: E,
listener: Listener<EmitterEvents<T>[E]>,
): this;
interface StreamListener<T> {
on(event: "data", listener: (chunk: StreamListDiff<T>[]) => void);
on(event: "finish", listener: () => void);
on(event: "error", listener: (error: Error) => void);
}

type EmitterEvents<T extends Record<string, unknown>> = {
data: [StreamListDiff<T>[]];
error: [Error];
finish: [];
};


type StreamListDiff<T extends Record<string, unknown>> = {
currentValue: T | null;
previousValue: T | null;
Expand Down
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import tseslint from "typescript-eslint";

export default [
{ files: ["**/*.{js,mjs,cjs,ts}"] },
{ ignores: ["dist", "jest.config.js"] },
{ ignores: ["dist", "jest.config.js", "src/lib/stream-list-diff/server/worker/node-worker.cjs"] },
{ settings: { react: { version: "detect" } } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
Expand Down
Empty file removed index.ts
Empty file.
12 changes: 9 additions & 3 deletions jest.config.js → jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module.exports = {
import type { Config } from "jest";

const config: Config = {
transform: {
"^.+\\.(ts|js)$": [
"^.+\\.(ts|js)$": [
"@swc/jest",
{
jsc: {
Expand All @@ -11,13 +13,17 @@ module.exports = {
dynamicImport: true,
},
paths: {
"@mocks/*": ["./src/mocks/*"],
"@models/*": ["./src/models/*"],
"@lib/*": ["./src/lib/*"],

},
target: "esnext",
},
},
],
},
testEnvironment: "node",
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
};

export default config;
5 changes: 5 additions & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { TextEncoder, TextDecoder } from "util";

global.TextEncoder = TextEncoder;
//@ts-expect-error - the TextDecoder is valid
global.TextDecoder = TextDecoder;
Loading