Skip to content

Commit e38c8c0

Browse files
committed
Added marshalling to/from
1 parent 2d4e55f commit e38c8c0

File tree

4 files changed

+198
-20
lines changed

4 files changed

+198
-20
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@ The marshalled version of the input data.
4444
* [X] Casting from/to `Array`.
4545
* [X] Casting from/to `symbol`.
4646
* [ ] Casting from/to `Date`.
47-
* [ ] Casting from/to `Function`
47+
* [X] Casting from/to `Function`
4848
* [ ] Casting from/to `Map`
4949
* [ ] Casting from/to `WeakSet`
5050
* [ ] Casting from/to `WeakMap`
5151
* [ ] Casting from/to `RegExp`
5252

5353
## Changelog:
5454

55+
**v1.0.6**:
56+
57+
- Added marshalling to/from `function`.
58+
5559
**v1.0.5**:
5660

5761
- Fixed a bug where errors could be thrown while attempting to marshal a string using heuristics.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"build:es2015": "tsc --module es2015 --outDir dist/es2015 -p tsconfig.dist.json",
1414
"build": "npm run build:pre && npm run build:cjs && npm run build:es2015",
1515
"test:pre": "tsc --module commonjs --target es2017 --sourceMap",
16-
"test": "NODE_ENV=TEST npm run test:pre && ava --verbose"
16+
"test": "NODE_ENV=TEST npm run test:pre && ava"
1717
},
1818
"keywords": [
1919
"marshaller",

src/Marshaller.ts

Lines changed: 165 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import {ITypeDetector, IArbitraryObject} from "@wessberg/typedetector";
77
*/
88
export class Marshaller implements IMarshaller {
99
private static readonly SYMBOL_REGEX: RegExp = /Symbol\(([^)]*)\)/;
10+
private static readonly FUNCTION_REGEX_1: RegExp = /function\s*\w*\s*\([^)]*\)\s*{/;
11+
private static readonly FUNCTION_REGEX_2: RegExp = /\([^)]*\)\s*=>/;
12+
private static readonly FUNCTION_REGEX_3: RegExp = /\w+\s*=>/;
1013

1114
constructor (private typeDetector: ITypeDetector) {}
1215

@@ -34,6 +37,15 @@ export class Marshaller implements IMarshaller {
3437
return representation;
3538
}
3639

40+
/**
41+
* Marshals a set into a function.
42+
* @param {Set<T>} data
43+
* @returns {Function}
44+
*/
45+
private marshalSetToFunction<T> (data: Set<T>): Function {
46+
return () => data;
47+
}
48+
3749
/**
3850
* Marshals a symbol into a string.
3951
* @param {symbol} data
@@ -45,6 +57,15 @@ export class Marshaller implements IMarshaller {
4557
return match[1];
4658
}
4759

60+
/**
61+
* Marshals a symbol into a function.
62+
* @param {symbol} data
63+
* @returns {Function}
64+
*/
65+
private marshalSymbolToFunction (data: symbol): Function {
66+
return () => data;
67+
}
68+
4869
/**
4970
* Marshals an object into a string.
5071
* @param {object} data
@@ -54,6 +75,15 @@ export class Marshaller implements IMarshaller {
5475
return JSON.stringify(data);
5576
}
5677

78+
/**
79+
* Marshals an object into a function.
80+
* @param {object} data
81+
* @returns {Function}
82+
*/
83+
private marshalObjectToFunction<T> (data: { [key: string]: T }): Function {
84+
return () => data;
85+
}
86+
5787
/**
5888
* Marshals a boolean into a string.
5989
* @param {boolean} data
@@ -63,6 +93,15 @@ export class Marshaller implements IMarshaller {
6393
return `${data instanceof Boolean ? data.valueOf() : data}`;
6494
}
6595

96+
/**
97+
* Marshals a boolean into a Function.
98+
* @param {boolean} data
99+
* @returns {Function}
100+
*/
101+
private marshalBooleanToFunction (data: boolean | Boolean): Function {
102+
return () => data;
103+
}
104+
66105
/**
67106
* Marshals a number into a string.
68107
* @param {number} data
@@ -72,6 +111,15 @@ export class Marshaller implements IMarshaller {
72111
return `${data instanceof Number ? data.valueOf() : data}`;
73112
}
74113

114+
/**
115+
* Marshals a number into a Function.
116+
* @param {number} data
117+
* @returns {Function}
118+
*/
119+
private marshalNumberToFunction (data: number | Number): Function {
120+
return () => data;
121+
}
122+
75123
/**
76124
* Marshals an array into a string.
77125
* @param {T[]} data
@@ -81,6 +129,36 @@ export class Marshaller implements IMarshaller {
81129
return JSON.stringify(data);
82130
}
83131

132+
/**
133+
* Marshals a function into a string.
134+
* @param {Function} data
135+
* @returns {string}
136+
*/
137+
private marshalFunctionToString (data: Function): string {
138+
return data.toString();
139+
}
140+
141+
/**
142+
* Marshals an array into a Function.
143+
* @param {T[]} data
144+
* @returns {Function}
145+
*/
146+
private marshalArrayToFunction<T> (data: T[]): Function {
147+
return () => data;
148+
}
149+
150+
/**
151+
* Marshals a string into a Function.
152+
* @param {string} data
153+
* @returns {Function}
154+
*/
155+
private marshalStringToFunction (data: string): Function {
156+
if (Marshaller.FUNCTION_REGEX_1.test(data)) return new Function(`return ${data}`)();
157+
if (Marshaller.FUNCTION_REGEX_2.test(data)) return new Function(`return ${data}`)();
158+
if (Marshaller.FUNCTION_REGEX_3.test(data)) return new Function(`return ${data}`)();
159+
return () => data;
160+
}
161+
84162
/**
85163
* Marshals a string into a boolean.
86164
* @param {string} data
@@ -91,6 +169,15 @@ export class Marshaller implements IMarshaller {
91169
return primitive === "true" || primitive === "1" || primitive === "";
92170
}
93171

172+
/**
173+
* Marshals a Function into a boolean.
174+
* @param {Function} _
175+
* @returns {boolean}
176+
*/
177+
private marshalFunctionToBoolean (_: Function): boolean {
178+
return true;
179+
}
180+
94181
/**
95182
* Marshals a symbol into a boolean.
96183
* @param {symbol} data
@@ -164,6 +251,15 @@ export class Marshaller implements IMarshaller {
164251
return Symbol(this.marshalNumberToString(primitive));
165252
}
166253

254+
/**
255+
* Marshals a number into a symbol.
256+
* @param {Function} data
257+
* @returns {symbol}
258+
*/
259+
private marshalFunctionToSymbol (data: Function): symbol {
260+
return Symbol(this.marshalFunctionToString(data));
261+
}
262+
167263
/**
168264
* Marshals a set into a symbol.
169265
* @param {Set<T>} data
@@ -211,6 +307,15 @@ export class Marshaller implements IMarshaller {
211307
return Number.parseFloat(primitive);
212308
}
213309

310+
/**
311+
* Marshals a Function into a number.
312+
* @param {Function} _
313+
* @returns {number}
314+
*/
315+
private marshalFunctionToNumber (_: Function): number {
316+
return 1;
317+
}
318+
214319
/**
215320
* Marshals a symbol into a number.
216321
* @param {symbol} data
@@ -270,14 +375,21 @@ export class Marshaller implements IMarshaller {
270375
}
271376

272377
/**
273-
* Marshals a symbol into a boolean.
378+
* Marshals a symbol into a Set.
274379
* @param {symbol} data
275380
* @returns {Set<string>}
276381
*/
277-
private marshalSymbolToSet (data: symbol): Set<string> {
278-
const match = data.toString().match(Marshaller.SYMBOL_REGEX);
279-
if (match == null) throw new ReferenceError(`${this.marshalSymbolToSet.name} was given an invalid symbol to marshal!`);
280-
return this.marshalStringToSet(match[1]);
382+
private marshalSymbolToSet (data: symbol): Set<Symbol> {
383+
return new Set([data]);
384+
}
385+
386+
/**
387+
* Marshals a Function into a Set.
388+
* @param {Function} data
389+
* @returns {Set<Function>}
390+
*/
391+
private marshalFunctionToSet (data: Function): Set<Function> {
392+
return new Set([data]);
281393
}
282394

283395
/**
@@ -345,6 +457,15 @@ export class Marshaller implements IMarshaller {
345457
return this.marshalStringToArray(match[1]);
346458
}
347459

460+
/**
461+
* Marshals a Function into an array.
462+
* @param {Function} data
463+
* @returns {Function[]}
464+
*/
465+
private marshalFunctionToArray (data: Function): Function[] {
466+
return [data];
467+
}
468+
348469
/**
349470
* Marshals a set into an Array.
350471
* @param {Set<T>} data
@@ -421,6 +542,15 @@ export class Marshaller implements IMarshaller {
421542
}
422543
}
423544

545+
/**
546+
* Marshals a Function into an Object.
547+
* @param {Function} data
548+
* @returns {object}
549+
*/
550+
private marshalFunctionToObject (data: Function): { [key: string]: Function } {
551+
return {[data.name]: data};
552+
}
553+
424554
/**
425555
* Marshals a symbol into an object.
426556
* @param {symbol} data
@@ -471,6 +601,7 @@ export class Marshaller implements IMarshaller {
471601
*/
472602
private marshalToBoolean<T> (data: T): boolean | null {
473603
if (this.typeDetector.isBoolean(data)) return data;
604+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToBoolean(data);
474605
if (this.typeDetector.isString(data)) return this.marshalStringToBoolean(data);
475606
if (typeof data === "symbol") return this.marshalSymbolToBoolean(data);
476607
if (data instanceof Set) return this.marshalSetToBoolean(data);
@@ -487,6 +618,7 @@ export class Marshaller implements IMarshaller {
487618
*/
488619
private marshalToNumber<T> (data: T): number | null {
489620
if (this.typeDetector.isNumber(data)) return data;
621+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToNumber(data);
490622
if (this.typeDetector.isString(data)) return this.marshalStringToNumber(data);
491623
if (typeof data === "symbol") return this.marshalSymbolToNumber(data);
492624
if (data instanceof Set) return this.marshalSetToNumber(data);
@@ -503,6 +635,7 @@ export class Marshaller implements IMarshaller {
503635
*/
504636
private marshalToSymbol<T> (data: T): symbol | null {
505637
if (typeof data === "symbol") return data;
638+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToSymbol(data);
506639
if (this.typeDetector.isString(data)) return this.marshalStringToSymbol(data);
507640
if (data instanceof Set) return this.marshalSetToSymbol(data);
508641
if (Array.isArray(data)) return this.marshalArrayToSymbol(data);
@@ -520,6 +653,7 @@ export class Marshaller implements IMarshaller {
520653
*/
521654
private marshalToString<T> (data: T): string | null {
522655
if (this.typeDetector.isString(data)) return (<String>data instanceof String ? <string>data.valueOf() : data);
656+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToString(data);
523657
if (typeof data === "symbol") return this.marshalSymbolToString(data);
524658
if (data instanceof Set) return this.marshalSetToString(data);
525659
if (Array.isArray(data)) return this.marshalArrayToString(data);
@@ -530,6 +664,24 @@ export class Marshaller implements IMarshaller {
530664
return data.toString();
531665
}
532666

667+
/**
668+
* Marshals the given data, whatever the type, into a Function.
669+
* @param {T} data
670+
* @returns {Function|null}
671+
*/
672+
private marshalToFunction<T> (data: T): Function | null {
673+
if (this.typeDetector.isFunction(data)) return data;
674+
if (this.typeDetector.isString(data)) return this.marshalStringToFunction(data);
675+
if (typeof data === "symbol") return this.marshalSymbolToFunction(data);
676+
if (data instanceof Set) return this.marshalSetToFunction(data);
677+
if (Array.isArray(data)) return this.marshalArrayToFunction(data);
678+
if (this.typeDetector.isObject(data)) return this.marshalObjectToFunction(data);
679+
if (this.typeDetector.isBoolean(data)) return this.marshalBooleanToFunction(data);
680+
if (this.typeDetector.isNumber(data)) return this.marshalNumberToFunction(data);
681+
if (data == null) return null;
682+
return () => data;
683+
}
684+
533685
/**
534686
* Marshals the given data, whatever the type, into a Set.
535687
* @param {T} data
@@ -538,6 +690,7 @@ export class Marshaller implements IMarshaller {
538690
private marshalToSet<T> (data: T): Set<{}> | null {
539691
if (data instanceof Set) return data;
540692
if (this.typeDetector.isString(data)) return this.marshalStringToSet(data);
693+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToSet(data);
541694
if (typeof data === "symbol") return this.marshalSymbolToSet(data);
542695
if (Array.isArray(data)) return this.marshalArrayToSet(data);
543696
if (this.typeDetector.isObject(data)) return this.marshalObjectToSet(data);
@@ -554,6 +707,7 @@ export class Marshaller implements IMarshaller {
554707
private marshalToArray<T> (data: T): {}[] | null {
555708
if (Array.isArray(data)) return data;
556709
if (this.typeDetector.isString(data)) return this.marshalStringToArray(data);
710+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToArray(data);
557711
if (typeof data === "symbol") return this.marshalSymbolToArray(data);
558712
if (data instanceof Set) return this.marshalSetToArray(data);
559713
if (this.typeDetector.isObject(data)) return this.marshalObjectToArray(data);
@@ -569,6 +723,7 @@ export class Marshaller implements IMarshaller {
569723
*/
570724
private marshalToObject<T> (data: T): IArbitraryObject<{}>|null {
571725
if (this.typeDetector.isObject(data)) return data;
726+
if (this.typeDetector.isFunction(data)) return this.marshalFunctionToObject(data);
572727
if (Array.isArray(data)) return this.marshalArrayToObject(data);
573728
if (typeof data === "symbol") return this.marshalSymbolToObject(data);
574729
if (this.typeDetector.isString(data)) return this.marshalStringToObject(data);
@@ -638,6 +793,10 @@ export class Marshaller implements IMarshaller {
638793
if (data === "NaN") return NaN;
639794
if (data === "Infinity") return Infinity;
640795

796+
if (Marshaller.FUNCTION_REGEX_1.test(primitive)) return new Function(`return ${primitive}`)();
797+
if (Marshaller.FUNCTION_REGEX_2.test(primitive)) return new Function(`return ${primitive}`)();
798+
if (Marshaller.FUNCTION_REGEX_3.test(primitive)) return new Function(`return ${primitive}`)();
799+
641800
try {
642801
return JSON.parse(primitive);
643802
} catch (e) {
@@ -659,6 +818,7 @@ export class Marshaller implements IMarshaller {
659818
if (this.typeDetector.isObject(to) || to === Object) return this.marshalToObject(data);
660819
if (this.typeDetector.isBoolean(to) || to === Boolean) return this.marshalToBoolean(data);
661820
if (this.typeDetector.isNumber(to) || to === Number) return this.marshalToNumber(data);
821+
if (this.typeDetector.isFunction(to) || to === <{}>Function) return this.marshalToFunction(data);
662822
return this.marshalToString(data);
663823
}
664824

0 commit comments

Comments
 (0)