Repository: blitz-js/superjson
Pull request #67 (2020-09-28 05:52:09)

Fix for TypeError: rule.isApplicable is not a function
Fixes an issue reported by @blakeley on Slack: 

>Has anyone seen a `TypeError: rule.isApplicable is not a function` error before?


Patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index 9879588..e84162b 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -11,5 +11,9 @@ module.exports = {
         exceptMethods: ['Object.assign'],
       },
     ],
+    "no-restricted-syntax": [
+      "error",
+      "ForInStatement"
+    ]
   },
 };
diff --git a/src/annotator.ts b/src/annotator.ts
index aa4173d..b1ab5ee 100644
--- a/src/annotator.ts
+++ b/src/annotator.ts
@@ -148,7 +148,6 @@ export const applyAnnotations = (plain: any, annotations: Annotations): any => {
       PathTree.expandRoot(annotations.referentialEqualities),
       (identicalObjects, path) => {
         const object = getDeep(plain, path);
-        console.log(object);
 
         PathTree.traversePaths(
           PathTree.expandRoot(identicalObjects),
diff --git a/src/transformer.ts b/src/transformer.ts
index 413c8bb..e7cbfb3 100644
--- a/src/transformer.ts
+++ b/src/transformer.ts
@@ -12,7 +12,7 @@ import {
 } from './is';
 import { ClassRegistry } from './class-registry';
 import { SymbolRegistry } from './symbol-registry';
-import { fromPairs, includes, entries } from 'lodash';
+import { fromPairs, includes, entries, find } from 'lodash';
 
 export type PrimitiveTypeAnnotation = 'number' | 'undefined' | 'bigint';
 
@@ -72,7 +72,20 @@ const simpleRules = [
     () => null,
     () => undefined
   ),
-  simpleTransformation(isBigint, 'bigint', v => v.toString(), BigInt),
+  simpleTransformation(
+    isBigint,
+    'bigint',
+    v => v.toString(),
+    v => {
+      if (typeof BigInt !== 'undefined') {
+        return BigInt(v);
+      }
+
+      console.error('Please add a BigInt polyfill.');
+
+      return v as any;
+    }
+  ),
   simpleTransformation(
     isDate,
     'Date',
@@ -189,24 +202,25 @@ const compositeRules = [classRule, symbolRule];
 export const transformValue = (
   value: any
 ): { value: any; type: TypeAnnotation } | undefined => {
-  for (const i in simpleRules) {
-    const rule = simpleRules[i];
-    if (rule.isApplicable(value)) {
-      return {
-        value: rule.transform(value as never),
-        type: rule.annotation,
-      };
-    }
+  const applicableSimpleRule = find(simpleRules, rule =>
+    rule.isApplicable(value)
+  );
+
+  if (applicableSimpleRule) {
+    return {
+      value: applicableSimpleRule.transform(value as never),
+      type: applicableSimpleRule.annotation,
+    };
   }
 
-  for (const i in compositeRules) {
-    const rule = compositeRules[i];
-    if (rule.isApplicable(value)) {
-      return {
-        value: rule.transform(value),
-        type: rule.annotation(value),
-      };
-    }
+  const applicableCompositeRule = find(compositeRules, rule =>
+    rule.isApplicable(value)
+  );
+  if (applicableCompositeRule) {
+    return {
+      value: applicableCompositeRule.transform(value as never),
+      type: applicableCompositeRule.annotation(value),
+    };
   }
 
   return undefined;


Test patch:
diff --git a/src/index.test.ts b/src/index.test.ts
index 4638741..e5fb30a 100644
--- a/src/index.test.ts
+++ b/src/index.test.ts
@@ -616,4 +616,34 @@ describe('stringify & parse', () => {
       }).toThrow();
     });
   });
+
+  test('regression #65: BigInt on Safari v13', () => {
+    const oldBigInt = global.BigInt;
+    delete global.BigInt;
+
+    const input = {
+      a: oldBigInt('1000'),
+    };
+
+    const superJSONed = SuperJSON.serialize(input);
+    expect(superJSONed).toEqual({
+      json: {
+        a: '1000',
+      },
+      meta: {
+        values: {
+          a: ['bigint'],
+        },
+      },
+    });
+
+    const deserialised = SuperJSON.deserialize(
+      JSON.parse(JSON.stringify(superJSONed))
+    );
+    expect(deserialised).toEqual({
+      a: '1000',
+    });
+
+    global.BigInt = oldBigInt;
+  });
 });