Skip to content

Commit af75aa7

Browse files
committed
Fix reference generation
1 parent c201ef4 commit af75aa7

File tree

3 files changed

+52
-57
lines changed

3 files changed

+52
-57
lines changed

packages/seroval/src/core/context/parser.ts

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,23 @@ export interface BaseParserContextOptions extends PluginAccessOptions {
3838
refs?: Map<unknown, number>;
3939
}
4040

41-
interface FreshReference {
42-
type: 'fresh';
41+
interface FreshNode {
42+
type: 0;
4343
value: number;
4444
}
4545

46-
interface CachedReference {
47-
type: 'cached';
48-
value: SerovalIndexedValueNode | SerovalReferenceNode;
46+
interface IndexedNode {
47+
type: 1;
48+
value: SerovalIndexedValueNode;
4949
}
5050

51+
interface ReferencedNode {
52+
type: 2;
53+
value: SerovalReferenceNode;
54+
}
55+
56+
type ObjectNode = FreshNode | IndexedNode | ReferencedNode;
57+
5158
export abstract class BaseParserContext implements PluginAccessOptions {
5259
abstract readonly mode: SerovalMode;
5360

@@ -73,78 +80,72 @@ export abstract class BaseParserContext implements PluginAccessOptions {
7380
return this.marked.has(id);
7481
}
7582

76-
protected getReference<T>(current: T): FreshReference | CachedReference {
83+
protected getIndexedValue<T>(current: T): FreshNode | IndexedNode {
7784
const registeredID = this.refs.get(current);
7885
if (registeredID != null) {
7986
this.markRef(registeredID);
8087
return {
81-
type: 'cached',
88+
type: 1,
8289
value: createIndexedValueNode(registeredID),
8390
};
8491
}
8592
const id = this.refs.size;
8693
this.refs.set(current, id);
94+
return {
95+
type: 0,
96+
value: id,
97+
};
98+
}
99+
100+
protected getReference<T>(current: T): ObjectNode {
101+
const indexed = this.getIndexedValue(current);
102+
if (indexed.type === 1) {
103+
return indexed;
104+
}
87105
if (hasReferenceID(current)) {
88106
return {
89-
type: 'cached',
90-
value: createReferenceNode(id, current),
107+
type: 2,
108+
value: createReferenceNode(indexed.value, current),
91109
};
92110
}
93-
return {
94-
type: 'fresh',
95-
value: id,
96-
};
111+
return indexed;
97112
}
98113

99114
protected getStrictReference<T>(current: T): SerovalIndexedValueNode | SerovalReferenceNode {
100-
const registeredID = this.refs.get(current);
101-
if (registeredID != null) {
102-
this.markRef(registeredID);
103-
return createIndexedValueNode(registeredID);
115+
assert(hasReferenceID(current), new Error('Cannot serialize ' + typeof current + ' without reference ID.'));
116+
const result = this.getIndexedValue(current);
117+
if (result.type === 1) {
118+
return result.value;
104119
}
105-
const id = this.refs.size;
106-
this.refs.set(current, id);
107-
return createReferenceNode(id, current);
120+
return createReferenceNode(result.value, current);
108121
}
109122

110123
// eslint-disable-next-line @typescript-eslint/ban-types
111124
protected parseFunction(current: Function): SerovalNode {
112-
assert(hasReferenceID(current), new Error('Cannot serialize function without reference ID.'));
113125
return this.getStrictReference(current);
114126
}
115127

116128
protected parseWKSymbol(
117129
current: symbol,
118130
): SerovalIndexedValueNode | SerovalWKSymbolNode | SerovalReferenceNode {
119-
const registeredID = this.refs.get(current);
120-
if (registeredID != null) {
121-
this.markRef(registeredID);
122-
return createIndexedValueNode(registeredID);
123-
}
124-
const isValid = current in INV_SYMBOL_REF;
125-
assert(current in INV_SYMBOL_REF || hasReferenceID(current), new Error('Cannot serialize symbol without reference ID.'));
126-
const id = this.refs.size;
127-
this.refs.set(current, id);
128-
if (isValid) {
129-
return createWKSymbolNode(id, current as WellKnownSymbols);
131+
const ref = this.getReference(current);
132+
if (ref.type !== 0) {
133+
return ref.value;
130134
}
131-
return createReferenceNode(id, current);
135+
assert(current in INV_SYMBOL_REF, new Error('Cannot serialized unsupported symbol.'));
136+
return createWKSymbolNode(ref.value, current as WellKnownSymbols);
132137
}
133138

134139
protected parseSpecialReference(
135140
ref: SpecialReference,
136141
): SerovalIndexedValueNode | SerovalSpecialReferenceNode {
137-
const specialRef = SPECIAL_REFS[ref];
138-
const registeredID = this.refs.get(specialRef);
139-
if (registeredID != null) {
140-
this.markRef(registeredID);
141-
return createIndexedValueNode(registeredID);
142+
const result = this.getIndexedValue(SPECIAL_REFS[ref]);
143+
if (result.type === 1) {
144+
return result.value;
142145
}
143-
const id = this.refs.size;
144-
this.refs.set(specialRef, id);
145146
return {
146147
t: SerovalNodeType.SpecialReference,
147-
i: id,
148+
i: result.value,
148149
s: ref,
149150
l: undefined,
150151
c: undefined,
@@ -159,16 +160,13 @@ export abstract class BaseParserContext implements PluginAccessOptions {
159160
}
160161

161162
protected parseIteratorFactory(): SerovalIndexedValueNode | SerovalIteratorFactoryNode {
162-
const registeredID = this.refs.get(ITERATOR);
163-
if (registeredID != null) {
164-
this.markRef(registeredID);
165-
return createIndexedValueNode(registeredID);
163+
const result = this.getIndexedValue(ITERATOR);
164+
if (result.type === 1) {
165+
return result.value;
166166
}
167-
const id = this.refs.size;
168-
this.refs.set(ITERATOR, id);
169167
return {
170168
t: SerovalNodeType.IteratorFactory,
171-
i: id,
169+
i: result.value,
172170
s: undefined,
173171
l: undefined,
174172
c: undefined,
@@ -183,16 +181,13 @@ export abstract class BaseParserContext implements PluginAccessOptions {
183181
}
184182

185183
protected parseAsyncIteratorFactory(): SerovalIndexedValueNode | SerovalAsyncIteratorFactoryNode {
186-
const registeredID = this.refs.get(ASYNC_ITERATOR);
187-
if (registeredID != null) {
188-
this.markRef(registeredID);
189-
return createIndexedValueNode(registeredID);
184+
const result = this.getIndexedValue(ASYNC_ITERATOR);
185+
if (result.type === 1) {
186+
return result.value;
190187
}
191-
const id = this.refs.size;
192-
this.refs.set(ASYNC_ITERATOR, id);
193188
return {
194189
t: SerovalNodeType.AsyncIteratorFactory,
195-
i: id,
190+
i: result.value,
196191
s: undefined,
197192
l: undefined,
198193
c: undefined,

packages/seroval/src/core/context/parser/async.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ export default abstract class BaseAsyncParserContext extends BaseParserContext {
478478
case 'object':
479479
if (current) {
480480
const ref = this.getReference(current);
481-
return ref.type === 'fresh' ? this.parseObject(ref.value, current as object) : ref.value;
481+
return ref.type === 0 ? this.parseObject(ref.value, current as object) : ref.value;
482482
}
483483
return NULL_NODE;
484484
case 'symbol':

packages/seroval/src/core/context/parser/sync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ export default abstract class BaseSyncParserContext extends BaseParserContext {
419419
case 'object':
420420
if (current) {
421421
const ref = this.getReference(current);
422-
return ref.type === 'fresh' ? this.parseObject(ref.value, current as object) : ref.value;
422+
return ref.type === 0 ? this.parseObject(ref.value, current as object) : ref.value;
423423
}
424424
return NULL_NODE;
425425
case 'symbol':

0 commit comments

Comments
 (0)