Skip to content

Commit 7728c65

Browse files
committed
Build TJS
1 parent 58f4a7a commit 7728c65

File tree

4 files changed

+270
-47
lines changed

4 files changed

+270
-47
lines changed

cjs/index.js

Lines changed: 133 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,44 @@
1-
var Flatted = (function (Primitive, primitive) {
1+
var TJS = (function (Primitive, primitive) {
2+
3+
var REF_KEY_PREFIX = '_';
4+
var REF_SEPARATOR = ';';
5+
var SINGLE_REF = REF_KEY_PREFIX + '0';
6+
var REF_PREFIX = {
7+
undefined: 'u',
8+
number: 'n',
9+
bigint: 'b',
10+
symbol: 's',
11+
RegExp: 'R',
12+
Map: 'M',
13+
Set: 'S'
14+
};
215

316
/*!
417
* ISC License
518
*
619
* Copyright (c) 2018, Andrea Giammarchi, @WebReflection
7-
*
8-
* Permission to use, copy, modify, and/or distribute this software for any
9-
* purpose with or without fee is hereby granted, provided that the above
10-
* copyright notice and this permission notice appear in all copies.
11-
*
12-
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
13-
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
14-
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
15-
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16-
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
17-
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18-
* PERFORMANCE OF THIS SOFTWARE.
1920
*/
2021

21-
var Flatted = {
22+
var TJS = {
2223

2324
parse: function parse(text, reviver) {
2425
var input = JSON.parse(text, Primitives).map(primitives);
26+
var len = input.length;
27+
var refs = len > 1 ? input[len - 1] : [];
2528
var value = input[0];
2629
var $ = reviver || noop;
2730
var tmp = typeof value === 'object' && value ?
28-
revive(input, new Set, value, $) :
29-
value;
31+
revive(input, refs, new Set, value, $) :
32+
(value === SINGLE_REF && refs.length ? reviveRefs(refs, 0) : value);
3033
return $.call({'': tmp}, '', tmp);
3134
},
3235

3336
stringify: function stringify(value, replacer, space) {
3437
for (var
3538
firstRun,
3639
known = new Map,
40+
knownRefs = new Map,
41+
refs = [],
3742
input = [],
3843
output = [],
3944
$ = replacer && typeof replacer === typeof input ?
@@ -43,13 +48,20 @@ var Flatted = (function (Primitive, primitive) {
4348
(replacer || noop),
4449
i = +set(known, input, $.call({'': value}, '', value)),
4550
replace = function (key, value) {
51+
var after = $.call(this, key, value);
52+
var refIndex = setRefs(knownRefs, refs, after);
53+
54+
if (refIndex) {
55+
return refIndex;
56+
}
57+
4658
if (firstRun) {
4759
firstRun = !firstRun;
4860
return value;
4961
// this was invoking twice each root object
5062
// return i < 1 ? value : $.call(this, key, value);
5163
}
52-
var after = $.call(this, key, value);
64+
5365
switch (typeof after) {
5466
case 'object':
5567
if (after === null) return after;
@@ -63,26 +75,70 @@ var Flatted = (function (Primitive, primitive) {
6375
firstRun = true;
6476
output[i] = JSON.stringify(input[i], replace, space);
6577
}
78+
refs.length && output.push(JSON.stringify(refs));
6679
return '[' + output.join(',') + ']';
6780
}
6881

6982
};
7083

71-
return Flatted;
84+
return TJS;
7285

7386
function noop(key, value) {
7487
return value;
7588
}
7689

77-
function revive(input, parsed, output, $) {
90+
function reviveRefs (refs, index) {
91+
var value = refs[index].substring(2);
92+
93+
switch (refs[index].charAt(0)) {
94+
case REF_PREFIX.undefined:
95+
refs[index] = undefined;
96+
break;
97+
case REF_PREFIX.number:
98+
refs[index] = Number(value);
99+
break;
100+
case REF_PREFIX.bigint:
101+
refs[index] = BigInt(value);
102+
break;
103+
case REF_PREFIX.symbol:
104+
refs[index] = Symbol.for(value);
105+
break;
106+
case REF_PREFIX.RegExp:
107+
var parts = /\/(.*)\/(.*)/.exec(value);
108+
refs[index] = new RegExp(parts[1], parts[2]);
109+
break;
110+
case REF_PREFIX.Map:
111+
refs[index] = new Map(TJS.parse(value));
112+
break;
113+
case REF_PREFIX.Set:
114+
refs[index] = new Set(TJS.parse(value));
115+
break;
116+
}
117+
118+
return refs[index];
119+
}
120+
121+
function revive(input, refs, parsed, output, $) {
78122
return Object.keys(output).reduce(
79123
function (output, key) {
80124
var value = output[key];
81125
if (value instanceof Primitive) {
126+
if (value.startsWith(REF_KEY_PREFIX)) {
127+
var index = value.substring(1);
128+
var tmp = refs[index];
129+
130+
if (refs[index] instanceof Primitive) {
131+
reviveRefs(refs, index);
132+
}
133+
134+
output[key] = refs[index];
135+
return output;
136+
}
137+
82138
var tmp = input[value];
83139
if (typeof tmp === 'object' && !parsed.has(tmp)) {
84140
parsed.add(tmp);
85-
output[key] = $.call(output, key, revive(input, parsed, tmp, $));
141+
output[key] = $.call(output, key, revive(input, refs, parsed, tmp, $));
86142
} else {
87143
output[key] = $.call(output, key, tmp);
88144
}
@@ -100,6 +156,62 @@ var Flatted = (function (Primitive, primitive) {
100156
return index;
101157
}
102158

159+
function setRefs(known, refs, value) {
160+
var after;
161+
162+
switch (typeof value) {
163+
case 'undefined':
164+
after = REF_PREFIX.undefined;
165+
break;
166+
case 'number':
167+
if (!Number.isFinite(value)) {
168+
after = REF_PREFIX.number + REF_SEPARATOR + Primitive(value);
169+
}
170+
break;
171+
case 'bigint':
172+
after = REF_PREFIX.bigint + REF_SEPARATOR + Primitive(value);
173+
break;
174+
case 'symbol':
175+
var description = Primitive(value);
176+
177+
after = REF_PREFIX.symbol + REF_SEPARATOR + description.substring(7, description.length - 1);
178+
break;
179+
case 'object':
180+
if (value instanceof RegExp) {
181+
after = REF_PREFIX.RegExp + REF_SEPARATOR + Primitive(value);
182+
}
183+
else if (value instanceof Map) {
184+
var m = [];
185+
for (var i of value.entries()) {
186+
m.push(i);
187+
}
188+
after = REF_PREFIX.Map + REF_SEPARATOR + TJS.stringify(m);
189+
}
190+
else if (value instanceof Set) {
191+
var s = [];
192+
for (var i of value.values()) {
193+
s.push(i);
194+
}
195+
after = REF_PREFIX.Set + REF_SEPARATOR + TJS.stringify(s);
196+
}
197+
break;
198+
}
199+
200+
if (!after) {
201+
return;
202+
}
203+
204+
var index = known.get(after);
205+
206+
if (index) {
207+
return index;
208+
}
209+
210+
index = REF_KEY_PREFIX + Primitive(refs.push(after) - 1);
211+
known.set(after, index);
212+
return index;
213+
}
214+
103215
// the two kinds of primitives
104216
// 1. the real one
105217
// 2. the wrapped one
@@ -113,4 +225,4 @@ var Flatted = (function (Primitive, primitive) {
113225
}
114226

115227
}(String, 'string'));
116-
module.exports = Flatted;
228+
module.exports = TJS;

0 commit comments

Comments
 (0)