seroval 0.15.1 → 1.0.2
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 +3 -3
- package/dist/cjs/development/index.cjs +1287 -1945
- package/dist/cjs/development/index.cjs.map +3 -3
- package/dist/cjs/production/index.cjs +3 -3
- package/dist/esm/development/index.mjs +1288 -1946
- package/dist/esm/development/index.mjs.map +3 -3
- package/dist/esm/production/index.mjs +3 -3
- package/dist/types/core/Serializer.d.ts +2 -1
- package/dist/types/core/Serializer.d.ts.map +1 -1
- package/dist/types/core/UnsupportedTypeError.d.ts.map +1 -1
- package/dist/types/core/base-primitives.d.ts +6 -2
- package/dist/types/core/base-primitives.d.ts.map +1 -1
- package/dist/types/core/compat.d.ts +5 -13
- package/dist/types/core/compat.d.ts.map +1 -1
- package/dist/types/core/constants.d.ts +17 -29
- package/dist/types/core/constants.d.ts.map +1 -1
- package/dist/types/core/context/deserializer.d.ts +6 -16
- package/dist/types/core/context/deserializer.d.ts.map +1 -1
- package/dist/types/core/context/parser/async.d.ts +2 -11
- package/dist/types/core/context/parser/async.d.ts.map +1 -1
- package/dist/types/core/context/parser/stream.d.ts +10 -10
- package/dist/types/core/context/parser/stream.d.ts.map +1 -1
- package/dist/types/core/context/parser/sync.d.ts +5 -7
- package/dist/types/core/context/parser/sync.d.ts.map +1 -1
- package/dist/types/core/context/parser.d.ts +26 -5
- package/dist/types/core/context/parser.d.ts.map +1 -1
- package/dist/types/core/context/serializer.d.ts +21 -30
- package/dist/types/core/context/serializer.d.ts.map +1 -1
- package/dist/types/core/cross/async.d.ts.map +1 -1
- package/dist/types/core/cross/deserializer.d.ts.map +1 -1
- package/dist/types/core/cross/index.d.ts.map +1 -1
- package/dist/types/core/cross/parser.d.ts.map +1 -1
- package/dist/types/core/cross/serializer.d.ts +1 -1
- package/dist/types/core/cross/serializer.d.ts.map +1 -1
- package/dist/types/core/cross/stream.d.ts.map +1 -1
- package/dist/types/core/cross/sync.d.ts.map +1 -1
- package/dist/types/core/keys.d.ts.map +1 -1
- package/dist/types/core/literals.d.ts.map +1 -1
- package/dist/types/core/plugin.d.ts +21 -0
- package/dist/types/core/plugin.d.ts.map +1 -1
- package/dist/types/core/reference.d.ts.map +1 -1
- package/dist/types/core/special-reference.d.ts +4 -9
- package/dist/types/core/special-reference.d.ts.map +1 -1
- package/dist/types/core/stream.d.ts +18 -0
- package/dist/types/core/stream.d.ts.map +1 -0
- package/dist/types/core/string.d.ts.map +1 -1
- package/dist/types/core/tree/async.d.ts.map +1 -1
- package/dist/types/core/tree/deserializer.d.ts.map +1 -1
- package/dist/types/core/tree/index.d.ts +1 -1
- package/dist/types/core/tree/index.d.ts.map +1 -1
- package/dist/types/core/tree/serializer.d.ts +3 -11
- package/dist/types/core/tree/serializer.d.ts.map +1 -1
- package/dist/types/core/types.d.ts +28 -122
- package/dist/types/core/types.d.ts.map +1 -1
- package/dist/types/core/utils/deferred.d.ts +0 -7
- package/dist/types/core/utils/deferred.d.ts.map +1 -1
- package/dist/types/core/utils/error.d.ts +2 -1
- package/dist/types/core/utils/error.d.ts.map +1 -1
- package/dist/types/core/utils/get-identifier.d.ts.map +1 -1
- package/dist/types/core/utils/is-valid-identifier.d.ts.map +1 -1
- package/dist/types/core/utils/iterator-to-sequence.d.ts +0 -12
- package/dist/types/core/utils/iterator-to-sequence.d.ts.map +1 -1
- package/dist/types/core/utils/typed-array.d.ts +2 -0
- package/dist/types/core/utils/typed-array.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -3
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/core/Serializer.ts +44 -28
- package/src/core/UnsupportedTypeError.ts +2 -3
- package/src/core/base-primitives.ts +124 -38
- package/src/core/compat.ts +5 -14
- package/src/core/constants.ts +28 -39
- package/src/core/context/deserializer.ts +122 -308
- package/src/core/context/parser/async.ts +163 -375
- package/src/core/context/parser/stream.ts +110 -381
- package/src/core/context/parser/sync.ts +125 -266
- package/src/core/context/parser.ts +119 -68
- package/src/core/context/serializer.ts +396 -473
- package/src/core/cross/async.ts +1 -1
- package/src/core/cross/deserializer.ts +1 -4
- package/src/core/cross/index.ts +26 -20
- package/src/core/cross/parser.ts +1 -1
- package/src/core/cross/serializer.ts +30 -20
- package/src/core/cross/stream.ts +1 -1
- package/src/core/cross/sync.ts +1 -1
- package/src/core/keys.ts +3 -1
- package/src/core/literals.ts +22 -8
- package/src/core/plugin.ts +48 -10
- package/src/core/reference.ts +4 -5
- package/src/core/special-reference.ts +5 -15
- package/src/core/stream.ts +205 -0
- package/src/core/string.ts +53 -22
- package/src/core/tree/async.ts +1 -1
- package/src/core/tree/deserializer.ts +4 -9
- package/src/core/tree/index.ts +15 -10
- package/src/core/tree/serializer.ts +6 -50
- package/src/core/types.ts +39 -179
- package/src/core/utils/deferred.ts +0 -27
- package/src/core/utils/error.ts +26 -15
- package/src/core/utils/get-identifier.ts +5 -4
- package/src/core/utils/is-valid-identifier.ts +6 -5
- package/src/core/utils/iterator-to-sequence.ts +0 -174
- package/src/core/utils/typed-array.ts +35 -11
- package/src/index.ts +3 -12
- package/dist/types/core/utils/constructors.d.ts +0 -5
- package/dist/types/core/utils/constructors.d.ts.map +0 -1
- package/dist/types/core/web-api.d.ts +0 -8
- package/dist/types/core/web-api.d.ts.map +0 -1
- package/dist/types/types.d.ts +0 -21
- package/dist/types/types.d.ts.map +0 -1
- package/src/core/utils/constructors.ts +0 -49
- package/src/core/web-api.ts +0 -138
- package/src/example.ts +0 -25
- package/src/types.ts +0 -84
package/src/core/cross/async.ts
CHANGED
|
@@ -2,7 +2,7 @@ import BaseAsyncParserContext from '../context/parser/async';
|
|
|
2
2
|
import type { CrossParserContextOptions } from './parser';
|
|
3
3
|
import type { SerovalMode } from '../plugin';
|
|
4
4
|
|
|
5
|
-
export type CrossAsyncParserContextOptions = CrossParserContextOptions
|
|
5
|
+
export type CrossAsyncParserContextOptions = CrossParserContextOptions;
|
|
6
6
|
|
|
7
7
|
export default class CrossAsyncParserContext extends BaseAsyncParserContext {
|
|
8
8
|
readonly mode: SerovalMode = 'cross';
|
|
@@ -7,10 +7,7 @@ export type CrossDeserializerContextOptions = BaseDeserializerOptions;
|
|
|
7
7
|
export default class CrossDeserializerContext extends BaseDeserializerContext {
|
|
8
8
|
readonly mode: SerovalMode = 'cross';
|
|
9
9
|
|
|
10
|
-
assignIndexedValue<T>(
|
|
11
|
-
index: number,
|
|
12
|
-
value: T,
|
|
13
|
-
): T {
|
|
10
|
+
assignIndexedValue<T>(index: number, value: T): T {
|
|
14
11
|
if (!this.refs.has(index)) {
|
|
15
12
|
this.refs.set(index, value);
|
|
16
13
|
}
|
package/src/core/cross/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolvePlugins } from '../plugin';
|
|
1
2
|
import type { SerovalNode } from '../types';
|
|
2
3
|
import type { CrossAsyncParserContextOptions } from './async';
|
|
3
4
|
import AsyncCrossParserContext from './async';
|
|
@@ -11,21 +12,22 @@ import type { CrossSyncParserContextOptions } from './sync';
|
|
|
11
12
|
import SyncCrossParserContext from './sync';
|
|
12
13
|
|
|
13
14
|
export interface CrossSerializeOptions
|
|
14
|
-
extends CrossSyncParserContextOptions,
|
|
15
|
-
}
|
|
15
|
+
extends CrossSyncParserContextOptions,
|
|
16
|
+
CrossContextOptions {}
|
|
16
17
|
|
|
17
18
|
export function crossSerialize<T>(
|
|
18
19
|
source: T,
|
|
19
20
|
options: CrossSerializeOptions = {},
|
|
20
21
|
): string {
|
|
22
|
+
const plugins = resolvePlugins(options.plugins);
|
|
21
23
|
const ctx = new SyncCrossParserContext({
|
|
22
|
-
plugins
|
|
24
|
+
plugins,
|
|
23
25
|
disabledFeatures: options.disabledFeatures,
|
|
24
26
|
refs: options.refs,
|
|
25
27
|
});
|
|
26
28
|
const tree = ctx.parse(source);
|
|
27
29
|
const serial = new CrossSerializerContext({
|
|
28
|
-
plugins
|
|
30
|
+
plugins,
|
|
29
31
|
features: ctx.features,
|
|
30
32
|
scopeId: options.scopeId,
|
|
31
33
|
markedRefs: ctx.marked,
|
|
@@ -34,21 +36,22 @@ export function crossSerialize<T>(
|
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
export interface CrossSerializeAsyncOptions
|
|
37
|
-
extends CrossAsyncParserContextOptions,
|
|
38
|
-
}
|
|
39
|
+
extends CrossAsyncParserContextOptions,
|
|
40
|
+
CrossContextOptions {}
|
|
39
41
|
|
|
40
42
|
export async function crossSerializeAsync<T>(
|
|
41
43
|
source: T,
|
|
42
44
|
options: CrossSerializeAsyncOptions = {},
|
|
43
45
|
): Promise<string> {
|
|
46
|
+
const plugins = resolvePlugins(options.plugins);
|
|
44
47
|
const ctx = new AsyncCrossParserContext({
|
|
45
|
-
plugins
|
|
48
|
+
plugins,
|
|
46
49
|
disabledFeatures: options.disabledFeatures,
|
|
47
50
|
refs: options.refs,
|
|
48
51
|
});
|
|
49
52
|
const tree = await ctx.parse(source);
|
|
50
53
|
const serial = new CrossSerializerContext({
|
|
51
|
-
plugins
|
|
54
|
+
plugins,
|
|
52
55
|
features: ctx.features,
|
|
53
56
|
scopeId: options.scopeId,
|
|
54
57
|
markedRefs: ctx.marked,
|
|
@@ -62,8 +65,9 @@ export function toCrossJSON<T>(
|
|
|
62
65
|
source: T,
|
|
63
66
|
options: CrossParserContextOptions = {},
|
|
64
67
|
): SerovalNode {
|
|
68
|
+
const plugins = resolvePlugins(options.plugins);
|
|
65
69
|
const ctx = new SyncCrossParserContext({
|
|
66
|
-
plugins
|
|
70
|
+
plugins,
|
|
67
71
|
disabledFeatures: options.disabledFeatures,
|
|
68
72
|
refs: options.refs,
|
|
69
73
|
});
|
|
@@ -76,16 +80,18 @@ export async function toCrossJSONAsync<T>(
|
|
|
76
80
|
source: T,
|
|
77
81
|
options: CrossParserContextOptions = {},
|
|
78
82
|
): Promise<SerovalNode> {
|
|
83
|
+
const plugins = resolvePlugins(options.plugins);
|
|
79
84
|
const ctx = new AsyncCrossParserContext({
|
|
80
|
-
plugins
|
|
85
|
+
plugins,
|
|
81
86
|
disabledFeatures: options.disabledFeatures,
|
|
82
87
|
refs: options.refs,
|
|
83
88
|
});
|
|
84
|
-
return ctx.parse(source);
|
|
89
|
+
return await ctx.parse(source);
|
|
85
90
|
}
|
|
86
91
|
|
|
87
92
|
export interface CrossSerializeStreamOptions
|
|
88
|
-
extends Omit<CrossStreamParserContextOptions, 'onParse'>,
|
|
93
|
+
extends Omit<CrossStreamParserContextOptions, 'onParse'>,
|
|
94
|
+
CrossContextOptions {
|
|
89
95
|
onSerialize: (data: string, initial: boolean) => void;
|
|
90
96
|
}
|
|
91
97
|
|
|
@@ -93,13 +99,14 @@ export function crossSerializeStream<T>(
|
|
|
93
99
|
source: T,
|
|
94
100
|
options: CrossSerializeStreamOptions,
|
|
95
101
|
): () => void {
|
|
102
|
+
const plugins = resolvePlugins(options.plugins);
|
|
96
103
|
const ctx = new StreamCrossParserContext({
|
|
97
|
-
plugins
|
|
104
|
+
plugins,
|
|
98
105
|
refs: options.refs,
|
|
99
106
|
disabledFeatures: options.disabledFeatures,
|
|
100
107
|
onParse(node, initial): void {
|
|
101
108
|
const serial = new CrossSerializerContext({
|
|
102
|
-
plugins
|
|
109
|
+
plugins,
|
|
103
110
|
features: ctx.features,
|
|
104
111
|
scopeId: options.scopeId,
|
|
105
112
|
markedRefs: ctx.marked,
|
|
@@ -116,10 +123,7 @@ export function crossSerializeStream<T>(
|
|
|
116
123
|
return;
|
|
117
124
|
}
|
|
118
125
|
|
|
119
|
-
options.onSerialize(
|
|
120
|
-
serialized,
|
|
121
|
-
initial,
|
|
122
|
-
);
|
|
126
|
+
options.onSerialize(serialized, initial);
|
|
123
127
|
},
|
|
124
128
|
onError: options.onError,
|
|
125
129
|
onDone: options.onDone,
|
|
@@ -138,8 +142,9 @@ export function toCrossJSONStream<T>(
|
|
|
138
142
|
source: T,
|
|
139
143
|
options: ToCrossJSONStreamOptions,
|
|
140
144
|
): () => void {
|
|
145
|
+
const plugins = resolvePlugins(options.plugins);
|
|
141
146
|
const ctx = new StreamCrossParserContext({
|
|
142
|
-
plugins
|
|
147
|
+
plugins,
|
|
143
148
|
refs: options.refs,
|
|
144
149
|
disabledFeatures: options.disabledFeatures,
|
|
145
150
|
onParse: options.onParse,
|
|
@@ -160,8 +165,9 @@ export function fromCrossJSON<T>(
|
|
|
160
165
|
source: SerovalNode,
|
|
161
166
|
options: FromCrossJSONOptions,
|
|
162
167
|
): T {
|
|
168
|
+
const plugins = resolvePlugins(options.plugins);
|
|
163
169
|
const ctx = new CrossDeserializerContext({
|
|
164
|
-
plugins
|
|
170
|
+
plugins,
|
|
165
171
|
refs: options.refs,
|
|
166
172
|
});
|
|
167
173
|
return ctx.deserialize(source) as T;
|
package/src/core/cross/parser.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
} from '../types';
|
|
4
|
-
import {
|
|
5
|
-
GLOBAL_CONTEXT_REFERENCES,
|
|
6
|
-
} from '../keys';
|
|
1
|
+
import type { SerovalNode } from '../types';
|
|
2
|
+
import { GLOBAL_CONTEXT_REFERENCES } from '../keys';
|
|
7
3
|
import type { BaseSerializerContextOptions } from '../context/serializer';
|
|
8
4
|
import BaseSerializerContext from '../context/serializer';
|
|
9
5
|
import type { SerovalMode } from '../plugin';
|
|
@@ -11,8 +7,8 @@ import { serializeString } from '../string';
|
|
|
11
7
|
import type { CrossContextOptions } from './parser';
|
|
12
8
|
|
|
13
9
|
export interface CrossSerializerContextOptions
|
|
14
|
-
extends BaseSerializerContextOptions,
|
|
15
|
-
}
|
|
10
|
+
extends BaseSerializerContextOptions,
|
|
11
|
+
CrossContextOptions {}
|
|
16
12
|
|
|
17
13
|
export default class CrossSerializerContext extends BaseSerializerContext {
|
|
18
14
|
readonly mode: SerovalMode = 'cross';
|
|
@@ -24,35 +20,49 @@ export default class CrossSerializerContext extends BaseSerializerContext {
|
|
|
24
20
|
this.scopeId = options.scopeId;
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
getRefParam(id: number
|
|
28
|
-
if (typeof id === 'string') {
|
|
29
|
-
return GLOBAL_CONTEXT_REFERENCES + '.' + id;
|
|
30
|
-
}
|
|
23
|
+
getRefParam(id: number): string {
|
|
31
24
|
return GLOBAL_CONTEXT_REFERENCES + '[' + id + ']';
|
|
32
25
|
}
|
|
33
26
|
|
|
34
|
-
protected assignIndexedValue(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
protected assignIndexedValue(index: number, value: string): string {
|
|
28
|
+
// In cross-reference, we have to assume that
|
|
29
|
+
// every reference are going to be referenced
|
|
30
|
+
// in the future, and so we need to store
|
|
31
|
+
// all of it into the reference array.
|
|
38
32
|
return this.getRefParam(index) + '=' + value;
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
serializeTop(tree: SerovalNode): string {
|
|
36
|
+
// Get the serialized result
|
|
42
37
|
const result = this.serialize(tree);
|
|
38
|
+
// If the node is a non-reference, return
|
|
39
|
+
// the result immediately
|
|
43
40
|
const id = tree.i;
|
|
44
41
|
if (id == null) {
|
|
45
42
|
return result;
|
|
46
43
|
}
|
|
44
|
+
// Get the patches
|
|
47
45
|
const patches = this.resolvePatches();
|
|
46
|
+
// Get the variable that represents the root
|
|
48
47
|
const ref = this.getRefParam(id);
|
|
48
|
+
// Parameters needed for scoping
|
|
49
49
|
const params = this.scopeId == null ? '' : GLOBAL_CONTEXT_REFERENCES;
|
|
50
|
-
|
|
50
|
+
// If there are patches, append it after the result
|
|
51
|
+
const body = patches ? result + ',' + patches + ref : result;
|
|
52
|
+
// If there are no params, there's no need to generate a function
|
|
51
53
|
if (params === '') {
|
|
52
|
-
return patches ? '(' +
|
|
54
|
+
return patches ? '(' + body + ')' : body;
|
|
53
55
|
}
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
+
// Get the arguments for the IIFE
|
|
57
|
+
const args =
|
|
58
|
+
this.scopeId == null
|
|
59
|
+
? '()'
|
|
60
|
+
: '(' +
|
|
61
|
+
GLOBAL_CONTEXT_REFERENCES +
|
|
62
|
+
'["' +
|
|
63
|
+
serializeString(this.scopeId) +
|
|
64
|
+
'"])';
|
|
65
|
+
// Create the IIFE
|
|
56
66
|
return '(' + this.createFunction([params], body) + ')' + args;
|
|
57
67
|
}
|
|
58
68
|
}
|
package/src/core/cross/stream.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { BaseStreamParserContextOptions } from '../context/parser/stream';
|
|
|
2
2
|
import BaseStreamParserContext from '../context/parser/stream';
|
|
3
3
|
import type { SerovalMode } from '../plugin';
|
|
4
4
|
|
|
5
|
-
export type CrossStreamParserContextOptions = BaseStreamParserContextOptions
|
|
5
|
+
export type CrossStreamParserContextOptions = BaseStreamParserContextOptions;
|
|
6
6
|
|
|
7
7
|
export default class CrossStreamParserContext extends BaseStreamParserContext {
|
|
8
8
|
readonly mode: SerovalMode = 'cross';
|
package/src/core/cross/sync.ts
CHANGED
|
@@ -2,7 +2,7 @@ import BaseSyncParserContext from '../context/parser/sync';
|
|
|
2
2
|
import type { SerovalMode } from '../plugin';
|
|
3
3
|
import type { CrossParserContextOptions } from './parser';
|
|
4
4
|
|
|
5
|
-
export type CrossSyncParserContextOptions = CrossParserContextOptions
|
|
5
|
+
export type CrossSyncParserContextOptions = CrossParserContextOptions;
|
|
6
6
|
|
|
7
7
|
export default class CrossSyncParserContext extends BaseSyncParserContext {
|
|
8
8
|
readonly mode: SerovalMode = 'cross';
|
package/src/core/keys.ts
CHANGED
|
@@ -11,5 +11,7 @@ export function getCrossReferenceHeader(id?: string): string {
|
|
|
11
11
|
if (id == null) {
|
|
12
12
|
return `${GLOBAL_CONTEXT_R}=${GLOBAL_CONTEXT_R}||[]`;
|
|
13
13
|
}
|
|
14
|
-
return `(${GLOBAL_CONTEXT_R}=${GLOBAL_CONTEXT_R}||{})["${serializeString(
|
|
14
|
+
return `(${GLOBAL_CONTEXT_R}=${GLOBAL_CONTEXT_R}||{})["${serializeString(
|
|
15
|
+
id,
|
|
16
|
+
)}"]=[]`;
|
|
15
17
|
}
|
package/src/core/literals.ts
CHANGED
|
@@ -18,11 +18,25 @@ function createConstantNode(value: SerovalConstant): SerovalConstantNode {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
export const TRUE_NODE = createConstantNode(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
export const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
export const
|
|
28
|
-
|
|
21
|
+
export const TRUE_NODE = /* @__PURE__ */ createConstantNode(
|
|
22
|
+
SerovalConstant.True,
|
|
23
|
+
);
|
|
24
|
+
export const FALSE_NODE = /* @__PURE__ */ createConstantNode(
|
|
25
|
+
SerovalConstant.False,
|
|
26
|
+
);
|
|
27
|
+
export const UNDEFINED_NODE = /* @__PURE__ */ createConstantNode(
|
|
28
|
+
SerovalConstant.Undefined,
|
|
29
|
+
);
|
|
30
|
+
export const NULL_NODE = /* @__PURE__ */ createConstantNode(
|
|
31
|
+
SerovalConstant.Null,
|
|
32
|
+
);
|
|
33
|
+
export const NEG_ZERO_NODE = /* @__PURE__ */ createConstantNode(
|
|
34
|
+
SerovalConstant.NegativeZero,
|
|
35
|
+
);
|
|
36
|
+
export const INFINITY_NODE = /* @__PURE__ */ createConstantNode(
|
|
37
|
+
SerovalConstant.Infinity,
|
|
38
|
+
);
|
|
39
|
+
export const NEG_INFINITY_NODE = /* @__PURE__ */ createConstantNode(
|
|
40
|
+
SerovalConstant.NegativeInfinity,
|
|
41
|
+
);
|
|
42
|
+
export const NAN_NODE = /* @__PURE__ */ createConstantNode(SerovalConstant.NaN);
|
package/src/core/plugin.ts
CHANGED
|
@@ -11,14 +11,24 @@ export interface PluginData {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface Plugin<Value, Node> {
|
|
14
|
+
/**
|
|
15
|
+
* A unique string that helps idenfity the plugin
|
|
16
|
+
*/
|
|
14
17
|
tag: string;
|
|
18
|
+
/**
|
|
19
|
+
* List of dependency plugins
|
|
20
|
+
*/
|
|
21
|
+
extends?: Plugin<any, any>[];
|
|
22
|
+
/**
|
|
23
|
+
* Method to test if a value is an expected value of the plugin
|
|
24
|
+
* @param value
|
|
25
|
+
*/
|
|
15
26
|
test(value: unknown): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Parsing modes
|
|
29
|
+
*/
|
|
16
30
|
parse: {
|
|
17
|
-
sync?: (
|
|
18
|
-
value: Value,
|
|
19
|
-
ctx: BaseSyncParserContext,
|
|
20
|
-
data: PluginData,
|
|
21
|
-
) => Node;
|
|
31
|
+
sync?: (value: Value, ctx: BaseSyncParserContext, data: PluginData) => Node;
|
|
22
32
|
async?: (
|
|
23
33
|
value: Value,
|
|
24
34
|
ctx: BaseAsyncParserContext,
|
|
@@ -30,11 +40,13 @@ export interface Plugin<Value, Node> {
|
|
|
30
40
|
data: PluginData,
|
|
31
41
|
) => Node;
|
|
32
42
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Convert the parsed node into a JS string
|
|
45
|
+
*/
|
|
46
|
+
serialize(node: Node, ctx: BaseSerializerContext, data: PluginData): string;
|
|
47
|
+
/**
|
|
48
|
+
* Convert the parsed node into its runtime equivalent.
|
|
49
|
+
*/
|
|
38
50
|
deserialize(
|
|
39
51
|
node: Node,
|
|
40
52
|
ctx: BaseDeserializerContext,
|
|
@@ -51,3 +63,29 @@ export function createPlugin<Value, Node>(
|
|
|
51
63
|
export interface PluginAccessOptions {
|
|
52
64
|
plugins?: Plugin<any, any>[];
|
|
53
65
|
}
|
|
66
|
+
|
|
67
|
+
function dedupePlugins(
|
|
68
|
+
deduped: Set<Plugin<any, any>>,
|
|
69
|
+
plugins: Plugin<any, any>[],
|
|
70
|
+
): void {
|
|
71
|
+
for (let i = 0, len = plugins.length; i < len; i++) {
|
|
72
|
+
const current = plugins[i];
|
|
73
|
+
if (!deduped.has(current)) {
|
|
74
|
+
deduped.add(current);
|
|
75
|
+
if (current.extends) {
|
|
76
|
+
dedupePlugins(deduped, current.extends);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function resolvePlugins(
|
|
83
|
+
plugins?: Plugin<any, any>[],
|
|
84
|
+
): Plugin<any, any>[] | undefined {
|
|
85
|
+
if (plugins) {
|
|
86
|
+
const deduped = new Set<Plugin<any, any>>();
|
|
87
|
+
dedupePlugins(deduped, plugins);
|
|
88
|
+
return [...deduped];
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
package/src/core/reference.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable no-restricted-globals */
|
|
2
1
|
import assert from './utils/assert';
|
|
3
2
|
import { REFERENCES_KEY } from './keys';
|
|
4
3
|
|
|
@@ -29,28 +28,28 @@ export function getReference<T>(id: string): T {
|
|
|
29
28
|
return INV_REFERENCE.get(id) as T;
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
if (typeof globalThis !== undefined) {
|
|
31
|
+
if (typeof globalThis !== 'undefined') {
|
|
33
32
|
Object.defineProperty(globalThis, REFERENCES_KEY, {
|
|
34
33
|
value: INV_REFERENCE,
|
|
35
34
|
configurable: true,
|
|
36
35
|
writable: false,
|
|
37
36
|
enumerable: false,
|
|
38
37
|
});
|
|
39
|
-
} else if (typeof window !== undefined) {
|
|
38
|
+
} else if (typeof window !== 'undefined') {
|
|
40
39
|
Object.defineProperty(window, REFERENCES_KEY, {
|
|
41
40
|
value: INV_REFERENCE,
|
|
42
41
|
configurable: true,
|
|
43
42
|
writable: false,
|
|
44
43
|
enumerable: false,
|
|
45
44
|
});
|
|
46
|
-
} else if (typeof self !== undefined) {
|
|
45
|
+
} else if (typeof self !== 'undefined') {
|
|
47
46
|
Object.defineProperty(self, REFERENCES_KEY, {
|
|
48
47
|
value: INV_REFERENCE,
|
|
49
48
|
configurable: true,
|
|
50
49
|
writable: false,
|
|
51
50
|
enumerable: false,
|
|
52
51
|
});
|
|
53
|
-
} else if (typeof global !== undefined) {
|
|
52
|
+
} else if (typeof global !== 'undefined') {
|
|
54
53
|
Object.defineProperty(global, REFERENCES_KEY, {
|
|
55
54
|
value: INV_REFERENCE,
|
|
56
55
|
configurable: true,
|
|
@@ -1,29 +1,19 @@
|
|
|
1
|
-
export const UNIVERSAL_SENTINEL = {};
|
|
2
|
-
|
|
3
1
|
export const ITERATOR = {};
|
|
4
2
|
|
|
5
3
|
export const ASYNC_ITERATOR = {};
|
|
6
4
|
|
|
7
5
|
export const enum SpecialReference {
|
|
8
6
|
MapSentinel = 0,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
ReadableStreamConstructor = 5,
|
|
14
|
-
ReadableStreamEnqueue = 6,
|
|
15
|
-
ReadableStreamError = 7,
|
|
16
|
-
ReadableStreamClose = 8,
|
|
7
|
+
PromiseConstructor = 1,
|
|
8
|
+
PromiseResolve = 2,
|
|
9
|
+
PromiseReject = 3,
|
|
10
|
+
StreamConstructor = 4,
|
|
17
11
|
}
|
|
18
12
|
|
|
19
13
|
export const SPECIAL_REFS: Record<SpecialReference, unknown> = {
|
|
20
14
|
[SpecialReference.MapSentinel]: {},
|
|
21
|
-
[SpecialReference.ReadableStream]: {},
|
|
22
15
|
[SpecialReference.PromiseConstructor]: {},
|
|
23
16
|
[SpecialReference.PromiseResolve]: {},
|
|
24
17
|
[SpecialReference.PromiseReject]: {},
|
|
25
|
-
[SpecialReference.
|
|
26
|
-
[SpecialReference.ReadableStreamEnqueue]: {},
|
|
27
|
-
[SpecialReference.ReadableStreamError]: {},
|
|
28
|
-
[SpecialReference.ReadableStreamClose]: {},
|
|
18
|
+
[SpecialReference.StreamConstructor]: {},
|
|
29
19
|
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { Deferred } from './utils/deferred';
|
|
2
|
+
import { createDeferred } from './utils/deferred';
|
|
3
|
+
|
|
4
|
+
interface StreamListener<T> {
|
|
5
|
+
next(value: T): void;
|
|
6
|
+
throw(value: unknown): void;
|
|
7
|
+
return(value: T): void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Stream<T> {
|
|
11
|
+
__SEROVAL_STREAM__: true;
|
|
12
|
+
|
|
13
|
+
on(listener: StreamListener<T>): () => void;
|
|
14
|
+
|
|
15
|
+
next(value: T): void;
|
|
16
|
+
throw(value: unknown): void;
|
|
17
|
+
return(value: T): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isStream<T>(value: object): value is Stream<T> {
|
|
21
|
+
return '__SEROVAL_STREAM__' in value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createStream<T>(): Stream<T> {
|
|
25
|
+
const listeners = new Set<StreamListener<T>>();
|
|
26
|
+
const buffer: unknown[] = [];
|
|
27
|
+
let alive = true;
|
|
28
|
+
let success = false;
|
|
29
|
+
|
|
30
|
+
function flushNext(value: T): void {
|
|
31
|
+
for (const listener of listeners.keys()) {
|
|
32
|
+
listener.next(value);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function flushThrow(value: unknown): void {
|
|
37
|
+
for (const listener of listeners.keys()) {
|
|
38
|
+
listener.throw(value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function flushReturn(value: T): void {
|
|
43
|
+
for (const listener of listeners.keys()) {
|
|
44
|
+
listener.return(value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
__SEROVAL_STREAM__: true,
|
|
50
|
+
on(listener: StreamListener<T>): () => void {
|
|
51
|
+
if (alive) {
|
|
52
|
+
listeners.add(listener);
|
|
53
|
+
}
|
|
54
|
+
for (let i = 0, len = buffer.length; i < len; i++) {
|
|
55
|
+
const value = buffer[i];
|
|
56
|
+
if (i === len - 1) {
|
|
57
|
+
if (success) {
|
|
58
|
+
listener.return(value as T);
|
|
59
|
+
} else {
|
|
60
|
+
listener.throw(value);
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
listener.next(value as T);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return () => {
|
|
67
|
+
if (alive) {
|
|
68
|
+
listeners.delete(listener);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
next(value): void {
|
|
73
|
+
if (alive) {
|
|
74
|
+
buffer.push(value);
|
|
75
|
+
flushNext(value);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
throw(value): void {
|
|
79
|
+
if (alive) {
|
|
80
|
+
buffer.push(value);
|
|
81
|
+
flushThrow(value);
|
|
82
|
+
alive = false;
|
|
83
|
+
success = false;
|
|
84
|
+
listeners.clear();
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
return(value): void {
|
|
88
|
+
if (alive) {
|
|
89
|
+
buffer.push(value);
|
|
90
|
+
flushReturn(value);
|
|
91
|
+
alive = false;
|
|
92
|
+
success = true;
|
|
93
|
+
listeners.clear();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function createStreamFromAsyncIterable<T>(
|
|
100
|
+
iterable: AsyncIterable<T>,
|
|
101
|
+
): Stream<T> {
|
|
102
|
+
const stream = createStream<T>();
|
|
103
|
+
|
|
104
|
+
const iterator = iterable[Symbol.asyncIterator]();
|
|
105
|
+
|
|
106
|
+
async function push(): Promise<void> {
|
|
107
|
+
try {
|
|
108
|
+
const value = await iterator.next();
|
|
109
|
+
if (value.done) {
|
|
110
|
+
stream.return(value.value as T);
|
|
111
|
+
} else {
|
|
112
|
+
stream.next(value.value);
|
|
113
|
+
await push();
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
stream.throw(error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
push().catch(() => {
|
|
121
|
+
// no-op
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
return stream;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function streamToAsyncIterable<T>(
|
|
128
|
+
stream: Stream<T>,
|
|
129
|
+
): () => AsyncIterableIterator<T> {
|
|
130
|
+
return (): AsyncIterableIterator<T> => {
|
|
131
|
+
const buffer: T[] = [];
|
|
132
|
+
const pending: Deferred[] = [];
|
|
133
|
+
let count = 0;
|
|
134
|
+
let doneAt = -1;
|
|
135
|
+
let isThrow = false;
|
|
136
|
+
|
|
137
|
+
function resolveAll(): void {
|
|
138
|
+
for (let i = 0, len = pending.length; i < len; i++) {
|
|
139
|
+
pending[i].resolve({ done: true, value: undefined });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
stream.on({
|
|
144
|
+
next(value) {
|
|
145
|
+
const current = pending.shift();
|
|
146
|
+
if (current) {
|
|
147
|
+
current.resolve({ done: false, value });
|
|
148
|
+
}
|
|
149
|
+
buffer.push(value);
|
|
150
|
+
},
|
|
151
|
+
throw(value) {
|
|
152
|
+
const current = pending.shift();
|
|
153
|
+
if (current) {
|
|
154
|
+
current.reject(value);
|
|
155
|
+
}
|
|
156
|
+
resolveAll();
|
|
157
|
+
doneAt = buffer.length;
|
|
158
|
+
buffer.push(value as T);
|
|
159
|
+
isThrow = true;
|
|
160
|
+
},
|
|
161
|
+
return(value) {
|
|
162
|
+
const current = pending.shift();
|
|
163
|
+
if (current) {
|
|
164
|
+
current.resolve({ done: true, value });
|
|
165
|
+
}
|
|
166
|
+
resolveAll();
|
|
167
|
+
doneAt = buffer.length;
|
|
168
|
+
buffer.push(value);
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
function finalize() {
|
|
173
|
+
const current = count++;
|
|
174
|
+
const value = buffer[current];
|
|
175
|
+
if (current !== doneAt) {
|
|
176
|
+
return { done: false, value };
|
|
177
|
+
}
|
|
178
|
+
if (isThrow) {
|
|
179
|
+
throw value;
|
|
180
|
+
}
|
|
181
|
+
return { done: true, value };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<T> {
|
|
186
|
+
return this;
|
|
187
|
+
},
|
|
188
|
+
async next(): Promise<IteratorResult<T>> {
|
|
189
|
+
if (doneAt === -1) {
|
|
190
|
+
const current = count++;
|
|
191
|
+
if (current >= buffer.length) {
|
|
192
|
+
const deferred = createDeferred();
|
|
193
|
+
pending.push(deferred);
|
|
194
|
+
return (await deferred.promise) as Promise<IteratorResult<T>>;
|
|
195
|
+
}
|
|
196
|
+
return { done: false, value: buffer[current] };
|
|
197
|
+
}
|
|
198
|
+
if (count > doneAt) {
|
|
199
|
+
return { done: true, value: undefined };
|
|
200
|
+
}
|
|
201
|
+
return finalize();
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
}
|