@botejs/core 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -20
- package/dist/cursor.d.ts +0 -7
- package/dist/cursor.js +0 -5
- package/dist/index.d.ts +1 -1
- package/dist/open.d.ts +3 -11
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,22 +7,15 @@ npm install @botejs/core
|
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
|
|
11
|
-
import { join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
12
11
|
import { open, fromFile } from '@botejs/core';
|
|
13
12
|
|
|
14
13
|
// 181 MB GeoJSON:
|
|
15
14
|
// { type: "...", features: [{ properties: { STREET: "..." }}] }
|
|
16
|
-
const filePath =
|
|
15
|
+
const filePath = fileURLToPath(new URL('../citylots.json', import.meta.url));
|
|
17
16
|
|
|
18
17
|
await using cursor = await open(fromFile(filePath));
|
|
19
18
|
|
|
20
|
-
console.log(`type: ${await cursor.get('type')}`);
|
|
21
|
-
// type: 'FeatureCollection'
|
|
22
|
-
|
|
23
|
-
console.log(`features: ${await cursor.count('features')}`);
|
|
24
|
-
// features: 206_560
|
|
25
|
-
|
|
26
19
|
const byStreet = await cursor
|
|
27
20
|
.iter('features', {
|
|
28
21
|
select: ['properties', 'STREET'],
|
|
@@ -35,21 +28,34 @@ const byStreet = await cursor
|
|
|
35
28
|
}, new Map());
|
|
36
29
|
|
|
37
30
|
console.log([...byStreet].sort((a, b) => b[1] - a[1]).slice(0, 10));
|
|
38
|
-
// [[ 'UNKNOWN', 2843 ], [ 'MASON', 2651 ], [ 'PINE', 1799 ], ... ]
|
|
39
31
|
```
|
|
40
32
|
|
|
41
|
-
Given a **seekable**
|
|
33
|
+
Given a **seekable** or **forward** source and a path, it retrieves values out of a JSON, without loading the whole thing in-memory.
|
|
34
|
+
|
|
35
|
+
Here's a run (Apple M1 Pro 2021, default settings, RUNS=100):
|
|
36
|
+
|
|
37
|
+
| method | mean time (seconds) | mean peak footprint (MB) |
|
|
38
|
+
| ------------------ | ----------------- | ------------------------ |
|
|
39
|
+
| bote | 0.517 ± 0.018 s | 40.3 ± 2.5 |
|
|
40
|
+
| JSON.parse | 0.816 ± 0.031 s | 648.9 ± 2.4 |
|
|
41
|
+
| JSONStream | 4.452 ± 0.052 s | 57.9 ± 3.9 |
|
|
42
|
+
| @streamparser/json | 5.103 ± 0.084 s | 47.9 ± 2.3 |
|
|
43
|
+
| oboe.js | 8.566 ± 0.295 s | 100.0 ± 4.6 |
|
|
44
|
+
| stream-json | 13.346 ± 0.569 s | 207.6 ± 8.4 |
|
|
45
|
+
|
|
46
|
+
For comparison notes, go [here](https://github.com/jankdc/bote-comparison).
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
* Modern `AsyncIterator` API with helpers that emulate the [tc39 ones](https://github.com/tc39/proposal-async-iterator-helpers)
|
|
51
|
+
* Validate with [Standard Schema](https://standardschema.dev/), avoiding those pesky `unknown`s
|
|
52
|
+
* Supports multiple sources of data (e.g. file, network, stream) or write a custom one (see [example](./examples/))
|
|
53
|
+
* For forward-only sources, there's support for replaying/buffering, allowing navigation to previous values
|
|
42
54
|
|
|
43
|
-
|
|
55
|
+
## Documentation
|
|
44
56
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
| JSON.parse | 0.81 s | 647.0 |
|
|
48
|
-
| bote | 1.062 s | 89.0 |
|
|
49
|
-
| @streamparser/json | 4.363 s | 98.7 |
|
|
50
|
-
| JSONStream | 4.417 s | 60.7 |
|
|
51
|
-
| oboe.js | 9.649 s | 102.6 |
|
|
52
|
-
| stream-json | 18.693 s | 184.3 |
|
|
57
|
+
Coming soon. Check the [./examples](./examples/) folder for usages. I've also heavily JSDoc'ed the hell out of the API so have fun
|
|
58
|
+
playing around with it for now.
|
|
53
59
|
|
|
54
60
|
## Status
|
|
55
61
|
|
package/dist/cursor.d.ts
CHANGED
|
@@ -43,13 +43,6 @@ export interface Cursor {
|
|
|
43
43
|
*/
|
|
44
44
|
get(...path: Segment[]): Promise<unknown>;
|
|
45
45
|
get<Sch extends StandardSchemaV1>(...args: [...Segment[], Sch]): Promise<InferOutput<Sch>>;
|
|
46
|
-
/**
|
|
47
|
-
* Count the members of the array or object at `path`.
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* const total = await root.count('users');
|
|
51
|
-
*/
|
|
52
|
-
count(...path: Segment[]): Promise<number>;
|
|
53
46
|
/**
|
|
54
47
|
* Stream the members of the array or object at `path` as an async iterable.
|
|
55
48
|
* A trailing Standard Schema validates each item; a trailing {@link IterOptions}
|
package/dist/cursor.js
CHANGED
|
@@ -43,11 +43,6 @@ export function wrap(native, state) {
|
|
|
43
43
|
}
|
|
44
44
|
return runStandardSchema(schema, value, path);
|
|
45
45
|
},
|
|
46
|
-
async count(...path) {
|
|
47
|
-
ensureOpen(state);
|
|
48
|
-
validatePath(path);
|
|
49
|
-
return withPath(path, () => native.count(path));
|
|
50
|
-
},
|
|
51
46
|
iter(...args) {
|
|
52
47
|
ensureOpen(state);
|
|
53
48
|
const { path, tail } = splitArgs(args);
|
package/dist/index.d.ts
CHANGED
|
@@ -7,4 +7,4 @@ export { type Source, type Reader, type ReadResult, type ForwardSource, type Fac
|
|
|
7
7
|
export { fromFile, fromBuffer, fromHttpRange, type HttpRangeOptions } from './source/seekable.ts';
|
|
8
8
|
export { fromReadable, fromHttpRequest, type ReadableOptions, type ReadableProducer, type HttpRequestOptions, } from './source/forward.ts';
|
|
9
9
|
export { type IterStream } from './stream.ts';
|
|
10
|
-
export { open, type
|
|
10
|
+
export { open, type SeekableOpenOptions } from './open.ts';
|
package/dist/open.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type RootCursor } from './cursor.ts';
|
|
2
2
|
import type { SeekableSource, ForwardSource } from './source/base.ts';
|
|
3
3
|
export declare const DEFAULT_SOURCE_CHUNK_BYTES: number;
|
|
4
|
-
export interface
|
|
4
|
+
export interface SeekableOpenOptions {
|
|
5
5
|
/**
|
|
6
6
|
* How much of the index that speeds up repeat lookups to keep in memory,
|
|
7
7
|
* measured in entries. Higher means faster repeat queries but more memory;
|
|
@@ -24,14 +24,6 @@ export interface OpenOptions {
|
|
|
24
24
|
*/
|
|
25
25
|
arrayIndexInterval?: number;
|
|
26
26
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Options for a forward source: every cache knob is forbidden (the structural-index
|
|
29
|
-
* cache is forced off). `Omit` would collapse to `{}` and silently permit them, so
|
|
30
|
-
* the knobs are mapped to `never` to reject them at compile time.
|
|
31
|
-
*/
|
|
32
|
-
export type ForwardOpenOptions = {
|
|
33
|
-
[K in keyof OpenOptions]?: never;
|
|
34
|
-
};
|
|
35
27
|
/**
|
|
36
28
|
* Open a cursor over a source.
|
|
37
29
|
*
|
|
@@ -43,5 +35,5 @@ export type ForwardOpenOptions = {
|
|
|
43
35
|
* The returned `RootCursor` owns the reader: `close()` (or `await using`) drives
|
|
44
36
|
* the reader's own `close()` exactly once.
|
|
45
37
|
*/
|
|
46
|
-
export declare function open(source: SeekableSource, options?:
|
|
47
|
-
export declare function open(source: ForwardSource
|
|
38
|
+
export declare function open(source: SeekableSource, options?: SeekableOpenOptions): Promise<RootCursor>;
|
|
39
|
+
export declare function open(source: ForwardSource): Promise<RootCursor>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@botejs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"prepublishOnly": "cp ../../README.md ./README.md && tsc"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@botejs/native": "^0.
|
|
39
|
+
"@botejs/native": "^0.7.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/node": "^22.0.0",
|